diff --git a/admin/assets/css/um-admin-columns.css b/admin/assets/css/um-admin-columns.css
index 6f0f02d7..5bac6216 100644
--- a/admin/assets/css/um-admin-columns.css
+++ b/admin/assets/css/um-admin-columns.css
@@ -3,7 +3,7 @@
-moz-osx-font-smoothing: grayscale;
}
-.um-admin.post-type-um_form .manage-column.column-id {width: 40px}
+.um-admin.post-type-um_form .manage-column.column-id {width: 60px}
.um-admin.post-type-um_form .manage-column.column-mode {width: 100px}
.um-admin.post-type-um_form .manage-column.column-title {width: 200px}
.um-admin.post-type-um_form .manage-column.column-shortcode {width: 200px}
@@ -32,7 +32,7 @@
.um-admin.post-type-um_directory td.column-shortcode,
.um-admin.post-type-um_directory td.column-id,
.um-admin.post-type-um_role td.column-count
-{color: #aaa;font-size: 14px;}
+{font-size: 14px;}
.um-admin.users-php td.column-um_actions {padding-top: 12px}
diff --git a/admin/assets/css/um-admin-misc.css b/admin/assets/css/um-admin-misc.css
index 48d22ab8..11e05f7d 100644
--- a/admin/assets/css/um-admin-misc.css
+++ b/admin/assets/css/um-admin-misc.css
@@ -1,5 +1,15 @@
/*
- - Columns
+ - Welcome
+*/
+
+.um-badge {
+ color: #fff;
+ background: none !important;
+ background: #3ba1da url(../img/logo_small.png) no-repeat center 0px !important;
+}
+
+/*
+ - General
*/
body.um-admin-modal-open {
@@ -8,9 +18,6 @@ body.um-admin-modal-open {
.um-admin #major-publishing-actions{background-color: #fff !important;border-top:0}
-.um-admin .postbox h3 {
-background: #f9f9f9;
-}
.um-admin .postbox h3 i {
font-size: 1.3em !important;
vertical-align: middle !important;
diff --git a/admin/assets/img/logo.png b/admin/assets/img/logo.png
new file mode 100644
index 00000000..98a578c7
Binary files /dev/null and b/admin/assets/img/logo.png differ
diff --git a/admin/assets/img/logo_small.png b/admin/assets/img/logo_small.png
new file mode 100644
index 00000000..43b514bf
Binary files /dev/null and b/admin/assets/img/logo_small.png differ
diff --git a/admin/core/lib/ReduxFramework/ReduxCore/framework.php b/admin/core/lib/ReduxFramework/ReduxCore/framework.php
index dbae4d20..9614712b 100644
--- a/admin/core/lib/ReduxFramework/ReduxCore/framework.php
+++ b/admin/core/lib/ReduxFramework/ReduxCore/framework.php
@@ -1299,6 +1299,9 @@
* @return void
*/
public function _options_page() {
+
+ $um_admin = new UM_Admin_API();
+
$this->import_export->in_field();
if ( $this->args['menu_type'] == 'submenu' ) {
@@ -1307,7 +1310,11 @@
add_menu_page( __('Ultimate Member', $this->slug), __('Ultimate Member', $this->slug), 'manage_options', $this->slug, array(&$this, 'admin_page'), 'dashicons-admin-users', '50.78578');
- add_submenu_page( '_welcome_to_um', __('Welcome to Ultimate Member!', $this->slug), __('Welcome to Ultimate Member!', $this->slug), 'manage_options', $this->slug . '-welcome', array(&$this, 'admin_page') );
+ foreach( $um_admin->about_tabs as $k => $tab ) {
+
+ add_submenu_page( '_'. $k . '_um', sprintf(__('%s | Ultimate Member', $this->slug), $tab), sprintf(__('%s | Ultimate Member', $this->slug), $tab), 'manage_options', $this->slug . '-' . $k, array(&$this, 'admin_page') );
+
+ }
add_submenu_page( $this->slug, __('Dashboard', $this->slug), __('Dashboard', $this->slug), 'manage_options', $this->slug, array(&$this, 'admin_page') );
@@ -1321,11 +1328,11 @@
add_submenu_page( $this->slug, __('Forms', $this->slug), __('Forms', $this->slug), 'manage_options', 'edit.php?post_type=um_form', '', '' );
- add_submenu_page( $this->slug, __('Roles', $this->slug), __('Roles', $this->slug), 'manage_options', 'edit.php?post_type=um_role', '', '' );
+ add_submenu_page( $this->slug, __('Member Levels', $this->slug), __('Member Levels', $this->slug), 'manage_options', 'edit.php?post_type=um_role', '', '' );
+
+ add_submenu_page( $this->slug, __('Member Directories', $this->slug), __('Member Directories', $this->slug), 'manage_options', 'edit.php?post_type=um_directory', '', '' );
add_submenu_page( $this->slug, __('Members', $this->slug), __('Members', $this->slug), 'manage_options', 'users.php', '', '' );
-
- add_submenu_page( $this->slug, __('Directories', $this->slug), __('Directories', $this->slug), 'manage_options', 'edit.php?post_type=um_directory', '', '' );
} else {
$this->page = add_menu_page(
@@ -4311,11 +4318,26 @@
public function admin_page(){
+ $um_admin = new UM_Admin_API();
+
$page = $_REQUEST['page'];
- if ( $page == 'ultimatemember')
-
+ if ( $page == 'ultimatemember' ) {
include_once um_path . 'admin/templates/dashboard.php';
+ }
+
+ if ( strstr( $page, 'ultimatemember-' ) ) {
+
+ $template = str_replace('ultimatemember-','',$page);
+ $file = um_path . 'admin/templates/'. $template . '.php';
+
+ if ( file_exists( $file ) ){
+ include_once um_path . 'admin/templates/'. $template . '.php';
+ } else {
+ echo '
' . __('Please create a team.php template in admin templates.','ultimatemember') . ' ';
+ }
+
+ }
}
diff --git a/admin/core/um-admin-columns.php b/admin/core/um-admin-columns.php
index aecae9c3..596d72fc 100644
--- a/admin/core/um-admin-columns.php
+++ b/admin/core/um-admin-columns.php
@@ -22,10 +22,10 @@ class UM_Admin_Columns {
$admin = new UM_Admin_Metabox();
$new_columns['cb'] = ' ';
- $new_columns['id'] = __('ID');
+ $new_columns['id'] = __('ID') . $admin->_tooltip( 'Unique ID for each form' );
$new_columns['title'] = __('Title');
- $new_columns['mode'] = __('Type');
- $new_columns['shortcode'] = __('Shortcode') . $admin->_tooltip( 'Copy this shortcode to any post/page to display the relevant form' );
+ $new_columns['mode'] = __('Type') . $admin->_tooltip( 'This is the type of the form' );
+ $new_columns['shortcode'] = __('Shortcode') . $admin->_tooltip( 'Use this shortcode to display the form' );
$new_columns['impressions'] = __('Impressions') . $admin->_tooltip( 'The total number of times this form has been viewed' );
$new_columns['conversions'] = __('Conversions') . $admin->_tooltip( 'The total number of conversions. e.g. Successful sign-ups' );
$new_columns['date'] = __('Date');
@@ -33,6 +33,23 @@ class UM_Admin_Columns {
return $new_columns;
}
+
+ /***
+ *** @Custom columns for Directory
+ ***/
+ function manage_edit_um_directory_columns($columns) {
+
+ $admin = new UM_Admin_Metabox();
+
+ $new_columns['cb'] = ' ';
+ $new_columns['id'] = __('ID') . $admin->_tooltip( 'Unique ID for each form' );
+ $new_columns['title'] = __('Title');
+ $new_columns['shortcode'] = __('Shortcode') . $admin->_tooltip( 'Use this shortcode to display the member directory' );
+ $new_columns['date'] = __('Date');
+
+ return $new_columns;
+
+ }
/***
*** @Display cusom columns for Form
@@ -75,18 +92,6 @@ class UM_Admin_Columns {
}
}
-
- /***
- *** @Custom columns for Directory
- ***/
- function manage_edit_um_directory_columns($columns) {
- $new_columns['cb'] = ' ';
- $new_columns['id'] = __('ID');
- $new_columns['title'] = __('Title');
- $new_columns['shortcode'] = __('Shortcode');
- $new_columns['date'] = __('Date');
- return $new_columns;
- }
/***
*** @Display cusom columns for Directory
diff --git a/admin/core/um-admin-enqueue.php b/admin/core/um-admin-enqueue.php
index c9e16b69..5b5d27ba 100644
--- a/admin/core/um-admin-enqueue.php
+++ b/admin/core/um-admin-enqueue.php
@@ -12,10 +12,25 @@ class UM_Admin_Enqueue {
add_filter('admin_body_class', array(&$this, 'admin_body_class'), 9 );
- add_filter( 'enter_title_here', array(&$this, 'enter_title_here') );
+ add_filter('enter_title_here', array(&$this, 'enter_title_here') );
+ add_filter('admin_footer_text', array(&$this, 'admin_footer_text') );
+
}
+ /***
+ *** @Show footer text
+ ***/
+ function admin_footer_text() {
+ $copyright = sprintf(__('Thank you for creating with Ultimate Member and WordPress .','ultimatemember'));
+
+ if ( um_get_option('admin_load_time') == 1 ) {
+ $copyright .= ' ' . sprintf(__('%1$s queries made in %2$s seconds','ultimatemember'), get_num_queries(), timer_stop(0) );
+ }
+
+ return '';
+ }
+
/***
*** @enter title placeholder
***/
@@ -42,8 +57,8 @@ class UM_Admin_Enqueue {
if ( strstr($screen_id, 'um_form') ) $highlighted_id = 3;
if ( strstr($screen_id, 'um_role') ) $highlighted_id = 4;
- if ( strstr($screen_id, 'um_directory') ) $highlighted_id = 6;
- if ( strstr($screen_id, 'user') || strstr($screen_id, 'profile') ) $highlighted_id = 5;
+ if ( strstr($screen_id, 'um_directory') ) $highlighted_id = 5;
+ if ( strstr($screen_id, 'user') || strstr($screen_id, 'profile') ) $highlighted_id = 6;
if ( isset($highlighted_id) ) { ?>
diff --git a/admin/core/um-admin-notices.php b/admin/core/um-admin-notices.php
index 3c47a5d7..20446390 100644
--- a/admin/core/um-admin-notices.php
+++ b/admin/core/um-admin-notices.php
@@ -5,9 +5,6 @@ class UM_Admin_Notices {
function __construct() {
add_action('admin_notices', array(&$this, 'admin_notices'));
-
- add_action('admin_notices', array(&$this, 'um_admin_notices'));
-
}
/***
@@ -47,21 +44,4 @@ class UM_Admin_Notices {
}
- /***
- *** @For custom-styled notices
- ***/
- function um_admin_notices() {
-
- $notices = get_option('um_admin_notices');
- if ( $notices ) {
-
- foreach($notices as $notice){
- echo "";
- }
-
- }
- }
-
}
\ No newline at end of file
diff --git a/admin/core/um-admin-redux.php b/admin/core/um-admin-redux.php
index 3386a451..a9cee43a 100644
--- a/admin/core/um-admin-redux.php
+++ b/admin/core/um-admin-redux.php
@@ -61,7 +61,7 @@
'google_api_key' => '', // Must be defined to add google fonts to the typography module
'async_typography' => true, // Use a asynchronous font on the front end or font string
- 'admin_bar' => true, // Show the panel pages on the admin bar
+ 'admin_bar' => false, // Show the panel pages on the admin bar
'global_variable' => '', // Set a different name for your global variable other than the opt_name
'dev_mode' => false, // Show the time the page took to load, etc
'customizer' => false, // Enable basic customizer support
diff --git a/admin/templates/about.php b/admin/templates/about.php
new file mode 100644
index 00000000..9cb27749
--- /dev/null
+++ b/admin/templates/about.php
@@ -0,0 +1,99 @@
+
+
+
+
+
+
Introducing Twenty Fifteen
+
+
+
+
+
+
+
Our newest default theme, Twenty Fifteen, is a blog-focused theme designed for clarity.
+
Twenty Fifteen has flawless language support, with help from Google’s Noto font family .
+
The straightforward typography is readable on any screen size.
+
Your content always takes center stage, whether viewed on a phone, tablet, laptop, or desktop computer.
+
+
+
+
+
+
+
+
+
+
+
+
+
Distraction-free writing
+
+
+
+
+
Just write.
+
Sometimes, you just need to concentrate on putting your thoughts into words. Try turning on distraction-free writing mode . When you start typing, all the distractions will fade away, letting you focus solely on your writing. All your editing tools instantly return when you need them.
+
+
+
+
+
+
+
The Finer Points
+
+
+
+
Choose a language
+
Right now, WordPress 4.1 is already translated into 40 languages, with more always in progress. You can switch to any translation on the General Settings screen.
+
+
+
+
Vine embeds
+
Embedding videos from Vine is as simple as pasting a URL onto its own line in a post. See the full list of supported embeds.
+
+
+
+
Log out everywhere
+
If you’ve ever worried you forgot to sign out from a shared computer, you can now go to your profile and log out everywhere.
+
+
+
+
Plugin recommendations
+
The plugin installer suggests plugins for you to try. Recommendations are based on the plugins you and other users have installed.
+
+
+
+
+
+
+
+
+
+
Under the Hood
+
+
+
+
Complex Queries
+
Metadata, date, and term queries now support advanced conditional logic, like nested clauses and multiple operators — A AND ( B OR C ).
+
+
Customizer API
+
Expanded JavaScript APIs in the customizer enable a new media experience as well as dynamic and contextual controls, sections, and panels.
+
+
+
<title> tags in themes
+
add_theme_support( 'title-tag' ) tells WordPress to handle the complexities of document titles.
+
+
Developer Reference
+
Continued improvements to inline code documentation have made the developer reference more complete than ever.
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/admin/templates/about_header.php b/admin/templates/about_header.php
new file mode 100644
index 00000000..97f0cbc7
--- /dev/null
+++ b/admin/templates/about_header.php
@@ -0,0 +1,24 @@
+
+ Welcome to Ultimate Member
+
+ Thank you for installing! Ultimate Member is a powerful community and membership plugin that allows you to create beautiful community and membership sites with WordPress.
+
+ Version
+
+
+
+ about_tabs as $k => $tab ) {
+
+ if ( $k == $template ) {
+ $active = 'nav-tab-active';
+ } else {
+ $active = '';
+ }
+
+ ?>
+
+
+
+
+
+
\ No newline at end of file
diff --git a/admin/templates/start.php b/admin/templates/start.php
new file mode 100644
index 00000000..edf8b46d
--- /dev/null
+++ b/admin/templates/start.php
@@ -0,0 +1,99 @@
+
+
+
+
+
+
Introducing Twenty Fifteen
+
+
+
+
+
+
+
Our newest default theme, Twenty Fifteen, is a blog-focused theme designed for clarity.
+
Twenty Fifteen has flawless language support, with help from Google’s Noto font family .
+
The straightforward typography is readable on any screen size.
+
Your content always takes center stage, whether viewed on a phone, tablet, laptop, or desktop computer.
+
+
+
+
+
+
+
+
+
+
+
+
+
Distraction-free writing
+
+
+
+
+
Just write.
+
Sometimes, you just need to concentrate on putting your thoughts into words. Try turning on distraction-free writing mode . When you start typing, all the distractions will fade away, letting you focus solely on your writing. All your editing tools instantly return when you need them.
+
+
+
+
+
+
+
The Finer Points
+
+
+
+
Choose a language
+
Right now, WordPress 4.1 is already translated into 40 languages, with more always in progress. You can switch to any translation on the General Settings screen.
+
+
+
+
Vine embeds
+
Embedding videos from Vine is as simple as pasting a URL onto its own line in a post. See the full list of supported embeds.
+
+
+
+
Log out everywhere
+
If you’ve ever worried you forgot to sign out from a shared computer, you can now go to your profile and log out everywhere.
+
+
+
+
Plugin recommendations
+
The plugin installer suggests plugins for you to try. Recommendations are based on the plugins you and other users have installed.
+
+
+
+
+
+
+
+
+
+
Under the Hood
+
+
+
+
Complex Queries
+
Metadata, date, and term queries now support advanced conditional logic, like nested clauses and multiple operators — A AND ( B OR C ).
+
+
Customizer API
+
Expanded JavaScript APIs in the customizer enable a new media experience as well as dynamic and contextual controls, sections, and panels.
+
+
+
<title> tags in themes
+
add_theme_support( 'title-tag' ) tells WordPress to handle the complexities of document titles.
+
+
Developer Reference
+
Continued improvements to inline code documentation have made the developer reference more complete than ever.
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/admin/templates/welcome.php b/admin/templates/welcome.php
deleted file mode 100644
index e69de29b..00000000
diff --git a/admin/um-admin-init.php b/admin/um-admin-init.php
index 89e7daab..70295881 100644
--- a/admin/um-admin-init.php
+++ b/admin/um-admin-init.php
@@ -8,6 +8,17 @@ class UM_Admin_API {
add_action('admin_init', array(&$this, 'admin_init'), 0);
+ if ( !class_exists( 'ReduxFramework' ) && file_exists( um_path . 'admin/core/lib/ReduxFramework/ReduxCore/framework.php' ) ) {
+ require_once( um_path . 'admin/core/lib/ReduxFramework/ReduxCore/framework.php' );
+ }
+ if ( file_exists ( um_path . 'admin/core/um-admin-redux.php' ) ) {
+ require_once( um_path . 'admin/core/um-admin-redux.php' );
+ }
+
+
+ $this->about_tabs['about'] = 'About';
+ $this->about_tabs['start'] = 'Getting Started';
+
}
/***
diff --git a/assets/css/um-styles.css b/assets/css/um-styles.css
index 1c8fcb33..b6bd28c7 100644
--- a/assets/css/um-styles.css
+++ b/assets/css/um-styles.css
@@ -26,6 +26,10 @@
box-sizing: content-box;
}
+.um a:focus {
+ outline: 0 !important;
+}
+
/* only in admin mode */
.um.um-in-admin {
padding-top: 0;
diff --git a/assets/js/um-fileupload.js b/assets/js/um-fileupload.js
index c5e82d85..9f02a168 100644
--- a/assets/js/um-fileupload.js
+++ b/assets/js/um-fileupload.js
@@ -5,4 +5,4 @@
* Copyright (c) 2013 Ravishanker Kusuma
* http://hayageek.com/
*/
-(function(b){if(b.fn.ajaxForm==undefined){b.getScript("http://malsup.github.io/jquery.form.js")}var a={};a.fileapi=b(" ").get(0).files!==undefined;a.formdata=window.FormData!==undefined;b.fn.uploadFile=function(t){var r=b.extend({url:"",method:"POST",enctype:"multipart/form-data",formData:null,returnType:null,allowedTypes:"*",fileName:"file",formData:{},dynamicFormData:function(){return{}},maxFileSize:-1,maxFileCount:-1,multiple:true,dragDrop:true,autoSubmit:true,showCancel:true,showAbort:true,showDone:true,showDelete:false,showError:true,showStatusAfterSuccess:true,showStatusAfterError:true,showFileCounter:true,fileCounterStyle:"). ",showProgress:false,onSelect:function(s){return true},onSubmit:function(s,u){},onSuccess:function(u,s,v){},onError:function(v,s,u){},deleteCallback:false,afterUploadAll:false,uploadButtonClass:"upload",dragDropStr:"",abortStr:"Abort",cancelStr:"Cancel",deletelStr:"Delete",doneStr:"Done",multiDragErrorStr:"Multiple File Drag & Drop is not allowed.",extErrorStr:"",sizeErrorStr:"",uploadErrorStr:"Upload is not allowed",maxFileCountErrorStr:""},t);this.fileCounter=1;this.selectedFiles=0;this.fCounter=0;this.sCounter=0;this.tCounter=0;var d="upload-"+(new Date().getTime());this.formGroup=d;this.hide();this.errorLog=b("
");this.after(this.errorLog);this.responses=[];if(!a.formdata){r.dragDrop=false}if(!a.formdata){r.multiple=false}var m=this;var e=b(""+b(this).html()+"
");b(e).addClass(r.uploadButtonClass);(function k(){if(b.fn.ajaxForm){if(r.dragDrop){var s=b('
');b(m).before(s);b(s).append(e);b(s).prepend(b(r.dragDropStr));f(m,r,s)}else{b(m).before(e)}q(m,d,r,e)}else{window.setTimeout(k,10)}})();this.startUpload=function(){b("."+this.formGroup).each(function(u,s){if(b(this).is("form")){b(this).submit()}})};this.stopUpload=function(){b(".upload-red").each(function(u,s){if(b(this).hasClass(m.formGroup)){b(this).click()}})};this.getResponses=function(){return this.responses};var g=false;function j(){if(r.afterUploadAll&&!g){g=true;(function s(){if(m.sCounter!=0&&(m.sCounter+m.fCounter==m.tCounter)){r.afterUploadAll(m);g=false}else{window.setTimeout(s,100)}})()}}function f(w,u,v){v.on("dragenter",function(s){s.stopPropagation();s.preventDefault();b(this).css("border","3px dashed #ddd")});v.on("dragover",function(s){s.stopPropagation();s.preventDefault()});v.on("drop",function(x){b(this).css("border","3px dashed #ddd");x.preventDefault();w.errorLog.html("");var s=x.originalEvent.dataTransfer.files;if(!u.multiple&&s.length>1){if(u.showError){b(""+u.multiDragErrorStr+"
").appendTo(w.errorLog)}return}if(u.onSelect(s)==false){return}l(u,w,s)});b(document).on("dragenter",function(s){s.stopPropagation();s.preventDefault()});b(document).on("dragover",function(s){s.stopPropagation();s.preventDefault();v.css("border","3px dashed #ddd")});b(document).on("drop",function(s){s.stopPropagation();s.preventDefault();v.css("border","3px dashed #ddd")})}function i(s){var v="";var u=s/1024;if(parseInt(u)>1024){var w=u/1024;v=w.toFixed(2)+" MB"}else{v=u.toFixed(2)+" KB"}return v}function o(x){var y=[];if(jQuery.type(x)=="string"){y=x.split("&")}else{y=b.param(x).split("&")}var u=y.length;var s=[];var w,v;for(w=0;w"+H.extErrorStr+"").appendTo(B.errorLog)}continue}if(H.maxFileSize!=-1&&u[C].size>H.maxFileSize){if(H.showError){b(" "+H.sizeErrorStr+"
").appendTo(B.errorLog)}continue}if(H.maxFileCount!=-1&&B.selectedFiles>=H.maxFileCount){if(H.showError){b(""+H.maxFileCountErrorStr+"
").appendTo(B.errorLog)}continue}B.selectedFiles++;var D=H;var w=new FormData();var A=H.fileName.replace("[]","");w.append(A,u[C]);var y=H.formData;if(y){var F=o(y);for(var z=0;z");v.appendTo("body");var x=[];x.push(u[C].name);n(v,D,E,x,B);B.fileCounter++}}function c(w,v,y){var x=v.allowedTypes.toLowerCase().split(",");var u=y.split(".").pop().toLowerCase();if(v.allowedTypes!="*"&&jQuery.inArray(u,x)<0){return false}return true}function h(u,w){if(u.showFileCounter){var v=b(".upload-filename").length;w.fileCounter=v+1;b(".upload-filename").each(function(A,y){var s=b(this).html().split(u.fileCounterStyle);var x=parseInt(s[0])-1;var z=v+u.fileCounterStyle+s[1];b(this).html(z);v--})}}function q(y,B,D,u){var A="ajax-upload-id-"+(new Date().getTime());var w=b("");var v=" ";if(D.multiple){if(D.fileName.indexOf("[]")!=D.fileName.length-2){D.fileName+="[]"}v=" "}var z=b(v).appendTo(w);z.change(function(){y.errorLog.html("");var K=D.allowedTypes.toLowerCase().split(",");var G=[];if(this.files){for(H=0;H"+D.extErrorStr+"").appendTo(y.errorLog)}return}F.push({name:I,size:"NA"});if(D.onSelect(F)==false){return}}h(D,y);u.unbind("click");w.hide();q(y,B,D,u);w.addClass(B);if(a.fileapi&&a.formdata){w.removeClass(B);var J=this.files;l(D,y,J)}else{var E="";for(var H=0;H"}else{E+=G[H]+" "}y.fileCounter++}if(D.maxFileCount!=-1&&(y.selectedFiles+G.length)>D.maxFileCount){if(D.showError){b(""+D.maxFileCountErrorStr+"
").appendTo(y.errorLog)}return}y.selectedFiles+=G.length;var s=new p(y,D);s.filename.html(E);n(w,D,s,G,y)}});w.css({margin:0,padding:0});var C=b(u).width()+10;if(C==10){C=120}var x=u.height()+10;if(x==10){x=35}u.css({position:"relative",overflow:"hidden",cursor:"default"});z.css({position:"absolute",cursor:"pointer",top:"0px",width:'100%',height:'34px',left:"0px","z-index":"100",opacity:"0.0",filter:"alpha(opacity=0)","-ms-filter":"alpha(opacity=0)","-khtml-opacity":"0.0","-moz-opacity":"0.0"});w.appendTo(u)}function p(v,u){this.statusbar=b("
");this.filename=b("
").appendTo(this.statusbar);this.progressDiv=b("").appendTo(this.statusbar).hide();this.progressbar=b("
").appendTo(this.progressDiv);this.abort=b("
"+u.abortStr+"
").appendTo(this.statusbar).hide();this.cancel=b("
"+u.cancelStr+"
").appendTo(this.statusbar).hide();this.done=b("
"+u.doneStr+"
").appendTo(this.statusbar).hide();this.del=b("
"+u.deletelStr+"
").appendTo(this.statusbar).hide();v.errorLog.after(this.statusbar);return this}function n(z,y,u,w,A){var x=null;var v={cache:false,contentType:false,processData:false,forceSync:false,data:y.formData,formData:y.fileData,dataType:y.returnType,beforeSubmit:function(F,C,E){if(y.onSubmit.call(this,w)!=false){var B=y.dynamicFormData();if(B){var s=o(B);if(s){for(var D=0;D
"+y.uploadErrorStr+" ");u.cancel.show();z.remove();u.cancel.click(function(){u.statusbar.remove()});return false},beforeSend:function(B,s){u.progressDiv.show();u.cancel.hide();u.done.hide();if(y.showAbort){u.abort.show();u.abort.click(function(){B.abort();A.selectedFiles-=w.length})}if(!a.formdata){u.progressbar.width("5%")}else{u.progressbar.width("1%")}},uploadProgress:function(E,s,D,C){if(C>98){C=98}var B=C+"%";if(C>1){u.progressbar.width(B)}if(y.showProgress){u.progressbar.html(B);u.progressbar.css("text-align","center")}},success:function(B,s,C){A.responses.push(B);u.progressbar.width("100%");if(y.showProgress){u.progressbar.html("100%");u.progressbar.css("text-align","center")}u.abort.hide();y.onSuccess.call(this,w,B,C);if(y.showStatusAfterSuccess){if(y.showDone){u.done.show();u.done.click(function(){u.statusbar.hide("slow");u.statusbar.remove()})}else{u.done.hide()}if(y.showDelete){u.del.show();u.del.click(function(){u.statusbar.hide().remove();if(y.deleteCallback){y.deleteCallback.call(this,B,u)}A.selectedFiles-=w.length;h(y,A)})}else{u.del.hide()}}else{u.statusbar.hide("slow");u.statusbar.remove()}z.remove();A.sCounter+=w.length},error:function(C,s,B){u.abort.hide();if(C.statusText=="abort"){u.statusbar.hide("slow").remove();h(y,A)}else{y.onError.call(this,w,s,B);if(y.showStatusAfterError){u.progressDiv.hide();u.statusbar.append("ERROR: "+B+" ")}else{u.statusbar.hide();u.statusbar.remove()}A.selectedFiles-=w.length}z.remove();A.fCounter+=w.length}};if(y.autoSubmit){z.ajaxSubmit(v)}else{if(y.showCancel){u.cancel.show();u.cancel.click(function(){z.remove();u.statusbar.remove();A.selectedFiles-=w.length;h(y,A)})}z.ajaxForm(v)}}return this}}(jQuery));
\ No newline at end of file
+(function(b){if(b.fn.ajaxForm==undefined){}var a={};a.fileapi=b(" ").get(0).files!==undefined;a.formdata=window.FormData!==undefined;b.fn.uploadFile=function(t){var r=b.extend({url:"",method:"POST",enctype:"multipart/form-data",formData:null,returnType:null,allowedTypes:"*",fileName:"file",formData:{},dynamicFormData:function(){return{}},maxFileSize:-1,maxFileCount:-1,multiple:true,dragDrop:true,autoSubmit:true,showCancel:true,showAbort:true,showDone:true,showDelete:false,showError:true,showStatusAfterSuccess:true,showStatusAfterError:true,showFileCounter:true,fileCounterStyle:"). ",showProgress:false,onSelect:function(s){return true},onSubmit:function(s,u){},onSuccess:function(u,s,v){},onError:function(v,s,u){},deleteCallback:false,afterUploadAll:false,uploadButtonClass:"upload",dragDropStr:"",abortStr:"Abort",cancelStr:"Cancel",deletelStr:"Delete",doneStr:"Done",multiDragErrorStr:"Multiple File Drag & Drop is not allowed.",extErrorStr:"",sizeErrorStr:"",uploadErrorStr:"Upload is not allowed",maxFileCountErrorStr:""},t);this.fileCounter=1;this.selectedFiles=0;this.fCounter=0;this.sCounter=0;this.tCounter=0;var d="upload-"+(new Date().getTime());this.formGroup=d;this.hide();this.errorLog=b("
");this.after(this.errorLog);this.responses=[];if(!a.formdata){r.dragDrop=false}if(!a.formdata){r.multiple=false}var m=this;var e=b(""+b(this).html()+"
");b(e).addClass(r.uploadButtonClass);(function k(){if(b.fn.ajaxForm){if(r.dragDrop){var s=b('
');b(m).before(s);b(s).append(e);b(s).prepend(b(r.dragDropStr));f(m,r,s)}else{b(m).before(e)}q(m,d,r,e)}else{window.setTimeout(k,10)}})();this.startUpload=function(){b("."+this.formGroup).each(function(u,s){if(b(this).is("form")){b(this).submit()}})};this.stopUpload=function(){b(".upload-red").each(function(u,s){if(b(this).hasClass(m.formGroup)){b(this).click()}})};this.getResponses=function(){return this.responses};var g=false;function j(){if(r.afterUploadAll&&!g){g=true;(function s(){if(m.sCounter!=0&&(m.sCounter+m.fCounter==m.tCounter)){r.afterUploadAll(m);g=false}else{window.setTimeout(s,100)}})()}}function f(w,u,v){v.on("dragenter",function(s){s.stopPropagation();s.preventDefault();b(this).css("border","3px dashed #ddd")});v.on("dragover",function(s){s.stopPropagation();s.preventDefault()});v.on("drop",function(x){b(this).css("border","3px dashed #ddd");x.preventDefault();w.errorLog.html("");var s=x.originalEvent.dataTransfer.files;if(!u.multiple&&s.length>1){if(u.showError){b(""+u.multiDragErrorStr+"
").appendTo(w.errorLog)}return}if(u.onSelect(s)==false){return}l(u,w,s)});b(document).on("dragenter",function(s){s.stopPropagation();s.preventDefault()});b(document).on("dragover",function(s){s.stopPropagation();s.preventDefault();v.css("border","3px dashed #ddd")});b(document).on("drop",function(s){s.stopPropagation();s.preventDefault();v.css("border","3px dashed #ddd")})}function i(s){var v="";var u=s/1024;if(parseInt(u)>1024){var w=u/1024;v=w.toFixed(2)+" MB"}else{v=u.toFixed(2)+" KB"}return v}function o(x){var y=[];if(jQuery.type(x)=="string"){y=x.split("&")}else{y=b.param(x).split("&")}var u=y.length;var s=[];var w,v;for(w=0;w"+H.extErrorStr+"").appendTo(B.errorLog)}continue}if(H.maxFileSize!=-1&&u[C].size>H.maxFileSize){if(H.showError){b(" "+H.sizeErrorStr+"
").appendTo(B.errorLog)}continue}if(H.maxFileCount!=-1&&B.selectedFiles>=H.maxFileCount){if(H.showError){b(""+H.maxFileCountErrorStr+"
").appendTo(B.errorLog)}continue}B.selectedFiles++;var D=H;var w=new FormData();var A=H.fileName.replace("[]","");w.append(A,u[C]);var y=H.formData;if(y){var F=o(y);for(var z=0;z");v.appendTo("body");var x=[];x.push(u[C].name);n(v,D,E,x,B);B.fileCounter++}}function c(w,v,y){var x=v.allowedTypes.toLowerCase().split(",");var u=y.split(".").pop().toLowerCase();if(v.allowedTypes!="*"&&jQuery.inArray(u,x)<0){return false}return true}function h(u,w){if(u.showFileCounter){var v=b(".upload-filename").length;w.fileCounter=v+1;b(".upload-filename").each(function(A,y){var s=b(this).html().split(u.fileCounterStyle);var x=parseInt(s[0])-1;var z=v+u.fileCounterStyle+s[1];b(this).html(z);v--})}}function q(y,B,D,u){var A="ajax-upload-id-"+(new Date().getTime());var w=b("");var v=" ";if(D.multiple){if(D.fileName.indexOf("[]")!=D.fileName.length-2){D.fileName+="[]"}v=" "}var z=b(v).appendTo(w);z.change(function(){y.errorLog.html("");var K=D.allowedTypes.toLowerCase().split(",");var G=[];if(this.files){for(H=0;H"+D.extErrorStr+"").appendTo(y.errorLog)}return}F.push({name:I,size:"NA"});if(D.onSelect(F)==false){return}}h(D,y);u.unbind("click");w.hide();q(y,B,D,u);w.addClass(B);if(a.fileapi&&a.formdata){w.removeClass(B);var J=this.files;l(D,y,J)}else{var E="";for(var H=0;H"}else{E+=G[H]+" "}y.fileCounter++}if(D.maxFileCount!=-1&&(y.selectedFiles+G.length)>D.maxFileCount){if(D.showError){b(""+D.maxFileCountErrorStr+"
").appendTo(y.errorLog)}return}y.selectedFiles+=G.length;var s=new p(y,D);s.filename.html(E);n(w,D,s,G,y)}});w.css({margin:0,padding:0});var C=b(u).width()+10;if(C==10){C=120}var x=u.height()+10;if(x==10){x=35}u.css({position:"relative",overflow:"hidden",cursor:"default"});z.css({position:"absolute",cursor:"pointer",top:"0px",width:'100%',height:'34px',left:"0px","z-index":"100",opacity:"0.0",filter:"alpha(opacity=0)","-ms-filter":"alpha(opacity=0)","-khtml-opacity":"0.0","-moz-opacity":"0.0"});w.appendTo(u)}function p(v,u){this.statusbar=b("
");this.filename=b("
").appendTo(this.statusbar);this.progressDiv=b("").appendTo(this.statusbar).hide();this.progressbar=b("
").appendTo(this.progressDiv);this.abort=b("
"+u.abortStr+"
").appendTo(this.statusbar).hide();this.cancel=b("
"+u.cancelStr+"
").appendTo(this.statusbar).hide();this.done=b("
"+u.doneStr+"
").appendTo(this.statusbar).hide();this.del=b("
"+u.deletelStr+"
").appendTo(this.statusbar).hide();v.errorLog.after(this.statusbar);return this}function n(z,y,u,w,A){var x=null;var v={cache:false,contentType:false,processData:false,forceSync:false,data:y.formData,formData:y.fileData,dataType:y.returnType,beforeSubmit:function(F,C,E){if(y.onSubmit.call(this,w)!=false){var B=y.dynamicFormData();if(B){var s=o(B);if(s){for(var D=0;D
"+y.uploadErrorStr+" ");u.cancel.show();z.remove();u.cancel.click(function(){u.statusbar.remove()});return false},beforeSend:function(B,s){u.progressDiv.show();u.cancel.hide();u.done.hide();if(y.showAbort){u.abort.show();u.abort.click(function(){B.abort();A.selectedFiles-=w.length})}if(!a.formdata){u.progressbar.width("5%")}else{u.progressbar.width("1%")}},uploadProgress:function(E,s,D,C){if(C>98){C=98}var B=C+"%";if(C>1){u.progressbar.width(B)}if(y.showProgress){u.progressbar.html(B);u.progressbar.css("text-align","center")}},success:function(B,s,C){A.responses.push(B);u.progressbar.width("100%");if(y.showProgress){u.progressbar.html("100%");u.progressbar.css("text-align","center")}u.abort.hide();y.onSuccess.call(this,w,B,C);if(y.showStatusAfterSuccess){if(y.showDone){u.done.show();u.done.click(function(){u.statusbar.hide("slow");u.statusbar.remove()})}else{u.done.hide()}if(y.showDelete){u.del.show();u.del.click(function(){u.statusbar.hide().remove();if(y.deleteCallback){y.deleteCallback.call(this,B,u)}A.selectedFiles-=w.length;h(y,A)})}else{u.del.hide()}}else{u.statusbar.hide("slow");u.statusbar.remove()}z.remove();A.sCounter+=w.length},error:function(C,s,B){u.abort.hide();if(C.statusText=="abort"){u.statusbar.hide("slow").remove();h(y,A)}else{y.onError.call(this,w,s,B);if(y.showStatusAfterError){u.progressDiv.hide();u.statusbar.append("ERROR: "+B+" ")}else{u.statusbar.hide();u.statusbar.remove()}A.selectedFiles-=w.length}z.remove();A.fCounter+=w.length}};if(y.autoSubmit){z.ajaxSubmit(v)}else{if(y.showCancel){u.cancel.show();u.cancel.click(function(){z.remove();u.statusbar.remove();A.selectedFiles-=w.length;h(y,A)})}z.ajaxForm(v)}}return this}}(jQuery));
\ No newline at end of file
diff --git a/assets/js/um-jquery-form.js b/assets/js/um-jquery-form.js
new file mode 100644
index 00000000..591ad6f1
--- /dev/null
+++ b/assets/js/um-jquery-form.js
@@ -0,0 +1,1277 @@
+/*!
+ * jQuery Form Plugin
+ * version: 3.51.0-2014.06.20
+ * Requires jQuery v1.5 or later
+ * Copyright (c) 2014 M. Alsup
+ * Examples and documentation at: http://malsup.com/jquery/form/
+ * Project repository: https://github.com/malsup/form
+ * Dual licensed under the MIT and GPL licenses.
+ * https://github.com/malsup/form#copyright-and-license
+ */
+/*global ActiveXObject */
+
+// AMD support
+(function (factory) {
+ "use strict";
+ if (typeof define === 'function' && define.amd) {
+ // using AMD; register as anon module
+ define(['jquery'], factory);
+ } else {
+ // no AMD; invoke directly
+ factory( (typeof(jQuery) != 'undefined') ? jQuery : window.Zepto );
+ }
+}
+
+(function($) {
+"use strict";
+
+/*
+ Usage Note:
+ -----------
+ Do not use both ajaxSubmit and ajaxForm on the same form. These
+ functions are mutually exclusive. Use ajaxSubmit if you want
+ to bind your own submit handler to the form. For example,
+
+ $(document).ready(function() {
+ $('#myForm').on('submit', function(e) {
+ e.preventDefault(); // <-- important
+ $(this).ajaxSubmit({
+ target: '#output'
+ });
+ });
+ });
+
+ Use ajaxForm when you want the plugin to manage all the event binding
+ for you. For example,
+
+ $(document).ready(function() {
+ $('#myForm').ajaxForm({
+ target: '#output'
+ });
+ });
+
+ You can also use ajaxForm with delegation (requires jQuery v1.7+), so the
+ form does not have to exist when you invoke ajaxForm:
+
+ $('#myForm').ajaxForm({
+ delegation: true,
+ target: '#output'
+ });
+
+ When using ajaxForm, the ajaxSubmit function will be invoked for you
+ at the appropriate time.
+*/
+
+/**
+ * Feature detection
+ */
+var feature = {};
+feature.fileapi = $(" ").get(0).files !== undefined;
+feature.formdata = window.FormData !== undefined;
+
+var hasProp = !!$.fn.prop;
+
+// attr2 uses prop when it can but checks the return type for
+// an expected string. this accounts for the case where a form
+// contains inputs with names like "action" or "method"; in those
+// cases "prop" returns the element
+$.fn.attr2 = function() {
+ if ( ! hasProp ) {
+ return this.attr.apply(this, arguments);
+ }
+ var val = this.prop.apply(this, arguments);
+ if ( ( val && val.jquery ) || typeof val === 'string' ) {
+ return val;
+ }
+ return this.attr.apply(this, arguments);
+};
+
+/**
+ * ajaxSubmit() provides a mechanism for immediately submitting
+ * an HTML form using AJAX.
+ */
+$.fn.ajaxSubmit = function(options) {
+ /*jshint scripturl:true */
+
+ // fast fail if nothing selected (http://dev.jquery.com/ticket/2752)
+ if (!this.length) {
+ log('ajaxSubmit: skipping submit process - no element selected');
+ return this;
+ }
+
+ var method, action, url, $form = this;
+
+ if (typeof options == 'function') {
+ options = { success: options };
+ }
+ else if ( options === undefined ) {
+ options = {};
+ }
+
+ method = options.type || this.attr2('method');
+ action = options.url || this.attr2('action');
+
+ url = (typeof action === 'string') ? $.trim(action) : '';
+ url = url || window.location.href || '';
+ if (url) {
+ // clean url (don't include hash vaue)
+ url = (url.match(/^([^#]+)/)||[])[1];
+ }
+
+ options = $.extend(true, {
+ url: url,
+ success: $.ajaxSettings.success,
+ type: method || $.ajaxSettings.type,
+ iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
+ }, options);
+
+ // hook for manipulating the form data before it is extracted;
+ // convenient for use with rich editors like tinyMCE or FCKEditor
+ var veto = {};
+ this.trigger('form-pre-serialize', [this, options, veto]);
+ if (veto.veto) {
+ log('ajaxSubmit: submit vetoed via form-pre-serialize trigger');
+ return this;
+ }
+
+ // provide opportunity to alter form data before it is serialized
+ if (options.beforeSerialize && options.beforeSerialize(this, options) === false) {
+ log('ajaxSubmit: submit aborted via beforeSerialize callback');
+ return this;
+ }
+
+ var traditional = options.traditional;
+ if ( traditional === undefined ) {
+ traditional = $.ajaxSettings.traditional;
+ }
+
+ var elements = [];
+ var qx, a = this.formToArray(options.semantic, elements);
+ if (options.data) {
+ options.extraData = options.data;
+ qx = $.param(options.data, traditional);
+ }
+
+ // give pre-submit callback an opportunity to abort the submit
+ if (options.beforeSubmit && options.beforeSubmit(a, this, options) === false) {
+ log('ajaxSubmit: submit aborted via beforeSubmit callback');
+ return this;
+ }
+
+ // fire vetoable 'validate' event
+ this.trigger('form-submit-validate', [a, this, options, veto]);
+ if (veto.veto) {
+ log('ajaxSubmit: submit vetoed via form-submit-validate trigger');
+ return this;
+ }
+
+ var q = $.param(a, traditional);
+ if (qx) {
+ q = ( q ? (q + '&' + qx) : qx );
+ }
+ if (options.type.toUpperCase() == 'GET') {
+ options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
+ options.data = null; // data is null for 'get'
+ }
+ else {
+ options.data = q; // data is the query string for 'post'
+ }
+
+ var callbacks = [];
+ if (options.resetForm) {
+ callbacks.push(function() { $form.resetForm(); });
+ }
+ if (options.clearForm) {
+ callbacks.push(function() { $form.clearForm(options.includeHidden); });
+ }
+
+ // perform a load on the target only if dataType is not provided
+ if (!options.dataType && options.target) {
+ var oldSuccess = options.success || function(){};
+ callbacks.push(function(data) {
+ var fn = options.replaceTarget ? 'replaceWith' : 'html';
+ $(options.target)[fn](data).each(oldSuccess, arguments);
+ });
+ }
+ else if (options.success) {
+ callbacks.push(options.success);
+ }
+
+ options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
+ var context = options.context || this ; // jQuery 1.4+ supports scope context
+ for (var i=0, max=callbacks.length; i < max; i++) {
+ callbacks[i].apply(context, [data, status, xhr || $form, $form]);
+ }
+ };
+
+ if (options.error) {
+ var oldError = options.error;
+ options.error = function(xhr, status, error) {
+ var context = options.context || this;
+ oldError.apply(context, [xhr, status, error, $form]);
+ };
+ }
+
+ if (options.complete) {
+ var oldComplete = options.complete;
+ options.complete = function(xhr, status) {
+ var context = options.context || this;
+ oldComplete.apply(context, [xhr, status, $form]);
+ };
+ }
+
+ // are there files to upload?
+
+ // [value] (issue #113), also see comment:
+ // https://github.com/malsup/form/commit/588306aedba1de01388032d5f42a60159eea9228#commitcomment-2180219
+ var fileInputs = $('input[type=file]:enabled', this).filter(function() { return $(this).val() !== ''; });
+
+ var hasFileInputs = fileInputs.length > 0;
+ var mp = 'multipart/form-data';
+ var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
+
+ var fileAPI = feature.fileapi && feature.formdata;
+ log("fileAPI :" + fileAPI);
+ var shouldUseFrame = (hasFileInputs || multipart) && !fileAPI;
+
+ var jqxhr;
+
+ // options.iframe allows user to force iframe mode
+ // 06-NOV-09: now defaulting to iframe mode if file input is detected
+ if (options.iframe !== false && (options.iframe || shouldUseFrame)) {
+ // hack to fix Safari hang (thanks to Tim Molendijk for this)
+ // see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
+ if (options.closeKeepAlive) {
+ $.get(options.closeKeepAlive, function() {
+ jqxhr = fileUploadIframe(a);
+ });
+ }
+ else {
+ jqxhr = fileUploadIframe(a);
+ }
+ }
+ else if ((hasFileInputs || multipart) && fileAPI) {
+ jqxhr = fileUploadXhr(a);
+ }
+ else {
+ jqxhr = $.ajax(options);
+ }
+
+ $form.removeData('jqxhr').data('jqxhr', jqxhr);
+
+ // clear element array
+ for (var k=0; k < elements.length; k++) {
+ elements[k] = null;
+ }
+
+ // fire 'notify' event
+ this.trigger('form-submit-notify', [this, options]);
+ return this;
+
+ // utility fn for deep serialization
+ function deepSerialize(extraData){
+ var serialized = $.param(extraData, options.traditional).split('&');
+ var len = serialized.length;
+ var result = [];
+ var i, part;
+ for (i=0; i < len; i++) {
+ // #252; undo param space replacement
+ serialized[i] = serialized[i].replace(/\+/g,' ');
+ part = serialized[i].split('=');
+ // #278; use array instead of object storage, favoring array serializations
+ result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]);
+ }
+ return result;
+ }
+
+ // XMLHttpRequest Level 2 file uploads (big hat tip to francois2metz)
+ function fileUploadXhr(a) {
+ var formdata = new FormData();
+
+ for (var i=0; i < a.length; i++) {
+ formdata.append(a[i].name, a[i].value);
+ }
+
+ if (options.extraData) {
+ var serializedData = deepSerialize(options.extraData);
+ for (i=0; i < serializedData.length; i++) {
+ if (serializedData[i]) {
+ formdata.append(serializedData[i][0], serializedData[i][1]);
+ }
+ }
+ }
+
+ options.data = null;
+
+ var s = $.extend(true, {}, $.ajaxSettings, options, {
+ contentType: false,
+ processData: false,
+ cache: false,
+ type: method || 'POST'
+ });
+
+ if (options.uploadProgress) {
+ // workaround because jqXHR does not expose upload property
+ s.xhr = function() {
+ var xhr = $.ajaxSettings.xhr();
+ if (xhr.upload) {
+ xhr.upload.addEventListener('progress', function(event) {
+ var percent = 0;
+ var position = event.loaded || event.position; /*event.position is deprecated*/
+ var total = event.total;
+ if (event.lengthComputable) {
+ percent = Math.ceil(position / total * 100);
+ }
+ options.uploadProgress(event, position, total, percent);
+ }, false);
+ }
+ return xhr;
+ };
+ }
+
+ s.data = null;
+ var beforeSend = s.beforeSend;
+ s.beforeSend = function(xhr, o) {
+ //Send FormData() provided by user
+ if (options.formData) {
+ o.data = options.formData;
+ }
+ else {
+ o.data = formdata;
+ }
+ if(beforeSend) {
+ beforeSend.call(this, xhr, o);
+ }
+ };
+ return $.ajax(s);
+ }
+
+ // private function for handling file uploads (hat tip to YAHOO!)
+ function fileUploadIframe(a) {
+ var form = $form[0], el, i, s, g, id, $io, io, xhr, sub, n, timedOut, timeoutHandle;
+ var deferred = $.Deferred();
+
+ // #341
+ deferred.abort = function(status) {
+ xhr.abort(status);
+ };
+
+ if (a) {
+ // ensure that every serialized input is still enabled
+ for (i=0; i < elements.length; i++) {
+ el = $(elements[i]);
+ if ( hasProp ) {
+ el.prop('disabled', false);
+ }
+ else {
+ el.removeAttr('disabled');
+ }
+ }
+ }
+
+ s = $.extend(true, {}, $.ajaxSettings, options);
+ s.context = s.context || s;
+ id = 'jqFormIO' + (new Date().getTime());
+ if (s.iframeTarget) {
+ $io = $(s.iframeTarget);
+ n = $io.attr2('name');
+ if (!n) {
+ $io.attr2('name', id);
+ }
+ else {
+ id = n;
+ }
+ }
+ else {
+ $io = $('');
+ $io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
+ }
+ io = $io[0];
+
+
+ xhr = { // mock object
+ aborted: 0,
+ responseText: null,
+ responseXML: null,
+ status: 0,
+ statusText: 'n/a',
+ getAllResponseHeaders: function() {},
+ getResponseHeader: function() {},
+ setRequestHeader: function() {},
+ abort: function(status) {
+ var e = (status === 'timeout' ? 'timeout' : 'aborted');
+ log('aborting upload... ' + e);
+ this.aborted = 1;
+
+ try { // #214, #257
+ if (io.contentWindow.document.execCommand) {
+ io.contentWindow.document.execCommand('Stop');
+ }
+ }
+ catch(ignore) {}
+
+ $io.attr('src', s.iframeSrc); // abort op in progress
+ xhr.error = e;
+ if (s.error) {
+ s.error.call(s.context, xhr, e, status);
+ }
+ if (g) {
+ $.event.trigger("ajaxError", [xhr, s, e]);
+ }
+ if (s.complete) {
+ s.complete.call(s.context, xhr, e);
+ }
+ }
+ };
+
+ g = s.global;
+ // trigger ajax global events so that activity/block indicators work like normal
+ if (g && 0 === $.active++) {
+ $.event.trigger("ajaxStart");
+ }
+ if (g) {
+ $.event.trigger("ajaxSend", [xhr, s]);
+ }
+
+ if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
+ if (s.global) {
+ $.active--;
+ }
+ deferred.reject();
+ return deferred;
+ }
+ if (xhr.aborted) {
+ deferred.reject();
+ return deferred;
+ }
+
+ // add submitting element to data if we know it
+ sub = form.clk;
+ if (sub) {
+ n = sub.name;
+ if (n && !sub.disabled) {
+ s.extraData = s.extraData || {};
+ s.extraData[n] = sub.value;
+ if (sub.type == "image") {
+ s.extraData[n+'.x'] = form.clk_x;
+ s.extraData[n+'.y'] = form.clk_y;
+ }
+ }
+ }
+
+ var CLIENT_TIMEOUT_ABORT = 1;
+ var SERVER_ABORT = 2;
+
+ function getDoc(frame) {
+ /* it looks like contentWindow or contentDocument do not
+ * carry the protocol property in ie8, when running under ssl
+ * frame.document is the only valid response document, since
+ * the protocol is know but not on the other two objects. strange?
+ * "Same origin policy" http://en.wikipedia.org/wiki/Same_origin_policy
+ */
+
+ var doc = null;
+
+ // IE8 cascading access check
+ try {
+ if (frame.contentWindow) {
+ doc = frame.contentWindow.document;
+ }
+ } catch(err) {
+ // IE8 access denied under ssl & missing protocol
+ log('cannot get iframe.contentWindow document: ' + err);
+ }
+
+ if (doc) { // successful getting content
+ return doc;
+ }
+
+ try { // simply checking may throw in ie8 under ssl or mismatched protocol
+ doc = frame.contentDocument ? frame.contentDocument : frame.document;
+ } catch(err) {
+ // last attempt
+ log('cannot get iframe.contentDocument: ' + err);
+ doc = frame.document;
+ }
+ return doc;
+ }
+
+ // Rails CSRF hack (thanks to Yvan Barthelemy)
+ var csrf_token = $('meta[name=csrf-token]').attr('content');
+ var csrf_param = $('meta[name=csrf-param]').attr('content');
+ if (csrf_param && csrf_token) {
+ s.extraData = s.extraData || {};
+ s.extraData[csrf_param] = csrf_token;
+ }
+
+ // take a breath so that pending repaints get some cpu time before the upload starts
+ function doSubmit() {
+ // make sure form attrs are set
+ var t = $form.attr2('target'),
+ a = $form.attr2('action'),
+ mp = 'multipart/form-data',
+ et = $form.attr('enctype') || $form.attr('encoding') || mp;
+
+ // update form attrs in IE friendly way
+ form.setAttribute('target',id);
+ if (!method || /post/i.test(method) ) {
+ form.setAttribute('method', 'POST');
+ }
+ if (a != s.url) {
+ form.setAttribute('action', s.url);
+ }
+
+ // ie borks in some cases when setting encoding
+ if (! s.skipEncodingOverride && (!method || /post/i.test(method))) {
+ $form.attr({
+ encoding: 'multipart/form-data',
+ enctype: 'multipart/form-data'
+ });
+ }
+
+ // support timout
+ if (s.timeout) {
+ timeoutHandle = setTimeout(function() { timedOut = true; cb(CLIENT_TIMEOUT_ABORT); }, s.timeout);
+ }
+
+ // look for server aborts
+ function checkState() {
+ try {
+ var state = getDoc(io).readyState;
+ log('state = ' + state);
+ if (state && state.toLowerCase() == 'uninitialized') {
+ setTimeout(checkState,50);
+ }
+ }
+ catch(e) {
+ log('Server abort: ' , e, ' (', e.name, ')');
+ cb(SERVER_ABORT);
+ if (timeoutHandle) {
+ clearTimeout(timeoutHandle);
+ }
+ timeoutHandle = undefined;
+ }
+ }
+
+ // add "extra" data to form if provided in options
+ var extraInputs = [];
+ try {
+ if (s.extraData) {
+ for (var n in s.extraData) {
+ if (s.extraData.hasOwnProperty(n)) {
+ // if using the $.param format that allows for multiple values with the same name
+ if($.isPlainObject(s.extraData[n]) && s.extraData[n].hasOwnProperty('name') && s.extraData[n].hasOwnProperty('value')) {
+ extraInputs.push(
+ $(' ').val(s.extraData[n].value)
+ .appendTo(form)[0]);
+ } else {
+ extraInputs.push(
+ $(' ').val(s.extraData[n])
+ .appendTo(form)[0]);
+ }
+ }
+ }
+ }
+
+ if (!s.iframeTarget) {
+ // add iframe to doc and submit the form
+ $io.appendTo('body');
+ }
+ if (io.attachEvent) {
+ io.attachEvent('onload', cb);
+ }
+ else {
+ io.addEventListener('load', cb, false);
+ }
+ setTimeout(checkState,15);
+
+ try {
+ form.submit();
+ } catch(err) {
+ // just in case form has element with name/id of 'submit'
+ var submitFn = document.createElement('form').submit;
+ submitFn.apply(form);
+ }
+ }
+ finally {
+ // reset attrs and remove "extra" input elements
+ form.setAttribute('action',a);
+ form.setAttribute('enctype', et); // #380
+ if(t) {
+ form.setAttribute('target', t);
+ } else {
+ $form.removeAttr('target');
+ }
+ $(extraInputs).remove();
+ }
+ }
+
+ if (s.forceSync) {
+ doSubmit();
+ }
+ else {
+ setTimeout(doSubmit, 10); // this lets dom updates render
+ }
+
+ var data, doc, domCheckCount = 50, callbackProcessed;
+
+ function cb(e) {
+ if (xhr.aborted || callbackProcessed) {
+ return;
+ }
+
+ doc = getDoc(io);
+ if(!doc) {
+ log('cannot access response document');
+ e = SERVER_ABORT;
+ }
+ if (e === CLIENT_TIMEOUT_ABORT && xhr) {
+ xhr.abort('timeout');
+ deferred.reject(xhr, 'timeout');
+ return;
+ }
+ else if (e == SERVER_ABORT && xhr) {
+ xhr.abort('server abort');
+ deferred.reject(xhr, 'error', 'server abort');
+ return;
+ }
+
+ if (!doc || doc.location.href == s.iframeSrc) {
+ // response not received yet
+ if (!timedOut) {
+ return;
+ }
+ }
+ if (io.detachEvent) {
+ io.detachEvent('onload', cb);
+ }
+ else {
+ io.removeEventListener('load', cb, false);
+ }
+
+ var status = 'success', errMsg;
+ try {
+ if (timedOut) {
+ throw 'timeout';
+ }
+
+ var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
+ log('isXml='+isXml);
+ if (!isXml && window.opera && (doc.body === null || !doc.body.innerHTML)) {
+ if (--domCheckCount) {
+ // in some browsers (Opera) the iframe DOM is not always traversable when
+ // the onload callback fires, so we loop a bit to accommodate
+ log('requeing onLoad callback, DOM not available');
+ setTimeout(cb, 250);
+ return;
+ }
+ // let this fall through because server response could be an empty document
+ //log('Could not access iframe DOM after mutiple tries.');
+ //throw 'DOMException: not available';
+ }
+
+ //log('response detected');
+ var docRoot = doc.body ? doc.body : doc.documentElement;
+ xhr.responseText = docRoot ? docRoot.innerHTML : null;
+ xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
+ if (isXml) {
+ s.dataType = 'xml';
+ }
+ xhr.getResponseHeader = function(header){
+ var headers = {'content-type': s.dataType};
+ return headers[header.toLowerCase()];
+ };
+ // support for XHR 'status' & 'statusText' emulation :
+ if (docRoot) {
+ xhr.status = Number( docRoot.getAttribute('status') ) || xhr.status;
+ xhr.statusText = docRoot.getAttribute('statusText') || xhr.statusText;
+ }
+
+ var dt = (s.dataType || '').toLowerCase();
+ var scr = /(json|script|text)/.test(dt);
+ if (scr || s.textarea) {
+ // see if user embedded response in textarea
+ var ta = doc.getElementsByTagName('textarea')[0];
+ if (ta) {
+ xhr.responseText = ta.value;
+ // support for XHR 'status' & 'statusText' emulation :
+ xhr.status = Number( ta.getAttribute('status') ) || xhr.status;
+ xhr.statusText = ta.getAttribute('statusText') || xhr.statusText;
+ }
+ else if (scr) {
+ // account for browsers injecting pre around json response
+ var pre = doc.getElementsByTagName('pre')[0];
+ var b = doc.getElementsByTagName('body')[0];
+ if (pre) {
+ xhr.responseText = pre.textContent ? pre.textContent : pre.innerText;
+ }
+ else if (b) {
+ xhr.responseText = b.textContent ? b.textContent : b.innerText;
+ }
+ }
+ }
+ else if (dt == 'xml' && !xhr.responseXML && xhr.responseText) {
+ xhr.responseXML = toXml(xhr.responseText);
+ }
+
+ try {
+ data = httpData(xhr, dt, s);
+ }
+ catch (err) {
+ status = 'parsererror';
+ xhr.error = errMsg = (err || status);
+ }
+ }
+ catch (err) {
+ log('error caught: ',err);
+ status = 'error';
+ xhr.error = errMsg = (err || status);
+ }
+
+ if (xhr.aborted) {
+ log('upload aborted');
+ status = null;
+ }
+
+ if (xhr.status) { // we've set xhr.status
+ status = (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) ? 'success' : 'error';
+ }
+
+ // ordering of these callbacks/triggers is odd, but that's how $.ajax does it
+ if (status === 'success') {
+ if (s.success) {
+ s.success.call(s.context, data, 'success', xhr);
+ }
+ deferred.resolve(xhr.responseText, 'success', xhr);
+ if (g) {
+ $.event.trigger("ajaxSuccess", [xhr, s]);
+ }
+ }
+ else if (status) {
+ if (errMsg === undefined) {
+ errMsg = xhr.statusText;
+ }
+ if (s.error) {
+ s.error.call(s.context, xhr, status, errMsg);
+ }
+ deferred.reject(xhr, 'error', errMsg);
+ if (g) {
+ $.event.trigger("ajaxError", [xhr, s, errMsg]);
+ }
+ }
+
+ if (g) {
+ $.event.trigger("ajaxComplete", [xhr, s]);
+ }
+
+ if (g && ! --$.active) {
+ $.event.trigger("ajaxStop");
+ }
+
+ if (s.complete) {
+ s.complete.call(s.context, xhr, status);
+ }
+
+ callbackProcessed = true;
+ if (s.timeout) {
+ clearTimeout(timeoutHandle);
+ }
+
+ // clean up
+ setTimeout(function() {
+ if (!s.iframeTarget) {
+ $io.remove();
+ }
+ else { //adding else to clean up existing iframe response.
+ $io.attr('src', s.iframeSrc);
+ }
+ xhr.responseXML = null;
+ }, 100);
+ }
+
+ var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
+ if (window.ActiveXObject) {
+ doc = new ActiveXObject('Microsoft.XMLDOM');
+ doc.async = 'false';
+ doc.loadXML(s);
+ }
+ else {
+ doc = (new DOMParser()).parseFromString(s, 'text/xml');
+ }
+ return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
+ };
+ var parseJSON = $.parseJSON || function(s) {
+ /*jslint evil:true */
+ return window['eval']('(' + s + ')');
+ };
+
+ var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
+
+ var ct = xhr.getResponseHeader('content-type') || '',
+ xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
+ data = xml ? xhr.responseXML : xhr.responseText;
+
+ if (xml && data.documentElement.nodeName === 'parsererror') {
+ if ($.error) {
+ $.error('parsererror');
+ }
+ }
+ if (s && s.dataFilter) {
+ data = s.dataFilter(data, type);
+ }
+ if (typeof data === 'string') {
+ if (type === 'json' || !type && ct.indexOf('json') >= 0) {
+ data = parseJSON(data);
+ } else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
+ $.globalEval(data);
+ }
+ }
+ return data;
+ };
+
+ return deferred;
+ }
+};
+
+/**
+ * ajaxForm() provides a mechanism for fully automating form submission.
+ *
+ * The advantages of using this method instead of ajaxSubmit() are:
+ *
+ * 1: This method will include coordinates for elements (if the element
+ * is used to submit the form).
+ * 2. This method will include the submit element's name/value data (for the element that was
+ * used to submit the form).
+ * 3. This method binds the submit() method to the form for you.
+ *
+ * The options argument for ajaxForm works exactly as it does for ajaxSubmit. ajaxForm merely
+ * passes the options argument along after properly binding events for submit elements and
+ * the form itself.
+ */
+$.fn.ajaxForm = function(options) {
+ options = options || {};
+ options.delegation = options.delegation && $.isFunction($.fn.on);
+
+ // in jQuery 1.3+ we can fix mistakes with the ready state
+ if (!options.delegation && this.length === 0) {
+ var o = { s: this.selector, c: this.context };
+ if (!$.isReady && o.s) {
+ log('DOM not ready, queuing ajaxForm');
+ $(function() {
+ $(o.s,o.c).ajaxForm(options);
+ });
+ return this;
+ }
+ // is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
+ log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
+ return this;
+ }
+
+ if ( options.delegation ) {
+ $(document)
+ .off('submit.form-plugin', this.selector, doAjaxSubmit)
+ .off('click.form-plugin', this.selector, captureSubmittingElement)
+ .on('submit.form-plugin', this.selector, options, doAjaxSubmit)
+ .on('click.form-plugin', this.selector, options, captureSubmittingElement);
+ return this;
+ }
+
+ return this.ajaxFormUnbind()
+ .bind('submit.form-plugin', options, doAjaxSubmit)
+ .bind('click.form-plugin', options, captureSubmittingElement);
+};
+
+// private event handlers
+function doAjaxSubmit(e) {
+ /*jshint validthis:true */
+ var options = e.data;
+ if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
+ e.preventDefault();
+ $(e.target).ajaxSubmit(options); // #365
+ }
+}
+
+function captureSubmittingElement(e) {
+ /*jshint validthis:true */
+ var target = e.target;
+ var $el = $(target);
+ if (!($el.is("[type=submit],[type=image]"))) {
+ // is this a child element of the submit el? (ex: a span within a button)
+ var t = $el.closest('[type=submit]');
+ if (t.length === 0) {
+ return;
+ }
+ target = t[0];
+ }
+ var form = this;
+ form.clk = target;
+ if (target.type == 'image') {
+ if (e.offsetX !== undefined) {
+ form.clk_x = e.offsetX;
+ form.clk_y = e.offsetY;
+ } else if (typeof $.fn.offset == 'function') {
+ var offset = $el.offset();
+ form.clk_x = e.pageX - offset.left;
+ form.clk_y = e.pageY - offset.top;
+ } else {
+ form.clk_x = e.pageX - target.offsetLeft;
+ form.clk_y = e.pageY - target.offsetTop;
+ }
+ }
+ // clear form vars
+ setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
+}
+
+
+// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
+$.fn.ajaxFormUnbind = function() {
+ return this.unbind('submit.form-plugin click.form-plugin');
+};
+
+/**
+ * formToArray() gathers form element data into an array of objects that can
+ * be passed to any of the following ajax functions: $.get, $.post, or load.
+ * Each object in the array has both a 'name' and 'value' property. An example of
+ * an array for a simple login form might be:
+ *
+ * [ { name: 'username', value: 'jresig' }, { name: 'password', value: 'secret' } ]
+ *
+ * It is this array that is passed to pre-submit callback functions provided to the
+ * ajaxSubmit() and ajaxForm() methods.
+ */
+$.fn.formToArray = function(semantic, elements) {
+ var a = [];
+ if (this.length === 0) {
+ return a;
+ }
+
+ var form = this[0];
+ var formId = this.attr('id');
+ var els = semantic ? form.getElementsByTagName('*') : form.elements;
+ var els2;
+
+ if (els && !/MSIE [678]/.test(navigator.userAgent)) { // #390
+ els = $(els).get(); // convert to standard array
+ }
+
+ // #386; account for inputs outside the form which use the 'form' attribute
+ if ( formId ) {
+ els2 = $(':input[form="' + formId + '"]').get(); // hat tip @thet
+ if ( els2.length ) {
+ els = (els || []).concat(els2);
+ }
+ }
+
+ if (!els || !els.length) {
+ return a;
+ }
+
+ var i,j,n,v,el,max,jmax;
+ for(i=0, max=els.length; i < max; i++) {
+ el = els[i];
+ n = el.name;
+ if (!n || el.disabled) {
+ continue;
+ }
+
+ if (semantic && form.clk && el.type == "image") {
+ // handle image inputs on the fly when semantic == true
+ if(form.clk == el) {
+ a.push({name: n, value: $(el).val(), type: el.type });
+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
+ }
+ continue;
+ }
+
+ v = $.fieldValue(el, true);
+ if (v && v.constructor == Array) {
+ if (elements) {
+ elements.push(el);
+ }
+ for(j=0, jmax=v.length; j < jmax; j++) {
+ a.push({name: n, value: v[j]});
+ }
+ }
+ else if (feature.fileapi && el.type == 'file') {
+ if (elements) {
+ elements.push(el);
+ }
+ var files = el.files;
+ if (files.length) {
+ for (j=0; j < files.length; j++) {
+ a.push({name: n, value: files[j], type: el.type});
+ }
+ }
+ else {
+ // #180
+ a.push({ name: n, value: '', type: el.type });
+ }
+ }
+ else if (v !== null && typeof v != 'undefined') {
+ if (elements) {
+ elements.push(el);
+ }
+ a.push({name: n, value: v, type: el.type, required: el.required});
+ }
+ }
+
+ if (!semantic && form.clk) {
+ // input type=='image' are not found in elements array! handle it here
+ var $input = $(form.clk), input = $input[0];
+ n = input.name;
+ if (n && !input.disabled && input.type == 'image') {
+ a.push({name: n, value: $input.val()});
+ a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
+ }
+ }
+ return a;
+};
+
+/**
+ * Serializes form data into a 'submittable' string. This method will return a string
+ * in the format: name1=value1&name2=value2
+ */
+$.fn.formSerialize = function(semantic) {
+ //hand off to jQuery.param for proper encoding
+ return $.param(this.formToArray(semantic));
+};
+
+/**
+ * Serializes all field elements in the jQuery object into a query string.
+ * This method will return a string in the format: name1=value1&name2=value2
+ */
+$.fn.fieldSerialize = function(successful) {
+ var a = [];
+ this.each(function() {
+ var n = this.name;
+ if (!n) {
+ return;
+ }
+ var v = $.fieldValue(this, successful);
+ if (v && v.constructor == Array) {
+ for (var i=0,max=v.length; i < max; i++) {
+ a.push({name: n, value: v[i]});
+ }
+ }
+ else if (v !== null && typeof v != 'undefined') {
+ a.push({name: this.name, value: v});
+ }
+ });
+ //hand off to jQuery.param for proper encoding
+ return $.param(a);
+};
+
+/**
+ * Returns the value(s) of the element in the matched set. For example, consider the following form:
+ *
+ *
+ *
+ * var v = $('input[type=text]').fieldValue();
+ * // if no values are entered into the text inputs
+ * v == ['','']
+ * // if values entered into the text inputs are 'foo' and 'bar'
+ * v == ['foo','bar']
+ *
+ * var v = $('input[type=checkbox]').fieldValue();
+ * // if neither checkbox is checked
+ * v === undefined
+ * // if both checkboxes are checked
+ * v == ['B1', 'B2']
+ *
+ * var v = $('input[type=radio]').fieldValue();
+ * // if neither radio is checked
+ * v === undefined
+ * // if first radio is checked
+ * v == ['C1']
+ *
+ * The successful argument controls whether or not the field element must be 'successful'
+ * (per http://www.w3.org/TR/html4/interact/forms.html#successful-controls).
+ * The default value of the successful argument is true. If this value is false the value(s)
+ * for each element is returned.
+ *
+ * Note: This method *always* returns an array. If no valid value can be determined the
+ * array will be empty, otherwise it will contain one or more values.
+ */
+$.fn.fieldValue = function(successful) {
+ for (var val=[], i=0, max=this.length; i < max; i++) {
+ var el = this[i];
+ var v = $.fieldValue(el, successful);
+ if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
+ continue;
+ }
+ if (v.constructor == Array) {
+ $.merge(val, v);
+ }
+ else {
+ val.push(v);
+ }
+ }
+ return val;
+};
+
+/**
+ * Returns the value of the field element.
+ */
+$.fieldValue = function(el, successful) {
+ var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
+ if (successful === undefined) {
+ successful = true;
+ }
+
+ if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
+ (t == 'checkbox' || t == 'radio') && !el.checked ||
+ (t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
+ tag == 'select' && el.selectedIndex == -1)) {
+ return null;
+ }
+
+ if (tag == 'select') {
+ var index = el.selectedIndex;
+ if (index < 0) {
+ return null;
+ }
+ var a = [], ops = el.options;
+ var one = (t == 'select-one');
+ var max = (one ? index+1 : ops.length);
+ for(var i=(one ? index : 0); i < max; i++) {
+ var op = ops[i];
+ if (op.selected) {
+ var v = op.value;
+ if (!v) { // extra pain for IE...
+ v = (op.attributes && op.attributes.value && !(op.attributes.value.specified)) ? op.text : op.value;
+ }
+ if (one) {
+ return v;
+ }
+ a.push(v);
+ }
+ }
+ return a;
+ }
+ return $(el).val();
+};
+
+/**
+ * Clears the form data. Takes the following actions on the form's input fields:
+ * - input text fields will have their 'value' property set to the empty string
+ * - select elements will have their 'selectedIndex' property set to -1
+ * - checkbox and radio inputs will have their 'checked' property set to false
+ * - inputs of type submit, button, reset, and hidden will *not* be effected
+ * - button elements will *not* be effected
+ */
+$.fn.clearForm = function(includeHidden) {
+ return this.each(function() {
+ $('input,select,textarea', this).clearFields(includeHidden);
+ });
+};
+
+/**
+ * Clears the selected form elements.
+ */
+$.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
+ var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
+ return this.each(function() {
+ var t = this.type, tag = this.tagName.toLowerCase();
+ if (re.test(t) || tag == 'textarea') {
+ this.value = '';
+ }
+ else if (t == 'checkbox' || t == 'radio') {
+ this.checked = false;
+ }
+ else if (tag == 'select') {
+ this.selectedIndex = -1;
+ }
+ else if (t == "file") {
+ if (/MSIE/.test(navigator.userAgent)) {
+ $(this).replaceWith($(this).clone(true));
+ } else {
+ $(this).val('');
+ }
+ }
+ else if (includeHidden) {
+ // includeHidden can be the value true, or it can be a selector string
+ // indicating a special test; for example:
+ // $('#myForm').clearForm('.special:hidden')
+ // the above would clean hidden inputs that have the class of 'special'
+ if ( (includeHidden === true && /hidden/.test(t)) ||
+ (typeof includeHidden == 'string' && $(this).is(includeHidden)) ) {
+ this.value = '';
+ }
+ }
+ });
+};
+
+/**
+ * Resets the form data. Causes all form elements to be reset to their original value.
+ */
+$.fn.resetForm = function() {
+ return this.each(function() {
+ // guard against an input with the name of 'reset'
+ // note that IE reports the reset function as an 'object'
+ if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
+ this.reset();
+ }
+ });
+};
+
+/**
+ * Enables or disables any matching elements.
+ */
+$.fn.enable = function(b) {
+ if (b === undefined) {
+ b = true;
+ }
+ return this.each(function() {
+ this.disabled = !b;
+ });
+};
+
+/**
+ * Checks/unchecks any matching checkboxes or radio buttons and
+ * selects/deselects and matching option elements.
+ */
+$.fn.selected = function(select) {
+ if (select === undefined) {
+ select = true;
+ }
+ return this.each(function() {
+ var t = this.type;
+ if (t == 'checkbox' || t == 'radio') {
+ this.checked = select;
+ }
+ else if (this.tagName.toLowerCase() == 'option') {
+ var $sel = $(this).parent('select');
+ if (select && $sel[0] && $sel[0].type == 'select-one') {
+ // deselect all other options
+ $sel.find('option').selected(false);
+ }
+ this.selected = select;
+ }
+ });
+};
+
+// expose debug var
+$.fn.ajaxSubmit.debug = false;
+
+// helper fn for console logging
+function log() {
+ if (!$.fn.ajaxSubmit.debug) {
+ return;
+ }
+ var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
+ if (window.console && window.console.log) {
+ window.console.log(msg);
+ }
+ else if (window.opera && window.opera.postError) {
+ window.opera.postError(msg);
+ }
+}
+
+}));
diff --git a/core/um-account.php b/core/um-account.php
index 5497d3e6..260a9ac2 100644
--- a/core/um-account.php
+++ b/core/um-account.php
@@ -127,7 +127,7 @@ class UM_Account {
$defaults = array(
'template' => 'account',
'mode' => 'account',
- 'form_id' => 'unique_account',
+ 'form_id' => 'um_account_id',
);
$args = wp_parse_args( $args, $defaults );
diff --git a/core/um-actions-global.php b/core/um-actions-global.php
index 2add35f2..61eed040 100644
--- a/core/um-actions-global.php
+++ b/core/um-actions-global.php
@@ -43,6 +43,18 @@
-
+
@@ -65,7 +65,7 @@
function um_after_login_submit(){ ?>
user->preview == true && is_admin() ) return;
+ if ( isset( $ultimatemember->user->preview ) && $ultimatemember->user->preview == true && is_admin() ) return;
?>
@@ -218,7 +218,7 @@
-
+
diff --git a/core/um-actions-tracking.php b/core/um-actions-tracking.php
index 85e1c14d..7222ea16 100644
--- a/core/um-actions-tracking.php
+++ b/core/um-actions-tracking.php
@@ -7,8 +7,10 @@
function um_add_page_view($args){
global $ultimatemember;
extract($args);
- if ( isset( $form_id ) )
- $ultimatemember->form->add_pageview( $form_id );
+ if ( isset( $form_id ) ) {
+ if ( !isset( $impressions ) ) $impressions = 0;
+ $ultimatemember->form->add_pageview( $form_id, $impressions );
+ }
}
/***
diff --git a/core/um-enqueue.php b/core/um-enqueue.php
index 73c7c54d..c7c411b1 100644
--- a/core/um-enqueue.php
+++ b/core/um-enqueue.php
@@ -65,6 +65,9 @@ class UM_Enqueue {
***/
function load_fileupload() {
+ wp_register_script('um_jquery_form', um_url . 'assets/js/um-jquery-form.js' );
+ wp_enqueue_script('um_jquery_form');
+
wp_register_script('um_fileupload', um_url . 'assets/js/um-fileupload.js' );
wp_enqueue_script('um_fileupload');
diff --git a/core/um-fields.php b/core/um-fields.php
index fa9c9653..5e9af37e 100644
--- a/core/um-fields.php
+++ b/core/um-fields.php
@@ -278,7 +278,7 @@ class UM_Fields {
global $ultimatemember;
// preview in backend
- if ( $ultimatemember->user->preview ) {
+ if ( isset( $ultimatemember->user->preview ) && $ultimatemember->user->preview ) {
$submitted = um_user('submitted');
if ( isset( $submitted[$key] ) && !empty( $submitted[$key] ) ) {
return $submitted[$key];
diff --git a/core/um-files.php b/core/um-files.php
index 6d46c40c..a4589f32 100644
--- a/core/um-files.php
+++ b/core/um-files.php
@@ -88,9 +88,9 @@ class UM_Files {
$this->upload_dir = wp_upload_dir();
- $this->upload_basedir = $this->upload_dir['basedir'] . '/ultimate-member/';
+ $this->upload_basedir = $this->upload_dir['basedir'] . '/ultimatemember/';
- $this->upload_baseurl = $this->upload_dir['baseurl'] . '/ultimate-member/';
+ $this->upload_baseurl = $this->upload_dir['baseurl'] . '/ultimatemember/';
// create plugin uploads directory
if (!file_exists( $this->upload_basedir )) {
diff --git a/core/um-filters-avatars.php b/core/um-filters-avatars.php
index 8beb0b14..87185818 100644
--- a/core/um-filters-avatars.php
+++ b/core/um-filters-avatars.php
@@ -4,8 +4,7 @@
*** @Override avatars with a high priority
***/
function um_get_avatar($content, $id='', $size = '96', $avatar_class = '', $default = '', $alt = '') {
-
- um_fetch_user( $id );
+
return um_user('profile_photo', $size);
}
diff --git a/core/um-form.php b/core/um-form.php
index b6583fca..131a00d1 100644
--- a/core/um-form.php
+++ b/core/um-form.php
@@ -162,15 +162,10 @@ class UM_Form {
/***
*** @Adds a page view for form
***/
- function add_pageview( $post_id ) {
+ function add_pageview( $form_id, $impressions ) {
global $ultimatemember;
-
- $impressions = $ultimatemember->query->get_attr('impressions', $post_id);
$new_impressions = (int)$impressions+1;
-
- $ultimatemember->query->update_attr('impressions', $post_id, $new_impressions);
-
- return $new_impressions;
+ $ultimatemember->query->update_attr('impressions', $form_id, $new_impressions);
}
/***
diff --git a/core/um-global-functions.php b/core/um-global-functions.php
deleted file mode 100644
index ec07e805..00000000
--- a/core/um-global-functions.php
+++ /dev/null
@@ -1,48 +0,0 @@
- 'um_role',
- 'posts_per_page' => -1,
- 'post_status' => array('publish'),
- );
- $results = new WP_Query($args);
- if ($results->posts){
- foreach($results->posts as $post) { setup_postdata($post);
-
- if ( $ultimatemember->query->is_core( $post->ID ) ){
- $roles[ $ultimatemember->query->is_core( $post->ID ) ] = $post->post_title;
- } else {
- $roles[ $post->post_name ] = $post->post_title;
- }
-
- }
- } else {
-
- $roles['member'] = 'Member';
- $roles['admin'] = 'Admin';
-
- }
-
- return $roles;
- }
\ No newline at end of file
diff --git a/core/um-query.php b/core/um-query.php
index 7ca4f534..6900da89 100644
--- a/core/um-query.php
+++ b/core/um-query.php
@@ -43,7 +43,7 @@ class UM_Query {
}
/***
- *** @update data
+ *** @Using wpdb instead of update_post_meta
***/
function update_attr( $key, $post_id, $new_value ){
update_post_meta( $post_id, '_um_' . $key, $new_value );
diff --git a/core/um-rewrite.php b/core/um-rewrite.php
index a29b1c35..607df854 100644
--- a/core/um-rewrite.php
+++ b/core/um-rewrite.php
@@ -46,7 +46,6 @@ class UM_Rewrite {
'top'
);
- flush_rewrite_rules();
}
}
diff --git a/core/um-setup.php b/core/um-setup.php
index 57b5d059..09aeb7f2 100644
--- a/core/um-setup.php
+++ b/core/um-setup.php
@@ -27,6 +27,7 @@ class UM_Setup {
'members' => array( 'title' => 'Members' ),
'logout' => array( 'title' => 'Logout' ),
'account' => array( 'title' => 'Account' ),
+ 'recover' => array( 'title' => 'Password Reset'),
);
$this->core_directory_meta['members'] = array(
@@ -323,6 +324,8 @@ class UM_Setup {
$content = '';
} else if ( $slug == 'account' ) {
$content = '[ultimatemember_account]';
+ } else if ( $slug == 'recover' ) {
+ $content = '[ultimatemember_recover]';
} else if ( $slug == 'user' ){
$content = $this->setup_shortcode['profile'];
} else {
diff --git a/core/um-short-functions.php b/core/um-short-functions.php
index 23b1e87e..ebfda21a 100644
--- a/core/um-short-functions.php
+++ b/core/um-short-functions.php
@@ -1,4 +1,14 @@
permalinks->core[ $slug ] )
+ return get_permalink( $ultimatemember->permalinks->core[ $slug ] );
+ return '';
+ }
/***
*** @Check value of queried search in text input
@@ -204,7 +214,7 @@
***/
function um_get_requested_user() {
global $ultimatemember;
- if ( $ultimatemember->user->target_id )
+ if ( isset( $ultimatemember->user->target_id ) && !empty( $ultimatemember->user->target_id ) )
return $ultimatemember->user->target_id;
return false;
}
@@ -357,7 +367,8 @@
*** @Gets an option from DB
***/
function um_get_option($option_id) {
- global $um_options;
+ global $ultimatemember;
+ $um_options = $ultimatemember->options;
if ( isset($um_options[$option_id]) && !empty( $um_options[$option_id] ) ) {
return $um_options[$option_id];
}
@@ -383,21 +394,6 @@
global $ultimatemember;
return $ultimatemember->permalinks->profile_url();
}
-
- /***
- *** @User has avatar
- ***/
- function um_has_gravatar($email) {
- $hash = md5($email);
- $uri = 'http://www.gravatar.com/avatar/' . $hash . '?d=404';
- $headers = @get_headers($uri);
- if (!preg_match("|200|", $headers[0])) {
- $has_valid_avatar = FALSE;
- } else {
- $has_valid_avatar = TRUE;
- }
- return $has_valid_avatar;
- }
/***
*** @Get all UM roles in array
@@ -552,24 +548,18 @@
break;
case 'profile_photo':
- if ( um_has_gravatar( um_profile('user_email') ) ) {
- return get_avatar( um_profile('ID'), $attrs);
-
- } else {
-
- $default_avatar_uri = um_get_option('default_avatar');
- $default_avatar_uri = $default_avatar_uri['url'];
-
- if ( !$default_avatar_uri ) {
- $default_avatar_uri = um_url . 'assets/img/default_avatar.png';
- }
-
- $default_avatar_uri = um_url . 'assets/img/Dollarphotoclub_57189843.jpg';
-
- return ' ';
+ $default_avatar_uri = um_get_option('default_avatar');
+ $default_avatar_uri = $default_avatar_uri['url'];
+ if ( !$default_avatar_uri ) {
+ $default_avatar_uri = um_url . 'assets/img/default_avatar.png';
}
+
+ $default_avatar_uri = um_url . 'assets/img/Dollarphotoclub_57189843.jpg';
+
+ return ' ';
+
break;
case 'cover_photo':
diff --git a/core/um-taxonomies.php b/core/um-taxonomies.php
index 47896d88..c51221ff 100644
--- a/core/um-taxonomies.php
+++ b/core/um-taxonomies.php
@@ -17,7 +17,7 @@ class UM_Taxonomies {
'labels' => array(
'name' => __( 'Forms' ),
'singular_name' => __( 'Form' ),
- 'add_new' => __( 'Add New Form' ),
+ 'add_new' => __( 'Add New' ),
'add_new_item' => __('Add New Form' ),
'edit_item' => __('Edit Form'),
'not_found' => __('You did not create any forms yet'),
@@ -33,14 +33,14 @@ class UM_Taxonomies {
register_post_type( 'um_role', array(
'labels' => array(
- 'name' => __( 'Roles' ),
- 'singular_name' => __( 'Role' ),
- 'add_new' => __( 'Add New Role' ),
- 'add_new_item' => __('Add New Role' ),
- 'edit_item' => __('Edit Role'),
- 'not_found' => __('You did not create any roles yet'),
+ 'name' => __( 'Member Levels' ),
+ 'singular_name' => __( 'Member Level' ),
+ 'add_new' => __( 'Add New' ),
+ 'add_new_item' => __('Add New Member Level' ),
+ 'edit_item' => __('Edit Member Level'),
+ 'not_found' => __('You did not create any member levels yet'),
'not_found_in_trash' => __('Nothing found in Trash'),
- 'search_items' => __('Search Roles')
+ 'search_items' => __('Search Member Levels')
),
'show_ui' => true,
'show_in_menu' => false,
@@ -51,14 +51,14 @@ class UM_Taxonomies {
register_post_type( 'um_directory', array(
'labels' => array(
- 'name' => __( 'Directories' ),
- 'singular_name' => __( 'Directory' ),
- 'add_new' => __( 'Add New Directory' ),
- 'add_new_item' => __('Add New Directory' ),
- 'edit_item' => __('Edit Directory'),
+ 'name' => __( 'Member Directories' ),
+ 'singular_name' => __( 'Member Directory' ),
+ 'add_new' => __( 'Add New' ),
+ 'add_new_item' => __('Add New Member Directory' ),
+ 'edit_item' => __('Edit Member Directory'),
'not_found' => __('You did not create any member directories yet'),
'not_found_in_trash' => __('Nothing found in Trash'),
- 'search_items' => __('Search Directories')
+ 'search_items' => __('Search Member Directories')
),
'show_ui' => true,
'show_in_menu' => false,
diff --git a/core/um-uninstall.php b/core/um-uninstall.php
index b91f4e82..92cd759e 100644
--- a/core/um-uninstall.php
+++ b/core/um-uninstall.php
@@ -29,10 +29,10 @@ class UM_Uninstall {
}
- $admin = $ultimatemember->query->find_post_id('um_role','_um_core','admin');
- $member = $ultimatemember->query->find_post_id('um_role','_um_core','member');
- wp_delete_post( $admin, 1 );
- wp_delete_post( $member, 1 );
+ $roles = get_posts( array( 'post_type' => 'um_role', 'number' => 999 ) );
+ foreach( $roles as $role ) {
+ wp_delete_post( $role->ID, 1 );
+ }
if ( is_plugin_active( um_plugin ) ) {
deactivate_plugins( um_plugin );
diff --git a/index.php b/index.php
index 661b85e0..0527b37b 100644
--- a/index.php
+++ b/index.php
@@ -29,10 +29,12 @@ Author URI: http://ultimatemember.com/
update_option('um_version', ULTIMATEMEMBER_VERSION );
- exit( wp_redirect( admin_url('admin.php?page=ultimatemember-welcome') ) );
+ exit( wp_redirect( admin_url('admin.php?page=ultimatemember-about') ) );
}
+ flush_rewrite_rules();
+
}
add_action( 'activated_plugin', 'ultimatemember_activation_hook' );
@@ -49,13 +51,13 @@ Author URI: http://ultimatemember.com/
***/
function ultimatemember_plugin_links( $links ) {
- $more_links[] = '' . __('Docs') . ' ';
- $more_links[] = '' . __('Support') . ' ';
- $more_links[] = '' . __('Settings') . ' ';
+ $more_links[] = '' . __('Docs','ultimatemember') . ' ';
+ $more_links[] = '' . __('Support','ultimatemember') . ' ';
+ $more_links[] = '' . __('Settings','ultimatemember') . ' ';
$links = $more_links + $links;
- $links[] = '' . __( 'Uninstall' ) . ' ';
+ $links[] = '' . __( 'Uninstall','ultimatemember' ) . ' ';
return $links;
diff --git a/um-config.php b/um-config.php
index 9408dd0b..75bc6bdc 100644
--- a/um-config.php
+++ b/um-config.php
@@ -29,7 +29,7 @@ $this->sections[] = array(
'title' => __( 'Default New User Role' ),
'desc' => __( 'Select the default role that will be assigned to user after registration If you did not specify custom role settings per form.' ),
'default' => 'member',
- 'options' => um_get_roles_(),
+ 'options' => $ultimatemember->query->get_roles( ),
'placeholder' => __('Choose user role...'),
),
@@ -243,7 +243,7 @@ $this->sections[] = array(
'type' => 'text',
'title' => __( 'Panic Key' ),
'desc' => 'Panic Key is a random generated key that allow you to access the WordPress backend always regardless of backend settings.',
- 'default' => um_random_string_(),
+ 'default' => $ultimatemember->validation->randomize(),
'desc' => trailingslashit( get_bloginfo('url') ).'wp-admin/?um_panic_key=YOUR_PANIC_KEY_VALUE '
),
@@ -1292,4 +1292,34 @@ $this->sections[] = array(
)
+);
+
+/***
+*** @
+***/
+
+$this->sections[] = array(
+
+ 'icon' => 'um-icon-tools',
+ 'title' => __( 'Advanced'),
+ 'fields' => array(
+
+ array(
+ 'id' => 'admin_load_time',
+ 'type' => 'switch',
+ 'title' => __( 'Show load time in admin footer' ),
+ 'default' => 0,
+ 'desc' => __('Display the number of queries and load time in backend','ultimatemember'),
+ ),
+
+ array(
+ 'id' => 'load_time',
+ 'type' => 'switch',
+ 'title' => __( 'Show load time in frontend' ),
+ 'default' => 0,
+ 'desc' => __('Display the number of queries and load time in frontend','ultimatemember'),
+ ),
+
+ )
+
);
\ No newline at end of file
diff --git a/um-init.php b/um-init.php
index 62a3c96e..844b5941 100644
--- a/um-init.php
+++ b/um-init.php
@@ -4,7 +4,6 @@ class UM_API {
function __construct() {
- require_once um_path . 'core/um-global-functions.php';
require_once um_path . 'core/um-short-functions.php';
if (is_admin()){
@@ -14,13 +13,6 @@ class UM_API {
add_action('init', array(&$this, 'init'), 0);
$this->honeypot = 'request';
-
- if ( !class_exists( 'ReduxFramework' ) && file_exists( um_path . 'admin/core/lib/ReduxFramework/ReduxCore/framework.php' ) ) {
- require_once( um_path . 'admin/core/lib/ReduxFramework/ReduxCore/framework.php' );
- }
- if ( file_exists ( um_path . 'admin/core/um-admin-redux.php' ) ) {
- require_once( um_path . 'admin/core/um-admin-redux.php' );
- }
}
@@ -111,6 +103,8 @@ class UM_API {
$this->members = new UM_Members();
$this->logout = new UM_Logout();
$this->modal = new UM_Modal();
+
+ $this->options = get_option('um_options');
}