diff --git a/ajax-admin.php b/ajax-admin.php new file mode 100644 index 0000000..2d0ea24 --- /dev/null +++ b/ajax-admin.php @@ -0,0 +1,15 @@ +ID; + $id = $part1 . $part2; + $static_id = (int)($id); + update_post_meta( $static_id, '_propel_preference',"admin"); + +?> \ No newline at end of file diff --git a/ajax-personal.php b/ajax-personal.php new file mode 100644 index 0000000..52a5761 --- /dev/null +++ b/ajax-personal.php @@ -0,0 +1,15 @@ +ID; + $id = $part1 . $part2; + $static_id = (int)($id); + update_post_meta( $static_id, '_propel_preference',"personal"); + +?> \ No newline at end of file diff --git a/functions.php b/functions.php index 7f072dc..a81f120 100644 --- a/functions.php +++ b/functions.php @@ -1,4 +1,177 @@ ID; + $id = $part1 . $part2; + $static_id = (int)($id); + $postID = $_POST['postid']; + echo "ok!"; + update_post_meta($static_id,'_propel_toggle',$postID); + +} + +add_action('wp_ajax_update_toggle', 'update_toggle' ); + +function set_page_title($admin_title, $title){ + global $post; + if($post){ + if(get_post_type($post->ID) == 'propel_project' ){ + if(!$_GET['action']){ + return 'Propel > ' . 'All Projects'; + } else { + return 'Propel > ' . $post->post_title; + } + } + if(get_post_type($post->ID) == 'propel_task' ){ + $parent = get_post($post->post_parent); + if(!$_GET['action']){ + return 'Propel > ' . 'All Tasks'; + } else { + return 'Propel > ' . $parent->post_title . ' > ' . $post->post_title; + } + } + } +} + +add_filter('admin_title','set_page_title',10,2); + +function remove_box(){ + remove_meta_box('commentstatusdiv', 'propel_project','normal'); + remove_meta_box('commentstatusdiv', 'propel_task','normal'); +} + +add_filter('add_meta_boxes','remove_box'); + +function set_context(){ + $part1 = "889999999999"; + $current_user = wp_get_current_user(); + $part2 = $current_user->ID; + $id = $part1 . $part2; + $static_id = (int)($id); + if(isset($_REQUEST['context'])){ + if ($_REQUEST['context'] == 'admin'){ + update_post_meta( $static_id, '_propel_preference',"admin"); + } elseif ($_REQUEST['context'] == 'personal'){ + update_post_meta( $static_id, '_propel_preference',"personal"); + } + } +} +add_action( 'admin_init', 'set_context' ); + +function mytheme_admin_bar_render() { + global $wp_admin_bar; + global $url_curr; + global $wp; + $current_url = "http://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; + $current_url = str_replace("&context=personal", "", $current_url); + $current_url = str_replace("&context=admin", "", $current_url); + $current_url = str_replace("?context=personal", "", $current_url); + $current_url = str_replace("?context=admin", "", $current_url); + $and_char = strrpos($current_url, '&'); + $quest_char = strrpos($current_url, '?'); + if (($and_char === false) && ($quest_char === false)) { + $con = '?'; + } elseif ((($and_char === false) && ($quest_char !== false)) || + (($and_char !== false) && ($quest_char !== false))) { + $con = '&'; + } + $wp_admin_bar->remove_menu('updates'); + $part1 = "889999999999"; + $current_user = wp_get_current_user(); + $part2 = $current_user->ID; + $id = $part1 . $part2; + $static_id = (int)($id); + $profile = get_post_meta( $static_id, '_propel_preference',true); + if(empty($profile)){ + $title = "Context - Personal"; + } elseif($profile == 'personal'){ + $title = "Context - Personal"; + } elseif($profile == 'admin'){ + $title = "Context - Admin"; + } + + $wp_admin_bar->add_menu( array( + 'parent' => false, + 'id' => 'customer_support', + 'title' => __($title) + )); + + $contactUsURL = $current_url; + $wp_admin_bar->add_menu(array( + 'parent' => 'customer_support', + 'id' => 'adminpref', + 'title' => __('Admin'), + 'href' => $current_url . $con ."context=admin" + )); + + $contactUsURL = $current_url; + $wp_admin_bar->add_menu(array( + 'parent' => 'customer_support', + 'id' => 'personalpref', + 'title' => __('Personal'), + 'href' => $current_url .$con ."context=personal" + )); +} + +add_action( 'wp_before_admin_bar_render', 'mytheme_admin_bar_render' ); + +/* TASKS FOR SIGNED IN USERS ONLY aps2012 */ +function get_authored_posts($query) { + global $user_ID; + $u = get_userdata($user_ID); + $queried_post_type = get_query_var('post_type'); + $part1 = "889999999999"; + $current_user = wp_get_current_user(); + $part2 = $current_user->ID; + $id = $part1 . $part2; + $static_id = (int)($id); + $profile = get_post_meta( $static_id, '_propel_preference',true); + if(empty($profile)){ + $profile = "personal"; + } + if (('propel_task' == $queried_post_type ) && ($profile == 'personal' )) { + $taxquery = array( + array( + 'taxonomy' => 'author', + 'field' => 'name', + 'terms' => $u->user_login + ) + ); + $query->set('tax_query', $taxquery); + } + if (('propel_project' == $queried_post_type ) && ($profile == 'personal' )) { + $taxquery = array( + array( + 'taxonomy' => 'author', + 'field' => 'name', + 'terms' => $u->user_login + ) + ); + $query->set('tax_query', $taxquery); + } + return $query; +} +add_filter('pre_get_posts', 'get_authored_posts'); + + /* CURRENT PROJECTS */ function dashboard_client_current_projects_metabox() { @@ -54,21 +227,6 @@ function dashboard_client_archived_projects_content() { add_action('wp_dashboard_setup', 'dashboard_client_archived_projects_metabox'); -/* GANTT CHART */ -function dashboard_client_gantt_chart_metabox() { - - function dashboard_client_gantt_chart_content() { - echo " - Gannt Chart - "; - } - - wp_add_dashboard_widget( 'dashboard_client_gantt_chart_content', __( 'Timeline' ), 'dashboard_client_gantt_chart_content' ); - -} -add_action('wp_dashboard_setup', 'dashboard_client_gantt_chart_metabox'); - - /* SUPPORT REQUESTS */ function dashboard_client_support_requests_metabox() { @@ -86,55 +244,312 @@ function dashboard_client_support_requests_content() { +/* DASHBOARD METABOX THAT DISPLAYS PAST DUE TASKS */ +function Past_Due_Function() { - -function dashboard_widget_function() { + global $user_ID; + $u = get_userdata($user_ID); + $part1 = "889999999999"; + $current_user = wp_get_current_user(); + $part2 = $current_user->ID; + $id = $part1 . $part2; + $static_id = (int)($id); + $profile = get_post_meta( $static_id, '_propel_preference',true); + + if(empty($profile)){ + $profile = "personal"; + } + $args = array( 'numberposts' => -1, 'post_type' => 'propel_project', 'post_status' => 'publish' ); - $projects = get_posts( $args ); - echo ""; + + + $projects = get_posts( $args );?> +
+
+ + + +
'; + $display = 0; + if($profile == "personal"){ + $argv = array( 'numberposts' => -1, 'post_type' => 'propel_task', 'post_status' => 'publish', - 'post_parent' => $project->ID + 'post_parent' => $project->ID, + 'tax_query' => array( + array( + 'taxonomy' => 'author', + 'field' => 'name', + 'terms' => $u->user_login + ) + ) ); - $tasks = get_posts( $argv ); - + } else { + $argv = array( + 'numberposts' => -1, + 'post_type' => 'propel_task', + 'post_status' => 'publish', + 'post_parent' => $project->ID + ); + } + + $tasks = get_posts( $argv ); + foreach( $tasks as $task ) { + $progress = get_post_meta( $task->ID, '_propel_complete', true ); - echo ""; - echo ""; - echo ""; - echo ""; - echo ""; + $date = get_post_meta( $task->ID, '_propel_end_date', true ); + // check if complete + if ($progress != 100){ + if($date) { + + //echo date( get_option( 'date_format' ) , $date ); // Project's actual due date. + + $day = date('d'); // Day of the countdown + $month = date('m'); // Month of the countdown + $year = date('Y'); // Year of the countdown + $hour = date('H'); // Hour of the day (east coast time) + + $calculation = ( $date - time() ) / 3600; + $hours = (int)$calculation + 24; + $days = (int)( $hours / 24 ) - 1; + + $hours_remaining = $hours-($days*24)-24; + + if ( $hours < 0 && $hours > -24 ) { + if ($display == 0){ + $part1 = "8877779999999"; + $current_user = wp_get_current_user(); + $part2 = $current_user->ID; + $id = $part1 . $part2; + $static_id = (int)($id); + if ($taskhide = explode("/" , get_post_meta($static_id, _propel_toggle, true))){ + if (in_array($project->ID, $taskhide)) { + $pdtask = "class='pdue_tasks taskhide'"; + } else { + $pdtask = "class='pdue_tasks'"; + } + } else { + $pdtask = "class='pdue_tasks'"; + } + + echo " +
+ " + .$project->post_title. " +
+ +
+ "; + $display++; + } + echo "
+ " . $task->post_title . "
"; + echo "
+ " . str_replace( '-', '', $hours) + . " hours past due.
"; + } + + if ( $hours < -24 ) { + if ($display == 0){ + $part1 = "8877779999999"; + $current_user = wp_get_current_user(); + $part2 = $current_user->ID; + $id = $part1 . $part2; + $static_id = (int)($id); + if ($taskhide = explode("/" , get_post_meta($static_id, '_propel_toggle', true))){ + if (in_array($project->ID, $taskhide)) { + $pdtask = "class='pdue_tasks taskhide'"; + } else { + $pdtask = "class='pdue_tasks'"; + } + } else { + $pdtask = "class='pdue_tasks'"; + } + echo " +
+ " + .$project->post_title. " +
+
+ "; + $display++; + } + echo ""; + echo "
" + . str_replace( '-', '', $days) . " days past due.
"; + } + }// if date + }// if complete + } // foreach + echo '
'; + } + echo "
' . $project->post_title . '
" . $task->post_title . "
" . $progress . "%
"; +} + +function Past_Due_Hook() { + wp_add_dashboard_widget('pastdue_dashboard_widget', 'Past Due Tasks', 'Past_Due_Function'); +} +add_action('wp_dashboard_setup', 'Past_Due_Hook' ); + +/*---------------------- + +------------------------*/ +function Due_Today_Tomorrow_Function() { + global $user_ID; + $u = get_userdata($user_ID); + $part1 = "889999999999"; + $current_user = wp_get_current_user(); + $part2 = $current_user->ID; + $id = $part1 . $part2; + $static_id = (int)($id); + $profile = get_post_meta( $static_id, '_propel_preference',true); + if(empty($profile)){ + $profile = "personal"; + } + + $args = array( + 'numberposts' => -1, + 'post_type' => 'propel_project', + 'post_status' => 'publish' + ); + + $projects = get_posts( $args ); + + echo ""; + + foreach( $projects as $project ) { + $display = 0; + if($profile == "personal") { + $argv = array( + 'numberposts' => -1, + 'post_type' => 'propel_task', + 'post_status' => 'publish', + 'post_parent' => $project->ID, + 'tax_query' => array( + array( + 'taxonomy' => 'author', + 'field' => 'name', + 'terms' => $u->user_login + ) + ) + ); + } else { + $argv = array( + 'numberposts' => -1, + 'post_type' => 'propel_task', + 'post_status' => 'publish', + 'post_parent' => $project->ID + ); + } + + $tasks = get_posts( $argv ); + + if ( !isset($tasks) ) { + echo ''; + } + + foreach( $tasks as $task ) { + + $progress = get_post_meta( $task->ID, '_propel_complete', true ); + $date = get_post_meta( $task->ID, '_propel_end_date', true ); + if($date) { + + //echo date( get_option( 'date_format' ) , $date ); // Project's actual due date. + + $day = date('d'); // Day of the countdown + $month = date('m'); // Month of the countdown + $year = date('Y'); // Year of the countdown + $hour = date('H'); // Hour of the day (east coast time) + + $calculation = ( $date - time() ) / 3600; + $hours = (int)$calculation + 24; + $days = (int)( $hours / 24 ) - 1; + + $hours_remaining = $hours-($days*24)-24; + + if ( $hours <= 48 && $hours >= 24 ) { + if ($display == 0){ + echo ""; + $display++; + } + echo ""; + echo ""; + echo " "; + echo ""; + } + + if ( $hours <= 24 && $hours >= 0 ) { + if ($display == 0){ + echo ""; + $display++; + } + echo ""; + echo ""; + echo " "; + echo ""; + } + + } } } echo "
' . $project->post_title . '
" .$project->post_title. "
" . $task->post_title . "Due tomorrow.
" .$project->post_title. "
" . $task->post_title . "Due today.
"; -?> - -status = $status; $functions->args = $args; diff --git a/gen/ui.css b/gen/ui.css index 41f55b0..f898c45 100644 --- a/gen/ui.css +++ b/gen/ui.css @@ -1,115 +1,115 @@ -.gen-table { - background-color: #F9F9F9; - border-color: #DFDFDF; - border-radius: 3px; - border-spacing: 0; - border-style: solid; - border-width: 1px; - text-align: left; -} - -.gen-table thead tr { - background-color: #F1F1F1; -} - -.gen-table .gen-hidden { - display: none; -} -/* -.gen-table tbody:hover { - background-color: #F1F1F1; - cursor: pointer; -} -*/ - -.gen-table td { - border-top: 1px solid #DFDFDF; - padding-left: 10px; -} - -.gen-icon { - width: 24px; - text-align: center; -} - -.gen-icon a:hover { - opacity: 1; -} - -.gen-icon a { - text-align: center; - height: 16px; - margin-top: 1px; - opacity: 0.5; - text-indent: -9999px; - width: 16px; - display: block; - background-position: center; -} - -.gen-delete-icon a { - background: url('images/delete.png') no-repeat; -} - -.gen-edit-icon a { - background: url('images/edit.png') no-repeat; -} - -.gen-unchecked-icon a { - background: url('images/unchecked.png') no-repeat; -} - -.gen-checked-icon a { - background: url('images/checked.png') no-repeat; -} - -.gen-table th.sortable { - color: #000; - cursor: pointer; - text-decoration: underline; - padding-left: 10px; -} - - -.dataTables_length { - width: 40%; - float: left; - margin: 5px; -} - -.dataTables_filter { - width:30%; - float: right; - text-align: right; - margin: 5px; -} - -.dataTables_info { - width:40%; - float: left; - margin: 5px; - margin-top: 15px; -} - -.dataTables_paginate { - float: right; - text-align: right; - margin: 5px; - margin-top: 15px; -} - -.paginate_active, .paginate_button { - margin: 2px; - border: 1px solid lightGrey; - font-weight: normal; - color: #555; - padding: 4px; - cursor: pointer; - background: #E6E6E6; -} - -.paginate_active { - font-weight: bold; - border: 1px solid darkGrey; - +.gen-table { + background-color: #F9F9F9; + border-color: #DFDFDF; + border-radius: 3px; + border-spacing: 0; + border-style: solid; + border-width: 1px; + text-align: left; +} + +.gen-table thead tr { + background-color: #F1F1F1; +} + +.gen-table .gen-hidden { + display: none; +} +/* +.gen-table tbody:hover { + background-color: #F1F1F1; + cursor: pointer; +} +*/ + +.gen-table td { + border-top: 1px solid #DFDFDF; + padding-left: 10px; +} + +.gen-icon { + width: 24px; + text-align: center; +} + +.gen-icon a:hover { + opacity: 1; +} + +.gen-icon a { + text-align: center; + height: 16px; + margin-top: 1px; + opacity: 0.5; + text-indent: -9999px; + width: 16px; + display: block; + background-position: center; +} + +.gen-delete-icon a { + background: url('images/delete.png') no-repeat; +} + +.gen-edit-icon a { + background: url('images/edit.png') no-repeat; +} + +.gen-unchecked-icon a { + background: url('images/unchecked.png') no-repeat; +} + +.gen-checked-icon a { + background: url('images/checked.png') no-repeat; +} + +.gen-table th.sortable { + color: #000; + cursor: pointer; + text-decoration: underline; + padding-left: 10px; +} + + +.dataTables_length { + width: 40%; + float: left; + margin: 5px; +} + +.dataTables_filter { + width:30%; + float: right; + text-align: right; + margin: 5px; +} + +.dataTables_info { + width:40%; + float: left; + margin: 5px; + margin-top: 15px; +} + +.dataTables_paginate { + float: right; + text-align: right; + margin: 5px; + margin-top: 15px; +} + +.paginate_active, .paginate_button { + margin: 2px; + border: 1px solid lightGrey; + font-weight: normal; + color: #555; + padding: 4px; + cursor: pointer; + background: #E6E6E6; +} + +.paginate_active { + font-weight: bold; + border: 1px solid darkGrey; + } \ No newline at end of file diff --git a/images/attachment.png b/images/attachment.png new file mode 100644 index 0000000..0bd3eb1 Binary files /dev/null and b/images/attachment.png differ diff --git a/images/attachment2.png b/images/attachment2.png new file mode 100644 index 0000000..0301e51 Binary files /dev/null and b/images/attachment2.png differ diff --git a/images/comment-grey-bubble.png b/images/comment-grey-bubble.png new file mode 100644 index 0000000..558ee8f Binary files /dev/null and b/images/comment-grey-bubble.png differ diff --git a/images/x.png b/images/x.png new file mode 100644 index 0000000..744c503 Binary files /dev/null and b/images/x.png differ diff --git a/js/functions.js b/js/functions.js index 7ecbf4e..0f8f794 100644 --- a/js/functions.js +++ b/js/functions.js @@ -36,28 +36,6 @@ jQuery(document).ready(function($) { "aoColumns" : asdf }); - jQuery('.tasks-table tbody tr').click(function() { - if(jQuery('#details-' + jQuery(this).attr('id')).length > 0) { - jQuery('#details-' + jQuery(this).attr('id')).remove(); - } else { - id = jQuery(this).attr('id'); - jQuery(this).after('

 

'); - get_details(id); - - } - }); - - /* - $('.tasks-table tbody tr').hover( - function() { - console.log($(this).children(':first')); - $(this).children(':first').toggleClass('toggle-arrow'); - }, - function() { - $(this).children(':first').toggleClass('toggle-arrow'); - } - ); - */ } ); function get_details(id) { diff --git a/js/jquery-ui-sliderAccess.js b/js/jquery-ui-sliderAccess.js new file mode 100644 index 0000000..4c96bd5 --- /dev/null +++ b/js/jquery-ui-sliderAccess.js @@ -0,0 +1,85 @@ +/* + * jQuery UI Slider Access + * By: Trent Richardson [http://trentrichardson.com] + * Version 0.2 + * Last Modified: 12/02/2011 + * + * Copyright 2011 Trent Richardson + * Dual licensed under the MIT and GPL licenses. + * http://trentrichardson.com/Impromptu/GPL-LICENSE.txt + * http://trentrichardson.com/Impromptu/MIT-LICENSE.txt + * + */ + (function($){ + + $.fn.extend({ + sliderAccess: function(options){ + options = options || {}; + options.touchonly = options.touchonly !== undefined? options.touchonly : true; // by default only show it if touch device + + if(options.touchonly === true && !("ontouchend" in document)) + return $(this); + + return $(this).each(function(i,obj){ + var $t = $(this), + o = $.extend({},{ + where: 'after', + step: $t.slider('option','step'), + upIcon: 'ui-icon-plus', + downIcon: 'ui-icon-minus', + text: false, + upText: '+', + downText: '-', + buttonset: true, + buttonsetTag: 'span' + }, options), + $buttons = $('<'+ o.buttonsetTag +' class="ui-slider-access">'+ + ''+ + ''+ + ''); + + $buttons.children('button').each(function(j, jobj){ + var $jt = $(this); + $jt.button({ + text: o.text, + icons: { primary: $jt.data('icon') } + }) + .click(function(e){ + var step = $jt.data('step'), + curr = $t.slider('value'), + newval = curr += step*1, + minval = $t.slider('option','min'), + maxval = $t.slider('option','max'); + + e.preventDefault(); + + if(newval < minval || newval > maxval) + return; + + $t.slider('value', newval); + + $t.slider("option", "slide").call($t, null, { value: newval }); + }); + }); + + // before or after + $t[o.where]($buttons); + + if(o.buttonset){ + $buttons.removeClass('ui-corner-right').removeClass('ui-corner-left').buttonset(); + $buttons.eq(0).addClass('ui-corner-left'); + $buttons.eq(1).addClass('ui-corner-right'); + } + + // adjust the width so we don't break the original layout + var bOuterWidth = $buttons.css({ + marginLeft: (o.where == 'after'? 10:0), + marginRight: (o.where == 'before'? 10:0) + }).outerWidth(true) + 5; + var tOuterWidth = $t.outerWidth(true); + $t.css('display','inline-block').width(tOuterWidth-bOuterWidth); + }); + } + }); + +})(jQuery); \ No newline at end of file diff --git a/js/jquery-ui-timepicker-addon.js b/js/jquery-ui-timepicker-addon.js new file mode 100644 index 0000000..b533572 --- /dev/null +++ b/js/jquery-ui-timepicker-addon.js @@ -0,0 +1,1326 @@ +/* +* jQuery timepicker addon +* By: Trent Richardson [http://trentrichardson.com] +* Version 1.0.0 +* Last Modified: 02/05/2012 +* +* Copyright 2012 Trent Richardson +* Dual licensed under the MIT and GPL licenses. +* http://trentrichardson.com/Impromptu/GPL-LICENSE.txt +* http://trentrichardson.com/Impromptu/MIT-LICENSE.txt +* +* HERES THE CSS: +* .ui-timepicker-div .ui-widget-header { margin-bottom: 8px; } +* .ui-timepicker-div dl { text-align: left; } +* .ui-timepicker-div dl dt { height: 25px; margin-bottom: -25px; } +* .ui-timepicker-div dl dd { margin: 0 10px 10px 65px; } +* .ui-timepicker-div td { font-size: 90%; } +* .ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; } +*/ + +(function($) { + +// Prevent "Uncaught RangeError: Maximum call stack size exceeded" +$.ui.timepicker = $.ui.timepicker || {}; +if ($.ui.timepicker.version) { + return; +} + +$.extend($.ui, { timepicker: { version: "1.0.0" } }); + +/* Time picker manager. + Use the singleton instance of this class, $.timepicker, to interact with the time picker. + Settings for (groups of) time pickers are maintained in an instance object, + allowing multiple different settings on the same page. */ + +function Timepicker() { + this.regional = []; // Available regional settings, indexed by language code + this.regional[''] = { // Default regional settings + currentText: 'Now', + closeText: 'Done', + ampm: false, + amNames: ['AM', 'A'], + pmNames: ['PM', 'P'], + timeFormat: 'hh:mm tt', + timeSuffix: '', + timeOnlyTitle: 'Choose Time', + timeText: 'Time', + hourText: 'Hour', + minuteText: 'Minute', + secondText: 'Second', + millisecText: 'Millisecond', + timezoneText: 'Time Zone' + }; + this._defaults = { // Global defaults for all the datetime picker instances + showButtonPanel: true, + timeOnly: false, + showHour: true, + showMinute: true, + showSecond: false, + showMillisec: false, + showTimezone: false, + showTime: true, + stepHour: 1, + stepMinute: 1, + stepSecond: 1, + stepMillisec: 1, + hour: 0, + minute: 0, + second: 0, + millisec: 0, + timezone: '+0000', + hourMin: 0, + minuteMin: 0, + secondMin: 0, + millisecMin: 0, + hourMax: 23, + minuteMax: 59, + secondMax: 59, + millisecMax: 999, + minDateTime: null, + maxDateTime: null, + onSelect: null, + hourGrid: 0, + minuteGrid: 0, + secondGrid: 0, + millisecGrid: 0, + alwaysSetTime: true, + separator: ' ', + altFieldTimeOnly: true, + showTimepicker: true, + timezoneIso8609: false, + timezoneList: null, + addSliderAccess: false, + sliderAccessArgs: null + }; + $.extend(this._defaults, this.regional['']); +}; + +$.extend(Timepicker.prototype, { + $input: null, + $altInput: null, + $timeObj: null, + inst: null, + hour_slider: null, + minute_slider: null, + second_slider: null, + millisec_slider: null, + timezone_select: null, + hour: 0, + minute: 0, + second: 0, + millisec: 0, + timezone: '+0000', + hourMinOriginal: null, + minuteMinOriginal: null, + secondMinOriginal: null, + millisecMinOriginal: null, + hourMaxOriginal: null, + minuteMaxOriginal: null, + secondMaxOriginal: null, + millisecMaxOriginal: null, + ampm: '', + formattedDate: '', + formattedTime: '', + formattedDateTime: '', + timezoneList: null, + + /* Override the default settings for all instances of the time picker. + @param settings object - the new settings to use as defaults (anonymous object) + @return the manager object */ + setDefaults: function(settings) { + extendRemove(this._defaults, settings || {}); + return this; + }, + + //######################################################################## + // Create a new Timepicker instance + //######################################################################## + _newInst: function($input, o) { + var tp_inst = new Timepicker(), + inlineSettings = {}; + + for (var attrName in this._defaults) { + var attrValue = $input.attr('time:' + attrName); + if (attrValue) { + try { + inlineSettings[attrName] = eval(attrValue); + } catch (err) { + inlineSettings[attrName] = attrValue; + } + } + } + tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, o, { + beforeShow: function(input, dp_inst) { + if ($.isFunction(o.beforeShow)) + return o.beforeShow(input, dp_inst, tp_inst); + }, + onChangeMonthYear: function(year, month, dp_inst) { + // Update the time as well : this prevents the time from disappearing from the $input field. + tp_inst._updateDateTime(dp_inst); + if ($.isFunction(o.onChangeMonthYear)) + o.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst); + }, + onClose: function(dateText, dp_inst) { + if (tp_inst.timeDefined === true && $input.val() != '') + tp_inst._updateDateTime(dp_inst); + if ($.isFunction(o.onClose)) + o.onClose.call($input[0], dateText, dp_inst, tp_inst); + }, + timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker'); + }); + tp_inst.amNames = $.map(tp_inst._defaults.amNames, function(val) { return val.toUpperCase(); }); + tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function(val) { return val.toUpperCase(); }); + + if (tp_inst._defaults.timezoneList === null) { + var timezoneList = []; + for (var i = -11; i <= 12; i++) + timezoneList.push((i >= 0 ? '+' : '-') + ('0' + Math.abs(i).toString()).slice(-2) + '00'); + if (tp_inst._defaults.timezoneIso8609) + timezoneList = $.map(timezoneList, function(val) { + return val == '+0000' ? 'Z' : (val.substring(0, 3) + ':' + val.substring(3)); + }); + tp_inst._defaults.timezoneList = timezoneList; + } + + tp_inst.hour = tp_inst._defaults.hour; + tp_inst.minute = tp_inst._defaults.minute; + tp_inst.second = tp_inst._defaults.second; + tp_inst.millisec = tp_inst._defaults.millisec; + tp_inst.ampm = ''; + tp_inst.$input = $input; + + if (o.altField) + tp_inst.$altInput = $(o.altField) + .css({ cursor: 'pointer' }) + .focus(function(){ $input.trigger("focus"); }); + + if(tp_inst._defaults.minDate==0 || tp_inst._defaults.minDateTime==0) + { + tp_inst._defaults.minDate=new Date(); + } + if(tp_inst._defaults.maxDate==0 || tp_inst._defaults.maxDateTime==0) + { + tp_inst._defaults.maxDate=new Date(); + } + + // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime.. + if(tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) + tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime()); + if(tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) + tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime()); + if(tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) + tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime()); + if(tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) + tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime()); + return tp_inst; + }, + + //######################################################################## + // add our sliders to the calendar + //######################################################################## + _addTimePicker: function(dp_inst) { + var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ? + this.$input.val() + ' ' + this.$altInput.val() : + this.$input.val(); + + this.timeDefined = this._parseTime(currDT); + this._limitMinMaxDateTime(dp_inst, false); + this._injectTimePicker(); + }, + + //######################################################################## + // parse the time string from input value or _setTime + //######################################################################## + _parseTime: function(timeString, withDate) { + var regstr = this._defaults.timeFormat.toString() + .replace(/h{1,2}/ig, '(\\d?\\d)') + .replace(/m{1,2}/ig, '(\\d?\\d)') + .replace(/s{1,2}/ig, '(\\d?\\d)') + .replace(/l{1}/ig, '(\\d?\\d?\\d)') + .replace(/t{1,2}/ig, this._getPatternAmpm()) + .replace(/z{1}/ig, '(z|[-+]\\d\\d:?\\d\\d)?') + .replace(/\s/g, '\\s?') + this._defaults.timeSuffix + '$', + order = this._getFormatPositions(), + ampm = '', + treg; + + if (!this.inst) this.inst = $.datepicker._getInst(this.$input[0]); + + if (withDate || !this._defaults.timeOnly) { + // the time should come after x number of characters and a space. + // x = at least the length of text specified by the date format + var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat'); + // escape special regex characters in the seperator + var specials = new RegExp("[.*+?|()\\[\\]{}\\\\]", "g"); + regstr = '^.{' + dp_dateFormat.length + ',}?' + this._defaults.separator.replace(specials, "\\$&") + regstr; + } + + treg = timeString.match(new RegExp(regstr, 'i')); + + if (treg) { + if (order.t !== -1) { + if (treg[order.t] === undefined || treg[order.t].length === 0) { + ampm = ''; + this.ampm = ''; + } else { + ampm = $.inArray(treg[order.t].toUpperCase(), this.amNames) !== -1 ? 'AM' : 'PM'; + this.ampm = this._defaults[ampm == 'AM' ? 'amNames' : 'pmNames'][0]; + } + } + + if (order.h !== -1) { + if (ampm == 'AM' && treg[order.h] == '12') + this.hour = 0; // 12am = 0 hour + else if (ampm == 'PM' && treg[order.h] != '12') + this.hour = (parseFloat(treg[order.h]) + 12).toFixed(0); // 12pm = 12 hour, any other pm = hour + 12 + else this.hour = Number(treg[order.h]); + } + + if (order.m !== -1) this.minute = Number(treg[order.m]); + if (order.s !== -1) this.second = Number(treg[order.s]); + if (order.l !== -1) this.millisec = Number(treg[order.l]); + if (order.z !== -1 && treg[order.z] !== undefined) { + var tz = treg[order.z].toUpperCase(); + switch (tz.length) { + case 1: // Z + tz = this._defaults.timezoneIso8609 ? 'Z' : '+0000'; + break; + case 5: // +hhmm + if (this._defaults.timezoneIso8609) + tz = tz.substring(1) == '0000' + ? 'Z' + : tz.substring(0, 3) + ':' + tz.substring(3); + break; + case 6: // +hh:mm + if (!this._defaults.timezoneIso8609) + tz = tz == 'Z' || tz.substring(1) == '00:00' + ? '+0000' + : tz.replace(/:/, ''); + else if (tz.substring(1) == '00:00') + tz = 'Z'; + break; + } + this.timezone = tz; + } + + return true; + + } + return false; + }, + + //######################################################################## + // pattern for standard and localized AM/PM markers + //######################################################################## + _getPatternAmpm: function() { + var markers = [], + o = this._defaults; + if (o.amNames) + $.merge(markers, o.amNames); + if (o.pmNames) + $.merge(markers, o.pmNames); + markers = $.map(markers, function(val) { return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&'); }); + return '(' + markers.join('|') + ')?'; + }, + + //######################################################################## + // figure out position of time elements.. cause js cant do named captures + //######################################################################## + _getFormatPositions: function() { + var finds = this._defaults.timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|t{1,2}|z)/g), + orders = { h: -1, m: -1, s: -1, l: -1, t: -1, z: -1 }; + + if (finds) + for (var i = 0; i < finds.length; i++) + if (orders[finds[i].toString().charAt(0)] == -1) + orders[finds[i].toString().charAt(0)] = i + 1; + + return orders; + }, + + //######################################################################## + // generate and inject html for timepicker into ui datepicker + //######################################################################## + _injectTimePicker: function() { + var $dp = this.inst.dpDiv, + o = this._defaults, + tp_inst = this, + // Added by Peter Medeiros: + // - Figure out what the hour/minute/second max should be based on the step values. + // - Example: if stepMinute is 15, then minMax is 45. + hourMax = parseInt((o.hourMax - ((o.hourMax - o.hourMin) % o.stepHour)) ,10), + minMax = parseInt((o.minuteMax - ((o.minuteMax - o.minuteMin) % o.stepMinute)) ,10), + secMax = parseInt((o.secondMax - ((o.secondMax - o.secondMin) % o.stepSecond)) ,10), + millisecMax = parseInt((o.millisecMax - ((o.millisecMax - o.millisecMin) % o.stepMillisec)) ,10), + dp_id = this.inst.id.toString().replace(/([^A-Za-z0-9_])/g, ''); + + // Prevent displaying twice + //if ($dp.find("div#ui-timepicker-div-"+ dp_id).length === 0) { + if ($dp.find("div#ui-timepicker-div-"+ dp_id).length === 0 && o.showTimepicker) { + var noDisplay = ' style="display:none;"', + html = '
' + + '
' + o.timeText + '
' + + '
' + + '
' + o.hourText + '
', + hourGridSize = 0, + minuteGridSize = 0, + secondGridSize = 0, + millisecGridSize = 0, + size = null; + + // Hours + html += '
'; + if (o.showHour && o.hourGrid > 0) { + html += '
'; + + for (var h = o.hourMin; h <= hourMax; h += parseInt(o.hourGrid,10)) { + hourGridSize++; + var tmph = (o.ampm && h > 12) ? h-12 : h; + if (tmph < 10) tmph = '0' + tmph; + if (o.ampm) { + if (h == 0) tmph = 12 +'a'; + else if (h < 12) tmph += 'a'; + else tmph += 'p'; + } + html += ''; + } + + html += '
' + tmph + '
'; + } + html += '
'; + + // Minutes + html += '
' + o.minuteText + '
'+ + '
'; + + if (o.showMinute && o.minuteGrid > 0) { + html += '
'; + + for (var m = o.minuteMin; m <= minMax; m += parseInt(o.minuteGrid,10)) { + minuteGridSize++; + html += ''; + } + + html += '
' + ((m < 10) ? '0' : '') + m + '
'; + } + html += '
'; + + // Seconds + html += '
' + o.secondText + '
'+ + '
'; + + if (o.showSecond && o.secondGrid > 0) { + html += '
'; + + for (var s = o.secondMin; s <= secMax; s += parseInt(o.secondGrid,10)) { + secondGridSize++; + html += ''; + } + + html += '
' + ((s < 10) ? '0' : '') + s + '
'; + } + html += '
'; + + // Milliseconds + html += '
' + o.millisecText + '
'+ + '
'; + + if (o.showMillisec && o.millisecGrid > 0) { + html += '
'; + + for (var l = o.millisecMin; l <= millisecMax; l += parseInt(o.millisecGrid,10)) { + millisecGridSize++; + html += ''; + } + + html += '
' + ((l < 10) ? '0' : '') + l + '
'; + } + html += '
'; + + // Timezone + html += '
' + o.timezoneText + '
'; + html += '
'; + + html += '
'; + $tp = $(html); + + // if we only want time picker... + if (o.timeOnly === true) { + $tp.prepend( + '
' + + '
' + o.timeOnlyTitle + '
' + + '
'); + $dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide(); + } + + this.hour_slider = $tp.find('#ui_tpicker_hour_'+ dp_id).slider({ + orientation: "horizontal", + value: this.hour, + min: o.hourMin, + max: hourMax, + step: o.stepHour, + slide: function(event, ui) { + tp_inst.hour_slider.slider( "option", "value", ui.value); + tp_inst._onTimeChange(); + } + }); + + + // Updated by Peter Medeiros: + // - Pass in Event and UI instance into slide function + this.minute_slider = $tp.find('#ui_tpicker_minute_'+ dp_id).slider({ + orientation: "horizontal", + value: this.minute, + min: o.minuteMin, + max: minMax, + step: o.stepMinute, + slide: function(event, ui) { + tp_inst.minute_slider.slider( "option", "value", ui.value); + tp_inst._onTimeChange(); + } + }); + + this.second_slider = $tp.find('#ui_tpicker_second_'+ dp_id).slider({ + orientation: "horizontal", + value: this.second, + min: o.secondMin, + max: secMax, + step: o.stepSecond, + slide: function(event, ui) { + tp_inst.second_slider.slider( "option", "value", ui.value); + tp_inst._onTimeChange(); + } + }); + + this.millisec_slider = $tp.find('#ui_tpicker_millisec_'+ dp_id).slider({ + orientation: "horizontal", + value: this.millisec, + min: o.millisecMin, + max: millisecMax, + step: o.stepMillisec, + slide: function(event, ui) { + tp_inst.millisec_slider.slider( "option", "value", ui.value); + tp_inst._onTimeChange(); + } + }); + + this.timezone_select = $tp.find('#ui_tpicker_timezone_'+ dp_id).append('').find("select"); + $.fn.append.apply(this.timezone_select, + $.map(o.timezoneList, function(val, idx) { + return $("