diff --git a/admin/core/um-admin-actions-fields.php b/admin/core/um-admin-actions-fields.php index 9bdec78d..e6dcaedd 100644 --- a/admin/core/um-admin-actions-fields.php +++ b/admin/core/um-admin-actions-fields.php @@ -27,9 +27,10 @@ $save = ''; $save[ $_metakey ]['roles'] = ''; + $save[ $_metakey ]['icon'] = ''; foreach( $array['post'] as $key => $val){ - if ( substr( $key, 0, 1) === '_' && $val != '' ) { // field attribute + if ( substr( $key, 0, 1) === '_' && $val != '' ) { // field attribute $new_key = ltrim ($key,'_'); if ( $new_key == 'options' ) { diff --git a/admin/core/um-admin-builder.php b/admin/core/um-admin-builder.php index 0b77497f..17fb3928 100644 --- a/admin/core/um-admin-builder.php +++ b/admin/core/um-admin-builder.php @@ -225,7 +225,7 @@ class UM_Admin_Builder {
- +
diff --git a/admin/core/um-admin-metabox.php b/admin/core/um-admin-metabox.php index e88abf58..61b24f94 100644 --- a/admin/core/um-admin-metabox.php +++ b/admin/core/um-admin-metabox.php @@ -245,7 +245,8 @@ class UM_Admin_Metabox { add_meta_box('um-admin-form-profile_customize', __('Customize this form'), array(&$this, 'load_metabox_form'), 'um_form', 'side', 'default'); add_meta_box('um-admin-form-login_customize', __('Customize this form'), array(&$this, 'load_metabox_form'), 'um_form', 'side', 'default'); - add_meta_box('um-admin-form-login_settings', __('Settings'), array(&$this, 'load_metabox_form'), 'um_form', 'side', 'default'); + add_meta_box('um-admin-form-profile_settings', __('Options'), array(&$this, 'load_metabox_form'), 'um_form', 'side', 'default'); + add_meta_box('um-admin-form-login_settings', __('Options'), array(&$this, 'load_metabox_form'), 'um_form', 'side', 'default'); } @@ -333,6 +334,7 @@ class UM_Admin_Metabox { $wpdb->update( $wpdb->posts, array( 'post_title' => $_POST['post_title'] ), $where ); // save + delete_post_meta( $post_id, '_um_profile_metafields' ); foreach( $_POST as $k => $v ) { if (strstr($k, '_um_')){ update_post_meta( $post_id, $k, $v); @@ -968,7 +970,7 @@ class UM_Admin_Metabox {

diff --git a/admin/templates/form/profile_settings.php b/admin/templates/form/profile_settings.php new file mode 100644 index 00000000..dfcf8d32 --- /dev/null +++ b/admin/templates/form/profile_settings.php @@ -0,0 +1,60 @@ +
+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +

+ + + + ui_on_off('_um_profile_show_bio', 1 ); ?> + + +

+ +
\ No newline at end of file diff --git a/assets/css/um-crop.css b/assets/css/um-crop.css index c5b4fce1..0440afcf 100644 --- a/assets/css/um-crop.css +++ b/assets/css/um-crop.css @@ -1,41 +1,271 @@ -/* - * imgAreaSelect default style - */ +.cropper-container { + position: relative; + overflow: hidden; -.imgareaselect-border1 { - background: url(../img/border-v.gif) repeat-y left top; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + -webkit-tap-highlight-color: transparent; + -webkit-touch-callout: none; } -.imgareaselect-border2 { - background: url(../img/border-h.gif) repeat-x left top; +.cropper-container img { + width: 100%; + height: 100%; + min-width: 0 !important; + min-height: 0 !important; + max-width: none !important; + max-height: none !important; } -.imgareaselect-border3 { - background: url(../img/border-v.gif) repeat-y right top; +.cropper-modal, +.cropper-canvas { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; } -.imgareaselect-border4 { - background: url(../img/border-h.gif) repeat-x left bottom; +.cropper-canvas { + background-color: #fff; + opacity: 0; + filter: alpha(opacity=0); } -.imgareaselect-border1, .imgareaselect-border2, -.imgareaselect-border3, .imgareaselect-border4 { - filter: alpha(opacity=50); - opacity: 0.5; +.cropper-modal { + background-color: #000; + opacity: .5; + filter: alpha(opacity=50); } -.imgareaselect-handle { - background-color: #fff; - border: solid 1px #000; - filter: alpha(opacity=50); - opacity: 0.5; +.cropper-dragger { + position: absolute; + top: 10%; + left: 10%; + width: 80%; + height: 80%; } -.imgareaselect-outer { - background-color: #000; - filter: alpha(opacity=50); - opacity: 0.5; +.cropper-viewer { + display: block; + width: 100%; + height: 100%; + overflow: hidden; + outline-width: 1px; + outline-style: solid; + outline-color: #69f; + outline-color: rgba(51, 102, 255, .75); } -.imgareaselect-selection { -} \ No newline at end of file +.cropper-dashed { + position: absolute; + display: block; + border: 0 dashed #fff; + opacity: .5; + filter: alpha(opacity=50); +} + +.cropper-dashed.dashed-h { + top: 33.3%; + left: 0; + width: 100%; + height: 33.3%; + border-top-width: 1px; + border-bottom-width: 1px; +} + +.cropper-dashed.dashed-v { + top: 0; + left: 33.3%; + width: 33.3%; + height: 100%; + border-right-width: 1px; + border-left-width: 1px; +} + +.cropper-face, +.cropper-line, +.cropper-point { + position: absolute; + display: block; + width: 100%; + height: 100%; + opacity: .1; + filter: alpha(opacity=10); +} + +.cropper-face { + top: 0; + left: 0; + cursor: move; + background-color: #fff; +} + +.cropper-line { + background-color: #69f; +} + +.cropper-line.line-e { + top: 0; + right: -3px; + width: 5px; + cursor: e-resize; +} + +.cropper-line.line-n { + top: -3px; + left: 0; + height: 5px; + cursor: n-resize; +} + +.cropper-line.line-w { + top: 0; + left: -3px; + width: 5px; + cursor: w-resize; +} + +.cropper-line.line-s { + bottom: -3px; + left: 0; + height: 5px; + cursor: s-resize; +} + +.cropper-point { + width: 5px; + height: 5px; + background-color: #69f; + opacity: .75; + filter: alpha(opacity=75); +} + +.cropper-point.point-e { + top: 50%; + right: -3px; + margin-top: -3px; + cursor: e-resize; +} + +.cropper-point.point-n { + top: -3px; + left: 50%; + margin-left: -3px; + cursor: n-resize; +} + +.cropper-point.point-w { + top: 50%; + left: -3px; + margin-top: -3px; + cursor: w-resize; +} + +.cropper-point.point-s { + bottom: -3px; + left: 50%; + margin-left: -3px; + cursor: s-resize; +} + +.cropper-point.point-ne { + top: -3px; + right: -3px; + cursor: ne-resize; +} + +.cropper-point.point-nw { + top: -3px; + left: -3px; + cursor: nw-resize; +} + +.cropper-point.point-sw { + bottom: -3px; + left: -3px; + cursor: sw-resize; +} + +.cropper-point.point-se { + right: -3px; + bottom: -3px; + width: 20px; + height: 20px; + cursor: se-resize; + opacity: 1; + filter: alpha(opacity=100); +} + +.cropper-point.point-se:before { + position: absolute; + right: -50%; + bottom: -50%; + display: block; + width: 200%; + height: 200%; + content: " "; + background-color: #69f; + opacity: 0; + filter: alpha(opacity=0); +} + +@media (min-width: 768px) { + .cropper-point.point-se { + width: 15px; + height: 15px; + } +} + +@media (min-width: 992px) { + .cropper-point.point-se { + width: 10px; + height: 10px; + } +} + +@media (min-width: 1200px) { + .cropper-point.point-se { + width: 5px; + height: 5px; + opacity: .75; + filter: alpha(opacity=75); + } +} + +/* Helper classes for JavaScript */ + +.cropper-hidden { + display: none !important; +} + +.cropper-invisible { + position: fixed; + top: 0; + left: 0; + z-index: -1; + width: auto !important; + max-width: none !important; + height: auto !important; + max-height: none !important; + opacity: 0; + filter: alpha(opacity=0); +} + +.cropper-move { + cursor: move; +} + +.cropper-crop { + cursor: crosshair; +} + +.cropper-disabled .cropper-canvas, +.cropper-disabled .cropper-face, +.cropper-disabled .cropper-line, +.cropper-disabled .cropper-point { + cursor: not-allowed; +} diff --git a/assets/css/um-fileupload.css b/assets/css/um-fileupload.css index 2d677d3d..1437fb01 100644 --- a/assets/css/um-fileupload.css +++ b/assets/css/um-fileupload.css @@ -7,14 +7,24 @@ margin-bottom: 20px; } +.um .um-single-image-preview > img { + max-height: 200px; + display: block; + overflow: hidden; + margin: auto; + border-radius: 3px; +} + .um-single-image-preview, .um-single-file-preview { display: none; - width: 100%; - box-sizing: border-box; text-align: center; position: relative; - min-height: 40px; +} + +.um-single-image-preview > img { + max-width: 100%; + max-height: inherit; } .um-single-image-preview a.cancel, @@ -27,8 +37,9 @@ border-radius: 999px; background: #ddd; cursor: pointer; - transition: 0.2s; text-decoration: none !important; + z-index: 8888; + opacity: 0.75; } .um-single-image-preview a.cancel i, @@ -39,44 +50,40 @@ top: 4px; } -.um-single-image-preview img { - max-width: 100%; - margin: 0 auto !important; - padding: 0 !important; - display: block !important; -} - /* - - file preview + - file info */ .um-single-fileinfo { - padding: 36px 0 30px 0; + padding: 26px 0 20px 0; display: inline-block; } .um-single-fileinfo span.icon { - font-size: 38px; + font-size: 42px; display: inline-block; width: 100px; height: 70px; - line-height: 70px; - border-radius: 5px; + border-radius: 3px; background-color: #666; color: #fff !important; } -.um-single-fileinfo span.icon i {line-height: 1em !important;vertical-align: middle} +.um-single-fileinfo span.icon i{vertical-align: middle} .um-single-fileinfo span.filename { display: block; - font-size: 18px; - line-height: 24px; - color: #666; + font-size: 16px; + color: #888; padding: 15px 0 0 0; } -.um-single-fileinfo a {text-decoration: none !important; opacity: 0.85 } -.um-single-fileinfo a:hover { opacity: 1 } +.um-single-fileinfo a { + text-decoration: none !important; + opacity: 0.9; +} +.um-single-fileinfo a:hover { + opacity: 1 +} /* - upload progress @@ -122,7 +129,7 @@ .ajax-upload-dragdrop span.str { display: block; - margin: 0 0 12px 0; + margin: 0 0 15px 0; } .ajax-upload-dragdrop span.icon { diff --git a/assets/css/um-members.css b/assets/css/um-members.css index ffaeb7fd..9c20cd3c 100644 --- a/assets/css/um-members.css +++ b/assets/css/um-members.css @@ -111,8 +111,14 @@ .um-gutter-sizer { width: 5% } +/* + - Member cover +*/ + .um-member-cover { background-color: #eee; + box-sizing: border-box; + position: relative; } .um-member-cover-e { diff --git a/assets/css/um-modal.css b/assets/css/um-modal.css index 1bb34bf2..729fb51a 100644 --- a/assets/css/um-modal.css +++ b/assets/css/um-modal.css @@ -64,7 +64,7 @@ background: #3ba1da; padding: 0 20px; box-sizing: border-box; - font-size: 15px; + font-size: 17px; } .um-modal-footer { @@ -93,6 +93,7 @@ display: inline-block; border-radius: 3px; padding: 0 20px; + text-align: center; color: #fff; background: #3ba1da; vertical-align: middle; diff --git a/assets/css/um-profile.css b/assets/css/um-profile.css index fb22a3ee..fd3f40d2 100644 --- a/assets/css/um-profile.css +++ b/assets/css/um-profile.css @@ -4,6 +4,19 @@ .um-profile { box-sizing: border-box; + padding-top: 10px; +} + +.um-profile .um-cover-overlay { + display: none; +} + +.um-profile.um-editing .um-cover.has-cover .um-cover-overlay { + display: block; +} + +.um-profile.um-viewing .um-profile-photo-overlay { + display: none; } .um-profile img {display: block;overflow:hidden;border-radius:0!important;margin: 0!important} @@ -33,21 +46,11 @@ - Profile cover */ -.um-cover{ +.um-cover { background-color: #eee; -} - -.um-cover-add span { - display: table-cell; - vertical-align: middle; -} - -.um-cover-e { - text-align: center; box-sizing: border-box; + position: relative; } -.um-cover-e.empty {border: 2px dashed #ddd} -.um-cover-e img {width: 100% !important} .um-cover-add { color: #aaa; @@ -55,8 +58,61 @@ width: 100%; display: table; } + +.um-cover-add span { + display: table-cell; + vertical-align: middle; +} + .um-cover-add:hover { color: #3ba1da } +.um-cover-e { + text-align: center; + box-sizing: border-box; +} + +.um-cover-e img {width: 100% !important} + +.um-cover-overlay { + position: absolute; + top: 0; + left: 0; + background: rgba(0,0,0,.5); + text-align: center; + box-sizing: border-box; + padding: 0 40px; + color: #fff; + text-shadow: 0 2px #333; + cursor: pointer !important; + line-height: 21px; + font-size: 16px; + height: 100%; + width: 100%; +} + +.um-cover-overlay:hover { + background: rgba(0,0,0,.55); +} + +.um-cover-overlay span.um-cover-overlay-s { + display: table; + height: 100%; + width: 100%; +} + +.um-cover-overlay ins { + display: table-cell; + vertical-align: middle; + height: 100%; + text-decoration: none !important; +} + +.um-cover-overlay i { + font-size: 46px; + display: block; + margin-bottom: 6px; +} + /* - Profile header */ @@ -70,7 +126,7 @@ .um-profile-edit { position: absolute; top: 15px; - right: 15px; + right: 0; vertical-align: middle; z-index: 99; font-size: 30px; @@ -124,7 +180,6 @@ .um-profile-photo { float: left; - width: 250px; position: relative; } @@ -136,11 +191,51 @@ left: 30px; } -.um-profile-photo img { +.um-profile-photo a.um-profile-photo-img img { width: 100%; height: 100%; } +.um-profile-photo-overlay { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0,0,0,.5); + text-align: center; + box-sizing: border-box; + padding: 0 40px; + color: #fff; + line-height: 21px; + font-size: 16px; + text-shadow: 0 1px #333; + cursor: pointer !important; +} + +.um-profile-photo-overlay:hover { + background: rgba(0,0,0,.55); +} + +.um-profile-photo-overlay span.um-profile-photo-overlay-s { + display: table; + height: 100%; + width: 100%; +} + +.um-profile-photo-overlay ins { + display: table-cell; + vertical-align: middle; + height: 100%; + text-decoration: none !important; +} + +.um-profile-photo-overlay i { + font-size: 46px; + display: block; + margin-bottom: 6px; +} + /* - Profile meta */ @@ -164,12 +259,13 @@ font-size: 15px; } +.um-meta span:first-child {margin: 0 5px 0 0} .um-meta span { margin: 0 5px; font-size: 14px; } .um-meta-text { - margin: 12px 0 0 0; + margin: 6px 0 0 0; color: #666; } \ No newline at end of file diff --git a/assets/css/um-responsive.css b/assets/css/um-responsive.css index a9240ae3..6c28150a 100644 --- a/assets/css/um-responsive.css +++ b/assets/css/um-responsive.css @@ -28,22 +28,31 @@ div.uimob960 .uimob960-hide /********************************************/ -.uimob340 .um-half { - float: none; - width: 100%; - margin: 0 0 10px 0; +div.uimob340 .um-cover-overlay span.um-cover-overlay-t, +div.uimob340 .um-profile-photo-overlay span.um-profile-photo-overlay-t +{ + display: none !important; } -.uimob340 .um-button.um-btn-auto-width { - min-width: auto; - max-width: auto; - width: 100%; +div.uimob340 .um-cover-overlay, +div.uimob340 .um-profile-photo-overlay +{ + padding: 0; +} + +div.uimob340 .um-cover-overlay i, +div.uimob340 .um-profile-photo-overlay i +{ + margin-bottom: 0; + font-size: 30px; } .um-modal.uimob340 { width: 100% !important; margin: 0 !important; left: 0 !important; + height: 100%; + background: #fff; } .um-modal.uimob340, @@ -52,16 +61,181 @@ div.uimob960 .uimob960-hide border-radius: 0; } +.um-modal.uimob340 .um-modal-header {text-align: center} +.um-modal.uimob340 .um-modal-footer { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + box-sizing: border-box; + padding: 10px; + border-top: 1px solid #ddd; +} + +.um-modal.uimob340 .um-modal-right { + width: 100%; + float: none; +} + +.um-modal.uimob340 .um-modal-footer a.um-modal-btn { + width: 48%; + margin: 0 1%; + float: left; + display: block; + line-height: 44px !important; + height: 44px; +} + +.um-modal.uimob340 .ajax-upload-dragdrop span.icon { + font-size: 40px; + line-height: 40px; +} + +div.uimob340 .um-profile-body { + padding-left: 0; + padding-right: 0; +} + +div.uimob340 .um-profile-photo { + width: 100% !important; + text-align: center !important; + position: absolute; + top: -20px; + left: 0; +} + +div.uimob340 .um-profile-photo a.um-profile-photo-img { + width: 100px !important; + height: 100px !important; + margin: 0 auto !important; + float: none !important; + display: inline-block !important; + position: relative !important; + top: auto !important; + left: auto !important; +} + +div.uimob340 .um-header .um-profile-meta { + padding-left: 0 !important; + padding-right: 0 !important; + text-align: center !important; + padding-top: 90px !important; +} + +div.uimob340 .um-header .um-name { + float: none !important; + margin-right: 0 !important; + font-size: 18px; +} + +div.uimob340 .um-header .um-meta-text { + padding: 0 20px; +} + +div.uimob340 .um-header .um-meta {padding: 0 20px} +div.uimob340 .um-header .um-meta span:first-child {display: block} +div.uimob340 .um-header .um-meta span {display: none} + +div.uimob340 .um-col-121, +div.uimob340 .um-col-122, +div.uimob340 .um-col-131, +div.uimob340 .um-col-132, +div.uimob340 .um-col-133 { + float: none; + width: 100%; + margin: 0; +} + +div.uimob340 .um-field-half { + float: none; + width: 100%; +} + +div.uimob340 .um-search { + padding: 20px 0 !important; + width: 100% !important; + box-sizing: border-box; +} + +div.uimob340 .um-search .um-search-filter { + width: 100% !important; + float: none !important; + padding: 0 0 15px 0 !important; +} + +div.uimob340 .um-search .um-search-submit .um-button { + display: block !important; + min-width: 100% !important; + margin: 0 0 15px 0 !important; +} + +div.uimob340 .um-member { + width: 100%; +} + +div.uimob340 .um-gutter-sizer { width: 0px } + +div.uimob340 .um-account-main { + float: none; + width: 100%; + padding: 0; + box-sizing: border-box; +} + +div.uimob340 .um-account-tab { + padding-bottom: 20px; + border-bottom: 1px solid #eee; +} + +div.uimob340 .um-account-main div.um-field {padding-top: 15px} + +div.uimob340 .um-account-meta { + margin-bottom: 0; +} + +.uimob340 .um-half { + float: none; + width: 100%; + margin: 0 0 10px 0; +} + +.uimob340 .um-button.um-btn-auto-width { + min-width: auto; + max-width: auto; + width: 100%; +} + /** for 500px and below **/ /********************************************/ +div.uimob500 .um-cover-overlay span.um-cover-overlay-t, +div.uimob500 .um-profile-photo-overlay span.um-profile-photo-overlay-t +{ + display: none !important; +} + +div.uimob500 .um-cover-overlay, +div.uimob500 .um-profile-photo-overlay +{ + padding: 0; +} + +div.uimob500 .um-cover-overlay i, +div.uimob500 .um-profile-photo-overlay i +{ + margin-bottom: 0; + font-size: 30px; +} + .um-modal.uimob500 { width: 100% !important; margin: 0 !important; left: 0 !important; + height: 100%; + background: #fff; } .um-modal.uimob500, @@ -70,15 +244,41 @@ div.uimob960 .uimob960-hide border-radius: 0; } +.um-modal.uimob500 .um-modal-header {text-align: center} +.um-modal.uimob500 .um-modal-footer { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + box-sizing: border-box; + padding: 10px; + border-top: 1px solid #ddd; +} + +.um-modal.uimob500 .um-modal-right { + width: 100%; + float: none; +} + +.um-modal.uimob500 .um-modal-footer a.um-modal-btn { + width: 48%; + margin: 0 1%; + float: left; + display: block; + line-height: 44px !important; + height: 44px; +} + +.um-modal.uimob500 .ajax-upload-dragdrop span.icon { + font-size: 40px; + line-height: 40px; +} + div.uimob500 .um-profile-body { padding-left: 0; padding-right: 0; } -div.uimob500 .um-profile-edit { - right: 0; -} - div.uimob500 .um-profile-photo { width: 100% !important; text-align: center !important; @@ -102,7 +302,7 @@ div.uimob500 .um-header .um-profile-meta { padding-left: 0 !important; padding-right: 0 !important; text-align: center !important; - padding-top: 70px !important; + padding-top: 80px !important; } div.uimob500 .um-header .um-name { @@ -112,13 +312,12 @@ div.uimob500 .um-header .um-name { } div.uimob500 .um-header .um-meta-text { - margin: 0; padding: 0 20px; } div.uimob500 .um-header .um-meta {padding: 0 20px} -div.uimob500 .um-header .um-meta span {display: block} -div.uimob500 .um-header .um-meta span.b {display: none} +div.uimob500 .um-header .um-meta span:first-child {display: block} +div.uimob500 .um-header .um-meta span {display: none} div.uimob500 .um-col-121, div.uimob500 .um-col-122, @@ -157,7 +356,7 @@ div.uimob500 .um-member { width: 100%; } -div.uimob500 .um-gutter-sizer { width: 0px } +div.uimob500 .um-gutter-sizer { width: 0px } div.uimob500 .um-account-main { float: none; @@ -246,6 +445,32 @@ div.uimob800 .um-account-meta img { border-radius: 3px; } +div.uimob800 .um-profile-photo { + width: 200px !important; +} + +div.uimob800 .um-profile-photo a.um-profile-photo-img { + width: 140px !important; + height: 140px !important; + top: -70px !important; +} + +div.uimob800 .um-header .um-profile-meta { + padding-left: 200px; +} + +div.uimob800 .um-cover-overlay span.um-cover-overlay-t, +div.uimob800 .um-profile-photo-overlay span.um-profile-photo-overlay-t +{ + display: none !important; +} + +div.uimob800 .um-cover-overlay, +div.uimob800 .um-profile-photo-overlay +{ + padding: 0; +} + /********************************************/ /** @@ -296,30 +521,62 @@ div.uimob960 .um-gutter-sizer { width: 4% } /************************************************/ -@media screen and ( max-height: 900px ){ - .um-single-image-preview img {max-height: 500px} +@media screen and (max-height: 400px) { + + .ajax-upload-dragdrop span.icon { + display: none; + } + + .um-modal { + width: 100% !important; + margin: 0 !important; + left: 0 !important; + height: 100%; + background: #fff; + } + + .um-modal, + .um-modal .um-modal-body, + .um-modal .um-modal-header { + border-radius: 0; + } + + .um-modal .um-modal-header {text-align: center; font-size: 14px} + .um-modal .um-modal-footer { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + box-sizing: border-box; + padding: 10px; + border-top: 1px solid #ddd; + } + + .um-modal .um-modal-right { + width: 100%; + float: none; + } + + .um-modal .um-modal-footer a.um-modal-btn { + width: 48%; + margin: 0 1%; + float: left; + display: block; + line-height: 44px !important; + height: 44px; + } + } -@media screen and ( max-height: 800px ){ - .um-single-image-preview img {max-height: 500px} -} +@media screen and (max-height: 300px) { -@media screen and ( max-height: 700px ){ - .um-single-image-preview img {max-height: 350px} -} + .um-modal-header { + display: none; + } + + .ajax-upload-dragdrop span.icon, + .ajax-upload-dragdrop span.str { + display: none; + } -@media screen and ( max-height: 600px ){ - .um-single-image-preview img {max-height: 300px} -} - -@media screen and ( max-height: 500px ){ - .um-single-image-preview img {max-height: 250px} -} - -@media screen and ( max-height: 400px ){ - .um-single-image-preview img {max-height: 200px} -} - -@media screen and ( max-height: 300px ){ - .um-single-image-preview img {max-height: 150px} } \ No newline at end of file diff --git a/assets/css/um-styles.css b/assets/css/um-styles.css index 74670e46..de3a7f66 100644 --- a/assets/css/um-styles.css +++ b/assets/css/um-styles.css @@ -25,7 +25,8 @@ box-sizing: content-box; } -.um a:focus { +.um a:focus, +.um-modal a:focus { outline: 0 !important; } @@ -209,8 +210,17 @@ p.um-notice.success { } .um-tip i { - font-size: 18px; + font-size: 20px; vertical-align: middle; + position: relative; + top: 2px; +} + +.um-tip-text { + display: block; + font-size: 13px; + line-height: 15px; + color: #999; } /* @@ -264,7 +274,6 @@ p.um-notice.success { .um-field-icon { position: absolute; - z-index: 888; cursor: default; text-align: center !important; top: 2px; @@ -485,4 +494,60 @@ a.um-link-alt { font-weight: normal; text-align: center; } -a.um-link-alt:hover {text-decoration: underline !important;} \ No newline at end of file +a.um-link-alt:hover {text-decoration: underline !important;} + +/* + - Dropdown menu +*/ + +.um-dropdown { + position: absolute; + height: auto; + background: #fff; + border-radius: 5px; + z-index: 555; + display: none; + border: 1px solid #e5e5e5; + box-sizing: border-box; + -webkit-box-shadow: 0 0 2px rgba(0,0,0,0.1); + box-shadow: 0 0 1px rgba(0,0,0,0.1); +} + +.um-dropdown ul, +.um-dropdown li { + list-style-type: none !important; + padding: 0 !important; + margin: 0 !important; +} + +.um-dropdown li a { + display: block; + padding: 8px 12px; + color: #666; + z-index: 4; + font-size: 14px; + line-height: 18px; + position: relative; +} + +.um-dropdown li:last-child a { + border-top: 1px solid #e5e5e5; + padding: 12px; +} + +.um-dropdown li a:hover { + color: #3ba1da; +} + +.um-dropdown-b { + position: relative; +} + +.um-dropdown-arr { + position: absolute; + color: #fff; + font-size: 24px; + width: 24px; + height: 24px; + z-index: 2; +} \ No newline at end of file diff --git a/assets/dynamic_css/dynamic_profile.php b/assets/dynamic_css/dynamic_profile.php index b45a9d02..7e580e8d 100644 --- a/assets/dynamic_css/dynamic_profile.php +++ b/assets/dynamic_css/dynamic_profile.php @@ -6,17 +6,35 @@ $photosize_up = ( $photosize / 2 ) + 10; $meta_padding = ( $photosize + 60 ) . 'px'; if ( $photocorner == 1 ) { -print ".um-$form_id.um .um-profile-photo a.um-profile-photo-img, .um-profile-photo img { border-radius: 999px !important }"; +print " +.um-$form_id.um .um-profile-photo a.um-profile-photo-img, +.um-$form_id.um .um-profile-photo img, +.um-$form_id.um .um-profile-photo span.um-profile-photo-overlay +{ border-radius: 999px !important }"; } if ( $photocorner == 2 ) { -print ".um-$form_id.um .um-profile-photo a.um-profile-photo-img, .um-profile-photo img { border-radius: 4px !important }"; +print " +.um-$form_id.um .um-profile-photo a.um-profile-photo-img, +.um-$form_id.um .um-profile-photo img, +.um-$form_id.um .um-profile-photo span.um-profile-photo-overlay +{ border-radius: 4px !important }"; } if ( $photocorner == 3 ) { -print ".um-$form_id.um .um-profile-photo a.um-profile-photo-img, .um-profile-photo img { border-radius: 0px !important }"; +print " +.um-$form_id.um .um-profile-photo a.um-profile-photo-img, +.um-$form_id.um .um-profile-photo img, +.um-$form_id.um .um-profile-photo span.um-profile-photo-overlay +{ border-radius: 0px !important }"; } +print " +.um-$form_id.um .um-profile-photo { + width: $meta_padding; +} +"; + print " .um-$form_id.um .um-header.no-cover a.um-profile-photo-img img, .um-$form_id.um .um-profile-photo a.um-profile-photo-img { diff --git a/assets/img/Dollarphotoclub_57189843.jpg b/assets/img/Dollarphotoclub_57189843.jpg deleted file mode 100644 index b31f6dc7..00000000 Binary files a/assets/img/Dollarphotoclub_57189843.jpg and /dev/null differ diff --git a/assets/img/best-hd-wallpapers-2.jpg b/assets/img/best-hd-wallpapers-2.jpg deleted file mode 100644 index 3debb249..00000000 Binary files a/assets/img/best-hd-wallpapers-2.jpg and /dev/null differ diff --git a/assets/js/um-crop.js b/assets/js/um-crop.js index bde7a214..3ab83a2c 100644 --- a/assets/js/um-crop.js +++ b/assets/js/um-crop.js @@ -1 +1,1569 @@ -eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(m($){18 W=2v.4T,D=2v.4S,F=2v.4R,u=2v.4Q;m V(){C $("<4P/>")};$.N=m(T,c){18 O=$(T),1F,A=V(),1k=V(),I=V().r(V()).r(V()).r(V()),B=V().r(V()).r(V()).r(V()),E=$([]),1K,G,l,17={v:0,l:0},Q,M,1l,1g={v:0,l:0},12=0,1J="1H",2k,2j,1t,1s,S,1B,1A,2o,2n,14,1Q,a,b,j,g,f={a:0,b:0,j:0,g:0,H:0,L:0},2u=R.4O,1M=4N.4M,$p,d,i,o,w,h,2p;m 1n(x){C x+17.v-1g.v};m 1m(y){C y+17.l-1g.l};m 1b(x){C x-17.v+1g.v};m 1a(y){C y-17.l+1g.l};m 1z(3J){C 3J.4L-1g.v};m 1y(3I){C 3I.4K-1g.l};m 13(32){18 1i=32||1t,1h=32||1s;C{a:u(f.a*1i),b:u(f.b*1h),j:u(f.j*1i),g:u(f.g*1h),H:u(f.j*1i)-u(f.a*1i),L:u(f.g*1h)-u(f.b*1h)}};m 23(a,b,j,g,31){18 1i=31||1t,1h=31||1s;f={a:u(a/1i||0),b:u(b/1h||0),j:u(j/1i||0),g:u(g/1h||0)};f.H=f.j-f.a;f.L=f.g-f.b};m 1f(){9(!1F||!O.H()){C}17={v:u(O.2t().v),l:u(O.2t().l)};Q=O.2Y();M=O.3H();17.l+=(O.30()-M)>>1;17.v+=(O.2q()-Q)>>1;1B=u(c.4J/1t)||0;1A=u(c.4I/1s)||0;2o=u(F(c.4H/1t||1<<24,Q));2n=u(F(c.4G/1s||1<<24,M));9($().4F=="1.3.2"&&1J=="21"&&!2u["4E"]){17.l+=D(R.1q.2r,2u.2r);17.v+=D(R.1q.2s,2u.2s)}1g=/1H|4D/.1c(1l.q("1p"))?{v:u(1l.2t().v)-1l.2s(),l:u(1l.2t().l)-1l.2r()}:1J=="21"?{v:$(R).2s(),l:$(R).2r()}:{v:0,l:0};G=1n(0);l=1m(0);9(f.j>Q||f.g>M){1U()}};m 1V(3F){9(!1Q){C}A.q({v:1n(f.a),l:1m(f.b)}).r(1k).H(w=f.H).L(h=f.L);1k.r(I).r(E).q({v:0,l:0});I.H(D(w-I.2q()+I.2Y(),0)).L(D(h-I.30()+I.3H(),0));$(B[0]).q({v:G,l:l,H:f.a,L:M});$(B[1]).q({v:G+f.a,l:l,H:w,L:f.b});$(B[2]).q({v:G+f.j,l:l,H:Q-f.j,L:M});$(B[3]).q({v:G+f.a,l:l+f.g,H:w,L:M-f.g});w-=E.2q();h-=E.30();2O(E.3f){15 8:$(E[4]).q({v:w>>1});$(E[5]).q({v:w,l:h>>1});$(E[6]).q({v:w>>1,l:h});$(E[7]).q({l:h>>1});15 4:E.3G(1,3).q({v:w});E.3G(2,4).q({l:h})}9(3F!==Y){9($.N.2Z!=2R){$(R).U($.N.2z,$.N.2Z)}9(c.1T){$(R)[$.N.2z]($.N.2Z=2R)}}9(1j&&I.2q()-I.2Y()==2){I.q("3E",0);3x(m(){I.q("3E","4C")},0)}};m 22(3D){1f();1V(3D);a=1n(f.a);b=1m(f.b);j=1n(f.j);g=1m(f.g)};m 27(2X,2w){c.1P?2X.4B(c.1P,2w):2X.1r()};m 1d(2W){18 x=1b(1z(2W))-f.a,y=1a(1y(2W))-f.b;9(!2p){1f();2p=11;A.1G("4A",m(){2p=Y})}S="";9(c.2D){9(y<=c.1W){S="n"}X{9(y>=f.L-c.1W){S="s"}}9(x<=c.1W){S+="w"}X{9(x>=f.H-c.1W){S+="e"}}}A.q("2V",S?S+"-19":c.26?"4z":"");9(1K){1K.4y()}};m 2S(4x){$("1q").q("2V","");9(c.4w||f.H*f.L==0){27(A.r(B),m(){$(J).1r()})}$(R).U("P",2l);A.P(1d);c.2f(T,13())};m 2C(1X){9(1X.3z!=1){C Y}1f();9(S){$("1q").q("2V",S+"-19");a=1n(f[/w/.1c(S)?"j":"a"]);b=1m(f[/n/.1c(S)?"g":"b"]);$(R).P(2l).1G("1x",2S);A.U("P",1d)}X{9(c.26){2k=G+f.a-1z(1X);2j=l+f.b-1y(1X);A.U("P",1d);$(R).P(2T).1G("1x",m(){c.2f(T,13());$(R).U("P",2T);A.P(1d)})}X{O.1O(1X)}}C Y};m 1w(3C){9(14){9(3C){j=D(G,F(G+Q,a+W(g-b)*14*(j>a||-1)));g=u(D(l,F(l+M,b+W(j-a)/14*(g>b||-1))));j=u(j)}X{g=D(l,F(l+M,b+W(j-a)/14*(g>b||-1)));j=u(D(G,F(G+Q,a+W(g-b)*14*(j>a||-1))));g=u(g)}}};m 1U(){a=F(a,G+Q);b=F(b,l+M);9(W(j-a)<1B){j=a-1B*(jG+Q){a=G+Q-1B}}}9(W(g-b)<1A){g=b-1A*(gl+M){b=l+M-1A}}}j=D(G,F(j,G+Q));g=D(l,F(g,l+M));1w(W(j-a)2o){j=a-2o*(j2n){g=b-2n*(g=0){E.H(5).L(5)}9(o=c.2K){E.q({2K:o,2H:"3m"})}1R(E,{3n:"2J-28",3l:"2I-28",3o:"1e"})}1t=c.4l/Q||1;1s=c.4k/M||1;9(K.a!=3q){23(K.a,K.b,K.j,K.g);K.2F=!K.1r}9(K.1T){c.1T=$.2c({2b:1,2a:"19"},K.1T)}B.29(c.1S+"-4j");1k.29(c.1S+"-4i");3p(i=0;i++<4;){$(I[i-1]).29(c.1S+"-2J"+i)}1R(1k,{4h:"2I-28",4g:"1e"});1R(I,{3o:"1e",2K:"2J-H"});1R(B,{4f:"2I-28",4e:"1e"});9(o=c.3n){$(I[0]).q({2H:"3m",3k:o})}9(o=c.3l){$(I[1]).q({2H:"4d",3k:o})}A.2G(1k.r(I).r(1K)).2G(E);9(1j){9(o=(B.q("3j")||"").3i(/1e=(\\d+)/)){B.q("1e",o[1]/1Z)}9(o=(I.q("3j")||"").3i(/1e=(\\d+)/)){I.q("1e",o[1]/1Z)}}9(K.1r){27(A.r(B))}X{9(K.2F&&1F){1Q=11;A.r(B).2E(c.1P||0);22()}}14=(d=(c.4c||"").4b(/:/))[0]/d[1];O.r(B).U("1O",2A);9(c.1E||c.1D===Y){A.U("P",1d).U("1O",2C);$(3h).U("19",2B)}X{9(c.1D||c.1E===Y){9(c.2D||c.26){A.P(1d).1O(2C)}$(3h).19(2B)}9(!c.4a){O.r(B).1O(2A)}}c.1D=c.1E=1Y};J.1o=m(){25({1E:11});A.r(B).1o()};J.49=m(){C c};J.33=25;J.48=13;J.47=23;J.46=1N;J.45=22;18 1j=(/44 ([\\w.]+)/i.43(1M)||[])[1],3c=/42/i.1c(1M),3d=/41/i.1c(1M)&&!/3Z/i.1c(1M);$p=O;3g($p.3f){12=D(12,!1L($p.q("z-3e"))?$p.q("z-3e"):12);9($p.q("1p")=="21"){1J="21"}$p=$p.20(":3Y(1q)")}12=c.1I||12;9(1j){O.3X("3W","3V")}$.N.2z=1j||3d?"3U":"3T";9(3c){1K=V().q({H:"1Z%",L:"1Z%",1p:"1H",1I:12+2||2})}A.r(B).q({3b:"3a",1p:1J,3S:"3a",1I:12||"0"});A.q({1I:12+2||2});1k.r(I).q({1p:"1H",36:0});T.35||T.3R=="35"||!O.2y("3Q")?2x():O.1G("3P",2x);9(!1F&&1j&&1j>=7){T.34=T.34}};$.2w.N=m(Z){Z=Z||{};J.3O(m(){9($(J).1C("N")){9(Z.1o){$(J).1C("N").1o();$(J).3N("N")}X{$(J).1C("N").33(Z)}}X{9(!Z.1o){9(Z.1D===1Y&&Z.1E===1Y){Z.1D=11}$(J).1C("N",3M $.N(J,Z))}}});9(Z.3L){C $(J).1C("N")}C J}})(3K);',62,304,'|||||||||if|x1|y1|_7|||_23|y2|||x2||top|function||||css|add|||_4|left|||||_a|_d|return|_2|_e|_3|_10|width|_c|this|_55|height|_13|imgAreaSelect|_8|mousemove|_12|document|_1c|_6|unbind|_5|_1|else|false|_58||true|_16|_2c|_21|case|_50|_11|var|resize|_29|_28|test|_3a|opacity|_30|_15|sy|sx|_35|_b|_14|_27|_26|remove|position|body|hide|_1b|_1a|break|_45|_42|mouseup|evY|evX|_1e|_1d|data|enable|disable|_9|one|absolute|zIndex|_17|_f|isNaN|ua|_4a|mousedown|fadeSpeed|_22|_51|classPrefix|keys|_31|_32|resizeMargin|_40|undefined|100|parent|fixed|_36|_2e||_4f|movable|_38|color|addClass|ctrl|shift|extend|_54|altKey|onSelectEnd|onSelectChange|_49|_4c|_19|_18|_3e|_48|_20|_1f|_25|outerWidth|scrollTop|scrollLeft|offset|_24|Math|fn|_4e|is|keyPress|_4b|_4d|_3f|resizable|fadeIn|show|append|borderStyle|background|border|borderWidth|handles|_53|key|switch|alt|arrows|_34|_3c|_41|_44|cursor|_3b|_39|innerWidth|onKeyPress|outerHeight|_2f|_2d|setOptions|src|complete|fontSize||||hidden|visibility|_56|_57|index|length|while|window|match|filter|borderColor|borderColor2|solid|borderColor1|borderOpacity|for|null|_52|default|originalEvent|ctrlKey|shiftKey|onInit|setTimeout|onSelectStart|which|_47|_46|_43|_37|margin|_33|slice|innerHeight|_2b|_2a|jQuery|instance|new|removeData|each|load|img|readyState|overflow|keypress|keydown|on|unselectable|attr|not|chrome||webkit|opera|exec|msie|update|cancelSelection|setSelection|getSelection|getOptions|persistent|split|aspectRatio|dashed|outerOpacity|outerColor|selectionOpacity|selectionColor|selection|outer|imageHeight|imageWidth|parseInt|handle|corners|in|keyCode|imgareaselect|animated|instanceof|visible|preventDefault|autoHide|_3d|toggle|move|mouseout|fadeOut|auto|relative|getBoundingClientRect|jquery|maxHeight|maxWidth|minHeight|minWidth|pageY|pageX|userAgent|navigator|documentElement|div|round|min|max|abs'.split('|'))) +(function (factory) { + if (typeof define === "function" && define.amd) { + // AMD. Register as anonymous module. + define(["jquery"], factory); + } else if (typeof exports === "object") { + // Node / CommonJS + factory(require("jquery")); + } else { + // Browser globals. + factory(jQuery); + } +})(function ($) { + + "use strict"; + + var $window = $(window), + $document = $(document), + location = window.location, + + // Constants + TRUE = true, + FALSE = false, + NULL = null, + NAN = NaN, + INFINITY = Infinity, + STRING_UNDEFINED = "undefined", + STRING_DIRECTIVE = "directive", + CROPPER_NAMESPACE = ".cropper", + + // RegExps + REGEXP_DIRECTIVES = /^(e|n|w|s|ne|nw|sw|se|all|crop|move|zoom)$/, + REGEXP_OPTIONS = /^(x|y|width|height)$/, + REGEXP_PROPERTIES = /^(naturalWidth|naturalHeight|width|height|aspectRatio|ratio|rotate)$/, + + // Classes + CLASS_MODAL = "cropper-modal", + CLASS_HIDDEN = "cropper-hidden", + CLASS_INVISIBLE = "cropper-invisible", + CLASS_MOVE = "cropper-move", + CLASS_CROP = "cropper-crop", + CLASS_DISABLED = "cropper-disabled", + + // Events + EVENT_MOUSE_DOWN = "mousedown touchstart", + EVENT_MOUSE_MOVE = "mousemove touchmove", + EVENT_MOUSE_UP = "mouseup mouseleave touchend touchleave touchcancel", + EVENT_WHEEL = "wheel mousewheel DOMMouseScroll", + EVENT_RESIZE = "resize" + CROPPER_NAMESPACE, // Bind to window with namespace + EVENT_DBLCLICK = "dblclick", + EVENT_BUILD = "build" + CROPPER_NAMESPACE, + EVENT_BUILT = "built" + CROPPER_NAMESPACE, + EVENT_DRAG_START = "dragstart" + CROPPER_NAMESPACE, + EVENT_DRAG_MOVE = "dragmove" + CROPPER_NAMESPACE, + EVENT_DRAG_END = "dragend" + CROPPER_NAMESPACE, + + // Functions + isNumber = function (n) { + return typeof n === "number"; + }, + + toArray = function (obj, offset) { + var args = []; + + if (typeof offset === "number") { // It's necessary for IE8 + args.push(offset); + } + + return args.slice.apply(obj, args); + }, + + // Custom proxy to avoid jQuery's guid + proxy = function (fn, context) { + var args = toArray(arguments, 2); + + return function () { + return fn.apply(context, args.concat(toArray(arguments))); + }; + }, + + // Constructor + Cropper = function (element, options) { + this.element = element; + this.$element = $(element); + this.defaults = $.extend({}, Cropper.DEFAULTS, $.isPlainObject(options) ? options : {}); + this.$original = NULL; + this.ready = FALSE; + this.built = FALSE; + this.cropped = FALSE; + this.rotated = FALSE; + this.disabled = FALSE; + this.replaced = FALSE; + this.init(); + }, + + // Others + sqrt = Math.sqrt, + min = Math.min, + max = Math.max, + abs = Math.abs, + sin = Math.sin, + cos = Math.cos, + num = parseFloat; + + Cropper.prototype = { + constructor: Cropper, + + support: { + canvas: $.isFunction($("")[0].getContext) + }, + + init: function () { + var defaults = this.defaults; + + $.each(defaults, function (i, n) { + switch (i) { + case "aspectRatio": + defaults[i] = abs(num(n)) || NAN; // 0 -> NaN + break; + + case "autoCropArea": + defaults[i] = abs(num(n)) || 0.8; // 0 | NaN -> 0.8 + break; + + case "minWidth": + case "minHeight": + defaults[i] = abs(num(n)) || 0; // NaN -> 0 + break; + + case "maxWidth": + case "maxHeight": + defaults[i] = abs(num(n)) || INFINITY; // 0 | NaN -> Infinity + break; + + // No default + } + }); + + // Set default image data + this.image = { + rotate: 0 + }; + + this.load(); + }, + + load: function () { + var _this = this, + $this = this.$element, + element = this.element, + image = this.image, + crossOrigin = "", + $clone, + url; + + if ($this.is("img")) { + url = $this.prop("src"); + } else if ($this.is("canvas") && this.support.canvas) { + url = element.toDataURL(); + } + + if (!url) { + return; + } + + // Reset image rotate degree + if (this.replaced) { + image.rotate = 0; + } + + if (this.defaults.checkImageOrigin) { + if ($this.prop("crossOrigin") || this.isCrossOriginURL(url)) { + crossOrigin = " crossOrigin"; + } + } + + this.$clone = ($clone = $("')); + + $clone.one("load", function () { + image.naturalWidth = this.naturalWidth || $clone.width(); + image.naturalHeight = this.naturalHeight || $clone.height(); + image.aspectRatio = image.naturalWidth / image.naturalHeight; + + _this.url = url; + _this.ready = TRUE; + _this.build(); + }); + + // Hide and prepend the clone iamge to the document body (Don't append to). + $clone.addClass(CLASS_INVISIBLE).prependTo("body"); + }, + + isCrossOriginURL: function (url) { + var parts = url.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i); + + if ((parts && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port))) { + return TRUE; + } + + return FALSE; + }, + + build: function () { + var $this = this.$element, + defaults = this.defaults, + buildEvent, + $cropper; + + if (!this.ready) { + return; + } + + if (this.built) { + this.unbuild(); + } + + $this.one(EVENT_BUILD, defaults.build); // Only trigger once + buildEvent = $.Event(EVENT_BUILD); + $this.trigger(buildEvent); + + if (buildEvent.isDefaultPrevented()) { + return; + } + + // Create cropper elements + this.$cropper = ($cropper = $(Cropper.TEMPLATE)); + + // Hide the original image + $this.addClass(CLASS_HIDDEN); + + // Show and prepend the clone iamge to the cropper + this.$clone.removeClass(CLASS_INVISIBLE).prependTo($cropper); + + // Save original image for rotation + if (!this.rotated) { + this.$original = this.$clone.clone(); + + // Append the image to document to avoid "NS_ERROR_NOT_AVAILABLE" error on Firefox when call the "drawImage" method. + this.$original.addClass(CLASS_HIDDEN).prependTo(this.$cropper); + + this.originalImage = $.extend({}, this.image); + } + + this.$container = $this.parent(); + this.$container.append($cropper); + + this.$canvas = $cropper.find(".cropper-canvas"); + this.$dragger = $cropper.find(".cropper-dragger"); + this.$viewer = $cropper.find(".cropper-viewer"); + + defaults.autoCrop ? (this.cropped = TRUE) : this.$dragger.addClass(CLASS_HIDDEN); + defaults.dragCrop && this.setDragMode("crop"); + defaults.modal && this.$canvas.addClass(CLASS_MODAL); + !defaults.dashed && this.$dragger.find(".cropper-dashed").addClass(CLASS_HIDDEN); + !defaults.movable && this.$dragger.find(".cropper-face").data(STRING_DIRECTIVE, "move"); + !defaults.resizable && this.$dragger.find(".cropper-line, .cropper-point").addClass(CLASS_HIDDEN); + + this.addListeners(); + this.initPreview(); + + this.built = TRUE; // Set `true` before update + this.update(); + this.replaced = FALSE; // Reset to `false` after update + + $this.one(EVENT_BUILT, defaults.built); // Only trigger once + $this.trigger(EVENT_BUILT); + }, + + unbuild: function () { + if (!this.built) { + return; + } + + this.built = FALSE; + this.removeListeners(); + + this.$preview.empty(); + this.$preview = NULL; + + this.$dragger = NULL; + this.$canvas = NULL; + this.$container = NULL; + + this.$cropper.remove(); + this.$cropper = NULL; + }, + + update: function (data) { + this.initContainer(); + this.initCropper(); + this.initImage(); + this.initDragger(); + + if (data) { + this.setData(data, TRUE); + this.setDragMode("crop"); + } else { + this.setData(this.defaults.data); + } + }, + + resize: function () { + clearTimeout(this.resizing); + this.resizing = setTimeout($.proxy(this.update, this, this.getData()), 200); + }, + + preview: function () { + var image = this.image, + dragger = this.dragger, + width = image.width, + height = image.height, + left = dragger.left - image.left, + top = dragger.top - image.top; + + this.$viewer.find("img").css({ + width: width, + height: height, + marginLeft: -left, + marginTop: -top + }); + + this.$preview.each(function () { + var $this = $(this), + ratio = $this.width() / dragger.width; + + $this.find("img").css({ + width: width * ratio, + height: height * ratio, + marginLeft: -left * ratio, + marginTop: -top * ratio + }); + }); + }, + + addListeners: function () { + var defaults = this.defaults; + + this.$element.on(EVENT_DRAG_START, defaults.dragstart).on(EVENT_DRAG_MOVE, defaults.dragmove).on(EVENT_DRAG_END, defaults.dragend); + this.$cropper.on(EVENT_MOUSE_DOWN, $.proxy(this.dragstart, this)).on(EVENT_DBLCLICK, $.proxy(this.dblclick, this)); + + if (defaults.zoomable) { + this.$cropper.on(EVENT_WHEEL, $.proxy(this.wheel, this)); + } + + if (defaults.multiple) { + this.$cropper.on(EVENT_MOUSE_MOVE, $.proxy(this.dragmove, this)).on(EVENT_MOUSE_UP, $.proxy(this.dragend, this)); + } else { + $document.on(EVENT_MOUSE_MOVE, (this._dragmove = proxy(this.dragmove, this))).on(EVENT_MOUSE_UP, (this._dragend = proxy(this.dragend, this))); + } + + $window.on(EVENT_RESIZE, (this._resize = proxy(this.resize, this))); + }, + + removeListeners: function () { + var defaults = this.defaults; + + this.$element.off(EVENT_DRAG_START, defaults.dragstart).off(EVENT_DRAG_MOVE, defaults.dragmove).off(EVENT_DRAG_END, defaults.dragend); + this.$cropper.off(EVENT_MOUSE_DOWN, this.dragstart).off(EVENT_DBLCLICK, this.dblclick); + + if (defaults.zoomable) { + this.$cropper.off(EVENT_WHEEL, this.wheel); + } + + if (defaults.multiple) { + this.$cropper.off(EVENT_MOUSE_MOVE, this.dragmove).off(EVENT_MOUSE_UP, this.dragend); + } else { + $document.off(EVENT_MOUSE_MOVE, this._dragmove).off(EVENT_MOUSE_UP, this._dragend); + } + + $window.off(EVENT_RESIZE, this._resize); + }, + + initPreview: function () { + var img = ''; + + this.$preview = $(this.defaults.preview); + this.$viewer.html(img); + this.$preview.html(img).find("img").css("cssText", "min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;"); + }, + + initContainer: function () { + var $container = this.$container; + + this.container = { + width: max($container.width(), 300), + height: max($container.height(), 150) + }; + }, + + initCropper: function () { + var container = this.container, + image = this.image, + cropper; + + if (((image.naturalWidth * container.height / image.naturalHeight) - container.width) >= 0) { + cropper = { + width: container.width, + height: container.width / image.aspectRatio, + left: 0 + }; + + cropper.top = (container.height - cropper.height) / 2; + } else { + cropper = { + width: container.height * image.aspectRatio, + height: container.height, + top: 0 + }; + + cropper.left = (container.width - cropper.width) / 2; + } + + this.$cropper.css({ + width: cropper.width, + height: cropper.height, + left: cropper.left, + top: cropper.top + }); + + this.cropper = cropper; + }, + + initImage: function () { + var image = this.image, + cropper = this.cropper, + defaultImage = { + _width: cropper.width, + _height: cropper.height, + width: cropper.width, + height: cropper.height, + left: 0, + top: 0, + ratio: cropper.width / image.naturalWidth + }; + + this.defaultImage = $.extend({}, image, defaultImage); + + if (image._width !== cropper.width || image._height !== cropper.height) { + $.extend(image, defaultImage); + } else { + image = $.extend({}, defaultImage, image); + + // Reset image ratio + if (this.replaced) { + image.ratio = defaultImage.ratio; + } + } + + this.image = image; + this.renderImage(); + }, + + renderImage: function (mode) { + var image = this.image; + + if (mode === "zoom") { + image.left -= (image.width - image.oldWidth) / 2; + image.top -= (image.height - image.oldHeight) / 2; + } + + image.left = min(max(image.left, image._width - image.width), 0); + image.top = min(max(image.top, image._height - image.height), 0); + + this.$clone.css({ + width: image.width, + height: image.height, + marginLeft: image.left, + marginTop: image.top + }); + + if (mode) { + this.defaults.done(this.getData()); + this.preview(); + } + }, + + initDragger: function () { + var defaults = this.defaults, + cropper = this.cropper, + // If not set, use the original aspect ratio of the image. + aspectRatio = defaults.aspectRatio || this.image.aspectRatio, + ratio = this.image.ratio, + dragger; + + if (((cropper.height * aspectRatio) - cropper.width) >= 0) { + dragger = { + height: cropper.width / aspectRatio, + width: cropper.width, + left: 0, + top: (cropper.height - (cropper.width / aspectRatio)) / 2, + maxWidth: cropper.width, + maxHeight: cropper.width / aspectRatio + }; + } else { + dragger = { + height: cropper.height, + width: cropper.height * aspectRatio, + left: (cropper.width - (cropper.height * aspectRatio)) / 2, + top: 0, + maxWidth: cropper.height * aspectRatio, + maxHeight: cropper.height + }; + } + + dragger.minWidth = 0; + dragger.minHeight = 0; + + if (defaults.aspectRatio) { + if (isFinite(defaults.maxWidth)) { + dragger.maxWidth = min(dragger.maxWidth, defaults.maxWidth * ratio); + dragger.maxHeight = dragger.maxWidth / aspectRatio; + } else if (isFinite(defaults.maxHeight)) { + dragger.maxHeight = min(dragger.maxHeight, defaults.maxHeight * ratio); + dragger.maxWidth = dragger.maxHeight * aspectRatio; + } + + if (defaults.minWidth > 0) { + dragger.minWidth = max(0, defaults.minWidth * ratio); + dragger.minHeight = dragger.minWidth / aspectRatio; + } else if (defaults.minHeight > 0) { + dragger.minHeight = max(0, defaults.minHeight * ratio); + dragger.minWidth = dragger.minHeight * aspectRatio; + } + } else { + dragger.maxWidth = min(dragger.maxWidth, defaults.maxWidth * ratio); + dragger.maxHeight = min(dragger.maxHeight, defaults.maxHeight * ratio); + dragger.minWidth = max(0, defaults.minWidth * ratio); + dragger.minHeight = max(0, defaults.minHeight * ratio); + } + + // minWidth can't be greater than maxWidth, and minHeight too. + dragger.minWidth = min(dragger.maxWidth, dragger.minWidth); + dragger.minHeight = min(dragger.maxHeight, dragger.minHeight); + + // Center the dragger by default + dragger.height *= defaults.autoCropArea; + dragger.width *= defaults.autoCropArea; + dragger.left = (cropper.width - dragger.width) / 2; + dragger.top = (cropper.height - dragger.height) / 2; + dragger.oldLeft = dragger.left; + dragger.oldTop = dragger.top; + + this.defaultDragger = dragger; + this.dragger = $.extend({}, dragger); + }, + + renderDragger: function () { + var dragger = this.dragger, + cropper = this.cropper; + + if (dragger.width > dragger.maxWidth) { + dragger.width = dragger.maxWidth; + dragger.left = dragger.oldLeft; + } else if (dragger.width < dragger.minWidth) { + dragger.width = dragger.minWidth; + dragger.left = dragger.oldLeft; + } + + if (dragger.height > dragger.maxHeight) { + dragger.height = dragger.maxHeight; + dragger.top = dragger.oldTop; + } else if (dragger.height < dragger.minHeight) { + dragger.height = dragger.minHeight; + dragger.top = dragger.oldTop; + } + + dragger.left = min(max(dragger.left, 0), cropper.width - dragger.width); + dragger.top = min(max(dragger.top, 0), cropper.height - dragger.height); + dragger.oldLeft = dragger.left; + dragger.oldTop = dragger.top; + + // Re-render the dragger + this.dragger = dragger; + + if (!this.disabled) { + this.defaults.done(this.getData()); + } + + this.$dragger.css({ + width: dragger.width, + height: dragger.height, + left: dragger.left, + top: dragger.top + }); + + this.preview(); + }, + + reset: function (deep) { + if (!this.cropped) { + return; + } + + if (deep) { + this.defaults.data = {}; + } + + this.image = $.extend({}, this.defaultImage); + this.renderImage(); + this.dragger = $.extend({}, this.defaultDragger); + this.setData(this.defaults.data); + }, + + clear: function () { + if (!this.cropped) { + return; + } + + this.cropped = FALSE; + + this.setData({ + x: 0, + y: 0, + width: 0, + height: 0 + }); + + this.$canvas.removeClass(CLASS_MODAL); + this.$dragger.addClass(CLASS_HIDDEN); + }, + + destroy: function () { + var $this = this.$element; + + if (!this.ready) { + return; + } + + this.unbuild(); + $this.removeClass(CLASS_HIDDEN).removeData("cropper"); + + if (this.rotated) { + $this.attr("src", this.$original.attr("src")); + } + }, + + replace: function (url, /*INTERNAL*/ rotated) { + var _this = this, + $this = this.$element, + element = this.element, + context; + + if (url && url !== this.url && url !== $this.attr("src")) { + if (!rotated) { + this.rotated = FALSE; + this.replaced = TRUE; + } + + if ($this.is("img")) { + $this.attr("src", url); + this.load(); + } else if ($this.is("canvas") && this.support.canvas) { + context = element.getContext("2d"); + + $('').one("load", function () { + element.width = this.width; + element.height = this.height; + context.clearRect(0, 0, element.width, element.height); + context.drawImage(this, 0, 0); + _this.load(); + }); + } + } + }, + + setData: function (data, /*INTERNAL*/ once) { + var cropper = this.cropper, + dragger = this.dragger, + image = this.image, + aspectRatio = this.defaults.aspectRatio; + + if (!this.built || typeof data === STRING_UNDEFINED) { + return; + } + + if (data === NULL || $.isEmptyObject(data)) { + dragger = $.extend({}, this.defaultDragger); + } + + if ($.isPlainObject(data) && !$.isEmptyObject(data)) { + + if (!once) { + this.defaults.data = data; + } + + data = this.transformData(data); + + if (isNumber(data.x) && data.x <= cropper.width - image.left) { + dragger.left = data.x + image.left; + } + + if (isNumber(data.y) && data.y <= cropper.height - image.top) { + dragger.top = data.y + image.top; + } + + if (aspectRatio) { + if (isNumber(data.width) && data.width <= dragger.maxWidth && data.width >= dragger.minWidth) { + dragger.width = data.width; + dragger.height = dragger.width / aspectRatio; + } else if (isNumber(data.height) && data.height <= dragger.maxHeight && data.height >= dragger.minHeight) { + dragger.height = data.height; + dragger.width = dragger.height * aspectRatio; + } + } else { + if (isNumber(data.width) && data.width <= dragger.maxWidth && data.width >= dragger.minWidth) { + dragger.width = data.width; + } + + if (isNumber(data.height) && data.height <= dragger.maxHeight && data.height >= dragger.minHeight) { + dragger.height = data.height; + } + } + } + + this.dragger = dragger; + this.renderDragger(); + }, + + getData: function (rounded) { + var dragger = this.dragger, + image = this.image, + data = {}; + + if (this.built) { + data = { + x: dragger.left - image.left, + y: dragger.top - image.top, + width: dragger.width, + height: dragger.height + }; + + data = this.transformData(data, TRUE, rounded); + } + + return data; + }, + + transformData: function (data, reversed, rounded) { + var ratio = this.image.ratio, + result = {}; + + $.each(data, function (i, n) { + n = num(n); + + if (REGEXP_OPTIONS.test(i) && !isNaN(n)) { + result[i] = reversed ? (rounded ? Math.round(n / ratio) : n / ratio) : n * ratio; + } + }); + + return result; + }, + + setAspectRatio: function (aspectRatio) { + var freeRatio = aspectRatio === "auto"; + + aspectRatio = num(aspectRatio); + + if (freeRatio || (!isNaN(aspectRatio) && aspectRatio > 0)) { + this.defaults.aspectRatio = freeRatio ? NAN : aspectRatio; + + if (this.built) { + this.initDragger(); + this.renderDragger(); + } + } + }, + + getImageData: function () { + var data = {}; + + if (this.ready) { + $.each(this.image, function (name, value) { + if (REGEXP_PROPERTIES.test(name)) { + data[name] = value; + } + }); + } + + return data; + }, + + getDataURL: function (options, type, quality) { + var canvas = $("")[0], + data = this.getData(), + dataURL = "", + context; + + if (!$.isPlainObject(options)) { + quality = type; + type = options; + options = {}; + } + + options = $.extend({ + width: data.width, + height: data.height + }, options); + + if (this.cropped && this.support.canvas) { + canvas.width = options.width; + canvas.height = options.height; + context = canvas.getContext("2d"); + + if (type === "image/jpeg") { + context.fillStyle = "#fff"; + context.fillRect(0, 0, options.width, options.height); + } + + context.drawImage(this.$clone[0], data.x, data.y, data.width, data.height, 0, 0, options.width, options.height); + dataURL = canvas.toDataURL(type, quality); + } + + return dataURL; + }, + + setDragMode: function (mode) { + var $canvas = this.$canvas, + defaults = this.defaults, + cropable = FALSE, + movable = FALSE; + + if (!this.built || this.disabled) { + return; + } + + switch (mode) { + case "crop": + if (defaults.dragCrop) { + cropable = TRUE; + $canvas.data(STRING_DIRECTIVE, mode); + } + + break; + + case "move": + movable = TRUE; + $canvas.data(STRING_DIRECTIVE, mode); + + break; + + default: + $canvas.removeData(STRING_DIRECTIVE); + } + + $canvas.toggleClass(CLASS_CROP, cropable).toggleClass(CLASS_MOVE, movable); + }, + + enable: function () { + if (this.built) { + this.disabled = FALSE; + this.$cropper.removeClass(CLASS_DISABLED); + } + }, + + disable: function () { + if (this.built) { + this.disabled = TRUE; + this.$cropper.addClass(CLASS_DISABLED); + } + }, + + rotate: function (degree) { + var image = this.image; + + degree = num(degree) || 0; + + if (!this.built || degree === 0 || this.disabled || !this.defaults.rotatable || !this.support.canvas) { + return; + } + + this.rotated = TRUE; + degree = (image.rotate = (image.rotate + degree) % 360); + + // replace with "true" to prevent to override the original image + this.replace(this.getRotatedDataURL(degree), true); + }, + + getRotatedDataURL: function (degree) { + var canvas = $("")[0], + context = canvas.getContext("2d"), + arc = degree * Math.PI / 180, + deg = abs(degree) % 180, + acuteAngle = deg > 90 ? (180 - deg) : deg, + acuteAngleArc = acuteAngle * Math.PI / 180, + originalImage = this.originalImage, + naturalWidth = originalImage.naturalWidth, + naturalHeight = originalImage.naturalHeight, + width = abs(naturalWidth * cos(acuteAngleArc) + naturalHeight * sin(acuteAngleArc)), + height = abs(naturalWidth * sin(acuteAngleArc) + naturalHeight * cos(acuteAngleArc)); + + canvas.width = width; + canvas.height = height; + context.save(); + context.translate(width / 2, height / 2); + context.rotate(arc); + context.drawImage(this.$original[0], -naturalWidth / 2, -naturalHeight / 2, naturalWidth, naturalHeight); + context.restore(); + + return canvas.toDataURL(); + }, + + zoom: function (delta) { + var image = this.image, + width, + height, + range; + + delta = num(delta); + + if (!this.built || !delta || this.disabled || !this.defaults.zoomable) { + return; + } + + width = image.width * (1 + delta); + height = image.height * (1 + delta); + range = width / image._width; + + if (range > 10) { + return; + } + + if (range < 1) { + width = image._width; + height = image._height; + } + + if (range <= 1) { + this.setDragMode("crop"); + } else { + this.setDragMode("move"); + } + + image.oldWidth = image.width; + image.oldHeight = image.height; + + image.width = width; + image.height = height; + image.ratio = image.width / image.naturalWidth; + + this.renderImage("zoom"); + }, + + dblclick: function () { + if (this.disabled) { + return; + } + + if (this.$canvas.hasClass(CLASS_CROP)) { + this.setDragMode("move"); + } else { + this.setDragMode("crop"); + } + }, + + wheel: function (event) { + var e = event.originalEvent, + msDeltaY = 117.25, // IE + mozDelatY = 5, // Firefox + webkitDelatY = 166.66665649414062, // Chrome, Opera + zoomDelta = 0.1, // 10% + delta; + + if (this.disabled) { + return; + } + + event.preventDefault(); + + if (e.deltaY) { + delta = e.deltaY; + delta = delta % mozDelatY === 0 ? delta / mozDelatY : delta % msDeltaY === 0 ? delta / msDeltaY : delta / webkitDelatY; + } else { + delta = e.wheelDelta ? -e.wheelDelta / 120 : (e.detail ? e.detail / 3 : 0); + } + + this.zoom(delta * zoomDelta); + }, + + dragstart: function (event) { + var touches = event.originalEvent.touches, + e = event, + directive, + dragStartEvent, + touchesLength; + + if (this.disabled) { + return; + } + + if (touches) { + touchesLength = touches.length; + + if (touchesLength > 1) { + if (this.defaults.zoomable && touchesLength === 2) { + e = touches[1]; + this.startX2 = e.pageX; + this.startY2 = e.pageY; + directive = "zoom"; + } else { + return; + } + } + + e = touches[0]; + } + + directive = directive || $(e.target).data(STRING_DIRECTIVE); + + if (REGEXP_DIRECTIVES.test(directive)) { + event.preventDefault(); + + dragStartEvent = $.Event(EVENT_DRAG_START); + this.$element.trigger(dragStartEvent); + + if (dragStartEvent.isDefaultPrevented()) { + return; + } + + this.directive = directive; + this.cropping = FALSE; + this.startX = e.pageX; + this.startY = e.pageY; + + if (directive === "crop") { + this.cropping = TRUE; + this.$canvas.addClass(CLASS_MODAL); + } + } + }, + + dragmove: function (event) { + var touches = event.originalEvent.touches, + e = event, + dragMoveEvent, + touchesLength; + + if (this.disabled) { + return; + } + + if (touches) { + touchesLength = touches.length; + + if (touchesLength > 1) { + if (this.defaults.zoomable && touchesLength === 2) { + e = touches[1]; + this.endX2 = e.pageX; + this.endY2 = e.pageY; + } else { + return; + } + } + + e = touches[0]; + } + + if (this.directive) { + event.preventDefault(); + + dragMoveEvent = $.Event(EVENT_DRAG_MOVE); + this.$element.trigger(dragMoveEvent); + + if (dragMoveEvent.isDefaultPrevented()) { + return; + } + + this.endX = e.pageX; + this.endY = e.pageY; + + this.dragging(); + } + }, + + dragend: function (event) { + var dragEndEvent; + + if (this.disabled) { + return; + } + + if (this.directive) { + event.preventDefault(); + + dragEndEvent = $.Event(EVENT_DRAG_END); + this.$element.trigger(dragEndEvent); + + if (dragEndEvent.isDefaultPrevented()) { + return; + } + + if (this.cropping) { + this.cropping = FALSE; + this.$canvas.toggleClass(CLASS_MODAL, this.cropped && this.defaults.modal); + } + + this.directive = ""; + } + }, + + dragging: function () { + var directive = this.directive, + image = this.image, + cropper = this.cropper, + maxWidth = cropper.width, + maxHeight = cropper.height, + dragger = this.dragger, + width = dragger.width, + height = dragger.height, + left = dragger.left, + top = dragger.top, + right = left + width, + bottom = top + height, + renderable = TRUE, + defaults = this.defaults, + aspectRatio = defaults.aspectRatio, + range = { + x: this.endX - this.startX, + y: this.endY - this.startY + }, + offset; + + if (aspectRatio) { + range.X = range.y * aspectRatio; + range.Y = range.x / aspectRatio; + } + + switch (directive) { + // Move dragger + case "all": + left += range.x; + top += range.y; + + break; + + // Resize dragger + case "e": + if (range.x >= 0 && (right >= maxWidth || aspectRatio && (top <= 0 || bottom >= maxHeight))) { + renderable = FALSE; + break; + } + + width += range.x; + + if (aspectRatio) { + height = width / aspectRatio; + top -= range.Y / 2; + } + + if (width < 0) { + directive = "w"; + width = 0; + } + + break; + + case "n": + if (range.y <= 0 && (top <= 0 || aspectRatio && (left <= 0 || right >= maxWidth))) { + renderable = FALSE; + break; + } + + height -= range.y; + top += range.y; + + if (aspectRatio) { + width = height * aspectRatio; + left += range.X / 2; + } + + if (height < 0) { + directive = "s"; + height = 0; + } + + break; + + case "w": + if (range.x <= 0 && (left <= 0 || aspectRatio && (top <= 0 || bottom >= maxHeight))) { + renderable = FALSE; + break; + } + + width -= range.x; + left += range.x; + + if (aspectRatio) { + height = width / aspectRatio; + top += range.Y / 2; + } + + if (width < 0) { + directive = "e"; + width = 0; + } + + break; + + case "s": + if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && (left <= 0 || right >= maxWidth))) { + renderable = FALSE; + break; + } + + height += range.y; + + if (aspectRatio) { + width = height * aspectRatio; + left -= range.X / 2; + } + + if (height < 0) { + directive = "n"; + height = 0; + } + + break; + + case "ne": + if (aspectRatio) { + if (range.y <= 0 && (top <= 0 || right >= maxWidth)) { + renderable = FALSE; + break; + } + + height -= range.y; + top += range.y; + width = height * aspectRatio; + } else { + if (range.x >= 0) { + if (right < maxWidth) { + width += range.x; + } else if (range.y <= 0 && top <= 0) { + renderable = FALSE; + } + } else { + width += range.x; + } + + if (range.y <= 0) { + if (top > 0) { + height -= range.y; + top += range.y; + } + } else { + height -= range.y; + top += range.y; + } + } + + if (height < 0) { + directive = "sw"; + height = 0; + width = 0; + } + + break; + + case "nw": + if (aspectRatio) { + if (range.y <= 0 && (top <= 0 || left <= 0)) { + renderable = FALSE; + break; + } + + height -= range.y; + top += range.y; + width = height * aspectRatio; + left += range.X; + } else { + if (range.x <= 0) { + if (left > 0) { + width -= range.x; + left += range.x; + } else if (range.y <= 0 && top <= 0) { + renderable = FALSE; + } + } else { + width -= range.x; + left += range.x; + } + + if (range.y <= 0) { + if (top > 0) { + height -= range.y; + top += range.y; + } + } else { + height -= range.y; + top += range.y; + } + } + + if (height < 0) { + directive = "se"; + height = 0; + width = 0; + } + + break; + + case "sw": + if (aspectRatio) { + if (range.x <= 0 && (left <= 0 || bottom >= maxHeight)) { + renderable = FALSE; + break; + } + + width -= range.x; + left += range.x; + height = width / aspectRatio; + } else { + if (range.x <= 0) { + if (left > 0) { + width -= range.x; + left += range.x; + } else if (range.y >= 0 && bottom >= maxHeight) { + renderable = FALSE; + } + } else { + width -= range.x; + left += range.x; + } + + if (range.y >= 0) { + if (bottom < maxHeight) { + height += range.y; + } + } else { + height += range.y; + } + } + + if (width < 0) { + directive = "ne"; + height = 0; + width = 0; + } + + break; + + case "se": + if (aspectRatio) { + if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) { + renderable = FALSE; + break; + } + + width += range.x; + height = width / aspectRatio; + } else { + if (range.x >= 0) { + if (right < maxWidth) { + width += range.x; + } else if (range.y >= 0 && bottom >= maxHeight) { + renderable = FALSE; + } + } else { + width += range.x; + } + + if (range.y >= 0) { + if (bottom < maxHeight) { + height += range.y; + } + } else { + height += range.y; + } + } + + if (width < 0) { + directive = "nw"; + height = 0; + width = 0; + } + + break; + + // Move image + case "move": + image.left += range.x; + image.top += range.y; + this.renderImage("move"); + renderable = FALSE; + + break; + + // Scale image + case "zoom": + if (defaults.zoomable) { + this.zoom(function (x, y, x1, y1, x2, y2) { + return (sqrt(x2 * x2 + y2 * y2) - sqrt(x1 * x1 + y1 * y1)) / sqrt(x * x + y * y); + }( + image.width, + image.height, + abs(this.startX - this.startX2), + abs(this.startY - this.startY2), + abs(this.endX - this.endX2), + abs(this.endY - this.endY2) + )); + + this.endX2 = this.startX2; + this.endY2 = this.startY2; + } + + break; + + // Crop image + case "crop": + if (range.x && range.y) { + offset = this.$cropper.offset(); + left = this.startX - offset.left; + top = this.startY - offset.top; + width = dragger.minWidth; + height = dragger.minHeight; + + if (range.x > 0) { + if (range.y > 0) { + directive = "se"; + } else { + directive = "ne"; + top -= height; + } + } else { + if (range.y > 0) { + directive = "sw"; + left -= width; + } else { + directive = "nw"; + left -= width; + top -= height; + } + } + + // Show the dragger if is hidden + if (!this.cropped) { + this.cropped = TRUE; + this.$dragger.removeClass(CLASS_HIDDEN); + } + } + + break; + + // No default + } + + if (renderable) { + dragger.width = width; + dragger.height = height; + dragger.left = left; + dragger.top = top; + this.directive = directive; + + this.renderDragger(); + } + + // Override + this.startX = this.endX; + this.startY = this.endY; + } + }; + + // Use the string compressor: Strmin (https://github.com/fengyuanchen/strmin) + Cropper.TEMPLATE = (function (source, words) { + words = words.split(","); + return source.replace(/\d+/g, function (i) { + return words[i]; + }); + })('<0 6="5-container"><0 6="5-canvas"><0 6="5-dragger"><1 6="5-viewer"><1 6="5-8 8-h"><1 6="5-8 8-v"><1 6="5-face" 3-2="all"><1 6="5-7 7-e" 3-2="e"><1 6="5-7 7-n" 3-2="n"><1 6="5-7 7-w" 3-2="w"><1 6="5-7 7-s" 3-2="s"><1 6="5-4 4-e" 3-2="e"><1 6="5-4 4-n" 3-2="n"><1 6="5-4 4-w" 3-2="w"><1 6="5-4 4-s" 3-2="s"><1 6="5-4 4-ne" 3-2="ne"><1 6="5-4 4-nw" 3-2="nw"><1 6="5-4 4-sw" 3-2="sw"><1 6="5-4 4-se" 3-2="se">', "div,span,directive,data,point,cropper,class,line,dashed"); + + /* Template source: +
+
+
+ + + + + + + + + + + + + + + + +
+
+ */ + + Cropper.DEFAULTS = { + // Basic + aspectRatio: "auto", + autoCropArea: 0.8, // 80% + data: { + // x: 0, + // y: 0, + // width: 300, + // height: 150 + }, + done: $.noop, + preview: "", + + // Toggles + multiple: FALSE, + autoCrop: TRUE, + dragCrop: TRUE, + dashed: TRUE, + modal: TRUE, + movable: TRUE, + resizable: TRUE, + zoomable: TRUE, + rotatable: TRUE, + checkImageOrigin: TRUE, + + // Dimensions + minWidth: 0, + minHeight: 0, + maxWidth: INFINITY, + maxHeight: INFINITY, + + // Events + build: NULL, + built: NULL, + dragstart: NULL, + dragmove: NULL, + dragend: NULL + }; + + Cropper.setDefaults = function (options) { + $.extend(Cropper.DEFAULTS, options); + }; + + // Save the other cropper + Cropper.other = $.fn.cropper; + + // Register as jQuery plugin + $.fn.cropper = function (options) { + var args = toArray(arguments, 1), + result; + + this.each(function () { + var $this = $(this), + data = $this.data("cropper"), + fn; + + if (!data) { + $this.data("cropper", (data = new Cropper(this, options))); + } + + if (typeof options === "string" && $.isFunction((fn = data[options]))) { + result = fn.apply(data, args); + } + }); + + return (typeof result !== STRING_UNDEFINED ? result : this); + }; + + $.fn.cropper.Constructor = Cropper; + $.fn.cropper.setDefaults = Cropper.setDefaults; + + // No conflict + $.fn.cropper.noConflict = function () { + $.fn.cropper = Cropper.other; + return this; + }; +}); diff --git a/assets/js/um-functions.js b/assets/js/um-functions.js index cd5ad3a1..44cc2b3d 100644 --- a/assets/js/um-functions.js +++ b/assets/js/um-functions.js @@ -1,11 +1,3 @@ -function initCrop_UM() { - - jQuery('.um-single-image-preview.crop img').imgAreaSelect({ - handles: true, - }); - -} - function initImageUpload_UM( trigger ) { if (trigger.data('upload_help_text')){ @@ -43,7 +35,7 @@ function initImageUpload_UM( trigger ) { showAbort: false, showDone: false, showFileCounter: false, - showStatusAfterSuccess: false, + showStatusAfterSuccess: true, onSubmit:function(files){ trigger.parents('.um-modal-body').find('.um-error-block').remove(); @@ -57,24 +49,114 @@ function initImageUpload_UM( trigger ) { if (data.error && data.error != '') { trigger.parents('.um-modal-body').append('
'+data.error+'
'); + trigger.parents('.um-modal-body').find('.upload-statusbar').hide(0); + um_modal_responsive(); } else { jQuery.each( data, function(key, value) { - trigger.parents('.um-modal-body').find('.um-single-image-preview img').attr('src', value); + + var img_id = trigger.parents('.um-modal-body').find('.um-single-image-preview img'); + var img_id_h = trigger.parents('.um-modal-body').find('.um-single-image-preview'); + + img_id.attr("src", value); + img_id.load(function(){ + + trigger.parents('.um-modal-body').find('.um-modal-btn.um-finish-upload.disabled').removeClass('disabled'); + trigger.parents('.um-modal-body').find('.ajax-upload-dragdrop,.upload-statusbar').hide(0); + img_id_h.show(0); + um_modal_responsive(); + + }); + }); - - trigger.parents('.um-modal-body').find('.ajax-upload-dragdrop').fadeOut( function () { - trigger.parents('.um-modal-body').find('.um-single-image-preview').show(); - trigger.parents('.um-modal-body').find('.um-modal-btn.um-finish-upload.disabled').removeClass('disabled'); - um_modal_responsive(); - } ); - - initCrop_UM(); - + } } }); +} + +function initFileUpload_UM( trigger ) { + + if (trigger.data('upload_help_text')){ + upload_help_text = '' + trigger.data('upload_help_text') + ''; + } else { + upload_help_text = ''; + } + + if ( trigger.data('icon') ) { + icon = ''; + } else { + icon = ''; + } + + if ( trigger.data('upload_text') ) { + upload_text = '' + trigger.data('upload_text') + ''; + } else { + upload_text = ''; + } + + trigger.uploadFile({ + url: ultimatemember_file_upload_url, + method: "POST", + multiple: false, + formData: {key: trigger.data('key'), set_id: trigger.data('set_id'), set_mode: trigger.data('set_mode') }, + fileName: trigger.data('key'), + allowedTypes: trigger.data('allowed_types'), + maxFileSize: trigger.data('max_size'), + dragDropStr: icon + upload_text + upload_help_text, + sizeErrorStr: trigger.data('max_size_error'), + extErrorStr: trigger.data('extension_error'), + maxFileCountErrorStr: trigger.data('max_files_error'), + maxFileCount: 1, + showDelete: false, + showAbort: false, + showDone: false, + showFileCounter: false, + showStatusAfterSuccess: true, + onSubmit:function(files){ + + trigger.parents('.um-modal-body').find('.um-error-block').remove(); + + }, + onSuccess:function(files,data,xhr){ + + trigger.selectedFiles = 0; + + data = jQuery.parseJSON(data); + if (data.error && data.error != '') { + + trigger.parents('.um-modal-body').append('
'+data.error+'
'); + trigger.parents('.um-modal-body').find('.upload-statusbar').hide(0); + um_modal_responsive(); + + } else { + + jQuery.each( data, function(key, value) { + + trigger.parents('.um-modal-body').find('.um-modal-btn.um-finish-upload.disabled').removeClass('disabled'); + trigger.parents('.um-modal-body').find('.ajax-upload-dragdrop,.upload-statusbar').hide(0); + trigger.parents('.um-modal-body').find('.um-single-file-preview').show(0); + + if (key == 'icon') { + trigger.parents('.um-modal-body').find('.um-single-fileinfo i').removeClass().addClass(value); + } else if ( key == 'icon_bg' ) { + trigger.parents('.um-modal-body').find('.um-single-fileinfo span.icon').css({'background-color' : value } ); + } else if ( key == 'filename' ) { + trigger.parents('.um-modal-body').find('.um-single-fileinfo span.filename').html(value); + } else { + trigger.parents('.um-modal-body').find('.um-single-fileinfo a').attr('href', value); + } + + }); + + um_modal_responsive(); + + } + + } + }); + } \ No newline at end of file diff --git a/assets/js/um-modal.js b/assets/js/um-modal.js index bcfb6fba..3c01d6b9 100644 --- a/assets/js/um-modal.js +++ b/assets/js/um-modal.js @@ -1,10 +1,103 @@ +function initCrop_UM() { + + // only when a crop image is in view + var target_img = jQuery('.um-modal:visible .um-single-image-preview.crop img'); + var target_img_parent = jQuery('.um-modal:visible .um-single-image-preview.crop'); + + var crop_data = target_img.parent().attr('data-crop'); + var min_width = target_img.parent().attr('data-min_width'); + var min_height = target_img.parent().attr('data-min_height'); + var ratio = target_img.parent().attr('data-ratio'); + + // custom defined ratio maybe + if ( jQuery('.um-modal').find('#um_upload_single').attr('data-ratio') ) { + var ratio = jQuery('.um-modal').find('#um_upload_single').attr('data-ratio'); + var ratio_split = ratio.split(':'); + var ratio = ratio_split[0]; + } + + if ( target_img.length ) { + + if ( target_img.attr('src') != '' ) { + + var max_height = jQuery(window).height() - ( jQuery('.um-modal-footer a').height() + 20 ) - 50 - ( jQuery('.um-modal-header:visible').height() ); + + target_img.css({'height' : 'auto'}); + target_img_parent.css({'height' : 'auto'}); + + if ( jQuery(window).height() <= 400 ) { + target_img_parent.css({ 'height': max_height +'px', 'max-height' : max_height + 'px' }); + target_img.css({ 'height' : 'auto' }); + } else { + target_img.css({ 'height': 'auto', 'max-height' : max_height + 'px' }); + target_img_parent.css({ 'height': target_img.height(), 'max-height' : max_height + 'px' }); + } + + if ( crop_data == 'square' ) { + + var opts = { + minWidth: min_width, + minHeight: min_height, + dragCrop: false, + aspectRatio: 1.0, + zoomable: false, + rotatable: false, + dashed: false, + done: function(data) { + target_img.parent().attr('data-coord', Math.round(data.x) + ',' + Math.round(data.y) + ',' + Math.round(data.width) + ',' + Math.round(data.height) ); + } + }; + + } else if ( crop_data == 'cover' ) { + + var opts = { + minWidth: min_width, + minHeight: Math.round( min_width / ratio ), + dragCrop: false, + aspectRatio: ratio, + zoomable: false, + rotatable: false, + dashed: false, + done: function(data) { + target_img.parent().attr('data-coord', Math.round(data.x) + ',' + Math.round(data.y) + ',' + Math.round(data.width) + ',' + Math.round(data.height) ); + } + }; + + } else { + + var opts = { + dragCrop: true, + aspectRatio: "auto", + zoomable: false, + rotatable: false, + dashed: false, + done: function(data) { + target_img.parent().attr('data-coord', Math.round(data.x) + ',' + Math.round(data.y) + ',' + Math.round(data.width) + ',' + Math.round(data.height) ); + } + }; + + } + + target_img.cropper( opts ); + + } + } + +} + function um_new_modal( id, size ){ var modal = jQuery('body').find('.um-modal-overlay'); jQuery('.tipsy').hide(); + jQuery('.um-dropdown').hide(); + jQuery('body,html').css("overflow", "hidden"); + + jQuery(document).bind("touchmove", function(e){e.preventDefault();}); + jQuery('.um-modal').on('touchmove', function(e){e.stopPropagation();}); + jQuery('body').append('
'); jQuery('#' + id).prependTo('.um-modal'); @@ -14,6 +107,8 @@ function um_new_modal( id, size ){ um_modal_size( size ); initImageUpload_UM( jQuery('.um-modal:visible').find('.um-single-image-upload') ); + + initFileUpload_UM( jQuery('.um-modal:visible').find('.um-single-file-upload') ); um_modal_responsive(); @@ -22,13 +117,9 @@ function um_new_modal( id, size ){ function um_modal_responsive() { var modal = jQuery('.um-modal:visible'); - + if ( modal.length ) { - - var window_height_diff = jQuery(window).height() - modal.innerHeight(); - - var half_gap = window_height_diff / 2 + 'px'; - + var element_width = jQuery(window).width(); modal.removeClass('uimob340'); @@ -37,35 +128,49 @@ function um_modal_responsive() { if ( element_width <= 340 ) { modal.addClass('uimob340'); + initCrop_UM(); modal.animate({ 'bottom' : 0 }, 300); } else if ( element_width <= 500 ) { modal.addClass('uimob500'); + initCrop_UM(); modal.animate({ 'bottom' : 0 }, 300); } else if ( element_width <= 800 ) { + initCrop_UM(); + var half_gap = ( jQuery(window).height() - modal.innerHeight() ) / 2 + 'px'; modal.animate({ 'bottom' : half_gap }, 300); } else if ( element_width <= 960 ) { + initCrop_UM(); + var half_gap = ( jQuery(window).height() - modal.innerHeight() ) / 2 + 'px'; modal.animate({ 'bottom' : half_gap }, 300); } else if ( element_width > 960 ) { + initCrop_UM(); + var half_gap = ( jQuery(window).height() - modal.innerHeight() ) / 2 + 'px'; modal.animate({ 'bottom' : half_gap }, 300); } - + } } function um_remove_modal(){ - jQuery('.um-single-image-preview.crop img').imgAreaSelect({ hide: true }); + + jQuery('.um-single-image-preview img').cropper("destroy"); + jQuery('body,html').css("overflow", "auto"); + + jQuery(document).unbind('touchmove'); + jQuery('.um-modal div[id^="um_"]').hide().appendTo('body'); jQuery('.um-modal,.um-modal-overlay').remove(); + } function um_modal_size( aclass ) { @@ -97,6 +202,25 @@ jQuery(document).ready(function() { return false; }); + /** + remove uploaded file + **/ + jQuery(document).on('click', '.um-modal .um-single-file-preview a.cancel', function(e){ + e.preventDefault(); + + var parent = jQuery(this).parents('.um-modal-body'); + + parent.find('.um-single-file-preview').hide(); + + parent.find('.ajax-upload-dragdrop').show(); + + parent.find('.um-modal-btn.um-finish-upload').addClass('disabled'); + + um_modal_responsive(); + + return false; + }); + /** remove uploaded image **/ @@ -105,6 +229,10 @@ jQuery(document).ready(function() { var parent = jQuery(this).parents('.um-modal-body'); + parent.find('.um-single-image-preview img').cropper("destroy"); + + parent.find('.um-single-image-preview img').attr('src', ''); + parent.find('.um-single-image-preview').hide(); parent.find('.ajax-upload-dragdrop').show(); @@ -117,19 +245,80 @@ jQuery(document).ready(function() { }); /** - finish upload + finish file upload **/ - jQuery(document).on('click', '.um-finish-upload', function(){ + jQuery(document).on('click', '.um-finish-upload.file', function(){ var key = jQuery(this).attr('data-key'); - - var src = jQuery(this).parents('.um-modal-body').find('.um-single-image-preview img').attr('src'); - - jQuery('.um-single-image-preview[data-key='+key+']').fadeIn().find('img').attr('src', src); + var preview = jQuery(this).parents('.um-modal-body').find('.um-single-file-preview').html(); um_remove_modal(); - jQuery('.um-single-image-preview[data-key='+key+']').parents('.um-field').find('.um-btn-auto-width').html('Change/Modify Photo'); + jQuery('.um-single-file-preview[data-key='+key+']').fadeIn().html( preview ); + + jQuery('.um-single-file-preview[data-key='+key+']').parents('.um-field').find('.um-btn-auto-width').html( jQuery(this).attr('data-change') ); + + }); + + /** + finish image upload + **/ + jQuery(document).on('click', '.um-finish-upload.image', function(){ + + var elem = jQuery(this); + var key = jQuery(this).attr('data-key'); + var img_c = jQuery(this).parents('.um-modal-body').find('.um-single-image-preview'); + var src = img_c.find('img').attr('src'); + var coord = img_c.attr('data-coord'); + + if ( jQuery(this).parents('#um_upload_single').attr('data-user_id') ) { + var user_id = jQuery(this).parents('#um_upload_single').attr('data-user_id'); + } else { + var user_id = 0; + } + + if ( coord ) { // crop image first before processing + + jQuery(this).html( jQuery(this).attr('data-processing') ).addClass('disabled'); + + jQuery.ajax({ + url: ultimatemember_ajax_url, + type: 'POST', + data: { + action: 'ultimatemember_resize_image', + src : src, + coord : coord, + user_id : user_id, + key: key, + }, + success: function(data){ + + d = new Date(); + + if ( key == 'profile_photo') { + jQuery('.um-profile-photo-img img').attr('src', data + "?"+d.getTime()); + } + + if ( key == 'cover_photo') { + jQuery('.um-cover-e').empty().html(''); + jQuery('.um-cover-overlay').show(); + } + + jQuery('.um-single-image-preview[data-key='+key+']').fadeIn().find('img').attr('src', data + "?"+d.getTime()); + um_remove_modal(); + jQuery('.um-single-image-preview[data-key='+key+']').parents('.um-field').find('.um-btn-auto-width').html( elem.attr('data-change') ); + + } + }); + + } else { + + d = new Date(); + jQuery('.um-single-image-preview[data-key='+key+']').fadeIn().find('img').attr('src', src + "?"+d.getTime()); + um_remove_modal(); + jQuery('.um-single-image-preview[data-key='+key+']').parents('.um-field').find('.um-btn-auto-width').html( elem.attr('data-change') ); + + } }); @@ -148,6 +337,19 @@ jQuery(document).ready(function() { if ( jQuery(this).data('modal-copy') ) { jQuery('#' + modal_id).html( jQuery(this).parents('.um-field').find('.um-modal-hidden-content').html() ); + + if ( jQuery(this).parents('.um-profile-photo').attr('data-user_id') ) { + jQuery('#' + modal_id).attr('data-user_id', jQuery(this).parents('.um-profile-photo').attr('data-user_id') ); + } + + if ( jQuery(this).parents('.um-cover').attr('data-ratio') ) { + jQuery('#' + modal_id).attr('data-ratio', jQuery(this).parents('.um-cover').attr('data-ratio') ); + } + + if ( jQuery(this).parents('.um-cover').attr('data-user_id') ) { + jQuery('#' + modal_id).attr('data-user_id', jQuery(this).parents('.um-cover').attr('data-user_id') ); + } + um_new_modal( modal_id, size ); } else { um_new_modal( modal_id, size ); diff --git a/assets/js/um-profile.js b/assets/js/um-profile.js index 3a53b6e2..53fe332c 100644 --- a/assets/js/um-profile.js +++ b/assets/js/um-profile.js @@ -8,5 +8,57 @@ jQuery(document).ready(function() { return false; }); + + /* No need to allow # */ + jQuery(document).on('click', '.um-cover a', function(e){ + e.preventDefault(); + return false; + }); + + /* Reset profile photo */ + jQuery(document).on('click', '.um-reset-profile-photo', function(e){ + + jQuery('.um-profile-photo-img img').attr('src', jQuery(this).attr('data-default_src') ); + + user_id = jQuery(this).attr('data-user_id'); + metakey = 'profile_photo'; + + jQuery.ajax({ + url: ultimatemember_ajax_url, + type: 'post', + data: { + action: 'ultimatemember_delete_profile_photo', + metakey: metakey, + user_id: user_id + } + }); + + }); + + /* Reset cover photo */ + jQuery(document).on('click', '.um-reset-cover-photo', function(e){ + + jQuery('.um-cover-overlay').hide(); + + jQuery('.um-cover-e').html(''); + + jQuery('.um-dropdown').hide(); + + um_responsive(); + + user_id = jQuery(this).attr('data-user_id'); + metakey = 'cover_photo'; + + jQuery.ajax({ + url: ultimatemember_ajax_url, + type: 'post', + data: { + action: 'ultimatemember_delete_cover_photo', + metakey: metakey, + user_id: user_id + } + }); + + }); }); \ No newline at end of file diff --git a/assets/js/um-responsive.js b/assets/js/um-responsive.js index f06c4bd1..3ab010c0 100644 --- a/assets/js/um-responsive.js +++ b/assets/js/um-responsive.js @@ -1,5 +1,57 @@ -function um_responsive(){ +function UM_domenus(){ + jQuery('.um-dropdown').each(function(){ + + var menu = jQuery(this); + var element = jQuery(this).attr('data-element'); + var position = jQuery(this).attr('data-position'); + + jQuery(element).addClass('um-trigger-menu-on-'+menu.attr('data-trigger')); + + if ( position == 'bc' ){ + + if ( 200 > jQuery(element).find('img').width() ) { + left_p = ( ( jQuery(element).width() - jQuery(element).find('img').width() ) / 2 ) + ( ( jQuery(element).find('img').width() - 200 ) / 2 ); + } else { + left_p = ( ( jQuery(element).width() - jQuery(element).find('img').width() ) / 2 ); + } + + top_ = parseInt( jQuery(element).find('a').css('top') ); + + if ( top_ ) { + top_p = jQuery(element).find('img').height() + 4 + top_; + left_gap = 4; + } else { + top_p = jQuery(element).find('img').height() + 4; + left_gap = 0; + } + + if ( top_p == 4 && element == 'div.um-cover' ) { + top_p = jQuery(element).height() / 2 + ( menu.height() / 2 ); + } + + menu.css({ + 'top' : top_p, + 'width': 200, + 'left': left_p + left_gap, + 'text-align' : 'center', + }); + + menu.find('.um-dropdown-arr').find('i').addClass('um-icon-arrow-sans-up'); + + menu.find('.um-dropdown-arr').css({ + 'top' : '-18px', + 'left' : ( menu.width() / 2 ) - 12, + }); + + } + }); + +} + +function um_responsive(){ + + // responsive um shortcode jQuery('.um').each(function(){ element_width = jQuery(this).width(); @@ -48,19 +100,39 @@ function um_responsive(){ jQuery(this).removeClass('uimob960'); } - - jQuery('.um-members').each(function(){ - UM_Member_Grid( jQuery(this) ); - }); + // account nav if ( jQuery('.um-account-nav').length > 0 && jQuery('.um-account-side').is(':visible') && jQuery('.um-account-tab:visible').length == 0 ) { jQuery('.um-account-side li a.current').trigger('click'); } + // show jQuery(this).css('opacity',1); }); + // responsive cover + jQuery('.um-cover, .um-member-cover').each(function(){ + + var elem = jQuery(this); + var ratio = elem.data('ratio'); + var width = elem.width(); + var ratios = ratio.split(':'); + + calcHeight = Math.round( width / ratios[0] ) + 'px'; + elem.height( calcHeight ); + elem.find('.um-cover-add').height( calcHeight ); + + }); + + // members directory + jQuery('.um-members').each(function(){ + UM_Member_Grid( jQuery(this) ); + }); + + // menus + UM_domenus(); + } /* Run only when window is loaded */ @@ -74,6 +146,8 @@ jQuery(window).load(function() { /* Run only when window is resized */ jQuery(window).resize(function() { + jQuery('.um-single-image-preview.crop:visible img').cropper("destroy"); + um_responsive(); um_modal_responsive(); diff --git a/assets/js/um-scripts.js b/assets/js/um-scripts.js index 581b8bf0..be100634 100644 --- a/assets/js/um-scripts.js +++ b/assets/js/um-scripts.js @@ -1,12 +1,40 @@ jQuery(document).ready(function() { - /* Tooltips */ + /* dropdown menu links */ + jQuery(document).on('click', '.um-dropdown a', function(e){ + e.preventDefault(); + return false; + }); + + /* trigger dropdown on click */ + jQuery(document).on('click', '.um-trigger-menu-on-click', function(e){ + e.preventDefault(); + jQuery('.um-dropdown').hide(); + menu = jQuery(this).find('.um-dropdown'); + menu.show(); + return false; + }); + + /* hide dropdown */ + jQuery(document).on('click', '.um-dropdown-hide', function(e){ + menu = jQuery(this).parents('.um-dropdown'); + menu.hide(); + }); + + /* manual triggers */ + jQuery(document).on('click', 'a.um-manual-trigger', function(){ + var child = jQuery(this).attr('data-child'); + var parent = jQuery(this).attr('data-parent'); + jQuery(this).parents( parent ).find( child ).trigger('click'); + }); + + /* tooltips */ jQuery('.um-tip-n').tipsy({gravity: 'n', opacity: 1, live: true, offset: 3 }); jQuery('.um-tip-w').tipsy({gravity: 'w', opacity: 1, live: true, offset: 3 }); jQuery('.um-tip-e').tipsy({gravity: 'e', opacity: 1, live: true, offset: 3 }); jQuery('.um-tip-s').tipsy({gravity: 's', opacity: 1, live: true, offset: 3 }); - /* Custom Radio Buttons */ + /* custom radio buttons */ jQuery('.um-field-radio').mouseenter(function(){ if (!jQuery(this).hasClass('active')) { jQuery(this).find('i').removeClass().addClass('um-icon-check-3'); @@ -26,7 +54,7 @@ jQuery(document).ready(function() { this_field.find('i').removeClass('um-icon-blank').addClass('um-icon-check-3'); }); - /* Custom Checkbox Buttons */ + /* custom checkbox buttons */ jQuery('.um-field-checkbox').mouseenter(function(){ if (!jQuery(this).hasClass('active')) { jQuery(this).find('i').removeClass().addClass('um-icon-cross'); @@ -51,7 +79,7 @@ jQuery(document).ready(function() { }); - /* Date picker */ + /* datepicker */ jQuery('.um-datepicker').pickadate({ min: [1900,1,1], max: true, @@ -60,7 +88,7 @@ jQuery(document).ready(function() { hiddenSuffix: '__true' }); - /* Time picker */ + /* timepicker */ jQuery('.um-timepicker').pickatime({ formatSubmit: 'HH:i', hiddenSuffix: '__true' @@ -95,108 +123,18 @@ jQuery(document).ready(function() { /* remove uploaded image */ jQuery(document).on('click', '.um .um-single-image-preview a.cancel', function(e){ e.preventDefault(); - var parent = jQuery(this).parents('.um-field'); - parent.find('.um-single-image-preview').hide(); - parent.find('.um-btn-auto-width').html('Upload'); - return false; }); - /* File Upload */ - jQuery(".um-single-file-upload").each(function(){ - - var trigger = jQuery(this); - - if (trigger.data('upload_help_text')){ - upload_help_text = '' + trigger.data('upload_help_text') + ''; - } else { - upload_help_text = ''; - } - - if ( trigger.data('icon') ) { - icon = ''; - } else { - icon = ''; - } - - if ( trigger.data('upload_text') ) { - upload_text = '' + trigger.data('upload_text') + ''; - } else { - upload_text = ''; - } - - trigger.uploadFile({ - url: ultimatemember_file_upload_url, - method: "POST", - multiple: false, - formData: {key: trigger.data('key'), set_id: trigger.data('set_id'), set_mode: trigger.data('set_mode') }, - fileName: trigger.data('key'), - allowedTypes: trigger.data('allowed_types'), - maxFileSize: trigger.data('max_size'), - dragDropStr: icon + upload_text + upload_help_text, - sizeErrorStr: trigger.data('max_size_error'), - extErrorStr: trigger.data('extension_error'), - maxFileCountErrorStr: trigger.data('max_files_error'), - maxFileCount: 1, - showDelete: false, - showAbort: false, - showDone: false, - showFileCounter: false, - showStatusAfterSuccess: false, - onSubmit:function(files){ - - trigger.parents('.um-field').find('.um-error-block').remove(); - - }, - onSuccess:function(files,data,xhr){ - - trigger.selectedFiles = 0; - - data = jQuery.parseJSON(data); - if (data.error && data.error != '') { - - trigger.parents('.um-field').append('
'+data.error+'
'); - - } else { - - trigger.parents('.um-field').find('.ajax-upload-dragdrop').fadeOut( function() { - trigger.parents('.um-field').find('.um-single-file-preview').fadeIn(); - }); - - jQuery.each( data, function(key, value) { - - if (key == 'icon') { - trigger.parents('.um-field').find('.um-single-fileinfo i').removeClass().addClass(value); - } else if ( key == 'icon_bg' ) { - trigger.parents('.um-field').find('.um-single-fileinfo span.icon').css({'background-color' : value } ); - } else if ( key == 'filename' ) { - trigger.parents('.um-field').find('.um-single-fileinfo span.filename').html(value); - } else { - trigger.parents('.um-field').find('.um-single-fileinfo a').attr('href', value); - } - - }); - - } - - } - }); - - }); - - /* Remove a single file upload */ - jQuery(document).on('click', '.um-single-file-preview a.cancel', function(e){ + /* remove uploaded file */ + jQuery(document).on('click', '.um .um-single-file-preview a.cancel', function(e){ e.preventDefault(); - - var trigger = jQuery(this).parents('.um-field').find('.um-single-file-upload'); - - trigger.parents('.um-field').find('.um-single-file-preview').fadeOut(function(){ - trigger.parents('.um-field').find('.ajax-upload-dragdrop').fadeIn(); - }); - + var parent = jQuery(this).parents('.um-field'); + parent.find('.um-single-file-preview').hide(); + parent.find('.um-btn-auto-width').html('Upload'); return false; }); diff --git a/core/lib/mobiledetect/Mobile_Detect.php b/core/lib/mobiledetect/Mobile_Detect.php new file mode 100644 index 00000000..3a82c296 --- /dev/null +++ b/core/lib/mobiledetect/Mobile_Detect.php @@ -0,0 +1,1341 @@ + + * Nick Ilyin + * + * Original author: Victor Stanciu + * + * @license Code and contributions have 'MIT License' + * More details: https://github.com/serbanghita/Mobile-Detect/blob/master/LICENSE.txt + * + * @link Homepage: http://mobiledetect.net + * GitHub Repo: https://github.com/serbanghita/Mobile-Detect + * Google Code: http://code.google.com/p/php-mobile-detect/ + * README: https://github.com/serbanghita/Mobile-Detect/blob/master/README.md + * HOWTO: https://github.com/serbanghita/Mobile-Detect/wiki/Code-examples + * + * @version 2.8.11 + */ + +class Mobile_Detect +{ + /** + * Mobile detection type. + * + * @deprecated since version 2.6.9 + */ + const DETECTION_TYPE_MOBILE = 'mobile'; + + /** + * Extended detection type. + * + * @deprecated since version 2.6.9 + */ + const DETECTION_TYPE_EXTENDED = 'extended'; + + /** + * A frequently used regular expression to extract version #s. + * + * @deprecated since version 2.6.9 + */ + const VER = '([\w._\+]+)'; + + /** + * Top-level device. + */ + const MOBILE_GRADE_A = 'A'; + + /** + * Mid-level device. + */ + const MOBILE_GRADE_B = 'B'; + + /** + * Low-level device. + */ + const MOBILE_GRADE_C = 'C'; + + /** + * Stores the version number of the current release. + */ + const VERSION = '2.8.11'; + + /** + * A type for the version() method indicating a string return value. + */ + const VERSION_TYPE_STRING = 'text'; + + /** + * A type for the version() method indicating a float return value. + */ + const VERSION_TYPE_FLOAT = 'float'; + + /** + * The User-Agent HTTP header is stored in here. + * @var string + */ + protected $userAgent = null; + + /** + * HTTP headers in the PHP-flavor. So HTTP_USER_AGENT and SERVER_SOFTWARE. + * @var array + */ + protected $httpHeaders = array(); + + /** + * The matching Regex. + * This is good for debug. + * @var string + */ + protected $matchingRegex = null; + + /** + * The matches extracted from the regex expression. + * This is good for debug. + * @var string + */ + protected $matchesArray = null; + + /** + * The detection type, using self::DETECTION_TYPE_MOBILE or self::DETECTION_TYPE_EXTENDED. + * + * @deprecated since version 2.6.9 + * + * @var string + */ + protected $detectionType = self::DETECTION_TYPE_MOBILE; + + /** + * HTTP headers that trigger the 'isMobile' detection + * to be true. + * + * @var array + */ + protected static $mobileHeaders = array( + + 'HTTP_ACCEPT' => array('matches' => array( + // Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/ + 'application/x-obml2d', + // BlackBerry devices. + 'application/vnd.rim.html', + 'text/vnd.wap.wml', + 'application/vnd.wap.xhtml+xml' + )), + 'HTTP_X_WAP_PROFILE' => null, + 'HTTP_X_WAP_CLIENTID' => null, + 'HTTP_WAP_CONNECTION' => null, + 'HTTP_PROFILE' => null, + // Reported by Opera on Nokia devices (eg. C3). + 'HTTP_X_OPERAMINI_PHONE_UA' => null, + 'HTTP_X_NOKIA_GATEWAY_ID' => null, + 'HTTP_X_ORANGE_ID' => null, + 'HTTP_X_VODAFONE_3GPDPCONTEXT' => null, + 'HTTP_X_HUAWEI_USERID' => null, + // Reported by Windows Smartphones. + 'HTTP_UA_OS' => null, + // Reported by Verizon, Vodafone proxy system. + 'HTTP_X_MOBILE_GATEWAY' => null, + // Seen this on HTC Sensation. SensationXE_Beats_Z715e. + 'HTTP_X_ATT_DEVICEID' => null, + // Seen this on a HTC. + 'HTTP_UA_CPU' => array('matches' => array('ARM')), + ); + + /** + * List of mobile devices (phones). + * + * @var array + */ + protected static $phoneDevices = array( + 'iPhone' => '\biPhone\b|\biPod\b', // |\biTunes + 'BlackBerry' => 'BlackBerry|\bBB10\b|rim[0-9]+', + 'HTC' => 'HTC|HTC.*(Sensation|Evo|Vision|Explorer|6800|8100|8900|A7272|S510e|C110e|Legend|Desire|T8282)|APX515CKT|Qtek9090|APA9292KT|HD_mini|Sensation.*Z710e|PG86100|Z715e|Desire.*(A8181|HD)|ADR6200|ADR6400L|ADR6425|001HT|Inspire 4G|Android.*\bEVO\b|T-Mobile G1|Z520m', + 'Nexus' => 'Nexus One|Nexus S|Galaxy.*Nexus|Android.*Nexus.*Mobile|Nexus 4|Nexus 5|Nexus 6', + // @todo: Is 'Dell Streak' a tablet or a phone? ;) + 'Dell' => 'Dell.*Streak|Dell.*Aero|Dell.*Venue|DELL.*Venue Pro|Dell Flash|Dell Smoke|Dell Mini 3iX|XCD28|XCD35|\b001DL\b|\b101DL\b|\bGS01\b', + 'Motorola' => 'Motorola|DROIDX|DROID BIONIC|\bDroid\b.*Build|Android.*Xoom|HRI39|MOT-|A1260|A1680|A555|A853|A855|A953|A955|A956|Motorola.*ELECTRIFY|Motorola.*i1|i867|i940|MB200|MB300|MB501|MB502|MB508|MB511|MB520|MB525|MB526|MB611|MB612|MB632|MB810|MB855|MB860|MB861|MB865|MB870|ME501|ME502|ME511|ME525|ME600|ME632|ME722|ME811|ME860|ME863|ME865|MT620|MT710|MT716|MT720|MT810|MT870|MT917|Motorola.*TITANIUM|WX435|WX445|XT300|XT301|XT311|XT316|XT317|XT319|XT320|XT390|XT502|XT530|XT531|XT532|XT535|XT603|XT610|XT611|XT615|XT681|XT701|XT702|XT711|XT720|XT800|XT806|XT860|XT862|XT875|XT882|XT883|XT894|XT901|XT907|XT909|XT910|XT912|XT928|XT926|XT915|XT919|XT925', + 'Samsung' => 'Samsung|SGH-I337|BGT-S5230|GT-B2100|GT-B2700|GT-B2710|GT-B3210|GT-B3310|GT-B3410|GT-B3730|GT-B3740|GT-B5510|GT-B5512|GT-B5722|GT-B6520|GT-B7300|GT-B7320|GT-B7330|GT-B7350|GT-B7510|GT-B7722|GT-B7800|GT-C3010|GT-C3011|GT-C3060|GT-C3200|GT-C3212|GT-C3212I|GT-C3262|GT-C3222|GT-C3300|GT-C3300K|GT-C3303|GT-C3303K|GT-C3310|GT-C3322|GT-C3330|GT-C3350|GT-C3500|GT-C3510|GT-C3530|GT-C3630|GT-C3780|GT-C5010|GT-C5212|GT-C6620|GT-C6625|GT-C6712|GT-E1050|GT-E1070|GT-E1075|GT-E1080|GT-E1081|GT-E1085|GT-E1087|GT-E1100|GT-E1107|GT-E1110|GT-E1120|GT-E1125|GT-E1130|GT-E1160|GT-E1170|GT-E1175|GT-E1180|GT-E1182|GT-E1200|GT-E1210|GT-E1225|GT-E1230|GT-E1390|GT-E2100|GT-E2120|GT-E2121|GT-E2152|GT-E2220|GT-E2222|GT-E2230|GT-E2232|GT-E2250|GT-E2370|GT-E2550|GT-E2652|GT-E3210|GT-E3213|GT-I5500|GT-I5503|GT-I5700|GT-I5800|GT-I5801|GT-I6410|GT-I6420|GT-I7110|GT-I7410|GT-I7500|GT-I8000|GT-I8150|GT-I8160|GT-I8190|GT-I8320|GT-I8330|GT-I8350|GT-I8530|GT-I8700|GT-I8703|GT-I8910|GT-I9000|GT-I9001|GT-I9003|GT-I9010|GT-I9020|GT-I9023|GT-I9070|GT-I9082|GT-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|GT-I9305|GT-I9500|GT-I9505|GT-M3510|GT-M5650|GT-M7500|GT-M7600|GT-M7603|GT-M8800|GT-M8910|GT-N7000|GT-S3110|GT-S3310|GT-S3350|GT-S3353|GT-S3370|GT-S3650|GT-S3653|GT-S3770|GT-S3850|GT-S5210|GT-S5220|GT-S5229|GT-S5230|GT-S5233|GT-S5250|GT-S5253|GT-S5260|GT-S5263|GT-S5270|GT-S5300|GT-S5330|GT-S5350|GT-S5360|GT-S5363|GT-S5369|GT-S5380|GT-S5380D|GT-S5560|GT-S5570|GT-S5600|GT-S5603|GT-S5610|GT-S5620|GT-S5660|GT-S5670|GT-S5690|GT-S5750|GT-S5780|GT-S5830|GT-S5839|GT-S6102|GT-S6500|GT-S7070|GT-S7200|GT-S7220|GT-S7230|GT-S7233|GT-S7250|GT-S7500|GT-S7530|GT-S7550|GT-S7562|GT-S7710|GT-S8000|GT-S8003|GT-S8500|GT-S8530|GT-S8600|SCH-A310|SCH-A530|SCH-A570|SCH-A610|SCH-A630|SCH-A650|SCH-A790|SCH-A795|SCH-A850|SCH-A870|SCH-A890|SCH-A930|SCH-A950|SCH-A970|SCH-A990|SCH-I100|SCH-I110|SCH-I400|SCH-I405|SCH-I500|SCH-I510|SCH-I515|SCH-I600|SCH-I730|SCH-I760|SCH-I770|SCH-I830|SCH-I910|SCH-I920|SCH-I959|SCH-LC11|SCH-N150|SCH-N300|SCH-R100|SCH-R300|SCH-R351|SCH-R400|SCH-R410|SCH-T300|SCH-U310|SCH-U320|SCH-U350|SCH-U360|SCH-U365|SCH-U370|SCH-U380|SCH-U410|SCH-U430|SCH-U450|SCH-U460|SCH-U470|SCH-U490|SCH-U540|SCH-U550|SCH-U620|SCH-U640|SCH-U650|SCH-U660|SCH-U700|SCH-U740|SCH-U750|SCH-U810|SCH-U820|SCH-U900|SCH-U940|SCH-U960|SCS-26UC|SGH-A107|SGH-A117|SGH-A127|SGH-A137|SGH-A157|SGH-A167|SGH-A177|SGH-A187|SGH-A197|SGH-A227|SGH-A237|SGH-A257|SGH-A437|SGH-A517|SGH-A597|SGH-A637|SGH-A657|SGH-A667|SGH-A687|SGH-A697|SGH-A707|SGH-A717|SGH-A727|SGH-A737|SGH-A747|SGH-A767|SGH-A777|SGH-A797|SGH-A817|SGH-A827|SGH-A837|SGH-A847|SGH-A867|SGH-A877|SGH-A887|SGH-A897|SGH-A927|SGH-B100|SGH-B130|SGH-B200|SGH-B220|SGH-C100|SGH-C110|SGH-C120|SGH-C130|SGH-C140|SGH-C160|SGH-C170|SGH-C180|SGH-C200|SGH-C207|SGH-C210|SGH-C225|SGH-C230|SGH-C417|SGH-C450|SGH-D307|SGH-D347|SGH-D357|SGH-D407|SGH-D415|SGH-D780|SGH-D807|SGH-D980|SGH-E105|SGH-E200|SGH-E315|SGH-E316|SGH-E317|SGH-E335|SGH-E590|SGH-E635|SGH-E715|SGH-E890|SGH-F300|SGH-F480|SGH-I200|SGH-I300|SGH-I320|SGH-I550|SGH-I577|SGH-I600|SGH-I607|SGH-I617|SGH-I627|SGH-I637|SGH-I677|SGH-I700|SGH-I717|SGH-I727|SGH-i747M|SGH-I777|SGH-I780|SGH-I827|SGH-I847|SGH-I857|SGH-I896|SGH-I897|SGH-I900|SGH-I907|SGH-I917|SGH-I927|SGH-I937|SGH-I997|SGH-J150|SGH-J200|SGH-L170|SGH-L700|SGH-M110|SGH-M150|SGH-M200|SGH-N105|SGH-N500|SGH-N600|SGH-N620|SGH-N625|SGH-N700|SGH-N710|SGH-P107|SGH-P207|SGH-P300|SGH-P310|SGH-P520|SGH-P735|SGH-P777|SGH-Q105|SGH-R210|SGH-R220|SGH-R225|SGH-S105|SGH-S307|SGH-T109|SGH-T119|SGH-T139|SGH-T209|SGH-T219|SGH-T229|SGH-T239|SGH-T249|SGH-T259|SGH-T309|SGH-T319|SGH-T329|SGH-T339|SGH-T349|SGH-T359|SGH-T369|SGH-T379|SGH-T409|SGH-T429|SGH-T439|SGH-T459|SGH-T469|SGH-T479|SGH-T499|SGH-T509|SGH-T519|SGH-T539|SGH-T559|SGH-T589|SGH-T609|SGH-T619|SGH-T629|SGH-T639|SGH-T659|SGH-T669|SGH-T679|SGH-T709|SGH-T719|SGH-T729|SGH-T739|SGH-T746|SGH-T749|SGH-T759|SGH-T769|SGH-T809|SGH-T819|SGH-T839|SGH-T919|SGH-T929|SGH-T939|SGH-T959|SGH-T989|SGH-U100|SGH-U200|SGH-U800|SGH-V205|SGH-V206|SGH-X100|SGH-X105|SGH-X120|SGH-X140|SGH-X426|SGH-X427|SGH-X475|SGH-X495|SGH-X497|SGH-X507|SGH-X600|SGH-X610|SGH-X620|SGH-X630|SGH-X700|SGH-X820|SGH-X890|SGH-Z130|SGH-Z150|SGH-Z170|SGH-ZX10|SGH-ZX20|SHW-M110|SPH-A120|SPH-A400|SPH-A420|SPH-A460|SPH-A500|SPH-A560|SPH-A600|SPH-A620|SPH-A660|SPH-A700|SPH-A740|SPH-A760|SPH-A790|SPH-A800|SPH-A820|SPH-A840|SPH-A880|SPH-A900|SPH-A940|SPH-A960|SPH-D600|SPH-D700|SPH-D710|SPH-D720|SPH-I300|SPH-I325|SPH-I330|SPH-I350|SPH-I500|SPH-I600|SPH-I700|SPH-L700|SPH-M100|SPH-M220|SPH-M240|SPH-M300|SPH-M305|SPH-M320|SPH-M330|SPH-M350|SPH-M360|SPH-M370|SPH-M380|SPH-M510|SPH-M540|SPH-M550|SPH-M560|SPH-M570|SPH-M580|SPH-M610|SPH-M620|SPH-M630|SPH-M800|SPH-M810|SPH-M850|SPH-M900|SPH-M910|SPH-M920|SPH-M930|SPH-N100|SPH-N200|SPH-N240|SPH-N300|SPH-N400|SPH-Z400|SWC-E100|SCH-i909|GT-N7100|GT-N7105|SCH-I535|SM-N900A|SGH-I317|SGH-T999L|GT-S5360B|GT-I8262|GT-S6802|GT-S6312|GT-S6310|GT-S5312|GT-S5310|GT-I9105|GT-I8510|GT-S6790N|SM-G7105|SM-N9005|GT-S5301|GT-I9295|GT-I9195|SM-C101|GT-S7392|GT-S7560|GT-B7610|GT-I5510|GT-S7582|GT-S7530E|GT-I8750', + 'LG' => '\bLG\b;|LG[- ]?(C800|C900|E400|E610|E900|E-900|F160|F180K|F180L|F180S|730|855|L160|LS740|LS840|LS970|LU6200|MS690|MS695|MS770|MS840|MS870|MS910|P500|P700|P705|VM696|AS680|AS695|AX840|C729|E970|GS505|272|C395|E739BK|E960|L55C|L75C|LS696|LS860|P769BK|P350|P500|P509|P870|UN272|US730|VS840|VS950|LN272|LN510|LS670|LS855|LW690|MN270|MN510|P509|P769|P930|UN200|UN270|UN510|UN610|US670|US740|US760|UX265|UX840|VN271|VN530|VS660|VS700|VS740|VS750|VS910|VS920|VS930|VX9200|VX11000|AX840A|LW770|P506|P925|P999|E612|D955|D802)', + 'Sony' => 'SonyST|SonyLT|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i|LT28h|LT26w|SonyEricssonMT27i|C5303|C6902|C6903|C6906|C6943|D2533', + 'Asus' => 'Asus.*Galaxy|PadFone.*Mobile', + // http://www.micromaxinfo.com/mobiles/smartphones + // Added because the codes might conflict with Acer Tablets. + 'Micromax' => 'Micromax.*\b(A210|A92|A88|A72|A111|A110Q|A115|A116|A110|A90S|A26|A51|A35|A54|A25|A27|A89|A68|A65|A57|A90)\b', + // @todo Complete the regex. + 'Palm' => 'PalmSource|Palm', // avantgo|blazer|elaine|hiptop|plucker|xiino ; + 'Vertu' => 'Vertu|Vertu.*Ltd|Vertu.*Ascent|Vertu.*Ayxta|Vertu.*Constellation(F|Quest)?|Vertu.*Monika|Vertu.*Signature', // Just for fun ;) + // http://www.pantech.co.kr/en/prod/prodList.do?gbrand=VEGA (PANTECH) + // Most of the VEGA devices are legacy. PANTECH seem to be newer devices based on Android. + 'Pantech' => 'PANTECH|IM-A850S|IM-A840S|IM-A830L|IM-A830K|IM-A830S|IM-A820L|IM-A810K|IM-A810S|IM-A800S|IM-T100K|IM-A725L|IM-A780L|IM-A775C|IM-A770K|IM-A760S|IM-A750K|IM-A740S|IM-A730S|IM-A720L|IM-A710K|IM-A690L|IM-A690S|IM-A650S|IM-A630K|IM-A600S|VEGA PTL21|PT003|P8010|ADR910L|P6030|P6020|P9070|P4100|P9060|P5000|CDM8992|TXT8045|ADR8995|IS11PT|P2030|P6010|P8000|PT002|IS06|CDM8999|P9050|PT001|TXT8040|P2020|P9020|P2000|P7040|P7000|C790', + // http://www.fly-phone.com/devices/smartphones/ ; Included only smartphones. + 'Fly' => 'IQ230|IQ444|IQ450|IQ440|IQ442|IQ441|IQ245|IQ256|IQ236|IQ255|IQ235|IQ245|IQ275|IQ240|IQ285|IQ280|IQ270|IQ260|IQ250', + 'iMobile' => 'i-mobile (IQ|i-STYLE|idea|ZAA|Hitz)', + // Added simvalley mobile just for fun. They have some interesting devices. + // http://www.simvalley.fr/telephonie---gps-_22_telephonie-mobile_telephones_.html + 'SimValley' => '\b(SP-80|XT-930|SX-340|XT-930|SX-310|SP-360|SP60|SPT-800|SP-120|SPT-800|SP-140|SPX-5|SPX-8|SP-100|SPX-8|SPX-12)\b', + // Wolfgang - a brand that is sold by Aldi supermarkets. + // http://www.wolfgangmobile.com/ + 'Wolfgang' => 'AT-B24D|AT-AS50HD|AT-AS40W|AT-AS55HD|AT-AS45q2|AT-B26D|AT-AS50Q', + 'Alcatel' => 'Alcatel', + 'Nintendo' => 'Nintendo 3DS', + // http://en.wikipedia.org/wiki/Amoi + 'Amoi' => 'Amoi', + // http://en.wikipedia.org/wiki/INQ + 'INQ' => 'INQ', + // @Tapatalk is a mobile app; http://support.tapatalk.com/threads/smf-2-0-2-os-and-browser-detection-plugin-and-tapatalk.15565/#post-79039 + 'GenericPhone' => 'Tapatalk|PDA;|SAGEM|\bmmp\b|pocket|\bpsp\b|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|\bwap\b|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser', + ); + + /** + * List of tablet devices. + * + * @var array + */ + protected static $tabletDevices = array( + 'iPad' => 'iPad|iPad.*Mobile', // @todo: check for mobile friendly emails topic. + 'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)|^.*Android.*Nexus(?:(?!Mobile).)*$', + 'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-I9205|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T707A|SM-T807A|SM-T237P|SM-T807P|SM-P607T|SM-T217T|SM-T337T', // SCH-P709|SCH-P729|SM-T2558 - Samsung Mega - treat them like a regular phone. + // http://docs.aws.amazon.com/silk/latest/developerguide/user-agent.html + 'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI)\b', + // Only the Surface tablets with Windows RT are considered mobile. + // http://msdn.microsoft.com/en-us/library/ie/hh920767(v=vs.85).aspx + 'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)', + // http://shopping1.hp.com/is-bin/INTERSHOP.enfinity/WFS/WW-USSMBPublicStore-Site/en_US/-/USD/ViewStandardCatalog-Browse?CatalogCategoryID=JfIQ7EN5lqMAAAEyDcJUDwMT + 'HPTablet' => 'HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10', + // Watch out for PadFone, see #132. + // http://www.asus.com/de/Tablets_Mobile/Memo_Pad_Products/ + 'AsusTablet' => '^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\bK00F\b|\bK00C\b|\bK00E\b|\bK00L\b|TX201LA|ME176C|ME102A|\bM80TA\b|ME372CL|ME560CG|ME372CG', + 'BlackBerryTablet' => 'PlayBook|RIM Tablet', + 'HTCtablet' => 'HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410', + 'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617', + 'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2', + // http://www.acer.ro/ac/ro/RO/content/drivers + // http://www.packardbell.co.uk/pb/en/GB/content/download (Packard Bell is part of Acer) + // http://us.acer.com/ac/en/US/content/group/tablets + // http://www.acer.de/ac/de/DE/content/models/tablets/ + // Can conflict with Micromax and Motorola phones codes. + 'AcerTablet' => 'Android.*; \b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\b|W3-810|\bA3-A10\b', + // http://eu.computers.toshiba-europe.com/innovation/family/Tablets/1098744/banner_id/tablet_footerlink/ + // http://us.toshiba.com/tablets/tablet-finder + // http://www.toshiba.co.jp/regza/tablet/ + 'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO', + // http://www.nttdocomo.co.jp/english/service/developer/smart_phone/technical_info/spec/index.html + // http://www.lg.com/us/tablets + 'LGTablet' => '\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\b', + 'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b', + // Prestigio Tablets http://www.prestigio.com/support + 'PrestigioTablet' => 'PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD', + // http://support.lenovo.com/en_GB/downloads/default.page?# + 'LenovoTablet' => 'Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)', + // http://www.dell.com/support/home/us/en/04/Products/tab_mob/tablets + 'DellTablet' => 'Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7', + // http://www.yarvik.com/en/matrix/tablets/ + 'YarvikTablet' => 'Android.*\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\b', + 'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB', + 'ArnovaTablet' => 'AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2', + // http://www.intenso.de/kategorie_en.php?kategorie=33 + // @todo: http://www.nbhkdz.com/read/b8e64202f92a2df129126bff.html - investigate + 'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004', + // IRU.ru Tablets http://www.iru.ru/catalog/soho/planetable/ + 'IRUTablet' => 'M702pro', + 'MegafonTablet' => 'MegaFon V9|\bZTE V9\b|Android.*\bMT7A\b', + // http://www.e-boda.ro/tablete-pc.html + 'EbodaTablet' => 'E-Boda (Supreme|Impresspeed|Izzycomm|Essential)', + // http://www.allview.ro/produse/droseries/lista-tablete-pc/ + 'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)', + // http://wiki.archosfans.com/index.php?title=Main_Page + 'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|Archos5|\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\b', + // http://www.ainol.com/plugin.php?identifier=ainol&module=product + 'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark', + // @todo: inspect http://esupport.sony.com/US/p/select-system.pl?DIRECTOR=DRIVER + // Readers http://www.atsuhiro-me.net/ebook/sony-reader/sony-reader-web-browser + // http://www.sony.jp/support/tablet/ + 'SonyTablet' => 'Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551', + // http://www.support.philips.com/support/catalog/worldproducts.jsp?userLanguage=en&userCountry=cn&categoryid=3G_LTE_TABLET_SU_CN_CARE&title=3G%20tablets%20/%20LTE%20range&_dyncharset=UTF-8 + 'PhilipsTablet' => '\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\b', + // db + http://www.cube-tablet.com/buy-products.html + 'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT', + // http://www.cobyusa.com/?p=pcat&pcat_id=3001 + 'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010', + // http://www.match.net.cn/products.asp + 'MIDTablet' => 'M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733', + // http://www.msi.com/support + // @todo Research the Windows Tablets. + 'MSITablet' => 'MSI \b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\b', + // @todo http://www.kyoceramobile.com/support/drivers/ + // 'KyoceraTablet' => null, + // @todo http://intexuae.com/index.php/category/mobile-devices/tablets-products/ + // 'IntextTablet' => null, + // http://pdadb.net/index.php?m=pdalist&list=SMiT (NoName Chinese Tablets) + // http://www.imp3.net/14/show.php?itemid=20454 + 'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)', + // http://www.rock-chips.com/index.php?do=prod&pid=2 + 'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A', + // http://www.fly-phone.com/devices/tablets/ ; http://www.fly-phone.com/service/ + 'FlyTablet' => 'IQ310|Fly Vision', + // http://www.bqreaders.com/gb/tablets-prices-sale.html + 'bqTablet' => 'bq.*(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant)|Maxwell.*Lite|Maxwell.*Plus', + // http://www.huaweidevice.com/worldwide/productFamily.do?method=index&directoryId=5011&treeId=3290 + // http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index&directoryId=3372&treeId=0&tb=1&type=software (including legacy tablets) + 'HuaweiTablet' => 'MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim', + // Nec or Medias Tab + 'NecTablet' => '\bN-06D|\bN-08D', + // Pantech Tablets: http://www.pantechusa.com/phones/ + 'PantechTablet' => 'Pantech.*P4100', + // Broncho Tablets: http://www.broncho.cn/ (hard to find) + 'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)', + // http://versusuk.com/support.html + 'VersusTablet' => 'TOUCHPAD.*[78910]|\bTOUCHTAB\b', + // http://www.zync.in/index.php/our-products/tablet-phablets + 'ZyncTablet' => 'z1000|Z99 2G|z99|z930|z999|z990|z909|Z919|z900', + // http://www.positivoinformatica.com.br/www/pessoal/tablet-ypy/ + 'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA', + // https://www.nabitablet.com/ + 'NabiTablet' => 'Android.*\bNabi', + 'KoboTablet' => 'Kobo Touch|\bK080\b|\bVox\b Build|\bArc\b Build', + // French Danew Tablets http://www.danew.com/produits-tablette.php + 'DanewTablet' => 'DSlide.*\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\b', + // Texet Tablets and Readers http://www.texet.ru/tablet/ + 'TexetTablet' => 'NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE', + // Avoid detecting 'PLAYSTATION 3' as mobile. + 'PlaystationTablet' => 'Playstation.*(Portable|Vita)', + // http://www.trekstor.de/surftabs.html + 'TrekstorTablet' => 'ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab', + // http://www.pyleaudio.com/Products.aspx?%2fproducts%2fPersonal-Electronics%2fTablets + 'PyleAudioTablet' => '\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\b', + // http://www.advandigital.com/index.php?link=content-product&jns=JP001 + // because of the short codenames we have to include whitespaces to reduce the possible conflicts. + 'AdvanTablet' => 'Android.* \b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\b ', + // http://www.danytech.com/category/tablet-pc + 'DanyTechTablet' => 'Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1', + // http://www.galapad.net/product.html + 'GalapadTablet' => 'Android.*\bG1\b', + // http://www.micromaxinfo.com/tablet/funbook + 'MicromaxTablet' => 'Funbook|Micromax.*\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\b', + // http://www.karbonnmobiles.com/products_tablet.php + 'KarbonnTablet' => 'Android.*\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\b', + // http://www.myallfine.com/Products.asp + 'AllFineTablet' => 'Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide', + // http://www.proscanvideo.com/products-search.asp?itemClass=TABLET&itemnmbr= + 'PROSCANTablet' => '\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\b', + // http://www.yonesnav.com/products/products.php + 'YONESTablet' => 'BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026', + // http://www.cjshowroom.com/eproducts.aspx?classcode=004001001 + // China manufacturer makes tablets for different small brands (eg. http://www.zeepad.net/index.html) + 'ChangJiaTablet' => 'TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503', + // http://www.gloryunion.cn/products.asp + // http://www.allwinnertech.com/en/apply/mobile.html + // http://www.ptcl.com.pk/pd_content.php?pd_id=284 (EVOTAB) + // @todo: Softwiner tablets? + // aka. Cute or Cool tablets. Not sure yet, must research to avoid collisions. + 'GUTablet' => 'TX-A1301|TX-M9002|Q702|kf026', // A12R|D75A|D77|D79|R83|A95|A106C|R15|A75|A76|D71|D72|R71|R73|R77|D82|R85|D92|A97|D92|R91|A10F|A77F|W71F|A78F|W78F|W81F|A97F|W91F|W97F|R16G|C72|C73E|K72|K73|R96G + // http://www.pointofview-online.com/showroom.php?shop_mode=product_listing&category_id=118 + 'PointOfViewTablet' => 'TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10', + // http://www.overmax.pl/pl/katalog-produktow,p8/tablety,c14/ + // @todo: add more tests. + 'OvermaxTablet' => 'OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)', + // http://hclmetablet.com/India/index.php + 'HCLTablet' => 'HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync', + // http://www.edigital.hu/Tablet_es_e-book_olvaso/Tablet-c18385.html + 'DPSTablet' => 'DPS Dream 9|DPS Dual 7', + // http://www.visture.com/index.asp + 'VistureTablet' => 'V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10', + // http://www.mijncresta.nl/tablet + 'CrestaTablet' => 'CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989', + // MediaTek - http://www.mediatek.com/_en/01_products/02_proSys.php?cata_sn=1&cata1_sn=1&cata2_sn=309 + 'MediatekTablet' => '\bMT8125|MT8389|MT8135|MT8377\b', + // Concorde tab + 'ConcordeTablet' => 'Concorde([ ]+)?Tab|ConCorde ReadMan', + // GoClever Tablets - http://www.goclever.com/uk/products,c1/tablet,c5/ + 'GoCleverTablet' => 'GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042', + // Modecom Tablets - http://www.modecom.eu/tablets/portal/ + 'ModecomTablet' => 'FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003', + // Vonino Tablets - http://www.vonino.eu/tablets + 'VoninoTablet' => '\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\bQ8\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\b', + // ECS Tablets - http://www.ecs.com.tw/ECSWebSite/Product/Product_Tablet_List.aspx?CategoryID=14&MenuID=107&childid=M_107&LanID=0 + 'ECSTablet' => 'V07OT2|TM105A|S10OT1|TR10CS1', + // Storex Tablets - http://storex.fr/espace_client/support.html + // @note: no need to add all the tablet codes since they are guided by the first regex. + 'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab', + // Generic Vodafone tablets. + 'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7', + // French tablets - Essentiel B http://www.boulanger.fr/tablette_tactile_e-book/tablette_tactile_essentiel_b/cl_68908.htm?multiChoiceToDelete=brand&mc_brand=essentielb + // Aka: http://www.essentielb.fr/ + 'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2', + // Ross & Moor - http://ross-moor.ru/ + 'RossMoorTablet' => 'RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711', + // i-mobile http://product.i-mobilephone.com/Mobile_Device + 'iMobileTablet' => 'i-mobile i-note', + // http://www.tolino.de/de/vergleichen/ + 'TolinoTablet' => 'tolino tab [0-9.]+|tolino shine', + // AudioSonic - a Kmart brand + // http://www.kmart.com.au/webapp/wcs/stores/servlet/Search?langId=-1&storeId=10701&catalogId=10001&categoryId=193001&pageSize=72¤tPage=1&searchCategory=193001%2b4294965664&sortBy=p_MaxPrice%7c1 + 'AudioSonicTablet' => '\bC-22Q|T7-QC|T-17B|T-17P\b', + // AMPE Tablets - http://www.ampe.com.my/product-category/tablets/ + // @todo: add them gradually to avoid conflicts. + 'AMPETablet' => 'Android.* A78 ', + // Skk Mobile - http://skkmobile.com.ph/product_tablets.php + 'SkkTablet' => 'Android.* (SKYPAD|PHOENIX|CYCLOPS)', + // Tecno Mobile (only tablet) - http://www.tecno-mobile.com/index.php/product?filterby=smart&list_order=all&page=1 + 'TecnoTablet' => 'TECNO P9', + // JXD (consoles & tablets) - http://jxd.hk/products.asp?selectclassid=009008&clsid=3 + 'JXDTablet' => 'Android.*\b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\b', + // i-Joy tablets - http://www.i-joy.es/en/cat/products/tablets/ + 'iJoyTablet' => 'Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)', + // http://www.intracon.eu/tablet + 'FX2Tablet' => 'FX2 PAD7|FX2 PAD10', + // http://www.xoro.de/produkte/ + // @note: Might be the same brand with 'Simply tablets' + 'XoroTablet' => 'KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151', + // http://www1.viewsonic.com/products/computing/tablets/ + 'ViewsonicTablet' => 'ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a', + // http://www.odys.de/web/internet-tablet_en.html + 'OdysTablet' => 'LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\bXELIO\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10', + // http://www.captiva-power.de/products.html#tablets-en + 'CaptivaTablet' => 'CAPTIVA PAD', + // IconBIT - http://www.iconbit.com/products/tablets/ + 'IconbitTablet' => 'NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S', + // http://www.teclast.com/topic.php?channelID=70&topicID=140&pid=63 + 'TeclastTablet' => 'T98 4G|\bP80\b|\bX90HD\b|X98 Air|X98 Air 3G|\bX89\b|P80 3G|\bX80h\b|P98 Air|\bX89HD\b|P98 3G|\bP90HD\b|P89 3G|X98 3G|\bP70h\b|P79HD 3G|G18d 3G|\bP79HD\b|\bP89s\b|\bA88\b|\bP10HD\b|\bP19HD\b|G18 3G|\bP78HD\b|\bA78\b|\bP75\b|G17s 3G|G17h 3G|\bP85t\b|\bP90\b|\bP11\b|\bP98t\b|\bP98HD\b|\bG18d\b|\bP85s\b|\bP11HD\b|\bP88s\b|\bA80HD\b|\bA80se\b|\bA10h\b|\bP89\b|\bP78s\b|\bG18\b|\bP85\b|\bA70h\b|\bA70\b|\bG17\b|\bP18\b|\bA80s\b|\bA11s\b|\bP88HD\b|\bA80h\b|\bP76s\b|\bP76h\b|\bP98\b|\bA10HD\b|\bP78\b|\bP88\b|\bA11\b|\bA10t\b|\bP76a\b|\bP76t\b|\bP76e\b|\bP85HD\b|\bP85a\b|\bP86\b|\bP75HD\b|\bP76v\b|\bA12\b|\bP75a\b|\bA15\b|\bP76Ti\b|\bP81HD\b|\bA10\b|\bT760VE\b|\bT720HD\b|\bP76\b|\bP73\b|\bP71\b|\bP72\b|\bT720SE\b|\bC520Ti\b|\bT760\b|\bT720VE\b|T720-3GE|T720-WiFi', + 'JaytechTablet' => 'TPC-PA762', + 'BlaupunktTablet' => 'Endeavour 800NG|Endeavour 1010', + // http://www.digma.ru/support/download/ + // @todo: Ebooks also (if requested) + 'DigmaTablet' => '\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\b', + // http://www.evolioshop.com/ro/tablete-pc.html + // http://www.evolio.ro/support/downloads_static.html?cat=2 + // @todo: Research some more + 'EvolioTablet' => 'ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\bEvotab\b|\bNeura\b', + // @todo http://www.lavamobiles.com/tablets-data-cards + 'LavaTablet' => 'QPAD E704|\bIvoryS\b|E-TAB IVORY', + // https://www.celkonmobiles.com/?_a=categoryphones&sid=2 + 'CelkonTablet' => 'CT695|CT888|CT[\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\bCT-1\b', + // http://www.mi.com/en + 'MiTablet' => '\bMI PAD\b|\bHM NOTE 1W\b', + // http://www.nbru.cn/index.html + 'NibiruTablet' => 'Nibiru M1|Nibiru Jupiter One', + // http://navroad.com/products/produkty/tablety/ + 'NexoTablet' => 'NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI', + // http://www.datawind.com/ubislate/ + 'UbislateTablet' => 'UbiSlate[\s]?7C', + // http://www.pocketbook-int.com/ru/support + 'PocketBookTablet' => 'Pocketbook', + // http://www.tesco.com/direct/hudl/ + 'Hudl' => 'Hudl HT7S3', + // http://www.telstra.com.au/home-phone/thub-2/ + 'TelstraTablet' => 'T-Hub2', + 'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|rk30sdk|\bEVOTAB\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\bM6pro\b|CT1020W|arc 10HD|\bJolla\b' + ); + + /** + * List of mobile Operating Systems. + * + * @var array + */ + protected static $operatingSystems = array( + 'AndroidOS' => 'Android', + 'BlackBerryOS' => 'blackberry|\bBB10\b|rim tablet os', + 'PalmOS' => 'PalmOS|avantgo|blazer|elaine|hiptop|palm|plucker|xiino', + 'SymbianOS' => 'Symbian|SymbOS|Series60|Series40|SYB-[0-9]+|\bS60\b', + // @reference: http://en.wikipedia.org/wiki/Windows_Mobile + 'WindowsMobileOS' => 'Windows CE.*(PPC|Smartphone|Mobile|[0-9]{3}x[0-9]{3})|Window Mobile|Windows Phone [0-9.]+|WCE;', + // @reference: http://en.wikipedia.org/wiki/Windows_Phone + // http://wifeng.cn/?r=blog&a=view&id=106 + // http://nicksnettravels.builttoroam.com/post/2011/01/10/Bogus-Windows-Phone-7-User-Agent-String.aspx + // http://msdn.microsoft.com/library/ms537503.aspx + 'WindowsPhoneOS' => 'Windows Phone 8.0|Windows Phone OS|XBLWP7|ZuneWP7|Windows NT 6.[23]; ARM;', + 'iOS' => '\biPhone.*Mobile|\biPod|\biPad', + // http://en.wikipedia.org/wiki/MeeGo + // @todo: research MeeGo in UAs + 'MeeGoOS' => 'MeeGo', + // http://en.wikipedia.org/wiki/Maemo + // @todo: research Maemo in UAs + 'MaemoOS' => 'Maemo', + 'JavaOS' => 'J2ME/|\bMIDP\b|\bCLDC\b', // '|Java/' produces bug #135 + 'webOS' => 'webOS|hpwOS', + 'badaOS' => '\bBada\b', + 'BREWOS' => 'BREW', + ); + + /** + * List of mobile User Agents. + * + * @var array + */ + protected static $browsers = array( + // @reference: https://developers.google.com/chrome/mobile/docs/user-agent + 'Chrome' => '\bCrMo\b|CriOS|Android.*Chrome/[.0-9]* (Mobile)?', + 'Dolfin' => '\bDolfin\b', + 'Opera' => 'Opera.*Mini|Opera.*Mobi|Android.*Opera|Mobile.*OPR/[0-9.]+|Coast/[0-9.]+', + 'Skyfire' => 'Skyfire', + 'IE' => 'IEMobile|MSIEMobile', // |Trident/[.0-9]+ + 'Firefox' => 'fennec|firefox.*maemo|(Mobile|Tablet).*Firefox|Firefox.*Mobile', + 'Bolt' => 'bolt', + 'TeaShark' => 'teashark', + 'Blazer' => 'Blazer', + // @reference: http://developer.apple.com/library/safari/#documentation/AppleApplications/Reference/SafariWebContent/OptimizingforSafarioniPhone/OptimizingforSafarioniPhone.html#//apple_ref/doc/uid/TP40006517-SW3 + 'Safari' => 'Version.*Mobile.*Safari|Safari.*Mobile|MobileSafari', + // http://en.wikipedia.org/wiki/Midori_(web_browser) + //'Midori' => 'midori', + 'Tizen' => 'Tizen', + 'UCBrowser' => 'UC.*Browser|UCWEB', + 'baiduboxapp' => 'baiduboxapp', + 'baidubrowser' => 'baidubrowser', + // https://github.com/serbanghita/Mobile-Detect/issues/7 + 'DiigoBrowser' => 'DiigoBrowser', + // http://www.puffinbrowser.com/index.php + 'Puffin' => 'Puffin', + // http://mercury-browser.com/index.html + 'Mercury' => '\bMercury\b', + // http://en.wikipedia.org/wiki/Obigo_Browser + 'ObigoBrowser' => 'Obigo', + // http://en.wikipedia.org/wiki/NetFront + 'NetFront' => 'NF-Browser', + // @reference: http://en.wikipedia.org/wiki/Minimo + // http://en.wikipedia.org/wiki/Vision_Mobile_Browser + 'GenericBrowser' => 'NokiaBrowser|OviBrowser|OneBrowser|TwonkyBeamBrowser|SEMC.*Browser|FlyFlow|Minimo|NetFront|Novarra-Vision|MQQBrowser|MicroMessenger', + ); + + /** + * Utilities. + * + * @var array + */ + protected static $utilities = array( + // Experimental. When a mobile device wants to switch to 'Desktop Mode'. + // http://scottcate.com/technology/windows-phone-8-ie10-desktop-or-mobile/ + // https://github.com/serbanghita/Mobile-Detect/issues/57#issuecomment-15024011 + 'DesktopMode' => 'WPDesktop', + 'TV' => 'SonyDTV|HbbTV', // experimental + 'WebKit' => '(webkit)[ /]([\w.]+)', + 'Bot' => 'Googlebot|YandexBot|bingbot|ia_archiver|AhrefsBot|Ezooms|GSLFbot|WBSearchBot|Twitterbot|TweetmemeBot|Twikle|PaperLiBot|Wotbox|UnwindFetchor|facebookexternalhit', + 'MobileBot' => 'Googlebot-Mobile|YahooSeeker/M1A1-R2D2', + // @todo: Include JXD consoles. + 'Console' => '\b(Nintendo|Nintendo WiiU|Nintendo 3DS|PLAYSTATION|Xbox)\b', + 'Watch' => 'SM-V700', + ); + + /** + * All possible HTTP headers that represent the + * User-Agent string. + * + * @var array + */ + protected static $uaHttpHeaders = array( + // The default User-Agent string. + 'HTTP_USER_AGENT', + // Header can occur on devices using Opera Mini. + 'HTTP_X_OPERAMINI_PHONE_UA', + // Vodafone specific header: http://www.seoprinciple.com/mobile-web-community-still-angry-at-vodafone/24/ + 'HTTP_X_DEVICE_USER_AGENT', + 'HTTP_X_ORIGINAL_USER_AGENT', + 'HTTP_X_SKYFIRE_PHONE', + 'HTTP_X_BOLT_PHONE_UA', + 'HTTP_DEVICE_STOCK_UA', + 'HTTP_X_UCBROWSER_DEVICE_UA' + ); + + /** + * The individual segments that could exist in a User-Agent string. VER refers to the regular + * expression defined in the constant self::VER. + * + * @var array + */ + protected static $properties = array( + + // Build + 'Mobile' => 'Mobile/[VER]', + 'Build' => 'Build/[VER]', + 'Version' => 'Version/[VER]', + 'VendorID' => 'VendorID/[VER]', + + // Devices + 'iPad' => 'iPad.*CPU[a-z ]+[VER]', + 'iPhone' => 'iPhone.*CPU[a-z ]+[VER]', + 'iPod' => 'iPod.*CPU[a-z ]+[VER]', + //'BlackBerry' => array('BlackBerry[VER]', 'BlackBerry [VER];'), + 'Kindle' => 'Kindle/[VER]', + + // Browser + 'Chrome' => array('Chrome/[VER]', 'CriOS/[VER]', 'CrMo/[VER]'), + 'Coast' => array('Coast/[VER]'), + 'Dolfin' => 'Dolfin/[VER]', + // @reference: https://developer.mozilla.org/en-US/docs/User_Agent_Strings_Reference + 'Firefox' => 'Firefox/[VER]', + 'Fennec' => 'Fennec/[VER]', + // @reference: http://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx + 'IE' => array('IEMobile/[VER];', 'IEMobile [VER]', 'MSIE [VER];'), + // http://en.wikipedia.org/wiki/NetFront + 'NetFront' => 'NetFront/[VER]', + 'NokiaBrowser' => 'NokiaBrowser/[VER]', + 'Opera' => array( ' OPR/[VER]', 'Opera Mini/[VER]', 'Version/[VER]' ), + 'Opera Mini' => 'Opera Mini/[VER]', + 'Opera Mobi' => 'Version/[VER]', + 'UC Browser' => 'UC Browser[VER]', + 'MQQBrowser' => 'MQQBrowser/[VER]', + 'MicroMessenger' => 'MicroMessenger/[VER]', + 'baiduboxapp' => 'baiduboxapp/[VER]', + 'baidubrowser' => 'baidubrowser/[VER]', + 'Iron' => 'Iron/[VER]', + // @note: Safari 7534.48.3 is actually Version 5.1. + // @note: On BlackBerry the Version is overwriten by the OS. + 'Safari' => array( 'Version/[VER]', 'Safari/[VER]' ), + 'Skyfire' => 'Skyfire/[VER]', + 'Tizen' => 'Tizen/[VER]', + 'Webkit' => 'webkit[ /][VER]', + + // Engine + 'Gecko' => 'Gecko/[VER]', + 'Trident' => 'Trident/[VER]', + 'Presto' => 'Presto/[VER]', + + // OS + 'iOS' => ' \bOS\b [VER] ', + 'Android' => 'Android [VER]', + 'BlackBerry' => array('BlackBerry[\w]+/[VER]', 'BlackBerry.*Version/[VER]', 'Version/[VER]'), + 'BREW' => 'BREW [VER]', + 'Java' => 'Java/[VER]', + // @reference: http://windowsteamblog.com/windows_phone/b/wpdev/archive/2011/08/29/introducing-the-ie9-on-windows-phone-mango-user-agent-string.aspx + // @reference: http://en.wikipedia.org/wiki/Windows_NT#Releases + 'Windows Phone OS' => array( 'Windows Phone OS [VER]', 'Windows Phone [VER]'), + 'Windows Phone' => 'Windows Phone [VER]', + 'Windows CE' => 'Windows CE/[VER]', + // http://social.msdn.microsoft.com/Forums/en-US/windowsdeveloperpreviewgeneral/thread/6be392da-4d2f-41b4-8354-8dcee20c85cd + 'Windows NT' => 'Windows NT [VER]', + 'Symbian' => array('SymbianOS/[VER]', 'Symbian/[VER]'), + 'webOS' => array('webOS/[VER]', 'hpwOS/[VER];'), + ); + + /** + * Construct an instance of this class. + * + * @param array $headers Specify the headers as injection. Should be PHP _SERVER flavored. + * If left empty, will use the global _SERVER['HTTP_*'] vars instead. + * @param string $userAgent Inject the User-Agent header. If null, will use HTTP_USER_AGENT + * from the $headers array instead. + */ + public function __construct( + array $headers = null, + $userAgent = null + ) { + $this->setHttpHeaders($headers); + $this->setUserAgent($userAgent); + } + + /** + * Get the current script version. + * This is useful for the demo.php file, + * so people can check on what version they are testing + * for mobile devices. + * + * @return string The version number in semantic version format. + */ + public static function getScriptVersion() + { + return self::VERSION; + } + + /** + * Set the HTTP Headers. Must be PHP-flavored. This method will reset existing headers. + * + * @param array $httpHeaders The headers to set. If null, then using PHP's _SERVER to extract + * the headers. The default null is left for backwards compatibilty. + */ + public function setHttpHeaders($httpHeaders = null) + { + //use global _SERVER if $httpHeaders aren't defined + if (!is_array($httpHeaders) || !count($httpHeaders)) { + $httpHeaders = $_SERVER; + } + + //clear existing headers + $this->httpHeaders = array(); + + //Only save HTTP headers. In PHP land, that means only _SERVER vars that + //start with HTTP_. + foreach ($httpHeaders as $key => $value) { + if (substr($key,0,5) == 'HTTP_') { + $this->httpHeaders[$key] = $value; + } + } + } + + /** + * Retrieves the HTTP headers. + * + * @return array + */ + public function getHttpHeaders() + { + return $this->httpHeaders; + } + + /** + * Retrieves a particular header. If it doesn't exist, no exception/error is caused. + * Simply null is returned. + * + * @param string $header The name of the header to retrieve. Can be HTTP compliant such as + * "User-Agent" or "X-Device-User-Agent" or can be php-esque with the + * all-caps, HTTP_ prefixed, underscore seperated awesomeness. + * + * @return string|null The value of the header. + */ + public function getHttpHeader($header) + { + //are we using PHP-flavored headers? + if (strpos($header, '_') === false) { + $header = str_replace('-', '_', $header); + $header = strtoupper($header); + } + + //test the alternate, too + $altHeader = 'HTTP_' . $header; + + //Test both the regular and the HTTP_ prefix + if (isset($this->httpHeaders[$header])) { + return $this->httpHeaders[$header]; + } elseif (isset($this->httpHeaders[$altHeader])) { + return $this->httpHeaders[$altHeader]; + } + + return null; + } + + public function getMobileHeaders() + { + return self::$mobileHeaders; + } + + /** + * Get all possible HTTP headers that + * can contain the User-Agent string. + * + * @return array List of HTTP headers. + */ + public function getUaHttpHeaders() + { + return self::$uaHttpHeaders; + } + + /** + * Set the User-Agent to be used. + * + * @param string $userAgent The user agent string to set. + * + * @return string|null + */ + public function setUserAgent($userAgent = null) + { + if (!empty($userAgent)) { + return $this->userAgent = $userAgent; + } else { + $this->userAgent = null; + foreach ($this->getUaHttpHeaders() as $altHeader) { + if (!empty($this->httpHeaders[$altHeader])) { // @todo: should use getHttpHeader(), but it would be slow. (Serban) + $this->userAgent .= $this->httpHeaders[$altHeader] . " "; + } + } + + return $this->userAgent = (!empty($this->userAgent) ? trim($this->userAgent) : null); + + } + } + + /** + * Retrieve the User-Agent. + * + * @return string|null The user agent if it's set. + */ + public function getUserAgent() + { + return $this->userAgent; + } + + /** + * Set the detection type. Must be one of self::DETECTION_TYPE_MOBILE or + * self::DETECTION_TYPE_EXTENDED. Otherwise, nothing is set. + * + * @deprecated since version 2.6.9 + * + * @param string $type The type. Must be a self::DETECTION_TYPE_* constant. The default + * parameter is null which will default to self::DETECTION_TYPE_MOBILE. + */ + public function setDetectionType($type = null) + { + if ($type === null) { + $type = self::DETECTION_TYPE_MOBILE; + } + + if ($type != self::DETECTION_TYPE_MOBILE && $type != self::DETECTION_TYPE_EXTENDED) { + return; + } + + $this->detectionType = $type; + } + + public function getMatchingRegex() + { + return $this->matchingRegex; + } + + public function getMatchesArray() + { + return $this->matchesArray; + } + + /** + * Retrieve the list of known phone devices. + * + * @return array List of phone devices. + */ + public static function getPhoneDevices() + { + return self::$phoneDevices; + } + + /** + * Retrieve the list of known tablet devices. + * + * @return array List of tablet devices. + */ + public static function getTabletDevices() + { + return self::$tabletDevices; + } + + /** + * Alias for getBrowsers() method. + * + * @return array List of user agents. + */ + public static function getUserAgents() + { + return self::getBrowsers(); + } + + /** + * Retrieve the list of known browsers. Specifically, the user agents. + * + * @return array List of browsers / user agents. + */ + public static function getBrowsers() + { + return self::$browsers; + } + + /** + * Retrieve the list of known utilities. + * + * @return array List of utilities. + */ + public static function getUtilities() + { + return self::$utilities; + } + + /** + * Method gets the mobile detection rules. This method is used for the magic methods $detect->is*(). + * + * @deprecated since version 2.6.9 + * + * @return array All the rules (but not extended). + */ + public static function getMobileDetectionRules() + { + static $rules; + + if (!$rules) { + $rules = array_merge( + self::$phoneDevices, + self::$tabletDevices, + self::$operatingSystems, + self::$browsers + ); + } + + return $rules; + + } + + /** + * Method gets the mobile detection rules + utilities. + * The reason this is separate is because utilities rules + * don't necessary imply mobile. This method is used inside + * the new $detect->is('stuff') method. + * + * @deprecated since version 2.6.9 + * + * @return array All the rules + extended. + */ + public function getMobileDetectionRulesExtended() + { + static $rules; + + if (!$rules) { + // Merge all rules together. + $rules = array_merge( + self::$phoneDevices, + self::$tabletDevices, + self::$operatingSystems, + self::$browsers, + self::$utilities + ); + } + + return $rules; + } + + /** + * Retrieve the current set of rules. + * + * @deprecated since version 2.6.9 + * + * @return array + */ + public function getRules() + { + if ($this->detectionType == self::DETECTION_TYPE_EXTENDED) { + return self::getMobileDetectionRulesExtended(); + } else { + return self::getMobileDetectionRules(); + } + } + + /** + * Retrieve the list of mobile operating systems. + * + * @return array The list of mobile operating systems. + */ + public static function getOperatingSystems() + { + return self::$operatingSystems; + } + + /** + * Check the HTTP headers for signs of mobile. + * This is the fastest mobile check possible; it's used + * inside isMobile() method. + * + * @return bool + */ + public function checkHttpHeadersForMobile() + { + + foreach ($this->getMobileHeaders() as $mobileHeader => $matchType) { + if ( isset($this->httpHeaders[$mobileHeader]) ) { + if ( is_array($matchType['matches']) ) { + foreach ($matchType['matches'] as $_match) { + if ( strpos($this->httpHeaders[$mobileHeader], $_match) !== false ) { + return true; + } + } + + return false; + } else { + return true; + } + } + } + + return false; + + } + + /** + * Magic overloading method. + * + * @method boolean is[...]() + * @param string $name + * @param array $arguments + * @return mixed + * @throws BadMethodCallException when the method doesn't exist and doesn't start with 'is' + */ + public function __call($name, $arguments) + { + //make sure the name starts with 'is', otherwise + if (substr($name, 0, 2) != 'is') { + throw new BadMethodCallException("No such method exists: $name"); + } + + $this->setDetectionType(self::DETECTION_TYPE_MOBILE); + + $key = substr($name, 2); + + return $this->matchUAAgainstKey($key); + } + + /** + * Find a detection rule that matches the current User-agent. + * + * @param null $userAgent deprecated + * @return boolean + */ + protected function matchDetectionRulesAgainstUA($userAgent = null) + { + // Begin general search. + foreach ($this->getRules() as $_regex) { + if (empty($_regex)) { + continue; + } + if ($this->match($_regex, $userAgent)) { + return true; + } + } + + return false; + } + + /** + * Search for a certain key in the rules array. + * If the key is found the try to match the corresponding + * regex agains the User-Agent. + * + * @param string $key + * @param null $userAgent deprecated + * @return mixed + */ + protected function matchUAAgainstKey($key, $userAgent = null) + { + // Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc. + $key = strtolower($key); + + //change the keys to lower case + $_rules = array_change_key_case($this->getRules()); + + if (array_key_exists($key, $_rules)) { + if (empty($_rules[$key])) { + return null; + } + + return $this->match($_rules[$key], $userAgent); + } + + return false; + } + + /** + * Check if the device is mobile. + * Returns true if any type of mobile device detected, including special ones + * @param null $userAgent deprecated + * @param null $httpHeaders deprecated + * @return bool + */ + public function isMobile($userAgent = null, $httpHeaders = null) + { + + if ($httpHeaders) { + $this->setHttpHeaders($httpHeaders); + } + + if ($userAgent) { + $this->setUserAgent($userAgent); + } + + $this->setDetectionType(self::DETECTION_TYPE_MOBILE); + + if ($this->checkHttpHeadersForMobile()) { + return true; + } else { + return $this->matchDetectionRulesAgainstUA(); + } + + } + + /** + * Check if the device is a tablet. + * Return true if any type of tablet device is detected. + * + * @param string $userAgent deprecated + * @param array $httpHeaders deprecated + * @return bool + */ + public function isTablet($userAgent = null, $httpHeaders = null) + { + $this->setDetectionType(self::DETECTION_TYPE_MOBILE); + + foreach (self::$tabletDevices as $_regex) { + if ($this->match($_regex, $userAgent)) { + return true; + } + } + + return false; + } + + /** + * This method checks for a certain property in the + * userAgent. + * @todo: The httpHeaders part is not yet used. + * + * @param string $key + * @param string $userAgent deprecated + * @param string $httpHeaders deprecated + * @return bool|int|null + */ + public function is($key, $userAgent = null, $httpHeaders = null) + { + // Set the UA and HTTP headers only if needed (eg. batch mode). + if ($httpHeaders) { + $this->setHttpHeaders($httpHeaders); + } + + if ($userAgent) { + $this->setUserAgent($userAgent); + } + + $this->setDetectionType(self::DETECTION_TYPE_EXTENDED); + + return $this->matchUAAgainstKey($key); + } + + /** + * Some detection rules are relative (not standard), + * because of the diversity of devices, vendors and + * their conventions in representing the User-Agent or + * the HTTP headers. + * + * This method will be used to check custom regexes against + * the User-Agent string. + * + * @param $regex + * @param string $userAgent + * @return bool + * + * @todo: search in the HTTP headers too. + */ + public function match($regex, $userAgent = null) + { + // Escape the special character which is the delimiter. + $regex = str_replace('/', '\/', $regex); + $match = (bool) preg_match('/'.$regex.'/is', (!empty($userAgent) ? $userAgent : $this->userAgent), $matches); + // If positive match is found, store the results for debug. + if ($match) { + $this->matchingRegex = $regex; + $this->matchesArray = $matches; + } + + return $match; + } + + /** + * Get the properties array. + * + * @return array + */ + public static function getProperties() + { + return self::$properties; + } + + /** + * Prepare the version number. + * + * @todo Remove the error supression from str_replace() call. + * + * @param string $ver The string version, like "2.6.21.2152"; + * + * @return float + */ + public function prepareVersionNo($ver) + { + $ver = str_replace(array('_', ' ', '/'), '.', $ver); + $arrVer = explode('.', $ver, 2); + + if (isset($arrVer[1])) { + $arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions. + } + + return (float) implode('.', $arrVer); + } + + /** + * Check the version of the given property in the User-Agent. + * Will return a float number. (eg. 2_0 will return 2.0, 4.3.1 will return 4.31) + * + * @param string $propertyName The name of the property. See self::getProperties() array + * keys for all possible properties. + * @param string $type Either self::VERSION_TYPE_STRING to get a string value or + * self::VERSION_TYPE_FLOAT indicating a float value. This parameter + * is optional and defaults to self::VERSION_TYPE_STRING. Passing an + * invalid parameter will default to the this type as well. + * + * @return string|float The version of the property we are trying to extract. + */ + public function version($propertyName, $type = self::VERSION_TYPE_STRING) + { + if (empty($propertyName)) { + return false; + } + + //set the $type to the default if we don't recognize the type + if ($type != self::VERSION_TYPE_STRING && $type != self::VERSION_TYPE_FLOAT) { + $type = self::VERSION_TYPE_STRING; + } + + $properties = self::getProperties(); + + // Check if the property exists in the properties array. + if (array_key_exists($propertyName, $properties)) { + + // Prepare the pattern to be matched. + // Make sure we always deal with an array (string is converted). + $properties[$propertyName] = (array) $properties[$propertyName]; + + foreach ($properties[$propertyName] as $propertyMatchString) { + + $propertyPattern = str_replace('[VER]', self::VER, $propertyMatchString); + + // Escape the special character which is the delimiter. + $propertyPattern = str_replace('/', '\/', $propertyPattern); + + // Identify and extract the version. + preg_match('/'.$propertyPattern.'/is', $this->userAgent, $match); + + if (!empty($match[1])) { + $version = ( $type == self::VERSION_TYPE_FLOAT ? $this->prepareVersionNo($match[1]) : $match[1] ); + + return $version; + } + + } + + } + + return false; + } + + /** + * Retrieve the mobile grading, using self::MOBILE_GRADE_* constants. + * + * @return string One of the self::MOBILE_GRADE_* constants. + */ + public function mobileGrade() + { + $isMobile = $this->isMobile(); + + if ( + // Apple iOS 4-7.0 – Tested on the original iPad (4.3 / 5.0), iPad 2 (4.3 / 5.1 / 6.1), iPad 3 (5.1 / 6.0), iPad Mini (6.1), iPad Retina (7.0), iPhone 3GS (4.3), iPhone 4 (4.3 / 5.1), iPhone 4S (5.1 / 6.0), iPhone 5 (6.0), and iPhone 5S (7.0) + $this->isIOS() && $this->version('iPad', self::VERSION_TYPE_FLOAT)>=4.3 || + $this->isIOS() && $this->version('iPhone', self::VERSION_TYPE_FLOAT)>=4.3 || + $this->isIOS() && $this->version('iPod', self::VERSION_TYPE_FLOAT)>=4.3 || + + // Android 2.1-2.3 - Tested on the HTC Incredible (2.2), original Droid (2.2), HTC Aria (2.1), Google Nexus S (2.3). Functional on 1.5 & 1.6 but performance may be sluggish, tested on Google G1 (1.5) + // Android 3.1 (Honeycomb) - Tested on the Samsung Galaxy Tab 10.1 and Motorola XOOM + // Android 4.0 (ICS) - Tested on a Galaxy Nexus. Note: transition performance can be poor on upgraded devices + // Android 4.1 (Jelly Bean) - Tested on a Galaxy Nexus and Galaxy 7 + ( $this->version('Android', self::VERSION_TYPE_FLOAT)>2.1 && $this->is('Webkit') ) || + + // Windows Phone 7.5-8 - Tested on the HTC Surround (7.5), HTC Trophy (7.5), LG-E900 (7.5), Nokia 800 (7.8), HTC Mazaa (7.8), Nokia Lumia 520 (8), Nokia Lumia 920 (8), HTC 8x (8) + $this->version('Windows Phone OS', self::VERSION_TYPE_FLOAT)>=7.5 || + + // Tested on the Torch 9800 (6) and Style 9670 (6), BlackBerry® Torch 9810 (7), BlackBerry Z10 (10) + $this->is('BlackBerry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)>=6.0 || + // Blackberry Playbook (1.0-2.0) - Tested on PlayBook + $this->match('Playbook.*Tablet') || + + // Palm WebOS (1.4-3.0) - Tested on the Palm Pixi (1.4), Pre (1.4), Pre 2 (2.0), HP TouchPad (3.0) + ( $this->version('webOS', self::VERSION_TYPE_FLOAT)>=1.4 && $this->match('Palm|Pre|Pixi') ) || + // Palm WebOS 3.0 - Tested on HP TouchPad + $this->match('hp.*TouchPad') || + + // Firefox Mobile 18 - Tested on Android 2.3 and 4.1 devices + ( $this->is('Firefox') && $this->version('Firefox', self::VERSION_TYPE_FLOAT)>=18 ) || + + // Chrome for Android - Tested on Android 4.0, 4.1 device + ( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT)>=4.0 ) || + + // Skyfire 4.1 - Tested on Android 2.3 device + ( $this->is('Skyfire') && $this->version('Skyfire', self::VERSION_TYPE_FLOAT)>=4.1 && $this->is('AndroidOS') && $this->version('Android', self::VERSION_TYPE_FLOAT)>=2.3 ) || + + // Opera Mobile 11.5-12: Tested on Android 2.3 + ( $this->is('Opera') && $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT)>=11.5 && $this->is('AndroidOS') ) || + + // Meego 1.2 - Tested on Nokia 950 and N9 + $this->is('MeeGoOS') || + + // Tizen (pre-release) - Tested on early hardware + $this->is('Tizen') || + + // Samsung Bada 2.0 - Tested on a Samsung Wave 3, Dolphin browser + // @todo: more tests here! + $this->is('Dolfin') && $this->version('Bada', self::VERSION_TYPE_FLOAT)>=2.0 || + + // UC Browser - Tested on Android 2.3 device + ( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android', self::VERSION_TYPE_FLOAT)>=2.3 ) || + + // Kindle 3 and Fire - Tested on the built-in WebKit browser for each + ( $this->match('Kindle Fire') || + $this->is('Kindle') && $this->version('Kindle', self::VERSION_TYPE_FLOAT)>=3.0 ) || + + // Nook Color 1.4.1 - Tested on original Nook Color, not Nook Tablet + $this->is('AndroidOS') && $this->is('NookTablet') || + + // Chrome Desktop 16-24 - Tested on OS X 10.7 and Windows 7 + $this->version('Chrome', self::VERSION_TYPE_FLOAT)>=16 && !$isMobile || + + // Safari Desktop 5-6 - Tested on OS X 10.7 and Windows 7 + $this->version('Safari', self::VERSION_TYPE_FLOAT)>=5.0 && !$isMobile || + + // Firefox Desktop 10-18 - Tested on OS X 10.7 and Windows 7 + $this->version('Firefox', self::VERSION_TYPE_FLOAT)>=10.0 && !$isMobile || + + // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 + $this->version('IE', self::VERSION_TYPE_FLOAT)>=7.0 && !$isMobile || + + // Opera Desktop 10-12 - Tested on OS X 10.7 and Windows 7 + $this->version('Opera', self::VERSION_TYPE_FLOAT)>=10 && !$isMobile + ){ + return self::MOBILE_GRADE_A; + } + + if ( + $this->isIOS() && $this->version('iPad', self::VERSION_TYPE_FLOAT)<4.3 || + $this->isIOS() && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<4.3 || + $this->isIOS() && $this->version('iPod', self::VERSION_TYPE_FLOAT)<4.3 || + + // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 + $this->is('Blackberry') && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)>=5 && $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<6 || + + //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 + ($this->version('Opera Mini', self::VERSION_TYPE_FLOAT)>=5.0 && $this->version('Opera Mini', self::VERSION_TYPE_FLOAT)<=7.0 && + ($this->version('Android', self::VERSION_TYPE_FLOAT)>=2.3 || $this->is('iOS')) ) || + + // Nokia Symbian^3 - Tested on Nokia N8 (Symbian^3), C7 (Symbian^3), also works on N97 (Symbian^1) + $this->match('NokiaN8|NokiaC7|N97.*Series60|Symbian/3') || + + // @todo: report this (tested on Nokia N71) + $this->version('Opera Mobi', self::VERSION_TYPE_FLOAT)>=11 && $this->is('SymbianOS') + ){ + return self::MOBILE_GRADE_B; + } + + if ( + // Blackberry 4.x - Tested on the Curve 8330 + $this->version('BlackBerry', self::VERSION_TYPE_FLOAT)<=5.0 || + // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) + $this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile', self::VERSION_TYPE_FLOAT)<=5.2 || + + // Tested on original iPhone (3.1), iPhone 3 (3.2) + $this->isIOS() && $this->version('iPad', self::VERSION_TYPE_FLOAT)<=3.2 || + $this->isIOS() && $this->version('iPhone', self::VERSION_TYPE_FLOAT)<=3.2 || + $this->isIOS() && $this->version('iPod', self::VERSION_TYPE_FLOAT)<=3.2 || + + // Internet Explorer 7 and older - Tested on Windows XP + $this->version('IE', self::VERSION_TYPE_FLOAT)<=7.0 && !$isMobile + ){ + return self::MOBILE_GRADE_C; + } + + //All older smartphone platforms and featurephones - Any device that doesn't support media queries + //will receive the basic, C grade experience. + return self::MOBILE_GRADE_C; + } +} diff --git a/core/um-actions-ajax.php b/core/um-actions-ajax.php index f25b34aa..d3594827 100644 --- a/core/um-actions-ajax.php +++ b/core/um-actions-ajax.php @@ -16,4 +16,69 @@ files->delete_core_user_photo( $user_id, 'profile_photo' ); + + } + + /*** + *** @remove cover photo silently + ***/ + add_action('wp_ajax_nopriv_ultimatemember_delete_cover_photo', 'ultimatemember_delete_cover_photo'); + add_action('wp_ajax_ultimatemember_delete_cover_photo', 'ultimatemember_delete_cover_photo'); + function ultimatemember_delete_cover_photo(){ + global $ultimatemember; + extract($_REQUEST); + + if ( !um_can_edit_profile( $user_id ) ) die( __('You can not edit this user') ); + + $ultimatemember->files->delete_core_user_photo( $user_id, 'cover_photo' ); + + } + + /*** + *** @resampling/crop images + ***/ + add_action('wp_ajax_nopriv_ultimatemember_resize_image', 'ultimatemember_resize_image'); + add_action('wp_ajax_ultimatemember_resize_image', 'ultimatemember_resize_image'); + function ultimatemember_resize_image(){ + global $ultimatemember; + $output = 0; + + extract($_REQUEST); + + if ( !isset($src) || !isset($coord) ) die( __('Invalid parameters') ); + + $coord_n = substr_count($coord, ","); + if ( $coord_n != 3 ) die( __('Invalid coordinates') ); + + $um_is_temp_image = um_is_temp_image( $src ); + if ( !$um_is_temp_image ) die( __('Invalid Image file') ); + + $crop = explode(',', $coord ); + $crop = array_map('intval', $crop); + + $uri = $ultimatemember->files->resize_image( $um_is_temp_image, $crop ); + + // If you're updating a user + if ( isset( $user_id ) && $user_id > 0 ) { + $uri = $ultimatemember->files->new_user_upload( $user_id, $um_is_temp_image, $key ); + } + + $output = $uri; + + if(is_array($output)){ print_r($output); }else{ echo $output; } die; + } \ No newline at end of file diff --git a/core/um-actions-members.php b/core/um-actions-members.php index 43540b93..1ae59a5c 100644 --- a/core/um-actions-members.php +++ b/core/um-actions-members.php @@ -191,6 +191,8 @@ if ( um_members('users_per_page') ) { + $default_size = str_replace( 'px', '', um_get_option('profile_photosize') ); + ?>
@@ -202,13 +204,13 @@
-
-
+
+
-
+
diff --git a/core/um-actions-profile.php b/core/um-actions-profile.php index b7590eb5..bf22087b 100644 --- a/core/um-actions-profile.php +++ b/core/um-actions-profile.php @@ -46,21 +46,62 @@ add_action('um_profile_header_cover_area', 'um_profile_header_cover_area' ); function um_profile_header_cover_area( $args ) { global $ultimatemember; - + if ( $args['cover_enabled'] == 1 ) { + $overlay = ' + + + + '.__('Change your cover photo').' + + + '; + ?> - -
+ +
+ + menu->new_ui( 'bc', 'div.um-cover', 'click', array( + ''.__('Change cover photo','ultimatemember').'', + ''.__('Remove','ultimatemember').'', + ''.__('Cancel','ultimatemember').'', + ), 'can_edit_user' ); + + ?> + + fields->add_hidden_field( 'cover_photo' ); ?> + + +
- - + + + + mobile->isMobile() ){ + echo um_user('cover_photo', 300); + } else { + echo um_user('cover_photo', 1000); + } + + ?> + + + + + +
+
- + + + + '.__('Change your profile photo').' + + + '; + ?>
-
- +
+ + + + fields->add_hidden_field( 'profile_photo' ); + + if ( !um_profile('profile_photo') ) { // has profile photo + + echo $ultimatemember->menu->new_ui( 'bc', 'div.um-profile-photo', 'click', array( + ''.__('Upload photo','ultimatemember').'', + ''.__('Cancel','ultimatemember').'', + ), 'can_edit_user' ); + + } else if ( $ultimatemember->fields->editing == true ) { + + echo $ultimatemember->menu->new_ui( 'bc', 'div.um-profile-photo', 'click', array( + ''.__('Change photo','ultimatemember').'', + ''.__('Remove photo','ultimatemember').'', + ''.__('Cancel','ultimatemember').'', + ), 'can_edit_user' ); + + } + + } + + ?> +
@@ -95,15 +176,15 @@
+
- Chief Executive Officer of Ultimate Member - - 28 Years Old - - United Kingdom + + profile->show_meta( $args['metafields'] ); ?> +
- - + + +
@@ -161,9 +242,9 @@ if ( isset( $ultimatemember->user->cannot_edit ) && $ultimatemember->user->cannot_edit == 1 ) return; if ( $ultimatemember->fields->editing == true ) { - $output .= '
'; + $output .= '
'; } else { - $output .= '
'; + $output .= '
'; } echo $output; diff --git a/core/um-builtin.php b/core/um-builtin.php index 074a6246..007f2566 100644 --- a/core/um-builtin.php +++ b/core/um-builtin.php @@ -520,6 +520,31 @@ class UM_Builtin { 'placeholder' => 'Enter a bit about yourself...', ), + 'profile_photo' => array( + 'title' => 'Profile Photo', + 'metakey' => 'profile_photo', + 'type' => 'image', + 'label' => 'Change your profile photo', + 'upload_text' => 'Upload your photo here', + 'icon' => 'um-icon-camera-5', + 'crop' => 1, + 'min_width' => str_replace('px','',um_get_option('profile_photosize')), + 'min_height' => str_replace('px','',um_get_option('profile_photosize')), + ), + + 'cover_photo' => array( + 'title' => 'Cover Photo', + 'metakey' => 'cover_photo', + 'type' => 'image', + 'label' => 'Change your cover photo', + 'upload_text' => 'Upload profile cover here', + 'icon' => 'um-icon-photo-2', + 'crop' => 2, + 'modal_size' => 'large', + 'ratio' => str_replace(':1','',um_get_option('profile_cover_ratio')), + 'min_width' => 1000, + ), + 'birth_date' => array( 'title' => 'Birth Date', 'metakey' => 'birth_date', diff --git a/core/um-fields.php b/core/um-fields.php index 5da36579..5d1dcfb1 100644 --- a/core/um-fields.php +++ b/core/um-fields.php @@ -11,6 +11,27 @@ class UM_Fields { } + /*** + *** @hidden fields inside shortcode + ***/ + function add_hidden_field( $field ) { + global $ultimatemember; + echo '
'; + + $fields = $ultimatemember->builtin->get_specific_fields( $field ); + + $output = null; + + foreach( $fields as $key => $data ) { + $output .= $ultimatemember->fields->edit_field( $key, $data ); + } + + echo $output; + + echo '
'; + + } + /*** *** @detect if we're editing profile in shortcode ***/ @@ -221,13 +242,23 @@ class UM_Fields { $output = null; $output .= '
'; - if ( isset($data['icon']) && $data['icon'] != '' && ( $this->field_icons == 'label' || $this->viewing == true ) ) { + if ( isset($data['icon']) && $data['icon'] != '' && isset( $this->field_icons ) && ( $this->field_icons == 'label' || $this->viewing == true ) ) { $output .= '
'; } $output .= ''; - if ( isset( $data['help'] ) && $this->viewing == false ) {$output .= '';} + if ( isset( $data['help'] ) && !empty( $data['help'] ) && $this->viewing == false ) { + + if ( !$ultimatemember->mobile->isMobile() ) { + $output .= ''; + } + + if ( $ultimatemember->mobile->isMobile() ) { + $output .= ''. $data['help'] . ''; + } + + } $output .= '
'; @@ -260,7 +291,7 @@ class UM_Fields { $classes .= 'um-timepicker '; } - if ( isset($data['icon']) && $this->field_icons == 'field' ) { + if ( isset($data['icon']) && $data['icon'] && $this->field_icons == 'field' ) { $classes .= 'um-iconed'; } @@ -594,7 +625,29 @@ class UM_Fields { case 'image': if ( !isset( $array['crop'] ) ) $array['crop'] = 0; - + + if ( $array['crop'] == 0 ) { + $array['crop_data'] = 0; + } else if ( $array['crop'] == 1 ) { + $array['crop_data'] = 'square'; + } else if ( $array['crop'] == 2 ) { + $array['crop_data'] = 'cover'; + } else { + $array['crop_data'] = 'user'; + } + + if ( !isset( $array['modal_size'] ) ) $array['modal_size'] = 'normal'; + + if ( $array['crop'] > 0 ) { + $array['crop_class'] = 'crop'; + } else { + $array['crop_class'] = ''; + } + + if ( !isset( $array['ratio'] ) ) $array['ratio'] = 1.0; + if ( !isset( $array['min_width'] ) ) $array['min_width'] = ''; + if ( !isset( $array['min_height'] ) ) $array['min_height'] = ''; + if (!isset($array['invalid_image'])) $array['invalid_image'] = "Please upload a valid image!"; if (!isset($array['allowed_types'])) { $array['allowed_types'] = "gif,jpg,jpeg,png"; @@ -615,6 +668,8 @@ class UM_Fields { case 'file': + if ( !isset( $array['modal_size'] ) ) $array['modal_size'] = 'normal'; + if (!isset($array['allowed_types'])) { $array['allowed_types'] = "pdf,txt"; } else { @@ -685,7 +740,7 @@ class UM_Fields { $output .= '
'; - if ( isset($icon) && $this->field_icons == 'field' ) { + if ( isset($icon) && $icon && $this->field_icons == 'field' ) { $output .= '
'; @@ -719,7 +774,7 @@ class UM_Fields { $output .= '
'; - if ( isset($icon) && $this->field_icons == 'field' ) { + if ( isset($icon) && $icon && $this->field_icons == 'field' ) { $output .= '
'; @@ -748,7 +803,7 @@ class UM_Fields { $output .= '
'; - if ( isset($icon) && $this->field_icons == 'field' ) { + if ( isset($icon) && $icon && $this->field_icons == 'field' ) { $output .= '
'; @@ -782,7 +837,7 @@ class UM_Fields { $output .= '
'; - if ( isset($icon) && $this->field_icons == 'field' ) { + if ( isset($icon) && $icon && $this->field_icons == 'field' ) { $output .= '
'; @@ -809,7 +864,7 @@ class UM_Fields { $output .= '
'; - if ( isset($icon) && $this->field_icons == 'field' ) { + if ( isset($icon) && $icon && $this->field_icons == 'field' ) { $output .= '
'; @@ -842,7 +897,7 @@ class UM_Fields { $output .= '
'; - if ( isset($icon) && $this->field_icons == 'field' ) { + if ( isset($icon) && $icon && $this->field_icons == 'field' ) { $output .= '
'; @@ -870,7 +925,7 @@ class UM_Fields { $output .= '
'; - if ( isset($icon) && $this->field_icons == 'field' ) { + if ( isset($icon) && $icon && $this->field_icons == 'field' ) { $output .= '
'; @@ -898,7 +953,7 @@ class UM_Fields { $output .= '
'; - if ( isset($icon) && $this->field_icons == 'field' ) { + if ( isset($icon) && $icon && $this->field_icons == 'field' ) { $output .= '
'; @@ -977,19 +1032,13 @@ class UM_Fields { $output .= $this->field_label($label, $key, $data); } - if ( $crop ) { - $crop_class = 'crop'; - } else { - $crop_class = ''; - } - $modal_label = ( isset( $data['label'] ) ) ? $data['label'] : __('Upload Photo','ultimatemember'); $output .= ''; @@ -1000,12 +1049,20 @@ class UM_Fields { $output .= '
'; - $output .= '
'; - $output .= '
'.$button_text.'
'; + if ( isset( $this->set_id ) ) { + $set_id = $this->set_id; + $set_mode = $this->set_mode; + } else { + $set_id = 0; + $set_mode = ''; + } + + $output .= '
'; + $output .= '
'.$button_text.'
'; $output .= ''; - $output .= '
'; break; /* Select dropdown */ @@ -1323,7 +1417,9 @@ class UM_Fields { } // Custom filter for field output + if ( isset( $this->set_mode ) ) { $output = apply_filters("um_{$key}_form_edit_field", $output, $this->set_mode); + } return $output; } diff --git a/core/um-files.php b/core/um-files.php index a4589f32..f4b631d4 100644 --- a/core/um-files.php +++ b/core/um-files.php @@ -89,29 +89,20 @@ class UM_Files { $this->upload_dir = wp_upload_dir(); $this->upload_basedir = $this->upload_dir['basedir'] . '/ultimatemember/'; - $this->upload_baseurl = $this->upload_dir['baseurl'] . '/ultimatemember/'; + + $this->upload_temp = $this->upload_basedir . 'temp/'; + $this->upload_temp_url = $this->upload_baseurl . 'temp/'; - // create plugin uploads directory if (!file_exists( $this->upload_basedir )) { @mkdir( $this->upload_basedir, 0777, true); } + + if (!file_exists( $this->upload_temp )) { + @mkdir( $this->upload_temp , 0777, true); + } } - - /*** - *** @Return upload directory - ***/ - function upload_dir(){ - return $this->upload_basedir; - } - - /*** - *** @Return upload URL - ***/ - function upload_url(){ - return $this->upload_baseurl; - } /*** *** @Generate unique temp directory @@ -119,34 +110,41 @@ class UM_Files { function unique_dir(){ global $ultimatemember; $unique_number = $ultimatemember->validation->generate(); - $array['dir'] = $this->upload_basedir . 'temp/'. $unique_number . '/'; - $array['url'] = $this->upload_baseurl . 'temp/'. $unique_number . '/'; + $array['dir'] = $this->upload_temp . $unique_number . '/'; + $array['url'] = $this->upload_temp_url . $unique_number . '/'; return $array; } /*** - *** @Fix image orientation + *** @get path only without file name ***/ - function fix_image_orientation(&$image, $source){ + function path_only( $file ) { + return trailingslashit( dirname( $file ) ); + } + + /*** + *** @fix image orientation + ***/ + function fix_image_orientation($rotate, $source){ $exif = @exif_read_data($source); if (isset($exif['Orientation'])) { switch ($exif['Orientation']) { case 3: - $image = imagerotate($image, 180, 0); + $rotate = imagerotate($rotate, 180, 0); break; case 6: - $image = imagerotate($image, -90, 0); + $rotate = imagerotate($rotate, -90, 0); break; case 8: - $image = imagerotate($image, 90, 0); + $rotate = imagerotate($rotate, 90, 0); break; } } - return $image; + return $rotate; } /*** @@ -154,7 +152,7 @@ class UM_Files { ***/ function create_and_copy_image($source, $destination, $quality = 100) { - $info = getimagesize($source); + $info = @getimagesize($source); if ($info['mime'] == 'image/jpeg'){ @@ -169,11 +167,26 @@ class UM_Files { $image = imagecreatefrompng($source); } + + list($w, $h) = @getimagesize( $source ); + if ( $w > um_get_option('image_max_width') ) { - $this->fix_image_orientation($image, $source); + $ratio = round( $w / $h, 2 ); + $new_w = um_get_option('image_max_width'); + $new_h = round( $new_w / $ratio, 2 ); + + $image_p = imagecreatetruecolor( $new_w, $new_h ); + imagecopyresampled( $image_p, $image, 0, 0, 0, 0, $new_w, $new_h, $w, $h ); + $image_p = $this->fix_image_orientation($image_p, $source); + imagejpeg( $image_p, $destination, $quality); - imagejpeg($image, $destination, $quality); - + } else { + + $image = $this->fix_image_orientation($image, $source); + imagejpeg( $image, $destination, $quality); + + } + } /*** @@ -292,6 +305,10 @@ class UM_Files { $error = $data['extension_error']; } elseif ( isset($data['min_size']) && ( $fileinfo['size'] < $data['min_size'] ) ) { $error = $data['min_size_error']; + } elseif ( isset($data['min_width']) && ( $fileinfo['width'] < $data['min_width'] ) ) { + $error = sprintf(__('Your photo is too small. It must be at least %spx wide.'), $data['min_width']); + } elseif ( isset($data['min_height']) && ( $fileinfo['height'] < $data['min_height'] ) ) { + $error = sprintf(__('Your photo is too small. It must be at least %spx wide.'), $data['min_height']); } return $error; @@ -325,4 +342,142 @@ class UM_Files { return false; } + /*** + *** @delete a main user photo + ***/ + function delete_core_user_photo( $user_id, $type ) { + + delete_user_meta( $user_id, $type ); + + $dir = $this->upload_basedir . $user_id . '/'; + $prefix = $type; + chdir($dir); + $matches = glob($prefix.'*',GLOB_MARK); + + if( is_array($matches) && !empty($matches)) { + foreach($matches as $match) { + if( is_file($dir.$match) ) unlink($dir.$match); + } + } + + if ( count(glob("$dir/*")) === 0) { + rmdir( $dir ); + } + + } + + /*** + *** @resize a local image + ***/ + function resize_image( $file, $crop ) { + + $targ_x1 = $crop[0]; + $targ_y1 = $crop[1]; + $targ_x2 = $crop[2]; + $targ_y2 = $crop[3]; + + $img_r = imagecreatefromjpeg($file); + $dst_r = imagecreatetruecolor( $targ_x2, $targ_y2 ); + + imagecopy( $dst_r, $img_r, 0, 0, $targ_x1, $targ_y1, $targ_x2, $targ_y2 ); + imagejpeg( $dst_r, $this->path_only( $file ) . basename( $file ), 100); + + $split = explode('/ultimatemember/temp/', $file); + return $this->upload_temp_url . $split[1]; + + } + + /*** + *** @new user upload + ***/ + function new_user_upload( $user_id, $source, $key ) { + + // if he does not have uploads dir yet + if ( !file_exists( $this->upload_basedir . $user_id . '/' ) ) { + @mkdir( $this->upload_basedir . $user_id . '/' , 0777, true); + } + + // name and extension stuff + $source_name = basename( $source ); + + if ( $key == 'profile_photo' ) { + $source_name = 'profile_photo.jpg'; + } + + if ( $key == 'cover_photo' ) { + $source_name = 'cover_photo.jpg'; + } + + $ext = '.' . pathinfo($source_name, PATHINFO_EXTENSION); + $name = str_replace( $ext, '', $source_name ); + $filename = $name . $ext; + + // copy image + copy( $source, $this->upload_basedir . $user_id . '/' . $filename ); + + // thumbs + if ( $key == 'profile_photo' ) { + + list($w, $h) = @getimagesize( $source ); + + $sizes = um_get_option('photo_thumb_sizes'); + foreach( $sizes as $size ) { + + if ( file_exists( $this->upload_basedir . $user_id . '/' . $name . '-' . $size . $ext ) ) { + unlink( $this->upload_basedir . $user_id . '/' . $name . '-' . $size . $ext ); + } + + if ( $size < $w ) { + + $thumb_s = imagecreatefromjpeg( $source ); + $thumb = imagecreatetruecolor( $size, $size ); + imagecopyresampled( $thumb, $thumb_s, 0, 0, 0, 0, $size, $size, $w, $h ); + imagejpeg( $thumb, $this->upload_basedir . $user_id . '/' . $name . '-' . $size . $ext, 100); + + } + + } + + } + + if ( $key == 'cover_photo' ) { + + list($w, $h) = @getimagesize( $source ); + + $sizes = um_get_option('cover_thumb_sizes'); + foreach( $sizes as $size ) { + + $ratio = round( $w / $h, 2 ); + $height = round( $size / $ratio, 2 ); + + if ( file_exists( $this->upload_basedir . $user_id . '/' . $name . '-' . $size . $ext ) ) { + unlink( $this->upload_basedir . $user_id . '/' . $name . '-' . $size . $ext ); + } + + if ( $size < $w ) { + + $thumb_s = imagecreatefromjpeg( $source ); + $thumb = imagecreatetruecolor( $size, $height ); + imagecopyresampled( $thumb, $thumb_s, 0, 0, 0, 0, $size, $height, $w, $h ); + imagejpeg( $thumb, $this->upload_basedir . $user_id . '/' . $name . '-' . $size . $ext, 100); + + } + + } + + } + + // clean up temp + $dir = dirname( $source ); + unlink( $source ); + rmdir( $dir ); + + // update user's meta + update_user_meta( $user_id, $key, $filename ); + + // the url of upload + return $this->upload_baseurl . $user_id . '/' . $filename; + + } + } \ No newline at end of file diff --git a/core/um-filters-arguments.php b/core/um-filters-arguments.php index 6ae2b9d1..cf853b22 100644 --- a/core/um-filters-arguments.php +++ b/core/um-filters-arguments.php @@ -4,16 +4,23 @@ *** @filter for shortcode args ***/ add_filter('um_shortcode_args_filter', 'um_shortcode_args_filter', 99); - function um_shortcode_args_filter( $array ) { + function um_shortcode_args_filter( $args ) { global $ultimatemember; - - // checks for message mode + if ($ultimatemember->shortcodes->message_mode == true) { - $array['template'] = 'message'; + $args['template'] = 'message'; $ultimatemember->shortcodes->custom_message = um_user( um_user('status') . '_message' ); um_reset_user(); } - return $array; + foreach( $args as $k => $v ) { + if ( $ultimatemember->validation->is_serialized( $args[$k] ) ) { + if ( !empty( $args[$k] ) ) { + $args[$k] = unserialize( $args[$k] ); + } + } + } + + return $args; } \ No newline at end of file diff --git a/core/um-filters-fields.php b/core/um-filters-fields.php index 37f80f4c..41cd1db5 100644 --- a/core/um-filters-fields.php +++ b/core/um-filters-fields.php @@ -11,7 +11,11 @@ $form_id = (isset ( $ultimatemember->fields->set_id ) ) ? $ultimatemember->fields->set_id : null; $mode = (isset( $ultimatemember->fields->set_mode ) ) ? $ultimatemember->fields->set_mode : null; + if ( $form_id && $mode ) { $array = $ultimatemember->query->get_attr('custom_fields', $form_id ); + } else { + $array = ''; + } return $array; diff --git a/core/um-filters-members.php b/core/um-filters-members.php index f9a170dd..4aadfa9e 100644 --- a/core/um-filters-members.php +++ b/core/um-filters-members.php @@ -1,23 +1,4 @@ $v ) { - if ( $ultimatemember->validation->is_serialized( $args[$k] ) ) { - if ( !empty( $args[$k] ) ) { - $args[$k] = unserialize( $args[$k] ); - } - } - } - - return $args; - } /*** *** @prepare the query args to show members diff --git a/core/um-menu.php b/core/um-menu.php new file mode 100644 index 00000000..2cfbfbfa --- /dev/null +++ b/core/um-menu.php @@ -0,0 +1,33 @@ + + +
+
+
+
    + $v ) { ?> + +
  • + + +
+
+
+ + ' . um_user( $k ) . ''; + $items[] = ''; + } + } + + if ( isset( $items ) ) { + array_pop($items); + foreach( $items as $item ) { + $output .= $item; + } + } + + return $output; + } + +} \ No newline at end of file diff --git a/core/um-setup.php b/core/um-setup.php index d8116908..3730773f 100644 --- a/core/um-setup.php +++ b/core/um-setup.php @@ -84,6 +84,7 @@ class UM_Setup { '_um_secondary_btn_color' => '#eee', '_um_secondary_btn_hover' => '#e5e5e5', '_um_secondary_btn_text' => '#666', + '_um_profile_show_bio' => 1, '_um_profile_role' => '0', '_um_profile_template' => 'profile', '_um_profile_max_width' => '1000px', diff --git a/core/um-short-functions.php b/core/um-short-functions.php index 7f55e2dd..b786095b 100644 --- a/core/um-short-functions.php +++ b/core/um-short-functions.php @@ -1,5 +1,40 @@ files->upload_temp . $url[1]; + + if ( !file_exists( $src ) ) + return false; + + list($width, $height, $type, $attr) = @getimagesize($src); + if ( isset( $width ) && isset( $height ) ) + return $src; + + } + return false; + } + /*** *** @Get core page url ***/ @@ -396,6 +431,56 @@ } } + /*** + *** @user uploads uri + ***/ + function um_user_uploads_uri() { + global $ultimatemember; + $uri = $ultimatemember->files->upload_baseurl . um_user('ID') . '/'; + return $uri; + } + + /*** + *** @get cover uri + ***/ + function um_get_cover_uri( $image, $attrs ) { + global $ultimatemember; + $uri = false; + if ( file_exists( $ultimatemember->files->upload_basedir . um_user('ID') . '/cover_photo.jpg' ) ) { + $uri = um_user_uploads_uri() . 'cover_photo.jpg?' . time(); + } + if ( file_exists( $ultimatemember->files->upload_basedir . um_user('ID') . '/cover_photo-' . $attrs. '.jpg' ) ){ + $uri = um_user_uploads_uri() . 'cover_photo-'.$attrs.'.jpg?' . time(); + } + return $uri; + } + + /*** + *** @get avatar uri + ***/ + function um_get_avatar_uri( $image, $attrs ) { + global $ultimatemember; + $uri = false; + if ( file_exists( $ultimatemember->files->upload_basedir . um_user('ID') . '/profile_photo.jpg' ) ) { + $uri = um_user_uploads_uri() . 'profile_photo.jpg?' . time(); + } + if ( file_exists( $ultimatemember->files->upload_basedir . um_user('ID') . '/profile_photo-' . $attrs. '.jpg' ) ){ + $uri = um_user_uploads_uri() . 'profile_photo-'.$attrs.'.jpg?' . time(); + } + return $uri; + } + + /*** + *** @default avatar + ***/ + function um_get_default_avatar_uri() { + $uri = um_get_option('default_avatar'); + $uri = $uri['url']; + if ( !$uri ) + $uri = um_url . 'assets/img/default_avatar.png'; + return $uri; + } + /*** *** @get user data ***/ @@ -526,24 +611,21 @@ case 'profile_photo': - $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'; + if ( um_profile('profile_photo') ) { + $avatar_uri = um_get_avatar_uri( um_profile('profile_photo'), $attrs ); + } else { + $avatar_uri = um_get_default_avatar_uri(); } - - $default_avatar_uri = um_url . 'assets/img/Dollarphotoclub_57189843.jpg'; - - return ''; + + return ''; break; case 'cover_photo': if ( um_profile('cover_photo') ) { - return ''; + $cover_uri = um_get_cover_uri( um_profile('cover_photo'), $attrs ); + return ''; } - return ''; break; } diff --git a/core/um-uninstall.php b/core/um-uninstall.php index 68a8b159..2f6b0a4e 100644 --- a/core/um-uninstall.php +++ b/core/um-uninstall.php @@ -14,9 +14,9 @@ class UM_Uninstall { foreach( wp_load_alloptions() as $k => $v ) { - if ( substr( $k, 0, 3 ) == 'um_' || substr( $k, 0, 3 ) == 'UM_' ) { + if ( substr( $k, 0, 3 ) == 'um_' ) { - if ( $k == 'um_core_forms' || $k == 'um_core_pages' || $k == 'um_core_directories' ) { + if ( $k == 'um_core_pages' ) { $v = unserialize( $v ); foreach( $v as $post_id ) { wp_delete_post( $post_id, 1 ); @@ -29,10 +29,14 @@ class UM_Uninstall { } + $forms = get_posts( array( 'post_type' => 'um_form', 'numberposts' => -1 ) ); + foreach( $forms as $form ) {wp_delete_post( $form->ID, 1 );} + + $directories = get_posts( array( 'post_type' => 'um_directory', 'numberposts' => -1 ) ); + foreach( $directories as $directory ) {wp_delete_post( $directory->ID, 1 );} + $roles = get_posts( array( 'post_type' => 'um_role', 'numberposts' => -1 ) ); - foreach( $roles as $role ) { - wp_delete_post( $role->ID, 1 ); - } + foreach( $roles as $role ) {wp_delete_post( $role->ID, 1 );} if ( is_plugin_active( um_plugin ) ) { deactivate_plugins( um_plugin ); diff --git a/templates/members.php b/templates/members.php index 4b0188d7..4241620b 100644 --- a/templates/members.php +++ b/templates/members.php @@ -2,8 +2,6 @@
- - diff --git a/templates/modal/um_upload_image.php b/templates/modal/um_upload_image.php deleted file mode 100644 index daa75ed8..00000000 --- a/templates/modal/um_upload_image.php +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/templates/modal/um_upload_single.php b/templates/modal/um_upload_single.php new file mode 100644 index 00000000..83e0abfa --- /dev/null +++ b/templates/modal/um_upload_single.php @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/um-config.php b/um-config.php index 6e071011..30a4815a 100644 --- a/um-config.php +++ b/um-config.php @@ -738,10 +738,30 @@ $this->sections[] = array( $this->sections[] = array( - 'icon' => 'um-icon-files', + 'icon' => 'um-icon-photo-2', 'title' => __( 'Image & File Uploads'), 'fields' => array( + array( + 'id' => 'photo_thumb_sizes', + 'type' => 'multi_text', + 'title' => __( 'Profile Photo Thumbnail Sizes' ), + 'desc' => __( 'Here you can define which thumbnail sizes will be created for each profile photo upload.' ), + 'default' => array( 40, 80, str_replace('px','',um_get_option('profile_photosize') ) ), + 'validate' => 'numeric', + 'add_text' => __('Add New Size'), + ), + + array( + 'id' => 'cover_thumb_sizes', + 'type' => 'multi_text', + 'title' => __( 'Cover Photo Thumbnail Sizes' ), + 'desc' => __( 'Here you can define which thumbnail sizes will be created for each cover photo upload.' ), + 'default' => array( 300, 600 ), + 'validate' => 'numeric', + 'add_text' => __('Add New Size'), + ), + array( 'id' => 'image_compression', 'type' => 'text', @@ -750,6 +770,15 @@ $this->sections[] = array( 'default' => 60, 'validate' => 'numeric', ), + + array( + 'id' => 'image_max_width', + 'type' => 'text', + 'title' => __( 'Image Upload Maximum Width' ), + 'desc' => __( 'Any image upload above this width will be resized to this limit automatically.' ), + 'default' => 1000, + 'validate' => 'numeric', + ), ) @@ -1163,6 +1192,14 @@ $this->sections[] = array( 'transparent' => false, ), + array( + 'id' => 'profile_show_bio', + 'type' => 'switch', + 'title' => __( 'Show user description in header' ), + 'default' => um_get_metadefault('profile_show_bio'), + 'desc' => 'Switch on/off the user description on profile header', + ), + ) ); diff --git a/um-init.php b/um-init.php index 0dd2818d..6e707f44 100644 --- a/um-init.php +++ b/um-init.php @@ -36,6 +36,7 @@ class UM_API { require_once um_path . 'core/um-fields.php'; require_once um_path . 'core/um-form.php'; require_once um_path . 'core/um-user.php'; + require_once um_path . 'core/um-profile.php'; require_once um_path . 'core/um-query.php'; require_once um_path . 'core/um-datetime.php'; require_once um_path . 'core/um-chart.php'; @@ -44,6 +45,7 @@ class UM_API { require_once um_path . 'core/um-taxonomies.php'; require_once um_path . 'core/um-validation.php'; require_once um_path . 'core/um-navmenu.php'; + require_once um_path . 'core/um-menu.php'; require_once um_path . 'core/um-access.php'; require_once um_path . 'core/um-permalinks.php'; require_once um_path . 'core/um-mail.php'; @@ -51,6 +53,8 @@ class UM_API { require_once um_path . 'core/um-logout.php'; require_once um_path . 'core/um-modal.php'; + require_once um_path . 'core/lib/mobiledetect/Mobile_Detect.php'; + require_once um_path . 'core/um-actions-form.php'; require_once um_path . 'core/um-actions-wpadmin.php'; require_once um_path . 'core/um-actions-core.php'; @@ -93,6 +97,7 @@ class UM_API { $this->register = new UM_Register(); $this->fields = new UM_Fields(); $this->user = new UM_User(); + $this->profile = new UM_Profile(); $this->datetime = new UM_DateTime(); $this->chart = new UM_Chart(); $this->builtin = new UM_Builtin(); @@ -101,12 +106,14 @@ class UM_API { $this->taxonomies = new UM_Taxonomies(); $this->validation = new UM_Validation(); $this->query = new UM_Query(); + $this->menu = new UM_Menu(); $this->access = new UM_Access(); $this->permalinks = new UM_Permalinks(); $this->mail = new UM_Mail(); $this->members = new UM_Members(); $this->logout = new UM_Logout(); $this->modal = new UM_Modal(); + $this->mobile = new Mobile_Detect; $this->options = get_option('um_options');