Created
March 26, 2014 17:52
-
-
Save whyisjake/9789254 to your computer and use it in GitHub Desktop.
The contribute page diff.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: css/style.css | |
=================================================================== | |
--- css/style.css (revision 141566) | |
+++ css/style.css (working copy) | |
@@ -4843,6 +4843,247 @@ | |
border-left-color: #ffffff; | |
bottom: -10px; | |
} | |
+.panel { | |
+ margin-bottom: 20px; | |
+ background-color: #ffffff; | |
+ border: 1px solid transparent; | |
+ border-radius: 4px; | |
+ -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); | |
+ -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); | |
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); | |
+} | |
+.panel-body { | |
+ padding: 15px; | |
+ *zoom: 1; | |
+} | |
+.panel-body:before, | |
+.panel-body:after { | |
+ display: table; | |
+ content: ""; | |
+ line-height: 0; | |
+} | |
+.panel-body:after { | |
+ clear: both; | |
+} | |
+.panel > .list-group { | |
+ margin-bottom: 0; | |
+} | |
+.panel > .list-group .list-group-item { | |
+ border-width: 1px 0; | |
+} | |
+.panel > .list-group .list-group-item:first-child { | |
+ -webkit-border-top-right-radius: 0; | |
+ -moz-border-radius-topright: 0; | |
+ border-top-right-radius: 0; | |
+ -webkit-border-top-left-radius: 0; | |
+ -moz-border-radius-topleft: 0; | |
+ border-top-left-radius: 0; | |
+} | |
+.panel > .list-group .list-group-item:last-child { | |
+ border-bottom: 0; | |
+} | |
+.panel-heading + .list-group .list-group-item:first-child { | |
+ border-top-width: 0; | |
+} | |
+.panel > .table, | |
+.panel > .table-responsive > .table { | |
+ margin-bottom: 0; | |
+} | |
+.panel > .panel-body + .table, | |
+.panel > .panel-body + .table-responsive { | |
+ border-top: 1px solid #dddddd; | |
+} | |
+.panel > .table > tbody:first-child th, | |
+.panel > .table > tbody:first-child td { | |
+ border-top: 0; | |
+} | |
+.panel > .table-bordered, | |
+.panel > .table-responsive > .table-bordered { | |
+ border: 0; | |
+} | |
+.panel > .table-bordered > thead > tr > th:first-child, | |
+.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, | |
+.panel > .table-bordered > tbody > tr > th:first-child, | |
+.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, | |
+.panel > .table-bordered > tfoot > tr > th:first-child, | |
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, | |
+.panel > .table-bordered > thead > tr > td:first-child, | |
+.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, | |
+.panel > .table-bordered > tbody > tr > td:first-child, | |
+.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, | |
+.panel > .table-bordered > tfoot > tr > td:first-child, | |
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { | |
+ border-left: 0; | |
+} | |
+.panel > .table-bordered > thead > tr > th:last-child, | |
+.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, | |
+.panel > .table-bordered > tbody > tr > th:last-child, | |
+.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, | |
+.panel > .table-bordered > tfoot > tr > th:last-child, | |
+.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, | |
+.panel > .table-bordered > thead > tr > td:last-child, | |
+.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, | |
+.panel > .table-bordered > tbody > tr > td:last-child, | |
+.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, | |
+.panel > .table-bordered > tfoot > tr > td:last-child, | |
+.panel > .table-responsive > .table-bordered > tfoot > tr > td:last-child { | |
+ border-right: 0; | |
+} | |
+.panel > .table-bordered > thead > tr:last-child > th, | |
+.panel > .table-responsive > .table-bordered > thead > tr:last-child > th, | |
+.panel > .table-bordered > tbody > tr:last-child > th, | |
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > th, | |
+.panel > .table-bordered > tfoot > tr:last-child > th, | |
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > th, | |
+.panel > .table-bordered > thead > tr:last-child > td, | |
+.panel > .table-responsive > .table-bordered > thead > tr:last-child > td, | |
+.panel > .table-bordered > tbody > tr:last-child > td, | |
+.panel > .table-responsive > .table-bordered > tbody > tr:last-child > td, | |
+.panel > .table-bordered > tfoot > tr:last-child > td, | |
+.panel > .table-responsive > .table-bordered > tfoot > tr:last-child > td { | |
+ border-bottom: 0; | |
+} | |
+.panel > .table-responsive { | |
+ border: 0; | |
+ margin-bottom: 0; | |
+} | |
+.panel-heading { | |
+ padding: 10px 15px; | |
+ border-bottom: 1px solid transparent; | |
+ -webkit-border-top-right-radius: 3px; | |
+ -moz-border-radius-topright: 3px; | |
+ border-top-right-radius: 3px; | |
+ -webkit-border-top-left-radius: 3px; | |
+ -moz-border-radius-topleft: 3px; | |
+ border-top-left-radius: 3px; | |
+} | |
+.panel-heading > .dropdown .dropdown-toggle { | |
+ color: inherit; | |
+} | |
+.panel-title { | |
+ margin-top: 0; | |
+ margin-bottom: 0; | |
+ font-size: 16px; | |
+ color: inherit; | |
+} | |
+.panel-title > a { | |
+ color: inherit; | |
+} | |
+.panel-footer { | |
+ padding: 10px 15px; | |
+ background-color: #f5f5f5; | |
+ border-top: 1px solid #dddddd; | |
+ -webkit-border-bottom-right-radius: 3px; | |
+ -moz-border-radius-bottomright: 3px; | |
+ border-bottom-right-radius: 3px; | |
+ -webkit-border-bottom-left-radius: 3px; | |
+ -moz-border-radius-bottomleft: 3px; | |
+ border-bottom-left-radius: 3px; | |
+} | |
+.panel-group .panel { | |
+ margin-bottom: 0; | |
+ border-radius: 4px; | |
+ overflow: hidden; | |
+} | |
+.panel-group .panel + .panel { | |
+ margin-top: 5px; | |
+} | |
+.panel-group .panel-heading { | |
+ border-bottom: 0; | |
+} | |
+.panel-group .panel-heading + .panel-collapse .panel-body { | |
+ border-top: 1px solid #dddddd; | |
+} | |
+.panel-group .panel-footer { | |
+ border-top: 0; | |
+} | |
+.panel-group .panel-footer + .panel-collapse .panel-body { | |
+ border-bottom: 1px solid #dddddd; | |
+} | |
+.panel-default { | |
+ border-color: #dddddd; | |
+} | |
+.panel-default > .panel-heading { | |
+ color: #333333; | |
+ background-color: #f5f5f5; | |
+ border-color: #dddddd; | |
+} | |
+.panel-default > .panel-heading + .panel-collapse .panel-body { | |
+ border-top-color: #dddddd; | |
+} | |
+.panel-default > .panel-footer + .panel-collapse .panel-body { | |
+ border-bottom-color: #dddddd; | |
+} | |
+.panel-primary { | |
+ border-color: #000000; | |
+} | |
+.panel-primary > .panel-heading { | |
+ color: #ffffff; | |
+ background-color: #cccccc; | |
+ border-color: #000000; | |
+} | |
+.panel-primary > .panel-heading + .panel-collapse .panel-body { | |
+ border-top-color: #000000; | |
+} | |
+.panel-primary > .panel-footer + .panel-collapse .panel-body { | |
+ border-bottom-color: #000000; | |
+} | |
+.panel-success { | |
+ border-color: #d6e9c6; | |
+} | |
+.panel-success > .panel-heading { | |
+ color: #468847; | |
+ background-color: #dff0d8; | |
+ border-color: #d6e9c6; | |
+} | |
+.panel-success > .panel-heading + .panel-collapse .panel-body { | |
+ border-top-color: #d6e9c6; | |
+} | |
+.panel-success > .panel-footer + .panel-collapse .panel-body { | |
+ border-bottom-color: #d6e9c6; | |
+} | |
+.panel-warning { | |
+ border-color: #fbeed5; | |
+} | |
+.panel-warning > .panel-heading { | |
+ color: #c09853; | |
+ background-color: #fcf8e3; | |
+ border-color: #fbeed5; | |
+} | |
+.panel-warning > .panel-heading + .panel-collapse .panel-body { | |
+ border-top-color: #fbeed5; | |
+} | |
+.panel-warning > .panel-footer + .panel-collapse .panel-body { | |
+ border-bottom-color: #fbeed5; | |
+} | |
+.panel-danger { | |
+ border-color: #eed3d7; | |
+} | |
+.panel-danger > .panel-heading { | |
+ color: #b94a48; | |
+ background-color: #f2dede; | |
+ border-color: #eed3d7; | |
+} | |
+.panel-danger > .panel-heading + .panel-collapse .panel-body { | |
+ border-top-color: #eed3d7; | |
+} | |
+.panel-danger > .panel-footer + .panel-collapse .panel-body { | |
+ border-bottom-color: #eed3d7; | |
+} | |
+.panel-info { | |
+ border-color: #bce8f1; | |
+} | |
+.panel-info > .panel-heading { | |
+ color: #3a87ad; | |
+ background-color: #d9edf7; | |
+ border-color: #bce8f1; | |
+} | |
+.panel-info > .panel-heading + .panel-collapse .panel-body { | |
+ border-top-color: #bce8f1; | |
+} | |
+.panel-info > .panel-footer + .panel-collapse .panel-body { | |
+ border-bottom-color: #bce8f1; | |
+} | |
.thumbnails { | |
margin-left: -20px; | |
list-style: none; | |
@@ -5488,6 +5729,38 @@ | |
background: #E4F4F9; | |
color: #ed1c24 !important; | |
} | |
+input.parsley-error, | |
+select.parsley-error, | |
+textarea.parsley-error, | |
+div.parsley-error.mce-panel { | |
+ color: #B94A48; | |
+ background: #F2DEDE; | |
+ border: 1px solid #EED3D7 !important; | |
+} | |
+.parsley-errors-list { | |
+ margin: 2px 0 3px 0; | |
+ padding: 0; | |
+ list-style-type: none; | |
+ font-size: 0.9em; | |
+ line-height: 0.9em; | |
+ opacity: 0; | |
+ -moz-opacity: 0; | |
+ -webkit-opacity: 0; | |
+ color: #B94A48; | |
+ transition: all 0.3s ease-in; | |
+ -o-transition: all 0.3s ease-in; | |
+ -ms-transition: all 0.3s ease-in-; | |
+ -moz-transition: all 0.3s ease-in; | |
+ -webkit-transition: all 0.3s ease-in; | |
+} | |
+.parsley-errors-list.post_content_errors { | |
+ position: absolute; | |
+ bottom: 26px; | |
+ left: 10px; | |
+} | |
+.parsley-errors-list.filled { | |
+ opacity: 1; | |
+} | |
.waist { | |
background-image: url('../img/blue_bg1.jpg'); | |
border-bottom: 2px solid #DBDBDB; | |
@@ -6802,6 +7075,11 @@ | |
width: 50%; | |
float: left; | |
} | |
+div.parts.row, | |
+div.tools.row { | |
+ width: 100%; | |
+ float: none; | |
+} | |
.description { | |
text-align: right; | |
} | |
@@ -9126,6 +9404,20 @@ | |
.top-navigation-wrapper .nav { | |
margin-bottom: 0; | |
} | |
+.login-wrapper { | |
+ position: absolute; | |
+ left: 245px; | |
+ top: -8px; | |
+ color: #005d8f; | |
+ font-size: 18px; | |
+ font-weight: bold; | |
+} | |
+.login-wrapper a { | |
+ display: inline-block; | |
+} | |
+.login-wrapper a:hover { | |
+ text-decoration: underline !important; | |
+} | |
.main-header { | |
padding: 15px 0 10px; | |
border-top: 1px solid #ed1c24; | |
@@ -9188,7 +9480,8 @@ | |
color: #ed1c24; | |
} | |
.main-header .additional-content .search-make { | |
- float: right; | |
+ position: absolute; | |
+ left: -695px; | |
margin: 0; | |
} | |
.main-header .additional-content .search-make input[type="text"] { | |
@@ -9265,7 +9558,7 @@ | |
font-size: 20px !important; | |
font-weight: bold; | |
position: relative; | |
- top: 92px; | |
+ top: 65px; | |
} | |
.primary-navigation ul > li { | |
margin-right: 18px; | |
@@ -12049,3 +12342,125 @@ | |
aside.pull-quote.pull-quote-1.pull-left img { | |
margin-right: 10px; | |
} | |
+.page-template-page-contribute-project-php .title { | |
+ width: 98%; | |
+ margin-bottom: 10px; | |
+} | |
+.page-template-page-contribute-project-php .thumbnail { | |
+ cursor: pointer; | |
+} | |
+.page-template-page-contribute-project-php .thumbnail.add { | |
+ width: 80px; | |
+ height: 38px; | |
+ text-align: center; | |
+ padding: 25px 5px; | |
+ opacity: .5; | |
+ border-style: dashed; | |
+ font-size: 14px; | |
+} | |
+.page-template-page-contribute-project-php #step_content { | |
+ width: 98%; | |
+ min-height: 100px; | |
+} | |
+.page-template-page-contribute-project-php .wp-core-ui .button { | |
+ color: #555 !important; | |
+} | |
+.page-template-page-contribute-project-php .wp-core-ui .button:hover { | |
+ background-color: #fafafa !important; | |
+ color: #222 !important; | |
+} | |
+.page-template-page-contribute-project-php .wp-editor-container { | |
+ border: 1px solid #dedede; | |
+} | |
+.page-template-page-contribute-project-php .projects-masthead { | |
+ padding-top: 0; | |
+} | |
+.btn-file { | |
+ overflow: hidden; | |
+ position: relative; | |
+ vertical-align: middle; | |
+} | |
+.btn-file > input { | |
+ position: absolute; | |
+ top: 0; | |
+ right: 0; | |
+ margin: 0; | |
+ opacity: 0; | |
+ filter: alpha(opacity=0); | |
+ transform: translate(-300px, 0) scale(4); | |
+ font-size: 23px; | |
+ height: 100%; | |
+ direction: ltr; | |
+ cursor: pointer; | |
+} | |
+.fileinput { | |
+ margin-bottom: 9px; | |
+ display: inline-block; | |
+} | |
+.fileinput .form-control { | |
+ padding-top: 7px; | |
+ padding-bottom: 5px; | |
+ display: inline-block; | |
+ margin-bottom: 0px; | |
+ vertical-align: middle; | |
+ cursor: text; | |
+} | |
+.fileinput .thumbnail { | |
+ overflow: hidden; | |
+ display: inline-block; | |
+ margin-bottom: 5px; | |
+ vertical-align: middle; | |
+ text-align: center; | |
+} | |
+.fileinput .thumbnail > img { | |
+ max-height: 100%; | |
+} | |
+.fileinput .btn { | |
+ vertical-align: middle; | |
+} | |
+.fileinput-exists .fileinput-new, | |
+.fileinput-new .fileinput-exists { | |
+ display: none; | |
+} | |
+.fileinput-inline .fileinput-controls { | |
+ display: inline; | |
+} | |
+.fileinput-filename { | |
+ vertical-align: middle; | |
+ display: inline-block; | |
+ overflow: hidden; | |
+} | |
+.form-control .fileinput-filename { | |
+ vertical-align: bottom; | |
+} | |
+.fileinput-new .input-group .btn-file { | |
+ border-radius: 0 4px 4px 0; | |
+} | |
+.fileinput-new .input-group .btn-file.btn-xs, | |
+.fileinput-new .input-group .btn-file.btn-sm { | |
+ border-radius: 0 3px 3px 0; | |
+} | |
+.fileinput-new .input-group .btn-file.btn-lg { | |
+ border-radius: 0 6px 6px 0; | |
+} | |
+.form-group.has-warning .fileinput .fileinput-preview { | |
+ color: #8a6d3b; | |
+} | |
+.form-group.has-warning .fileinput .thumbnail { | |
+ border-color: #faebcc; | |
+} | |
+.form-group.has-error .fileinput .fileinput-preview { | |
+ color: #a94442; | |
+} | |
+.form-group.has-error .fileinput .thumbnail { | |
+ border-color: #ebccd1; | |
+} | |
+.form-group.has-success .fileinput .fileinput-preview { | |
+ color: #3c763d; | |
+} | |
+.form-group.has-success .fileinput .thumbnail { | |
+ border-color: #d6e9c6; | |
+} | |
+.input-group-addon:not(:first-child) { | |
+ border-left: 0; | |
+} | |
Index: functions.php | |
=================================================================== | |
--- functions.php (revision 141566) | |
+++ functions.php (working copy) | |
@@ -1,4 +1,4 @@ | |
-<?php | |
+<?php | |
/* | |
@@ -29,6 +29,9 @@ | |
// 2. WordPress.com VIP Hosting Stuff | |
include_once dirname( __FILE__ ) . '/includes/vip.php'; | |
+// Load Gigya! | |
+include_once dirname( __FILE__ ) . '/includes/gigya/gigya.php'; | |
+ | |
// 3. NUMBERED PAGE NAVIGATION | |
include_once dirname( __FILE__ ) . '/includes/pagenavi.php'; | |
@@ -47,7 +50,7 @@ | |
// 8. Page 2 - Custom Post Type | |
include_once dirname( __FILE__ ) . '/includes/page_2.php'; | |
-// 9. YouTube Embed Function | |
+// 9. YouTube Embed Function | |
include_once dirname( __FILE__ ) . '/includes/youtube.php'; | |
// 10. Contribute Function | |
@@ -156,5 +159,7 @@ | |
// 45. Related Content Blocks | |
include_once dirname( __FILE__ ) . '/includes/related.php'; | |
+// 45. Contribute Form | |
+include_once dirname( __FILE__ ) . '/includes/contribute/contribute.php'; | |
?> | |
\ No newline at end of file | |
Index: includes/contribute/contribute.php | |
=================================================================== | |
--- includes/contribute/contribute.php (revision 0) | |
+++ includes/contribute/contribute.php (working copy) | |
@@ -0,0 +1,389 @@ | |
+<?php | |
+ | |
+/** | |
+ * Contribute! | |
+ * | |
+ * A class that will allow for forms to contribute posts. | |
+ * | |
+ * @since Quantrons | |
+ */ | |
+ | |
+/** | |
+ * The guts. | |
+ * | |
+ * This little guy controls and loads all that is Gigya. | |
+ * The namespace for this class is Make because in the future this will be expanded to other make websites. | |
+ * | |
+ * @since Quantrons | |
+ */ | |
+class Make_Contribute { | |
+ | |
+ /** | |
+ * THE CONSTRUCT. | |
+ * | |
+ * All Hooks and Filter here. | |
+ * Anything else that needs to run when the class is instantiated, place them here. | |
+ * Maybe you'll get a cake if you do. | |
+ * | |
+ * @return void | |
+ * @since Quantrons | |
+ */ | |
+ public function __construct() { | |
+ add_action( 'wp_enqueue_scripts', array( $this, 'load_resources' ), 30 ); | |
+ | |
+ // Process our ajax requests. We need ajax processing for both logged in and logged out users. | |
+ // Since our login may be used by users logged into WordPress, we'll need the second option to run ajax requests. | |
+ add_action( 'wp_ajax_nopriv_contribute_post', array( $this, 'contribute_post' ) ); | |
+ add_action( 'wp_ajax_contribute_post', array( $this, 'contribute_post' ) ); | |
+ | |
+ // Add the steps ajax actions. | |
+ add_action( 'wp_ajax_nopriv_add_steps', array( $this, 'add_steps' ) ); | |
+ add_action( 'wp_ajax_add_steps', array( $this, 'add_steps' ) ); | |
+ | |
+ // Add the tools ajax actions. | |
+ add_action( 'wp_ajax_nopriv_add_tools', array( $this, 'add_tools' ) ); | |
+ add_action( 'wp_ajax_add_tools', array( $this, 'add_tools' ) ); | |
+ | |
+ // Add the parts ajax actions. | |
+ add_action( 'wp_ajax_nopriv_add_parts', array( $this, 'add_parts' ) ); | |
+ add_action( 'wp_ajax_add_parts', array( $this, 'add_parts' ) ); | |
+ | |
+ // Get the steps for a project. | |
+ add_action( 'wp_ajax_nopriv_get_steps', array( $this, 'get_steps' ) ); | |
+ add_action( 'wp_ajax_get_steps', array( $this, 'get_steps' ) ); | |
+ | |
+ // Get the steps for a project. | |
+ add_action( 'wp_ajax_nopriv_get_steps_list', array( $this, 'get_steps_list' ) ); | |
+ add_action( 'wp_ajax_get_steps_list', array( $this, 'get_steps_list' ) ); | |
+ } | |
+ | |
+ /** | |
+ * Let's add all of our resouces to make our magic happen. | |
+ * Any scripts we should include in the footer or else things will conflict due to how we have to load the socialize API file... #facepalm | |
+ * | |
+ * @return void | |
+ * @since Quantrons | |
+ */ | |
+ public function load_resources() { | |
+ | |
+ // JavaScript | |
+ wp_enqueue_script( 'parseley-js', get_stylesheet_directory_uri() . '/js/parsley.min.js', array( 'jquery' ), '2.0', true ); | |
+ wp_enqueue_script( 'bootstrap-file-input', get_stylesheet_directory_uri() . '/js/bootstrap.file-input.min.js', array( 'jquery' ), '1.0', true ); | |
+ wp_enqueue_script( 'make-contribute', get_stylesheet_directory_uri() . '/includes/contribute/js/contribute.js', array( 'jquery' ), '1.0', true ); | |
+ wp_enqueue_script( 'make-contrib-ui', get_stylesheet_directory_uri() . '/includes/contribute/js/contrib-ui.js', array( 'jquery' ), '1.0', true ); | |
+ } | |
+ | |
+ /** | |
+ * Uploads images and documents. | |
+ * @param Integer $post_id The post ID we are adding the image to | |
+ * @param Array $files An array of files being uploaded (captured via $_FILES) | |
+ * @return Array | |
+ */ | |
+ private function upload_files( $post_id, $files ) { | |
+ | |
+ if ( ! function_exists( 'wp_handle_upload' ) ) | |
+ require_once( ABSPATH . 'wp-admin/includes/file.php' ); | |
+ | |
+ if ( ! function_exists( 'wp_crop_image' ) ) | |
+ require_once( ABSPATH . 'wp-admin/includes/image.php' ); | |
+ | |
+ // And array of allowed file types to be uploaded | |
+ $allowed_file_types = array( | |
+ 'jpg', | |
+ 'jpeg', | |
+ 'png', | |
+ 'gif', | |
+ ); | |
+ | |
+ // Setup the image array | |
+ $images = array(); | |
+ | |
+ // Loop through all of our uploaded files | |
+ foreach ( $files as $name => $values ) { | |
+ | |
+ $file_type = wp_check_filetype( $values['name'] ); | |
+ // Ensure the file type being passed matches the field type (ie. photo uploads should only allow photos and documents as documents) | |
+ if ( ! in_array( $file_type['ext'], $allowed_file_types ) ) | |
+ return; | |
+ | |
+ $overrides = array( 'test_form' => false ); | |
+ $file = wp_handle_upload( $values, $overrides ); | |
+ | |
+ // Check if there were any errors | |
+ if ( isset( $file['error'] ) ) { | |
+ // TODO: update this to trigger a wp_error instead... | |
+ return $results['error'] = $file['error']; | |
+ exit(); | |
+ } | |
+ | |
+ $attachment = array( | |
+ 'guid' => $file['url'], | |
+ 'post_mime_type' => $file['type'], | |
+ 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $values['name'] ) ), | |
+ 'post_content' => '', | |
+ 'post_status' => 'inherit' | |
+ ); | |
+ $attachment_id = wp_insert_attachment( $attachment, $file['file'], $post_id ); | |
+ | |
+ $attachment_data = wp_generate_attachment_metadata( $attachment_id, $values['name'] ); | |
+ | |
+ wp_update_attachment_metadata( $attachment_id, $attachment_data ); | |
+ | |
+ // Attach as a featured image if we are uploading the project photo | |
+ if ( $name === 'file' ) | |
+ update_post_meta( $post_id, '_thumbnail_id', $attachment_id ); | |
+ | |
+ // Get the upload directory | |
+ $wp_upload_dir = wp_upload_dir(); | |
+ $thumb = image_make_intermediate_size( $file['file'], 500, 500 ); | |
+ | |
+ // Due to legacy code, we need to pass two empty fields. | |
+ // TODO: Update the image handling in make_magazine_projects_build_step_data() to allow a varying number of images, fixing the need to pass two empty values. | |
+ $images[ sanitize_key( $name ) ] = array( | |
+ esc_url( $file['url'] ), | |
+ '', | |
+ '', | |
+ ); | |
+ } | |
+ | |
+ return $images; | |
+ } | |
+ | |
+ | |
+ /** | |
+ * Allows us to determine if the contributing author is a WordPress user or Guest Author based on the ID passed and return their username | |
+ * @return string | false | |
+ * | |
+ * @since Robot House | |
+ */ | |
+ public function get_author_name( $id ) { | |
+ // Gigya always passes IDs as long strings, if it's an integer, then we have a WP user | |
+ if ( ctype_digit( $id ) ) { // Ensure the string contains only numbers..... | |
+ $author_name = get_the_author_meta( 'user_login', absint( $id ) ); | |
+ | |
+ return array( 'post_author' => $id, 'login_name' => $author_name ); | |
+ } else { | |
+ global $make_gigya; | |
+ | |
+ // We'll need to check for this gigya user and return their information | |
+ $guest_author = $make_gigya->search_for_maker_by_id( $id ); | |
+ | |
+ if ( $guest_author ) { | |
+ return array( 'login_name' => $guest_author[0]->post_name ); | |
+ } else { | |
+ return false; | |
+ } | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Build a row of photos based on uploaded images. | |
+ */ | |
+ public function image_rows( $id ) { | |
+ $output = ''; | |
+ $media = get_attached_media( 'image', $id ); | |
+ $rows = array_chunk( $media, 4 ); | |
+ foreach ( $rows as $images ) { | |
+ $output .= '<div class="row">'; | |
+ foreach ($images as $image) { | |
+ $output .= '<div class="span2">'; | |
+ $output .= '<img src="' . esc_url( wpcom_vip_get_resized_remote_image_url( $image->guid, '130', '170' ) ) . '" alt="' . esc_attr( $image->post_title ) . '">'; | |
+ $output .= '</div>'; | |
+ } | |
+ $output .= '</div>'; | |
+ } | |
+ return $output; | |
+ } | |
+ | |
+ /** | |
+ * Take the form data, and add a post/project. | |
+ * | |
+ * @return json | |
+ * | |
+ * @since Quantrons | |
+ */ | |
+ public function contribute_post() { | |
+ global $coauthors_plus; | |
+ | |
+ // Check our nonce and make sure it's correct | |
+ if ( ! wp_verify_nonce( $_POST['contribute_post'], 'contribute_post_nonce' ) ) | |
+ die( 'We weren\'t able to verify that nonce...' ); | |
+ | |
+ // Get the author ID | |
+ $author_name = $this->get_author_name( $_POST['user_id'] ); | |
+ | |
+ // Make sure an author was returned | |
+ if ( ! $author_name ) | |
+ die( json_encode( 'ERROR: AUTHOR NOT FOUND' ) ); | |
+ | |
+ $allowed_post_types = array( | |
+ 'post', | |
+ 'projects' | |
+ ); | |
+ | |
+ // Setup the post variables yo. | |
+ $post = array( | |
+ 'post_status' => 'draft', | |
+ 'post_title' => ( isset( $_POST['post_title'] ) ) ? sanitize_text_field( $_POST['post_title'] ) : '', | |
+ 'post_name' => ( isset( $_POST['post_title'] ) ) ? sanitize_title( $_POST['post_title'] ) : '', | |
+ 'post_content' => ( isset( $_POST['post_content'] ) ) ? wp_kses_post( $_POST['post_content'] ) : '', | |
+ 'post_category' => ( isset( $_POST['cat'] ) ) ? array( absint( $_POST['cat'] ) ) : '', | |
+ 'post_type' => ( isset( $_POST['post_type'] ) && in_array( $_POST['post_type'], $allowed_post_types ) ) ? sanitize_text_field( $_POST['post_type'] ) : 'post', | |
+ 'post_author' => ( isset( $author_id['post_author'] ) ) ? absint( $author_id['post_author'] ) : 604631, | |
+ ); | |
+ | |
+ // Insert the post | |
+ $pid = wp_insert_post( $post ); | |
+ | |
+ // Add to CoAuthors Plus (for all users, not just Guest Authors) | |
+ $author_set = $coauthors_plus->add_coauthors( absint( $pid ), array( $author_name['login_name'] ) ); | |
+ | |
+ // Upload the files | |
+ $this->upload_files( $pid, $_FILES ); | |
+ | |
+ // Get the newly created post | |
+ $post = get_post( $pid ); | |
+ | |
+ $post->media = $this->image_rows( $pid ); | |
+ | |
+ // Send back the Post as JSON | |
+ die( json_encode( $post ) ); | |
+ | |
+ } | |
+ | |
+ /** | |
+ * Take the form data, and add a post/project. | |
+ * | |
+ * @return json | |
+ * | |
+ * @since Quantrons | |
+ */ | |
+ public function add_steps() { | |
+ | |
+ //////////////////// | |
+ // Check our nonce and make sure it's correct | |
+ if ( ! wp_verify_nonce( $_POST['contribute_steps_nonce'], 'contribute_steps_nonce' ) ) | |
+ die( 'We weren\'t able to verify that nonce...' ); | |
+ | |
+ //////////////////// | |
+ // Upload the files | |
+ $files = $this->upload_files( absint( $_POST['post_ID'] ), $_FILES ); | |
+ | |
+ //////////////////// | |
+ // Merge the files array and the $_POST array. | |
+ $merged = array_merge( $_POST, $files ); | |
+ | |
+ ////////////////////////// | |
+ // STEPS | |
+ $step_object = make_magazine_projects_build_step_data( $merged ); | |
+ | |
+ // Update our post meta for Steps if any exist | |
+ update_post_meta( absint( $_POST['post_ID'] ), 'Steps', $step_object ); | |
+ | |
+ // Send back the | |
+ die( json_encode( array( 'post_id' => $_POST['post_ID'] ) ) ); | |
+ | |
+ } | |
+ | |
+ public function add_tools() { | |
+ | |
+ //////////////////// | |
+ // Check our nonce and make sure it's correct | |
+ if ( ! wp_verify_nonce( $_POST['contribute_tools'], 'contribute_tools' ) ) | |
+ die( 'We weren\'t able to verify that nonce...' ); | |
+ | |
+ //////////////////// | |
+ // Build the tools object | |
+ $tools_object = make_magazine_projects_build_tools_data( $_POST ); | |
+ | |
+ //////////////////// | |
+ // Update our post meta for Steps. Unlike Steps and Tools, we want one meta key. | |
+ update_post_meta( absint( absint( $_POST['post_ID'] ) ), 'Tools', $tools_object ); | |
+ | |
+ //////////////////// | |
+ // Let's get the tools out of the database. | |
+ $tools = get_post_meta( absint( $_POST['post_ID'] ), 'Tools' ); | |
+ | |
+ //////////////////// | |
+ // Send back the tools object | |
+ die( make_projects_tools( $tools ) ); | |
+ | |
+ } | |
+ | |
+ public function add_parts() { | |
+ | |
+ //////////////////// | |
+ // Check our nonce and make sure it's correct | |
+ if ( ! wp_verify_nonce( $_POST['contribute_parts'], 'contribute_parts' ) ) | |
+ die( 'We weren\'t able to verify that nonce...' ); | |
+ | |
+ /////////////////////// | |
+ // PARTS | |
+ $parts = make_magazine_projects_build_parts_data( $_POST ); | |
+ | |
+ $meta_obj = array(); | |
+ foreach ( $parts as $part ) { | |
+ $meta_obj[] = add_post_meta( absint( $_POST['post_ID'] ), 'parts', $part ); | |
+ } | |
+ | |
+ $parts = get_post_meta( absint( $_POST['post_ID'] ), 'parts' ); | |
+ | |
+ //////////////////// | |
+ // Send back the tools object | |
+ die( make_projects_parts( $parts ) ); | |
+ | |
+ } | |
+ | |
+ /** | |
+ * Get the steps HTML | |
+ */ | |
+ public function get_steps() { | |
+ | |
+ //////////////////// | |
+ // Check our nonce and make sure it's correct | |
+ if ( ! wp_verify_nonce( $_POST['get_steps'], 'get_steps' ) ) | |
+ die( 'We weren\'t able to verify that nonce...' ); | |
+ | |
+ /////////////////////// | |
+ // Get the steps. | |
+ $steps = get_post_custom_values( 'Steps', absint( $_POST['post_ID'] ) ); | |
+ | |
+ /////////////////////// | |
+ // HTMLify the steps. | |
+ make_projects_steps( $steps ); | |
+ | |
+ //////////////////// | |
+ // We are done here right? | |
+ die(); | |
+ | |
+ } | |
+ | |
+ /** | |
+ * Get the steps HTML | |
+ */ | |
+ public function get_steps_list() { | |
+ | |
+ //////////////////// | |
+ // Check our nonce and make sure it's correct | |
+ if ( ! wp_verify_nonce( $_POST['get_steps'], 'get_steps' ) ) | |
+ die( 'We weren\'t able to verify that nonce...' ); | |
+ | |
+ /////////////////////// | |
+ // Get the steps. | |
+ $steps = get_post_custom_values( 'Steps', absint( $_POST['post_ID'] ) ); | |
+ | |
+ /////////////////////// | |
+ // HTMLify the steps. | |
+ make_projects_steps_list( $steps ); | |
+ | |
+ //////////////////// | |
+ // Done here right? | |
+ die(); | |
+ | |
+ } | |
+ | |
+ | |
+ | |
+} | |
+ | |
+$make_contribute = new Make_Contribute(); | |
Index: includes/contribute/js/contrib-ui.js | |
=================================================================== | |
--- includes/contribute/js/contrib-ui.js (revision 0) | |
+++ includes/contribute/js/contrib-ui.js (working copy) | |
@@ -0,0 +1,207 @@ | |
+/** | |
+ * This file handles all the UI stuff like adding new fields | |
+ */ | |
+ | |
+jQuery( document ).ready( function( $ ) { | |
+ // Trigger the step addition when we click the "Add Step" button | |
+ $( '.btn.add-step' ).click( function( e ) { | |
+ e.preventDefault(); | |
+ | |
+ make_contribute_add_field( 'steps' ); | |
+ }); | |
+ | |
+ // Trigger the parts addition when we click the "Add Parts" button | |
+ $( '.btn.add-part' ).click( function( e ) { | |
+ e.preventDefault(); | |
+ | |
+ make_contribute_add_field( 'parts' ); | |
+ }); | |
+ | |
+ // Trigger the tools addition when we click the "Add Parts" button | |
+ $( '.btn.add-tool' ).click( function( e ) { | |
+ e.preventDefault(); | |
+ | |
+ make_contribute_add_field( 'tools' ); | |
+ }); | |
+}); | |
+ | |
+ | |
+/** | |
+ * Adds new elements of our contributor form to the page | |
+ * @param strong fields the type of field we are dealing with | |
+ * @return void | |
+ */ | |
+function make_contribute_add_field( fields ) { | |
+ // Count the number of fields we have and increment | |
+ var count = jQuery( 'input[name="total-' + fields + '"]' ).val(); | |
+ count++; | |
+ | |
+ // Get the template | |
+ var template = jQuery( '#' + fields + '-template' ).html(); | |
+ | |
+ // Run a find and replace on the template to add our field count variable | |
+ temp = template.replace( new RegExp( '##count##', 'g' ), count ); | |
+ | |
+ // Append the new template to our list of items | |
+ jQuery( '.' + fields + '-list' ).append( temp ); | |
+ | |
+ // Update our item count | |
+ jQuery( 'input[name="total-' + fields + '"]' ).val( count ); | |
+ | |
+ // Make sure we trigger the removal event of the field after its been added | |
+ make_contribute_remove_field( fields ); | |
+} | |
+ | |
+ | |
+/** | |
+ * Removes an element from the contribute form | |
+ * @param string fields the type of field we are dealing with | |
+ * @return void | |
+ */ | |
+function make_contribute_remove_field( fields ) { | |
+ | |
+ // The field variable is passed as a plural, let's remove make singular | |
+ field = fields.substring( 0, fields.length - 1 ); | |
+ | |
+ // Trigger the field removal | |
+ jQuery( '.btn.remove-' + field ).click( function( e ) { | |
+ e.preventDefault(); | |
+ | |
+ // Remove the element | |
+ jQuery( this ).parents( '.' + field + '.row' ).remove(); | |
+ | |
+ // Make sure we reiterate over our steps and update their count. This will allow users to remove steps in-between steps | |
+ make_contribute_get_update_fields( fields ); | |
+ }); | |
+} | |
+ | |
+ | |
+/** | |
+ * A controller function to determine what function we need to use based on the form field type | |
+ * @param string fields The type of field we are dealing with | |
+ * @return void | |
+ */ | |
+function make_contribute_get_update_fields( fields ) { | |
+ if ( fields === 'steps' ) { | |
+ make_contribute_update_steps(); | |
+ } else if ( fields === 'parts' ) { | |
+ make_contribute_update_parts(); | |
+ } else if ( fields === 'tools' ) { | |
+ make_contribute_update_tools(); | |
+ } | |
+ | |
+} | |
+ | |
+ | |
+/** | |
+ * Updates the step form fields to ensure they are all labeled with the right number | |
+ * @return void | |
+ */ | |
+function make_contribute_update_steps() { | |
+ var i = 1; | |
+ jQuery( '.step.row' ).each( function() { | |
+ var step = jQuery(this); | |
+ | |
+ // Update the step number title | |
+ step.find( '.step-title' ).html( 'Step ' + i ); | |
+ | |
+ // Update the step number | |
+ step.find( 'input[type="hidden"].step-number' ).attr({ | |
+ 'name' : 'step-number-' + i, | |
+ 'value' : i | |
+ }); | |
+ | |
+ // Update the step image | |
+ step.find( 'input[type="file"].step-file' ).attr( 'name', 'step-images-' + i + '[]' ); | |
+ | |
+ // Update the step title | |
+ step.find( 'input[type="text"].title' ).attr( 'name', 'step-title-' + i ); | |
+ | |
+ // Update the step lines | |
+ step.find( 'textarea.step_content' ).attr( 'name', 'step-lines-' + i + '[]' ); | |
+ | |
+ i++; | |
+ }); | |
+ | |
+ // Update the total step count | |
+ jQuery( '#add-steps' ).find( 'input[type="hidden"][name="total-steps"]' ).val( i - 1 ); | |
+} | |
+ | |
+ | |
+/** | |
+ * Updates the part form fields to ensure they are all labeled with the right number | |
+ * @return void | |
+ */ | |
+function make_contribute_update_parts() { | |
+ var i = 1; | |
+ jQuery( '.part.row' ).each( function() { | |
+ var part = jQuery(this); | |
+ | |
+ // Update the part number title | |
+ part.find( '.part-title' ).html( 'Part ' + i ); | |
+ | |
+ // Update the part number | |
+ part.find( 'input[type="hidden"].part-number' ).attr({ | |
+ 'name' : 'part-number-' + i, | |
+ 'value' : i | |
+ }); | |
+ | |
+ // Update the parts notes count | |
+ part.find( 'input[type="hidden"].parts-notes' ).attr( 'name', 'parts-notes-' + i ); | |
+ | |
+ // Update the part name | |
+ part.find( 'input[type="text"].parts-name' ).attr( 'name', 'parts-name-' + i ); | |
+ | |
+ // Update the parts quantity | |
+ part.find( 'input[type="number"].parts-qty' ).attr( 'name', 'parts-qty-' + i ); | |
+ | |
+ // Update the parts url | |
+ part.find( 'input[type="url"].parts-url' ).attr( 'name', 'parts-url-' + i ); | |
+ | |
+ // Update the parts type | |
+ part.find( 'input[type="text"].parts-type' ).attr( 'name', 'parts-type-' + i ); | |
+ | |
+ i++; | |
+ }); | |
+ | |
+ // Update the total step count | |
+ jQuery( '#add-parts' ).find( 'input[type="hidden"][name="total-parts"]' ).val( i - 1 ); | |
+} | |
+ | |
+ | |
+/** | |
+ * Updates the tools form fields to ensure they are all labeled with the right number | |
+ * @return void | |
+ */ | |
+function make_contribute_update_tools() { | |
+ var i = 1; | |
+ jQuery( '.tool.row' ).each( function() { | |
+ var tool = jQuery(this); | |
+ | |
+ // Update the tools number title | |
+ tool.find( '.tool-title' ).html( 'Tool ' + i ); | |
+ | |
+ // Update the tools number | |
+ tool.find( 'input[type="hidden"].tools-number' ).attr({ | |
+ 'name' : 'tool-number-' + i, | |
+ 'value' : i | |
+ }); | |
+ | |
+ // Update the tools thumb name | |
+ tool.find( 'input[type="hidden"].tools-thumb' ).attr( 'name', 'tools-thumb-' + i ); | |
+ | |
+ // Update the tool notes name | |
+ tool.find( 'input[type="hidden"].tools-notes' ).attr( 'name', 'tools-notes-' + i ); | |
+ | |
+ // Update the tool name | |
+ tool.find( 'input[type="text"].tools-name' ).attr( 'name', 'tools-name-' + i ); | |
+ | |
+ // Update the tool url | |
+ tool.find( 'input[type="url"].tools-url' ).attr( 'name', 'tools-url-' + i ); | |
+ | |
+ i++; | |
+ }); | |
+ | |
+ // Update the total step count | |
+ jQuery( '#add-tools' ).find( 'input[type="hidden"][name="total-tools"]' ).val( i - 1 ); | |
+} | |
\ No newline at end of file | |
Index: includes/contribute/js/contribute.js | |
=================================================================== | |
--- includes/contribute/js/contribute.js (revision 0) | |
+++ includes/contribute/js/contribute.js (working copy) | |
@@ -0,0 +1,381 @@ | |
+jQuery( document ).ready( function( $ ) { | |
+ | |
+ // Load the nifty file input styling for Bootstrap | |
+ $('.file-inputs').bootstrapFileInput(); | |
+ | |
+ // Let's hide all of the steps. | |
+ $( '.contribute-form-steps, .contribute-form-parts, .contribute-form-tools' ).hide(); | |
+ | |
+ // Init our form validation | |
+ $( '.validate-form' ).parsley(); | |
+ | |
+ // On post creation, we need a way to tell if we are creating a project or post. | |
+ // The below will help us set a variable accessed in the submission of the form. | |
+ var make_contribute_post_type = ''; | |
+ $( '.submit-review' ).click( function() { | |
+ make_contribute_post_type = $( this ).data( 'type' ); | |
+ }); | |
+ | |
+ // Handle the AJAX for saving the first stage of the post. The rest will be over Backbone. | |
+ $( '#add-post-content' ).submit( function( e ) { | |
+ | |
+ // Prevent the button from sending the form. | |
+ e.preventDefault(); | |
+ | |
+ // Validate that we our form has passed our preliminary check. | |
+ var check_form = $( this ).parsley( 'validate' ); | |
+ if ( ! check_form.validationResult ) | |
+ return; | |
+ | |
+ // Disable the inputs. | |
+ make_contribute_input_disabler( 'contribute-form' ); | |
+ | |
+ // Hide the form | |
+ make_contribute_close_forms(); | |
+ | |
+ // Add the loading bar | |
+ make_contribute_loading_screen(); | |
+ | |
+ // Let's hide this, and bring it back when we have something to put in it. | |
+ $( '.parts-tools').hide(); | |
+ | |
+ // Save the form, pushing the data back. | |
+ tinyMCE.triggerSave(); | |
+ | |
+ // Setup the form. | |
+ var form = $( 'contribute-form' ); | |
+ | |
+ var data = new FormData( form ); | |
+ jQuery.each( $( '#file' )[0].files, function( i, file ) { | |
+ // Inject the files | |
+ data.append( 'file-' + i, file ); | |
+ }); | |
+ | |
+ // Append all of the other field.s | |
+ data.append( 'contribute_post', $( '.contribute-form #contribute_post' ).val() ); | |
+ data.append( 'post_title', $( '.contribute-form #post_title' ).val() ); | |
+ data.append( 'user_id', $( '.contribute-form #user_id' ).val() ); | |
+ data.append( 'post_content', tinyMCE.activeEditor.getContent() ); | |
+ data.append( 'cat', $( '.contribute-form #cat' ).val() ); | |
+ data.append( 'post_type', make_contribute_post_type ); | |
+ data.append( 'post_author', $( '.user_id' ).val() ); | |
+ data.append( 'action', 'contribute_post' ); | |
+ | |
+ // Send off the AJAX request. | |
+ $.ajax({ | |
+ url: make_gigya.ajax, | |
+ data: data, | |
+ cache: false, | |
+ contentType: false, | |
+ processData: false, | |
+ type: 'POST', | |
+ success: function( data ){ | |
+ post_obj = JSON.parse( data ); | |
+ make_contribute_post_filler( post_obj ); | |
+ | |
+ if ( make_contribute_post_type === 'projects' ) { | |
+ $( '.contribute-form-steps' ).slideDown(); | |
+ $( '.post_ID' ).each( function() { | |
+ $( this ).val( post_obj.ID ); | |
+ }); | |
+ } else { | |
+ $( '.content-wrapper' ).append( '<div class="row"><div class="span12"><h3>Thanks for submitting a post! We\'ll review your contribution shortly.</h3></div></div>' ); | |
+ } | |
+ | |
+ make_contribute_remove_progress_bar(); | |
+ } | |
+ }); | |
+ }); | |
+ | |
+ | |
+ // Save the steps. | |
+ $( '.submit-steps' ).on( 'click', function( e ) { | |
+ | |
+ // Prevent the button from triggering | |
+ e.preventDefault(); | |
+ | |
+ // Disable the form inputs | |
+ make_contribute_input_disabler( 'contribute-form-steps' ); | |
+ | |
+ // Hide the steps. | |
+ make_contribute_close_forms(); | |
+ | |
+ // Added this for Cole... | |
+ make_contribute_loading_screen(); | |
+ | |
+ // Let's get the steps initialized. | |
+ var form = $( 'contribute-form-steps' ); | |
+ | |
+ // Grab all of the inputs. | |
+ var the_files = $( '.contribute-form-steps :file' ); | |
+ var inputs = $( '.contribute-form-steps input:not(:file), .contribute-form-steps textarea' ); | |
+ | |
+ // New FormData | |
+ var data = new FormData( form ); | |
+ | |
+ // Setup the form object, just kinda playing with this as a source of data. | |
+ var form_obj = {}; | |
+ | |
+ // Add the add_steps action to the object. | |
+ form_obj.action = 'add_steps'; | |
+ | |
+ // Append each of the images to the object, giving each a name. | |
+ jQuery.each( the_files, function( i, file_obj ) { | |
+ jQuery.each( file_obj.files, function( key, file ) { | |
+ form_obj['step-images-' + ( i + 1 )] = file; | |
+ data.append( 'step-images-' + ( i + 1 ), file ); | |
+ }); | |
+ }); | |
+ | |
+ // Loop through all of the inputs, with the exception of the file ones, and add the to the form_object, and then to the data object. | |
+ inputs.each( function() { | |
+ form_obj[ this.name ] = $( this ).val(); | |
+ data.append( this.name, $( this ).val() ); | |
+ }); | |
+ | |
+ // Append the action to the data object. | |
+ data.append( 'action', 'add_steps' ); | |
+ | |
+ // Ajax request. | |
+ $.ajax({ | |
+ url: make_gigya.ajax, | |
+ data: data, | |
+ cache: false, | |
+ contentType: false, | |
+ processData: false, | |
+ type: 'POST', | |
+ success: function( response ){ | |
+ response = JSON.parse( response ); | |
+ make_contribute_close_forms(); | |
+ make_contribute_display_steps( response.post_id ); | |
+ make_contribute_remove_progress_bar(); | |
+ } | |
+ }); | |
+ }); | |
+ | |
+ // Save the parts data | |
+ $( '.submit-parts' ).on( 'click', function( e ) { | |
+ | |
+ // Prevent the button from trggering | |
+ e.preventDefault(); | |
+ | |
+ // Disable the inputs. | |
+ make_contribute_input_disabler( 'contribute-form-parts' ); | |
+ | |
+ // Hide the form | |
+ make_contribute_close_forms(); | |
+ | |
+ // Add the loading bar. | |
+ make_contribute_loading_screen(); | |
+ | |
+ // Let's start gathering values. | |
+ var inputs = $( '.contribute-form-parts :input' ); | |
+ | |
+ // Create the form array. | |
+ var form = {}; | |
+ inputs.each( function() { | |
+ form[ this.name ] = $( this ).val(); | |
+ }); | |
+ | |
+ // Add the action here. | |
+ form.action = 'add_parts'; | |
+ | |
+ // Make the ajax request with the form data. | |
+ $.ajax({ | |
+ url: make_gigya.ajax, | |
+ data: form, | |
+ type: 'POST', | |
+ success: function( data ){ | |
+ make_contribute_remove_progress_bar(); | |
+ $( '.parts-tools' ).show(); | |
+ $( '.parts-pane' ).empty(); | |
+ $( '.parts-pane' ).html( data ); | |
+ $( '.contribute-form-tools' ).slideDown(); | |
+ } | |
+ }); | |
+ }); | |
+ | |
+ // Save all of the tools data. | |
+ $( '.submit-tools' ).on( 'click', function( e ) { | |
+ | |
+ // Prevent the button from triggering | |
+ e.preventDefault(); | |
+ | |
+ // Disable the inputs. | |
+ make_contribute_input_disabler( 'contribute-form-tools' ); | |
+ | |
+ // Grab all of the inputs | |
+ var inputs = $( '.contribute-form-tools :input' ); | |
+ | |
+ // Hide the form | |
+ make_contribute_close_forms(); | |
+ | |
+ // Add the loading bar. | |
+ make_contribute_loading_screen(); | |
+ | |
+ // Grab all of the form data. | |
+ var form = {}; | |
+ inputs.each( function() { | |
+ form[ this.name ] = $( this ).val(); | |
+ }); | |
+ | |
+ form.action = 'add_tools'; | |
+ | |
+ // Make the ajax request with the form data. | |
+ $.ajax({ | |
+ url: make_gigya.ajax, | |
+ data: form, | |
+ type: 'POST', | |
+ success: function( data ){ | |
+ make_contribute_remove_progress_bar(); | |
+ $( '.tools-pane' ).empty(); | |
+ $( '.tools-pane' ).html( data ); | |
+ $( '#contribute-form-wrapper' ).html( '<h2>Thanks for your project submission!</h2><p>We\'ll review your project and contact you shortly</p>' ); | |
+ } | |
+ }); | |
+ }); | |
+ | |
+}); | |
+ | |
+ | |
+/** | |
+ * Displays the steps | |
+ * @param int post_id The post ID we are going to be updating the form fields to | |
+ * @return void | |
+ */ | |
+function make_contribute_display_steps( post_id ) { | |
+ var inputs = jQuery( '.contribute-form-get-steps :input' ); | |
+ | |
+ var form = { | |
+ action : 'get_steps', | |
+ post_ID: post_id, | |
+ }; | |
+ | |
+ inputs.each( function() { | |
+ form[ this.name ] = jQuery( this ).val(); | |
+ }); | |
+ | |
+ // Make the ajax request with the form data. | |
+ jQuery.ajax({ | |
+ url: make_gigya.ajax, | |
+ data: form, | |
+ type: 'POST', | |
+ success: function( data ){ | |
+ jQuery( '.saving-progress' ).html(''); | |
+ jQuery( '.steps-output' ).html( data ); | |
+ } | |
+ }); | |
+ | |
+ form.action = ''; | |
+ form.action = 'get_steps_list'; | |
+ | |
+ // Make the ajax request with the form data. | |
+ jQuery.ajax({ | |
+ url: make_gigya.ajax, | |
+ data: form, | |
+ type: 'POST', | |
+ success: function( data ){ | |
+ // Output the steps. | |
+ jQuery( '.steps-list-output' ).html( data ); | |
+ // Display the parts form. | |
+ jQuery( '.contribute-form-parts' ).slideDown(); | |
+ } | |
+ }); | |
+ | |
+} | |
+ | |
+/** | |
+ * Take the saved data, and display it on the page. | |
+ * @param obj data The data being passed back from a post save so we can inject it into the preview window | |
+ * @return void | |
+ */ | |
+function make_contribute_post_filler( data ) { | |
+ jQuery( '.post-title' ).html( data.post_title ); | |
+ jQuery( '.post-content' ).html( data.post_content ); | |
+ jQuery( '.post-content' ).append( data.media ); | |
+} | |
+ | |
+ | |
+/** | |
+ * When the forms get saved, we'll disable all inputs | |
+ * @param string form The form name we wish to disable | |
+ * @return void | |
+ */ | |
+function make_contribute_input_disabler( form ) { | |
+ // Grab the inputs | |
+ var inputs = jQuery( '.' + form + ' :input' ); | |
+ | |
+ // Disable them all. | |
+ inputs.each( function() { | |
+ jQuery( this ).prop( 'disabled', true ); | |
+ }); | |
+} | |
+ | |
+ | |
+/** | |
+ * Allows us to assign a Gigya ID so we can assign the coauthor to the contribute form | |
+ * | |
+ * @since | |
+ */ | |
+function make_contribute_add_gigya_id( uid ) { | |
+ jQuery( 'input#user_id[type="hidden"]' ).val( uid ); | |
+} | |
+ | |
+ | |
+/** | |
+ * Add some nifty loading text that is nerdy and fun | |
+ */ | |
+function make_contribute_loading_screen() { | |
+ jQuery( '.post-holder' ).fadeIn(); | |
+ | |
+ var selector = '.saving-progress'; | |
+ var time = 1500; | |
+ var text = [ | |
+ '', // Pass an empty variable here as our random number goes from 1-10 and 0 will never be called | |
+ 'Adjusting tension bolts', | |
+ 'Calculating feeds & speeds', | |
+ 'Preheating print gun', | |
+ 'Zeroing out CNC Machine...', | |
+ 'Waiting for glue to dry', | |
+ 'Energizing primary coil...', | |
+ 'Reticulating splines', | |
+ 'Rendering mesh', | |
+ 'Slicing object layer', | |
+ 'Doing science' | |
+ ]; | |
+ // Randomly get our text on each call (does it 1 - 10) | |
+ var index = Math.floor( ( Math.random() * 10 ) + 1 ); | |
+ | |
+ jQuery( selector ).html( '<h3 class="loading-text" style="text-align:center">' + text[ index ] + '</h3><div class="progress progress-striped active"><div class="bar" style="width: 100%;"></div></div>' ); | |
+ | |
+ // Change the loading text every 5 seconds | |
+ var interval_id = setInterval( function() { | |
+ // Reset the Index on each new interval | |
+ index = Math.floor( ( Math.random() * 10 ) + 1 ); | |
+ | |
+ // Only run as long as the loading text is present | |
+ if ( jQuery( '.loading-text' ).length === 1 ) { | |
+ jQuery( '.post-content' ).find( '.loading-text' ).text( text[ index ] + '...' ); | |
+ } else { | |
+ clearInterval( interval_id ); | |
+ } | |
+ }, time ); | |
+} | |
+ | |
+ | |
+/** | |
+ * Removes the saving progress bar. Wunderbar! | |
+ * @return voide | |
+ */ | |
+function make_contribute_remove_progress_bar() { | |
+ jQuery( '.saving-progress' ).html( '' ); | |
+} | |
+ | |
+ | |
+/** | |
+ * Any time we save a form, we want to force all form fields to close while saving. | |
+ * @return void | |
+ */ | |
+function make_contribute_close_forms() { | |
+ jQuery( '.contribute-form, .contribute-form-tools, .contribute-form-parts, .contribute-form-steps' ).slideUp(); | |
+} | |
\ No newline at end of file | |
Index: includes/gigya/css/login.css | |
=================================================================== | |
--- includes/gigya/css/login.css (revision 0) | |
+++ includes/gigya/css/login.css (working copy) | |
@@ -0,0 +1,252 @@ | |
+.authentication { display:none; } | |
+.login-required { | |
+ height:300px; | |
+} | |
+.gigya-screen *, div.gigya-screen, .gigya-screen span, .gigya-screen a:hover, .gigya-screen a:visited, .gigya-screen a:link, .gigya-screen a:active { | |
+ border: none; | |
+ padding: 0px; | |
+ margin: 0px; | |
+ color: inherit; | |
+ text-decoration: none; | |
+ width: auto; | |
+ float: none; | |
+ -moz-border-radius: 0; | |
+ border-radius: 0; | |
+ font-family: arial; | |
+ font-size: 12px; | |
+ color: #333333; | |
+ background: none; | |
+ text-align: left; | |
+ font-family: arial; | |
+} | |
+.gigya-screen a, .gigya-screen a:visited, .gigya-screen a:link, .gigya-screen a:active { | |
+ color: #0098ca; | |
+ text-decoration: underline; | |
+} | |
+.gigya-screen-set .gigya-screen { | |
+ margin: 0 auto; | |
+} | |
+.gigya-screen h2 { | |
+ font-size:16px; | |
+ color:#333; | |
+ font-weight: normal; | |
+} | |
+.gigya-screen a:hover { | |
+ text-decoration: none; | |
+} | |
+.gigya-screen h1 { | |
+ border-bottom: 1px solid #dbdbdb; | |
+ font-size: 16px; | |
+ font-family: Arial; | |
+ font-weight: bold; | |
+ color: #333; | |
+ padding-bottom: 5px; | |
+ margin-bottom: 45px; | |
+} | |
+.gigya-screen .gigya-layout-row { | |
+ width:100%; | |
+ zoom:1; | |
+ float:left; | |
+ display:block; | |
+} | |
+.gigya-screen .gigya-layout-cell { | |
+ float: left; | |
+ width: 50%; | |
+ margin-top: 1px; | |
+} | |
+.gigya-screen .gigya-layout-cell-right { | |
+ float: right; | |
+ width: 50%; | |
+} | |
+.gigya-screen select { | |
+ margin: 5px 0px; | |
+ padding: 5px; | |
+ border-radius: 5px; | |
+ background-color: #FFFFFF; | |
+ border: 1px solid #CCCCCC; | |
+ -moz-box-sizing: border-box; | |
+ -webkit-box-sizing: border-box; | |
+ box-sizing: border-box; | |
+ width: 100%; | |
+} | |
+.gigya-screen option { | |
+ padding: 5px; | |
+} | |
+.gigya-screen option:hover { | |
+ background-color: #3593C1; | |
+} | |
+.gigya-screen .gigya-label { | |
+ display: block; | |
+ font-weight: bold; | |
+ font-size: 12px; | |
+} | |
+.gigya-screen .gigya-required { | |
+ color: red; | |
+ font-size: 12px; | |
+ font-weight: bold; | |
+ margin-left: 5px; | |
+} | |
+.gigya-input-text, .gigya-input-password, .gigya-textarea { | |
+ -moz-box-sizing: border-box; | |
+ -webkit-box-sizing: border-box; | |
+ box-sizing: border-box; | |
+ width:100%; | |
+ margin: 5px 0px; | |
+ padding: 0 5px; | |
+ border-radius: 4px; | |
+ background-color: #FFFFFF; | |
+ border: 1px solid #CCCCCC; | |
+ color: #555555; | |
+ outline: none; | |
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05); | |
+ -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05); | |
+ -moz-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05); | |
+} | |
+.gigya-textarea { | |
+ padding: 5px; | |
+} | |
+.gigya-input-text, .gigya-input-password, .gigya-screen select, .gigya-input-submit, .gigya-input-button { | |
+ height: 28px; | |
+} | |
+.gigya-input-text:focus, .gigya-input-password:focus, .gigya-textarea:focus, .gigya-screen select:focus { | |
+ border: 1px solid #87B9EA; | |
+ outline: none; | |
+} | |
+.gigya-input-text:focus, .gigya-input-password:focus, .gigya-textarea:focus { | |
+ box-shadow: 0 0 3px #50BADE, inset 0 1px 3px rgba(0, 0, 0, .05); | |
+ -webkit-box-shadow: 0 0 3px #50BADE, inset 0 1px 3px rgba(0, 0, 0, .05); | |
+ -moz-box-shadow: 0 0 3px #50BADE, inset 0 1px 3px rgba(0, 0, 0, .05); | |
+} | |
+.gigya-input-submit, .gigya-input-button { | |
+ text-align:center; | |
+ border: 1px solid #CECECE; | |
+ cursor: pointer; | |
+ padding: 0 12px; | |
+ color: #333333; | |
+ font-weight: bold; | |
+ border-radius: 4px; | |
+ line-height: 26px; | |
+ background: #F2F2F2; | |
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFFFFF", endColorstr="#F2F2F2"); | |
+ background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#F2F2F2)); | |
+ background: -moz-linear-gradient(top, #FFFFFF, #F2F2F2); | |
+} | |
+.gigya-input-submit:hover, .gigya-input-button:hover { | |
+ background: #FFFFFF; | |
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#F2F2F2", endColorstr="#FFFFFF"); | |
+ background: -webkit-gradient(linear, left top, left bottom, from(#F2F2F2), to(#FFFFFF)); | |
+ background: -moz-linear-gradient(top, #F2F2F2, #FFFFFF); | |
+} | |
+.gigya-input-radio, .gigya-input-checkbox { | |
+ margin-right: 5px; | |
+ vertical-align: bottom; | |
+ height: 14px; | |
+ width: 14px; | |
+} | |
+input.gigya-input-text, input.gigya-input-password { | |
+ display: block; | |
+} | |
+.gigya-screen .gigya-composite-control { | |
+ padding: 5px 13px 5px 10px; | |
+} | |
+.gigya-screen .gigya-composite-control-submit, .gigya-screen .gigya-composite-control-button, .gigya-screen .gigya-composite-control-form-error { | |
+ padding-bottom:5px; | |
+ padding-right:13px; | |
+} | |
+.gigya-composite-control-multi-choice .gigya-multi-choice-item, .gigya-composite-control-checkboxes .gigya-checkboxes-item { | |
+ padding-top:5px; | |
+} | |
+.gigya-composite-control-form-error { | |
+ padding-bottom:5px; | |
+ padding-right:5px; | |
+} | |
+.gigya-screen .gigya-composite-control-submit { | |
+ text-align: right; | |
+} | |
+.gigya-screen .gigya-composite-control-label { | |
+ display:block; | |
+} | |
+.gigya-clear { | |
+ clear: both; | |
+ overflow: hidden; | |
+ font-size:0px; | |
+} | |
+.gigya-composite-control-radio label { | |
+ font-weight: normal; | |
+} | |
+.gigya-composite-control-checkbox label { | |
+ font-weight: normal; | |
+} | |
+.gigya-screen .gigya-composite-control-checkbox { | |
+ padding: 5px 10px; | |
+} | |
+.gigya-screen .gigya-composite-control-checkbox label { | |
+ display: inline; | |
+ text-indent: 10px; | |
+ margin-left: 0px; | |
+} | |
+.gigya-screen .gigya-message { | |
+ font-size:14px; | |
+ color:#333; | |
+ display: block; | |
+ text-align: center; | |
+} | |
+.gigya-screen .gigya-error-display { | |
+ display:block; | |
+ visibility:hidden; | |
+} | |
+.gigya-screen .gigya-error-display-active { | |
+ display:block; | |
+ visibility:visible; | |
+} | |
+.gigya-screen .gigya-error-msg { | |
+ line-height: 14px; | |
+ color: #dd4b39; | |
+ font-size: 11px; | |
+ display:block; | |
+ font-weight:normal; | |
+ -moz-box-sizing: border-box; | |
+ -webkit-box-sizing: border-box; | |
+ box-sizing: border-box; | |
+} | |
+.gigya-screen .gigya-form-error-msg { | |
+ _height:26px; | |
+ min-height: 26px; | |
+ line-height: 14px; | |
+ color: #dd4b39; | |
+ font-size: 11px; | |
+ text-align: center; | |
+ margin-top: 1px; | |
+ border: 1px solid #FFDCCE; | |
+ display: block; | |
+ background: #FFE7E1; | |
+ font-weight:normal; | |
+ padding:5px; | |
+ -moz-box-sizing: border-box; | |
+ -webkit-box-sizing: border-box; | |
+ box-sizing: border-box; | |
+} | |
+.gigya-screen a.gigya-composite-control-link { | |
+ display:block; | |
+ padding-left:13px; | |
+} | |
+.gigya-screen .gigya-composite-control a.gigya-composite-control-link { | |
+ display:inline; | |
+ padding:0px; | |
+} | |
+.gigya-screen .gigya-composite-control-checkbox .gigya-label, .gigya-screen .gigya-composite-control-radio .gigya-label { | |
+ font-weight:normal; | |
+} | |
+.gigya-layout-footer { | |
+ text-align:right; | |
+ clear:both; | |
+} | |
+#gigya-login-screen .gigya-composite-control-social-login, #gigya-register-screen .gigya-composite-control-social-login { | |
+ border-right: 1px solid #CCC; | |
+ height: 125px; | |
+ width:285px; | |
+ padding: 13px 38px 0 0px; | |
+} | |
+#gigya-register-screen .gigya-composite-control-social-login { | |
+ height: 240px; | |
+} | |
\ No newline at end of file | |
Index: includes/gigya/gigya.php | |
=================================================================== | |
--- includes/gigya/gigya.php (revision 0) | |
+++ includes/gigya/gigya.php (working copy) | |
@@ -0,0 +1,371 @@ | |
+<?php | |
+ | |
+/** | |
+ * Gigya! | |
+ * | |
+ * A class that will integrate all the social login fun stuff good times. | |
+ * | |
+ * Since Gigya is a third party system, we use their SDK to login users there and store information. | |
+ * All we need to do is log them into Gigya, and when all is successful and logged in, we'll create them | |
+ * a guest author account. | |
+ * | |
+ * This DOES NOT integrate into the WordPress Users database, nor can it due to VIP's global tables. | |
+ * To get around that, we'll process users into Guest Authors storing some custom information such as | |
+ * the Gigya UID and other stuff. | |
+ * | |
+ * @since SPRINT_NAME | |
+ */ | |
+ | |
+/** | |
+ * Set up some Constants | |
+ */ | |
+// The main URL to the plugin directory | |
+define( 'MAKE_GIGYA_URL', get_template_directory_uri() . '/includes/gigya' ); | |
+ | |
+// Plugin version | |
+define( 'MAKE_GIGYA_VERSION', '0.1' ); | |
+ | |
+// Gigya Public Key | |
+define( 'MAKE_GIGYA_PUBLIC_KEY', sanitize_text_field( get_option( 'make_gigya_public_key' ) ) ); | |
+ | |
+// Gigya Private Key | |
+define( 'MAKE_GIGYA_PRIVATE_KEY', sanitize_text_field( get_option( 'make_gigya_private_key' ) ) ); | |
+ | |
+ | |
+/** | |
+ * Load the Gigya Socialize SDK | |
+ * | |
+ * @since SPRINT_NAME | |
+ */ | |
+if ( ! class_exists( 'GSRequest' ) ) | |
+ include_once( 'includes/GSSDK.php' ); | |
+ | |
+/** | |
+ * Load our admin settings displayed in Settings > General | |
+ * | |
+ * @since SPRINT_NAME | |
+ */ | |
+include_once( 'includes/settings.php' ); | |
+ | |
+// Set a default timezone | |
+date_default_timezone_set( 'America/Los_Angeles' ); | |
+ | |
+/** | |
+ * The guts. | |
+ * | |
+ * This little guy controls and loads all that is Gigya. | |
+ * The namespace for this class is Make because in the future this will be expanded to other make websites. | |
+ * | |
+ * @since SPRINT_NAME | |
+ */ | |
+class Make_Gigya { | |
+ | |
+ /** | |
+ * THE CONSTRUCT. | |
+ * | |
+ * All Hooks and Filter here. | |
+ * Anything else that needs to run when the class is instantiated, place them here. | |
+ * Maybe you'll get a cake if you do. | |
+ * | |
+ * @return void | |
+ * @since SPRINT_NAME | |
+ */ | |
+ public function __construct() { | |
+ | |
+ // Load our Gigya Social SDK and configurations | |
+ add_action( 'wp_head', array( $this, 'socialize_api' ), 999 ); | |
+ | |
+ // Load our resources | |
+ add_action( 'wp_enqueue_scripts', array( $this, 'load_resources' ), 30 ); | |
+ | |
+ // Process our ajax requests. We need ajax processing for both logged in and logged out users. | |
+ // Since our login may be used by users logged into WordPress, we'll need the second option to run ajax requests. | |
+ add_action( 'wp_ajax_nopriv_make_login_user', array( $this, 'user_login' ) ); | |
+ add_action( 'wp_ajax_make_login_user', array( $this, 'user_login' ) ); | |
+ } | |
+ | |
+ | |
+ /** | |
+ * Spits out the Gigya API for the socialize features. | |
+ * Sadly, we have to manually echo this to wp_head() because Gigya requires the socialize.js API key to be passed with options wrapped in the same script tag... lame sauce. | |
+ * | |
+ * Well only enable Facebook, Twitter and Google+ as social media providers, we'll also tell Gigya to end the users session with their service after 24 hours. | |
+ * | |
+ * @return html | |
+ * @since SPRINT_NAME | |
+ */ | |
+ public function socialize_api() { ?> | |
+ <script src="http://cdn.gigya.com/JS/socialize.js?apikey=<?php echo urlencode( MAKE_GIGYA_PUBLIC_KEY ); ?>">{ enabledProviders: 'facebook,twitter,googleplus', sessionExpiration: 86400 }</script> | |
+ <?php } | |
+ | |
+ | |
+ /** | |
+ * Let's add all of our resouces to make our magic happen. | |
+ * Any scripts we should include in the footer or else things will conflict due to how we have to load the socialize API file... #facepalm | |
+ * | |
+ * @return void | |
+ * @since SPRINT_NAME | |
+ */ | |
+ public function load_resources() { | |
+ // CSS | |
+ wp_enqueue_style( 'make-login', MAKE_GIGYA_URL . '/css/login.css', null, MAKE_GIGYA_VERSION ); | |
+ | |
+ // JavaScript | |
+ wp_enqueue_script( 'make-login', MAKE_GIGYA_URL . '/js/login.js', array( 'jquery' ), MAKE_GIGYA_VERSION, true ); | |
+ wp_localize_script( 'make-login', 'make_gigya', array( | |
+ 'ajax' => esc_url( admin_url( 'admin-ajax.php' ) ), | |
+ 'loading' => 'Loading', | |
+ 'secure_it' => wp_create_nonce( 'ajax-nonce' ), | |
+ 'root_path' => esc_url( home_url( '/' ) ), | |
+ 'loggedin' => ( is_user_logged_in() ) ? 'true' : 'false', | |
+ ) ); | |
+ } | |
+ | |
+ | |
+ /** | |
+ * Process' our Gigya interactions with the database. This method will take the info processed from the Gigya JS API and pass it through to either login or log out. | |
+ * These users are created and managed through the Tools > Guest Authors. | |
+ * @return json | |
+ * | |
+ * @since SPRINT_NAME | |
+ */ | |
+ public function user_login() { | |
+ | |
+ // Check our nonce and make sure it's correct | |
+ check_ajax_referer( 'ajax-nonce', 'nonce' ); | |
+ | |
+ $uid = $_POST['object']['UID']; | |
+ | |
+ // Make sure some required fields are being passed first for security reasons | |
+ if ( isset( $_POST['request'] ) && $_POST['request'] == 'login' && wp_verify_nonce( $_POST['nonce'], 'ajax-nonce' ) ) { | |
+ | |
+ // Before we continue we must verify this request is even a valid request from Gigya | |
+ if ( $this->verify_gigya_user( $uid, $_POST['object']['signatureTimestamp'], $_POST['object']['UIDSignature'] ) ) { | |
+ | |
+ // Search for a maker and return them or else false. | |
+ $users = $this->search_for_maker( $uid, $_POST['object']['profile']['email'] ); | |
+ | |
+ // Check if a user already exists, if not we'll create one. | |
+ if ( $users ) { | |
+ | |
+ // Check if the user existed and needs to have a Gigya ID added to the post meta | |
+ if ( isset( $users['add_guid'] ) && $users['add_guid'] ) { | |
+ update_post_meta( absint( $users[0]->ID ), 'cap-guid', sanitize_text_field( $uid ) ); | |
+ } | |
+ | |
+ // mark when the user logged in | |
+ update_post_meta( absint( $users[0]->ID ), 'cap-last_login', date( 'm/d/Y g:i:s a', time() ) ); | |
+ | |
+ $results = array( | |
+ 'loggedin' => true, | |
+ 'message' => 'Login Successful!', | |
+ 'maker' => absint( $users[0]->ID ), | |
+ ); | |
+ | |
+ // User didn't exist, let's make one. | |
+ } else { | |
+ // Pass our User Info sent from Gigya | |
+ $user = ( is_array( $_POST['object']['profile'] ) ) ? $_POST['object']['profile'] : ''; | |
+ | |
+ // Create the maker and return their ID | |
+ $maker_id = $this->create_maker( $user, $uid ); | |
+ | |
+ // Report our status to pass back to the modal window | |
+ if ( is_wp_error( $maker_id ) ) { | |
+ $results = array( | |
+ 'loggedin' => false, | |
+ 'message' => 'A user account could not be created. Please try again.', | |
+ 'user' => absint( $maker_id ), | |
+ ); | |
+ } else { | |
+ $results = array( | |
+ 'loggedin' => true, | |
+ 'message' => 'User account created and logged in!', | |
+ 'maker' => absint( $maker_id ), | |
+ ); | |
+ } | |
+ } | |
+ } else { | |
+ $results = array( | |
+ 'loggedin' => false, | |
+ 'message' => 'Request could not be validated. Please try again.', | |
+ ); | |
+ } | |
+ } else { | |
+ $results = array( | |
+ 'loggedin' => false, | |
+ 'message' => 'Missing required parameters', | |
+ ); | |
+ } | |
+ | |
+ // Return our results and handle them in the Ajax callback | |
+ die( json_encode( $results ) ); | |
+ } | |
+ | |
+ | |
+ /** | |
+ * Searches the Makers lists and locates a usr based on their UID | |
+ * @param string $uid The user ID from Gigya | |
+ * @return object | |
+ * | |
+ * @since SPRINT_NAME | |
+ */ | |
+ private function search_for_maker( $uid, $email ) { | |
+ // Stick a hashed version of our usr ID for wp cache | |
+ $user_hash = md5( sanitize_text_field( $uid ) ); | |
+ | |
+ // Check if our makers are already cached. | |
+ $users = wp_cache_get( 'mf_user_' . $user_hash ); | |
+ | |
+ if ( $users == false ) { | |
+ $maker_guid_query = array( | |
+ 'post_type' => 'guest-author', | |
+ 'meta_key' => 'cap-guid', | |
+ 'meta_value' => sanitize_text_field( $uid ), | |
+ ); | |
+ $users = new WP_Query( $maker_guid_query ); | |
+ | |
+ // If a user was not found with a Gigya ID, let's check for an email | |
+ if ( empty ( $users->posts ) ) { | |
+ $maker_email_query = array( | |
+ 'post_type' => 'guest-author', | |
+ 'meta_key' => 'cap-user_email', | |
+ 'meta_value' => sanitize_email( $email ), | |
+ ); | |
+ $users = new WP_Query( $maker_email_query ); | |
+ | |
+ if ( ! empty( $users->posts ) ) | |
+ $found_with_email = true; | |
+ } | |
+ | |
+ // Save the results to the cache | |
+ wp_cache_set( 'mf_user_' . $user_hash, $users, '', 86400 ); // Since we are caching each user, might as well hold onto it for 24 hours. | |
+ | |
+ if ( isset( $found_with_email ) && $found_with_email ) | |
+ $users->posts['add_guid'] = true; | |
+ } | |
+ | |
+ return $users->posts; | |
+ } | |
+ | |
+ | |
+ /** | |
+ * Searches the Makers lists and locates a usr based on their UID. While this is similar to search_for_maker(), this has a different use case. | |
+ * We need this function for checking against already logged in users. search_for_maker() method is used primarily for logging in and pairing Gigya to an account. | |
+ * This method will specifically find an existing user by Gigya ID and return their profile object | |
+ * @param string $uid The user ID from Gigya | |
+ * @return object | |
+ * | |
+ * @since SPRINT_NAME | |
+ */ | |
+ public function search_for_maker_by_id( $uid ) { | |
+ // Stick a hashed version of our usr ID for wp cache | |
+ $user_hash = md5( sanitize_text_field( $uid ) ); | |
+ | |
+ // Check if our makers are already cached. | |
+ $user = wp_cache_get( 'mf_user_' . $user_hash ); | |
+ | |
+ if ( $user == false ) { | |
+ $maker_guid_query = array( | |
+ 'post_type' => 'guest-author', | |
+ 'meta_key' => 'cap-guid', | |
+ 'meta_value' => sanitize_text_field( $uid ), | |
+ ); | |
+ $user = new WP_Query( $maker_guid_query ); | |
+ | |
+ // Save the results to the cache | |
+ wp_cache_set( 'mf_user_' . $user_hash, $user, '', 86400 ); // Since we are caching each user, might as well hold onto it for 24 hours. | |
+ } | |
+ | |
+ return $user->posts; | |
+ } | |
+ | |
+ | |
+ /** | |
+ * Creates a new maker in the makers listings and returns the makers ID | |
+ * @param array $user The data passed from Gigya for use in the maker creation | |
+ * @return integer | |
+ */ | |
+ private function create_maker( $user, $uid ) { | |
+ | |
+ // Handle our user name | |
+ if ( ! empty( $user['firstName'] ) && ! empty( $user['lastName'] ) ) { | |
+ $user_name = $user['firstName'] . ' ' . $user['lastName']; | |
+ } elseif ( ! empty( $user['firstName'] ) && empty( $user['lastName'] ) ) { | |
+ $user_name = $user['firstName']; | |
+ } elseif ( empty( $user['firstName'] ) && empty( $user['lastName'] ) && ! empty( $user['nickname'] ) ) { | |
+ $user_name = $user['nickname']; | |
+ } else { | |
+ $user_name = 'Undefined Username'; | |
+ } | |
+ | |
+ // Our user doesn't exist, that means we need to sync them up, create a maker account and log them in. | |
+ $maker = array( | |
+ 'post_title' => sanitize_text_field( $user_name ), | |
+ 'post_status' => 'publish', | |
+ 'post_type' => 'guest-author', | |
+ 'post_name' => 'cap-' . sanitize_title( $user_name ), | |
+ ); | |
+ $maker_id = wp_insert_post( $maker ); | |
+ | |
+ // If an error happens, we want to report that back before running any post meta updates. | |
+ if ( is_wp_error( $maker_id ) ) | |
+ return 0; | |
+ | |
+ // We'll want to add some custom fields. Let's do that. | |
+ // **************************************************** | |
+ // Date Created && last logged in | |
+ update_post_meta( absint( $maker_id ), 'cap-created', date( 'm/d/Y g:i:s a', time() ) ); | |
+ update_post_meta( absint( $maker_id ), 'cap-last_login', date( 'm/d/Y g:i:s a', time() ) ); | |
+ | |
+ // Add the maker Display Name | |
+ $display_name = ( isset( $user_name ) && ! empty( $user_name ) ) ? $user_name : ''; | |
+ update_post_meta( absint( $maker_id ), 'cap-display_name', sanitize_text_field( $display_name ) ); | |
+ | |
+ // Add the makers unique slug | |
+ $slug = preg_replace( '/[^A-Za-z0-9-]+/', '-', sanitize_text_field( $display_name ) ); | |
+ update_post_meta( absint( $maker_id ), 'cap-user_login', sanitize_title_with_dashes( $slug ) ); | |
+ | |
+ // Add the makers first name | |
+ $first_name = ( isset( $user['firstName'] ) && ! empty( $user['firstName'] ) ) ? $user['firstName'] : ''; | |
+ update_post_meta( absint( $maker_id ), 'cap-first_name', sanitize_text_field( $first_name ) ); | |
+ | |
+ // Add the makers last name | |
+ $last_name = ( isset( $user['lastName'] ) && ! empty( $user['lastName'] ) ) ? $user['lastName'] : ''; | |
+ update_post_meta( absint( $maker_id ), 'cap-last_name', sanitize_text_field( $user['lastName'] ) ); | |
+ | |
+ // Add the makers email | |
+ $email = ( isset( $user['email'] ) && ! empty( $user['email'] ) ) ? $user['email'] : ''; | |
+ update_post_meta( absint( $maker_id ), 'cap-user_email', sanitize_email( $email ) ); | |
+ | |
+ // Add the maker photo | |
+ $user_photo = ( isset( $user['photoURL'] ) && ! empty( $user['photoURL'] ) ) ? $user['photoURL'] : ''; | |
+ update_post_meta( absint( $maker_id ), 'cap-photo_url', esc_url( $user_photo ) ); | |
+ | |
+ // Add the Maker Gigya ID | |
+ update_post_meta( absint( $maker_id ), 'cap-guid', sanitize_text_field( $uid ) ); | |
+ | |
+ return $maker_id; | |
+ } | |
+ | |
+ | |
+ /** | |
+ * We want to verify our Gigya interactions are valid. | |
+ * Since all interactions are via the JavaScript API, we'll need to verify these via AJAX | |
+ * @return json | |
+ * | |
+ * @since SPRINT_NAME | |
+ */ | |
+ public function verify_gigya_user( $uid, $timestamp, $sig) { | |
+ | |
+ // Validate the signature is authentic | |
+ $valid = SigUtils::validateUserSignature( sanitize_text_field( $uid ), absint( $timestamp ), MAKE_GIGYA_PRIVATE_KEY, sanitize_text_field( $sig ) ); | |
+ | |
+ if ( $valid ) { | |
+ return true; | |
+ } else { | |
+ return false; | |
+ } | |
+ } | |
+} | |
+$make_gigya = new Make_Gigya(); | |
Index: includes/gigya/images/default-profile-image.jpg | |
=================================================================== | |
Cannot display: file marked as a binary type. | |
svn:mime-type = application/octet-stream | |
Index: includes/gigya/images/default-profile-image.jpg | |
=================================================================== | |
--- includes/gigya/images/default-profile-image.jpg (revision 141566) | |
+++ includes/gigya/images/default-profile-image.jpg (working copy) | |
Property changes on: includes/gigya/images/default-profile-image.jpg | |
___________________________________________________________________ | |
Added: svn:mime-type | |
## -0,0 +1 ## | |
+application/octet-stream | |
\ No newline at end of property | |
Index: includes/gigya/includes/GSSDK.php | |
=================================================================== | |
--- includes/gigya/includes/GSSDK.php (revision 0) | |
+++ includes/gigya/includes/GSSDK.php (working copy) | |
@@ -0,0 +1,1083 @@ | |
+<?php | |
+ /* | |
+* Copyright (C) 2013 Gigya, Inc. | |
+* Version 2.15.4 | |
+* | |
+* | |
+* Gigya PHP SDK | |
+* @author Shachar Bar-David | |
+*/ | |
+ | |
+if (!function_exists('curl_init')) { | |
+ throw new Exception('Gigya.Socialize needs the CURL PHP extension.'); | |
+} | |
+if (!function_exists('json_decode')) { | |
+ throw new Exception('Gigya.Socialize needs the JSON PHP extension.'); | |
+} | |
+ | |
+ | |
+/** | |
+ * Gigya Socialize Exception | |
+ * | |
+ */ | |
+class GSException extends Exception{ | |
+ | |
+ public $errorMessage; | |
+} | |
+ | |
+/** | |
+ * Gigya Socialize Key Not Found Exception | |
+ * | |
+ */ | |
+class GSKeyNotFoundException extends GSException{ | |
+ | |
+ public function __construct($key){ | |
+ $this->errorMessage = "GSObject does not contain a value for key ".$key; | |
+ } | |
+} | |
+ | |
+ | |
+/** | |
+ * A Request to Gigya Socialize API | |
+ * | |
+ */ | |
+ | |
+class GSRequest { | |
+ private static $cafile; | |
+ const DEFAULT_API_DOMAIN = "gigya.com"; | |
+ const version = "2.15.4"; | |
+ | |
+ private $host; | |
+ private $domain; | |
+ private $path; | |
+ private $traceLog = array(); | |
+ protected $method; | |
+ private $proxy; | |
+ private $proxyType = CURLPROXY_HTTP; | |
+ private $proxyUserPass = ":"; | |
+ private $curlArray = array(); | |
+ | |
+ private $apiKey; | |
+ private $userKey; | |
+ private $secretKey; | |
+ private $params; //GSObject | |
+ private $useHTTPS; | |
+ private $apiDomain = self::DEFAULT_API_DOMAIN; | |
+ | |
+ | |
+ /** | |
+ * Constructs a request using an apiKey and secretKey. | |
+ * You must provide a user ID (UID) of the tage user. | |
+ * Suitable for calling our old REST API | |
+ * @param apiKey | |
+ * @param secretKey | |
+ * @param apiMethod the api method (including namespace) to call. for example: socialize.getUserInfo | |
+ * If namespaces is not supplied "socialize" is assumed | |
+ * @param params the request parameters | |
+ * @param useHTTPS useHTTPS set this to true if you want to use HTTPS. | |
+ * @param userKey userKey A key of an administrative user with extra permissions. | |
+ * If this parameter is provided, then the secretKey parameter is assumed to be the admin user's secret key and not the site's secret key. | |
+ */ | |
+ public function __construct($apiKey, $secretKey, $apiMethod, $params = null, $useHTTPS = false, $userKey = null ) | |
+ { | |
+ if (!isset($apiMethod) || strlen($apiMethod)==0) | |
+ return; | |
+ | |
+ if (substr($apiMethod,0,1) == "/") | |
+ $apiMethod = substr($apiMethod,1); | |
+ | |
+ if (strrpos($apiMethod,".")==0) | |
+ { | |
+ $this->domain = "socialize.gigya.com"; | |
+ $this->path = "/socialize." . $apiMethod; | |
+ } else | |
+ { | |
+ $tokens = explode(".",$apiMethod); | |
+ $this->domain = $tokens[0].".gigya.com"; | |
+ $this->path = "/".$apiMethod; | |
+ } | |
+ | |
+ $this->method = $apiMethod; | |
+ | |
+ if (empty($params)) | |
+ $this->params = new GSObject(); | |
+ else | |
+ $this->params = clone $params; | |
+ | |
+ // use "_host" to override domain, if available | |
+ $this->domain = $this->params->getString("_host", $this->domain); | |
+ | |
+ $this->useHTTPS = $useHTTPS; | |
+ | |
+ $this->apiKey = $apiKey; | |
+ $this->secretKey = $secretKey; | |
+ $this->userKey = $userKey; | |
+ | |
+ $this->traceField("apiMethod",$apiMethod); | |
+ $this->traceField("apiKey",$apiKey); | |
+ } | |
+ | |
+ public function setParam($param, $val) { | |
+ $this->params->put($param, $val); | |
+ } | |
+ | |
+ public function getParams() | |
+ { | |
+ return $this->params; | |
+ } | |
+ | |
+ /** | |
+ * Sets the domain used for making API calls. This method provides the option to override the default domain "gigya.com" and specify an alternative data center to be used. | |
+ * Parameters: | |
+ * $apiDomain - the domain of the data center to be used. For example: "eu1.gigya.com" for Europe data center. | |
+ */ | |
+ public function setAPIDomain($apiDomain) | |
+ { | |
+ if(!isset($apiDomain) || strlen($apiDomain)==0) | |
+ $this->apiDomain = self::DEFAULT_API_DOMAIN; | |
+ else | |
+ $this->apiDomain = $apiDomain; | |
+ } | |
+ | |
+ public static function setCAFile($filename) | |
+ { | |
+ GSRequest::$cafile = $filename; | |
+ } | |
+ | |
+ public function setProxy($proxy, $proxyUserPass=":", $proxyType=CURLPROXY_HTTP) | |
+ { | |
+ $this->proxy = $proxy; | |
+ $this->proxyType = $proxyType; | |
+ $this->proxyUserPass = $proxyUserPass; | |
+ $this->traceField("proxy",$proxy); | |
+ $this->traceField("proxyType",$proxyType); | |
+ $this->traceField("proxyUserPass",$proxyUserPass); | |
+ } | |
+ | |
+ public function setCurlOptionsArray($curlArray) | |
+ { | |
+ $this->curlArray = $curlArray; | |
+ $this->traceField("curlArray", $curlArray); | |
+ } | |
+ | |
+ /** | |
+ * Send the request synchronously | |
+ */ | |
+ public function send($timeout=null) | |
+ { | |
+ $format = $this->params->getString("format",null); | |
+ | |
+ if (!strrpos($this->method, ".")) { | |
+ $this->host = "socialize.".$this->apiDomain; | |
+ $this->path = "/socialize.".$this->method; | |
+ } else { | |
+ $tokens = explode( ".", $this->method ); | |
+ $this->host = $tokens[0].".".$this->apiDomain; | |
+ $this->path = "/".$this->method; | |
+ } | |
+ | |
+ //set json as default format. | |
+ if (empty($format)) | |
+ { | |
+ $format = "json"; | |
+ $this->setParam("format", $format); | |
+ } | |
+ if(!empty($timeout)) | |
+ { | |
+ $this->traceField("timeout",$timeout); | |
+ } | |
+ | |
+ if (empty($this->method) || (empty($this->apiKey) and empty($this->userKey)) ) | |
+ { | |
+ return new GSResponse($this->method,null,$this->params,400002,null,$this->traceLog); | |
+ } | |
+ | |
+ try | |
+ { | |
+ $this->setParam("httpStatusCodes", "false"); | |
+ | |
+ $this->traceField("userKey", $this->userKey); | |
+ $this->traceField("apiKey", $this->apiKey); | |
+ $this->traceField("apiMethod", $this->method); | |
+ $this->traceField("params",$this->params); | |
+ $this->traceField("useHTTPS", $this->useHTTPS); | |
+ | |
+ $responseStr = $this->sendRequest("POST", $this->host, $this->path, $this->params, $this->apiKey, $this->secretKey, $this->useHTTPS,$timeout, $this->userKey); | |
+ | |
+ return new GSResponse($this->method,$responseStr,null,0,null,$this->traceLog); | |
+ } | |
+ catch (Exception $ex) { | |
+ $errcode = 500000; | |
+ $errMsg = $ex->getMessage(); | |
+ $length = strlen("Operation timed out"); | |
+ if((substr($ex->getMessage(), 0, $length) === "Operation timed out")) | |
+ { | |
+ $errcode = 504002; | |
+ $errMsg = "Request Timeout"; | |
+ } | |
+ | |
+ return new GSResponse($this->method,null,$this->params,$errcode,$errMsg, $this->traceLog); | |
+ } | |
+ } | |
+ | |
+ private function sendRequest($method,$domain,$path,$params,$token,$secret,$useHTTPS=false,$timeout=null,$userKey=null) | |
+ { | |
+ $params->put("sdk", "php_".GSRequest::version); | |
+ //prepare query params | |
+ $protocol = $useHTTPS || empty($secret) ? "https" : "http"; | |
+ $resourceURI = $protocol."://".$domain.$path; | |
+ | |
+ //UTC timestamp. | |
+ $timestamp = (string) time(); | |
+ | |
+ //timestamp in milliseconds | |
+ $nonce = ((string)SigUtils::currentTimeMillis()).rand(); | |
+ $httpMethod = "POST"; | |
+ | |
+ if ($userKey) | |
+ { | |
+ $params->put("userKey", $userKey); | |
+ } | |
+ | |
+ if (!empty($secret)) | |
+ { | |
+ $params->put("apiKey", $token); | |
+ | |
+ $params->put("timestamp", $timestamp); | |
+ $params->put("nonce", $nonce); | |
+ | |
+ //signature | |
+ $signature = self::getOAuth1Signature($secret, $httpMethod, $resourceURI, $useHTTPS, $params); | |
+ $params->put("sig", $signature); | |
+ } | |
+ else { | |
+ $params->put("oauth_token", $token); | |
+ } | |
+ | |
+ //get rest response. | |
+ $res = $this->curl($resourceURI, $params, $timeout); | |
+ return $res; | |
+ } | |
+ | |
+ | |
+ private function curl($url, $params, $timeout=null) | |
+ { | |
+ foreach($params->getKeys() as $key) | |
+ { | |
+ $value = $params->getString($key); | |
+ $postData[$key] = $value; | |
+ } | |
+ | |
+ $qs = http_build_query($postData); | |
+ $this->traceField("URL",$url); | |
+ $this->traceField("postData",$qs); | |
+ | |
+ /* POST */ | |
+ $defaults = array( | |
+ CURLOPT_URL => $url, | |
+ CURLOPT_POST=>1, | |
+ CURLOPT_HEADER => 1, | |
+ CURLOPT_POSTFIELDS=>$qs, | |
+ CURLOPT_HTTPHEADER => array( 'Expect:'), | |
+ CURLOPT_RETURNTRANSFER => TRUE, | |
+ CURLOPT_SSL_VERIFYPEER => TRUE, | |
+ CURLOPT_SSL_VERIFYHOST => 2, | |
+ CURLOPT_CAINFO => GSRequest::$cafile , | |
+ CURLOPT_PROXY => $this->proxy, | |
+ CURLOPT_PROXYTYPE => $this->proxyType, | |
+ CURLOPT_PROXYUSERPWD => $this->proxyUserPass, | |
+ CURLOPT_TIMEOUT_MS => $timeout | |
+ ); | |
+ | |
+ $ch = curl_init(); | |
+ $mergedCurlArray = ($this->curlArray + $defaults); | |
+ | |
+ curl_setopt_array($ch, $mergedCurlArray); | |
+ | |
+ if(!$result = curl_exec($ch)) | |
+ { | |
+ $err = curl_error($ch) ; | |
+ throw new Exception($err); | |
+ } | |
+ | |
+ curl_close($ch); | |
+ | |
+ list($header, $body) = explode("\r\n\r\n", $result, 2); | |
+ $headers = explode("\r\n", $header); | |
+ foreach($headers as $value) | |
+ { | |
+ $kvp = explode(":", $value); | |
+ if($kvp[0] == "x-server") | |
+ { | |
+ $this->traceField("server",$kvp[1]); | |
+ break; | |
+ } | |
+ } | |
+ | |
+ return $body; | |
+ } | |
+ | |
+ /** | |
+ * Converts a GSObject to a query string | |
+ * @param params | |
+ * @return | |
+ */ | |
+ public static function buildQS($params) | |
+ { | |
+ $val; | |
+ $ret = ""; | |
+ foreach($params->getKeys() as $key) | |
+ { | |
+ $val = $params->getString($key); | |
+ if (isset($val)) | |
+ { | |
+ $ret .="$key=".urlencode($val); | |
+ } | |
+ $ret .='&'; | |
+ } | |
+ | |
+ $ret = rtrim($ret, "&"); | |
+ | |
+ return $ret; | |
+ } | |
+ | |
+ private static function getOAuth1Signature($key, $httpMethod, $url, $isSecureConnection, $requestParams) | |
+ { | |
+ // Create the BaseString. | |
+ $baseString = self::calcOAuth1BaseString($httpMethod, $url, $isSecureConnection, $requestParams); | |
+ return SigUtils::calcSignature($baseString,$key); | |
+ } | |
+ | |
+ private static function calcOAuth1BaseString($httpMethod, $url, $isSecureConnection, $requestParams) | |
+ { | |
+ | |
+ | |
+ $normalizedUrl = ""; | |
+ $u = parse_url($url); | |
+ $protocol = strtolower($u["scheme"]); | |
+ | |
+ if(array_key_exists('port',$u)) | |
+ { | |
+ $port = $u['port']; | |
+ } | |
+ else | |
+ $port = null; | |
+ | |
+ $normalizedUrl .= $protocol."://"; | |
+ $normalizedUrl .= strtolower($u["host"]); | |
+ | |
+ if ( $port != "" && (($protocol=="http" && $port!=80) || ($protocol=="https" && $port!=443))) | |
+ { | |
+ $normalizedUrl .= ':'.$port; | |
+ } | |
+ $normalizedUrl .= $u["path"]; | |
+ | |
+ // Create a sorted list of query parameters | |
+ $amp = ""; | |
+ $queryString = ""; | |
+ $keys = $requestParams->getKeys(); | |
+ sort($keys); | |
+ foreach($keys as $key) | |
+ { | |
+ $value = $requestParams->getString($key); | |
+ if ($value !== false && $value != "0" && empty($value)) | |
+ { | |
+ $value = ""; | |
+ } | |
+ | |
+ //curl is sending 1 and 0 when the value is boolean. | |
+ //so in order to create a valid signature we're changing false to 0 and true to 1. | |
+ if($value === false)$value = "0"; | |
+ if($value === true)$value = "1"; | |
+ $queryString .= $amp.$key."=".self::UrlEncode($value); | |
+ $amp = "&"; | |
+ } | |
+ | |
+ // Construct the base string from the HTTP method, the URL and the parameters | |
+ $baseString = strtoupper($httpMethod)."&".self::UrlEncode($normalizedUrl)."&".self::UrlEncode($queryString); | |
+ return $baseString; | |
+ | |
+ } | |
+ | |
+ public static function UrlEncode($value) | |
+ { | |
+ if ($value === false) | |
+ { | |
+ return $value; | |
+ } | |
+ else | |
+ { | |
+ return str_replace('%7E', '~', rawurlencode($value)); | |
+ } | |
+ } | |
+ | |
+ private function traceField($name,$value) | |
+ { | |
+ array_push($this->traceLog,$name."=". print_r($value, true)); | |
+ } | |
+ | |
+} | |
+ | |
+ | |
+/** | |
+ * Wraps the server's response. | |
+ * If the request was sent with the format set to "xml", the getData() will return null and you should use getResponseText() instead. | |
+ * We only parse response text into GSObject if request format is set "json" which is the default. | |
+ * | |
+ */ | |
+class GSResponse | |
+{ | |
+ private $errorCode = 0; | |
+ private $errorMessage = null; | |
+ private $rawData = ""; | |
+ private $data; //GSObject | |
+ private static $errorMsgDic; | |
+ private $params = null; | |
+ private $method = null; | |
+ private $traceLog = null; | |
+ | |
+ public static function Init(){ | |
+ self::$errorMsgDic = new GSObject(); | |
+ self::$errorMsgDic->put(400002, "Required parameter is missing"); | |
+ self::$errorMsgDic->put(500000, "General server error"); | |
+ } | |
+ | |
+ | |
+ public function getErrorCode() | |
+ { | |
+ return $this->errorCode; | |
+ } | |
+ | |
+ public function getErrorMessage() { | |
+ if (isset($this->errorMessage)) | |
+ return $this->errorMessage; | |
+ else | |
+ { | |
+ | |
+ if ($this->errorCode==0 || !self::$errorMsgDic->containsKey((int)$this->errorCode)) | |
+ return ""; | |
+ else | |
+ return self::$errorMsgDic->getString($this->errorCode); | |
+ } | |
+ } | |
+ | |
+ public function getResponseText() | |
+ { | |
+ return $this->rawData; | |
+ } | |
+ | |
+ public function getData() | |
+ { | |
+ return $this->data; | |
+ } | |
+ | |
+ /* GET BOOLEAN */ | |
+ public function getBool($key, $defaultValue=GSObject::DEFAULT_VALUE) | |
+ { | |
+ return $this->data->getBool($key,$defaultValue); | |
+ } | |
+ | |
+ /* GET INTEGER */ | |
+ public function getInt($key, $defaultValue=GSObject::DEFAULT_VALUE) | |
+ { | |
+ return $this->data->getInt($key,$defaultValue); | |
+ } | |
+ | |
+ /* GET LONG */ | |
+ public function getLong($key, $defaultValue=GSObject::DEFAULT_VALUE) | |
+ { | |
+ return $this->data->getLong($key,$defaultValue); | |
+ } | |
+ /* GET INTEGER */ | |
+ public function getDouble($key, $defaultValue=GSObject::DEFAULT_VALUE) | |
+ { | |
+ return $this->data->getDouble($key,$defaultValue); | |
+ } | |
+ | |
+ /* GET STRING */ | |
+ public function getString($key, $defaultValue=GSObject::DEFAULT_VALUE) | |
+ { | |
+ return $this->data->getString($key,$defaultValue); | |
+ } | |
+ | |
+ /* GET GSOBJECT */ | |
+ public function getObject($key) | |
+ { | |
+ return $this->data->getObject($key); | |
+ } | |
+ | |
+ /* GET GSOBJECT[] */ | |
+ public function getArray($key) | |
+ { | |
+ return $this->data->getArray($key); | |
+ } | |
+ | |
+ | |
+ /* C'tor */ | |
+ public function __construct($method,$responseText=null,$params=null,$errorCode=null,$errorMessage=null,$traceLog=null) | |
+ { | |
+ | |
+ $this->traceLog = $traceLog; | |
+ $this->method = $method; | |
+ if(empty($params)) | |
+ $this->params = new GSObject(); | |
+ else | |
+ $this->params=$params; | |
+ | |
+ if(!empty($responseText)) | |
+ { | |
+ $this->rawData = $responseText; | |
+ if(strpos(ltrim($responseText),"{") !== false) | |
+ { | |
+ | |
+ $this->data = new GSObject($responseText); | |
+ if(isset($this->data)) | |
+ { | |
+ if ($this->data->containsKey("errorCode")) | |
+ { | |
+ $this->errorCode = $this->data->getInt("errorCode"); | |
+ } | |
+ if ($this->data->containsKey("errorMessage")) | |
+ { | |
+ $this->errorMessage = $this->data->getString("errorMessage"); | |
+ } | |
+ } | |
+ } | |
+ else | |
+ { | |
+ $matches= array(); | |
+ preg_match("~<errorCode\s*>([^<]+)~", $this->rawData, $matches); | |
+ if(sizeof($matches)>0) | |
+ { | |
+ $errCodeStr = $matches[1]; | |
+ if ($errCodeStr!=null) | |
+ { | |
+ $this->errorCode = (int)$errCodeStr; | |
+ | |
+ $matches= array(); | |
+ preg_match("~<errorMessage\s*>([^<]+)~", $this->rawData, $matches); | |
+ if(sizeof($matches)>0){ | |
+ $this->errorMessage = $matches[1]; | |
+ } | |
+ } | |
+ } | |
+ } | |
+ | |
+ } | |
+ else{ | |
+ | |
+ $this->errorCode = $errorCode; | |
+ $this->errorMessage = $errorMessage != null ? $errorMessage : self::getErrorMessage(); | |
+ $this->populateClientResponseText(); | |
+ } | |
+ } | |
+ | |
+ private function populateClientResponseText() | |
+ { | |
+ if ($this->params->getString("format","json")) | |
+ { | |
+ $this->rawData = "{errorCode:" . $this->errorCode . ",errorMessage:\"" . $this->errorMessage . "\"}"; | |
+ } | |
+ else | |
+ { | |
+ $sb = array( | |
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>" | |
+ ,"<".$this->method."Response xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:com:gigya:api http://socialize-api.gigya.com/schema\" xmlns=\"urn:com:gigya:api\">" | |
+ ,"<errorCode>".$this->errorCode."</errorCode>" | |
+ ,"<errorMessage>".$this->errorMessage."</errorMessager>" | |
+ ,"</".$this->method."Response>" | |
+ ); | |
+ | |
+ | |
+ $this->rawData = implode("\r\n",$sb); | |
+ } | |
+ } | |
+ | |
+ public function getLog() | |
+ { | |
+ return implode("\r\n",$this->traceLog); | |
+ } | |
+ | |
+ | |
+ public function __toString() | |
+ { | |
+ $sb = ""; | |
+ $sb .= "\terrorCode:"; | |
+ $sb .= $this->errorCode; | |
+ $sb .= "\n\terrorMessage:"; | |
+ $sb .= $this->errorMessage; | |
+ $sb .= "\n\tdata:"; | |
+ $sb .= $this->data; | |
+ return $sb; | |
+ } | |
+} | |
+GSResponse::Init(); | |
+ | |
+ | |
+/** | |
+ * Used for passing parameters when issueing requests e.g. GSRequest.send | |
+ * As well as returning response data e.g. GSResponse.getData | |
+* @version 1.0 | |
+*/ | |
+ | |
+class GSObject { | |
+ private $map; | |
+ | |
+ /* PUBLIC INTERFACE */ | |
+ /** | |
+ * Construct a GSObject from json string, throws excpetion. | |
+ * @param json the json formatted string | |
+ * @throws Exception if unable to parse json | |
+ */ | |
+ public function __construct($json=null) | |
+ { | |
+ $this->map = array(); | |
+ if(!empty($json)){ | |
+ | |
+ //parse json string. | |
+ if(gettype($json) == 'string') | |
+ { | |
+ $obj = json_decode($json,false); | |
+ | |
+ | |
+ if($obj == null){ | |
+ throw new GSException(); | |
+ } | |
+ } | |
+ else | |
+ { | |
+ $obj = $json; | |
+ } | |
+ | |
+ self::processJsonObject($obj,$this); | |
+ } | |
+ } | |
+ | |
+ public function serialize() | |
+ { | |
+ $arr = Array(); | |
+ if(empty($this->map))return $arr; | |
+ | |
+ $arr = $this->serializeGSObject($this); | |
+ | |
+ return $arr; | |
+ } | |
+ | |
+ public static function serializeGSObject($gsd) | |
+ { | |
+ $arr = Array(); | |
+ foreach ($gsd->map as $name=>$value) { | |
+ | |
+ $val = GSObject::serializeValue($value); | |
+ $arr[$name] = $val; | |
+ } | |
+ return $arr; | |
+ } | |
+ | |
+ | |
+ | |
+ public static function serializeValue($value) | |
+ { | |
+ | |
+ //GSDictionary | |
+ if($value instanceof GSObject){ | |
+ return GSObject::serializeGSObject($value); | |
+ } | |
+ | |
+ //array | |
+ else if($value instanceof GSArray){ | |
+ return GSArray::serializeGSArray($value); | |
+ } | |
+ | |
+ //else just add | |
+ else{ | |
+ return $value; | |
+ } | |
+ } | |
+ | |
+ | |
+ /* Put */ | |
+ const DEFAULT_VALUE = '@@EMPTY@@'; | |
+ | |
+ public function put($key,$value) | |
+ { | |
+ $this->map[$key] = $value; | |
+ } | |
+ | |
+ | |
+ private function get($key,$defaultValue) | |
+ { | |
+ if (array_key_exists($key, $this->map)) { | |
+ return $this->map[$key]; | |
+ } | |
+ | |
+ if($defaultValue !== GSObject::DEFAULT_VALUE) | |
+ { | |
+ return $defaultValue; | |
+ } | |
+ throw new GSKeyNotFoundException($key); | |
+ } | |
+ | |
+ /* GET BOOLEAN */ | |
+ public function getBool($key, $defaultValue=GSObject::DEFAULT_VALUE) | |
+ { | |
+ return (bool)$this->get($key,$defaultValue); | |
+ } | |
+ | |
+ /* GET INTEGER */ | |
+ public function getInt($key, $defaultValue=GSObject::DEFAULT_VALUE) | |
+ { | |
+ return (int)$this->get($key,$defaultValue); | |
+ } | |
+ | |
+ /* GET LONG */ | |
+ public function getLong($key, $defaultValue=GSObject::DEFAULT_VALUE) | |
+ { | |
+ return (float)$this->get($key,$defaultValue); | |
+ } | |
+ | |
+ /* GET DOUBLE */ | |
+ public function getDouble($key, $defaultValue=GSObject::DEFAULT_VALUE) | |
+ { | |
+ return (double)$this->get($key,$defaultValue); | |
+ } | |
+ | |
+ /* GET STRING */ | |
+ public function getString($key, $defaultValue=GSObject::DEFAULT_VALUE) | |
+ { | |
+ $obj = $this->get($key,$defaultValue); | |
+ return (string)$obj; | |
+ } | |
+ | |
+ /* GET GSOBJECT */ | |
+ public function getObject($key) | |
+ { | |
+ return (object)$this->get($key,null); | |
+ } | |
+ | |
+ /* GET GSOBJECT[] */ | |
+ public function getArray($key) | |
+ { | |
+ return $this->get($key,null); | |
+ } | |
+ | |
+ /** | |
+ * Parse parameters from URL into the dictionary | |
+ * @param url | |
+ */ | |
+ public function parseURL($url) | |
+ { | |
+ try { | |
+ $u = parse_url($url); | |
+ if(isset($u["query"])) | |
+ $this->parseQueryString($u["query"]); | |
+ if(isset($u["fragment"])) | |
+ $this->parseQueryString($u["fragment"]); | |
+ } catch (Exception $e) { | |
+ } | |
+ } | |
+ | |
+ | |
+ /** | |
+ * Parse parameters from query string | |
+ * @param qs | |
+ */ | |
+ public function parseQueryString($qs) | |
+ { | |
+ if (!isset($qs)) return; | |
+ parse_str($qs, $this->map); | |
+ } | |
+ | |
+ public function containsKey($key) | |
+ { | |
+ return array_key_exists($key, $this->map); | |
+ } | |
+ | |
+ public function remove($key) | |
+ { | |
+ unset($this->map[$key]); | |
+ } | |
+ | |
+ public function clear() | |
+ { | |
+ unset($this->map); | |
+ $this->map = array(); | |
+ } | |
+ | |
+ public function getKeys(){ | |
+ return array_keys($this->map); | |
+ } | |
+ | |
+ public function __toString() { | |
+ return $this->toJsonString(); | |
+ } | |
+ | |
+ public function toString() { | |
+ return $this->toJsonString(); | |
+ } | |
+ | |
+ public function toJsonString() | |
+ { | |
+ try { | |
+ return json_encode($this->serialize()); | |
+ } catch (Exception $e) | |
+ { | |
+ return null; | |
+ } | |
+ } | |
+ | |
+ private static function processJsonObject($jo, $parentObj) | |
+ { | |
+ if(!empty($jo)) | |
+ foreach ($jo as $name=>$value) { | |
+ | |
+ | |
+ //array | |
+ if(is_array(($value))) | |
+ { | |
+ $parentObj->put($name, new GSArray($value)); | |
+ } | |
+ //object | |
+ elseif (is_object($value)) | |
+ { | |
+ | |
+ $childObj = new GSObject(); | |
+ $parentObj->put($name, $childObj); | |
+ self::processJsonObject($value, $childObj); | |
+ | |
+ | |
+ } | |
+ //primitive | |
+ else{ | |
+ $parentObj->put($name, $value); | |
+ } | |
+ } | |
+ | |
+ return $parentObj; | |
+ | |
+ } | |
+ | |
+} | |
+ | |
+ | |
+class GSArray{ | |
+ private $map; | |
+ const NO_INDEX_EX = "GSArray does not contain a value at index "; | |
+ | |
+ public function __construct($value=null) | |
+ { | |
+ $this->map = array(); | |
+ if(!empty($value)){ | |
+ $obj = $value; | |
+ | |
+ //parse json string. | |
+ if(gettype($value) == 'string') | |
+ { | |
+ $obj = json_decode($value,false); | |
+ | |
+ if($obj == null){ | |
+ throw new GSException(); | |
+ } | |
+ } | |
+ | |
+ $this->processJsonObject($obj,$this); | |
+ } | |
+ } | |
+ | |
+ private static function processJsonObject($value,$gsarr) | |
+ { | |
+ if(!empty($value)){ | |
+ foreach($value as $val) | |
+ { | |
+ if ($val == null) | |
+ { | |
+ $gsarr->add($val); | |
+ } | |
+ elseif (is_object($val)) | |
+ { | |
+ $gsobj = new GSObject($val); | |
+ $gsarr->add($gsobj); | |
+ } | |
+ else if(is_array(($val))) | |
+ { | |
+ $newGsarr = new GSArray($val); | |
+ $gsarr->add($newGsarr); | |
+ } | |
+ else | |
+ { | |
+ $gsarr->add($val); | |
+ } | |
+ } | |
+ } | |
+ } | |
+ | |
+ public function add($value){ | |
+ array_push($this->map, $value); | |
+ } | |
+ | |
+ public function getString($inx){ | |
+ $obj = $this->map[$inx]; | |
+ if ($obj === null) | |
+ return null; | |
+ else | |
+ return strval($obj); | |
+ } | |
+ | |
+ public function getBool($inx){ | |
+ $obj = $this->map[$inx]; | |
+ if ($obj === null) | |
+ throw new Exception(GSArray::NO_INDEX_EX+$inx); | |
+ | |
+ if (is_bool($obj)) | |
+ { | |
+ return (Boolean)$obj; | |
+ } else | |
+ { | |
+ $val = strtolower(strval($obj)); | |
+ return $val == "true" || $val == "1"; | |
+ } | |
+ } | |
+ | |
+ public function getInt($inx){ | |
+ | |
+ $obj = $this->map[$inx]; | |
+ if ($obj === null) | |
+ throw new Exception(GSArray::NO_INDEX_EX+$inx); | |
+ | |
+ if (is_int($obj)) | |
+ { | |
+ return (int)$obj; | |
+ } else | |
+ { | |
+ return intval($this->getString($inx)); | |
+ } | |
+ } | |
+ | |
+ public function getLong($inx){ | |
+ $obj = $this->map[$inx]; | |
+ if ($obj === null) | |
+ throw new Exception(GSArray::NO_INDEX_EX+$inx); | |
+ | |
+ if (is_float($obj)) | |
+ { | |
+ return (float)$obj; | |
+ } else | |
+ { | |
+ return floatval($this->getString($inx)); | |
+ } | |
+ } | |
+ | |
+ public function getDouble($inx){ | |
+ $obj = $this->map[$inx]; | |
+ if ($obj === null) | |
+ throw new Exception(GSArray::NO_INDEX_EX+$inx); | |
+ | |
+ if (is_double($obj)) | |
+ { | |
+ return (double)$obj; | |
+ } else | |
+ { | |
+ return doubleval($this->getString($inx)); | |
+ } | |
+ } | |
+ | |
+ public function getObject($inx){ | |
+ return $this->map[$inx]; | |
+ } | |
+ | |
+ public function getArray($inx){ | |
+ return $this->map[$inx]; | |
+ } | |
+ | |
+ public function length(){ | |
+ return sizeof($this->map); | |
+ } | |
+ | |
+ | |
+ public function __toString() { | |
+ return $this->toJsonString(); | |
+ } | |
+ | |
+ public function toString() { | |
+ return $this->toJsonString(); | |
+ } | |
+ | |
+ public function toJsonString() | |
+ { | |
+ try { | |
+ return json_encode($this->serialize()); | |
+ } catch (Exception $e) | |
+ { | |
+ return null; | |
+ } | |
+ } | |
+ public function serialize() | |
+ { | |
+ $arr = Array(); | |
+ if(empty($this->map))return $arr; | |
+ | |
+ $arr = GSArray::serializeGSArray($this); | |
+ | |
+ return $arr; | |
+ } | |
+ | |
+ public static function serializeGSArray($gsarr){ | |
+ $arr = Array(); | |
+ for($i=0; $i < $gsarr->length(); $i++) { | |
+ | |
+ $val = $gsarr->getObject($i); | |
+ $val = GSObject::serializeValue($val); | |
+ array_push($arr,$val); | |
+ } | |
+ return $arr; | |
+ } | |
+} | |
+ | |
+ | |
+ | |
+class SigUtils | |
+{ | |
+ public static function validateUserSignature($UID, $timestamp, $secret, $signature) | |
+ { | |
+ $baseString = $timestamp."_".$UID; | |
+ $expectedSig = self::calcSignature($baseString, $secret); | |
+ return $expectedSig == $signature; | |
+ } | |
+ | |
+ public static function validateFriendSignature($UID, $timestamp, $friendUID, $secret, $signature) | |
+ { | |
+ $baseString = $timestamp."_".$friendUID."_".$UID; | |
+ $expectedSig = self::calcSignature($baseString, $secret); | |
+ return $expectedSig == $signature; | |
+ } | |
+ | |
+ static function currentTimeMillis() | |
+ { | |
+ // get utc time in ms | |
+ list( $msecs, $uts ) = explode( ' ', microtime()); | |
+ return floor(($uts+$msecs)*1000); | |
+ } | |
+ | |
+ public static function getDynamicSessionSignature($glt_cookie, $timeoutInSeconds, $secret) | |
+ { | |
+ // cookie format: | |
+ // <expiration time in unix time format>_BASE64(HMACSHA1(secret key, <login token>_<expiration time in unix time format>)) | |
+ $expirationTimeUnixMS = (SigUtils::currentTimeMillis()/1000) + $timeoutInSeconds; | |
+ $expirationTimeUnix = (string)floor($expirationTimeUnixMS); | |
+ $unsignedExpString = $glt_cookie . "_" . $expirationTimeUnix; | |
+ $signedExpString = SigUtils::calcSignature($unsignedExpString, $secret); // sign the base string using the secret key | |
+ | |
+ $ret = $expirationTimeUnix . '_' . $signedExpString; // define the cookie value | |
+ | |
+ return $ret; | |
+ } | |
+ | |
+ static function calcSignature($baseString,$key) | |
+ { | |
+ $baseString = utf8_encode($baseString); | |
+ $rawHmac = hash_hmac("sha1", utf8_encode($baseString), base64_decode($key), true); | |
+ $signature = base64_encode($rawHmac); | |
+ return $signature; | |
+ } | |
+} | |
+?> | |
Index: includes/gigya/includes/settings.php | |
=================================================================== | |
--- includes/gigya/includes/settings.php (revision 0) | |
+++ includes/gigya/includes/settings.php (working copy) | |
@@ -0,0 +1,77 @@ | |
+<?php | |
+ | |
+/** | |
+ * This file contains all the fun stuff that is added to the WordPress Settings screen | |
+ * This will allow us to store and pass our Gigya public and private keys (which we don't we available publicly, so we'll save them to the database) | |
+ * | |
+ * @since HAL 9000 | |
+ */ | |
+ | |
+ | |
+/** | |
+ * Adds a new section on to Settings > General screen | |
+ * This section will allow us to add the fields needed for passing our Gigya public and private keys and store them in the DB. | |
+ * @return void | |
+ * | |
+ * @since HAL 9000 | |
+ */ | |
+function make_gigya_init_settings() { | |
+ | |
+ // Define our settings section | |
+ add_settings_section( 'make_gigya_settings_section', 'Gigya Settings', 'make_gigya_settings_description', 'general' ); | |
+ | |
+ // Define our actual settings and asign them to the settings section | |
+ add_settings_field( 'make_gigya_public_key', 'API Key', 'make_gigya_text_field', 'general', 'make_gigya_settings_section', array( | |
+ 'name' => 'make_gigya_public_key', | |
+ 'id' => 'make_gigya_public_key', | |
+ ) ); | |
+ add_settings_field( 'make_gigya_private_key', 'Secret Key', 'make_gigya_text_field', 'general', 'make_gigya_settings_section', array( | |
+ 'name' => 'make_gigya_private_key', | |
+ 'id' => 'make_gigya_private_key', | |
+ ) ); | |
+ | |
+ // Now we need to register our settings | |
+ register_setting( 'general', 'make_gigya_public_key', 'make_gigya_sanitize_input' ); | |
+ register_setting( 'general', 'make_gigya_private_key', 'make_gigya_sanitize_input' ); | |
+} | |
+add_action( 'admin_init', 'make_gigya_init_settings' ); | |
+ | |
+ | |
+/** | |
+ * The callback function to the settings section set in make_gigya_init_settings() | |
+ * @return string | |
+ * | |
+ * @since HAL 9000 | |
+ */ | |
+function make_gigya_settings_description() { | |
+ echo '<p>The place where all the cool kids store their Gigya API keys :D</p>'; | |
+} | |
+ | |
+ | |
+/** | |
+ * A generic function that will output a text field | |
+ * To customize, add a name and id to the add_settings_field array arguments | |
+ * @param array $args The arguments passed from add_settings_field() | |
+ * @return string | |
+ * | |
+ * @since HAL 9000 | |
+ */ | |
+function make_gigya_text_field( $args ) { | |
+ $value = get_option( esc_attr( $args['name'] ) ); | |
+ | |
+ echo '<input type="text" name="' . esc_attr( $args['name'] ) . '" id="' . esc_attr( $args['id'] ) . '" class="regular-text" value="' . ( ! empty( $value ) ? esc_attr( $value ) : '' ) . '" />'; | |
+} | |
+ | |
+ | |
+/** | |
+ * Sanitizes user input in the gigya public and private keys | |
+ * @param string $input The value passed through the form | |
+ * @return string | |
+ * | |
+ * @since HAL 9000 | |
+ */ | |
+function make_gigya_sanitize_input( $input ) { | |
+ $input = sanitize_text_field( $input ); | |
+ | |
+ return $input; | |
+} | |
\ No newline at end of file | |
Index: includes/gigya/js/login.js | |
=================================================================== | |
--- includes/gigya/js/login.js (revision 0) | |
+++ includes/gigya/js/login.js (working copy) | |
@@ -0,0 +1,180 @@ | |
+/** | |
+ * This script contains all the JavaScript that controls or interfaces with the socialize features of Gigya (AKA Facebook, Twitter, etc etc logins) | |
+ * To hit our deadline for Maker Faire Bay Area, we need to rely on the JavaScript SDK from Gigya. | |
+ * A server-side SDK is preferred, but a new spec and time is needed to be done to do so. | |
+ * | |
+ * @since SPRINT_NAME | |
+ */ | |
+ | |
+// Set debugging mode. | |
+var gigya_debug = true; | |
+ | |
+jQuery( document ).ready(function() { | |
+ | |
+ // Return our makers information. If a session is not found, Gigya will report back with an error and handled in the callback. | |
+ gigya.accounts.getAccountInfo({ callback: make_is_logged_in }); | |
+ | |
+ // Listen for a click event to open the login screen | |
+ jQuery( document ).on( 'click', '.user-creds.signin', function( e ) { | |
+ e.preventDefault(); | |
+ | |
+ gigya.accounts.showScreenSet({ | |
+ screenSet: 'Login-web', | |
+ mobileScreenSet: 'Login-mobile' | |
+ }); | |
+ }); | |
+ | |
+ // Listen for a click event to open the register screen | |
+ jQuery( document ).on( 'click', '.user-creds.join', function( e ) { | |
+ e.preventDefault(); | |
+ | |
+ gigya.accounts.showScreenSet({ | |
+ screenSet: 'makezine-login', | |
+ mobileScreenSet: 'makezine-mobile-login', | |
+ startScreen: 'gigya-register-screen' | |
+ }); | |
+ }); | |
+ | |
+ // Check that we aren't dealing with a logged in WP user, if not, log them out of Gigya. | |
+ if ( make_gigya.loggedin ) { | |
+ jQuery( document ).on( 'click', '.user-creds.signout', function( e ) { | |
+ e.preventDefault(); | |
+ | |
+ if ( gigya_debug ) | |
+ console.log( 'Logout Started' ); | |
+ | |
+ gigya.accounts.logout(); | |
+ }); | |
+ } | |
+}); | |
+ | |
+ | |
+/** | |
+ * The Gigya service generates several global application events for various situations that are driven by user interactions. | |
+ * Global application events are fired whenever the event to which they refer occurs, regardless of what was the action that triggered the event. | |
+ * This method allows setting event handlers for each of the supported global events. | |
+ * @url http://developers.gigya.com/020_Client_API/020_Accounts/accounts.addEventHandlers | |
+ * | |
+ * @since SPRINT_NAME | |
+ */ | |
+gigya.accounts.addEventHandlers({ // | |
+ onLogin: make_on_login, | |
+ onLogout: make_on_logout | |
+}); | |
+ | |
+ | |
+/** | |
+ * Event handler of socialize. | |
+ * http://developers.gigya.com/020_Client_API/010_Socialize/socialize.addEventHandlers#section_1 | |
+ * | |
+ * NOTE: It is important to use the REST API for logging in or registering users http://developers.gigya.com/037_API_reference/010_Socialize | |
+ * | |
+ * @param object eventObj The event object? | |
+ * @since SPRINT_NAME | |
+ */ | |
+function make_on_login( eventObj ) { | |
+ if ( gigya_debug ) | |
+ console.log( 'Logged in to Gigya!' ); | |
+ | |
+ // Send our data via Ajax to the server to verify if the user is a returning user or a new one and create their profile. | |
+ jQuery.ajax({ | |
+ type: 'POST', | |
+ dataType: 'json', | |
+ url: make_gigya.ajax, | |
+ xhrFields: { | |
+ withCredentials: true | |
+ }, | |
+ data: { | |
+ 'action' : 'make_login_user', // Calls our wp_ajax_nopriv_make_ajax_login or wp_ajax_make_ajax_login actions | |
+ 'request' : 'login', | |
+ 'object' : eventObj, | |
+ 'nonce' : make_gigya.secure_it | |
+ }, | |
+ success: function( results ) { | |
+ if ( gigya_debug ) | |
+ console.log( results.message ); | |
+ | |
+ // Check that everything went well | |
+ if ( results.loggedin === true ) { | |
+ document.location = make_gigya.root_path + 'contribute'; | |
+ } else { | |
+ // We may have logged into Gigya, but something happened on our end. Let's correct Gigya. | |
+ gigya.accounts.logout(); | |
+ | |
+ alert( 'Something went wrong and we couldn\'t log you in. Please try again.' ); | |
+ } | |
+ | |
+ }, | |
+ error: function( jqXHR, textStatus, errorThrown ) { | |
+ if ( gigya_debug ) { | |
+ console.log( 'ERROR' ); | |
+ console.log( textStatus ); | |
+ console.log( errorThrown ); | |
+ } | |
+ }, | |
+ complete: function( jqXHR, textStatus ) { | |
+ if ( gigya_debug ) | |
+ console.log( 'Login Complete.' ); | |
+ } | |
+ }); | |
+} | |
+ | |
+ | |
+/** | |
+ * onLogout Event handler | |
+ * After we have successfully logged out, we'll redirect to the homepage. | |
+ * | |
+ * @since SPRINT_NAME | |
+ */ | |
+function make_on_logout() { | |
+ if ( gigya_debug ) | |
+ console.log( 'User logged out' ); | |
+ | |
+ // Redirect back to the homepage | |
+ document.location = make_gigya.root_path; | |
+} | |
+ | |
+ | |
+/** | |
+ * Checks if gigya returned a user account and verifies the signature for additional security | |
+ * @param object maker The object returned by gigya.accounts.getAccountInfo() | |
+ * @return mixed | |
+ * | |
+ * @since SPRINT_NAME | |
+ */ | |
+function make_is_logged_in( maker ) { | |
+ if ( gigya_debug ) { | |
+ console.log( maker ); | |
+ | |
+ if ( make_gigya.loggedin === 'false' ) { | |
+ console.log( 'WP not logged in' ); | |
+ } else { | |
+ console.log( 'WP logged in' ); | |
+ } | |
+ } | |
+ | |
+ if ( make_gigya.loggedin === 'true' || maker.errorCode === 0 ) { | |
+ if ( gigya_debug ) | |
+ console.log( 'User Logged In.' ); | |
+ | |
+ // We only want to provide a sign out feature for Gigya users | |
+ var signout = ( make_gigya.loggedin === 'false' ) ? '<a href="#signout" class="user-creds signout">Sign Out</a> / ' : ''; | |
+ | |
+ jQuery( '.main-header' ).find( '.row' ).append( '<div class="login-wrapper">' + signout + '<a href="' + make_gigya.root_path + 'contribute" class="user-creds profile">Contribute</a></div>' ); | |
+ | |
+ // Display our content | |
+ jQuery( '.container.authentication' ).show(); | |
+ | |
+ // Append the Gigya UID to the contribute form | |
+ if ( make_gigya.loggedin === 'false' ) | |
+ make_contribute_add_gigya_id( maker.UID ); | |
+ } else { | |
+ if ( gigya_debug ) | |
+ console.log( 'User Not Logged In.' ); | |
+ | |
+ // Add our login/register links | |
+ jQuery( '.main-header' ).find( '.row' ).append( '<div class="login-wrapper"><a href="#signin" class="user-creds signin">Sign In</a> / <a href="#join" class="user-creds join">Join</a></div>' ); | |
+ | |
+ jQuery( '.container.authentication' ).html( '<div class="row"><div class="span12 login-required"><h2>You must be logged in to access this area. Please <a href="#signin" class="user-creds signin">Sign In</a> or <a href="#join" class="user-creds join">Join</a>.</h2></div></div>' ).show(); | |
+ } | |
+} | |
Index: includes/maker-profile/includes/meta-boxes.php | |
=================================================================== | |
--- includes/maker-profile/includes/meta-boxes.php (revision 0) | |
+++ includes/maker-profile/includes/meta-boxes.php (working copy) | |
@@ -0,0 +1,75 @@ | |
+<?php | |
+ | |
+/** | |
+ * While guest-authors is defiend by CoAuthors Plus, we need to integrate some extra info | |
+ * To better cater to our custom user login interface. | |
+ * | |
+ * @since SPRINT_NAME | |
+ */ | |
+ | |
+/** | |
+ * Add custom meta boxes to the edit screen of Guest Authors | |
+ * @return void | |
+ * | |
+ * @since SPRINT_NAME | |
+ */ | |
+function make_guest_author_meta_boxes() { | |
+ add_meta_box( 'make_ga_custom_fieldds', 'Additional Info', 'make_guest_authors_custom_fields', 'guest-author', 'normal', 'low' ); | |
+} | |
+add_action( 'add_meta_boxes', 'make_guest_author_meta_boxes' ); | |
+ | |
+ | |
+/** | |
+ * Displays random, additional information for makers accounts | |
+ * IE. Gigya ID, Last Logged in, Date Created on Gigya, etc etc | |
+ * @param object $guest_authors Post object | |
+ * @return html | |
+ * | |
+ * @since SPRINT_NAME | |
+ */ | |
+function make_guest_authors_custom_fields( $guest_author ) { | |
+ $guid = get_post_meta( absint( $guest_author->ID ), 'cap-guid', true ); | |
+ $last_login = get_post_meta( absint( $guest_author->ID ), 'cap-last_login', true ); | |
+ $created = get_post_meta( absint( $guest_author->ID ), 'cap-created', true ); ?> | |
+ <table class="form-table"> | |
+ <tbody> | |
+ <tr> | |
+ <th><label for="cap-guid">Gigya ID</label></th> | |
+ <td><input type="text" name="cap-guid" value="<?php echo ( ! empty( $guid ) ) ? sanitize_text_field( $guid ) : ''; ?>" class="regular-text"></td> | |
+ </tr> | |
+ <tr> | |
+ <th><label for="cap-last_login">Last Login</label></th> | |
+ <td><input type="text" name="cap-last_login" value="<?php echo ( ! empty( $last_login ) ) ? sanitize_text_field( $last_login ) : ''; ?>" class="regular-text" disabled="disabled"></td> | |
+ </tr> | |
+ <tr> | |
+ <th><label for="cap-created">Date Created (via Gigya)</label></th> | |
+ <td><input type="text" name="cap-created" value="<?php echo ( ! empty( $created ) ) ? sanitize_text_field( $created ) : ''; ?>" class="regular-text" disabled="disabled"></td> | |
+ </tr> | |
+ </tbody> | |
+ </table> | |
+ <?php wp_nonce_field( 'save_guest_author_custom_fields', 'ga_custom_fields' ); | |
+} | |
+ | |
+ | |
+/** | |
+ * Save our custom Guest Author meta boxes | |
+ * @param integer $id The post ID | |
+ * @return void | |
+ * | |
+ * @since SPRINT_NAME | |
+ */ | |
+function make_guest_authors_save( $id ) { | |
+ | |
+ // Make sure we are only saving Guest Authors | |
+ if ( get_post_type() == 'guest-author' ) | |
+ return; | |
+ | |
+ if ( ! isset( $_POST['ga_custom_fields'] ) || ! wp_verify_nonce( $_POST['ga_custom_fields'], 'save_guest_author_custom_fields' ) ) | |
+ return; | |
+ | |
+ if ( isset( $_POST['cap-guid'] ) ) | |
+ update_post_meta( absint( $id ), 'cap-guid', sanitize_text_field( $_POST['cap-guid'] ) ); | |
+ | |
+ // We never want to allow updating of last login and creation dates manually, only systematically. | |
+} | |
+add_action( 'save_post', 'make_guest_authors_save' ); | |
\ No newline at end of file | |
Index: includes/maker-profile/maker-profile.php | |
=================================================================== | |
--- includes/maker-profile/maker-profile.php (revision 0) | |
+++ includes/maker-profile/maker-profile.php (working copy) | |
@@ -0,0 +1,6 @@ | |
+<?php | |
+ | |
+ | |
+// TODO - Continue building the user profile interface | |
+ | |
+include_once( 'includes/meta-boxes.php' ); | |
\ No newline at end of file | |
Index: includes/post-types/newsletter.php | |
=================================================================== | |
--- includes/post-types/newsletter.php (revision 141566) | |
+++ includes/post-types/newsletter.php (working copy) | |
@@ -107,10 +107,10 @@ | |
$dropdown_args['post_status'] = array('publish', 'draft', 'pending', 'future', 'private'); | |
return $dropdown_args; | |
} | |
- | |
-add_filter( 'page_attributes_dropdown_pages_args', 'make_page_attributes_metabox_add_parents', 10, 2 ); | |
+ | |
+add_filter( 'page_attributes_dropdown_pages_args', 'make_page_attributes_metabox_add_parents', 10, 2 ); | |
add_filter( 'quick_edit_dropdown_pages_args', 'make_page_attributes_metabox_add_parents', 10); | |
- | |
+ | |
/** | |
* Add (status) to titles in page parent dropdowns | |
* | |
@@ -124,9 +124,9 @@ | |
$title .= " ($status)"; | |
return $title; | |
} | |
- | |
+ | |
add_filter( 'list_pages', 'make_page_parent_status_filter', 10, 2); | |
- | |
+ | |
/** | |
* Filter pages metabox on menu admin screen to include all built-in statuses. | |
* | |
@@ -137,17 +137,17 @@ | |
if ( is_admin() ) { | |
if ( function_exists( 'get_current_screen' ) ) { | |
$screen = get_current_screen(); | |
- if ( 'nav-menus' == $screen->base ) | |
- $query->set( 'post_status', 'publish,private,future,pending,draft' ); | |
+ // if ( 'nav-menus' == $screen->base ) | |
+ // $query->set( 'post_status', 'publish,private,future,pending,draft' ); | |
} | |
} | |
return $query; | |
} | |
- | |
+ | |
add_filter('pre_get_posts', 'make_private_page_query_filter'); | |
- | |
+ | |
/** | |
- * Filter lists of pages to include privately published ones. | |
+ * Filter lists of pages to include privately published ones. | |
* This a duplicate of wp_list_pages() except we change post_status in the default args, and we return without echoing. | |
* | |
* @param string $output Original output of wp_list_pages(), which we will overwrite. | |
@@ -156,38 +156,38 @@ | |
*/ | |
function make_wp_list_pages_with_private($output, $args) { | |
$defaults = array( 'post_status' => 'publish,private' ); // other defaults already parsed in wp_list_pages() | |
- | |
+ | |
$r = wp_parse_args( $args, $defaults ); | |
extract( $r, EXTR_SKIP ); | |
- | |
+ | |
$output = ''; | |
$current_page = 0; | |
- | |
+ | |
// sanitize, mostly to keep spaces out | |
$r['exclude'] = preg_replace('/[^0-9,]/', '', $r['exclude']); | |
- | |
+ | |
// Allow plugins to filter an array of excluded pages (but don't put a nullstring into the array) | |
$exclude_array = ( $r['exclude'] ) ? explode(',', $r['exclude']) : array(); | |
$r['exclude'] = implode( ',', apply_filters('wp_list_pages_excludes', $exclude_array) ); | |
- | |
+ | |
// Query pages. | |
$r['hierarchical'] = 0; | |
$pages = get_pages($r); | |
- | |
+ | |
if ( !empty($pages) ) { | |
if ( $r['title_li'] ) | |
$output .= '<li class="pagenav">' . $r['title_li'] . '<ul>'; | |
- | |
+ | |
global $wp_query; | |
if ( is_page() || is_attachment() || $wp_query->is_posts_page ) | |
$current_page = $wp_query->get_queried_object_id(); | |
$output .= walk_page_tree($pages, $r['depth'], $current_page, $r); | |
- | |
+ | |
if ( $r['title_li'] ) | |
$output .= '</ul></li>'; | |
} | |
- | |
+ | |
return $output; | |
} | |
- | |
+ | |
add_filter('wp_list_pages', 'make_wp_list_pages_with_private', 1, 2); | |
Index: includes/projects-cpt.php | |
=================================================================== | |
--- includes/projects-cpt.php (revision 141566) | |
+++ includes/projects-cpt.php (working copy) | |
@@ -5,7 +5,7 @@ | |
* @package makeblog | |
* @license http://opensource.org/licenses/gpl-license.php GNU Public License | |
* @author Jake Spurlock <jspurlock@makermedia.com> | |
- * | |
+ * | |
*/ | |
add_action( 'init', 'register_cpt_project' ); | |
@@ -19,7 +19,7 @@ | |
add_rewrite_rule( 'projects/([^/]*)/([^/]*)/?$','index.php?projects=$matches[2]','top' ); | |
- $labels = array( | |
+ $labels = array( | |
'name' => _x( 'Projects', 'Project' ), | |
'singular_name' => _x( 'Project', 'Project' ), | |
'add_new' => _x( 'Add New', 'Project' ), | |
@@ -34,7 +34,7 @@ | |
'menu_name' => _x( 'Projects', 'Project' ), | |
); | |
- $args = array( | |
+ $args = array( | |
'labels' => $labels, | |
'hierarchical' => true, | |
'description' => 'MAKE magazine Projects will be stored here. Goal is to build the back archive of all issues and Projects.', | |
@@ -68,7 +68,7 @@ | |
'Image' => array(), | |
'TimeRequired' => array(), | |
'PageNumber' => array(), | |
- 'Conclusion' => array( | |
+ 'Conclusion' => array( | |
'type' => 'textarea', | |
'label' => 'Projects Conclusion', | |
), | |
@@ -86,7 +86,7 @@ | |
* Generate the TOC for projects. | |
* | |
* @deprecated February 2013. The make_magazine_toc has been made more flexible to allow for any post type. | |
- * | |
+ * | |
*/ | |
function make_magazine_projects_toc() { | |
global $post; | |
@@ -95,7 +95,7 @@ | |
'no_found_rows' => true, | |
'post_type' => 'projects' | |
); | |
- | |
+ | |
if($post->post_parent == 0) { | |
echo '<h3>Projects</h3>'; | |
} | |
@@ -124,10 +124,10 @@ | |
</div> | |
<div class="clear"></div> | |
- | |
+ | |
<hr /> | |
- </Project> | |
+ </Project> | |
<?php endwhile; | |
@@ -140,9 +140,9 @@ | |
/** | |
* Add the parent selector to assign to a project to a volume. | |
- * | |
+ * | |
*/ | |
-function make_projects_add_meta_box() { | |
+function make_projects_add_meta_box() { | |
add_meta_box('volume-parent', 'Magazine Volume', 'make_magazine_parent_page', 'projects', 'side', 'high'); | |
} | |
@@ -150,9 +150,9 @@ | |
/** | |
* Remove the existing parent selector meta box. | |
- * | |
+ * | |
*/ | |
-function make_projects_remove_parent_meta_box() { | |
+function make_projects_remove_parent_meta_box() { | |
remove_meta_box('pageparentdiv', 'projects', 'normal'); | |
} | |
@@ -176,11 +176,11 @@ | |
/** | |
* Register the flags taxonomy | |
- * | |
+ * | |
*/ | |
function make_register_taxonomy_flags() { | |
- $labels = array( | |
+ $labels = array( | |
'name' => _x( 'Flags', 'flags' ), | |
'singular_name' => _x( 'Flag', 'flags' ), | |
'search_items' => _x( 'Search Flags', 'flags' ), | |
@@ -198,7 +198,7 @@ | |
'menu_name' => _x( 'Flags', 'flags' ), | |
); | |
- $args = array( | |
+ $args = array( | |
'labels' => $labels, | |
'public' => true, | |
'show_in_nav_menus' => true, | |
@@ -217,11 +217,11 @@ | |
/** | |
* Add the difficulty taxonomy | |
- * | |
+ * | |
*/ | |
function make_register_taxonomy_difficulty() { | |
- $labels = array( | |
+ $labels = array( | |
'name' => _x( 'Difficulties', 'difficulty' ), | |
'singular_name' => _x( 'Difficulty', 'difficulty' ), | |
'search_items' => _x( 'Search Difficulties', 'difficulty' ), | |
@@ -239,7 +239,7 @@ | |
'menu_name' => _x( 'Difficulties', 'difficulty' ), | |
); | |
- $args = array( | |
+ $args = array( | |
'labels' => $labels, | |
'public' => true, | |
'show_in_nav_menus' => true, | |
@@ -257,11 +257,11 @@ | |
/** | |
* Add the tools taxonomy | |
- * | |
+ * | |
*/ | |
function register_taxonomy_tools() { | |
- $labels = array( | |
+ $labels = array( | |
'name' => _x( 'Tools', 'tools' ), | |
'singular_name' => _x( 'Tool', 'tools' ), | |
'search_items' => _x( 'Search Tools', 'tools' ), | |
@@ -279,7 +279,7 @@ | |
'menu_name' => _x( 'Tools', 'tools' ), | |
); | |
- $args = array( | |
+ $args = array( | |
'labels' => $labels, | |
'public' => true, | |
'show_in_nav_menus' => true, | |
@@ -297,11 +297,11 @@ | |
/** | |
* Add the parts taxonomy | |
- * | |
+ * | |
*/ | |
function register_taxonomy_parts() { | |
- $labels = array( | |
+ $labels = array( | |
'name' => _x( 'Parts', 'parts' ), | |
'singular_name' => _x( 'Part', 'parts' ), | |
'search_items' => _x( 'Search Parts', 'parts' ), | |
@@ -319,7 +319,7 @@ | |
'menu_name' => _x( 'Parts', 'parts' ), | |
); | |
- $args = array( | |
+ $args = array( | |
'labels' => $labels, | |
'public' => true, | |
'show_in_nav_menus' => true, | |
@@ -338,11 +338,11 @@ | |
/** | |
* Add the types taxonomy | |
- * | |
+ * | |
*/ | |
function register_taxonomy_types() { | |
- $labels = array( | |
+ $labels = array( | |
'name' => _x( 'Types', 'types' ), | |
'singular_name' => _x( 'Type', 'types' ), | |
'search_items' => _x( 'Search Types', 'types' ), | |
@@ -360,7 +360,7 @@ | |
'menu_name' => _x( 'Types', 'types' ), | |
); | |
- $args = array( | |
+ $args = array( | |
'labels' => $labels, | |
'public' => true, | |
'show_in_nav_menus' => true, | |
@@ -376,19 +376,19 @@ | |
/** | |
* Simple grid for the projects landing page. | |
- * | |
+ * | |
*/ | |
function make_projects_grid( $label, $posts, $taxonomy, $terms ) { | |
$output = '<div class="' . $label . '"> | |
<div class="page-header"> | |
- | |
+ | |
<h3>' . $label . '</h3> | |
- | |
+ | |
</div> | |
- | |
- | |
+ | |
+ | |
<div class="row-fluid">'; | |
$args = array( | |
@@ -415,7 +415,7 @@ | |
} elseif ( $posts == 6 ) { | |
$output .= '<div class="span2">'; | |
} | |
- | |
+ | |
$url = get_post_custom_values('Image'); | |
//$url = esc_url($url); | |
$output .= '<img src="' . wpcom_vip_get_resized_remote_image_url( $url[0] , 293, 200 ) . '" alt="' . esc_attr( get_the_title() ) . '" />'; | |
@@ -424,7 +424,7 @@ | |
$output .= esc_html( $description[0] ); | |
$output .= '</div></div>'; | |
endwhile; | |
- | |
+ | |
$output .= '</div>'; | |
$output .= '</div><!--' . $label . '-->'; | |
@@ -433,7 +433,7 @@ | |
/** | |
* The steps thumbmails for the projects pages. | |
- * | |
+ * | |
*/ | |
function make_projects_steps_nav( $steps ) { | |
$steps = unserialize($steps[0]); | |
@@ -455,7 +455,7 @@ | |
echo '<img src="' . get_stylesheet_directory_uri() . '/img/placeholder.jpg" alt="No Image" class="' . esc_attr( $step->number ) . '" />'; | |
} | |
echo '<h4 class="red">Step #' . esc_html( $step->number ) . '</h4>'; | |
- echo '</div>'; | |
+ echo '</div>'; | |
} | |
echo '</div>'; | |
} | |
@@ -464,7 +464,7 @@ | |
/** | |
* Spit out the steps as a list. | |
- * | |
+ * | |
*/ | |
function make_projects_steps_list( $steps ) { | |
$steps = unserialize($steps[0]); | |
@@ -479,8 +479,8 @@ | |
} else { | |
echo '<a>' . esc_html( $step->number ) . ". " . esc_html( wp_trim_words( stripslashes( $step->lines[0]->text ), 5, '...' ) ) . '</a>'; | |
} | |
- | |
- echo '</li>'; | |
+ | |
+ echo '</li>'; | |
} | |
echo '</ul></div>'; | |
} | |
@@ -503,10 +503,12 @@ | |
$replace = 'make-images.s3.amazonaws.com/'; | |
if ( $haystack == 'http://cacher.dozuki.net/static/images/make/guide/NoImageMP_96x72.gif' or empty( $haystack ) ) { | |
return $haystack; | |
- } | |
+ } | |
$str = str_replace( $needle, $replace, $haystack); | |
- if ( strpos($str, 'make-images') !== true ) { | |
- return $str . '.jpg'; | |
+ $allowed = array('gif','png' ,'jpg'); | |
+ $ext = pathinfo( $str, PATHINFO_EXTENSION ); | |
+ if( ! in_array( $ext, $allowed ) ) { | |
+ return $str . '.jpg'; | |
} else { | |
return $str; | |
} | |
@@ -514,7 +516,7 @@ | |
/** | |
* Full content of the steps. | |
- * | |
+ * | |
*/ | |
function make_projects_steps( $steps, $print = false ) { | |
$steps = unserialize($steps[0]); | |
@@ -554,7 +556,7 @@ | |
echo ''; | |
} | |
echo '</span>'; | |
- | |
+ | |
$images = $step->images; | |
if ( isset( $images[0]->text ) ) { | |
if ( function_exists( 'wpcom_vip_get_resized_remote_image_url' ) ) { | |
@@ -573,11 +575,15 @@ | |
echo '</span><!--.row-->'; | |
} | |
$lines = $step->lines; | |
- echo '<ul>'; | |
- foreach ($lines as $line) { | |
- echo '<li>' . wp_kses_post( stripslashes( $line->text ) ) . '</li>'; | |
+ if ( isset( $lines[1] ) ) { | |
+ echo '<ul>'; | |
+ foreach ($lines as $line) { | |
+ echo '<li>' . wp_kses_post( stripslashes( $line->text ) ) . '</li>'; | |
+ } | |
+ echo '</ul>'; | |
+ } else { | |
+ echo Markdown( wp_kses_post( $lines[0]->text ) ); | |
} | |
- echo '</ul>'; | |
echo '</div><!--.right_column-->'; | |
} | |
} | |
@@ -617,7 +623,7 @@ | |
} | |
$output .= '</a> '; | |
- | |
+ | |
$output .= ' <span class="muted">'; | |
$output .= wp_kses_post( $notes ); | |
$output .= '</span>'; | |
Index: includes/projects-manager.php | |
=================================================================== | |
--- includes/projects-manager.php (revision 141566) | |
+++ includes/projects-manager.php (working copy) | |
@@ -59,7 +59,7 @@ | |
* This function is built to be used by any multidimensional array | |
* @param array REQUIRED $array The array of steps, parts or tools to sort by. | |
* @param string REQUIRED $sort_field The field in the array you wish to sort by. TODO: Make this happen. | |
- * @return array | |
+ * @return array | |
* | |
* @version 1.1 | |
* @since GLaDOS | |
@@ -455,9 +455,9 @@ | |
// Set our images array and contain each image as an object in the Steps object | |
$int = 0; | |
- | |
+ | |
foreach( $data[ 'step-images-' . $i ] as $image ) { | |
- | |
+ | |
$image_url = ( ! empty( $image ) ) ? esc_url_raw( $image ) : ''; | |
$step['images'][ $int ] = (object) array( | |
'imageid' => absint( $data['post_ID'] ), | |
@@ -611,7 +611,7 @@ | |
/////////////////////// | |
// PARTS | |
$parts = make_magazine_projects_build_parts_data( $_POST ); | |
- | |
+ | |
foreach ( $parts as $part ) { | |
add_post_meta( absint( $post_id ), 'parts', $part ); | |
} | |
@@ -629,7 +629,7 @@ | |
/** | |
* Autosave our post meta. | |
- * Since the core of our projects | |
+ * Since the core of our projects | |
* @return void | |
* | |
* @since Iron Giant | |
@@ -646,7 +646,7 @@ | |
////////////////////////// | |
// STEPS | |
$step_object = make_magazine_projects_build_step_data( $_POST ); | |
- | |
+ | |
// Update our post meta for Steps if any exist | |
update_post_meta( absint( $_POST['post_ID'] ), 'Steps', $step_object ); | |
@@ -654,7 +654,7 @@ | |
/////////////////////// | |
// PARTS | |
$parts = make_magazine_projects_build_parts_data( $_POST ); | |
- | |
+ | |
foreach ( $parts as $part ) { | |
add_post_meta( absint( absint( $_POST['post_ID'] ) ), 'parts', $part ); | |
} | |
Index: includes/theme_stuff.php | |
=================================================================== | |
--- includes/theme_stuff.php (revision 141680) | |
+++ includes/theme_stuff.php (working copy) | |
@@ -280,7 +280,8 @@ | |
wp_enqueue_script( 'make-projects', get_stylesheet_directory_uri() . '/js/projects.js', array( 'jquery' ), false, true ); | |
wp_enqueue_script( 'make-header', get_stylesheet_directory_uri() . '/js/header.js', array( 'jquery' ), false, true ); | |
wp_enqueue_script( 'make-oembed', get_stylesheet_directory_uri() . '/js/jquery.oembed.js', array( 'jquery' ) ); | |
- | |
+ // File Input | |
+ wp_enqueue_script( 'make-fileinput', get_stylesheet_directory_uri() . '/js/fileinput.js', array( 'jquery' ) ); | |
// display our map sort plugin for Maker Camp | |
if ( is_page( 315793 ) ) | |
wp_enqueue_script( 'make-sort-table', get_stylesheet_directory_uri() . '/js/jquery.tablesorter.min.js', array( 'jquery' ), false, true ); | |
@@ -1811,4 +1812,4 @@ | |
} | |
-add_action( 'category_top', 'make_get_banner_to_category_page' ); | |
\ No newline at end of file | |
+add_action( 'category_top', 'make_get_banner_to_category_page' ); | |
Index: js/bootstrap.file-input.min.js | |
=================================================================== | |
--- js/bootstrap.file-input.min.js (revision 0) | |
+++ js/bootstrap.file-input.min.js (working copy) | |
@@ -0,0 +1 @@ | |
+jQuery(function($){$.fn.bootstrapFileInput=function(){this.each(function(e,t){var i=$(t);if("undefined"==typeof i.attr("data-bfi-disabled")){var n="Browse";"undefined"!=typeof i.attr("title")&&(n=i.attr("title"));var p="";i.attr("class")&&(p=" "+i.attr("class")),i.wrap('<a class="file-input-wrapper btn btn-default '+p+'"></a>').parent().prepend(n)}}).promise().done(function(){$(".file-input-wrapper").mousemove(function(e){var t,i,n,p,a,r,f,l;i=$(this),t=i.find("input"),n=i.offset().left,p=i.offset().top,a=t.width(),r=t.height(),f=e.pageX,l=e.pageY,moveInputX=f-n-a+20,moveInputY=l-p-r/2,t.css({left:moveInputX,top:moveInputY})}),$("body").on("change",".file-input-wrapper input[type=file]",function(){var e;e=$(this).val(),$(this).parent().next(".file-input-name").remove(),e=$(this).prop("files")&&$(this).prop("files").length>1?$(this)[0].files.length+" files":e.substring(e.lastIndexOf("\\")+1,e.length),$(this).parent().after('<span class="file-input-name">'+e+"</span>")})})};var e="<style>.file-input-wrapper { overflow: hidden; position: relative; cursor: pointer; z-index: 1; }.file-input-wrapper input[type=file], .file-input-wrapper input[type=file]:focus, .file-input-wrapper input[type=file]:hover { position: absolute; top: 0; left: 0; cursor: pointer; opacity: 0; filter: alpha(opacity=0); z-index: 99; outline: 0; }.file-input-name { margin-left: 8px; }</style>";$("link[rel=stylesheet]").eq(0).before(e)}); | |
\ No newline at end of file | |
Index: js/fileinput.js | |
=================================================================== | |
--- js/fileinput.js (revision 0) | |
+++ js/fileinput.js (working copy) | |
@@ -0,0 +1,192 @@ | |
+/* =========================================================== | |
+ * Bootstrap: fileinput.js v3.1.0 | |
+ * http://jasny.github.com/bootstrap/javascript/#fileinput | |
+ * =========================================================== | |
+ * Copyright 2012-2014 Arnold Daniels | |
+ * | |
+ * Licensed under the Apache License, Version 2.0 (the "License") | |
+ * you may not use this file except in compliance with the License. | |
+ * You may obtain a copy of the License at | |
+ * | |
+ * http://www.apache.org/licenses/LICENSE-2.0 | |
+ * | |
+ * Unless required by applicable law or agreed to in writing, software | |
+ * distributed under the License is distributed on an "AS IS" BASIS, | |
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
+ * See the License for the specific language governing permissions and | |
+ * limitations under the License. | |
+ * ========================================================== */ | |
+ | |
++function ($) { "use strict"; | |
+ | |
+ var isIE = window.navigator.appName == 'Microsoft Internet Explorer'; | |
+ // FILEUPLOAD PUBLIC CLASS DEFINITION | |
+ // ================================= | |
+ | |
+ var Fileinput = function (element, options) { | |
+ this.$element = $(element); | |
+ | |
+ this.$input = this.$element.find(':file'); | |
+ if (this.$input.length === 0) return; | |
+ | |
+ this.name = this.$input.attr('name') || options.name; | |
+ | |
+ this.$hidden = this.$element.find('input[type=hidden][name="' + this.name + '"]'); | |
+ if (this.$hidden.length === 0) { | |
+ this.$hidden = $('<input type="hidden" />'); | |
+ this.$element.prepend(this.$hidden); | |
+ } | |
+ | |
+ this.$preview = this.$element.find('.fileinput-preview'); | |
+ var height = this.$preview.css('height'); | |
+ if (this.$preview.css('display') != 'inline' && height != '0px' && height != 'none') this.$preview.css('line-height', height); | |
+ | |
+ this.original = { | |
+ exists: this.$element.hasClass('fileinput-exists'), | |
+ preview: this.$preview.html(), | |
+ hiddenVal: this.$hidden.val() | |
+ }; | |
+ | |
+ this.listen(); | |
+ }; | |
+ | |
+ Fileinput.prototype.listen = function() { | |
+ this.$input.on('change.bs.fileinput', $.proxy(this.change, this)); | |
+ $(this.$input[0].form).on('reset.bs.fileinput', $.proxy(this.reset, this)); | |
+ | |
+ this.$element.find('[data-trigger="fileinput"]').on('click.bs.fileinput', $.proxy(this.trigger, this)); | |
+ this.$element.find('[data-dismiss="fileinput"]').on('click.bs.fileinput', $.proxy(this.clear, this)); | |
+ }, | |
+ | |
+ Fileinput.prototype.change = function(e) { | |
+ if (e.target.files === undefined) e.target.files = e.target && e.target.value ? [ {name: e.target.value.replace(/^.+\\/, '')} ] : []; | |
+ if (e.target.files.length === 0) return; | |
+ | |
+ this.$hidden.val(''); | |
+ this.$hidden.attr('name', ''); | |
+ this.$input.attr('name', this.name); | |
+ | |
+ var file = e.target.files[0]; | |
+ | |
+ if (this.$preview.length > 0 && (typeof file.type !== "undefined" ? file.type.match('image.*') : file.name.match(/\.(gif|png|jpe?g)$/i)) && typeof FileReader !== "undefined") { | |
+ var reader = new FileReader(); | |
+ var preview = this.$preview; | |
+ var element = this.$element; | |
+ | |
+ reader.onload = function(re) { | |
+ var $img = $('<img>'); // .attr('src', re.target.result) | |
+ $img[0].src = re.target.result; | |
+ e.target.files[0].result = re.target.result; | |
+ | |
+ element.find('.fileinput-filename').text(file.name); | |
+ | |
+ // if parent has max-height, using `(max-)height: 100%` on child doesn't take padding and border into account | |
+ if (preview.css('max-height') != 'none') $img.css('max-height', parseInt(preview.css('max-height'), 10) - parseInt(preview.css('padding-top'), 10) - parseInt(preview.css('padding-bottom'), 10) - parseInt(preview.css('border-top'), 10) - parseInt(preview.css('border-bottom'), 10)); | |
+ | |
+ preview.html($img); | |
+ element.addClass('fileinput-exists').removeClass('fileinput-new'); | |
+ | |
+ element.trigger('change.bs.fileinput', e.target.files); | |
+ element.trigger('image_added');; | |
+ | |
+ }; | |
+ | |
+ reader.readAsDataURL(file); | |
+ } else { | |
+ this.$element.find('.fileinput-filename').text(file.name); | |
+ this.$preview.text(file.name); | |
+ | |
+ this.$element.addClass('fileinput-exists').removeClass('fileinput-new'); | |
+ | |
+ this.$element.trigger('change.bs.fileinput'); | |
+ } | |
+ }, | |
+ | |
+ Fileinput.prototype.clear = function(e) { | |
+ if (e) e.preventDefault(); | |
+ | |
+ this.$hidden.val(''); | |
+ this.$hidden.attr('name', this.name); | |
+ this.$input.attr('name', ''); | |
+ | |
+ //ie8+ doesn't support changing the value of input with type=file so clone instead | |
+ if (isIE) { | |
+ var inputClone = this.$input.clone(true); | |
+ this.$input.after(inputClone); | |
+ this.$input.remove(); | |
+ this.$input = inputClone; | |
+ } else { | |
+ this.$input.val(''); | |
+ } | |
+ | |
+ this.$preview.html(''); | |
+ this.$element.find('.fileinput-filename').text(''); | |
+ this.$element.addClass('fileinput-new').removeClass('fileinput-exists'); | |
+ | |
+ if (e !== false) { | |
+ this.$input.trigger('change'); | |
+ this.$element.trigger('clear.bs.fileinput'); | |
+ } | |
+ }, | |
+ | |
+ Fileinput.prototype.reset = function() { | |
+ this.clear(false); | |
+ | |
+ this.$hidden.val(this.original.hiddenVal); | |
+ this.$preview.html(this.original.preview); | |
+ this.$element.find('.fileinput-filename').text(''); | |
+ | |
+ if (this.original.exists) this.$element.addClass('fileinput-exists').removeClass('fileinput-new'); | |
+ else this.$element.addClass('fileinput-new').removeClass('fileinput-exists'); | |
+ | |
+ this.$element.trigger('reset.bs.fileinput'); | |
+ }, | |
+ | |
+ Fileinput.prototype.trigger = function(e) { | |
+ this.$input.trigger('click'); | |
+ e.preventDefault(); | |
+ }; | |
+ | |
+ | |
+ // FILEUPLOAD PLUGIN DEFINITION | |
+ // =========================== | |
+ | |
+ var old = $.fn.fileinput; | |
+ | |
+ $.fn.fileinput = function (options) { | |
+ return this.each(function () { | |
+ var $this = $(this), | |
+ data = $this.data('fileinput'); | |
+ if (!data) $this.data('fileinput', (data = new Fileinput(this, options))); | |
+ if (typeof options == 'string') data[options](); | |
+ }); | |
+ }; | |
+ | |
+ $.fn.fileinput.Constructor = Fileinput; | |
+ | |
+ | |
+ // FILEINPUT NO CONFLICT | |
+ // ==================== | |
+ | |
+ $.fn.fileinput.noConflict = function () { | |
+ $.fn.fileinput = old; | |
+ return this; | |
+ }; | |
+ | |
+ | |
+ // FILEUPLOAD DATA-API | |
+ // ================== | |
+ | |
+ $(document).on('click.fileinput.data-api', '[data-provides="fileinput"]', function (e) { | |
+ var $this = $(this); | |
+ if ($this.data('fileinput')) return; | |
+ $this.fileinput($this.data()); | |
+ | |
+ var $target = $(e.target).closest('[data-dismiss="fileinput"],[data-trigger="fileinput"]'); | |
+ if ($target.length > 0) { | |
+ e.preventDefault(); | |
+ $target.trigger('click.bs.fileinput'); | |
+ } | |
+ }); | |
+ | |
+}(window.jQuery); | |
\ No newline at end of file | |
Index: js/parsley.min.js | |
=================================================================== | |
--- js/parsley.min.js (revision 0) | |
+++ js/parsley.min.js (working copy) | |
@@ -0,0 +1,10 @@ | |
+/*! | |
+* Parsleyjs | |
+* Guillaume Potier - <guillaume@wisembly.com> | |
+* Version 2.0.0-rc4 - built Sun Mar 23 2014 14:09:58 | |
+* MIT Licensed | |
+* Form Validation | |
+* | |
+*/ | |
+!function(a){var b={attr:function(a,b,c){var d,e={},f=new RegExp("^"+b,"i");if("undefined"==typeof a||"undefined"==typeof a[0])return{};for(var g in a[0].attributes)if(d=a[0].attributes[g],"undefined"!=typeof d&&null!==d&&d.specified&&f.test(d.name)){if("undefined"!=typeof c&&new RegExp(c+"$","i").test(d.name))return!0;e[this.camelize(d.name.replace(b,""))]=this.deserializeValue(d.value)}return"undefined"==typeof c?e:!1},setAttr:function(a,b,c,d){a[0].setAttribute(this.dasherize(b+c),String(d))},get:function(a,b){for(var c=0,d=(b||"").split(".");this.isObject(a)||this.isArray(a);)if(a=a[d[c++]],c===d.length)return a;return void 0},hash:function(a){return String(Math.random()).substring(2,a?a+2:9)},isArray:function(a){return"[object Array]"===Object.prototype.toString.call(a)},isObject:function(a){return a===Object(a)},deserializeValue:function(b){var c;try{return b?"true"==b||("false"==b?!1:"null"==b?null:isNaN(c=Number(b))?/^[\[\{]/.test(b)?a.parseJSON(b):b:c):b}catch(d){return b}},camelize:function(a){return a.replace(/-+(.)?/g,function(a,b){return b?b.toUpperCase():""})},dasherize:function(a){return a.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}},c={namespace:"data-parsley-",inputs:"input, textarea, select",excluded:"input[type=button], input[type=submit], input[type=reset]",priorityEnabled:!0,uiEnabled:!0,validationThreshold:3,focus:"first",trigger:!1,errorClass:"parsley-error",successClass:"parsley-success",classHandler:function(){},errorsContainer:function(){},errorsWrapper:'<ul class="parsley-errors-list"></ul>',errorTemplate:"<li></li>"},d=function(){};d.prototype={asyncSupport:!1,actualizeOptions:function(){return this.options=this.parsleyInstance.OptionsFactory.get(this),this},validateThroughValidator:function(a,b,c){return window.ParsleyValidator.validate.apply(window.ParsleyValidator,[a,b,c])},subscribe:function(b,c){return a.listenTo(this,b.toLowerCase(),c),this},unsubscribe:function(b){return a.unsubscribeTo(this,b.toLowerCase()),this},reset:function(){if("ParsleyForm"!==this.__class__)return a.emit("parsley:field:reset",this);for(var b=0;b<this.fields.length;b++)a.emit("parsley:field:reset",this.fields[b]);a.emit("parsley:form:reset",this)},destroy:function(){if("ParsleyForm"!==this.__class__)return a.emit("parsley:field:destroy",this),void this.$element.removeData("Parsley");for(var b=0;b<this.fields.length;b++)this.fields[b].destroy();a.emit("parsley:form:destroy",this),this.$element.removeData("Parsley")}},function(a){var b=function(a){return this.__class__="Validator",this.__version__="0.5.8",this.options=a||{},this.bindingKey=this.options.bindingKey||"_validatorjsConstraint",this};b.prototype={constructor:b,validate:function(a,b,c){if("string"!=typeof a&&"object"!=typeof a)throw new Error("You must validate an object or a string");return"string"==typeof a||g(a)?this._validateString(a,b,c):this.isBinded(a)?this._validateBindedObject(a,b):this._validateObject(a,b,c)},bind:function(a,b){if("object"!=typeof a)throw new Error("Must bind a Constraint to an object");return a[this.bindingKey]=new c(b),this},unbind:function(a){return"undefined"==typeof a._validatorjsConstraint?this:(delete a[this.bindingKey],this)},isBinded:function(a){return"undefined"!=typeof a[this.bindingKey]},getBinded:function(a){return this.isBinded(a)?a[this.bindingKey]:null},_validateString:function(a,b,c){var f,h=[];g(b)||(b=[b]);for(var i=0;i<b.length;i++){if(!(b[i]instanceof e))throw new Error("You must give an Assert or an Asserts array to validate a string");f=b[i].check(a,c),f instanceof d&&h.push(f)}return h.length?h:!0},_validateObject:function(a,b,d){if("object"!=typeof b)throw new Error("You must give a constraint to validate an object");return b instanceof c?b.check(a,d):new c(b).check(a,d)},_validateBindedObject:function(a,b){return a[this.bindingKey].check(a,b)}},b.errorCode={must_be_a_string:"must_be_a_string",must_be_an_array:"must_be_an_array",must_be_a_number:"must_be_a_number",must_be_a_string_or_array:"must_be_a_string_or_array"};var c=function(a,b){if(this.__class__="Constraint",this.options=b||{},this.nodes={},a)try{this._bootstrap(a)}catch(c){throw new Error("Should give a valid mapping object to Constraint",c,a)}return this};c.prototype={constructor:c,check:function(a,b){var c,d={};for(var h in this.options.strict?this.nodes:a)if(this.options.strict?this.has(h,a):this.has(h))c=this._check(h,a[h],b),(g(c)&&c.length>0||!g(c)&&!f(c))&&(d[h]=c);else if(this.options.strict)try{(new e).HaveProperty(h).validate(a)}catch(i){d[h]=i}return f(d)?!0:d},add:function(a,b){if(b instanceof e||g(b)&&b[0]instanceof e)return this.nodes[a]=b,this;if("object"==typeof b&&!g(b))return this.nodes[a]=b instanceof c?b:new c(b),this;throw new Error("Should give an Assert, an Asserts array, a Constraint",b)},has:function(a,b){return b="undefined"!=typeof b?b:this.nodes,"undefined"!=typeof b[a]},get:function(a,b){return this.has(a)?this.nodes[a]:b||null},remove:function(a){var b=[];for(var c in this.nodes)c!==a&&(b[c]=this.nodes[c]);return this.nodes=b,this},_bootstrap:function(a){if(a instanceof c)return this.nodes=a.nodes;for(var b in a)this.add(b,a[b])},_check:function(a,b,d){if(this.nodes[a]instanceof e)return this._checkAsserts(b,[this.nodes[a]],d);if(g(this.nodes[a]))return this._checkAsserts(b,this.nodes[a],d);if(this.nodes[a]instanceof c)return this.nodes[a].check(b,d);throw new Error("Invalid node",this.nodes[a])},_checkAsserts:function(a,b,c){for(var d,e=[],f=0;f<b.length;f++)d=b[f].check(a,c),"undefined"!=typeof d&&!0!==d&&e.push(d);return e}};var d=function(a,b,c){if(this.__class__="Violation",!(a instanceof e))throw new Error("Should give an assertion implementing the Assert interface");this.assert=a,this.value=b,"undefined"!=typeof c&&(this.violation=c)};d.prototype={show:function(){var a={assert:this.assert.__class__,value:this.value};return this.violation&&(a.violation=this.violation),a},__toString:function(){return"undefined"!=typeof this.violation&&(this.violation='", '+this.getViolation().constraint+" expected was "+this.getViolation().expected),this.assert.__class__+' assert failed for "'+this.value+this.violation||""},getViolation:function(){var a,b;for(a in this.violation)b=this.violation[a];return{constraint:a,expected:b}}};var e=function(a){return this.__class__="Assert",this.__parentClass__=this.__class__,this.groups=[],"undefined"!=typeof a&&this.addGroup(a),this};e.prototype={construct:e,check:function(a,b){if(!(b&&!this.hasGroup(b)||!b&&this.hasGroups()))try{return this.validate(a,b)}catch(c){return c}},hasGroup:function(a){return g(a)?this.hasOneOf(a):"Any"===a?!0:this.hasGroups()?-1!==this.groups.indexOf(a):"Default"===a},hasOneOf:function(a){for(var b=0;b<a.length;b++)if(this.hasGroup(a[b]))return!0;return!1},hasGroups:function(){return this.groups.length>0},addGroup:function(a){return g(a)?this.addGroups(a):(this.hasGroup(a)||this.groups.push(a),this)},removeGroup:function(a){for(var b=[],c=0;c<this.groups.length;c++)a!==this.groups[c]&&b.push(this.groups[c]);return this.groups=b,this},addGroups:function(a){for(var b=0;b<a.length;b++)this.addGroup(a[b]);return this},HaveProperty:function(a){return this.__class__="HaveProperty",this.node=a,this.validate=function(a){if("undefined"==typeof a[this.node])throw new d(this,a,{value:this.node});return!0},this},Blank:function(){return this.__class__="Blank",this.validate=function(a){if("string"!=typeof a)throw new d(this,a,{value:b.errorCode.must_be_a_string});if(""!==a.replace(/^\s+/g,"").replace(/\s+$/g,""))throw new d(this,a);return!0},this},Callback:function(a){if(this.__class__="Callback",this.arguments=Array.prototype.slice.call(arguments),1===this.arguments.length?this.arguments=[]:this.arguments.splice(0,1),"function"!=typeof a)throw new Error("Callback must be instanciated with a function");return this.fn=a,this.validate=function(a){var b=this.fn.apply(this,[a].concat(this.arguments));if(!0!==b)throw new d(this,a,{result:b});return!0},this},Choice:function(a){if(this.__class__="Choice",!g(a)&&"function"!=typeof a)throw new Error("Choice must be instanciated with an array or a function");return this.list=a,this.validate=function(a){for(var b="function"==typeof this.list?this.list():this.list,c=0;c<b.length;c++)if(a===b[c])return!0;throw new d(this,a,{choices:b})},this},Collection:function(a){return this.__class__="Collection",this.constraint="undefined"!=typeof a?new c(a):!1,this.validate=function(a,c){var e,h=new b,i=0,j={},k=this.groups.length?this.groups:c;if(!g(a))throw new d(this,array,{value:b.errorCode.must_be_an_array});for(var l=0;l<a.length;l++)e=this.constraint?h.validate(a[l],this.constraint,k):h.validate(a[l],k),f(e)||(j[i]=e),i++;return f(j)?!0:j},this},Count:function(a){return this.__class__="Count",this.count=a,this.validate=function(a){if(!g(a))throw new d(this,a,{value:b.errorCode.must_be_an_array});var c="function"==typeof this.count?this.count(a):this.count;if(isNaN(Number(c)))throw new Error("Count must be a valid interger",c);if(c!==a.length)throw new d(this,a,{count:c});return!0},this},Email:function(){return this.__class__="Email",this.validate=function(a){var c=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i;if("string"!=typeof a)throw new d(this,a,{value:b.errorCode.must_be_a_string});if(!c.test(a))throw new d(this,a);return!0},this},Eql:function(a){if(this.__class__="Eql","undefined"==typeof a)throw new Error("Equal must be instanciated with an Array or an Object");return this.eql=a,this.validate=function(a){var b="function"==typeof this.eql?this.eql(a):this.eql;if(!h.eql(b,a))throw new d(this,a,{eql:b});return!0},this},EqualTo:function(a){if(this.__class__="EqualTo","undefined"==typeof a)throw new Error("EqualTo must be instanciated with a value or a function");return this.reference=a,this.validate=function(a){var b="function"==typeof this.reference?this.reference(a):this.reference;if(b!==a)throw new d(this,a,{value:b});return!0},this},GreaterThan:function(a){if(this.__class__="GreaterThan","undefined"==typeof a)throw new Error("Should give a threshold value");return this.threshold=a,this.validate=function(a){if(""===a||isNaN(Number(a)))throw new d(this,a,{value:b.errorCode.must_be_a_number});if(this.threshold>=a)throw new d(this,a,{threshold:this.threshold});return!0},this},GreaterThanOrEqual:function(a){if(this.__class__="GreaterThanOrEqual","undefined"==typeof a)throw new Error("Should give a threshold value");return this.threshold=a,this.validate=function(a){if(""===a||isNaN(Number(a)))throw new d(this,a,{value:b.errorCode.must_be_a_number});if(this.threshold>a)throw new d(this,a,{threshold:this.threshold});return!0},this},InstanceOf:function(a){if(this.__class__="InstanceOf","undefined"==typeof a)throw new Error("InstanceOf must be instanciated with a value");return this.classRef=a,this.validate=function(a){if(!0!=a instanceof this.classRef)throw new d(this,a,{classRef:this.classRef});return!0},this},IPv4:function(){return this.__class__="IPv4",this.validate=function(a){var c=/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;if("string"!=typeof a)throw new d(this,a,{value:b.errorCode.must_be_a_string});if(!c.test(a))throw new d(this,a);return!0},this},Length:function(a){if(this.__class__="Length",!a.min&&!a.max)throw new Error("Lenth assert must be instanciated with a { min: x, max: y } object");return this.min=a.min,this.max=a.max,this.validate=function(a){if("string"!=typeof a&&!g(a))throw new d(this,a,{value:b.errorCode.must_be_a_string_or_array});if("undefined"!=typeof this.min&&this.min===this.max&&a.length!==this.min)throw new d(this,a,{min:this.min,max:this.max});if("undefined"!=typeof this.max&&a.length>this.max)throw new d(this,a,{max:this.max});if("undefined"!=typeof this.min&&a.length<this.min)throw new d(this,a,{min:this.min});return!0},this},LessThan:function(a){if(this.__class__="LessThan","undefined"==typeof a)throw new Error("Should give a threshold value");return this.threshold=a,this.validate=function(a){if(""===a||isNaN(Number(a)))throw new d(this,a,{value:b.errorCode.must_be_a_number});if(this.threshold<=a)throw new d(this,a,{threshold:this.threshold});return!0},this},LessThanOrEqual:function(a){if(this.__class__="LessThanOrEqual","undefined"==typeof a)throw new Error("Should give a threshold value");return this.threshold=a,this.validate=function(a){if(""===a||isNaN(Number(a)))throw new d(this,a,{value:b.errorCode.must_be_a_number});if(this.threshold<a)throw new d(this,a,{threshold:this.threshold});return!0},this},Mac:function(){return this.__class__="Mac",this.validate=function(a){var c=/^(?:[0-9A-F]{2}:){5}[0-9A-F]{2}$/i;if("string"!=typeof a)throw new d(this,a,{value:b.errorCode.must_be_a_string});if(!c.test(a))throw new d(this,a);return!0},this},NotNull:function(){return this.__class__="NotNull",this.validate=function(a){if(null===a||"undefined"==typeof a)throw new d(this,a);return!0},this},NotBlank:function(){return this.__class__="NotBlank",this.validate=function(a){if("string"!=typeof a)throw new d(this,a,{value:b.errorCode.must_be_a_string});if(""===a.replace(/^\s+/g,"").replace(/\s+$/g,""))throw new d(this,a);return!0},this},Null:function(){return this.__class__="Null",this.validate=function(a){if(null!==a)throw new d(this,a);return!0},this},Range:function(a,b){if(this.__class__="Range","undefined"==typeof a||"undefined"==typeof b)throw new Error("Range assert expects min and max values");return this.min=a,this.max=b,this.validate=function(a){try{return"string"==typeof a&&isNaN(Number(a))||g(a)?(new e).Length({min:this.min,max:this.max}).validate(a):(new e).GreaterThanOrEqual(this.min).validate(a)&&(new e).LessThanOrEqual(this.max).validate(a),!0}catch(b){throw new d(this,a,b.violation)}return!0},this},Regexp:function(a,c){if(this.__class__="Regexp","undefined"==typeof a)throw new Error("You must give a regexp");return this.regexp=a,this.flag=c||"",this.validate=function(a){if("string"!=typeof a)throw new d(this,a,{value:b.errorCode.must_be_a_string});if(!new RegExp(this.regexp,this.flag).test(a))throw new d(this,a,{regexp:this.regexp,flag:this.flag});return!0},this},Required:function(){return this.__class__="Required",this.validate=function(a){if("undefined"==typeof a)throw new d(this,a);try{"string"==typeof a?(new e).NotNull().validate(a)&&(new e).NotBlank().validate(a):!0===g(a)&&(new e).Length({min:1}).validate(a)}catch(b){throw new d(this,a)}return!0},this},Unique:function(a){return this.__class__="Unique","object"==typeof a&&(this.key=a.key),this.validate=function(a){var c,e=[];if(!g(a))throw new d(this,a,{value:b.errorCode.must_be_an_array});for(var f=0;f<a.length;f++)if(c="object"==typeof a[f]?a[f][this.key]:a[f],"undefined"!=typeof c){if(-1!==e.indexOf(c))throw new d(this,a,{value:c});e.push(c)}return!0},this}},a.Assert=e,a.Validator=b,a.Violation=d,a.Constraint=c,Array.prototype.indexOf||(Array.prototype.indexOf=function(a){if(null===this)throw new TypeError;var b=Object(this),c=b.length>>>0;if(0===c)return-1;var d=0;if(arguments.length>1&&(d=Number(arguments[1]),d!=d?d=0:0!==d&&1/0!=d&&d!=-1/0&&(d=(d>0||-1)*Math.floor(Math.abs(d)))),d>=c)return-1;for(var e=d>=0?d:Math.max(c-Math.abs(d),0);c>e;e++)if(e in b&&b[e]===a)return e;return-1});var f=function(a){for(var b in a)return!1;return!0},g=function(a){return"[object Array]"===Object.prototype.toString.call(a)},h={eql:function(a,b){if(a===b)return!0;if("undefined"!=typeof Buffer&&Buffer.isBuffer(a)&&Buffer.isBuffer(b)){if(a.length!==b.length)return!1;for(var c=0;c<a.length;c++)if(a[c]!==b[c])return!1;return!0}return a instanceof Date&&b instanceof Date?a.getTime()===b.getTime():"object"!=typeof a&&"object"!=typeof b?a==b:this.objEquiv(a,b)},isUndefinedOrNull:function(a){return null===a||"undefined"==typeof a},isArguments:function(a){return"[object Arguments]"==Object.prototype.toString.call(a)},keys:function(a){if(Object.keys)return Object.keys(a);var b=[];for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&b.push(c);return b},objEquiv:function(a,b){if(this.isUndefinedOrNull(a)||this.isUndefinedOrNull(b))return!1;if(a.prototype!==b.prototype)return!1;if(this.isArguments(a))return this.isArguments(b)?eql(pSlice.call(a),pSlice.call(b)):!1;try{var c,d,e=this.keys(a),f=this.keys(b);if(e.length!==f.length)return!1;for(e.sort(),f.sort(),d=e.length-1;d>=0;d--)if(e[d]!=f[d])return!1;for(d=e.length-1;d>=0;d--)if(c=e[d],!this.eql(a[c],b[c]))return!1;return!0}catch(g){return!1}}};"function"==typeof define&&define.amd&&define("validator",[],function(){return a})}("undefined"==typeof exports?this["undefined"!=typeof validatorjs_ns?validatorjs_ns:"Validator"]={}:exports);var e=function(a,b){this.__class__="ParsleyValidator",this.Validator=Validator,this.locale="en",this.init(a||{},b||{})};e.prototype={init:function(b,c){this.catalog=c;for(var d in b)this.addValidator(d,b[d].fn,b[d].priority);a.emit("parsley:validator:init")},setLocale:function(a){if("undefined"==typeof this.catalog[a])throw new Error(a+" is not available in the catalog");return this.locale=a,this},addCatalog:function(a,b,c){return"object"==typeof b&&(this.catalog[a]=b),!0===c?this.setLocale(a):this},addMessage:function(a,b,c){void 0===typeof this.catalog[a]&&(this.catalog[a]={}),this.catalog[a][b]=c},validate:function(){return(new this.Validator.Validator).validate.apply(new Validator.Validator,arguments)},addValidator:function(b,c,d){return this.validators[b]=function(b){return a.extend((new Validator.Assert).Callback(c,b),{priority:d})},this},updateValidator:function(a,b,c){return addValidator(a,b,c)},removeValidator:function(a){return delete this.validators[a],this},getErrorMessage:function(a){var b;return b="type"===a.name?window.ParsleyConfig.i18n[this.locale][a.name][a.requirements]:this.formatMesssage(window.ParsleyConfig.i18n[this.locale][a.name],a.requirements),""!==b?b:window.ParsleyConfig.i18n[this.locale].defaultMessage},formatMesssage:function(a,b){if("object"==typeof b){for(var c in b)a=this.formatMesssage(a,b[c]);return a}return"string"==typeof a?a.replace(new RegExp("%s","i"),b):""},validators:{notblank:function(){return a.extend((new Validator.Assert).NotBlank(),{priority:2})},required:function(){return a.extend((new Validator.Assert).Required(),{priority:512})},type:function(b){var c;switch(b){case"email":c=(new Validator.Assert).Email();break;case"number":c=(new Validator.Assert).Regexp("^-?(?:\\d+|\\d{1,3}(?:,\\d{3})+)?(?:\\.\\d+)?$");break;case"integer":c=(new Validator.Assert).Regexp("^-?\\d+$");break;case"digits":c=(new Validator.Assert).Regexp("^\\d+$");break;case"alphanum":c=(new Validator.Assert).Regexp("^\\w+$","i");break;case"url":c=(new Validator.Assert).Regexp("(https?:\\/\\/)?(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,4}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)","i");break;default:throw new Error("validator type `"+b+"` is not supported")}return a.extend(c,{priority:256})},pattern:function(b){var c="";return/^\/.*\/(?:[gimy]*)$/.test(b)&&(c=b.replace(/.*\/([gimy]*)$/,"$1"),b=b.replace(new RegExp("^/(.*?)/"+c+"$"),"$1")),a.extend((new Validator.Assert).Regexp(b,c),{priority:64})},minlength:function(b){return a.extend((new Validator.Assert).Length({min:b}),{priority:30,requirementsTransformer:function(){return"string"!=typeof b||isNaN(b)?b:parseInt(b,10)}})},maxlength:function(b){return a.extend((new Validator.Assert).Length({max:b}),{priority:30,requirementsTransformer:function(){return"string"!=typeof b||isNaN(b)?b:parseInt(b,10)}})},length:function(b){return a.extend((new Validator.Assert).Length({min:b[0],max:b[1]}),{priority:32})},mincheck:function(a){return this.minlength(a)},maxcheck:function(a){return this.maxlength(a)},check:function(a){return this.length(a)},min:function(b){return a.extend((new Validator.Assert).GreaterThanOrEqual(b),{priority:30,requirementsTransformer:function(){return"string"!=typeof b||isNaN(b)?b:parseInt(b,10)}})},max:function(b){return a.extend((new Validator.Assert).LessThanOrEqual(b),{priority:30,requirementsTransformer:function(){return"string"!=typeof b||isNaN(b)?b:parseInt(b,10)}})},range:function(b){return a.extend((new Validator.Assert).Range(b[0],b[1]),{priority:32,requirementsTransformer:function(){for(var a=0;a<b.length;a++)b[a]="string"!=typeof b[a]||isNaN(b[a])?b[a]:parseInt(b[a],10);return b}})},equalto:function(b){return a.extend((new Validator.Assert).EqualTo(b),{priority:256,requirementsTransformer:function(){return a(b).length?a(b).val():b}})}}};var f=function(){this.__class__="ParsleyUI"};f.prototype={listen:function(){return a.listen("parsley:form:init",this,this.setupForm),a.listen("parsley:field:init",this,this.setupField),a.listen("parsley:field:validated",this,this.reflow),a.listen("parsley:form:validated",this,this.focus),a.listen("parsley:field:reset",this,this.reset),a.listen("parsley:form:destroy",this,this.destroy),a.listen("parsley:field:destroy",this,this.destroy),this},reflow:function(a){if("undefined"!=typeof a._ui&&!1!==a._ui.active){var b=this._diff(a.validationResult,a._ui.lastValidationResult);a._ui.lastValidationResult=a.validationResult,a._ui.validatedOnce=!0,this.manageStatusClass(a),this.manageErrorsMessages(a,b),this.actualizeTriggers(a),(b.kept.length||b.added.length)&&"undefined"==typeof a._ui.failedOnce&&this.manageFailingFieldTrigger(a)}},manageStatusClass:function(a){!0===a.validationResult?this._successClass(a):a.validationResult.length>0?this._errorClass(a):this._resetClass(a)},manageErrorsMessages:function(b,c){if("undefined"==typeof b.options.errorsMessagesDisabled){if("undefined"!=typeof b.options.errorMessage)return void(c.added.length||c.kept.length?(0===b._ui.$errorsWrapper.find(".parsley-custom-error-message").length&&b._ui.$errorsWrapper.append(a(b.options.errorTemplate).addClass("parsley-custom-error-message")),b._ui.$errorsWrapper.addClass("filled").find(".parsley-custom-error-message").html(b.options.errorMessage)):b._ui.$errorsWrapper.removeClass("filled").find(".parsley-custom-error-message").remove());for(var d=0;d<c.removed.length;d++)this.removeError(b,c.removed[d].assert.name,!0);for(d=0;d<c.added.length;d++)this.addError(b,c.added[d].assert.name,void 0,c.added[d].assert,!0);for(d=0;d<c.kept.length;d++)this.updateError(b,c.kept[d].assert.name,void 0,c.kept[d].assert,!0)}},addError:function(b,c,d,e,f){b._ui.$errorsWrapper.addClass("filled").append(a(b.options.errorTemplate).addClass("parsley-"+c).html(d||this._getErrorMessage(b,e))),!0!==f&&this._errorClass(b)},updateError:function(a,b,c,d,e){a._ui.$errorsWrapper.addClass("filled").find(".parsley-"+b).html(c||this._getErrorMessage(a,d)),!0!==e&&this._errorClass(a)},removeError:function(a,b,c){a._ui.$errorsWrapper.removeClass("filled").find(".parsley-"+b).remove(),!0!==c&&this.manageStatusClass(a)},focus:function(a){if(!0===a.validationResult||"none"===a.options.focus)return a._focusedField=null;a._focusedField=null;for(var b=0;b<a.fields.length;b++)if(!0!==a.fields[b].validationResult&&a.fields[b].validationResult.length>0&&"undefined"==typeof a.fields[b].options.noFocus){if("first"===a.options.focus)return a._focusedField=a.fields[b].$element,a._focusedField.focus();a._focusedField=a.fields[b].$element}return null===a._focusedField?null:a._focusedField.focus()},_getErrorMessage:function(a,b){var c=b.name+"Message";return"undefined"!=typeof a.options[c]?a.options[c]:window.ParsleyValidator.getErrorMessage(b)},_diff:function(a,b,c){for(var d=[],e=[],f=0;f<a.length;f++){for(var g=!1,h=0;h<b.length;h++)if(a[f].assert.name===b[h].assert.name){g=!0;break}g?e.push(a[f]):d.push(a[f])}return{kept:e,added:d,removed:c?[]:this._diff(b,a,!0).added}},setupForm:function(b){b.$element.on("submit.Parsley",!1,a.proxy(b.onSubmitValidate,b)),!1!==b.options.uiEnabled&&b.$element.attr("novalidate","")},setupField:function(b){var c={active:!1};!1!==b.options.uiEnabled&&(c.active=!0,b.$element.attr(b.options.namespace+"id",b.__id__),c.$errorClassHandler=this._manageClassHandler(b),c.errorsWrapperId="parsley-id-"+("undefined"!=typeof b.options.multiple?"multiple-"+b.options.multiple:b.__id__),c.$errorsWrapper=a(b.options.errorsWrapper).attr("id",c.errorsWrapperId),c.lastValidationResult=[],c.validatedOnce=!1,c.validationInformationVisible=!1,b._ui=c,this._insertErrorWrapper(b),this.actualizeTriggers(b))},_manageClassHandler:function(b){if("string"==typeof b.options.classHandler&&a(b.options.classHandler).length)return a(b.options.classHandler);var c=b.options.classHandler(b);return"undefined"!=typeof c&&c.length?c:"undefined"==typeof b.options.multiple||b.$element.is("select")?b.$element:b.$element.parent()},_insertErrorWrapper:function(b){var c;if("string"==typeof b.options.errorsContainer){if(a(b.options.errorsContainer+"").length)return a(b.options.errorsContainer).append(b._ui.$errorsWrapper);window.console&&window.console.warn&&window.console.warn("The errors container `"+b.options.errorsContainer+"` does not exist in DOM")}return"function"==typeof b.options.errorsContainer&&(c=b.options.errorsContainer(b)),"undefined"!=typeof c&&c.length?c.append(b._ui.$errorsWrapper):"undefined"==typeof b.options.multiple?b.$element.after(b._ui.$errorsWrapper):b.$element.parent().after(b._ui.$errorsWrapper)},actualizeTriggers:function(b){var c=this;if(b.options.multiple?a("["+b.options.namespace+'multiple="'+b.options.multiple+'"]').each(function(){a(this).off(".Parsley")}):b.$element.off(".Parsley"),!1!==b.options.trigger){var d=b.options.trigger.replace(/^\s+/g,"").replace(/\s+$/g,"");""!==d&&(b.options.multiple?a("["+b.options.namespace+'multiple="'+b.options.multiple+'"]').each(function(){a(this).on(d.split(" ").join(".Parsley ")+".Parsley",!1,a.proxy("function"==typeof b.eventValidate?b.eventValidate:c.eventValidate,b))}):b.$element.on(d.split(" ").join(".Parsley ")+".Parsley",!1,a.proxy("function"==typeof b.eventValidate?b.eventValidate:this.eventValidate,b)))}},eventValidate:function(a){new RegExp("key").test(a.type)&&!this._ui.validationInformationVisible&&this.getValue().length<=this.options.validationThreshold||(this._ui.validatedOnce=!0,this.validate())},manageFailingFieldTrigger:function(b){return b._ui.failedOnce=!0,b.options.multiple&&a("["+b.options.namespace+'multiple="'+b.options.multiple+'"]').each(function(){return new RegExp("change","i").test(a(this).parsley().options.trigger||"")?void 0:a(this).on("change.ParsleyFailedOnce",!1,a.proxy(b.validate,b))}),b.$element.is("select")&&!new RegExp("change","i").test(b.options.trigger||"")?b.$element.on("change.ParsleyFailedOnce",!1,a.proxy(b.validate,b)):new RegExp("keyup","i").test(b.options.trigger||"")?void 0:b.$element.on("keyup.ParsleyFailedOnce",!1,a.proxy(b.validate,b))},reset:function(b){"undefined"!=typeof b._ui&&(b.$element.off(".Parsley"),b.$element.off(".ParsleyFailedOnce"),"ParsleyForm"!==b.__class__&&(b._ui.$errorsWrapper.children().each(function(){a(this).remove()}),this._resetClass(b),b._ui.validatedOnce=!1,b._ui.lastValidationResult=[],b._ui.validationInformationVisible=!1))},destroy:function(a){"undefined"!=typeof a._ui&&(this.reset(a),"ParsleyForm"!==a.__class__&&(a._ui.$errorsWrapper.remove(),delete a._ui))},_successClass:function(a){a._ui.validationInformationVisible=!0,a._ui.$errorClassHandler.removeClass(a.options.errorClass).addClass(a.options.successClass)},_errorClass:function(a){a._ui.validationInformationVisible=!0,a._ui.$errorClassHandler.removeClass(a.options.successClass).addClass(a.options.errorClass)},_resetClass:function(a){a._ui.$errorClassHandler.removeClass(a.options.successClass).removeClass(a.options.errorClass)}};var g=function(c,d,e,f){this.__class__="OptionsFactory",this.__id__=b.hash(4),this.formOptions=null,this.fieldOptions=null,this.staticOptions=a.extend(!0,{},c,d,e,{namespace:f})};g.prototype={get:function(a){if("undefined"==typeof a.__class__)throw new Error("Parsley Instance expected");switch(a.__class__){case"Parsley":return this.staticOptions;case"ParsleyForm":return this.getFormOptions(a);case"ParsleyField":case"ParsleyFieldMultiple":return this.getFieldOptions(a);default:throw new Error("Instance "+a.__class__+" is not supported")}},getFormOptions:function(c){return this.formOptions=b.attr(c.$element,this.staticOptions.namespace),a.extend({},this.staticOptions,this.formOptions)},getFieldOptions:function(c){return this.fieldOptions=b.attr(c.$element,this.staticOptions.namespace),null===this.formOptions&&"ParsleyForm"===c.parsleyInstance.__proxy__&&(this.formOptions=getFormOptions(c.parsleyInstance)),a.extend({},this.staticOptions,this.formOptions,this.fieldOptions)}};var h=function(c,d){if(this.__class__="ParsleyForm",this.__id__=b.hash(4),"Parsley"!==b.get(d,"__class__"))throw new Error("You must give a Parsley instance");this.parsleyInstance=d,this.$element=a(c)};h.prototype={init:function(){return this.validationResult=null,this.options=this.parsleyInstance.OptionsFactory.get(this),this._bindFields(),this},onSubmitValidate:function(b){return this.validate(void 0,void 0,b),!1===this.validationResult&&b instanceof a.Event&&b.preventDefault(),this},validate:function(b,c,d){this.submitEvent=d,this.validationResult=!0;var e=[];this._refreshFields(),a.emit("parsley:form:validate",this);for(var f=0;f<this.fields.length;f++)b&&b!==this.fields[f].options.group||(e=this.fields[f].validate(c),!0!==e&&e.length>0&&this.validationResult&&(this.validationResult=!1));return a.emit("parsley:form:validated",this),this.validationResult},isValid:function(a,b){this._refreshFields();for(var c=0;c<this.fields.length;c++)if((!a||a===this.fields[c].options.group)&&!1===this.fields[c].isValid(b))return!1;return!0},_refreshFields:function(){return this.actualizeOptions()._bindFields()},_bindFields:function(){var a=this;return this.fields=[],this.fieldsMappedById={},this.$element.find(this.options.inputs).each(function(){var b=new window.Parsley(this,{},a.parsleyInstance);"ParsleyField"!==b.__class__&&"ParsleyFieldMultiple"!==b.__class__||b.$element.is(b.options.excluded)||"undefined"==typeof a.fieldsMappedById[b.__class__+"-"+b.__id__]&&(a.fieldsMappedById[b.__class__+"-"+b.__id__]=b,a.fields.push(b))}),this}};var i=function(c,d,e,f,g){if(!new RegExp("ParsleyField").test(b.get(c,"__class__")))throw new Error("ParsleyField or ParsleyFieldMultiple instance expected");if("function"!=typeof window.ParsleyValidator.validators[d]&&"Assert"!==window.ParsleyValidator.validators[d](e).__parentClass__)throw new Error("Valid validator expected");var h=function(a,c){return"undefined"!=typeof a.options[c+"Priority"]?a.options[c+"Priority"]:b.get(window.ParsleyValidator.validators[c](e),"priority")||2};return f=f||h(c,d),"function"==typeof window.ParsleyValidator.validators[d](e).requirementsTransformer&&(e=window.ParsleyValidator.validators[d](e).requirementsTransformer()),a.extend(window.ParsleyValidator.validators[d](e),{name:d,requirements:e,priority:f,groups:[f],isDomConstraint:g||b.attr(c.$element,c.options.namespace,d)})},j=function(c,d){if(this.__class__="ParsleyField",this.__id__=b.hash(4),"Parsley"!==b.get(d,"__class__"))throw new Error("You must give a Parsley instance");this.parsleyInstance=d,this.$element=a(c),this.options=this.parsleyInstance.OptionsFactory.get(this) | |
+};j.prototype={init:function(){return this.constraints=[],this.validationResult=[],this.bindConstraints(),this},validate:function(b){return this.value=this.getValue(),a.emit("parsley:field:validate",this),a.emit("parsley:field:"+(this.isValid(b,this.value)?"success":"error"),this),a.emit("parsley:field:validated",this),this.validationResult},getConstraintsSortedPriorities:function(){for(var a=[],b=0;b<this.constraints.length;b++)-1===a.indexOf(this.constraints[b].priority)&&a.push(this.constraints[b].priority);return a.sort(function(a,b){return b-a}),a},isValid:function(a,b){this.refreshConstraints();var c=this.getConstraintsSortedPriorities();if(b=b||this.getValue(),0===b.length&&!this.isRequired()&&"undefined"==typeof this.options.validateIfEmpty&&"undefined"==typeof a)return this.validationResult=[];if(!1===this.options.priorityEnabled)return!0===(this.validationResult=this.validateThroughValidator(b,this.constraints,"Any"));for(var d=0;d<c.length;d++)if(!0!==(this.validationResult=this.validateThroughValidator(b,this.constraints,c[d])))return!1;return!0},isRequired:function(){var a=this._constraintIndex("required");return!(-1===a||-1!==a&&!1===this.constraints[a].requirements)},getValue:function(){var a;return a="undefined"!=typeof this.options.value?this.options.value:this.$element.val(),!0===this.options.trimValue?a.replace(/^\s+|\s+$/g,""):a},refreshConstraints:function(){return this.actualizeOptions().bindConstraints(),this},bindConstraints:function(){for(var a=[],b=0;b<this.constraints.length;b++)!1===this.constraints[b].isDomConstraint&&a.push(this.constraints[b]);this.constraints=a;for(var c in this.options)this.addConstraint(c,this.options[c]);return this.bindHtml5Constraints()},bindHtml5Constraints:function(){(this.$element.hasClass("required")||this.$element.attr("required"))&&this.addConstraint("required",!0,void 0,!0),"string"==typeof this.$element.attr("pattern")&&this.addConstraint("pattern",this.$element.attr("pattern"),void 0,!0),"undefined"!=typeof this.$element.attr("min")&&"undefined"!=typeof this.$element.attr("max")?this.addConstraint("range",[this.$element.attr("min"),this.$element.attr("max")],void 0,!0):"undefined"!=typeof this.$element.attr("min")?this.addConstraint("min",this.$element.attr("min"),void 0,!0):"undefined"!=typeof this.$element.attr("max")&&this.addConstraint("max",this.$element.attr("max"),void 0,!0);var a=this.$element.attr("type");return"undefined"==typeof a?this:"number"===a?this.addConstraint("type","integer",void 0,!0):new RegExp(a,"i").test("email url range")?this.addConstraint("type",a,void 0,!0):void 0},addConstraint:function(a,b,c,d){if(a=a.toLowerCase(),"function"==typeof window.ParsleyValidator.validators[a]){var e=new i(this,a,b,c,d);-1!==this._constraintIndex(e.name)&&this.removeConstraint(e.name),this.constraints.push(e)}return this},removeConstraint:function(a){for(var b=0;b<this.constraints.length;b++)if(a===this.constraints[b].name){this.constraints.splice(b,1);break}return this},updateConstraint:function(a,b,c){return this.removeConstraint(a).addConstraint(a,b,c)},_constraintIndex:function(a){for(var b=0;b<this.constraints.length;b++)if(a===this.constraints[b].name)return b;return-1}};var k=function(){this.__class__="ParsleyFieldMultiple"};k.prototype={init:function(a){return this.$elements=[this.$element],this.options.multiple=a,this},addElement:function(a){return this.$elements.push(a),this},refreshConstraints:function(){if(this.constraints=[],this.$element.is("select"))return this.actualizeOptions().bindConstraints(),this;for(var a=0;a<this.$elements.length;a++)this.constraints=this.constraints.concat(this.$elements[a].data("ParsleyFieldMultiple").refreshConstraints().constraints);return this},getValue:function(){if("undefined"!=typeof this.options.value)return this.options.value;if(this.$element.is("input[type=radio]"))return a("["+this.options.namespace+'multiple="'+this.options.multiple+'"]:checked').val()||"";if(this.$element.is("input[type=checkbox]")){var b=[];return a("["+this.options.namespace+'multiple="'+this.options.multiple+'"]:checked').each(function(){b.push(a(this).val())}),b.length?b:[]}return this.$element.is("select")?null===this.$element.val()?[]:this.$element.val():void 0}};var l=a({}),m={};a.listen=function(a){if("undefined"==typeof m[a]&&(m[a]=[]),"function"==typeof arguments[1])return m[a].push({fn:arguments[1]});if("object"==typeof arguments[1]&&"function"==typeof arguments[2])return m[a].push({fn:arguments[2],ctxt:arguments[1]});throw new Error("Wrong parameters")},a.listenTo=function(a,b,c){if("undefined"==typeof m[b]&&(m[b]=[]),!(a instanceof j||a instanceof h))throw new Error("Must give Parsley instance");if("string"!=typeof b||"function"!=typeof c)throw new Error("Wrong parameters");m[b].push({instance:a,fn:c})},a.unsubscribe=function(a,b){if("undefined"!=typeof m[a]){if("string"!=typeof a||"function"!=typeof b)throw new Error("Wrong arguments");for(var c=0;c<m[a].length;c++)if(m[a][c].fn===b)return m[a].splice(c,1)}},a.unsubscribeTo=function(a,b){if("undefined"!=typeof m[b]){if(!(a instanceof j||a instanceof h))throw new Error("Must give Parsley instance");for(var c=0;c<m[b].length;c++)if("undefined"!=typeof m[b][c].instance&&m[b][c].instance.__id__===a.__id__)return m[b].splice(c,1)}},a.unsubscribeAll=function(a){"undefined"!=typeof m[a]&&delete m[a]},a.emit=function(a,b){if("undefined"!=typeof m[a])for(var c=0;c<m[a].length;c++)if("undefined"!=typeof m[a][c].instance){if(b instanceof j||b instanceof h)if(m[a][c].instance.__id__!==b.__id__){if(m[a][c].instance instanceof h&&b instanceof j)for(var d=0;d<m[a][c].instance.fields.length;d++)if(m[a][c].instance.fields[d].__id__===b.__id__){m[a][c].fn.apply(l,Array.prototype.slice.call(arguments,1));continue}}else m[a][c].fn.apply(l,Array.prototype.slice.call(arguments,1))}else m[a][c].fn.apply("undefined"!=typeof m[a][c].ctxt?m[a][c].ctxt:l,Array.prototype.slice.call(arguments,1))},a.subscribed=function(){return m},window.ParsleyConfig=window.ParsleyConfig||{},window.ParsleyConfig.i18n=window.ParsleyConfig.i18n||{},window.ParsleyConfig.i18n.en=a.extend(window.ParsleyConfig.i18n.en||{},{defaultMessage:"This value seems to be invalid.",type:{email:"This value should be a valid email.",url:"This value should be a valid url.",number:"This value should be a valid number.",integer:"This value should be a valid integer.",digits:"This value should be digits.",alphanum:"This value should be alphanumeric."},notblank:"This value should not be blank.",required:"This value is required.",pattern:"This value seems to be invalid.",min:"This value should be greater than or equal to %s.",max:"This value should be lower than or equal to %s.",range:"This value should be between %s and %s.",minlength:"This value is too short. It should have %s characters or more.",maxlength:"This value is too long. It should have %s characters or less.",length:"This value length is invalid. It should be between %s and %s characters long.",mincheck:"You must select at least %s choices.",maxcheck:"You must select %s choices or less.",check:"You must select between %s and %s choices.",equalto:"This value should be the same."}),"undefined"!=typeof window.ParsleyValidator&&window.ParsleyValidator.addCatalog("en",window.ParsleyConfig.i18n.en,!0);var n=function(c,d,e){if(this.__class__="Parsley",this.__version__="2.0.0-rc4",this.__id__=b.hash(4),"undefined"==typeof c)throw new Error("You must give an element");return this.init(a(c),d,e)};n.prototype={init:function(a,d,e){if(!a.length)throw new Error("You must bind Parsley on an existing element.");if(this.$element=a,this.$element.data("Parsley")){var f=this.$element.data("Parsley");return"undefined"!=typeof e&&"ParsleyField"===f.parsleyInstance.__proxy__&&(f.parsleyInstance=e),f}return this.OptionsFactory=new g(c,b.get(window,"ParsleyConfig")||{},d,this.getNamespace(d)),this.options=this.OptionsFactory.get(this),this.$element.is("form")||b.attr(this.$element,this.options.namespace,"validate")&&!this.$element.is(this.options.inputs)?this.bind("parsleyForm",e):this.$element.is(this.options.inputs)&&!this.$element.is(this.options.excluded)?this.isMultiple()?this.handleMultiple(e):this.bind("parsleyField",e):this},isMultiple:function(){return this.$element.is("input[type=radio], input[type=checkbox]")&&"undefined"==typeof this.options.multiple||this.$element.is("select")&&"undefined"!=typeof this.$element.attr("multiple")},handleMultiple:function(c){var d,e,f,g=this;if(this.options=a.extend(this.options,b.attr(this.$element,this.options.namespace)),this.options.multiple?e=this.options.multiple:"undefined"!=typeof this.$element.attr("name")&&this.$element.attr("name").length?e=d=this.$element.attr("name"):"undefined"!=typeof this.$element.attr("id")&&this.$element.attr("id").length&&(e=this.$element.attr("id")),this.$element.is("select")&&"undefined"!=typeof this.$element.attr("multiple"))return this.bind("parsleyFieldMultiple",c,e||this.__id__);if("undefined"==typeof e)return window.console&&window.console.warn&&window.console.warn("To be binded by Parsley, a radio, a checkbox and a multiple select input must have either a name or a multiple option.",this.$element),this;if(e=e.replace(/(:|\.|\[|\]|\$)/g,""),"undefined"!=typeof d&&a('input[name="'+d+'"]').each(function(){a(this).attr(g.options.namespace+"multiple",e)}),a("["+this.options.namespace+"multiple="+e+"]").length)for(var h=0;h<a("["+this.options.namespace+"multiple="+e+"]").length;h++)if("undefined"!=typeof a(a("["+this.options.namespace+"multiple="+e+"]").get(h)).data("Parsley")){f=a(a("["+this.options.namespace+"multiple="+e+"]").get(h)).data("Parsley"),this.$element.data("ParsleyFieldMultiple")||(f.addElement(this.$element),this.$element.attr(this.options.namespace+"id",f.__id__));break}return this.bind("parsleyField",c,e,!0),f||this.bind("parsleyFieldMultiple",c,e)},getNamespace:function(a){return"undefined"!=typeof this.$element.data("parsleyNamespace")?this.$element.data("parsleyNamespace"):"undefined"!=typeof b.get(a,"namespace")?a.namespace:"undefined"!=typeof b.get(window,"ParsleyConfig.namespace")?window.ParsleyConfig.namespace:c.namespace},bind:function(c,e,f,g){var i;switch(c){case"parsleyForm":i=a.extend(new h(this.$element,e||this),new d,window.ParsleyExtend).init();break;case"parsleyField":i=a.extend(new j(this.$element,e||this),new d,window.ParsleyExtend).init();break;case"parsleyFieldMultiple":i=a.extend(new j(this.$element,e||this).init(),new d,new k,window.ParsleyExtend).init(f);break;default:throw new Error(c+"is not a supported Parsley type")}return"undefined"!=typeof f&&b.setAttr(this.$element,this.options.namespace,"multiple",f),"undefined"!=typeof g?(this.$element.data("ParsleyFieldMultiple",i),i):(new RegExp("ParsleyF","i").test(i.__class__)&&(this.$element.data("Parsley",i),this.__proxy__=i.__class__,a.emit("parsley:"+("parsleyForm"===c?"form":"field")+":init",i)),i)}},a.fn.parsley=a.fn.psly=function(b){if(this.length>1){var c=[];return this.each(function(){c.push(a(this).parsley(b))}),c}return a(this).length?new n(this,b):void(window.console&&window.console.warn&&window.console.warn("You must bind Parsley on an existing element."))},window.ParsleyUI="function"==typeof b.get(window,"ParsleyConfig.ParsleyUI")?(new window.ParsleyConfig.ParsleyUI).listen():(new f).listen(),"undefined"==typeof window.ParsleyExtend&&(window.ParsleyExtend={}),"undefined"==typeof window.ParsleyConfig&&(window.ParsleyConfig={}),window.Parsley=window.psly=n,window.ParsleyUtils=b,window.ParsleyValidator=new e(window.ParsleyConfig.validators,window.ParsleyConfig.i18n),!1!==b.get(window,"ParsleyConfig.autoBind")&&a(document).ready(function(){a("[data-parsley-validate]").length&&a("[data-parsley-validate]").parsley()})}(window.jQuery); | |
\ No newline at end of file | |
Index: js/project-savepost.js | |
=================================================================== | |
--- js/project-savepost.js (revision 141566) | |
+++ js/project-savepost.js (working copy) | |
@@ -56,7 +56,7 @@ | |
setInterval( function() { | |
if ( idle_state === false ) { | |
var post = $( '#post ').serialize(); | |
- | |
+ | |
$.ajax({ | |
type: 'POST', | |
dataType: 'json', | |
Index: js/projects.js | |
=================================================================== | |
--- js/projects.js (revision 141566) | |
+++ js/projects.js (working copy) | |
@@ -1,56 +1,54 @@ | |
-jQuery(document).ready(function(){ | |
- jQuery('#tabs li.steps').click(function() { | |
- jQuery(this).addClass('current'); | |
+jQuery( document ).ready( function( $ ) { | |
+ | |
+ // Handle the click actions on the list items in the steps box | |
+ $( 'body' ).on( 'click', '#tabs li.steps', function() { | |
var id = jQuery(this).attr('id'); | |
- jQuery('#steppers div#js-' + id).slideDown().removeClass('hide').addClass('active'); | |
- jQuery('#steppers div:not(#js-' + id + ')').slideUp(); | |
- jQuery('#tabs li:not(#' + id + ')').removeClass('current'); | |
+ | |
+ // Progress the slider | |
+ $( '#steppers' ).find( '.jstep#js-' + id ).slideDown().removeClass( 'hide' ); | |
+ $( '#steppers' ).find( '.jstep:not( #js-' + id + ')' ).slideUp(); | |
+ | |
+ // Update the side navigation list | |
+ jQuery( this ).addClass( 'current' ); | |
+ jQuery( '#tabs li:not(#' + id + ')' ).removeClass( 'current' ); | |
+ | |
+ // Run our trackers | |
googletag.pubads().refresh(); | |
_gaq.push(['_trackPageview']); | |
- console.log('Pushed a pageview, like a boss.'); | |
- var urlref = location.href; | |
- PARSELY.beacon.trackPageView({ | |
- url: urlref, | |
- urlref: urlref, | |
- js: 1, | |
- action_name: "Step Clicked" | |
- }); | |
- return true; | |
}); | |
- jQuery('.nexter').click(function() { | |
- var id = jQuery(this).attr('id'); | |
- jQuery('#steppers div#js-' + id).slideDown().removeClass('hide'); | |
- jQuery('#steppers div:not(#js-' + id + ')').slideUp(); | |
- jQuery(this).addClass('current'); | |
- jQuery('#tabs li#' + id).addClass('current'); | |
- jQuery('#tabs li:not(#' + id + ')').removeClass('current'); | |
+ | |
+ // Allows us to advance in the slider | |
+ $( 'body' ).on( 'click', '.nexter', function() { | |
+ var id = $(this).attr('id'); | |
+ | |
+ // Progress the slider | |
+ $( '#steppers' ).find( '.jstep#js-' + id ).slideDown().removeClass( 'hide' ); | |
+ $( '#steppers' ).find( '.jstep:not( #js-' + id + ')' ).slideUp(); | |
+ | |
+ // Update side navigation list | |
+ $( '#tabs').find( ' li#' + id ).addClass( 'current' ); | |
+ $( '#tabs' ).find( 'li:not( #' + id + ')' ).removeClass( 'current' ); | |
+ | |
+ // Run our trackers | |
googletag.pubads().refresh(); | |
_gaq.push(['_trackPageview']); | |
- console.log('Pushed a pageview, like a boss.'); | |
- var urlref = location.href; | |
- PARSELY.beacon.trackPageView({ | |
- url: urlref, | |
- urlref: urlref, | |
- js: 1, | |
- action_name: "Next Project Step" | |
+ }); | |
+ | |
+ // Display all projects when we click "View All" | |
+ jQuery( 'body' ).on( 'click', '.aller', function() { | |
+ // Display all the slides | |
+ jQuery( '#steppers' ).find( '.js-step' ).each( function() { | |
+ jQuery( this ).slideDown(); | |
}); | |
- return true; | |
- }); | |
- jQuery('.aller').click(function() { | |
- jQuery('#steppers').children().slideDown(); | |
- jQuery('#steppers .nexter, #steppers .disabled').hide(); | |
+ | |
+ // Hide the next/previous buttons | |
+ jQuery( '#steppers .nexter, #steppers .disabled' ).hide(); | |
+ | |
+ // Run our trackers | |
googletag.pubads().refresh(); | |
_gaq.push(['_trackPageview']); | |
- console.log('Pushed a pageview, like a boss.'); | |
- var urlref = location.href; | |
- PARSELY.beacon.trackPageView({ | |
- url: urlref, | |
- urlref: urlref, | |
- js: 1, | |
- action_name: "View all on the projects" | |
- }); | |
- return true; | |
}); | |
+ | |
jQuery('.carousel').on('slid', function () { | |
jQuery('.slide').find('iframe').each( function(){ | |
jQuery(this).attr('src', ''); | |
@@ -176,7 +174,7 @@ | |
_gaq.push(['_trackPageview']); | |
} ); | |
} )( jQuery ); | |
- | |
+ | |
jQuery('.print-page').on('click', function() { | |
window.print(); | |
}); | |
Index: less/bootstrap/bootstrap.less | |
=================================================================== | |
--- less/bootstrap/bootstrap.less (revision 141566) | |
+++ less/bootstrap/bootstrap.less (working copy) | |
@@ -41,6 +41,9 @@ | |
@import "tooltip.less"; | |
@import "popovers.less"; | |
+// Components: Panels | |
+@import "panels.less"; | |
+ | |
// Components: Misc | |
@import "thumbnails.less"; | |
@import "media.less"; | |
Index: less/bootstrap/mixins.less | |
=================================================================== | |
--- less/bootstrap/mixins.less (revision 141566) | |
+++ less/bootstrap/mixins.less (working copy) | |
@@ -196,8 +196,27 @@ | |
} | |
} | |
+// Panels | |
+// ------------------------- | |
+.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) { | |
+ border-color: @border; | |
+ & > .panel-heading { | |
+ color: @heading-text-color; | |
+ background-color: @heading-bg-color; | |
+ border-color: @heading-border; | |
+ + .panel-collapse .panel-body { | |
+ border-top-color: @border; | |
+ } | |
+ } | |
+ & > .panel-footer { | |
+ + .panel-collapse .panel-body { | |
+ border-bottom-color: @border; | |
+ } | |
+ } | |
+} | |
+ | |
// CSS3 PROPERTIES | |
// -------------------------------------------------- | |
Index: less/bootstrap/panels.less | |
=================================================================== | |
--- less/bootstrap/panels.less (revision 0) | |
+++ less/bootstrap/panels.less (working copy) | |
@@ -0,0 +1,182 @@ | |
+// | |
+// Panels | |
+// -------------------------------------------------- | |
+ | |
+ | |
+// Base class | |
+.panel { | |
+ margin-bottom: @line-height-computed; | |
+ background-color: @panel-bg; | |
+ border: 1px solid transparent; | |
+ border-radius: @panel-border-radius; | |
+ .box-shadow(0 1px 1px rgba(0,0,0,.05)); | |
+} | |
+ | |
+// Panel contents | |
+.panel-body { | |
+ padding: 15px; | |
+ .clearfix(); | |
+} | |
+ | |
+ | |
+// List groups in panels | |
+// | |
+// By default, space out list group content from panel headings to account for | |
+// any kind of custom content between the two. | |
+ | |
+.panel { | |
+ > .list-group { | |
+ margin-bottom: 0; | |
+ | |
+ .list-group-item { | |
+ border-width: 1px 0; | |
+ | |
+ // Remove border radius for top one | |
+ &:first-child { | |
+ .border-top-radius(0); | |
+ } | |
+ // But keep it for the last one | |
+ &:last-child { | |
+ border-bottom: 0; | |
+ } | |
+ } | |
+ } | |
+} | |
+// Collapse space between when there's no additional content. | |
+.panel-heading + .list-group { | |
+ .list-group-item:first-child { | |
+ border-top-width: 0; | |
+ } | |
+} | |
+ | |
+ | |
+// Tables in panels | |
+// | |
+// Place a non-bordered `.table` within a panel (not within a `.panel-body`) and | |
+// watch it go full width. | |
+ | |
+.panel { | |
+ > .table, | |
+ > .table-responsive > .table { | |
+ margin-bottom: 0; | |
+ } | |
+ > .panel-body + .table, | |
+ > .panel-body + .table-responsive { | |
+ border-top: 1px solid @tableBorder; | |
+ } | |
+ > .table > tbody:first-child th, | |
+ > .table > tbody:first-child td { | |
+ border-top: 0; | |
+ } | |
+ > .table-bordered, | |
+ > .table-responsive > .table-bordered { | |
+ border: 0; | |
+ > thead, | |
+ > tbody, | |
+ > tfoot { | |
+ > tr { | |
+ > th:first-child, | |
+ > td:first-child { | |
+ border-left: 0; | |
+ } | |
+ > th:last-child, | |
+ > td:last-child { | |
+ border-right: 0; | |
+ } | |
+ | |
+ &:last-child > th, | |
+ &:last-child > td { | |
+ border-bottom: 0; | |
+ } | |
+ } | |
+ } | |
+ } | |
+ > .table-responsive { | |
+ border: 0; | |
+ margin-bottom: 0; | |
+ } | |
+} | |
+ | |
+ | |
+// Optional heading | |
+.panel-heading { | |
+ padding: 10px 15px; | |
+ border-bottom: 1px solid transparent; | |
+ .border-top-radius(@panel-border-radius - 1); | |
+ | |
+ > .dropdown .dropdown-toggle { | |
+ color: inherit; | |
+ } | |
+} | |
+ | |
+// Within heading, strip any `h*` tag of it's default margins for spacing. | |
+.panel-title { | |
+ margin-top: 0; | |
+ margin-bottom: 0; | |
+ font-size: ceil((@baseFontSize * 1.125)); | |
+ color: inherit; | |
+ | |
+ > a { | |
+ color: inherit; | |
+ } | |
+} | |
+ | |
+// Optional footer (stays gray in every modifier class) | |
+.panel-footer { | |
+ padding: 10px 15px; | |
+ background-color: @panel-footer-bg; | |
+ border-top: 1px solid @panel-inner-border; | |
+ .border-bottom-radius(@panel-border-radius - 1); | |
+} | |
+ | |
+ | |
+// Collapsable panels (aka, accordion) | |
+// | |
+// Wrap a series of panels in `.panel-group` to turn them into an accordion with | |
+// the help of our collapse JavaScript plugin. | |
+ | |
+.panel-group { | |
+ // Tighten up margin so it's only between panels | |
+ .panel { | |
+ margin-bottom: 0; | |
+ border-radius: @panel-border-radius; | |
+ overflow: hidden; // crop contents when collapsed | |
+ + .panel { | |
+ margin-top: 5px; | |
+ } | |
+ } | |
+ | |
+ .panel-heading { | |
+ border-bottom: 0; | |
+ + .panel-collapse .panel-body { | |
+ border-top: 1px solid @panel-inner-border; | |
+ } | |
+ } | |
+ .panel-footer { | |
+ border-top: 0; | |
+ + .panel-collapse .panel-body { | |
+ border-bottom: 1px solid @panel-inner-border; | |
+ } | |
+ } | |
+} | |
+ | |
+ | |
+// Contextual variations | |
+.panel-default { | |
+ .panel-variant(@panel-default-border; @panel-default-text; @panel-default-heading-bg; @panel-default-border); | |
+} | |
+.panel-primary { | |
+ .panel-variant(@panel-primary-border; @panel-primary-text; @panel-primary-heading-bg; @panel-primary-border); | |
+} | |
+.panel-success { | |
+ .panel-variant(@panel-success-border; @panel-success-text; @panel-success-heading-bg; @panel-success-border); | |
+} | |
+.panel-warning { | |
+ .panel-variant(@panel-warning-border; @panel-warning-text; @panel-warning-heading-bg; @panel-warning-border); | |
+} | |
+.panel-danger { | |
+ .panel-variant(@panel-danger-border; @panel-danger-text; @panel-danger-heading-bg; @panel-danger-border); | |
+} | |
+.panel-info { | |
+ .panel-variant(@panel-info-border; @panel-info-text; @panel-info-heading-bg; @panel-info-border); | |
+} | |
Index: less/bootstrap/variables.less | |
=================================================================== | |
--- less/bootstrap/variables.less (revision 141566) | |
+++ less/bootstrap/variables.less (working copy) | |
@@ -74,6 +74,8 @@ | |
@borderRadiusLarge: 6px; | |
@borderRadiusSmall: 3px; | |
+@line-height-base: 1.428571429; // 20/14 | |
+@line-height-computed: floor(@baseFontSize * @line-height-base); // ~20px | |
// Tables | |
// ------------------------- | |
@@ -233,7 +235,38 @@ | |
@navbarBlueBrandColor: #ED1C24; | |
+// Panels | |
+// ------------------------- | |
+@panel-bg: #fff; | |
+@panel-inner-border: #ddd; | |
+@panel-border-radius: @baseBorderRadius; | |
+@panel-footer-bg: #f5f5f5; | |
+@panel-default-text: @grayDark; | |
+@panel-default-border: #ddd; | |
+@panel-default-heading-bg: #f5f5f5; | |
+ | |
+@panel-primary-text: #fff; | |
+@panel-primary-border: #000; | |
+@panel-primary-heading-bg: #ccc; | |
+ | |
+@panel-success-text: @successText; | |
+@panel-success-border: @successBorder; | |
+@panel-success-heading-bg: @successBackground; | |
+ | |
+@panel-warning-text: @warningText; | |
+@panel-warning-border: @warningBorder; | |
+@panel-warning-heading-bg: @warningBackground; | |
+ | |
+@panel-danger-text: @errorText; | |
+@panel-danger-border: @errorBorder; | |
+@panel-danger-heading-bg: @errorBackground; | |
+ | |
+@panel-info-text: @infoText; | |
+@panel-info-border: @infoBorder; | |
+@panel-info-heading-bg: @infoBackground; | |
+ | |
+ | |
// Pagination | |
// ------------------------- | |
@paginationBackground: #fff; | |
Index: less/make/contribute.less | |
=================================================================== | |
--- less/make/contribute.less (revision 0) | |
+++ less/make/contribute.less (working copy) | |
@@ -0,0 +1,35 @@ | |
+.page-template-page-contribute-project-php { | |
+ .title { | |
+ width:98%; | |
+ margin-bottom:10px; | |
+ } | |
+ .thumbnail { | |
+ cursor:pointer; | |
+ &.add { | |
+ width:80px; | |
+ height:38px; | |
+ text-align:center; | |
+ padding:25px 5px; | |
+ opacity:.5; | |
+ border-style:dashed; | |
+ font-size:14px; | |
+ } | |
+ } | |
+ #step_content { | |
+ width:98%; | |
+ min-height:100px; | |
+ } | |
+ .wp-core-ui .button { | |
+ color: #555 !important; | |
+ &:hover { | |
+ background-color:#fafafa !important; | |
+ color:#222 !important; | |
+ } | |
+ } | |
+ .wp-editor-container { | |
+ border:1px solid #dedede; | |
+ } | |
+ .projects-masthead { | |
+ padding-top:0; | |
+ } | |
+} | |
\ No newline at end of file | |
Index: less/make/fileinput.less | |
=================================================================== | |
--- less/make/fileinput.less (revision 0) | |
+++ less/make/fileinput.less (working copy) | |
@@ -0,0 +1,108 @@ | |
+// Fileinput.less | |
+// CSS for file upload button and fileinput widget | |
+// ------------------------------------------------ | |
+ | |
+.btn-file { | |
+ overflow: hidden; | |
+ position: relative; | |
+ vertical-align: middle; | |
+ > input { | |
+ position: absolute; | |
+ top: 0; | |
+ right: 0; | |
+ margin: 0; | |
+ opacity: 0; | |
+ filter: alpha(opacity=0); | |
+ transform: translate(-300px, 0) scale(4); | |
+ font-size: 23px; | |
+ height: 100%; | |
+ direction: ltr; | |
+ cursor: pointer; | |
+ } | |
+} | |
+ | |
+.fileinput { | |
+ margin-bottom: 9px; | |
+ display: inline-block; | |
+ .form-control { | |
+ padding-top: 7px; | |
+ padding-bottom: 5px; | |
+ display: inline-block; | |
+ margin-bottom: 0px; | |
+ vertical-align: middle; | |
+ cursor: text; | |
+ } | |
+ .thumbnail { | |
+ overflow: hidden; | |
+ display: inline-block; | |
+ margin-bottom: 5px; | |
+ vertical-align: middle; | |
+ text-align: center; | |
+ > img { | |
+ max-height: 100%; | |
+ } | |
+ } | |
+ .btn { | |
+ vertical-align: middle; | |
+ } | |
+} | |
+.fileinput-exists .fileinput-new, | |
+.fileinput-new .fileinput-exists { | |
+ display: none; | |
+} | |
+.fileinput-inline .fileinput-controls { | |
+ display: inline; | |
+} | |
+ | |
+.fileinput-filename { | |
+ vertical-align: middle; | |
+ display: inline-block; | |
+ overflow: hidden; | |
+} | |
+.form-control .fileinput-filename { | |
+ vertical-align: bottom; | |
+} | |
+ | |
+// Not 100% correct, but helps in typical use case | |
+.fileinput-new .input-group .btn-file { | |
+ border-radius: 0 @border-radius-base @border-radius-base 0; | |
+} | |
+.fileinput-new .input-group .btn-file.btn-xs, | |
+.fileinput-new .input-group .btn-file.btn-sm { | |
+ border-radius: 0 @border-radius-small @border-radius-small 0; | |
+} | |
+.fileinput-new .input-group .btn-file.btn-lg { | |
+ border-radius: 0 @border-radius-large @border-radius-large 0; | |
+} | |
+ | |
+.form-group.has-warning .fileinput { | |
+ .fileinput-preview { | |
+ color: @state-warning-text; | |
+ } | |
+ .thumbnail { | |
+ border-color: @state-warning-border; | |
+ } | |
+} | |
+.form-group.has-error .fileinput { | |
+ .fileinput-preview { | |
+ color: @state-danger-text; | |
+ } | |
+ .thumbnail { | |
+ border-color: @state-danger-border; | |
+ } | |
+} | |
+.form-group.has-success .fileinput { | |
+ .fileinput-preview { | |
+ color: @state-success-text; | |
+ } | |
+ .thumbnail { | |
+ border-color: @state-success-border; | |
+ } | |
+} | |
+ | |
+ | |
+// Input group fixes | |
+ | |
+.input-group-addon:not(:first-child) { | |
+ border-left: 0; | |
+} | |
\ No newline at end of file | |
Index: less/make/header.less | |
=================================================================== | |
--- less/make/header.less (revision 141566) | |
+++ less/make/header.less (working copy) | |
@@ -10,6 +10,22 @@ | |
.nav { margin-bottom:0; } | |
} | |
+// User Login Wrapper | |
+.login-wrapper { | |
+ position:absolute; | |
+ left:245px; | |
+ top:-8px; | |
+ color:#005d8f; | |
+ font-size:18px; | |
+ font-weight:bold; | |
+ a { | |
+ display:inline-block; | |
+ &:hover { | |
+ text-decoration:underline !important; | |
+ } | |
+ } | |
+} | |
+ | |
// Wrapper containing the main navigaiton | |
.main-header { | |
padding:15px 0 10px; | |
@@ -25,7 +41,9 @@ | |
position:absolute; | |
top:-15px; | |
right:0; | |
- .subscribe, .search-make, { .pull-left; } | |
+ .subscribe, .search-make, { | |
+ .pull-left; | |
+ } | |
.subscribe { | |
> a { | |
margin-right:6px; | |
@@ -58,7 +76,8 @@ | |
} | |
} | |
.search-make { | |
- float:right; | |
+ position:absolute; | |
+ left:-695px; | |
margin:0; | |
input[type="text"] { | |
width:165px; | |
@@ -133,7 +152,7 @@ | |
font-size:20px !important; | |
font-weight:bold; | |
position:relative; | |
- top:92px; | |
+ top:65px; | |
ul { | |
> li { | |
margin-right: 18px; | |
Index: less/make/style.less | |
=================================================================== | |
--- less/make/style.less (revision 141566) | |
+++ less/make/style.less (working copy) | |
@@ -1,6 +1,6 @@ | |
// Google Custom Search Styles | |
-.gsc-cursor .gsc-cursor-current-page { | |
- background-color:#005d8f; | |
+.gsc-cursor .gsc-cursor-current-page { | |
+ background-color:#005d8f; | |
} | |
// Generic Page Styles | |
@@ -22,7 +22,7 @@ | |
display: none; | |
} | |
-body.search .well { | |
+body.search .well { | |
margin-bottom:0 !important; | |
} | |
@@ -55,16 +55,16 @@ | |
.blog { | |
.projects-masthead { | |
- h2 { | |
- margin-bottom: -10px; | |
+ h2 { | |
+ margin-bottom: -10px; | |
} | |
} | |
.projects-meta { | |
color:#333; | |
font-weight:normal; | |
} | |
- article { | |
- margin:20px 0 45px; | |
+ article { | |
+ margin:20px 0 45px; | |
} | |
} | |
// h1 masthead styles | |
@@ -93,6 +93,44 @@ | |
} | |
} | |
} | |
+ | |
+ | |
+// Parseley Form Validation Styles | |
+input.parsley-error, select.parsley-error, textarea.parsley-error, div.parsley-error.mce-panel { | |
+ color: #B94A48; | |
+ background: #F2DEDE; | |
+ border: 1px solid #EED3D7 !important; | |
+} | |
+ | |
+.parsley-errors-list { | |
+ margin: 2px 0 3px 0; | |
+ padding: 0; | |
+ list-style-type: none; | |
+ font-size: 0.9em; | |
+ line-height: 0.9em; | |
+ opacity: 0; | |
+ -moz-opacity: 0; | |
+ -webkit-opacity: 0; | |
+ color:#B94A48; | |
+ | |
+ transition: all .3s ease-in; | |
+ -o-transition: all .3s ease-in; | |
+ -ms-transition: all .3s ease-in-; | |
+ -moz-transition: all .3s ease-in; | |
+ -webkit-transition: all .3s ease-in; | |
+ &.post_content_errors { | |
+ position:absolute; | |
+ bottom:26px; | |
+ left:10px; | |
+ } | |
+} | |
+ | |
+.parsley-errors-list.filled { | |
+ opacity: 1; | |
+} | |
+ | |
+ | |
+ | |
.waist { | |
background-image: url('../img/blue_bg1.jpg'); | |
border-bottom:2px solid #DBDBDB; | |
@@ -132,8 +170,8 @@ | |
line-height: 18px; | |
} | |
-.look_like_h4 { | |
- font-size: 14px !important; | |
+.look_like_h4 { | |
+ font-size: 14px !important; | |
font-weight: bold !important; | |
line-height: 18px !important; | |
height: 120px !important; | |
@@ -570,7 +608,7 @@ | |
display: inline-block; | |
padding-bottom: 8px; | |
} | |
- | |
+ | |
footer { | |
padding-top:40px; | |
padding-bottom:20px; | |
@@ -593,7 +631,7 @@ | |
margin-right: 5px; | |
margin-top: 8px; | |
max-width: 140px!important; | |
-} | |
+} | |
//This class is to keep some pages from inheriting the wrong giant font in the footer. | |
.p_footer { | |
@@ -605,14 +643,14 @@ | |
.twtr-widget { | |
border:1px solid #D0D0CE !important; | |
} | |
- | |
+ | |
.more_faires { | |
background-color:#E8F1F4; | |
border:1px solid #D0D0CE; | |
padding:10px; | |
max-height: 373px; | |
} | |
- | |
+ | |
.more_faires h3 { | |
font-family:"proxima-nova", sans-serif; | |
font-weight:300; | |
@@ -620,7 +658,7 @@ | |
color:#67abc6; | |
margin-bottom:10px; | |
} | |
- | |
+ | |
.more_faires h4 { | |
font-family:"proxima-nova", sans-serif; | |
font-weight:300; | |
@@ -633,19 +671,19 @@ | |
font-size:16px; | |
list-style-image:url('../img/arrow.gif'); | |
} | |
- | |
+ | |
.more_faires ul li a { | |
font-weight:bold; | |
color:#065270; | |
} | |
- | |
- | |
- | |
-footer .pills { | |
+ | |
+ | |
+ | |
+footer .pills { | |
margin-left:100px; | |
margin-top:20px; | |
} | |
- | |
+ | |
footer .pills a { | |
color:#5a6479; | |
} | |
@@ -1019,14 +1057,14 @@ | |
.drop-down { | |
margin-left:0px; | |
- columns: auto 3; | |
+ columns: auto 3; | |
-webkit-columns: auto 3; | |
-moz-columns: auto 3; | |
- margin-top: 23px; | |
+ margin-top: 23px; | |
} | |
.drop-down.fix { | |
- columns: auto auto; | |
+ columns: auto auto; | |
-webkit-columns: auto auto; | |
-moz-columns: auto auto; | |
} | |
@@ -1251,7 +1289,7 @@ | |
.third:first-child { | |
margin-left:20px; | |
-} | |
+} | |
.third h4 { | |
color:#045876; | |
@@ -1401,10 +1439,10 @@ | |
-moz-column-rule-style: solid; | |
-webkit-column-rule-width: 1px; | |
-webkit-column-rule-color: #ccc; | |
- -webkit-column-rule-style: solid; | |
+ -webkit-column-rule-style: solid; | |
column-rule-width: 1px; | |
column-rule-color: #ccc; | |
- column-rule-style: solid; | |
+ column-rule-style: solid; | |
} | |
.two-column h5 { | |
@@ -1623,7 +1661,7 @@ | |
width: 8em; | |
text-align: right; | |
} | |
-.pop-posts a { | |
+.pop-posts a { | |
display: block; | |
margin-bottom:15px; | |
} | |
@@ -1676,6 +1714,11 @@ | |
float:left; | |
} | |
+div.parts.row, div.tools.row { | |
+ width:100%; | |
+ float:none; | |
+} | |
+ | |
.description { | |
text-align: right; | |
} | |
@@ -1717,14 +1760,14 @@ | |
text-transform: uppercase; | |
border-bottom:1px solid #b0bac1; | |
} | |
- | |
+ | |
#review_box h2 { | |
line-height:22px; | |
margin-bottom:2px; | |
color:#021329; | |
font-size:22px; | |
} | |
- | |
+ | |
#review_box h5 { | |
text-transform: uppercase; | |
margin:5px 0 !important; | |
@@ -1744,41 +1787,41 @@ | |
margin-left: 10px; | |
margin-bottom:20px; | |
} | |
- | |
+ | |
#review_box .meta { | |
border-top:1px solid #b0bac1; | |
border-bottom:1px solid #b0bac1; | |
margin:5px 0; | |
padding:7px 0; | |
} | |
- | |
+ | |
#review_box .meta p { | |
margin:0px; | |
line-height: 14px; | |
} | |
- | |
+ | |
.ratings { | |
border-bottom:1px solid #b0bac1; | |
padding-bottom:5px; | |
margin-bottom:5px; | |
} | |
- | |
+ | |
.ratings dd { | |
height:11px; | |
width:182px; | |
margin:0 0 5px; | |
- } | |
+ } | |
.term1 { | |
background-image: url('images/1.gif'); | |
background-repeat:no-repeat; | |
} | |
- | |
+ | |
.term2 { | |
background-image: url('images/2.gif'); | |
background-repeat:no-repeat; | |
} | |
- | |
+ | |
.term3 { | |
background-image: url('images/3.gif'); | |
background-repeat:no-repeat; | |
@@ -1788,7 +1831,7 @@ | |
background-image: url('images/4.gif'); | |
background-repeat:no-repeat; | |
} | |
- | |
+ | |
.term5 { | |
background-image: url('images/5.gif'); | |
background-repeat:no-repeat; | |
@@ -1797,7 +1840,7 @@ | |
.the_tags { | |
font-size:13px; | |
} | |
- | |
+ | |
.the_tags a { | |
font-style: italic; | |
color:#5b5a54; | |
@@ -1833,39 +1876,39 @@ | |
ul#sidebar { | |
margin:0px; | |
} | |
- | |
+ | |
ul#sidebar li { | |
list-style-type: none; | |
} | |
- | |
+ | |
.drillz { | |
background-color:#fff; | |
height:20px; | |
line-height:0px; | |
- padding:2px 10px 2px 0; | |
+ padding:2px 10px 2px 0; | |
} | |
- | |
+ | |
.drill-list { | |
margin-bottom:15px; | |
} | |
- | |
+ | |
.term-item { | |
list-style-image:url('images/uncheck.gif'); | |
font-weight: bold; | |
} | |
- | |
+ | |
.current-term { | |
list-style-image:url('images/check.gif'); | |
} | |
- | |
+ | |
#sidebar li ul li { | |
font-weight: bold; | |
} | |
- | |
+ | |
.nobold li { | |
font-weight: 400 !important; | |
} | |
- | |
+ | |
#term-list-post_tag ul li { | |
font-weight: 400 !important; | |
} | |
@@ -1878,7 +1921,7 @@ | |
li.term-item { | |
margin-left:20px; | |
} | |
- | |
+ | |
.side { | |
background-color: white; | |
margin-top: 10px; | |
@@ -1904,7 +1947,7 @@ | |
font-style: normal; | |
font-weight: 900; | |
} | |
- | |
+ | |
body#shop { | |
background: none!important; | |
} | |
@@ -2181,7 +2224,7 @@ | |
} | |
.hoa.onair { | |
- background-image: url('../img/Google_Hangout_WebAd2_on_air.gif'); | |
+ background-image: url('../img/Google_Hangout_WebAd2_on_air.gif'); | |
} | |
.hoa h4 { | |
@@ -2210,31 +2253,31 @@ | |
background-color:#dff0f8; | |
padding:10px 0 5px 15px; | |
} | |
- | |
+ | |
#make-money #box-area ul { | |
- background-color:#fff; | |
+ background-color:#fff; | |
padding:20px 10px; | |
- margin:15px;color:#333; | |
- list-style-image:none; | |
- list-style-position:outside; | |
+ margin:15px;color:#333; | |
+ list-style-image:none; | |
+ list-style-position:outside; | |
list-style-type:square; | |
- color:#328938; | |
- margin-left:0; | |
+ color:#328938; | |
+ margin-left:0; | |
padding-left:25px; | |
} | |
- | |
+ | |
#make-money #box-area ul li {color:green;} | |
#make-money #box-area ul li span { color:black;} | |
-#make-money ul.specials { | |
- list-style-type: square; | |
+#make-money ul.specials { | |
+ list-style-type: square; | |
margin:0 0 10px 15px; | |
padding-bottom:5px; | |
} | |
-#make-money ul.specials li { | |
-color:green; | |
+#make-money ul.specials li { | |
+color:green; | |
font-size:13px; | |
line-height:18px; | |
} | |
@@ -2243,14 +2286,14 @@ | |
#make-money a.money { | |
color:green; | |
- text-decoration:none; | |
+ text-decoration:none; | |
} | |
#make-money h3, #make-money li {font-family: "proxima-nova", sans-serif;} | |
- | |
+ | |
#make-money h3 { | |
margin:0; | |
- font-size:1.2em; | |
+ font-size:1.2em; | |
font-weight:normal; | |
margin:0; | |
} | |
@@ -2293,7 +2336,7 @@ | |
width: auto !important; | |
} | |
#isBillShipAddrNotSame { | |
- width:auto !important; | |
+ width:auto !important; | |
width: auto !important; | |
} | |
#make_subcription_form .btn-02-area, #make_subcription_form .btn-01-area { | |
@@ -2562,7 +2605,7 @@ | |
margin-top: 30px; | |
label { | |
font-size:16px; | |
- } | |
+ } | |
.control-label{ | |
font-size:16px; | |
font-weight:600; | |
@@ -2582,7 +2625,7 @@ | |
.ctx_blocks_widget2 { | |
.ctx_subhead { | |
background-color: transparent !important; | |
- } | |
+ } | |
.ctx_link { | |
font-size: 13px !important; | |
line-height: 16px !important; | |
@@ -2617,88 +2660,88 @@ | |
.sprite { | |
background-image:url('../images/makezine_sprites.png'); | |
} | |
-.sprite-arrow-footer { | |
- background-position: 0 0; | |
- width: 95px; | |
- height: 46px; | |
+.sprite-arrow-footer { | |
+ background-position: 0 0; | |
+ width: 95px; | |
+ height: 46px; | |
margin: -40px 0 5px -16px; | |
border: none !important; | |
-} | |
-.sprite-digital-book-foot { | |
- background-position: 0 -51px; | |
- width: 29px; | |
- height: 22px; | |
+} | |
+.sprite-digital-book-foot { | |
+ background-position: 0 -51px; | |
+ width: 29px; | |
+ height: 22px; | |
float: left; | |
padding-right: 5px; | |
margin-top: 29px; | |
-} | |
-.sprite-facebook { | |
- background-position: 0 -78px; | |
- width: 24px; | |
- height: 24px; | |
-} | |
-.sprite-flickr { | |
- background-position: 0 -107px; | |
- width: 24px; | |
- height: 24px; | |
-} | |
-.sprite-google-plus { | |
- background-position: 0 -136px; | |
- width: 24px; | |
- height: 24px; | |
-} | |
-.sprite-instagram { | |
- background-position: 0 -165px; | |
- width: 24px; | |
- height: 24px; | |
-} | |
-.sprite-makershed_footer1 { | |
- background-position: 0 -194px; | |
- width: 29px; | |
- height: 22px; | |
+} | |
+.sprite-facebook { | |
+ background-position: 0 -78px; | |
+ width: 24px; | |
+ height: 24px; | |
+} | |
+.sprite-flickr { | |
+ background-position: 0 -107px; | |
+ width: 24px; | |
+ height: 24px; | |
+} | |
+.sprite-google-plus { | |
+ background-position: 0 -136px; | |
+ width: 24px; | |
+ height: 24px; | |
+} | |
+.sprite-instagram { | |
+ background-position: 0 -165px; | |
+ width: 24px; | |
+ height: 24px; | |
+} | |
+.sprite-makershed_footer1 { | |
+ background-position: 0 -194px; | |
+ width: 29px; | |
+ height: 22px; | |
float: left; | |
margin: 30px 5px 0 13px; | |
-} | |
-.sprite-pinterest { | |
- background-position: 0 -221px; | |
- width: 24px; | |
- height: 24px; | |
-} | |
-.sprite-stumbleupon { | |
- background-position: 0 -274px; | |
- width: 24px; | |
- height: 24px; | |
-} | |
-.sprite-twitter { | |
- background-position: 0 -303px; | |
- width: 24px; | |
- height: 24px; | |
-} | |
-.sprite-youtube { | |
- background-position: 0 -332px; | |
- width: 24px; | |
- height: 24px; | |
} | |
+.sprite-pinterest { | |
+ background-position: 0 -221px; | |
+ width: 24px; | |
+ height: 24px; | |
+} | |
+.sprite-stumbleupon { | |
+ background-position: 0 -274px; | |
+ width: 24px; | |
+ height: 24px; | |
+} | |
+.sprite-twitter { | |
+ background-position: 0 -303px; | |
+ width: 24px; | |
+ height: 24px; | |
+} | |
+.sprite-youtube { | |
+ background-position: 0 -332px; | |
+ width: 24px; | |
+ height: 24px; | |
+} | |
// HOME PAGE JPG SPRITES | |
.sprite-images { | |
background-image:url('../images/sprite_images.jpg'); | |
} | |
-.sprite-forum { | |
- background-position: 0 0; | |
- width: 620px; | |
- height: 174px; | |
-} | |
-.sprite-page2 { | |
- background-position: 0 -176px; | |
- width: 620px; | |
- height: 174px; | |
-} | |
-.sprite-sip { | |
- background-position: 0 -352px; | |
- width: 620px; | |
- height: 174px; | |
-} | |
-.sprite-forum{ background-position: 0 0; width: 620px; height: 174px; } | |
-.sprite-page2{ background-position: 0 -176px; width: 620px; height: 174px; } | |
-.sprite-sip{ background-position: 0 -352px; width: 620px; height: 174px; } | |
\ No newline at end of file | |
+.sprite-forum { | |
+ background-position: 0 0; | |
+ width: 620px; | |
+ height: 174px; | |
+} | |
+.sprite-page2 { | |
+ background-position: 0 -176px; | |
+ width: 620px; | |
+ height: 174px; | |
+} | |
+.sprite-sip { | |
+ background-position: 0 -352px; | |
+ width: 620px; | |
+ height: 174px; | |
+} | |
+.sprite-forum{ background-position: 0 0; width: 620px; height: 174px; } | |
+.sprite-page2{ background-position: 0 -176px; width: 620px; height: 174px; } | |
+.sprite-sip{ background-position: 0 -352px; width: 620px; height: 174px; } | |
\ No newline at end of file | |
Index: less/style.less | |
=================================================================== | |
--- less/style.less (revision 141566) | |
+++ less/style.less (working copy) | |
@@ -13,7 +13,25 @@ | |
@light-grey: #cdcdcd; | |
@font: "proxima-nova",sans-serif; | |
@blue: #005d8f; | |
+@border-radius-base: 4px; | |
+@border-radius-large: 6px; | |
+@border-radius-small: 3px; | |
+@state-success-text: #3c763d; | |
+@state-success-bg: #dff0d8; | |
+@state-success-border: darken(spin(@state-success-bg, -10), 5%); | |
+@state-info-text: #31708f; | |
+@state-info-bg: #d9edf7; | |
+@state-info-border: darken(spin(@state-info-bg, -10), 7%); | |
+ | |
+@state-warning-text: #8a6d3b; | |
+@state-warning-bg: #fcf8e3; | |
+@state-warning-border: darken(spin(@state-warning-bg, -10), 5%); | |
+ | |
+@state-danger-text: #a94442; | |
+@state-danger-bg: #f2dede; | |
+@state-danger-border: darken(spin(@state-danger-bg, -10), 5%); | |
+ | |
// Bring in MAKE Styles. | |
@import "make/mixins.less"; | |
@import "make/style.less"; | |
@@ -42,4 +60,6 @@ | |
@import "make/search.less"; | |
@import "make/shortcodes.less"; | |
@import "make/comments.less"; | |
-@import "make/aside.less"; | |
\ No newline at end of file | |
+@import "make/aside.less"; | |
+@import "make/contribute.less"; | |
+@import "make/fileinput.less"; | |
\ No newline at end of file | |
Index: page-contribute-project.php | |
=================================================================== | |
--- page-contribute-project.php (revision 0) | |
+++ page-contribute-project.php (working copy) | |
@@ -0,0 +1,461 @@ | |
+<?php | |
+/* | |
+ * Template Name: Post Contribute Form | |
+ * | |
+ * @package makeblog | |
+ * @license http://opensource.org/licenses/gpl-license.php GNU Public License | |
+ * | |
+ */ | |
+get_header(); ?> | |
+ | |
+ <div class="single"> | |
+ | |
+ <div class="container authentication"> | |
+ | |
+ <div class="row"> | |
+ | |
+ <div class="span12"> | |
+ | |
+ <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?> | |
+ | |
+ <article class="post-holder category-top" style="display:none;"> | |
+ <h3 class="submitted-title">Preview</h3> | |
+ <header class="projects-masthead"> | |
+ <h1 class="post-title"></h1> | |
+ </header> | |
+ <div class="row content-wrapper"> | |
+ <div class="span8"> | |
+ <section class="post-content"></section> | |
+ </div> | |
+ <div class="span4"> | |
+ | |
+ <div class="projects-ad"> | |
+ | |
+ <!-- Beginning Sync AdSlot 2 for Ad unit header ### size: [[300,250]] --> | |
+ <div id='div-gpt-ad-664089004995786621-2'> | |
+ <script type='text/javascript'> | |
+ googletag.cmd.push(function(){googletag.display('div-gpt-ad-664089004995786621-2')}); | |
+ </script> | |
+ </div> | |
+ <!-- End AdSlot 2 --> | |
+ | |
+ </div> | |
+ | |
+ <div class="parts-tools"> | |
+ <ul class="top"> | |
+ <li class="active"><a href="#parts-pane" data-toggle="tab">Parts</a></li> | |
+ <li class="divider"> / </li> | |
+ <li class=""><a href="#tools-pane" data-toggle="tab">Tools</a></li> | |
+ </ul> | |
+ <div class="tab-content"> | |
+ <div class="tab-pane tools-pane" id="tools-pane"> | |
+ <p>No tools, yet...</p> | |
+ </div> | |
+ <div class="tab-pane active parts-pane" id="parts-pane"> | |
+ <p>No parts, yet...</p> | |
+ </div> | |
+ </div> | |
+ </div> | |
+ </div> | |
+ </div> | |
+ | |
+ <div class="bottom-steps" id="target"> | |
+ | |
+ <form class="form form-horizontal contribute-form-get-steps" method="post"> | |
+ <?php echo wp_nonce_field( 'get_steps', 'get_steps' ); ?> | |
+ <input type="hidden" name="post_id" value="80"> | |
+ </form> | |
+ | |
+ <div class="row"> | |
+ | |
+ <div class="span4"> | |
+ | |
+ <div class="steps-list-output"></div> | |
+ | |
+ <!-- Beginning Sync AdSlot 3 for Ad unit header ### size: [[300,250]] --> | |
+ <div id='div-gpt-ad-664089004995786621-3'> | |
+ <script type='text/javascript'> | |
+ // We should find a way to display this ad... | |
+ // googletag.display('div-gpt-ad-664089004995786621-3'); | |
+ </script> | |
+ </div> | |
+ <!-- End AdSlot 3 --> | |
+ | |
+ </div> | |
+ | |
+ <div class="span8"> | |
+ | |
+ <div class="tab-content" id="steppers"> | |
+ | |
+ <div class="steps-output"></div> | |
+ | |
+ </div> | |
+ | |
+ </div> | |
+ | |
+ </div> | |
+ </div> | |
+ | |
+ <div class="saving-progress"></div> | |
+ </article> | |
+ | |
+ | |
+ <section id="contribute-form-wrapper" <?php post_class(); ?>> | |
+ | |
+ <!-- Contribute --> | |
+ <form class="form form-horizontal validate-form contribute-form" id="add-post-content" method="post"> | |
+ <?php echo wp_nonce_field( 'contribute_post_nonce', 'contribute_post' ); ?> | |
+ <input type="hidden" name="user_id" id="user_id" class="user_id" value="<?php echo get_current_user_id(); ?>"> | |
+ <fieldset> | |
+ <div class="control-group"> | |
+ <div class="control-label"></div> | |
+ <div class="controls"> | |
+ <div class="projects-masthead"> | |
+ <h1><?php the_title(); ?></h1> | |
+ </div> | |
+ </div> | |
+ </div> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="post_title">Title</label> | |
+ <div class="controls"> | |
+ <input type="text" class="input-xlarge" name="post_title" id="post_title" required> | |
+ <p class="help-block">Add the name of the post here.</p> | |
+ </div> | |
+ </div> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="post_content">Content</label> | |
+ <div class="controls"> | |
+ <?php wp_editor( '', 'post_content', array( 'teeny' => true ) ); ?> | |
+ </div> | |
+ </div> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="category">Category</label> | |
+ <div class="controls"> | |
+ <?php | |
+ $categories = get_categories(); | |
+ | |
+ if ( ! empty( $categories ) ) { | |
+ | |
+ echo '<select name="cat" id="cat" class="postform" required>'; | |
+ echo '<option value="">– Select A Category –</option>'; | |
+ foreach ( $categories as $cat ) { | |
+ echo '<option class="category-' . absint( $cat->term_id ) . ' category-' . esc_attr( $cat->slug ) . '" value="' . absint( $cat->term_id ) . '">' . esc_html( $cat->name ) . '</option>'; | |
+ } | |
+ echo '</select>'; | |
+ | |
+ } | |
+ ?> | |
+ </div> | |
+ </div> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="browse_file">Image</label> | |
+ <div class="controls"> | |
+ <input type="file" name="" value="" title="Add One or More Images" id="file" class="file-inputs" multiple required> | |
+ </div> | |
+ </div> | |
+ <div class="form-actions"> | |
+ <button type="submit" class="btn btn-warning submit-review" data-type="projects">Want to add steps to the post?</button> | |
+ <button type="submit" class="btn btn-primary submit-review" data-type="post">Submit for Review</button> | |
+ </div> | |
+ </fieldset> | |
+ </form> | |
+ | |
+ <!-- Steps --> | |
+ <form class="form form-horizontal validate-form contribute-form-steps" id="add-steps" action="add_steps" method="post"> | |
+ <fieldset> | |
+ <section class="control-group"> | |
+ <div class="control-label"></div> | |
+ <div class="controls"> | |
+ <h1>Add Steps to the Project</h1> | |
+ </div> | |
+ </section> | |
+ <section class="nonce"> | |
+ <?php echo wp_nonce_field( 'contribute_steps_nonce', 'contribute_steps_nonce' ); ?> | |
+ <input type="hidden" name="total-steps" value="1"> | |
+ <input type="hidden" class="post_ID" name="post_ID" value=""> | |
+ </section> | |
+ <section class="steps-wrapper"> | |
+ <div class="steps-list"> | |
+ <div class="step row"> | |
+ <div class="span12"> | |
+ <h4 class="step-title">Step 1</h4> | |
+ <input type="hidden" class="step-number" name="step-number-1" value="1"> | |
+ </div> | |
+ <div class="image-wrapper span3"> | |
+ <div class="fileinput fileinput-new" data-provides="fileinput"> | |
+ <div class="fileinput-preview thumbnail" data-trigger="fileinput" style="width: 200px; height: 150px;"></div> | |
+ <div> | |
+ <span class="btn btn-default btn-file"> | |
+ <span class="fileinput-new">Select image</span> | |
+ <span class="fileinput-exists">Change</span> | |
+ <input type="file" class="step-file" id="step-image" name="step-images-1[]" required> | |
+ </span> | |
+ <a href="#" class="btn btn-default fileinput-exists" data-dismiss="fileinput">Remove</a> | |
+ </div> | |
+ </div> | |
+ </div> | |
+ <div class="content-wrapper span9"> | |
+ <input type="text" class="title" name="step-title-1" placeholder="Enter your step title..." value=""> | |
+ <textarea name="step-lines-1[]" id="step_content"></textarea> | |
+ </div> | |
+ </div> | |
+ </div> | |
+ <script id="steps-template" type="text/template"> | |
+ <div class="step row"> | |
+ <div class="span12"> | |
+ <h4 class="step-title">Step ##count##</h4> | |
+ <input type="hidden" class="step-number" name="step-number-##count##" value="##count##"> | |
+ </div> | |
+ <div class="image-wrapper span3"> | |
+ <div class="fileinput fileinput-new" data-provides="fileinput"> | |
+ <div class="fileinput-preview thumbnail" data-trigger="fileinput" style="width: 200px; height: 150px;"></div> | |
+ <div> | |
+ <span class="btn btn-default btn-file"> | |
+ <span class="fileinput-new">Select image</span> | |
+ <span class="fileinput-exists">Change</span> | |
+ <input type="file" class="step-file" id="step-image" name="step-images-##count##[]"> | |
+ </span> | |
+ <a href="#" class="btn btn-default fileinput-exists" data-dismiss="fileinput">Remove</a> | |
+ </div> | |
+ </div> | |
+ </div> | |
+ <div class="content-wrapper span9"> | |
+ <input type="text" class="title" name="step-title-##count##" placeholder="Enter your step title..." value=""> | |
+ <textarea name="step-lines-##count##[]" class="step_content" id="step_content"></textarea> | |
+ <button class="btn alignright remove-step"><i class="icon icon-minus"></i> Remove Step</button> | |
+ </div> | |
+ </div> | |
+ </script> | |
+ <section class="repeater-tools"> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="tools-url"></label> | |
+ <div class="controls"> | |
+ <button class="btn add-step"><i class="icon icon-plus"></i> Add Another Step</button> | |
+ </div> | |
+ </div> | |
+ </section> | |
+ <div class="form-actions"> | |
+ <button type="submit" class="btn btn-primary submit-steps">Save Steps</button> | |
+ </div> | |
+ </section> | |
+ </fieldset> | |
+ </form> | |
+ | |
+ <!-- Parts Form --> | |
+ <form class="form form-horizontal validate-form contribute-form-parts" id="add-parts" method="post"> | |
+ <fieldset> | |
+ <section class="control-group"> | |
+ <div class="control-label"></div> | |
+ <div class="controls"> | |
+ <h1>Add Parts to the Project</h1> | |
+ </div> | |
+ </section> | |
+ <section class="nonce"> | |
+ <?php echo wp_nonce_field( 'contribute_parts', 'contribute_parts' ); ?> | |
+ <input type="hidden" name="total-parts" value="1"> | |
+ <input type="hidden" class="post_ID" name="post_ID" value=""> | |
+ </section> | |
+ <div class="parts-wrapper"> | |
+ <div class="parts-list"> | |
+ <div class="part row"> | |
+ <div class="span12"> | |
+ <div class="control-group"> | |
+ <label class="control-label"></label> | |
+ <div class="controls"> | |
+ <h4 class="part-title">Part 1</h4> | |
+ <input type="hidden" name="part-number-1" value="1"> | |
+ <input type="hidden" name="parts-notes-1" class="parts-notes" id="parts-notes"> | |
+ </div> | |
+ </div> | |
+ <section class="part"> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="parts-name">Name</label> | |
+ <div class="controls"> | |
+ <input type="text" name="parts-name-1" id="parts-name" class="input-xlarge parts-name" value=""> | |
+ </div> | |
+ </div> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="parts-qty">Quantity</label> | |
+ <div class="controls"> | |
+ <input type="number" name="parts-qty-1" id="parts-qty" class="input-xlarge parts-qty" value=""> | |
+ </div> | |
+ </div> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="parts-url">URL</label> | |
+ <div class="controls"> | |
+ <input type="url" name="parts-url-1" id="parts-url" class="input-xlarge parts-url" value=""> | |
+ </div> | |
+ </div> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="parts-type">Type</label> | |
+ <div class="controls"> | |
+ <input type="text" name="parts-type-1" id="parts-type" class="input-xlarge parts-type" value=""> | |
+ </div> | |
+ </div> | |
+ </section> | |
+ </div> | |
+ </div> | |
+ </div> | |
+ <script id="parts-template" type="text/template"> | |
+ <div class="part row"> | |
+ <div class="span12"> | |
+ <div class="control-group"> | |
+ <label class="control-label"></label> | |
+ <div class="controls"> | |
+ <h4 class="part-title">Part ##count##</h4> | |
+ <input type="hidden" name="part-number-##count##" class="part-number" value="1"> | |
+ <input type="hidden" name="parts-notes-##count##" class="parts-notes" id="parts-notes"> | |
+ </div> | |
+ </div> | |
+ <section class="part"> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="parts-name">Name</label> | |
+ <div class="controls"> | |
+ <input type="text" name="parts-name-##count##" id="parts-name" class="input-xlarge parts-name" value=""> | |
+ </div> | |
+ </div> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="parts-qty">Quantity</label> | |
+ <div class="controls"> | |
+ <input type="number" name="parts-qty-##count##" id="parts-qty" class="input-xlarge parts-qty" value=""> | |
+ </div> | |
+ </div> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="parts-url">URL</label> | |
+ <div class="controls"> | |
+ <input type="url" name="parts-url-##count##" id="parts-url" class="input-xlarge parts-url" value=""> | |
+ </div> | |
+ </div> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="parts-type">Type</label> | |
+ <div class="controls"> | |
+ <input type="text" name="parts-type-##count##" id="parts-type" class="input-xlarge parts-type" value=""> | |
+ </div> | |
+ </div> | |
+ <div class="control-group"> | |
+ <label for="" class="control-label"></label> | |
+ <div class="controls"> | |
+ <button class="btn alignleft remove-part"><i class="icon icon-minus"></i> Remove Part</button> | |
+ </div> | |
+ </div> | |
+ </section> | |
+ </div> | |
+ </div> | |
+ </script> | |
+ <section class="repeater-tools clear"> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="parts-url"></label> | |
+ <div class="controls"> | |
+ <button class="btn add-part"><i class="icon icon-plus"></i> Add Another Part</button> | |
+ </div> | |
+ </div> | |
+ </section> | |
+ <div class="form-actions"> | |
+ <button type="submit" class="btn btn-primary submit-parts">Save Parts</button> | |
+ </div> | |
+ </section> | |
+ </fieldset> | |
+ </form> | |
+ | |
+ <!-- Let's add the tools --> | |
+ <form class="form form-horizontal validate-form contribute-form-tools" id="add-tools" method="post"> | |
+ <fieldset> | |
+ <section class="control-group"> | |
+ <div class="control-label"></div> | |
+ <div class="controls"> | |
+ <h1>Add Tools to the Project</h1> | |
+ </div> | |
+ </section> | |
+ <section class="nonce"> | |
+ <?php echo wp_nonce_field( 'contribute_tools', 'contribute_tools' ); ?> | |
+ <input type="hidden" name="total-tools" value="1"> | |
+ <input type="hidden" class="post_ID" name="post_ID" value=""> | |
+ </section> | |
+ <div class="tool-wrapper"> | |
+ <div class="tools-list"> | |
+ <div class="tool row"> | |
+ <div class="span12"> | |
+ <div class="control-group"> | |
+ <label class="control-label"></label> | |
+ <div class="controls"> | |
+ <h4 class="part-title">Tool 1</h4> | |
+ <input type="hidden" name="tools-number-1" value="1"> | |
+ <input type="hidden" name="tools-thumb-1" value=""> | |
+ <input type="hidden" name="tools-notes-1" value=""> | |
+ </div> | |
+ </div> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="tools-name">Name</label> | |
+ <div class="controls"> | |
+ <input type="text" name="tools-name-1" id="tools-name" class="input-xlarge" value=""> | |
+ </div> | |
+ </div> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="tools-url">URL</label> | |
+ <div class="controls"> | |
+ <input type="url" name="tools-url-1" id="tools-url" class="input-xlarge" value=""> | |
+ </div> | |
+ </div> | |
+ </div> | |
+ </div> | |
+ </div> | |
+ </div> | |
+ <script id="tools-template" type="text/template"> | |
+ <div class="tool row"> | |
+ <div class="span12"> | |
+ <div class="control-group"> | |
+ <label class="control-label"></label> | |
+ <div class="controls"> | |
+ <h4 class="tool-title">Tool ##count##</h4> | |
+ <input type="hidden" name="tools-number-##count##" class="tools-number" value=""> | |
+ <input type="hidden" name="tools-thumb-##count##" class="tools-thumb" value=""> | |
+ <input type="hidden" name="tools-notes-##count##" class="tools-notes" value=""> | |
+ </div> | |
+ </div> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="tools-name">Name</label> | |
+ <div class="controls"> | |
+ <input type="text" name="tools-name-##count##" id="tools-name" class="input-xlarge tools-name" value=""> | |
+ </div> | |
+ </div> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="tools-url">URL</label> | |
+ <div class="controls"> | |
+ <input type="url" name="tools-url-##count##" id="tools-url" class="input-xlarge tools-url" value=""> | |
+ </div> | |
+ </div> | |
+ <div class="control-group"> | |
+ <label for="" class="control-label"></label> | |
+ <div class="controls"> | |
+ <button class="btn alignleft remove-tool"><i class="icon icon-minus"></i> Remove Tool</button> | |
+ </div> | |
+ </div> | |
+ </div> | |
+ </div> | |
+ </script> | |
+ <section class="repeater-tools"> | |
+ <div class="control-group"> | |
+ <label class="control-label" for="tools-url"></label> | |
+ <div class="controls"> | |
+ <button class="btn add-tool"><i class="icon icon-plus"></i> Add Another Tool</button> | |
+ </div> | |
+ </div> | |
+ </section> | |
+ <div class="form-actions"> | |
+ <button type="submit" class="btn btn-primary submit-tools">Save Tools</button> | |
+ </div> | |
+ </fieldset> | |
+ </form> | |
+ </section> | |
+ | |
+ <?php endwhile; else: endif; ?> | |
+ | |
+ <div> | |
+ | |
+ </div> | |
+ | |
+ </div> | |
+ | |
+ </div> | |
+ | |
+<?php get_footer(); ?> | |
\ No newline at end of file |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment