♥Tsimi Posted September 11, 2014 Share Posted September 11, 2014 (edited) Hi Jonas Thanks for your reply! Me too, i don't use all functions since i don't need all of them. And if there are mini bugs i just go around them. ;) The basic functions work and that's what counts. I just meant it more to help you hunt down remaining bugs. Which most of them are browser related (stupid FF! <_< ) I don't think that there ever will be a 100% clean, bug free order editor unless it is a commercial add-on. Like i mentioned the effort and support you put in your add-ons is exceptional and deserves respect. Regarding Bug 4, very clever! Didn't think about it that way. Bug 5, i'll check it out. It is not a super vital function though. Thanks again and kind regards Lambros Edited September 11, 2014 by Tsimi Quote Link to comment Share on other sites More sharing options...
Dr. Rolex Posted September 11, 2014 Author Share Posted September 11, 2014 Hi Jonas Thanks for your reply! Me too, i don't use all functions since i don't need all of them. And if there are mini bugs i just go around them. ;) The basic functions work and that's what counts. I just meant it more to help you hunt down remaining bugs. Which most of them are browser related (stupid FF! <_< ) I really appreciate that you and others spend time to report bugs and give feedback. Without any response here on the forum I would quickly grow tired of making Add-Ons. So please do continue to report the mini bugs that you find. ha ha :thumbsup: I don't think that there ever will be a 100% clean, bug free order editor unless it is a commercial add-on. I have to say that I disagree, since when did commercial products outperform Open Source projects? :P I can't say that I'm very impressed with most of the commercial tools I use in my business, even though there are exceptions of course. They simply lack creativity and only have the absolutely base functionality which often leaves a lot to be desired .. I'm certain that there can be a 100% working order editor which fits all needs. This, of course, requires that there aren't any prior errors on the osC installation when the order editor is installed. It looks like a lot of people have broken/deprecated Javascript code from other Add-Ons which can and probably will break the order handler. I'll guess there's always a way of fixing that, like having a separate template_top file dedicated to the order handler without all the "muck". The biggest challenge is compatibility with all shipping/payment/order total modules. But I think I'm well on the way to solving this. A problem, of course, is that since (almost) nobody reports any mini bugs or problems, so then I have to assume that there aren't any. :rolleyes: Like i mentioned the effort and support you put in your add-ons is exceptional and deserves respect. Regarding Bug 4, very clever! Didn't think about it that way. Bug 5, i'll check it out. It is not a super vital function though. Thanks again and kind regards Lambros Glad I can be of help! I'll take a look at the invoice bug and see if I can give you a quick fix for it. Quote osC OpenSSL Encryption with jCryptionSupport Forum jQuery/Ajax Advanced Statistics 2.3Support Forum jQuery/Ajax Advanced Order Handler 2.3.3Support ForumjQuery/Ajax Advanced Caching System 2.3.3Support ForumjQuery/Ajax Fast checkout/Shopping Cart/Login/Create Account 2.3.3Support ForumjQuery/Ajax Shopping Cart 2.3.3Support ForumjQuery/Ajax Dynamic Checkout 2.3.3Support ForumjQuery/Ajax Mini Cart for osCommerce 2.3.3Support ForumjQuery Cycle What's New InfoboxAuto Out Of Stock CSS Image OverlayjQuery-UI Autocomplete Product Search with Links & MySQLi support for osCommerce 2.X Link to comment Share on other sites More sharing options...
Dr. Rolex Posted September 11, 2014 Author Share Posted September 11, 2014 Bug 1: Invoice function inside the footer menu outputs an empty invoice page. No customer info, no order details (except for order number and date), just the stylesheet is loaded nothing else. This doesn't happen if I click the jquery ui invoice button inside the order detail page where it loads the vanilla osC invoice. Tested with all three browsers. Same result. All right! Solution: find this code in ./admin/includes/modules/order_handler/general_functions.php $script = tep_catalog_href_link($script, (is_numeric($version) ? $version : ''), $connection); else $script = (($cookieless == true) ? HTTP_COOKIELESS_DOMAIN : '') . $script; if ($type == 'script') return '<script src="' . (($cookieless == true) ? HTTP_COOKIELESS_DOMAIN : '') . $script . '"></script>'; if ($type == 'link') return '<link rel="stylesheet" href="' . (($cookieless == true) ? HTTP_COOKIELESS_DOMAIN : '') . $script . '" />'; return "No link found"; } Replace With $script = tep_catalog_href_link($script, (is_numeric($version) ? $version : ''), $connection); else $script = (($cookieless == true) ? HTTP_COOKIELESS_DOMAIN : '') . $script; if ($type == 'script') return '<script src="' . (($cookieless == true) ? HTTP_COOKIELESS_DOMAIN : '') . $script . '"></script>'; if ($type == 'link') return '<link rel="stylesheet" href="' . (($cookieless == true) ? HTTP_COOKIELESS_DOMAIN : '') . $script . '" />'; return "No link found"; } function tep_address($address_format, $address, $html, $boln, $eoln, $skip_name = false) { $company = tep_output_string_protected($address['company']); if ( ! $skip_name ) { if (isset($address['firstname']) && tep_not_null($address['firstname'])) { $firstname = tep_output_string_protected($address['firstname']); $lastname = tep_output_string_protected($address['lastname']); } elseif (isset($address['name']) && tep_not_null($address['name'])) { $firstname = tep_output_string_protected($address['name']); $lastname = ''; } else { $firstname = ''; $lastname = ''; } } $street = tep_output_string_protected($address['street_address']); $suburb = tep_output_string_protected($address['suburb']); $city = tep_output_string_protected($address['city']); $state = tep_output_string_protected($address['state']); if (isset($address['country_id']) && tep_not_null($address['country_id'])) { $country = tep_get_country_name($address['country_id']); if (isset($address['zone_id']) && tep_not_null($address['zone_id'])) { $state = tep_get_zone_code($address['country_id'], $address['zone_id'], $state); } } elseif (isset($address['country']) && tep_not_null($address['country'])) { $country = tep_output_string_protected($address['country']); } else { $country = ''; } $postcode = tep_output_string_protected($address['postcode']); $zip = $postcode; if ($html) { // HTML Mode $HR = '<hr />'; $hr = '<hr />'; if ( ($boln == '') && ($eoln == "\n") ) { // Values not specified, use rational defaults $CR = '<br />'; $cr = '<br />'; $eoln = $cr; } else { // Use values supplied $CR = $eoln . $boln; $cr = $CR; } } else { // Text Mode $CR = $eoln; $cr = $CR; $HR = '----------------------------------------'; $hr = '----------------------------------------'; } $statecomma = ''; $streets = $street; if ($suburb != '') $streets = $street . $cr . $suburb; if ($country == '') $country = tep_output_string_protected($address['country']); if ($state != '') $statecomma = $state . ', '; $fmt = $address_format; eval("\$address = \"$fmt\";"); if ( (ACCOUNT_COMPANY == 'true') && (tep_not_null($company)) ) { $address = $company . $cr . $address; } return $address; } Find this code echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_03_bootstrap-multiselect-3.1.1.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_04_bootstrap-theme-custom.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_05_tikslusdialog.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_06_select2.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_07_red.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_08_jquery.contextMenu.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_09_orange.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_10_jtable-custom.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_11_contact.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_12_jquery.qtip.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_13_order_handler.css', 'link', false, false, '0928' ); } Replace With echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_03_bootstrap-multiselect-3.1.1.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_04_bootstrap-theme-custom.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_05_tikslusdialog.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_06_select2.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_07_red.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_08_jquery.contextMenu.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_09_orange.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_10_jtable-custom.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_11_contact.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_12_jquery.qtip.css', 'link', false, false, '0928' ); echo tep_static_link( DIR_WS_MODULES . 'order_handler/css/01_13_order_handler.css', 'link', false, false, '0928' ); } //// //Error Handling function error_message( $title, $message ) { $error_message = '<script> window.opener.oHandler.gritter( "' . $title . '", "' . $message . '", "fa-warning" ); self.close(); $( ".progress" ).show(); </script>'; die( $error_message ); } Replace the entire ./admin/print_batch_process_3.php with this <?php /* Advanced Order Handler Rev3 for osCommerce 2.3.3 Copyright (C) 2014 Jonas [email protected] This file is part of Advanced Order Handler Rev3. Advanced Order Handler Rev3 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Advanced Order Handler Rev3 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Advanced Order Handler Rev3. If not, see <http://www.gnu.org/licenses/>. */ require 'includes/application_top.php'; require_once DIR_WS_MODULES . 'order_handler/general_functions.php'; require DIR_WS_CLASSES . 'currencies.php'; $currencies = new currencies(); //Define Tables to Variables $tablename_o = TABLE_ORDERS; $tablename_ot = TABLE_ORDERS_TOTAL; $tablename_c = TABLE_COUNTRIES; $tablename_osh = TABLE_ORDERS_STATUS_HISTORY; unset( $batch_order_numbers ); if ( $_POST['batch_order_numbers'] ) { foreach ( $_POST['batch_order_numbers'] as $order_number => $print_order ) { $batch_order_numbers[] = $order_number; } } // Uncomment this if you always want your orders sorted by order number //sort( $batch_order_numbers ); if ( !( is_array( $batch_order_numbers ) ) && !isset( $_POST['order_nums'] ) ) { error_message( "404: Not Found", "Error: no orders selected!" ); } else if ( isset( $_POST['batch_delete_x'] ) || isset( $_POST['batch_delete_y'] ) ) { include DIR_WS_LANGUAGES . $language . '/order_handler.php'; if ( isset( $_POST['batch_confirm_x'] ) || isset( $_POST['batch_confirm_y'] ) ) { die( include DIR_WS_MODULES . 'order_handler/oc_batch_delete.php' ); } else { die( include DIR_WS_MODULES . 'order_handler/oc_batch_delete_confirm.php' ); } } include DIR_WS_MODULES . 'order_handler/order_prepared.php'; $order = new order; if ( 'envelope' == $_POST['target_file'] ) { require DIR_WS_MODULES . 'order_handler/print_batch_envelope.php'; } elseif( 'export' == $_POST['target_file'] ) { #Export to XML header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache"); header('Content-Type: text/xml'); header('Content-Disposition: attachment; filename="'.date('Ymdhis').'.xml"'); $buffer[] = '<?xml version="1.0" encoding="utf-8"?>'."\r\n"; $buffer[] = '<your_shipping_here>'."\r\n"; foreach ($batch_order_numbers as $order_id) { if($order_id != "null") { $db_get = "SELECT o.orders_id,o.customers_id,o.customers_name,o.payment_method,o.delivery_name,o.delivery_company,o.delivery_street_address,o.delivery_suburb,o.delivery_city,o.delivery_postcode,o.delivery_state,o.delivery_country,o.customers_telephone,o.customers_email_address,ot.value,c.countries_iso_code_2 FROM $tablename_o o, $tablename_ot ot, $tablename_c c WHERE (o.orders_id = ot.orders_id AND ot.class = 'ot_total') AND (o.orders_id = ? AND o.delivery_country = c.countries_name) ORDER BY orders_id DESC LIMIT 1"; $db_res = mysqli_prepared_query($db_get, "i", array($order_id)); $db_ary = $db_res[0]; $buffer[] = "\t".'<receiver rcvid="'.$db_ary['orders_id'].'">'."\r\n"; $buffer[] = "\t\t".'<val n="name">'.$db_ary['delivery_name'].'</val>'."\r\n"; $buffer[] = "\t\t".'<val n="address1">'.$db_ary['delivery_street_address'].'</val>'."\r\n"; $buffer[] = "\t\t".'<val n="address2">'.$db_ary['delivery_suburb'].'</val>'."\r\n"; $buffer[] = "\t\t".'<val n="zipcode">'.$db_ary['delivery_postcode'].'</val>'."\r\n"; $buffer[] = "\t\t".'<val n="city">'.$db_ary['delivery_city'].'</val>'."\r\n"; $buffer[] = "\t\t".'<val n="country">'.$db_ary['countries_iso_code_2'].'</val>'."\r\n"; $buffer[] = "\t\t".'<val n="contact">'.$db_ary['customers_name'].'</val>'."\r\n"; $buffer[] = "\t\t".'<val n="phone">'.$db_ary['customers_telephone'].'</val>'."\r\n"; $buffer[] = "\t\t".'<val n="email">'.$db_ary['customers_email_address'].'</val>'."\r\n"; $buffer[] = "\t\t".'<val n="sms">'.$db_ary['customers_telephone'].'</val>'."\r\n"; $buffer[] = '</val>'."\r\n"; $buffer[] = "\t\t".'</container>'."\r\n"; $buffer[] = "\t".'</shipment>'."\r\n"; } } $buffer[] = '</your_shipping_here>'."\r\n"; die( implode('',$buffer) ); } elseif ( $_POST['target_file'] == 'labels' ) { //Create CSV for Envelope header( 'Content-type: application/csv' ); header( 'Content-Disposition: inline; filename="'.date( "ymd" ).'.csv"' ); echo "Name;Street address;Postcode;City;Country\n"; $order->prepare_query(); foreach ( $batch_order_numbers as $order_id ) { $order->query( $order_id ); echo "" . $order->delivery['name'] . ";" . $order->delivery['street_address'] . ";" . $order->delivery['postcode'] . ";" . $order->delivery['city'] . ";" . $order->delivery['country'] . "\n"; } $order->close_query(); exit; } $total_invoices = count( $batch_order_numbers ); ?> <!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"> <html <?php echo HTML_PARAMS; ?>> <head> <meta http-equiv="Content-Type" content="text/html; charset=<?php echo CHARSET; ?>"> <meta name="robots" content="noindex,nofollow"> <title><?php echo 'Invoices (' . $total_invoices . ')'; ?></title> <link rel="stylesheet" type="text/css" href="includes/stylesheet.css"> <script src="<?php echo tep_catalog_href_link( 'ext/jquery/jquery-2.1.0.min.js' ); ?>"></script> </head> <body marginwidth="0" marginheight="0" topmargin="0" bottommargin="0" leftmargin="0" rightmargin="0" bgcolor="#FFFFFF"> <div id="ajax_loader" style="display:block;"> <div id="loader_content"> <div class="circle"></div> <div class="circle1"></div> <div class="progress progress-striped active"> <div class="progress-bar" id="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%"> <span class="" style="color: rgb(255, 255, 255);font-weight: 400;">0 Updated</span> </div> </div> </div> </div> <script> $( ".progress" ).show(); </script> <?php $firstinvoice=1; $invoice = 0; $order->prepare_query(); //Let's iterate the Invoices foreach ( $batch_order_numbers as $order_id ) { $order->query( $order_id ); if ( $firstinvoice ) { $firstinvoice = 0; } else { echo '<br style="">'; } $invoice++; include DIR_WS_MODULES . 'order_handler/print_batch_invoice.php'; } $order->close_query(); ?> <script> $(function(){ $( "#ajax_loader" ).remove(); // Required for Print Page to work in Chrome <?php if ( "true" == $_POST['print'] ) { ?> // Comment/Uncomment /*window.print();*/ to display a print window after invoices has loaded. // Comment/Uncomment /*window.close();*/ to close window/tab after print window has closed. setTimeout( function(){ window.print(); /*window.close();*/ }, 1 ); <?php } ?> }); </script> </body> </html> <?php require DIR_WS_INCLUDES . 'application_bottom.php'; Quote osC OpenSSL Encryption with jCryptionSupport Forum jQuery/Ajax Advanced Statistics 2.3Support Forum jQuery/Ajax Advanced Order Handler 2.3.3Support ForumjQuery/Ajax Advanced Caching System 2.3.3Support ForumjQuery/Ajax Fast checkout/Shopping Cart/Login/Create Account 2.3.3Support ForumjQuery/Ajax Shopping Cart 2.3.3Support ForumjQuery/Ajax Dynamic Checkout 2.3.3Support ForumjQuery/Ajax Mini Cart for osCommerce 2.3.3Support ForumjQuery Cycle What's New InfoboxAuto Out Of Stock CSS Image OverlayjQuery-UI Autocomplete Product Search with Links & MySQLi support for osCommerce 2.X Link to comment Share on other sites More sharing options...
Dr. Rolex Posted September 11, 2014 Author Share Posted September 11, 2014 Envelope Module - Non-mysqlnd compatible version To add the Envelope Module to the non mysqlnd version of the Order Handler, make the following changes. 1. Make the replacement mentioned in post #204 2. In ./admin/get_table.php Find tep_load_css( true ); Replace With tep_load_css( false ); Find tep_preload_scripts( $store_country_iso_2[0]['countries_iso_code_2'], true ); tep_afterload_scripts( true ); Replace With tep_preload_scripts( $store_country_iso_2[0]['countries_iso_code_2'], false ); tep_afterload_scripts( false ); Find - Two occurrences - line 163 & 215 tep_preload_scripts( $store_country_iso_2[0]['countries_iso_code_2'], true ); Replace With tep_preload_scripts( $store_country_iso_2[0]['countries_iso_code_2'], false ); 3. In ./admin/includes/languages/english/order_handler.php Find @[member=definedmedia]('ENTRY_EXPORT', ' Export'); Replace With @[member=definedmedia]('ENTRY_EXPORT', ' CSV'); 4. In ./admin/includes/modules/order_handler/js/01_03_order_handler_rev3_module.js Find & REMOVE form = $( "#batch_orders" ), Find if ( target != "invoice.php" ) form[0].target = "_self"; else newWin = window.open("","_newtab"); form.submit(); } Replace With if ( target != "invoice" && "envelope" != target ) s.buttons.batchOrders[0].target = "_self"; else if ( "envelope" == target ) window.open( "", "_envelope" ); else window.open( "", "_newtab" ); s.buttons.batchOrders.submit(); } Find if ( target != "invoice.php" ) navbar[0].target = "_self"; Replace With if ( target != "invoice" && "envelope" != target ) navbar[0].target = "_self"; else if ( "envelope" == target ) navbar[0].target = "_envelope"; Find s.buttons.autostatus.multiselect({ buttonClass: 'btn btn-lg btn-default' }); s.buttons.autostatus.multiselect({ buttonClass: 'btn btn-lg btn-default' }); Replace With s.buttons.autostatus.multiselect({ buttonClass: 'btn btn-lg btn-default' }); $( "#envelope_back" ).multiselect({ buttonClass: 'btn btn-lg btn-default', maxHeight: 400, onChange: function(element, checked) { this.$select.find( "option" ).removeAttr( "selected" ); element.attr( "selected", "selected" ); // Toggle State of Tooltips localStorage.evelopeSize = element[0].value; this.$select.multiselect('select', localStorage.evelopeSize); } }); 5. In ./admin/includes/modules/order_handler/navbars.php Replace Entire File <?php /* Advanced Order Handler Rev3 for osCommerce 2.3.3 Copyright (C) 2014 Jonas [email protected] This file is part of Advanced Order Handler Rev3. Advanced Order Handler Rev3 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Advanced Order Handler Rev3 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Advanced Order Handler Rev3. If not, see <http://www.gnu.org/licenses/>. */ ?> <div id="navBars"> <!-- Top Navbar --> <nav class="navbar navbar-default navbar-fixed-top navbar-inverse" role="navigation" data-tooltip-title="<?php echo TOOLTIP_NAVIGATION_TOP_TITLE; ?>" id="navigationTop" style="height: 44px;min-height: 44px;"> <div class="navbarOverlay"></div> <div class="container-fluid"> <!-- Expand Window Button --> <div class="input-group btn-group navbar-left" style="width:50px;" data-toggle="buttons"> <i class="expand_table fa fa-arrows-alt tooltip_set" data-placement="bottom" title="<?php echo TOOLTIP_EXPAND_TABLE; ?>" style=""></i> </div> <!-- END Expand Window Button --> <!-- Toggle Right Click Menu Button --> <div class="input-group btn-group navbar-form navbar-left tooltip_set" data-placement="bottom" title="<?php echo TOOLTIP_ADMIN_MENU; ?>" style="width:50px;margin-left: 50px;"> <input type="checkbox" class="js-switch" id="js-switch" checked /> </div> <div class="input-group btn-group navbar-form navbar-left" style="width:14%;min-width:250px;" data-toggle="buttons"> <input type="checkbox" name="context_menu" <?php echo (isset($_GET['context_menu']) ? 'checked="checked"' : ''); ?> id="context_menu" class="iCheck" checked="checked"> <label for="context_menu"><?php echo TEXT_INFO_DISABLE_MENU; ?></label> </div> <!-- END Toggle Right Click Menu Button --> <!-- Search Orders --> <?php $orders_statuses = array(); $envelope_back = array(); $orders_status_array = array(); $orders_status_query = mysqli_prepared_query("SELECT orders_status_id, orders_status_name FROM $tablename_os WHERE language_id = ? ORDER BY orders_status_id ASC", "i", array($languages_id)); foreach ($orders_status_query as $orders_status) { $orders_statuses[] = array('id' => $orders_status['orders_status_id'], 'text' => $orders_status['orders_status_name']); $orders_status_array[$orders_status['orders_status_id']] = $orders_status['orders_status_name']; } # International standard sizes $envelope_back[] = array( 'id' => json_encode(array(110,220)), 'text' => 'DL' ); $envelope_back[] = array( 'id' => json_encode(array(81,114)), 'text' => 'C7' ); $envelope_back[] = array( 'id' => json_encode(array(81,162)), 'text' => 'C7/C6' ); $envelope_back[] = array( 'id' => json_encode(array(114,162)), 'text' => 'C6' ); $envelope_back[] = array( 'id' => json_encode(array(114,229)), 'text' => 'C6/C5' ); $envelope_back[] = array( 'id' => json_encode(array(162,229)), 'text' => 'C5' ); $envelope_back[] = array( 'id' => json_encode(array(229,324)), 'text' => 'C4' ); $envelope_back[] = array( 'id' => json_encode(array(324,458)), 'text' => 'C3' ); $envelope_back[] = array( 'id' => json_encode(array(125,176)), 'text' => 'B6' ); $envelope_back[] = array( 'id' => json_encode(array(176,250)), 'text' => 'B5' ); $envelope_back[] = array( 'id' => json_encode(array(250,353)), 'text' => 'B4' ); $envelope_back[] = array( 'id' => json_encode(array(280,400)), 'text' => 'E4' ); # North American sizes $envelope_back[] = array( 'id' => json_encode(array(111.1,146.1)), 'text' => 'A2' ); $envelope_back[] = array( 'id' => json_encode(array(120.7,165.1)), 'text' => 'A6' ); $envelope_back[] = array( 'id' => json_encode(array(133.4,184.2)), 'text' => 'A7' ); $envelope_back[] = array( 'id' => json_encode(array(139.7,206.4)), 'text' => 'A8' ); $envelope_back[] = array( 'id' => json_encode(array(146.1,222.3)), 'text' => 'A9' ); $envelope_back[] = array( 'id' => json_encode(array(152.4,241.3)), 'text' => 'A10' ); $envelope_back[] = array( 'id' => json_encode(array(92.1,165.1)), 'text' => '6¾' ); $envelope_back[] = array( 'id' => json_encode(array(98.4,190.5)), 'text' => '7¾' ); $envelope_back[] = array( 'id' => json_encode(array(98.4,225.4)), 'text' => '9' ); $envelope_back[] = array( 'id' => json_encode(array(104.8,241.3)), 'text' => '10' ); $envelope_back[] = array( 'id' => json_encode(array(114.3,263.5)), 'text' => '11' ); $envelope_back[] = array( 'id' => json_encode(array(120.7,279.4)), 'text' => '12' ); $envelope_back[] = array( 'id' => json_encode(array(127.0,292.1)), 'text' => '14' ); echo tep_draw_form('search', "get_table.php", '', 'get', 'class="navbar-form" role="search"') . '<div class="form-group navbar-left navbar-form" style="width: 23%;">' . tep_draw_input_field('search', '', 'class="bigdrop tooltip_set" placeholder="Search by Name, E-Mail, Order Number, Customer Number" title="' . TOOLTIP_SEARCH_ORDERS . '" id="search_orders" style="min-width:335px;"') . '</div>' . '</form>'; ?> <!-- END Search Orders --> <!-- Remove Gritter Button --> <div class="navbar-form input-group btn-group navbar-right" style="margin-right: -15px;" data-toggle="buttons"> <label class="btn btn-lg btn-danger" style="opacity:0;padding: 0px 5px 0px 5px;z-index:100;margin-right:20px;" id="gritterRemove"> <i class="fa fa-times fa-2 tooltip_set" data-placement="top" title="<?php echo TOOLTIP_GRITTER_REMOVE; ?>" style="width: 20px;font-size:1.5em;z-index:0;"></i> <?php echo tep_draw_checkbox_field('long_poller'); ?> </label> </div> <!-- END Remove Gritter Button --> <!-- Refresh Button --> <div class="navbar-form input-group btn-group navbar-right" style="" data-toggle="buttons"> <label class="btn btn-lg btn-success" style="padding: 0px 5px 0px 5px;z-index:100;" id="refresh-button"> <i class="fa fa-2 fa-refresh tooltip_set" data-placement="bottom" title="<?php echo TOOLTIP_REFRESH; ?>" style="font-size:1.5em;z-index:0;"> <a href="<?php echo tep_href_link(FILENAME_LOGIN, 'action=logoff'); ?>"></a> </i> </label> </div> <!-- END Refresh Button --> <!-- Logout Button --> <div class="navbar-form input-group btn-group navbar-right" style="" data-toggle="buttons"> <label class="btn btn-lg btn-danger" style="padding: 0px 5px 0px 5px;z-index:100;margin-right:20px;" id="logout-button"> <i class="fa fa-2 fa-sign-out tooltip_set" data-placement="bottom" title="<?php echo TOOLTIP_LOGOUT; ?>" style="width: 20px;font-size:1.5em;z-index:0;"> <a href="<?php echo tep_href_link(FILENAME_LOGIN, 'action=logoff'); ?>"></a> </i> </label> </div> <!-- END Logout Button --> <!-- Sort By Status --> <?php echo tep_draw_form('status', "get_table.php", '', 'get', 'id="select_status"') . '<div class="form-group navbar-right navbar-form tooltip_set" data-placement="bottom" title="' . TOOLTIP_SORT_STATUS . '" style="width:20%;min-width:335px;margin-right:0;">' . tep_draw_pull_down_menu('status', array_merge(array(array('id' => '', 'text' => TEXT_ALL_ORDERS)), $orders_statuses), '', 'id="status" style="width:100%;"') . '</div>' . '</form>'; ?> <!-- END Sort By Status --> </div> </nav> <!-- END Top Navbar --> <!-- Bottom Navbar --> <?php echo tep_draw_form('navbar', 'print_batch_process_3.php', '', 'post', 'target="_newtab" id="navbar"') . tep_draw_hidden_field('print', "true", 'id="print"'); ?> <nav class="navbar navbar-default navbar-fixed-bottom navbar-inverse" role="navigation" id="navigationBottom" data-tooltip-title="<?php echo TOOLTIP_NAVIGATION_BOTTOM_TITLE; ?>"> <div class="navbarOverlay"></div> <!-- Navbar Header --> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"></button> <a class="navbar-brand" href="javascript:void(0);">Menu</a> </div> <!-- END Navbar Header --> <!-- Output Menu --> <div class="container-fluid"> <div class="btn-group navbar-form navbar-left" id="target_file" style="width:28%;min-width:446px;padding:0;" data-toggle="buttons"> <label class="btn btn-lg btn-primary active"> <?php echo tep_draw_radio_field('target_file', 'invoice', true) . ENTRY_INVOICE; ?> </label> <label class="btn btn-lg btn-primary"> <?php echo tep_draw_radio_field('target_file', 'labels') . ENTRY_EXPORT; ?> </label> <label class="btn btn-lg btn-primary"> <?php echo tep_draw_radio_field('target_file', 'export') . ENTRY_XML; ?> </label> <label class="btn btn-lg btn-primary"> <?php echo tep_draw_radio_field('target_file', 'envelope') . ENTRY_ENVELOPE; ?> </label> <?php echo tep_draw_pull_down_menu('envelope_back', $envelope_back, json_encode(array(162,229)), 'id="envelope_back" class="multiselect btn btn-lg btn-info"'); ?> </div> <!-- END Output Menu --> <!-- Email Customer Menu --> <div class="input-group navbar-form btn-group navbar-left" style="margin-left:20px;margin-right:20px;width:10%;min-width:160px;padding:0;" data-toggle="buttons"> <span class="input-group-addon"><b class="glyphicon glyphicon-envelope"></b></span> <label class="btn btn-lg btn-info tooltip_set" data-placement="top" title="<?php echo IMAGE_SEND_EMAIL; ?>"> <?php echo ENTRY_NOTIFY_YES . tep_draw_radio_field('notify', 'Yes'); ?> </label> <label class="btn btn-lg btn-info active tooltip_set" data-placement="top" title="<?php echo TOOLTIP_DO_NOT_SEND_EMAIL; ?>" style="border-bottom-right-radius:4px;border-top-right-radius:4px;"> <?php echo tep_draw_radio_field('notify', 'No', true) . ENTRY_NOTIFY_NO; ?> </label> </div> <!-- END Email Customer Menu --> <!-- Update Status Menu --> <div class="input-group btn-group navbar-form navbar-left" id="autoupdatestatus" style="min-width:400px;width:29%;padding:0;" data-toggle="buttons"> <span class="input-group-addon"><b class="glyphicon"></b><?php echo ENTRY_UPDATE_STATUS; ?></span> <label class="btn btn-lg btn-info tooltip_set" data-placement="top" title="<?php echo TOOLTIP_UPDATE_STATUS; ?>"> <?php echo ENTRY_NOTIFY_YES . tep_draw_radio_field('autoupdatestatus', 'Yes'); ?> </label> <label class="btn btn-lg btn-info active tooltip_set" data-placement="top" title="<?php echo TOOLTIP_DO_NOT_UPDATE_STATUS; ?>"> <?php echo tep_draw_radio_field('autoupdatestatus', 'No', true) . ENTRY_NOTIFY_NO; ?> </label> <?php echo tep_draw_pull_down_menu('autostatus', $orders_statuses, 3, 'id="autostatus" class="multiselect btn btn-lg btn-info"'); ?> </div> <!-- END Update Status Menu --> <!-- Delete Button --> <div class="btn-group navbar-form navbar-right" style="margin-right: -15px;"> <button type="button" id="batch_delete" name="batch_delete" class="btn btn-lg btn-danger navbar-right ui-priority-secondary tooltip_set" data-placement="top" title="<?php echo TOOLTIP_DELETE_ORDERS; ?>"><?php echo IMAGE_DELETE; ?></button> </div> <!-- END Delete Button --> <!-- Ajax Polling Menu --> <div class="input-group input-group-lg btn-group navbar-form navbar-right" style="width:12%;min-width:200px;padding:0;margin-left:10px;margin-right:10px;" id="poller" data-toggle="buttons"> <span class="input-group-addon"><i class="fa fa-cog"></i></span> <?php echo tep_draw_input_field('poll_timer', '20', 'id="poll_timer" class="form-control tooltip_set" data-placement="top" title="' . TOOLTIP_TIMEOUT . '" placeholder="20" style="width:55px;height:46px;"'); ?> <label class="btn btn-lg btn-default" style="padding: 9px 16px 8px 10px;" id="enable_button"> <i class="fa fa-check fa-2 tooltip_set" data-placement="top" title="<?php echo TOOLTIP_ENABLE_POLLING; ?>" style="width: 20px;font-size:1.5em;"></i> <?php echo tep_draw_checkbox_field('long_poller'); ?> </label> <label class="btn btn-lg btn-danger active" style="padding: 9px 14px 8px 12px;z-index:100;" id="disable_button"> <i class="fa fa-times fa-2 tooltip_set" data-placement="top" title="<?php echo TOOLTIP_DISABLE_POLLING; ?>" style="width: 20px;font-size:1.5em;z-index:0;"></i> <?php echo tep_draw_checkbox_field('long_poller'); ?> </label> </div> <!-- END Ajax Polling Menu --> <!-- Confirm Button --> <div class="btn-group navbar-form navbar-right" style="margin-right:0;padding:0;margin-right:10px;"> <a href="<?php echo tep_href_link("get_table.php", tep_get_all_get_params(array('action')) . 'action=update_orders_status'); ?>" target="_newtab" type="submit" class="submit_button btn btn-lg btn-success ui-priority-primary" style="font-weight: normal;"><?php echo IMAGE_CONFIRM; ?></a> </div> <!-- END Confirm Button --> </div> </nav> </form> </div> 6. Copy new files from Package uploaded on 16 Jul 2014 ./admin/includes/modules/order_handler/css/images/airmail-graphicsfairy002c-right.jpg ./admin/includes/modules/order_handler/font/* ./admin/includes/modules/order_handler/print_batch_envelope.php ./admin/includes/modules/order_handler/tfpdf.php Quote osC OpenSSL Encryption with jCryptionSupport Forum jQuery/Ajax Advanced Statistics 2.3Support Forum jQuery/Ajax Advanced Order Handler 2.3.3Support ForumjQuery/Ajax Advanced Caching System 2.3.3Support ForumjQuery/Ajax Fast checkout/Shopping Cart/Login/Create Account 2.3.3Support ForumjQuery/Ajax Shopping Cart 2.3.3Support ForumjQuery/Ajax Dynamic Checkout 2.3.3Support ForumjQuery/Ajax Mini Cart for osCommerce 2.3.3Support ForumjQuery Cycle What's New InfoboxAuto Out Of Stock CSS Image OverlayjQuery-UI Autocomplete Product Search with Links & MySQLi support for osCommerce 2.X Link to comment Share on other sites More sharing options...
♥Tsimi Posted September 12, 2014 Share Posted September 12, 2014 Hi Jonas I have to say that I disagree, since when did commercial products outperform Open Source projects? :PI can't say that I'm very impressed with most of the commercial tools I use in my business, even though there are exceptions of course. They simply lack creativity and only have the absolutely base functionality which often leaves a lot to be desired .. Well they might lack the creativity, true, but since you pay for them you have the rights to get a 100% working tool even if it is just basic. If not, then that would be unprofessional work by the seller/developer. Of course open source is awesome if you have good people working on it (like yourself for example). But since it is free we can't always expect it to work 100% out of the box. That is why we have this nice forum here to do that together. (In this case it is only you though... :P ) Some people just always think that osC and it's add-ons should work perfectly from the start without any efforts and that is wrong thinking. If it works 100% great! If not then pull up your sleeves and get to it.... :D I'm certain that there can be a 100% working order editor which fits all needs. This, of course, requires that there aren't any prior errors on the osC installation when the order editor is installed. It looks like a lot of people have broken/deprecated Javascript code from other Add-Ons which can and probably will break the order handler. Yep. some people install many add-ons that conflict later on and then the point the finger mostly to the latest installed one and forget that the previous installed add-ons could be faulty too. Your fix and additions from post 204 and 205 worked! Very nice! Now i just need to change the button size from btn-lg to maybe btn-sm or even btn-xs the footer menu getting quite full now. On my 21" monitor no preblem but on my 15" notebook the footer menu covers the under part of the listing because of the btn-lg buttons. This is a part where everyone needs to adjust to their own needs. Thanks again...Dr. Kind regards Lambros Quote Link to comment Share on other sites More sharing options...
♥Tsimi Posted September 12, 2014 Share Posted September 12, 2014 (edited) Zu früh gefreut! I have the order handler on two shops installed both 2.3.4 untouched pure vanilla osC shops. one localhost and one real server. On my localhost the patches/fixes that you posted in 204 and 205 worked. I can see the invoice and envelope now. On my server i can't get the envelope to show. The invoice works though. I get the following message from adobe reader: "This PDF document might not be displayed correctly." Edited September 12, 2014 by Tsimi Quote Link to comment Share on other sites More sharing options...
Dr. Rolex Posted September 12, 2014 Author Share Posted September 12, 2014 Zu früh gefreut! I have the order handler on two shops installed both 2.3.4 untouched pure vanilla osC shops. one localhost and one real server. On my localhost the patches/fixes that you posted in 204 and 205 worked. I can see the invoice and envelope now. On my server i can't get the envelope to show. The invoice works though. I get the following message from adobe reader: "This PDF document might not be displayed correctly." Super schön! I'm guessing this problem only occurs in Firefox, right? I know I had this problem at some point when developing the envelope module but I can't remember why or how I fixed it. Do you get the same error if you use another envelope size and/or another address? Any warnings or errors in your PHP log? You can change a FPDF setting in ./admin/includes/modules/order_handler/print_batch_envelope.php which will instead of displaying the envelope in the browser force a download of the PDF. I had problem printing the invoices from the built in PDF reader in Firefox so personally I always download and open them with Preview (PDF Reader software for Mac). To do this change the second parameter ( 'I' ) on this line to e.g. 'D' instead. $pdf->Output( "Envelope-" . date( "ymd" ).'.pdf', 'I' ); From the Manual: Destination where to send the document. It can take one of the following values: I: send the file inline to the browser. The plug-in is used if available. The name given by name is used when one selects the "Save as" option on the link generating the PDF. D: send to the browser and force a file download with the name given by name. F: save to a local file with the name given by name (may include a path). S: return the document as a string. name is ignored. It could be a problem with your plugin/Browser Add-On. Found some threads about the problem on mozilla support forum: https://support.mozilla.org/sv/questions/947783 https://support.mozilla.org/sv/questions/948061 Quote osC OpenSSL Encryption with jCryptionSupport Forum jQuery/Ajax Advanced Statistics 2.3Support Forum jQuery/Ajax Advanced Order Handler 2.3.3Support ForumjQuery/Ajax Advanced Caching System 2.3.3Support ForumjQuery/Ajax Fast checkout/Shopping Cart/Login/Create Account 2.3.3Support ForumjQuery/Ajax Shopping Cart 2.3.3Support ForumjQuery/Ajax Dynamic Checkout 2.3.3Support ForumjQuery/Ajax Mini Cart for osCommerce 2.3.3Support ForumjQuery Cycle What's New InfoboxAuto Out Of Stock CSS Image OverlayjQuery-UI Autocomplete Product Search with Links & MySQLi support for osCommerce 2.X Link to comment Share on other sites More sharing options...
♥Tsimi Posted September 12, 2014 Share Posted September 12, 2014 Hi Jonas Tried with Chrome and IE too. Chrome gives me same result invoice OK but error on the envelopes. IE this one is the worst of all (of course, what else...) it even doesn't load the invoice nor the envelops in fact nothing from the footer menu but that is OK i don't really care about IE since i never use that to work in the admin area. The funny thing is the right click function works perfect on IE but fails with Chrome or FF. What a crazy world... (w00t) I will give it another go and report back... Thank you . Kind regards Lambros Quote Link to comment Share on other sites More sharing options...
Dr. Rolex Posted September 12, 2014 Author Share Posted September 12, 2014 Hi Jonas Tried with Chrome and IE too. Chrome gives me same result invoice OK but error on the envelopes. IE this one is the worst of all (of course, what else...) it even doesn't load the invoice nor the envelops in fact nothing from the footer menu but that is OK i don't really care about IE since i never use that to work in the admin area. The funny thing is the right click function works perfect on IE but fails with Chrome or FF. What a crazy world... (w00t) I will give it another go and report back... Thank you . Kind regards Lambros Yeah, it's almost a harassment to work with IE. :x Did you check your error log? Since you're not having the same problem on your computer then perhaps your server configuration is set to add some kind of header to all pages. Check the Request and Response Headers when opening envelopes and compare them to the ones your getting on localhost. In Chrome developer tools you'll find these under the Network tab. First open some envelopes, go to that tab and open developer tools and click on the network tab, then reload the page and look at the print_batch_process_3.php request. Under Response Headers you should find Content-Type:application/pdf Quote osC OpenSSL Encryption with jCryptionSupport Forum jQuery/Ajax Advanced Statistics 2.3Support Forum jQuery/Ajax Advanced Order Handler 2.3.3Support ForumjQuery/Ajax Advanced Caching System 2.3.3Support ForumjQuery/Ajax Fast checkout/Shopping Cart/Login/Create Account 2.3.3Support ForumjQuery/Ajax Shopping Cart 2.3.3Support ForumjQuery/Ajax Dynamic Checkout 2.3.3Support ForumjQuery/Ajax Mini Cart for osCommerce 2.3.3Support ForumjQuery Cycle What's New InfoboxAuto Out Of Stock CSS Image OverlayjQuery-UI Autocomplete Product Search with Links & MySQLi support for osCommerce 2.X Link to comment Share on other sites More sharing options...
Dr. Rolex Posted October 5, 2014 Author Share Posted October 5, 2014 All right then, I have made an update to the Order Handler which should make it more stable and even more featureful than before! Automatic Module Recalculation of Order Totals Now when you modify an order the Order Handler will reload all shipping, payment and order total modules and recalculate Order Totals correctly. E.g. if you change the Shipping Method for an order to 'Per Item' Shipping Method and then change the product quantity, then the order handler will Update the order to the correct Shipping Price. Changing the Tax Rate etc. should now work without any miscalculations. At least, let's hope so!? :thumbsup: Order Status Dropdown Quickly change the Order Status without the need to go to any of the two 'Edit Order' Modes. Shipping Method Dropdown Quickly Change the Shipping Method on orders, the Order Handler will recalculate the correct shipping price and modify Order Totals. Payment Method Dropdown Quickly Change the Payment Method on orders, the Order Handler will recalculate the correct payment method price and modify Order Totals. New Toolbar Button - Quick Search Click on the magnifying glass and you will get a list with all orders from that customer. Bug Fixes All bugs mentioned so far should now be fixed and others as well.. I will Post the required changes here tomorrow and upload an updated package when I have time for that. ** See Screenshot Below ** Quote osC OpenSSL Encryption with jCryptionSupport Forum jQuery/Ajax Advanced Statistics 2.3Support Forum jQuery/Ajax Advanced Order Handler 2.3.3Support ForumjQuery/Ajax Advanced Caching System 2.3.3Support ForumjQuery/Ajax Fast checkout/Shopping Cart/Login/Create Account 2.3.3Support ForumjQuery/Ajax Shopping Cart 2.3.3Support ForumjQuery/Ajax Dynamic Checkout 2.3.3Support ForumjQuery/Ajax Mini Cart for osCommerce 2.3.3Support ForumjQuery Cycle What's New InfoboxAuto Out Of Stock CSS Image OverlayjQuery-UI Autocomplete Product Search with Links & MySQLi support for osCommerce 2.X Link to comment Share on other sites More sharing options...
♥joli1811 Posted October 5, 2014 Share Posted October 5, 2014 (edited) Just a quick mention the latest zip when unpacking also had problems it unpacked but with errors I found I was missing mainly images (bootstrap icons) and a few files from the includes/modules/order_handler/ I compared to original download not quite sure what you removed to make space tested 7zip and winrar to unpack. So still a problem with the file size have not had time to test but the next few days Regards John Edited October 5, 2014 by joli1811 Quote To improve is to change; to be perfect is to change often. Link to comment Share on other sites More sharing options...
Dr. Rolex Posted October 6, 2014 Author Share Posted October 6, 2014 Just a quick mention the latest zip when unpacking also had problems it unpacked but with errors I found I was missing mainly images (bootstrap icons) and a few files from the includes/modules/order_handler/ I compared to original download not quite sure what you removed to make space tested 7zip and winrar to unpack. So still a problem with the file size have not had time to test but the next few days Regards John Hello John, Let's put an end to the xz compression dilemma. I will exclude the screenshots in any new packages that I upload and just compress them with Tar/Gzip instead. ;) Quote osC OpenSSL Encryption with jCryptionSupport Forum jQuery/Ajax Advanced Statistics 2.3Support Forum jQuery/Ajax Advanced Order Handler 2.3.3Support ForumjQuery/Ajax Advanced Caching System 2.3.3Support ForumjQuery/Ajax Fast checkout/Shopping Cart/Login/Create Account 2.3.3Support ForumjQuery/Ajax Shopping Cart 2.3.3Support ForumjQuery/Ajax Dynamic Checkout 2.3.3Support ForumjQuery/Ajax Mini Cart for osCommerce 2.3.3Support ForumjQuery Cycle What's New InfoboxAuto Out Of Stock CSS Image OverlayjQuery-UI Autocomplete Product Search with Links & MySQLi support for osCommerce 2.X Link to comment Share on other sites More sharing options...
Dr. Rolex Posted October 6, 2014 Author Share Posted October 6, 2014 Okay, so if you want to test this new update then make the following changes. 1. Find this in ./admin/get_table.php case "update_order": die( $orders_ajax->update_order( $_GET, $_POST ) ); Replace With case "update_order": die( $orders_ajax->update_order( $_GET, $_POST ) ); case "update_shipping_method": die( $orders_ajax->update_shipping_method( $_GET ) ); ______________________________________________________ Find This tep_load_css( true ); Replace With tep_load_css( false ); ______________________________________________________ Find This tep_preload_scripts( $store_country_iso_2[0]['countries_iso_code_2'], true ); tep_afterload_scripts( true ); Replace With tep_preload_scripts( $store_country_iso_2[0]['countries_iso_code_2'], false ); tep_afterload_scripts( false ); ______________________________________________________ Find This tep_preload_scripts( $store_country_iso_2[0]['countries_iso_code_2'], true ); Replace With tep_preload_scripts( $store_country_iso_2[0]['countries_iso_code_2'], false ); ______________________________________________________ Find This tep_afterload_scripts( true ); Replace With tep_afterload_scripts( false ); ______________________________________________________ 2. Add this to ./admin/includes/languages/english/order_handler.php @[member=definedmedia]('TOOLTIP_SEARCH_CUSTOMER_ORDERS', 'List all orders from %s.'); ______________________________________________________ 3. Find this in ./admin/includes/modules/order_handler/css/01_10_jtable-custom.css div.jtable-main-container div.jtable-column-selection-container { Replace With div.jtable-column-selection-container { ______________________________________________________ Find This div.jtable-main-container div.jtable-column-selection-container ul.jtable-column-select-list { Replace With div.jtable-column-selection-container ul.jtable-column-select-list { ______________________________________________________ Find This div.jtable-main-container div.jtable-column-selection-container ul.jtable-column-select-list li { Replace With div.jtable-column-selection-container ul.jtable-column-select-list li { ______________________________________________________ Find This div.jtable-main-container div.jtable-column-selection-container ul.jtable-column-select-list li label span { Replace With div.jtable-column-selection-container ul.jtable-column-select-list li label span { ______________________________________________________ Find This div.jtable-main-container div.jtable-column-selection-container ul.jtable-column-select-list li input[type="checkbox"] { Replace With div.jtable-column-selection-container ul.jtable-column-select-list li input[type="checkbox"] { ______________________________________________________ 4. Find this in ./admin/includes/modules/order_handler/css/01_13_order_handler.css /* Body Prepare */ #body_content.ready { width: 100%; position: absolute; Replace With /* Body Prepare */ #body_content.ready { width: 100%; position: absolute; padding-bottom: 50px; ______________________________________________________ 5. Find this in ./admin/includes/modules/order_handler/general_functions.php $script = tep_catalog_href_link($script, (is_numeric($version) ? $version : ''), $connection); else $script = (($cookieless == true) ? HTTP_COOKIELESS_DOMAIN : '') . $script; if ($type == 'script') return '<script src="' . (($cookieless == true) ? HTTP_COOKIELESS_DOMAIN : '') . $script . '"></script>'; if ($type == 'link') return '<link rel="stylesheet" href="' . (($cookieless == true) ? HTTP_COOKIELESS_DOMAIN : '') . $script . '" />'; return "No link found"; } Replace With $script = tep_catalog_href_link($script, (is_numeric($version) ? $version : ''), $connection); else $script = (($cookieless == true) ? HTTP_COOKIELESS_DOMAIN : '') . $script; if ($type == 'script') return '<script src="' . (($cookieless == true) ? HTTP_COOKIELESS_DOMAIN : '') . $script . '"></script>'; if ($type == 'link') return '<link rel="stylesheet" href="' . (($cookieless == true) ? HTTP_COOKIELESS_DOMAIN : '') . $script . '" />'; return "No link found"; } function tep_address($address_format, $address, $html, $boln, $eoln, $skip_name = false) { $company = tep_output_string_protected($address['company']); if ( ! $skip_name ) { if (isset($address['firstname']) && tep_not_null($address['firstname'])) { $firstname = tep_output_string_protected($address['firstname']); $lastname = tep_output_string_protected($address['lastname']); } elseif (isset($address['name']) && tep_not_null($address['name'])) { $firstname = tep_output_string_protected($address['name']); $lastname = ''; } else { $firstname = ''; $lastname = ''; } } $street = tep_output_string_protected($address['street_address']); $suburb = tep_output_string_protected($address['suburb']); $city = tep_output_string_protected($address['city']); $state = tep_output_string_protected($address['state']); if (isset($address['country_id']) && tep_not_null($address['country_id'])) { $country = tep_get_country_name($address['country_id']); if (isset($address['zone_id']) && tep_not_null($address['zone_id'])) { $state = tep_get_zone_code($address['country_id'], $address['zone_id'], $state); } } elseif (isset($address['country']) && tep_not_null($address['country'])) { $country = tep_output_string_protected($address['country']); } else { $country = ''; } $postcode = tep_output_string_protected($address['postcode']); $zip = $postcode; if ($html) { // HTML Mode $HR = '<hr />'; $hr = '<hr />'; if ( ($boln == '') && ($eoln == "\n") ) { // Values not specified, use rational defaults $CR = '<br />'; $cr = '<br />'; $eoln = $cr; } else { // Use values supplied $CR = $eoln . $boln; $cr = $CR; } } else { // Text Mode $CR = $eoln; $cr = $CR; $HR = '----------------------------------------'; $hr = '----------------------------------------'; } $statecomma = ''; $streets = $street; if ($suburb != '') $streets = $street . $cr . $suburb; if ($country == '') $country = tep_output_string_protected($address['country']); if ($state != '') $statecomma = $state . ', '; $fmt = $address_format; eval("\$address = \"$fmt\";"); if ( (ACCOUNT_COMPANY == 'true') && (tep_not_null($company)) ) { $address = $company . $cr . $address; } return $address; } ______________________________________________________ Find This $rs->data_seek( 0 ); while ( $row = $rs->fetch_assoc() ) { $var[] = $row; } return substr( json_encode( $var ), 1, -1 ); } //// // Returns a jTable formatted pull down menu with payment methods function tep_cfg_pull_down_payment( $selected_payment_module = '', $parameters = '', $custom = false, $required = false ) { global $language; Replace With $rs->data_seek( 0 ); while ( $row = $rs->fetch_assoc() ) { $var[] = $row; } return substr( json_encode( $var ), 1, -1 ); } //// // Returns a jTable formatted pull down menu with shipping methods function tep_cfg_pull_down_shipping( $selected_shipping_module = '', $parameters = '', $custom = false, $required = false ) { global $language, $order; if ( defined( 'MODULE_SHIPPING_INSTALLED' ) && tep_not_null( MODULE_SHIPPING_INSTALLED ) ) { $installed_modules = explode( ';', MODULE_SHIPPING_INSTALLED ); $include_modules = array(); $modules = array(); reset( $modules ); while ( list( , $value ) = each( $installed_modules ) ) { $class = substr( $value, 0, strrpos( $value, '.' ) ); $include_modules[] = array( 'class' => $class, 'file' => $value ); } for ( $i=0, $n=sizeof( $include_modules ); $i<$n; $i++ ) { include_once DIR_FS_CATALOG . DIR_WS_LANGUAGES . $language . '/modules/shipping/' . $include_modules[$i]['file']; include_once DIR_FS_CATALOG . DIR_WS_MODULES . 'shipping/' . $include_modules[$i]['file']; $modules[] = new $include_modules[$i]['class']; } } $shipping_array = array(); $default = ''; if ( true === $custom ) { $shipping_array[] = array( 'id' => json_encode( array( "_custom", $selected_shipping_module ) ), 'text' => $selected_shipping_module, ); } foreach ( $modules as $value ) { $shipping_array[] = array( 'id' => $value->code, 'text' => $value->title, ); $haystack = preg_replace( '/\s\(.+$/', '', $selected_shipping_module ); if ( stristr( $haystack, $value->title ) ) { $default = $value->code; } } //var_dump($default); return tep_draw_pull_down_menu( 'shipping_method_selection', $shipping_array, $default, $parameters, $required ); } //// // Returns a jTable formatted pull down menu with payment methods function tep_cfg_pull_down_payment( $selected_payment_module = '', $parameters = '', $custom = false, $required = false ) { global $language, $order; ______________________________________________________ * End Part 1 * ______________________________________________________ Quote osC OpenSSL Encryption with jCryptionSupport Forum jQuery/Ajax Advanced Statistics 2.3Support Forum jQuery/Ajax Advanced Order Handler 2.3.3Support ForumjQuery/Ajax Advanced Caching System 2.3.3Support ForumjQuery/Ajax Fast checkout/Shopping Cart/Login/Create Account 2.3.3Support ForumjQuery/Ajax Shopping Cart 2.3.3Support ForumjQuery/Ajax Dynamic Checkout 2.3.3Support ForumjQuery/Ajax Mini Cart for osCommerce 2.3.3Support ForumjQuery Cycle What's New InfoboxAuto Out Of Stock CSS Image OverlayjQuery-UI Autocomplete Product Search with Links & MySQLi support for osCommerce 2.X Link to comment Share on other sites More sharing options...
Dr. Rolex Posted October 6, 2014 Author Share Posted October 6, 2014 P.S. Sorry for the lost indentation in the previous post, the original post was too big and osc forum doesn't save indentation for some reason.. D.S. Replace ./admin/includes/modules/order_handler/js/01_02_jquery.jtable.js With This: (1/3 Part of this file) /* jTable 2.4.0 http://www.jtable.org --------------------------------------------------------------------------- Copyright (C) 2011-2014 by Halil İbrahim Kalkan (http://www.halilibrahimkalkan.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /************************************************************************ * CORE jTable module * *************************************************************************/ (function ($) { var unloadingPage; $(window).on('beforeunload', function () { unloadingPage = true; }); $(window).on('unload', function () { unloadingPage = false; }); $.widget("hik.jtable", { /************************************************************************ * DEFAULT OPTIONS / EVENTS * *************************************************************************/ options: { //Options actions: {}, fields: {}, animationsEnabled: true, defaultDateFormat: 'yy-mm-dd', dialogShowEffect: 'fade', dialogHideEffect: 'fade', showCloseButton: false, loadingAnimationDelay: 500, saveUserPreferences: true, jqueryuiTheme: false, unAuthorizedRequestRedirectUrl: null, ajaxSettings: { type: 'POST', dataType: 'json', global: false }, toolbar: { hoverAnimation: true, hoverAnimationDuration: 60, hoverAnimationEasing: undefined, items: [] }, //Events closeRequested: function (event, data) { }, formCreated: function (event, data) { }, formSubmitting: function (event, data) { }, formClosed: function (event, data) { }, loadingRecords: function (event, data) { }, recordsLoaded: function (event, data) { }, rowInserted: function (event, data) { }, rowsRemoved: function (event, data) { }, //Localization messages: { serverCommunicationError: 'An error occured while communicating to the server.', loadingMessage: 'Loading records...', loadingProgress: 'Records Loaded: {0} out of {1}', noDataAvailable: 'No data available!', areYouSure: 'Are you sure?', save: 'Save', saving: 'Saving', cancel: 'Cancel', error: 'Error', close: 'Close', cannotLoadOptionsFor: 'Can not load options for field {0}' } }, /************************************************************************ * PRIVATE FIELDS * *************************************************************************/ _$mainContainer: null, //Reference to the main container of all elements that are created by this plug-in (jQuery object) _$titleDiv: null, //Reference to the title div (jQuery object) _$toolbarDiv: null, //Reference to the toolbar div (jQuery object) _$table: null, //Reference to the main <table> (jQuery object) _$tableBody: null, //Reference to <body> in the table (jQuery object) _$tableRows: null, //Array of all <tr> in the table (except "no data" row) (jQuery object array) _$busyDiv: null, //Reference to the div that is used to block UI while busy (jQuery object) _$busyMessageDiv: null, //Reference to the div that is used to show some message when UI is blocked (jQuery object) _$errorDialogDiv: null, //Reference to the error dialog div (jQuery object) _columnList: null, //Name of all data columns in the table (select column and command columns are not included) (string array) _fieldList: null, //Name of all fields of a record (defined in fields option) (string array) _keyField: null, //Name of the key field of a record (that is defined as 'key: true' in the fields option) (string) _firstDataColumnOffset: 0, //Start index of first record field in table columns (some columns can be placed before first data column, such as select checkbox column) (integer) _lastPostData: null, //Last posted data on load method (object) _cache: null, //General purpose cache dictionary (object) /************************************************************************ * CONSTRUCTOR AND INITIALIZATION METHODS * *************************************************************************/ /* Contructor. *************************************************************************/ _create: function () { //Initialization this._normalizeFieldsOptions(); this._initializeFields(); this._createFieldAndColumnList(); //Creating DOM elements this._createMainContainer(); this._createTableTitle(); this._createToolBar(); this._createTable(); this._createBusyPanel(); this._createErrorDialogDiv(); this._addNoDataRow(); this._cookieKeyPrefix = this._generateCookieKeyPrefix(); }, /* Normalizes some options for all fields (sets default values). *************************************************************************/ _normalizeFieldsOptions: function () { var self = this; $.each(self.options.fields, function (fieldName, props) { self._normalizeFieldOptions(fieldName, props); }); }, /* Normalizes some options for a field (sets default values). *************************************************************************/ _normalizeFieldOptions: function (fieldName, props) { if (props.listClass == undefined) { props.listClass = ''; } if (props.inputClass == undefined) { props.inputClass = ''; } //Convert dependsOn to array if it's a comma seperated lists if (props.dependsOn && $.type(props.dependsOn) === 'string') { var dependsOnArray = props.dependsOn.split(','); props.dependsOn = []; for (var i = 0; i < dependsOnArray.length; i++) { props.dependsOn.push($.trim(dependsOnArray[i])); } } }, /* Intializes some private variables. *************************************************************************/ _initializeFields: function () { this._lastPostData = {}; this._$tableRows = []; this._columnList = []; this._fieldList = []; this._cache = []; }, /* Fills _fieldList, _columnList arrays and sets _keyField variable. *************************************************************************/ _createFieldAndColumnList: function () { var self = this; $.each(self.options.fields, function (name, props) { //Add field to the field list self._fieldList.push(name); //Check if this field is the key field if (props.key == true) { self._keyField = name; } //Add field to column list if it is shown in the table if (props.list != false && props.type != 'hidden') { self._columnList.push(name); } }); }, /* Creates the main container div. *************************************************************************/ _createMainContainer: function () { this._$mainContainer = $('<div />') .addClass('jtable-main-container') .appendTo(this.element); this._jqueryuiThemeAddClass(this._$mainContainer, 'ui-widget'); }, /* Creates title of the table if a title supplied in options. *************************************************************************/ _createTableTitle: function () { var self = this; if (!self.options.title) { return; } var $titleDiv = $('<div />') .addClass('jtable-title') .appendTo(self._$mainContainer); self._jqueryuiThemeAddClass($titleDiv, 'ui-widget-header'); $('<div />') .addClass('jtable-title-text') .appendTo($titleDiv) .append(self.options.title); var $titleDivNext = $('<div />') .addClass('jtable-title-text-next') .appendTo($titleDiv); if (self.options.showCloseButton) { var $textSpan = $('<span />') .html(self.options.messages.close); $('<button></button>') .addClass('jtable-command-button jtable-close-button') .attr('title', self.options.messages.close) .append($textSpan) .appendTo($titleDivNext) .click(function (e) { e.preventDefault(); e.stopPropagation(); self._onCloseRequested(); }); } self._$titleDiv = $titleDiv; }, /* Creates the table. *************************************************************************/ _createTable: function () { this._$table = $('<table></table>') .addClass('jtable') .appendTo(this._$mainContainer); if (this.options.tableId) { this._$table.attr('id', this.options.tableId); } this._jqueryuiThemeAddClass(this._$table, 'ui-widget-content'); this._createTableHead(); this._createTableBody(); }, /* Creates header (all column headers) of the table. *************************************************************************/ _createTableHead: function () { var $thead = $('<thead></thead>') .appendTo(this._$table); this._addRowToTableHead($thead); }, /* Adds tr element to given thead element *************************************************************************/ _addRowToTableHead: function ($thead) { var $tr = $('<tr></tr>') .appendTo($thead); this._addColumnsToHeaderRow($tr); }, /* Adds column header cells to given tr element. *************************************************************************/ _addColumnsToHeaderRow: function ($tr) { for (var i = 0; i < this._columnList.length; i++) { var fieldName = this._columnList[i]; var $headerCell = this._createHeaderCellForField(fieldName, this.options.fields[fieldName]); $headerCell.appendTo($tr); } }, /* Creates a header cell for given field. * Returns th jQuery object. *************************************************************************/ _createHeaderCellForField: function (fieldName, field) { field.width = field.width || '10%'; //default column width: 10%. var $headerTextSpan = $('<span />') .addClass('jtable-column-header-text') .html(field.title); var $headerContainerDiv = $('<div />') .addClass('jtable-column-header-container') .append($headerTextSpan); var $th = $('<th></th>') .addClass('jtable-column-header') .addClass(field.listClass) .css('width', field.width) .data('fieldName', fieldName) .append($headerContainerDiv); this._jqueryuiThemeAddClass($th, 'ui-state-default'); return $th; }, /* Creates an empty header cell that can be used as command column headers. *************************************************************************/ _createEmptyCommandHeader: function () { var $th = $('<th></th>') .addClass('jtable-command-column-header') .css('width', '1%'); this._jqueryuiThemeAddClass($th, 'ui-state-default'); return $th; }, /* Creates tbody tag and adds to the table. *************************************************************************/ _createTableBody: function () { this._$tableBody = $('<tbody></tbody>').appendTo(this._$table); }, /* Creates a div to block UI while jTable is busy. *************************************************************************/ _createBusyPanel: function () { this._$busyMessageDiv = $('<div />').addClass('jtable-busy-message').prependTo(this._$mainContainer); this._$busyDiv = $('<div />').addClass('jtable-busy-panel-background').prependTo(this._$mainContainer); this._jqueryuiThemeAddClass(this._$busyMessageDiv, 'ui-widget-header'); this._hideBusy(); }, /* Creates and prepares error dialog div. *************************************************************************/ _createErrorDialogDiv: function () { var self = this; self._$errorDialogDiv = $('<div></div>').appendTo(self._$mainContainer); self._$errorDialogDiv.dialog({ autoOpen: false, show: self.options.dialogShowEffect, hide: self.options.dialogHideEffect, modal: true, dialogClass: "edit_order_dialog", title: self.options.messages.error, buttons: [{ text: self.options.messages.close, click: function () { self._$errorDialogDiv.dialog('close'); } }], open: function( event, ui ) { var height = $( window ).height(), dialog = $( this ).closest( "div.ui-dialog" ).appendTo( "#navBars" ); dialog.offset({ top: (height - dialog.height()) / 2 - 10 }); } }); }, /************************************************************************ * PUBLIC METHODS * *************************************************************************/ /* Loads data using AJAX call, clears table and fills with new data. *************************************************************************/ load: function (postData, completeCallback) { if ( "undefined" === typeof postData ) postData = this._loadPostDataSettings(); this._lastPostData = postData; /* Order Handler - Added to save Sorting Selection */ this._savePostDataSettings(); this._reloadTable(completeCallback); }, // _delete_cookie: function ( name ) { // document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;'; // }, /* Order Handler - Saves user preferences for sorting *************************************************************************/ _savePostDataSettings: function() { // if( null !== this._getCookie('postdata-sorting') ) { // var key = this._cookieKeyPrefix + 'postdata-sorting'; // document.cookie = encodeURIComponent( key ) + '=; expires=Thu, 01 Jan 1970 00:00:01 GMT;'; // } var params = ""; if (!this.options.saveUserPreferences || "undefined" == typeof this._lastPostData) { return; } for(var name in this._lastPostData) { params = '{"status":"' + '&' + name + '=' + this._lastPostData[name] + '"}'; } if( "undefined" !== typeof params ) { this._setCookie('postdata-sorting', params); } }, /* Order Handler - Loads user preferences for paging. *************************************************************************/ _loadPostDataSettings: function() { if (!this.options.saveUserPreferences) { return; } var params = $.parseJSON(this._getCookie('postdata-sorting')), status = "", param = "", obj = {}; if ( null === params ) return; for ( var name in params ) { // status = name; param = params[ name ]; } value = param.match(/=(.+)/); if ( null === value ) return; value = value[1]; status = param.match( /^&(.+)=/ ); status = status[1]; $( "#" + status ).val( value ); if ( 'status_pf' == status && '1' == value ) { polling = true; } obj[ status ] = value; if ( params ) { return obj; } }, /* Refreshes (re-loads) table data with last postData. *************************************************************************/ reload: function (completeCallback) { this._reloadTable(completeCallback); }, /* Gets a jQuery row object according to given record key *************************************************************************/ getRowByKey: function (key) { for (var i = 0; i < this._$tableRows.length; i++) { if (key == this._getKeyValueOfRecord(this._$tableRows[i].data('record'))) { return this._$tableRows[i]; } } return null; }, /* Completely removes the table from it's container. *************************************************************************/ destroy: function () { this.element.empty(); $.Widget.prototype.destroy.call(this); }, /* Block the table while performing actions on it. *************************************************************************/ showBusy: function (message,delay) { this._showBusy(message,delay); }, /* UnBlock the table *************************************************************************/ hideBusy: function (message) { this._hideBusy(); }, /************************************************************************ * PRIVATE METHODS * *************************************************************************/ /* Used to change options dynamically after initialization. *************************************************************************/ _setOption: function (key, value) { }, /* LOADING RECORDS *****************************************************/ /* Performs an AJAX call to reload data of the table. *************************************************************************/ _reloadTable: function (completeCallback) { var self = this; var completeReload = function(data) { self._hideBusy(); //Show the error message if server returns error if (data.Result != 'OK') { self._showError(data.Message); return; } //Re-generate table rows self._removeAllRows('reloading'); self._addRecordsToTable(data.Records); self._onRecordsLoaded(data); //Call complete callback if (completeCallback) { completeCallback(); } }; self._showBusy(self.options.messages.loadingMessage, self.options.loadingAnimationDelay); //Disable table since it's busy self._onLoadingRecords(); //listAction may be a function, check if it is if ($.isFunction(self.options.actions.listAction)) { //Execute the function var funcResult = self.options.actions.listAction(self._lastPostData, self._createJtParamsForLoading()); //Check if result is a jQuery Deferred object if (self._isDeferredObject(funcResult)) { funcResult.done(function(data) { completeReload(data); }).fail(function() { self._showError(self.options.messages.serverCommunicationError); }).always(function() { self._hideBusy(); }); } else { //assume it's the data we're loading completeReload(funcResult); } } else { //assume listAction as URL string. //Generate URL (with query string parameters) to load records var loadUrl = self._createRecordLoadUrl(); //Load data from server using AJAX self._ajax({ url: loadUrl, data: self._lastPostData, success: function (data) { completeReload(data); }, error: function () { self._hideBusy(); self._showError(self.options.messages.serverCommunicationError); } }); } }, /* Creates URL to load records. *************************************************************************/ _createRecordLoadUrl: function () { return this.options.actions.listAction; }, _createJtParamsForLoading: function() { return { //Empty as default, paging, sorting or other extensions can override this method to add additional params to load request }; }, /* TABLE MANIPULATION METHODS *******************************************/ /* Creates a row from given record *************************************************************************/ _createRowFromRecord: function (record) { var $tr = $('<tr></tr>') .addClass('jtable-data-row') .attr('data-record-key', this._getKeyValueOfRecord(record)) .data('record', record); this._addCellsToRowUsingRecord($tr); // $tr.find( '.tooltip_set').qtip({ // style: { // classes: 'qtip-bootstrap', // }, // position: { // viewport: $(window) // }, // show: { // // solo: true, // effect: function() { // $(this).fadeIn(400); // } // }, // hide: { // distance: 30, // effect: function() { // $(this).fadeOut(400); // } // } // }); if ( "true" == localStorage.toolTips ) $( $tr ).find( '.tooltip_set').tlp(); else $( $tr ).find( '.comments').tlp(); return $tr; }, /* Adds all cells to given row. *************************************************************************/ _addCellsToRowUsingRecord: function ($row) { var record = $row.data('record'); for (var i = 0; i < this._columnList.length; i++) { this._createCellForRecordField(record, this._columnList[i]) .appendTo($row); } }, /* Create a cell for given field. *************************************************************************/ _createCellForRecordField: function (record, fieldName) { return $('<td></td>') .addClass(this.options.fields[fieldName].listClass) .append((this._getDisplayTextForRecordField(record, fieldName))); }, /* Adds a list of records to the table. *************************************************************************/ _addRecordsToTable: function (records) { var self = this; $.each(records, function (index, record) { self._addRow(self._createRowFromRecord(record)); }); self._refreshRowStyles(); }, /* Adds a single row to the table. * NOTE: THIS METHOD IS DEPRECATED AND WILL BE REMOVED FROM FEATURE RELEASES. * USE _addRow METHOD. *************************************************************************/ _addRowToTable: function ($tableRow, index, isNewRow, animationsEnabled) { var options = { index: this._normalizeNumber(index, 0, this._$tableRows.length, this._$tableRows.length) }; if (isNewRow == true) { options.isNewRow = true; } if (animationsEnabled === false) { options.animationsEnabled = false; } this._addRow($tableRow, options); }, /* Adds a single row to the table. *************************************************************************/ _addRow: function ($row, options) { //Set defaults options = $.extend({ index: this._$tableRows.length, isNewRow: false, animationsEnabled: true }, options); //Remove 'no data' row if this is first row if (this._$tableRows.length <= 0) { this._removeNoDataRow(); } //Add new row to the table according to it's index options.index = this._normalizeNumber(options.index, 0, this._$tableRows.length, this._$tableRows.length); if (options.index == this._$tableRows.length) { //add as last row this._$tableBody.append($row); this._$tableRows.push($row); } else if (options.index === 0) { //add as first row this._$tableBody.prepend($row); this._$tableRows.unshift($row); } else { //insert to specified index this._$tableRows[options.index - 1].after($row); this._$tableRows.splice(options.index, 0, $row); } this._onRowInserted($row, options.isNewRow); //Show animation if needed if (options.isNewRow) { this._refreshRowStyles(); if (this.options.animationsEnabled && options.animationsEnabled) { this._showNewRowAnimation($row); } } }, /* Shows created animation for a table row * TODO: Make this animation cofigurable and changable *************************************************************************/ _showNewRowAnimation: function ($tableRow) { var className = 'jtable-row-created'; if (this.options.jqueryuiTheme) { className = className + ' ui-state-highlight'; } $tableRow.addClass(className, 'slow', '', function () { $tableRow.removeClass(className, 5000); }); }, /* Removes a row or rows (jQuery selection) from table. *************************************************************************/ _removeRowsFromTable: function ($rows, reason) { var self = this; //Check if any row specified if ($rows.length <= 0) { return; } //remove from DOM $rows.addClass('jtable-row-removed').remove(); //remove from _$tableRows array $rows.each(function () { var index = self._findRowIndex($(this)); if (index >= 0) { self._$tableRows.splice(index, 1); } }); self._onRowsRemoved($rows, reason); //Add 'no data' row if all rows removed from table if (self._$tableRows.length == 0) { self._addNoDataRow(); } self._refreshRowStyles(); }, /* Finds index of a row in table. *************************************************************************/ _findRowIndex: function ($row) { return this._findIndexInArray($row, this._$tableRows, function ($row1, $row2) { return $row1.data('record') == $row2.data('record'); }); }, /* Removes all rows in the table and adds 'no data' row. *************************************************************************/ _removeAllRows: function (reason) { //If no rows does exists, do nothing if (this._$tableRows.length <= 0) { return; } //Select all rows (to pass it on raising _onRowsRemoved event) var $rows = this._$tableBody.find('tr.jtable-data-row'); //Remove all rows from DOM and the _$tableRows array this._$tableBody.empty(); this._$tableRows = []; this._onRowsRemoved($rows, reason); //Add 'no data' row since we removed all rows this._addNoDataRow(); }, /* Adds "no data available" row to the table. *************************************************************************/ _addNoDataRow: function () { if (this._$tableBody.find('>tr.jtable-no-data-row').length > 0) { return; } var $tr = $('<tr></tr>') .addClass('jtable-no-data-row') .appendTo(this._$tableBody); var totalColumnCount = this._$table.find('thead th').length; $('<td></td>') .attr('colspan', totalColumnCount) .html(this.options.messages.noDataAvailable) .appendTo($tr); }, /* Removes "no data available" row from the table. *************************************************************************/ _removeNoDataRow: function () { this._$tableBody.find('.jtable-no-data-row').remove(); }, /* Refreshes styles of all rows in the table *************************************************************************/ _refreshRowStyles: function () { for (var i = 0; i < this._$tableRows.length; i++) { if (i % 2 == 0) { this._$tableRows[i].addClass('jtable-row-even'); } else { this._$tableRows[i].removeClass('jtable-row-even'); } } }, /* RENDERING FIELD VALUES ***********************************************/ /* Gets text for a field of a record according to it's type. *************************************************************************/ _getDisplayTextForRecordField: function (record, fieldName) { var field = this.options.fields[fieldName]; var fieldValue = record[fieldName]; //if this is a custom field, call display function if (field.display) { return field.display({ record: record }); } if (field.type == 'date') { return this._getDisplayTextForDateRecordField(field, fieldValue); } else if (field.type == 'checkbox') { return this._getCheckBoxTextForFieldByValue(fieldName, fieldValue); } else if (field.options) { //combobox or radio button list since there are options. var options = this._getOptionsForField(fieldName, { record: record, value: fieldValue, source: 'list', dependedValues: this._createDependedValuesUsingRecord(record, field.dependsOn) }); return this._findOptionByValue(options, fieldValue).DisplayText; } else { //other types return fieldValue; } }, /* Creates and returns an object that's properties are depended values of a record. *************************************************************************/ _createDependedValuesUsingRecord: function (record, dependsOn) { if (!dependsOn) { return {}; } var dependedValues = {}; for (var i = 0; i < dependsOn.length; i++) { dependedValues[dependsOn[i]] = record[dependsOn[i]]; } return dependedValues; }, /* Finds an option object by given value. *************************************************************************/ _findOptionByValue: function (options, value) { for (var i = 0; i < options.length; i++) { if (options[i].Value == value) { return options[i]; } } return {}; //no option found }, /* Gets text for a date field. *************************************************************************/ _getDisplayTextForDateRecordField: function (field, fieldValue) { if (!fieldValue) { return ''; } var displayFormat = field.displayFormat || this.options.defaultDateFormat; var date = this._parseDate(fieldValue); return $.datepicker.formatDate(displayFormat, date); }, /* Gets options for a field according to user preferences. *************************************************************************/ _getOptionsForField: function (fieldName, funcParams) { var field = this.options.fields[fieldName]; var optionsSource = field.options; if ($.isFunction(optionsSource)) { //prepare parameter to the function funcParams = $.extend(true, { _cacheCleared: false, dependedValues: {}, clearCache: function () { this._cacheCleared = true; } }, funcParams); //call function and get actual options source optionsSource = optionsSource(funcParams); } var options; //Build options according to it's source type if (typeof optionsSource == 'string') { //It is an Url to download options var cacheKey = 'options_' + fieldName + '_' + optionsSource; //create a unique cache key if (funcParams._cacheCleared || (!this._cache[cacheKey])) { //if user calls clearCache() or options are not found in the cache, download options this._cache[cacheKey] = this._buildOptionsFromArray(this._downloadOptions(fieldName, optionsSource)); this._sortFieldOptions(this._cache[cacheKey], field.optionsSorting); } else { //found on cache.. //if this method (_getOptionsForField) is called to get option for a specific value (on funcParams.source == 'list') //and this value is not in cached options, we need to re-download options to get the unfound (probably new) option. if (funcParams.value != undefined) { var optionForValue = this._findOptionByValue(this._cache[cacheKey], funcParams.value); if (optionForValue.DisplayText == undefined) { //this value is not in cached options... this._cache[cacheKey] = this._buildOptionsFromArray(this._downloadOptions(fieldName, optionsSource)); this._sortFieldOptions(this._cache[cacheKey], field.optionsSorting); } } } options = this._cache[cacheKey]; } else if (jQuery.isArray(optionsSource)) { //It is an array of options options = this._buildOptionsFromArray(optionsSource); this._sortFieldOptions(options, field.optionsSorting); } else { //It is an object that it's properties are options options = this._buildOptionsArrayFromObject(optionsSource); this._sortFieldOptions(options, field.optionsSorting); } return options; }, /* Download options for a field from server. *************************************************************************/ _downloadOptions: function (fieldName, url) { var self = this; var options = []; self._ajax({ url: url, async: false, success: function (data) { if (data.Result != 'OK') { self._showError(data.Message); return; } options = data.Options; }, error: function () { var errMessage = self._formatString(self.options.messages.cannotLoadOptionsFor, fieldName); self._showError(errMessage); } }); return options; }, /* Sorts given options according to sorting parameter. * sorting can be: 'value', 'value-desc', 'text' or 'text-desc'. *************************************************************************/ _sortFieldOptions: function (options, sorting) { if ((!options) || (!options.length) || (!sorting)) { return; } //Determine using value of text var dataSelector; if (sorting.indexOf('value') == 0) { dataSelector = function (option) { return option.Value; }; } else { //assume as text dataSelector = function (option) { return option.DisplayText; }; } var compareFunc; if ($.type(dataSelector(options[0])) == 'string') { compareFunc = function (option1, option2) { return dataSelector(option1).localeCompare(dataSelector(option2)); }; } else { //asuume as numeric compareFunc = function (option1, option2) { return dataSelector(option1) - dataSelector(option2); }; } if (sorting.indexOf('desc') > 0) { options.sort(function (a, b) { return compareFunc(b, a); }); } else { //assume as asc options.sort(function (a, b) { return compareFunc(a, b); }); } }, /* Creates an array of options from given object. *************************************************************************/ _buildOptionsArrayFromObject: function (options) { var list = []; $.each(options, function (propName, propValue) { list.push({ Value: propName, DisplayText: propValue }); }); return list; }, /* Creates array of options from giving options array. *************************************************************************/ _buildOptionsFromArray: function (optionsArray) { var list = []; for (var i = 0; i < optionsArray.length; i++) { if ($.isPlainObject(optionsArray[i])) { list.push(optionsArray[i]); } else { //assumed as primitive type (int, string...) list.push({ Value: optionsArray[i], DisplayText: optionsArray[i] }); } } return list; }, /* Parses given date string to a javascript Date object. * Given string must be formatted one of the samples shown below: * /Date(1320259705710)/ * 2011-01-01 20:32:42 (YYYY-MM-DD HH:MM:SS) * 2011-01-01 (YYYY-MM-DD) *************************************************************************/ _parseDate: function (dateString) { if (dateString.indexOf('Date') >= 0) { //Format: /Date(1320259705710)/ return new Date( parseInt(dateString.substr(6), 10) ); } else if (dateString.length == 10) { //Format: 2011-01-01 return new Date( parseInt(dateString.substr(0, 4), 10), parseInt(dateString.substr(5, 2), 10) - 1, parseInt(dateString.substr(8, 2), 10) ); } else if (dateString.length == 19) { //Format: 2011-01-01 20:32:42 return new Date( parseInt(dateString.substr(0, 4), 10), parseInt(dateString.substr(5, 2), 10) - 1, parseInt(dateString.substr(8, 2, 10)), parseInt(dateString.substr(11, 2), 10), parseInt(dateString.substr(14, 2), 10), parseInt(dateString.substr(17, 2), 10) ); } else { this._logWarn('Given date is not properly formatted: ' + dateString); return 'format error!'; } }, /* TOOL BAR *************************************************************/ /* Creates the toolbar. *************************************************************************/ _createToolBar: function () { this._$toolbarDiv = $('<div />') .addClass('jtable-toolbar') .appendTo(this._$titleDiv); for (var i = 0; i < this.options.toolbar.items.length; i++) { this._addToolBarItem(this.options.toolbar.items[i]); } }, /* Adds a new item to the toolbar. *************************************************************************/ _addToolBarItem: function (item) { //Check if item is valid if ((item == undefined) || (item.text == undefined && item.icon == undefined)) { this._logWarn('Can not add tool bar item since it is not valid!'); this._logWarn(item); return null; } var $toolBarItem = $('<span></span>') .addClass('jtable-toolbar-item') .appendTo(this._$toolbarDiv); this._jqueryuiThemeAddClass($toolBarItem, 'ui-widget ui-state-default ui-corner-all', 'ui-state-hover'); //cssClass property if (item.cssClass) { $toolBarItem .addClass(item.cssClass); } //tooltip property if (item.tooltip) { $toolBarItem .attr('title', item.tooltip); } //icon property if (item.icon) { var $icon = $('<span class="jtable-toolbar-item-icon"></span>').appendTo($toolBarItem); if (item.icon === true) { //do nothing } else if ($.type(item.icon === 'string')) { $icon.css('background', 'url("' + item.icon + '")'); } } //Added for Order Handler - css icon property if (item.iconCSS) { var $iconCSS = $('<span class="jtable-toolbar-item-icon"></span>').appendTo($toolBarItem); if (item.iconCSS === true) { //do nothing } else if ($.type(item.iconCSS === 'string')) { var $iconCSSimage = $('<i class="fa ' + item.iconCSS + '"></i>').appendTo($iconCSS); } } //text property if (item.text) { $('<span class=""></span>') .html(item.text) .addClass('jtable-toolbar-item-text').appendTo($toolBarItem); } //click event if (item.click) { $toolBarItem.click(function () { item.click(); }); } //set hover animation parameters var hoverAnimationDuration = undefined; var hoverAnimationEasing = undefined; if (this.options.toolbar.hoverAnimation) { hoverAnimationDuration = this.options.toolbar.hoverAnimationDuration; hoverAnimationEasing = this.options.toolbar.hoverAnimationEasing; } //change class on hover $toolBarItem.hover(function () { $toolBarItem.addClass('jtable-toolbar-item-hover', hoverAnimationDuration, hoverAnimationEasing); }, function () { $toolBarItem.removeClass('jtable-toolbar-item-hover', hoverAnimationDuration, hoverAnimationEasing); }); return $toolBarItem; }, /* ERROR DIALOG *********************************************************/ /* Shows error message dialog with given message. *************************************************************************/ _showError: function (message) { this._$errorDialogDiv.html(message).dialog('open'); }, /* BUSY PANEL ***********************************************************/ /* Shows busy indicator and blocks table UI. * TODO: Make this cofigurable and changable *************************************************************************/ _setBusyTimer: null, _showBusy: function (message, delay) { var self = this; // //Show a transparent overlay to prevent clicking to the table self._$busyDiv .width(self._$mainContainer.width()) .height(self._$mainContainer.height()) .addClass('jtable-busy-panel-background-invisible') .show(); var makeVisible = function () { self._$busyDiv.removeClass('jtable-busy-panel-background-invisible'); self._$busyMessageDiv.html(message).show(); }; if (delay) { if (self._setBusyTimer) { return; } self._setBusyTimer = setTimeout(makeVisible, delay); } else { makeVisible(); } }, /* Hides busy indicator and unblocks table UI. *************************************************************************/ _hideBusy: function () { clearTimeout(this._setBusyTimer); this._setBusyTimer = null; this._$busyDiv.hide(); this._$busyMessageDiv.html('').hide(); }, /* Returns true if jTable is busy. *************************************************************************/ _isBusy: function () { return this._$busyMessageDiv.is(':visible'); }, /* Adds jQueryUI class to an item. *************************************************************************/ _jqueryuiThemeAddClass: function ($elm, className, hoverClassName) { if (!this.options.jqueryuiTheme) { return; } $elm.addClass(className); if (hoverClassName) { $elm.hover(function () { $elm.addClass(hoverClassName); }, function () { $elm.removeClass(hoverClassName); }); } }, /* COMMON METHODS *******************************************************/ /* Performs an AJAX call to specified URL. * THIS METHOD IS DEPRECATED AND WILL BE REMOVED FROM FEATURE RELEASES. * USE _ajax METHOD. *************************************************************************/ _performAjaxCall: function (url, postData, async, success, error) { this._ajax({ url: url, data: postData, async: async, success: success, error: error }); }, _unAuthorizedRequestHandler: function() { if (this.options.unAuthorizedRequestRedirectUrl) { location.href = this.options.unAuthorizedRequestRedirectUrl; } else { location.reload(true); } }, /* This method is used to perform AJAX calls in jTable instead of direct * usage of jQuery.ajax method. *************************************************************************/ _ajax: function (options) { var self = this; //Handlers for HTTP status codes var opts = { statusCode: { 401: function () { //Unauthorized self._unAuthorizedRequestHandler(); } }, global: false, }; opts = $.extend(opts, this.options.ajaxSettings, options); //Override success opts.success = function (data) { //Checking for Authorization error if (data && data.UnAuthorizedRequest == true) { self._unAuthorizedRequestHandler(); } if (options.success) { options.success(data); } }; //Override error opts.error = function (jqXHR, textStatus, errorThrown) { if (unloadingPage) { jqXHR.abort(); return; } if (options.error) { options.error(arguments); } }; //Override complete opts.complete = function () { if (options.complete) { options.complete(); } }; $.ajax(opts); }, /* Gets value of key field of a record. *************************************************************************/ _getKeyValueOfRecord: function (record) { return record[this._keyField]; }, /************************************************************************ * COOKIE * *************************************************************************/ /* Sets a cookie with given key. *************************************************************************/ _setCookie: function (key, value) { key = this._cookieKeyPrefix + key; var expireDate = new Date(); expireDate.setDate(expireDate.getDate() + 30); document.cookie = encodeURIComponent(key) + '=' + encodeURIComponent(value) + "; expires=" + expireDate.toUTCString(); }, /* Gets a cookie with given key. *************************************************************************/ _getCookie: function (key) { key = this._cookieKeyPrefix + key; var equalities = document.cookie.split('; '); for (var i = 0; i < equalities.length; i++) { if (!equalities[i]) { continue; } var splitted = equalities[i].split('='); if (splitted.length != 2) { continue; } if (decodeURIComponent(splitted[0]) === key) { return decodeURIComponent(splitted[1] || ''); } } return null; }, /* Generates a hash key to be prefix for all cookies for this jtable instance. *************************************************************************/ _generateCookieKeyPrefix: function () { var simpleHash = function (value) { var hash = 0; if (value.length == 0) { return hash; } for (var i = 0; i < value.length; i++) { var ch = value.charCodeAt(i); hash = ((hash << 5) - hash) + ch; hash = hash & hash; } return hash; }; var strToHash = ''; if (this.options.tableId) { strToHash = strToHash + this.options.tableId + '#'; } strToHash = strToHash + this._columnList.join('$') + '#c' + this._$table.find('thead th').length; return 'jtable#' + simpleHash(strToHash); }, /************************************************************************ * EVENT RAISING METHODS * *************************************************************************/ _onLoadingRecords: function () { this._trigger("loadingRecords", null, {}); }, _onRecordsLoaded: function (data) { this._trigger("recordsLoaded", null, { records: data.Records, serverResponse: data }); }, _onRowInserted: function ($row, isNewRow) { this._trigger("rowInserted", null, { row: $row, record: $row.data('record'), isNewRow: isNewRow }); }, _onRowsRemoved: function ($rows, reason) { this._trigger("rowsRemoved", null, { rows: $rows, reason: reason }); }, _onCloseRequested: function () { this._trigger("closeRequested", null, {}); } }); }(jQuery)); /************************************************************************ * Some UTULITY methods used by jTable * *************************************************************************/ (function ($) { $.extend(true, $.hik.jtable.prototype, { /* Gets property value of an object recursively. *************************************************************************/ _getPropertyOfObject: function (obj, propName) { if (propName.indexOf('.') < 0) { return obj[propName]; } else { var preDot = propName.substring(0, propName.indexOf('.')); var postDot = propName.substring(propName.indexOf('.') + 1); return this._getPropertyOfObject(obj[preDot], postDot); } }, /* Sets property value of an object recursively. *************************************************************************/ _setPropertyOfObject: function (obj, propName, value) { if (propName.indexOf('.') < 0) { obj[propName] = value; } else { var preDot = propName.substring(0, propName.indexOf('.')); var postDot = propName.substring(propName.indexOf('.') + 1); this._setPropertyOfObject(obj[preDot], postDot, value); } }, /* Inserts a value to an array if it does not exists in the array. *************************************************************************/ _insertToArrayIfDoesNotExists: function (array, value) { if ($.inArray(value, array) < 0) { array.push(value); } }, /* Finds index of an element in an array according to given comparision function *************************************************************************/ _findIndexInArray: function (value, array, compareFunc) { //If not defined, use default comparision if (!compareFunc) { compareFunc = function (a, b) { return a == b; }; } for (var i = 0; i < array.length; i++) { if (compareFunc(value, array[i])) { return i; } } return -1; }, /* Normalizes a number between given bounds or sets to a defaultValue * if it is undefined *************************************************************************/ _normalizeNumber: function (number, min, max, defaultValue) { if (number == undefined || number == null || isNaN(number)) { return defaultValue; } if (number < min) { return min; } if (number > max) { return max; } return number; }, /* Formats a string just like string.format in c#. * Example: * _formatString('Hello {0}','Halil') = 'Hello Halil' *************************************************************************/ _formatString: function () { if (arguments.length === 0) { return null; } var str = arguments[0]; for (var i = 1; i < arguments.length; i++) { var placeHolder = '{' + (i - 1) + '}'; str = str.replace(placeHolder, arguments[i]); } return str; }, /* Checks if given object is a jQuery Deferred object. */ _isDeferredObject: function (obj) { return obj.then && obj.done && obj.fail; }, //Logging methods //////////////////////////////////////////////////////// _logDebug: function (text) { if (!window.console) { return; } console.log('jTable DEBUG: ' + text); }, _logInfo: function (text) { if (!window.console) { return; } console.log('jTable INFO: ' + text); }, _logWarn: function (text) { if (!window.console) { return; } console.log('jTable WARNING: ' + text); }, _logError: function (text) { if (!window.console) { return; } console.log('jTable ERROR: ' + text); } }); /* Fix for array.indexOf method in IE7. * This code is taken from http://www.tutorialspoint.com/javascript/array_indexof.htm */ if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (elt) { var len = this.length; var from = Number(arguments[1]) || 0; from = (from < 0) ? Math.ceil(from) : Math.floor(from); if (from < 0) from += len; for (; from < len; from++) { if (from in this && this[from] === elt) return from; } return -1; }; } })(jQuery); /************************************************************************ * FORMS extension for jTable (base for edit/create forms) * *************************************************************************/ (function ($) { $.extend(true, $.hik.jtable.prototype, { /************************************************************************ * PRIVATE METHODS * *************************************************************************/ /* Submits a form asynchronously using AJAX. * This method is needed, since form submitting logic can be overrided * by extensions. *************************************************************************/ _submitFormUsingAjax: function (url, formData, success, error) { this._ajax({ url: url, data: formData, success: success, error: error }); }, /* Creates label for an input element. *************************************************************************/ _createInputLabelForRecordField: function (fieldName) { //TODO: May create label tag instead of a div. return $('<div />') .addClass('jtable-input-label') .html(this.options.fields[fieldName].inputTitle || this.options.fields[fieldName].title); }, /* Creates an input element according to field type. *************************************************************************/ _createInputForRecordField: function (funcParams) { var fieldName = funcParams.fieldName, value = funcParams.value, record = funcParams.record, formType = funcParams.formType, form = funcParams.form; //Get the field var field = this.options.fields[fieldName]; //If value if not supplied, use defaultValue of the field if (value == undefined || value == null) { value = field.defaultValue; } //Use custom function if supplied if (field.input) { var $input = $(field.input({ value: value, record: record, formType: formType, form: form })); //Add id attribute if does not exists if (!$input.attr('id')) { $input.attr('id', 'Edit-' + fieldName); } //Wrap input element with div return $('<div />') .addClass('jtable-input jtable-custom-input') .append($input); } //Create input according to field type if (field.type == 'date') { return this._createDateInputForField(field, fieldName, value); } else if (field.type == 'textarea') { return this._createTextAreaForField(field, fieldName, value); } else if (field.type == 'password') { return this._createPasswordInputForField(field, fieldName, value); } else if (field.type == 'checkbox') { return this._createCheckboxForField(field, fieldName, value); } else if (field.options) { if (field.type == 'radiobutton') { return this._createRadioButtonListForField(field, fieldName, value, record, formType); } else { return this._createDropDownListForField(field, fieldName, value, record, formType, form); } } else { return this._createTextInputForField(field, fieldName, value); } }, //Creates a hidden input element with given name and value. _createInputForHidden: function (fieldName, value) { if (value == undefined) { value = ""; } return $('<input type="hidden" name="' + fieldName + '" id="Edit-' + fieldName + '"></input>') .val(value); }, /* Creates a date input for a field. *************************************************************************/ _createDateInputForField: function (field, fieldName, value) { var $input = $('<input class="' + field.inputClass + '" id="Edit-' + fieldName + '" type="text" name="' + fieldName + '"></input>'); if(value !== undefined) { $input.val(value); } var displayFormat = field.displayFormat || this.options.defaultDateFormat; $input.datepicker({ dateFormat: displayFormat }); return $('<div />') .addClass('jtable-input jtable-date-input') .append($input); }, /* Creates a textarea element for a field. *************************************************************************/ _createTextAreaForField: function (field, fieldName, value) { var $textArea = $('<textarea class="' + field.inputClass + '" id="Edit-' + fieldName + '" name="' + fieldName + '"></textarea>'); if (value != undefined) { $textArea.val(value); } return $('<div />') .addClass('jtable-input jtable-textarea-input') .append($textArea); }, /* Creates a standart textbox for a field. *************************************************************************/ _createTextInputForField: function (field, fieldName, value) { var $input = $('<input class="' + field.inputClass + '" id="Edit-' + fieldName + '" type="text" name="' + fieldName + '"></input>'); if (value != undefined) { $input.val(value); } return $('<div />') .addClass('jtable-input jtable-text-input') .append($input); }, /* Creates a password input for a field. *************************************************************************/ _createPasswordInputForField: function (field, fieldName, value) { var $input = $('<input class="' + field.inputClass + '" id="Edit-' + fieldName + '" type="password" name="' + fieldName + '"></input>'); if (value != undefined) { $input.val(value); } return $('<div />') .addClass('jtable-input jtable-password-input') .append($input); }, /* Creates a checkboxfor a field. *************************************************************************/ _createCheckboxForField: function (field, fieldName, value) { var self = this; //If value is undefined, get unchecked state's value if (value == undefined) { value = self._getCheckBoxPropertiesForFieldByState(fieldName, false).Value; } //Create a container div var $containerDiv = $('<div />') .addClass('jtable-input jtable-checkbox-input'); //Create checkbox and check if needed var $checkBox = $('<input class="' + field.inputClass + '" id="Edit-' + fieldName + '" type="checkbox" name="' + fieldName + '" />') .appendTo($containerDiv); if (value != undefined) { $checkBox.val(value); } //Create display text of checkbox for current state var $textSpan = $('<span>' + (field.formText || self._getCheckBoxTextForFieldByValue(fieldName, value)) + '</span>') .appendTo($containerDiv); //Check the checkbox if it's value is checked-value if (self._getIsCheckBoxSelectedForFieldByValue(fieldName, value)) { $checkBox.attr('checked', 'checked'); } //This method sets checkbox's value and text according to state of the checkbox var refreshCheckBoxValueAndText = function () { var checkboxProps = self._getCheckBoxPropertiesForFieldByState(fieldName, $checkBox.is(':checked')); $checkBox.attr('value', checkboxProps.Value); $textSpan.html(field.formText || checkboxProps.DisplayText); }; //Register to click event to change display text when state of checkbox is changed. $checkBox.click(function () { refreshCheckBoxValueAndText(); }); //Change checkbox state when clicked to text if (field.setOnTextClick != false) { $textSpan .addClass('jtable-option-text-clickable') .click(function () { if ($checkBox.is(':checked')) { $checkBox.attr('checked', false); } else { $checkBox.attr('checked', true); } refreshCheckBoxValueAndText(); }); } return $containerDiv; }, /* Creates a drop down list (combobox) input element for a field. *************************************************************************/ _createDropDownListForField: function (field, fieldName, value, record, source, form) { //Create a container div var $containerDiv = $('<div />') .addClass('jtable-input jtable-dropdown-input'); //Create select element var $select = $('<select class="' + field.inputClass + '" id="Edit-' + fieldName + '" name="' + fieldName + '"></select>') .appendTo($containerDiv); //add options var options = this._getOptionsForField(fieldName, { record: record, source: source, form: form, dependedValues: this._createDependedValuesUsingForm(form, field.dependsOn) }); this._fillDropDownListWithOptions($select, options, value); return $containerDiv; }, /* Fills a dropdown list with given options. *************************************************************************/ _fillDropDownListWithOptions: function ($select, options, value) { $select.empty(); for (var i = 0; i < options.length; i++) { $('<option' + (options[i].Value == value ? ' selected="selected"' : '') + '>' + options[i].DisplayText + '</option>') .val(options[i].Value) .appendTo($select); } }, /* Creates depended values object from given form. *************************************************************************/ _createDependedValuesUsingForm: function ($form, dependsOn) { if (!dependsOn) { return {}; } var dependedValues = {}; for (var i = 0; i < dependsOn.length; i++) { var dependedField = dependsOn[i]; var $dependsOn = $form.find('select[name=' + dependedField + ']'); if ($dependsOn.length <= 0) { continue; } dependedValues[dependedField] = $dependsOn.val(); } return dependedValues; }, /* Creates a radio button list for a field. *************************************************************************/ _createRadioButtonListForField: function (field, fieldName, value, record, source) { var $containerDiv = $('<div />') .addClass('jtable-input jtable-radiobuttonlist-input'); var options = this._getOptionsForField(fieldName, { record: record, source: source }); $.each(options, function(i, option) { var $radioButtonDiv = $('<div class=""></div>') .addClass('jtable-radio-input') .appendTo($containerDiv); var $radioButton = $('<input type="radio" id="Edit-' + fieldName + '-' + i + '" class="' + field.inputClass + '" name="' + fieldName + '"' + ((option.Value == (value + '')) ? ' checked="true"' : '') + ' />') .val(option.Value) .appendTo($radioButtonDiv); var $textSpan = $('<span></span>') .html(option.DisplayText) .appendTo($radioButtonDiv); if (field.setOnTextClick != false) { $textSpan .addClass('jtable-option-text-clickable') .click(function () { if (!$radioButton.is(':checked')) { $radioButton.attr('checked', true); } }); } }); return $containerDiv; }, /* Gets display text for a checkbox field. *************************************************************************/ _getCheckBoxTextForFieldByValue: function (fieldName, value) { return this.options.fields[fieldName].values[value]; }, /* Returns true if given field's value must be checked state. *************************************************************************/ _getIsCheckBoxSelectedForFieldByValue: function (fieldName, value) { return (this._createCheckBoxStateArrayForFieldWithCaching(fieldName)[1].Value.toString() == value.toString()); }, /* Gets an object for a checkbox field that has Value and DisplayText * properties. *************************************************************************/ _getCheckBoxPropertiesForFieldByState: function (fieldName, checked) { return this._createCheckBoxStateArrayForFieldWithCaching(fieldName)[(checked ? 1 : 0)]; }, /* Calls _createCheckBoxStateArrayForField with caching. *************************************************************************/ _createCheckBoxStateArrayForFieldWithCaching: function (fieldName) { var cacheKey = 'checkbox_' + fieldName; if (!this._cache[cacheKey]) { this._cache[cacheKey] = this._createCheckBoxStateArrayForField(fieldName); } return this._cache[cacheKey]; }, /* Creates a two element array of objects for states of a checkbox field. * First element for unchecked state, second for checked state. * Each object has two properties: Value and DisplayText *************************************************************************/ _createCheckBoxStateArrayForField: function (fieldName) { var stateArray = []; var currentIndex = 0; $.each(this.options.fields[fieldName].values, function (propName, propValue) { if (currentIndex++ < 2) { stateArray.push({ 'Value': propName, 'DisplayText': propValue }); } }); return stateArray; }, /* Searches a form for dependend dropdowns and makes them cascaded. */ _makeCascadeDropDowns: function ($form, record, source) { var self = this; $form.find('select') //for each combobox .each(function () { var $thisDropdown = $(this); //get field name var fieldName = $thisDropdown.attr('name'); if (!fieldName) { return; } var field = self.options.fields[fieldName]; //check if this combobox depends on others if (!field.dependsOn) { return; } //for each dependency $.each(field.dependsOn, function (index, dependsOnField) { //find the depended combobox var $dependsOnDropdown = $form.find('select[name=' + dependsOnField + ']'); //when depended combobox changes $dependsOnDropdown.change(function () { ______________________________________________________ * End Part 2 * ______________________________________________________ Quote osC OpenSSL Encryption with jCryptionSupport Forum jQuery/Ajax Advanced Statistics 2.3Support Forum jQuery/Ajax Advanced Order Handler 2.3.3Support ForumjQuery/Ajax Advanced Caching System 2.3.3Support ForumjQuery/Ajax Fast checkout/Shopping Cart/Login/Create Account 2.3.3Support ForumjQuery/Ajax Shopping Cart 2.3.3Support ForumjQuery/Ajax Dynamic Checkout 2.3.3Support ForumjQuery/Ajax Mini Cart for osCommerce 2.3.3Support ForumjQuery Cycle What's New InfoboxAuto Out Of Stock CSS Image OverlayjQuery-UI Autocomplete Product Search with Links & MySQLi support for osCommerce 2.X Link to comment Share on other sites More sharing options...
Dr. Rolex Posted October 6, 2014 Author Share Posted October 6, 2014 Replace ./admin/includes/modules/order_handler/js/01_02_jquery.jtable.js With This: (2/3 Part of this File) //Refresh options var funcParams = { record: record, source: source, form: $form, dependedValues: {} }; funcParams.dependedValues = self._createDependedValuesUsingForm($form, field.dependsOn); var options = self._getOptionsForField(fieldName, funcParams); //Fill combobox with new options self._fillDropDownListWithOptions($thisDropdown, options, undefined); //Thigger change event to refresh multi cascade dropdowns. $thisDropdown.change(); }); }); }); }, /* Updates values of a record from given form *************************************************************************/ _updateRecordValuesFromForm: function (record, $form) { for (var i = 0; i < this._fieldList.length; i++) { var fieldName = this._fieldList[i]; var field = this.options.fields[fieldName]; //Do not update non-editable fields if (field.edit == false) { continue; } //Get field name and the input element of this field in the form var $inputElement = $form.find('[name="' + fieldName + '"]'); if ($inputElement.length <= 0) { continue; } //Update field in record according to it's type if (field.type == 'date') { var dateVal = $inputElement.val(); if (dateVal) { var displayFormat = field.displayFormat || this.options.defaultDateFormat; try { var date = $.datepicker.parseDate(displayFormat, dateVal); record[fieldName] = '/Date(' + date.getTime() + ')/'; } catch (e) { //TODO: Handle incorrect/different date formats this._logWarn('Date format is incorrect for field ' + fieldName + ': ' + dateVal); record[fieldName] = undefined; } } else { this._logDebug('Date is empty for ' + fieldName); record[fieldName] = undefined; //TODO: undefined, null or empty string? } } else if (field.options && field.type == 'radiobutton') { var $checkedElement = $inputElement.filter(':checked'); if ($checkedElement.length) { record[fieldName] = $checkedElement.val(); } else { record[fieldName] = undefined; } } else { record[fieldName] = $inputElement.val(); } } }, /* Sets enabled/disabled state of a dialog button. *************************************************************************/ _setEnabledOfDialogButton: function ($button, enabled, buttonText) { if (!$button) { return; } if (enabled != false) { $button .removeAttr('disabled') .removeClass('ui-state-disabled'); } else { $button .attr('disabled', 'disabled') .addClass('ui-state-disabled'); } if (buttonText) { $button .find('span') .text(buttonText); } } }); })(jQuery); /************************************************************************ * CREATE RECORD extension for jTable * *************************************************************************/ (function ($) { //Reference to base object members var base = { _create: $.hik.jtable.prototype._create }; //extension members $.extend(true, $.hik.jtable.prototype, { /************************************************************************ * DEFAULT OPTIONS / EVENTS * *************************************************************************/ options: { //Events recordAdded: function (event, data) { }, //Localization messages: { addNewRecord: 'Add new record' } }, /************************************************************************ * PRIVATE FIELDS * *************************************************************************/ _$addRecordDiv: null, //Reference to the adding new record dialog div (jQuery object) /************************************************************************ * CONSTRUCTOR * *************************************************************************/ /* Overrides base method to do create-specific constructions. *************************************************************************/ _create: function () { base._create.apply(this, arguments); if (!this.options.actions.createAction) { return; } this._createAddRecordDialogDiv(); }, /* Creates and prepares add new record dialog div *************************************************************************/ _createAddRecordDialogDiv: function () { var self = this; //Create a div for dialog and add to container element self._$addRecordDiv = $('<div />') .appendTo(self._$mainContainer); //Prepare dialog self._$addRecordDiv.dialog({ autoOpen: false, //appendTo: "#navBars", show: self.options.dialogShowEffect, hide: self.options.dialogHideEffect, //width: 360, minWidth: 400, //height: "auto", dialogClass: "edit_order_dialog", //position: { my: "center center", at: "center center" }, // maxHeight: 400, modal: true, title: self.options.messages.addNewRecord, buttons: [{ //Cancel button text: self.options.messages.cancel, click: function () { self._$addRecordDiv.dialog('close'); } }, { //Save button id: 'AddRecordDialogSaveButton', text: self.options.messages.save, click: function () { self._onSaveClickedOnCreateForm(); } }], close: function () { var $addRecordForm = self._$addRecordDiv.find('form').first(); var $saveButton = self._$addRecordDiv.parent().find('#AddRecordDialogSaveButton'); self._trigger("formClosed", null, { form: $addRecordForm, formType: 'create' }); self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save); $addRecordForm.remove(); }, open: function( event, ui ) { var height = $( window ).height(), dialog = $( this ).closest( "div.ui-dialog" ).appendTo( "#navBars" ); $( this ).height( height / 2 * 1.5 ); dialog.offset({ top: (height - dialog.height()) / 2 - 10 }); } }); if (self.options.addRecordButton) { //If user supplied a button, bind the click event to show dialog form self.options.addRecordButton.click(function (e) { e.preventDefault(); self._showAddRecordForm(); }); } else { //If user did not supplied a button, create a 'add record button' toolbar item. self._addToolBarItem({ icon: true, cssClass: 'jtable-toolbar-item-add-record', text: self.options.messages.addNewRecord, click: function () { self._showAddRecordForm(); } }); } }, _onSaveClickedOnCreateForm: function () { var self = this; var $saveButton = self._$addRecordDiv.parent().find('#AddRecordDialogSaveButton'); var $addRecordForm = self._$addRecordDiv.find('form'); if (self._trigger("formSubmitting", null, { form: $addRecordForm, formType: 'create' }) != false) { self._setEnabledOfDialogButton($saveButton, false, self.options.messages.saving); self._saveAddRecordForm($addRecordForm, $saveButton); } }, /************************************************************************ * PUBLIC METHODS * *************************************************************************/ /* Shows add new record dialog form. *************************************************************************/ showCreateForm: function () { this._showAddRecordForm(); }, /* Adds a new record to the table (optionally to the server also) *************************************************************************/ addRecord: function (options) { var self = this; options = $.extend({ clientOnly: false, index: this._$tableRows.length, animationsEnabled: self.options.animationsEnabled, success: function () { }, error: function () { } }, options); if (!options.record) { self._logWarn('options parameter in addRecord method must contain a record property.'); return; } if (options.clientOnly) { self._addRow( self._createRowFromRecord(options.record), { isNewRow: true, animationsEnabled: options.animationsEnabled, clientOnly: options.clientOnly, index: options.index }); options.success(); return; } var completeAddRecord = function (data) { if (data.Result != 'OK') { self._showError(data.Message); options.error(data); return; } if (!data.Record) { self._logError('Server must return the created Record object.'); options.error(data); return; } self._onRecordAdded(data); self._addRow( self._createRowFromRecord(data.Record), { isNewRow: true, animationsEnabled: options.animationsEnabled, clientOnly: options.clientOnly, index: options.index }); options.success(data); }; //createAction may be a function, check if it is if (!options.url && $.isFunction(self.options.actions.createAction)) { //Execute the function var funcResult = self.options.actions.createAction($.param(options.record)); //Check if result is a jQuery Deferred object if (self._isDeferredObject(funcResult)) { //Wait promise funcResult.done(function (data) { completeAddRecord(data); }).fail(function () { self._showError(self.options.messages.serverCommunicationError); options.error(); }); } else { //assume it returned the creation result completeAddRecord(funcResult); } } else { //Assume it's a URL string //Make an Ajax call to create record self._submitFormUsingAjax( options.url || self.options.actions.createAction, $.param(options.record), function (data) { completeAddRecord(data); }, function () { self._showError(self.options.messages.serverCommunicationError); options.error(); }); } }, /************************************************************************ * PRIVATE METHODS * *************************************************************************/ /* Shows add new record dialog form. *************************************************************************/ _showAddRecordForm: function () { var self = this; //Create add new record form var $addRecordForm = $('<form id="jtable-create-form" class="jtable-dialog-form jtable-create-form"></form>'); //Create input elements for (var i = 0; i < self._fieldList.length; i++) { var fieldName = self._fieldList[i]; var field = self.options.fields[fieldName]; //Do not create input for fields that is key and not specially marked as creatable if (field.key == true && field.create != true) { continue; } //Do not create input for fields that are not creatable if (field.create == false) { continue; } if (field.type == 'hidden') { $addRecordForm.append(self._createInputForHidden(fieldName, field.defaultValue)); continue; } //Create a container div for this input field and add to form var $fieldContainer = $('<div />') .addClass('jtable-input-field-container') .appendTo($addRecordForm); //Create a label for input $fieldContainer.append(self._createInputLabelForRecordField(fieldName)); //Create input element $fieldContainer.append( self._createInputForRecordField({ fieldName: fieldName, formType: 'create', form: $addRecordForm })); } self._makeCascadeDropDowns($addRecordForm, undefined, 'create'); $addRecordForm.submit(function () { self._onSaveClickedOnCreateForm(); return false; }); //Open the form self._$addRecordDiv.append($addRecordForm).dialog('open'); self._trigger("formCreated", null, { form: $addRecordForm, formType: 'create' }); }, /* Saves new added record to the server and updates table. *************************************************************************/ _saveAddRecordForm: function ($addRecordForm, $saveButton) { var self = this; var completeAddRecord = function (data) { if (data.Result != 'OK') { self._showError(data.Message); self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save); return; } if (!data.Record) { self._logError('Server must return the created Record object.'); self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save); return; } self._onRecordAdded(data); self._addRow( self._createRowFromRecord(data.Record), { isNewRow: true, animationsEnabled: true, clientOnly: true, index: 0 }); self._$addRecordDiv.dialog("close"); // Activate Bootstrap Multiselect on new Row var new_row = $( "#jTable" ).find( "tr.jtable-data-row" ).eq(0); new_row.find( "select" ).multiselect({ buttonClass: 'btn btn-xs btn-info' }); }; $addRecordForm.data('submitting', true); //TODO: Why it's used, can remove? Check it. //createAction may be a function, check if it is if ($.isFunction(self.options.actions.createAction)) { //Execute the function var funcResult = self.options.actions.createAction($addRecordForm.serialize()); //Check if result is a jQuery Deferred object if (self._isDeferredObject(funcResult)) { //Wait promise funcResult.done(function (data) { completeAddRecord(data); }).fail(function () { self._showError(self.options.messages.serverCommunicationError); self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save); }); } else { //assume it returned the creation result completeAddRecord(funcResult); } } else { //Assume it's a URL string //Make an Ajax call to create record self._submitFormUsingAjax( self.options.actions.createAction, $addRecordForm.serialize(), function (data) { completeAddRecord(data); }, function () { self._showError(self.options.messages.serverCommunicationError); self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save); }); } }, _onRecordAdded: function (data) { this._trigger("recordAdded", null, { record: data.Record, serverResponse: data }); } }); })(jQuery); /************************************************************************ * EDIT RECORD extension for jTable * *************************************************************************/ (function ($) { //Reference to base object members var base = { _create: $.hik.jtable.prototype._create, _addColumnsToHeaderRow: $.hik.jtable.prototype._addColumnsToHeaderRow, _addCellsToRowUsingRecord: $.hik.jtable.prototype._addCellsToRowUsingRecord }; //extension members $.extend(true, $.hik.jtable.prototype, { /************************************************************************ * DEFAULT OPTIONS / EVENTS * *************************************************************************/ options: { //Events recordUpdated: function (event, data) { }, rowUpdated: function (event, data) { }, //Localization messages: { editRecord: 'Edit Record' } }, /************************************************************************ * PRIVATE FIELDS * *************************************************************************/ _$editDiv: null, //Reference to the editing dialog div (jQuery object) _$editingRow: null, //Reference to currently editing row (jQuery object) /************************************************************************ * CONSTRUCTOR AND INITIALIZATION METHODS * *************************************************************************/ /* Overrides base method to do editing-specific constructions. *************************************************************************/ _create: function () { base._create.apply(this, arguments); if (!this.options.actions.updateAction) { return; } this._createEditDialogDiv(); }, /* Creates and prepares edit dialog div *************************************************************************/ _createEditDialogDiv: function () { var self = this; //Create a div for dialog and add to container element self._$editDiv = $('<div></div>') .appendTo(self._$mainContainer); //Prepare dialog self._$editDiv.dialog({ autoOpen: false, show: self.options.dialogShowEffect, hide: self.options.dialogHideEffect, //width: 'auto', minWidth: 400, dialogClass: "edit_order_dialog", modal: true, title: self.options.messages.editRecord, buttons: [{ //cancel button text: self.options.messages.cancel, click: function () { self._$editDiv.dialog('close'); } }, { //save button id: 'EditDialogSaveButton', text: self.options.messages.save, click: function () { self._onSaveClickedOnEditForm(); } }], close: function () { var $editForm = self._$editDiv.find('form:first'); var $saveButton = self._$editDiv.parent().find('#EditDialogSaveButton'); self._trigger("formClosed", null, { form: $editForm, formType: 'edit', row: self._$editingRow }); self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save); $editForm.remove(); }, open: function( event, ui ) { var height = $( window ).height(), dialog = $( this ).closest( "div.ui-dialog" ).appendTo( "#navBars" ); $( this ).height( height / 2 * 1.5 ); dialog.offset({ top: (height - dialog.height()) / 2 - 10 }); } }); }, /* Saves editing form to server. *************************************************************************/ _onSaveClickedOnEditForm: function () { var self = this; //row maybe removed by another source, if so, do nothing if (self._$editingRow.hasClass('jtable-row-removed')) { self._$editDiv.dialog('close'); return; } var $saveButton = self._$editDiv.parent().find('#EditDialogSaveButton'); var $editForm = self._$editDiv.find('form'); if (self._trigger("formSubmitting", null, { form: $editForm, formType: 'edit', row: self._$editingRow }) != false) { self._setEnabledOfDialogButton($saveButton, false, self.options.messages.saving); self._saveEditForm($editForm, $saveButton); } }, /************************************************************************ * PUBLIC METHODS * *************************************************************************/ /* Updates a record on the table (optionally on the server also) *************************************************************************/ updateRecord: function (options) { var self = this; options = $.extend({ clientOnly: false, animationsEnabled: self.options.animationsEnabled, success: function () { }, error: function () { } }, options); if (!options.record) { self._logWarn('options parameter in updateRecord method must contain a record property.'); return; } var key = self._getKeyValueOfRecord(options.record); if (key == undefined || key == null) { self._logWarn('options parameter in updateRecord method must contain a record that contains the key field property.'); return; } var $updatingRow = self.getRowByKey(key); if ($updatingRow == null) { self._logWarn('Can not found any row by key "' + key + '" on the table. Updating row must be visible on the table.'); return; } if (options.clientOnly) { $.extend($updatingRow.data('record'), options.record); self._updateRowTexts($updatingRow); self._onRecordUpdated($updatingRow, null); if (options.animationsEnabled) { self._showUpdateAnimationForRow($updatingRow); } options.success(); return; } var completeEdit = function (data) { if (data.Result != 'OK') { self._showError(data.Message); options.error(data); return; } $.extend($updatingRow.data('record'), options.record); self._updateRecordValuesFromServerResponse($updatingRow.data('record'), data); self._updateRowTexts($updatingRow); self._onRecordUpdated($updatingRow, data); if (options.animationsEnabled) { self._showUpdateAnimationForRow($updatingRow); } options.success(data); }; //updateAction may be a function, check if it is if (!options.url && $.isFunction(self.options.actions.updateAction)) { //Execute the function var funcResult = self.options.actions.updateAction($.param(options.record)); //Check if result is a jQuery Deferred object if (self._isDeferredObject(funcResult)) { //Wait promise funcResult.done(function (data) { completeEdit(data); }).fail(function () { self._showError(self.options.messages.serverCommunicationError); options.error(); }); } else { //assume it returned the creation result completeEdit(funcResult); } } else { //Assume it's a URL string //Make an Ajax call to create record self._submitFormUsingAjax( options.url || self.options.actions.updateAction, $.param(options.record), function (data) { completeEdit(data); }, function () { self._showError(self.options.messages.serverCommunicationError); options.error(); }); } }, /************************************************************************ * OVERRIDED METHODS * *************************************************************************/ /* Overrides base method to add a 'editing column cell' to header row. *************************************************************************/ _addColumnsToHeaderRow: function ($tr) { base._addColumnsToHeaderRow.apply(this, arguments); if (this.options.actions.updateAction != undefined) { $tr.append(this._createEmptyCommandHeader()); } }, /* Overrides base method to add a 'edit command cell' to a row. *************************************************************************/ _addCellsToRowUsingRecord: function ($row) { var self = this; base._addCellsToRowUsingRecord.apply(this, arguments); if (self.options.actions.updateAction != undefined) { var $span = $('<span></span>').html(self.options.messages.editRecord); var $button = $('<button title="' + self.options.messages.editRecord + '"></button>') .addClass('jtable-command-button jtable-edit-command-button tooltip_set') .append($span) .click(function (e) { e.preventDefault(); e.stopPropagation(); self._showEditForm($row); }); $('<td></td>') .addClass('jtable-command-column') .append($button) .appendTo($row); } }, /************************************************************************ * PRIVATE METHODS * *************************************************************************/ /* Shows edit form for a row. *************************************************************************/ _showEditForm: function ($tableRow) { var self = this; var record = $tableRow.data('record'); //Create edit form var $editForm = $('<form id="jtable-edit-form" class="jtable-dialog-form jtable-edit-form"></form>'); //Create input fields for (var i = 0; i < self._fieldList.length; i++) { var fieldName = self._fieldList[i]; var field = self.options.fields[fieldName]; var fieldValue = record[fieldName]; if (field.key == true) { if (field.edit != true) { //Create hidden field for key $editForm.append(self._createInputForHidden(fieldName, fieldValue)); continue; } else { //Create a special hidden field for key (since key is be editable) $editForm.append(self._createInputForHidden('jtRecordKey', fieldValue)); } } //Do not create element for non-editable fields if (field.edit == false) { continue; } //Hidden field if (field.type == 'hidden') { $editForm.append(self._createInputForHidden(fieldName, fieldValue)); continue; } //Create a container div for this input field and add to form var $fieldContainer = $('<div class="jtable-input-field-container"></div>').appendTo($editForm); //Create a label for input $fieldContainer.append(self._createInputLabelForRecordField(fieldName)); //Create input element with it's current value var currentValue = self._getValueForRecordField(record, fieldName); $fieldContainer.append( self._createInputForRecordField({ fieldName: fieldName, value: currentValue, record: record, formType: 'edit', form: $editForm })); } self._makeCascadeDropDowns($editForm, record, 'edit'); $editForm.submit(function () { self._onSaveClickedOnEditForm(); return false; }); //Open dialog self._$editingRow = $tableRow; self._$editDiv.append($editForm).dialog('open'); self._trigger("formCreated", null, { form: $editForm, formType: 'edit', record: record, row: $tableRow }); }, /* Saves editing form to the server and updates the record on the table. *************************************************************************/ _saveEditForm: function ($editForm, $saveButton) { var self = this; var completeEdit = function (data) { if (data.Result != 'OK') { self._showError(data.Message); self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save); return; } var record = self._$editingRow.data('record'); self._updateRecordValuesFromForm(record, $editForm); self._updateRecordValuesFromServerResponse(record, data); self._updateRowTexts(self._$editingRow); self._$editingRow.attr('data-record-key', self._getKeyValueOfRecord(record)); self._onRecordUpdated(self._$editingRow, data); if (self.options.animationsEnabled) { self._showUpdateAnimationForRow(self._$editingRow); } self._$editDiv.dialog("close"); }; //updateAction may be a function, check if it is if ($.isFunction(self.options.actions.updateAction)) { //Execute the function var funcResult = self.options.actions.updateAction($editForm.serialize()); //Check if result is a jQuery Deferred object if (self._isDeferredObject(funcResult)) { //Wait promise funcResult.done(function (data) { completeEdit(data); }).fail(function () { self._showError(self.options.messages.serverCommunicationError); self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save); }); } else { //assume it returned the creation result completeEdit(funcResult); } } else { //Assume it's a URL string //Make an Ajax call to update record self._submitFormUsingAjax( self.options.actions.updateAction, $editForm.serialize(), function(data) { completeEdit(data); }, function() { self._showError(self.options.messages.serverCommunicationError); self._setEnabledOfDialogButton($saveButton, true, self.options.messages.save); }); } }, /* This method ensures updating of current record with server response, * if server sends a Record object as response to updateAction. *************************************************************************/ _updateRecordValuesFromServerResponse: function (record, serverResponse) { if (!serverResponse || !serverResponse.Record) { return; } $.extend(true, record, serverResponse.Record); }, /* Gets text for a field of a record according to it's type. *************************************************************************/ _getValueForRecordField: function (record, fieldName) { var field = this.options.fields[fieldName]; var fieldValue = record[fieldName]; if (field.type == 'date') { return this._getDisplayTextForDateRecordField(field, fieldValue); } else { return fieldValue; } }, /* Updates cells of a table row's text values from row's record values. *************************************************************************/ _updateRowTexts: function ($tableRow) { var record = $tableRow.data('record'); var $columns = $tableRow.find('td'); for (var i = 0; i < this._columnList.length; i++) { var displayItem = this._getDisplayTextForRecordField(record, this._columnList[i]); if ((displayItem != "") && (displayItem == 0)) displayItem = "0"; $columns.eq(this._firstDataColumnOffset + i).html(displayItem || ''); } this._onRowUpdated($tableRow); }, /* Shows 'updated' animation for a table row. *************************************************************************/ _showUpdateAnimationForRow: function ($tableRow) { var className = 'jtable-row-updated'; if (this.options.jqueryuiTheme) { className = className + ' ui-state-highlight'; } $tableRow.stop(true, true).addClass(className, 'slow', '', function () { $tableRow.removeClass(className, 5000); }); }, /************************************************************************ * EVENT RAISING METHODS * *************************************************************************/ _onRowUpdated: function ($row) { this._trigger("rowUpdated", null, { row: $row, record: $row.data('record') }); }, _onRecordUpdated: function ($row, data) { this._trigger("recordUpdated", null, { record: $row.data('record'), row: $row, serverResponse: data }); } }); })(jQuery); /************************************************************************ * DELETION extension for jTable * *************************************************************************/ (function ($) { //Reference to base object members var base = { _create: $.hik.jtable.prototype._create, _addColumnsToHeaderRow: $.hik.jtable.prototype._addColumnsToHeaderRow, _addCellsToRowUsingRecord: $.hik.jtable.prototype._addCellsToRowUsingRecord }; //extension members $.extend(true, $.hik.jtable.prototype, { /************************************************************************ * DEFAULT OPTIONS / EVENTS * *************************************************************************/ options: { //Options deleteConfirmation: true, clientOnly: true, //Events recordDeleted: function (event, data) { }, //Localization messages: { deleteConfirmation: 'This record will be deleted. Are you sure?', deleteText: 'Delete', deleting: 'Deleting', canNotDeletedRecords: 'Can not delete {0} of {1} records!', deleteProggress: 'Deleting {0} of {1} records, processing...' } }, /************************************************************************ * PRIVATE FIELDS * *************************************************************************/ _$deleteRecordDiv: null, //Reference to the adding new record dialog div (jQuery object) _$deletingRow: null, //Reference to currently deleting row (jQuery object) /************************************************************************ * CONSTRUCTOR * *************************************************************************/ /* Overrides base method to do deletion-specific constructions. *************************************************************************/ _create: function () { base._create.apply(this, arguments); this._createDeleteDialogDiv(); }, /* Creates and prepares delete record confirmation dialog div. *************************************************************************/ _createDeleteDialogDiv: function () { var self = this; //Check if deleteAction is supplied if (!self.options.actions.deleteAction) { return; } //Create div element for delete confirmation dialog self._$deleteRecordDiv = $('<div><p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;"></span><span class="jtable-delete-confirm-message"></span></p></div>').appendTo(self._$mainContainer); //Prepare dialog self._$deleteRecordDiv.dialog({ autoOpen: false, show: self.options.dialogShowEffect, hide: self.options.dialogHideEffect, modal: true, dialogClass: "edit_order_dialog", title: self.options.messages.areYouSure, buttons: [{ //cancel button text: self.options.messages.cancel, click: function () { self._$deleteRecordDiv.dialog("close"); } }, {//delete button id: 'DeleteDialogButton', text: self.options.messages.deleteText, click: function () { //row maybe removed by another source, if so, do nothing if (self._$deletingRow.hasClass('jtable-row-removed')) { self._$deleteRecordDiv.dialog('close'); return; } var $deleteButton = self._$deleteRecordDiv.parent().find('#DeleteDialogButton'); self._setEnabledOfDialogButton($deleteButton, false, self.options.messages.deleting); self._deleteRecordFromServer( self._$deletingRow, function () { self._removeRowsFromTableWithAnimation(self._$deletingRow, false, self.options.clientOnly); self._$deleteRecordDiv.dialog('close'); }, function (message) { //error self._showError(message); self._setEnabledOfDialogButton($deleteButton, true, self.options.messages.deleteText); } ); } }], close: function () { var $deleteButton = self._$deleteRecordDiv.parent().find('#DeleteDialogButton'); self._setEnabledOfDialogButton($deleteButton, true, self.options.messages.deleteText); }, open: function( event, ui ) { var height = $( window ).height(), dialog = $( this ).closest( "div.ui-dialog" ).appendTo( "#navBars" ); //$( this ).height( height / 2 * 1.5 ); dialog.offset({ top: (height - dialog.height()) / 2 - 10 }); } }); }, /************************************************************************ * PUBLIC METHODS * *************************************************************************/ /* This method is used to delete one or more rows from server and the table. *************************************************************************/ deleteRows: function ($rows, options) { var self = this; if ($rows.length <= 0) { self._logWarn('No rows specified to jTable deleteRows method.'); return; } if (self._isBusy()) { self._logWarn('Can not delete rows since jTable is busy!'); return; } //Deleting just one row if ($rows.length == 1) { self._deleteRecordFromServer( $rows, function () { //success self._removeRowsFromTableWithAnimation($rows, false, self.options.clientOnly); }, function (message) { //error self._showError(message); } ); return; } //Deleting multiple rows self._showBusy(self._formatString(self.options.messages.deleteProggress, 0, $rows.length)); //This method checks if deleting of all records is completed var completedCount = 0; var isCompleted = function () { return (completedCount >= $rows.length); }; //This method is called when deleting of all records completed var completed = function () { var $deletedRows = $rows.filter('.jtable-row-ready-to-remove'); if ($deletedRows.length < $rows.length) { self._showError(self._formatString(self.options.messages.canNotDeletedRecords, $rows.length - $deletedRows.length, $rows.length)); } if ($deletedRows.length > 0) { self._removeRowsFromTableWithAnimation($deletedRows, false, self.options.clientOnly); } self._hideBusy(); }; //Delete all rows var deletedCount = 0; $rows.each(function () { var $row = $(this); self._deleteRecordFromServer( $row, function () { //success ++deletedCount; ++completedCount; $row.addClass('jtable-row-ready-to-remove'); self._showBusy(self._formatString(self.options.messages.deleteProggress, deletedCount, $rows.length)); if (isCompleted()) { completed(); } }, function () { //error ++completedCount; if (isCompleted()) { completed(); } } ); }); }, /* Deletes a record from the table (optionally from the server also). *************************************************************************/ deleteRecord: function (options) { var self = this; options = $.extend({ clientOnly: false, animationsEnabled: self.options.animationsEnabled, url: self.options.actions.deleteAction, success: function () { }, error: function () { } }, options); if (options.key == undefined) { self._logWarn('options parameter in deleteRecord method must contain a key property.'); return; } var $deletingRow = self.getRowByKey(options.key); if ($deletingRow == null) { self._logWarn('Can not found any row by key: ' + options.key); return; } if (options.clientOnly) { self._removeRowsFromTableWithAnimation($deletingRow, options.animationsEnabled, options.clientOnly); options.success(); return; } self._deleteRecordFromServer( $deletingRow, function (data) { //success self._removeRowsFromTableWithAnimation($deletingRow, options.animationsEnabled, options.clientOnly); options.success(data); }, function (message) { //error self._showError(message); options.error(message); }, options.url ); }, /************************************************************************ * OVERRIDED METHODS * *************************************************************************/ /* Overrides base method to add a 'deletion column cell' to header row. *************************************************************************/ _addColumnsToHeaderRow: function ($tr) { base._addColumnsToHeaderRow.apply(this, arguments); if (this.options.actions.deleteAction != undefined) { $tr.append(this._createEmptyCommandHeader()); } }, /* Overrides base method to add a 'delete command cell' to a row. *************************************************************************/ _addCellsToRowUsingRecord: function ($row) { base._addCellsToRowUsingRecord.apply(this, arguments); var self = this; if (self.options.actions.deleteAction != undefined) { var $span = $('<span></span>').html(self.options.messages.deleteText); var $button = $('<button data-placement="left" title="' + self.options.messages.deleteText + '"></button>') .addClass('jtable-command-button jtable-delete-command-button tooltip_set') .append($span) .click(function (e) { e.preventDefault(); e.stopPropagation(); self._deleteButtonClickedForRow($row); }); $('<td></td>') .addClass('jtable-command-column') .append($button) .appendTo($row); } }, /************************************************************************ * PRIVATE METHODS * *************************************************************************/ /* This method is called when user clicks delete button on a row. *************************************************************************/ _deleteButtonClickedForRow: function ($row) { var self = this; var deleteConfirm; var deleteConfirmMessage = self.options.messages.deleteConfirmation; //If options.deleteConfirmation is function then call it if ($.isFunction(self.options.deleteConfirmation)) { var data = { row: $row, record: $row.data('record'), deleteConfirm: true, deleteConfirmMessage: deleteConfirmMessage, cancel: false, cancelMessage: null }; self.options.deleteConfirmation(data); //If delete progress is cancelled if (data.cancel) { //If a canlellation reason is specified if (data.cancelMessage) { self._showError(data.cancelMessage); //TODO: show warning/stop message instead of error (also show warning/error ui icon)! } return; } deleteConfirmMessage = data.deleteConfirmMessage; deleteConfirm = data.deleteConfirm; } else { deleteConfirm = self.options.deleteConfirmation; } if (deleteConfirm != false) { //Confirmation self._$deleteRecordDiv.find('.jtable-delete-confirm-message').html(deleteConfirmMessage); self._showDeleteDialog($row); } else { //No confirmation self._deleteRecordFromServer( $row, function () { //success self._removeRowsFromTableWithAnimation($row, false, self.options.clientOnly); }, function (message) { //error self._showError(message); } ); } }, /* Shows delete comfirmation dialog. *************************************************************************/ _showDeleteDialog: function ($row) { this._$deletingRow = $row; this._$deleteRecordDiv.dialog('open'); }, /* Performs an ajax call to server to delete record * and removes row of the record from table if ajax call success. *************************************************************************/ _deleteRecordFromServer: function ($row, success, error, url) { var self = this; var completeDelete = function(data) { if (data.Result != 'OK') { $row.data('deleting', false); if (error) { error(data.Message); } return; } self._trigger("recordDeleted", null, { record: $row.data('record'), row: $row, serverResponse: data }); if (success) { success(data); } }; //Check if it is already being deleted right now if ($row.data('deleting') == true) { return; } $row.data('deleting', true); var postData = {}; postData[self._keyField] = self._getKeyValueOfRecord($row.data('record')); //deleteAction may be a function, check if it is if (!url && $.isFunction(self.options.actions.deleteAction)) { //Execute the function var funcResult = self.options.actions.deleteAction(postData); //Check if result is a jQuery Deferred object if (self._isDeferredObject(funcResult)) { //Wait promise funcResult.done(function (data) { completeDelete(data); }).fail(function () { $row.data('deleting', false); if (error) { error(self.options.messages.serverCommunicationError); } }); } else { //assume it returned the deletion result completeDelete(funcResult); } } else { //Assume it's a URL string //Make ajax call to delete the record from server this._ajax({ url: (url || self.options.actions.deleteAction), data: postData, success: function (data) { completeDelete(data); }, error: function () { $row.data('deleting', false); if (error) { error(self.options.messages.serverCommunicationError); } } }); } }, /* Removes a row from table after a 'deleting' animation. *************************************************************************/ _removeRowsFromTableWithAnimation: function ($rows, animationsEnabled, clientOnly) { var self = this; if (animationsEnabled == undefined) { animationsEnabled = self.options.animationsEnabled; } if (animationsEnabled) { var className = 'jtable-row-deleting'; if (this.options.jqueryuiTheme) { className = className + ' ui-state-disabled'; } //Stop current animation (if does exists) and begin 'deleting' animation. $rows.stop(true, true).addClass(className, 'slow', '').promise().done(function () { self._removeRowsFromTable($rows, 'deleted', clientOnly); }); } else { self._removeRowsFromTable($rows, 'deleted', clientOnly); } } }); })(jQuery); /************************************************************************ * SELECTING extension for jTable * *************************************************************************/ (function ($) { //Reference to base object members var base = { _create: $.hik.jtable.prototype._create, _addColumnsToHeaderRow: $.hik.jtable.prototype._addColumnsToHeaderRow, _addCellsToRowUsingRecord: $.hik.jtable.prototype._addCellsToRowUsingRecord, _onLoadingRecords: $.hik.jtable.prototype._onLoadingRecords, _onRecordsLoaded: $.hik.jtable.prototype._onRecordsLoaded, _onRowsRemoved: $.hik.jtable.prototype._onRowsRemoved }; //extension members $.extend(true, $.hik.jtable.prototype, { /************************************************************************ * DEFAULT OPTIONS / EVENTS * *************************************************************************/ options: { //Options selecting: false, multiselect: false, selectingCheckboxes: false, selectOnRowClick: true, //Events selectionChanged: function (event, data) { } }, /************************************************************************ * PRIVATE FIELDS * *************************************************************************/ _selectedRecordIdsBeforeLoad: null, //This array is used to store selected row Id's to restore them after a page refresh (string array). _$selectAllCheckbox: null, //Reference to the 'select/deselect all' checkbox (jQuery object) _shiftKeyDown: false, //True, if shift key is currently down. /************************************************************************ * CONSTRUCTOR * *************************************************************************/ /* Overrides base method to do selecting-specific constructions. *************************************************************************/ _create: function () { if (this.options.selecting && this.options.selectingCheckboxes) { ++this._firstDataColumnOffset; this._bindKeyboardEvents(); } //Call base method base._create.apply(this, arguments); }, /* Registers to keyboard events those are needed for selection *************************************************************************/ _bindKeyboardEvents: function () { var self = this; //Register to events to set _shiftKeyDown value $(document) .keydown(function (event) { switch (event.which) { case 16: self._shiftKeyDown = true; break; } }) .keyup(function (event) { switch (event.which) { case 16: self._shiftKeyDown = false; break; } }); }, /************************************************************************ * PUBLIC METHODS * *************************************************************************/ /* Gets jQuery selection for currently selected rows. *************************************************************************/ selectedRows: function () { return this._getSelectedRows(); }, /* Makes row/rows 'selected'. *************************************************************************/ selectRows: function ($rows) { this._selectRows($rows); this._onSelectionChanged(); //TODO: trigger only if selected rows changes? }, /************************************************************************ * OVERRIDED METHODS * *************************************************************************/ /* Overrides base method to add a 'select column' to header row. *************************************************************************/ _addColumnsToHeaderRow: function ($tr) { if (this.options.selecting && this.options.selectingCheckboxes) { if (this.options.multiselect) { $tr.append(this._createSelectAllHeader()); } else { $tr.append(this._createEmptyCommandHeader()); } } base._addColumnsToHeaderRow.apply(this, arguments); }, /* Overrides base method to add a 'delete command cell' to a row. *************************************************************************/ _addCellsToRowUsingRecord: function ($row) { if (this.options.selecting) { this._makeRowSelectable($row); } base._addCellsToRowUsingRecord.apply(this, arguments); }, /* Overrides base event to store selection list *************************************************************************/ _onLoadingRecords: function () { if (this.options.selecting) { this._storeSelectionList(); } base._onLoadingRecords.apply(this, arguments); }, /* Overrides base event to restore selection list *************************************************************************/ _onRecordsLoaded: function () { if (this.options.selecting) { this._restoreSelectionList(); } base._onRecordsLoaded.apply(this, arguments); }, /* Overrides base event to check is any selected row is being removed. *************************************************************************/ _onRowsRemoved: function ($rows, reason) { if (this.options.selecting && (reason != 'reloading') && ($rows.filter('.jtable-row-selected').length > 0)) { this._onSelectionChanged(); } base._onRowsRemoved.apply(this, arguments); }, /************************************************************************ * PRIVATE METHODS * *************************************************************************/ /* Creates a header column to select/deselect all rows. *************************************************************************/ _createSelectAllHeader: function () { var self = this; var $columnHeader = $('<th class=""></th>') .addClass('jtable-command-column-header jtable-column-header-selecting'); this._jqueryuiThemeAddClass($columnHeader, 'ui-state-default'); var $headerContainer = $('<div />') .addClass('jtable-column-header-container') .appendTo($columnHeader); self._$selectAllCheckbox = $('<input type="checkbox" />') .appendTo($headerContainer) .click(function () { if (self._$tableRows.length <= 0) { self._$selectAllCheckbox.attr('checked', false); return; } var allRows = self._$tableBody.find('>tr.jtable-data-row'); if (self._$selectAllCheckbox.is(':checked')) { self._selectRows(allRows); } else { self._deselectRows(allRows); } self._onSelectionChanged(); }); return $columnHeader; }, /* Stores Id's of currently selected records to _selectedRecordIdsBeforeLoad. *************************************************************************/ _storeSelectionList: function () { var self = this; if (!self.options.selecting) { return; } self._selectedRecordIdsBeforeLoad = []; self._getSelectedRows().each(function () { self._selectedRecordIdsBeforeLoad.push(self._getKeyValueOfRecord($(this).data('record'))); }); }, /* Selects rows whose Id is in _selectedRecordIdsBeforeLoad; *************************************************************************/ _restoreSelectionList: function () { var self = this; if (!self.options.selecting) { return; } var selectedRowCount = 0; for (var i = 0; i < self._$tableRows.length; ++i) { var recordId = self._getKeyValueOfRecord(self._$tableRows[i].data('record')); if ($.inArray(recordId, self._selectedRecordIdsBeforeLoad) > -1) { self._selectRows(self._$tableRows[i]); ++selectedRowCount; } } if (self._selectedRecordIdsBeforeLoad.length > 0 && self._selectedRecordIdsBeforeLoad.length != selectedRowCount) { self._onSelectionChanged(); } self._selectedRecordIdsBeforeLoad = []; self._refreshSelectAllCheckboxState(); }, /* Gets all selected rows. *************************************************************************/ _getSelectedRows: function () { return this._$tableBody .find('>tr.jtable-row-selected'); }, /* Adds selectable feature to a row. *************************************************************************/ _makeRowSelectable: function ($row) { var self = this; //Select/deselect on row click if (self.options.selectOnRowClick) { $row.click(function () { self._invertRowSelection($row); }); } //'select/deselect' checkbox column if (self.options.selectingCheckboxes) { var $cell = $('<td></td>').addClass('jtable-selecting-column'); var $selectCheckbox = $('<input type="checkbox" />').appendTo($cell); if (!self.options.selectOnRowClick) { $selectCheckbox.click(function () { self._invertRowSelection($row); }); } $row.append($cell); } }, /* Inverts selection state of a single row. *************************************************************************/ _invertRowSelection: function ($row) { if ($row.hasClass('jtable-row-selected')) { this._deselectRows($row); } else { //Shift key? if (this._shiftKeyDown) { var rowIndex = this._findRowIndex($row); //try to select row and above rows until first selected row var beforeIndex = this._findFirstSelectedRowIndexBeforeIndex(rowIndex) + 1; if (beforeIndex > 0 && beforeIndex < rowIndex) { this._selectRows(this._$tableBody.find('tr').slice(beforeIndex, rowIndex + 1)); } else { //try to select row and below rows until first selected row var afterIndex = this._findFirstSelectedRowIndexAfterIndex(rowIndex) - 1; if (afterIndex > rowIndex) { this._selectRows(this._$tableBody.find('tr').slice(rowIndex, afterIndex + 1)); } else { //just select this row this._selectRows($row); } } } else { this._selectRows($row); } } this._onSelectionChanged(); }, /* Search for a selected row (that is before given row index) to up and returns it's index *************************************************************************/ _findFirstSelectedRowIndexBeforeIndex: function (rowIndex) { for (var i = rowIndex - 1; i >= 0; --i) { if (this._$tableRows[i].hasClass('jtable-row-selected')) { return i; } } return -1; }, /* Search for a selected row (that is after given row index) to down and returns it's index *************************************************************************/ _findFirstSelectedRowIndexAfterIndex: function (rowIndex) { for (var i = rowIndex + 1; i < this._$tableRows.length; ++i) { if (this._$tableRows[i].hasClass('jtable-row-selected')) { return i; } } return -1; }, /* Makes row/rows 'selected'. *************************************************************************/ _selectRows: function ($rows) { if (!this.options.multiselect) { this._deselectRows(this._getSelectedRows()); } $rows.addClass('jtable-row-selected'); this._jqueryuiThemeAddClass($rows, 'ui-state-highlight'); if (this.options.selectingCheckboxes) { $rows.find('>td.jtable-selecting-column >input').prop('checked', true); } this._refreshSelectAllCheckboxState(); }, /* Makes row/rows 'non selected'. *************************************************************************/ _deselectRows: function ($rows) { $rows.removeClass('jtable-row-selected ui-state-highlight'); if (this.options.selectingCheckboxes) { $rows.find('>td.jtable-selecting-column >input').prop('checked', false); } this._refreshSelectAllCheckboxState(); }, /* Updates state of the 'select/deselect' all checkbox according to count of selected rows. *************************************************************************/ _refreshSelectAllCheckboxState: function () { if (!this.options.selectingCheckboxes || !this.options.multiselect) { return; } var totalRowCount = this._$tableRows.length; var selectedRowCount = this._getSelectedRows().length; if (selectedRowCount == 0) { this._$selectAllCheckbox.prop('indeterminate', false); this._$selectAllCheckbox.attr('checked', false); } else if (selectedRowCount == totalRowCount) { this._$selectAllCheckbox.prop('indeterminate', false); this._$selectAllCheckbox.attr('checked', true); } else { this._$selectAllCheckbox.attr('checked', false); this._$selectAllCheckbox.prop('indeterminate', true); } }, /************************************************************************ * EVENT RAISING METHODS * *************************************************************************/ _onSelectionChanged: function () { this._trigger("selectionChanged", null, {}); } }); })(jQuery); /************************************************************************ * PAGING extension for jTable * *************************************************************************/ (function ($) { //Reference to base object members var base = { load: $.hik.jtable.prototype.load, _create: $.hik.jtable.prototype._create, _setOption: $.hik.jtable.prototype._setOption, _createRecordLoadUrl: $.hik.jtable.prototype._createRecordLoadUrl, _createJtParamsForLoading: $.hik.jtable.prototype._createJtParamsForLoading, _addRowToTable: $.hik.jtable.prototype._addRowToTable, _addRow: $.hik.jtable.prototype._addRow, _removeRowsFromTable: $.hik.jtable.prototype._removeRowsFromTable, _onRecordsLoaded: $.hik.jtable.prototype._onRecordsLoaded }; //extension members $.extend(true, $.hik.jtable.prototype, { /************************************************************************ * DEFAULT OPTIONS / EVENTS * *************************************************************************/ options: { paging: false, pageList: 'normal', //possible values: 'minimal', 'normal' pageSize: 10, pageSizes: [10, 25, 50, 100, 250, 500], pageSizeChangeArea: true, gotoPageArea: 'combobox', //possible values: 'textbox', 'combobox', 'none' messages: { pagingInfo: 'Showing {0}-{1} of {2}', pageSizeChangeLabel: 'Row count', gotoPageLabel: 'Go to page' } }, /************************************************************************ * PRIVATE FIELDS * *************************************************************************/ _$bottomPanel: null, //Reference to the panel at the bottom of the table (jQuery object) _$pagingListArea: null, //Reference to the page list area in to bottom panel (jQuery object) _$pageSizeChangeArea: null, //Reference to the page size change area in to bottom panel (jQuery object) _$pageInfoSpan: null, //Reference to the paging info area in to bottom panel (jQuery object) _$gotoPageArea: null, //Reference to 'Go to page' input area in to bottom panel (jQuery object) _$gotoPageInput: null, //Reference to 'Go to page' input in to bottom panel (jQuery object) _totalRecordCount: 0, //Total count of records on all pages _currentPageNo: 1, //Current page number /************************************************************************ * CONSTRUCTOR AND INITIALIZING METHODS * *************************************************************************/ /* Overrides base method to do paging-specific constructions. *************************************************************************/ _create: function() { base._create.apply(this, arguments); if (this.options.paging) { this._loadPagingSettings(); this._createBottomPanel(); this._createPageListArea(); this._createGotoPageInput(); this._createPageSizeSelection(); } }, /* Loads user preferences for paging. *************************************************************************/ _loadPagingSettings: function() { if (!this.options.saveUserPreferences) { return; } var pageSize = this._getCookie('page-size'); if (pageSize) { this.options.pageSize = this._normalizeNumber(pageSize, 1, 1000000, this.options.pageSize); } }, /* Creates bottom panel and adds to the page. *************************************************************************/ _createBottomPanel: function() { this._$bottomPanel = $('<div />') .addClass('jtable-bottom-panel') .insertAfter(this._$table); this._jqueryuiThemeAddClass(this._$bottomPanel, 'ui-state-default'); $('<div />').addClass('jtable-left-area').appendTo(this._$bottomPanel); $('<div />').addClass('jtable-right-area').appendTo(this._$bottomPanel); }, /* Creates page list area. *************************************************************************/ _createPageListArea: function() { this._$pagingListArea = $('<span></span>') .addClass('jtable-page-list') .appendTo(this._$bottomPanel.find('.jtable-left-area')); this._$pageInfoSpan = $('<span></span>') .addClass('jtable-page-info') .appendTo(this._$bottomPanel.find('.jtable-right-area')); }, /* Creates page list change area. *************************************************************************/ _createPageSizeSelection: function() { var self = this; if (!self.options.pageSizeChangeArea) { return; } //Add current page size to page sizes list if not contains it if (self._findIndexInArray(self.options.pageSize, self.options.pageSizes) < 0) { self.options.pageSizes.push(parseInt(self.options.pageSize)); self.options.pageSizes.sort(function(a, b) { return a - b; }); } //Add a span to contain page size change items self._$pageSizeChangeArea = $('<span></span>') .addClass('jtable-page-size-change') .appendTo(self._$bottomPanel.find('.jtable-left-area')); //Page size label self._$pageSizeChangeArea.append('<span>' + self.options.messages.pageSizeChangeLabel + ': </span>'); //Page size change combobox var $pageSizeChangeCombobox = $('<select></select>').appendTo(self._$pageSizeChangeArea); //Add page sizes to the combobox for (var i = 0; i < self.options.pageSizes.length; i++) { $pageSizeChangeCombobox.append('<option value="' + self.options.pageSizes[i] + '">' + self.options.pageSizes[i] + '</option>'); } //Select current page size $pageSizeChangeCombobox.val(self.options.pageSize); //Change page size on combobox change $pageSizeChangeCombobox.change(function() { self._changePageSize(parseInt($(this).val())); }); }, /* Creates go to page area. *************************************************************************/ _createGotoPageInput: function() { var self = this; if (!self.options.gotoPageArea || self.options.gotoPageArea == 'none') { return; } //Add a span to contain goto page items this._$gotoPageArea = $('<span></span>') .addClass('jtable-goto-page') .appendTo(self._$bottomPanel.find('.jtable-left-area')); //Goto page label this._$gotoPageArea.append('<span>' + self.options.messages.gotoPageLabel + ': </span>'); //Goto page input if (self.options.gotoPageArea == 'combobox') { self._$gotoPageInput = $('<select></select>') .appendTo(this._$gotoPageArea) .data('pageCount', 1) .change(function() { self._changePage(parseInt($(this).val())); }); self._$gotoPageInput.append('<option value="1">1</option>'); } else { //textbox self._$gotoPageInput = $('<input type="text" maxlength="10" value="' + self._currentPageNo + '" />') .appendTo(this._$gotoPageArea) .keypress(function(event) { if (event.which == 13) { //enter event.preventDefault(); self._changePage(parseInt(self._$gotoPageInput.val())); } else if (event.which == 43) { // + event.preventDefault(); self._changePage(parseInt(self._$gotoPageInput.val()) + 1); } else if (event.which == 45) { // - event.preventDefault(); self._changePage(parseInt(self._$gotoPageInput.val()) - 1); } else { //Allow only digits var isValid = ( (47 < event.keyCode && event.keyCode < 58 && event.shiftKey == false && event.altKey == false) || (event.keyCode == 8) || (event.keyCode == 9) ); if (!isValid) { event.preventDefault(); } } }); } }, /* Refreshes the 'go to page' input. *************************************************************************/ _refreshGotoPageInput: function() { if (!this.options.gotoPageArea || this.options.gotoPageArea == 'none') { return; } if (this._totalRecordCount <= 0) { this._$gotoPageArea.hide(); } else { this._$gotoPageArea.show(); } if (this.options.gotoPageArea == 'combobox') { var oldPageCount = this._$gotoPageInput.data('pageCount'); var currentPageCount = this._calculatePageCount(); if (oldPageCount != currentPageCount) { this._$gotoPageInput.empty(); //Skip some pages is there are too many pages var pageStep = 1; if (currentPageCount > 10000) { pageStep = 100; } else if (currentPageCount > 5000) { pageStep = 10; } else if (currentPageCount > 2000) { pageStep = 5; } else if (currentPageCount > 1000) { pageStep = 2; } for (var i = pageStep; i <= currentPageCount; i += pageStep) { this._$gotoPageInput.append('<option value="' + i + '">' + i + '</option>'); } ______________________________________________________ * End Part 3 * ______________________________________________________ Quote osC OpenSSL Encryption with jCryptionSupport Forum jQuery/Ajax Advanced Statistics 2.3Support Forum jQuery/Ajax Advanced Order Handler 2.3.3Support ForumjQuery/Ajax Advanced Caching System 2.3.3Support ForumjQuery/Ajax Fast checkout/Shopping Cart/Login/Create Account 2.3.3Support ForumjQuery/Ajax Shopping Cart 2.3.3Support ForumjQuery/Ajax Dynamic Checkout 2.3.3Support ForumjQuery/Ajax Mini Cart for osCommerce 2.3.3Support ForumjQuery Cycle What's New InfoboxAuto Out Of Stock CSS Image OverlayjQuery-UI Autocomplete Product Search with Links & MySQLi support for osCommerce 2.X Link to comment Share on other sites More sharing options...
Dr. Rolex Posted October 6, 2014 Author Share Posted October 6, 2014 Replace ./admin/includes/modules/order_handler/js/01_02_jquery.jtable.js With This: (3/3 Part of this file) this._$gotoPageInput.data('pageCount', currentPageCount); } } //same for 'textbox' and 'combobox' this._$gotoPageInput.val(this._currentPageNo); }, /************************************************************************ * OVERRIDED METHODS * *************************************************************************/ /* Overrides load method to set current page to 1. *************************************************************************/ load: function() { this._currentPageNo = 1; base.load.apply(this, arguments); }, /* Used to change options dynamically after initialization. *************************************************************************/ _setOption: function(key, value) { base._setOption.apply(this, arguments); if (key == 'pageSize') { this._changePageSize(parseInt(value)); } }, /* Changes current page size with given value. *************************************************************************/ _changePageSize: function(pageSize) { if (pageSize == this.options.pageSize) { return; } this.options.pageSize = pageSize; //Normalize current page var pageCount = this._calculatePageCount(); if (this._currentPageNo > pageCount) { this._currentPageNo = pageCount; } if (this._currentPageNo <= 0) { this._currentPageNo = 1; } //if user sets one of the options on the combobox, then select it. var $pageSizeChangeCombobox = this._$bottomPanel.find('.jtable-page-size-change select'); if ($pageSizeChangeCombobox.length > 0) { if (parseInt($pageSizeChangeCombobox.val()) != pageSize) { var selectedOption = $pageSizeChangeCombobox.find('option[value=' + pageSize + ']'); if (selectedOption.length > 0) { $pageSizeChangeCombobox.val(pageSize); } } } this._savePagingSettings(); this._reloadTable(); }, /* Saves user preferences for paging *************************************************************************/ _savePagingSettings: function() { if (!this.options.saveUserPreferences) { return; } this._setCookie('page-size', this.options.pageSize); }, /* Overrides _createRecordLoadUrl method to add paging info to URL. *************************************************************************/ _createRecordLoadUrl: function() { var loadUrl = base._createRecordLoadUrl.apply(this, arguments); loadUrl = this._addPagingInfoToUrl(loadUrl, this._currentPageNo); return loadUrl; }, /* Overrides _createJtParamsForLoading method to add paging parameters to jtParams object. *************************************************************************/ _createJtParamsForLoading: function () { var jtParams = base._createJtParamsForLoading.apply(this, arguments); if (this.options.paging) { jtParams.jtStartIndex = (this._currentPageNo - 1) * this.options.pageSize; jtParams.jtPageSize = this.options.pageSize; } var params = this._loadPostDataSettings(); for(var name in params) { jtParams[name] = params[name]; } return jtParams; }, /* Overrides _addRowToTable method to re-load table when a new row is created. * NOTE: THIS METHOD IS DEPRECATED AND WILL BE REMOVED FROM FEATURE RELEASES. * USE _addRow METHOD. *************************************************************************/ _addRowToTable: function ($tableRow, index, isNewRow) { if (isNewRow && this.options.paging) { this._reloadTable(); return; } base._addRowToTable.apply(this, arguments); }, /* Overrides _addRow method to re-load table when a new row is created. *************************************************************************/ _addRow: function ($row, options) { if (options && options.isNewRow && this.options.paging && options.clientOnly != true) { this._reloadTable(); return; } base._addRow.apply(this, arguments); }, /* Overrides _removeRowsFromTable method to re-load table when a row is removed from table. *************************************************************************/ _removeRowsFromTable: function ($rows, reason, clientOnly) { base._removeRowsFromTable.apply(this, arguments); if (this.options.paging) { if (this._$tableRows.length <= 0 && this._currentPageNo > 1) { --this._currentPageNo; } if (clientOnly != true) this._reloadTable(); } }, /* Overrides _onRecordsLoaded method to to do paging specific tasks. *************************************************************************/ _onRecordsLoaded: function (data) { if (this.options.paging) { this._totalRecordCount = data.TotalRecordCount; this._createPagingList(); this._createPagingInfo(); this._refreshGotoPageInput(); } base._onRecordsLoaded.apply(this, arguments); }, /************************************************************************ * PRIVATE METHODS * *************************************************************************/ /* Adds jtStartIndex and jtPageSize parameters to a URL as query string. *************************************************************************/ _addPagingInfoToUrl: function (url, pageNumber) { if (!this.options.paging) { return url; } var jtStartIndex = (pageNumber - 1) * this.options.pageSize; var jtPageSize = this.options.pageSize; return (url + (url.indexOf('?') < 0 ? '?' : '&') + 'jtStartIndex=' + jtStartIndex + '&jtPageSize=' + jtPageSize); }, /* Creates and shows the page list. *************************************************************************/ _createPagingList: function () { if (this.options.pageSize <= 0) { return; } this._$pagingListArea.empty(); if (this._totalRecordCount <= 0) { return; } var pageCount = this._calculatePageCount(); this._createFirstAndPreviousPageButtons(); if (this.options.pageList == 'normal') { this._createPageNumberButtons(this._calculatePageNumbers(pageCount)); } this._createLastAndNextPageButtons(pageCount); this._bindClickEventsToPageNumberButtons(); }, /* Creates and shows previous and first page links. *************************************************************************/ _createFirstAndPreviousPageButtons: function () { var $first = $('<span></span>') .addClass('jtable-page-number-first') .html('<<') .data('pageNumber', 1) .appendTo(this._$pagingListArea); var $previous = $('<span></span>') .addClass('jtable-page-number-previous') .html('<') .data('pageNumber', this._currentPageNo - 1) .appendTo(this._$pagingListArea); this._jqueryuiThemeAddClass($first, 'ui-button ui-state-default', 'ui-state-hover'); this._jqueryuiThemeAddClass($previous, 'ui-button ui-state-default', 'ui-state-hover'); if (this._currentPageNo <= 1) { $first.addClass('jtable-page-number-disabled'); $previous.addClass('jtable-page-number-disabled'); this._jqueryuiThemeAddClass($first, 'ui-state-disabled'); this._jqueryuiThemeAddClass($previous, 'ui-state-disabled'); } }, /* Creates and shows next and last page links. *************************************************************************/ _createLastAndNextPageButtons: function (pageCount) { var $next = $('<span></span>') .addClass('jtable-page-number-next') .html('>') .data('pageNumber', this._currentPageNo + 1) .appendTo(this._$pagingListArea); var $last = $('<span></span>') .addClass('jtable-page-number-last') .html('>>') .data('pageNumber', pageCount) .appendTo(this._$pagingListArea); this._jqueryuiThemeAddClass($next, 'ui-button ui-state-default', 'ui-state-hover'); this._jqueryuiThemeAddClass($last, 'ui-button ui-state-default', 'ui-state-hover'); if (this._currentPageNo >= pageCount) { $next.addClass('jtable-page-number-disabled'); $last.addClass('jtable-page-number-disabled'); this._jqueryuiThemeAddClass($next, 'ui-state-disabled'); this._jqueryuiThemeAddClass($last, 'ui-state-disabled'); } }, /* Creates and shows page number links for given number array. *************************************************************************/ _createPageNumberButtons: function (pageNumbers) { var previousNumber = 0; for (var i = 0; i < pageNumbers.length; i++) { //Create "..." between page numbers if needed if ((pageNumbers[i] - previousNumber) > 1) { $('<span></span>') .addClass('jtable-page-number-space') .html('...') .appendTo(this._$pagingListArea); } this._createPageNumberButton(pageNumbers[i]); previousNumber = pageNumbers[i]; } }, /* Creates a page number link and adds to paging area. *************************************************************************/ _createPageNumberButton: function (pageNumber) { var $pageNumber = $('<span></span>') .addClass('jtable-page-number') .html(pageNumber) .data('pageNumber', pageNumber) .appendTo(this._$pagingListArea); this._jqueryuiThemeAddClass($pageNumber, 'ui-button ui-state-default', 'ui-state-hover'); if (this._currentPageNo == pageNumber) { $pageNumber.addClass('jtable-page-number-active jtable-page-number-disabled'); this._jqueryuiThemeAddClass($pageNumber, 'ui-state-active'); } }, /* Calculates total page count according to page size and total record count. *************************************************************************/ _calculatePageCount: function () { var pageCount = Math.floor(this._totalRecordCount / this.options.pageSize); if (this._totalRecordCount % this.options.pageSize != 0) { ++pageCount; } return pageCount; }, /* Calculates page numbers and returns an array of these numbers. *************************************************************************/ _calculatePageNumbers: function (pageCount) { if (pageCount <= 4) { //Show all pages var pageNumbers = []; for (var i = 1; i <= pageCount; ++i) { pageNumbers.push(i); } return pageNumbers; } else { //show first three, last three, current, previous and next page numbers var shownPageNumbers = [1, 2, pageCount - 1, pageCount]; var previousPageNo = this._normalizeNumber(this._currentPageNo - 1, 1, pageCount, 1); var nextPageNo = this._normalizeNumber(this._currentPageNo + 1, 1, pageCount, 1); this._insertToArrayIfDoesNotExists(shownPageNumbers, previousPageNo); this._insertToArrayIfDoesNotExists(shownPageNumbers, this._currentPageNo); this._insertToArrayIfDoesNotExists(shownPageNumbers, nextPageNo); shownPageNumbers.sort(function (a, b) { return a - b; }); return shownPageNumbers; } }, /* Creates and shows paging informations. *************************************************************************/ _createPagingInfo: function () { if (this._totalRecordCount <= 0) { this._$pageInfoSpan.empty(); return; } var startNo = (this._currentPageNo - 1) * this.options.pageSize + 1; var endNo = this._currentPageNo * this.options.pageSize; endNo = this._normalizeNumber(endNo, startNo, this._totalRecordCount, 0); if (endNo >= startNo) { var pagingInfoMessage = this._formatString(this.options.messages.pagingInfo, startNo, endNo, this._totalRecordCount); this._$pageInfoSpan.html(pagingInfoMessage); } }, /* Binds click events of all page links to change the page. *************************************************************************/ _bindClickEventsToPageNumberButtons: function () { var self = this; self._$pagingListArea .find('.jtable-page-number,.jtable-page-number-previous,.jtable-page-number-next,.jtable-page-number-first,.jtable-page-number-last') .not('.jtable-page-number-disabled') .click(function (e) { e.preventDefault(); self._changePage($(this).data('pageNumber')); }); }, /* Changes current page to given value. *************************************************************************/ _changePage: function (pageNo) { pageNo = this._normalizeNumber(pageNo, 1, this._calculatePageCount(), 1); if (pageNo == this._currentPageNo) { this._refreshGotoPageInput(); return; } this._currentPageNo = pageNo; this._reloadTable(); } }); })(jQuery); /************************************************************************ * SORTING extension for jTable * *************************************************************************/ (function ($) { //Reference to base object members var base = { _initializeFields: $.hik.jtable.prototype._initializeFields, _normalizeFieldOptions: $.hik.jtable.prototype._normalizeFieldOptions, _createHeaderCellForField: $.hik.jtable.prototype._createHeaderCellForField, _createRecordLoadUrl: $.hik.jtable.prototype._createRecordLoadUrl, _createJtParamsForLoading: $.hik.jtable.prototype._createJtParamsForLoading }; //extension members $.extend(true, $.hik.jtable.prototype, { /************************************************************************ * DEFAULT OPTIONS / EVENTS * *************************************************************************/ options: { sorting: false, multiSorting: false, defaultSorting: '' }, /************************************************************************ * PRIVATE FIELDS * *************************************************************************/ _lastSorting: null, //Last sorting of the table /************************************************************************ * OVERRIDED METHODS * *************************************************************************/ /* Overrides base method to create sorting array. *************************************************************************/ _initializeFields: function () { base._initializeFields.apply(this, arguments); this._lastSorting = []; if (this.options.sorting) { this._buildDefaultSortingArray(); } }, /* Overrides _normalizeFieldOptions method to normalize sorting option for fields. *************************************************************************/ _normalizeFieldOptions: function (fieldName, props) { base._normalizeFieldOptions.apply(this, arguments); props.sorting = (props.sorting != false); }, /* Overrides _createHeaderCellForField to make columns sortable. *************************************************************************/ _createHeaderCellForField: function (fieldName, field) { var $headerCell = base._createHeaderCellForField.apply(this, arguments); if (this.options.sorting && field.sorting) { this._makeColumnSortable($headerCell, fieldName); } return $headerCell; }, /* Overrides _createRecordLoadUrl to add sorting specific info to URL. *************************************************************************/ _createRecordLoadUrl: function () { var loadUrl = base._createRecordLoadUrl.apply(this, arguments); loadUrl = this._addSortingInfoToUrl(loadUrl); return loadUrl; }, /************************************************************************ * PRIVATE METHODS * *************************************************************************/ /* Builds the sorting array according to defaultSorting string *************************************************************************/ _buildDefaultSortingArray: function () { var self = this; $.each(self.options.defaultSorting.split(","), function (orderIndex, orderValue) { $.each(self.options.fields, function (fieldName, fieldProps) { if (fieldProps.sorting) { var colOffset = orderValue.indexOf(fieldName); if (colOffset > -1) { if (orderValue.toUpperCase().indexOf(' DESC', colOffset) > -1) { self._lastSorting.push({ fieldName: fieldName, sortOrder: 'DESC' }); } else { self._lastSorting.push({ fieldName: fieldName, sortOrder: 'ASC' }); } } } }); }); }, /* Makes a column sortable. *************************************************************************/ _makeColumnSortable: function ($columnHeader, fieldName) { var self = this; $columnHeader .addClass('jtable-column-header-sortable') .click(function (e) { e.preventDefault(); if (!self.options.multiSorting || !e.ctrlKey) { self._lastSorting = []; //clear previous sorting } self._sortTableByColumn($columnHeader); }); //Set default sorting $.each(this._lastSorting, function (sortIndex, sortField) { if (sortField.fieldName == fieldName) { if (sortField.sortOrder == 'DESC') { $columnHeader.addClass('jtable-column-header-sorted-desc'); } else { $columnHeader.addClass('jtable-column-header-sorted-asc'); } } }); }, /* Sorts table according to a column header. *************************************************************************/ _sortTableByColumn: function ($columnHeader) { //Remove sorting styles from all columns except this one if (this._lastSorting.length == 0) { $columnHeader.siblings().removeClass('jtable-column-header-sorted-asc jtable-column-header-sorted-desc'); } //If current sorting list includes this column, remove it from the list for (var i = 0; i < this._lastSorting.length; i++) { if (this._lastSorting[i].fieldName == $columnHeader.data('fieldName')) { this._lastSorting.splice(i--, 1); } } //Sort ASC or DESC according to current sorting state if ($columnHeader.hasClass('jtable-column-header-sorted-asc')) { $columnHeader.removeClass('jtable-column-header-sorted-asc').addClass('jtable-column-header-sorted-desc'); this._lastSorting.push({ 'fieldName': $columnHeader.data('fieldName'), sortOrder: 'DESC' }); } else { $columnHeader.removeClass('jtable-column-header-sorted-desc').addClass('jtable-column-header-sorted-asc'); this._lastSorting.push({ 'fieldName': $columnHeader.data('fieldName'), sortOrder: 'ASC' }); } //Load current page again this._reloadTable(); }, /* Adds jtSorting parameter to a URL as query string. *************************************************************************/ _addSortingInfoToUrl: function (url) { if (!this.options.sorting || this._lastSorting.length == 0) { return url; } var sorting = []; $.each(this._lastSorting, function (idx, value) { sorting.push(value.fieldName + ' ' + value.sortOrder); }); return (url + (url.indexOf('?') < 0 ? '?' : '&') + 'jtSorting=' + sorting.join(",")); }, /* Overrides _createJtParamsForLoading method to add sorging parameters to jtParams object. *************************************************************************/ _createJtParamsForLoading: function () { var jtParams = base._createJtParamsForLoading.apply(this, arguments); if (this.options.sorting && this._lastSorting.length) { var sorting = []; $.each(this._lastSorting, function (idx, value) { sorting.push(value.fieldName + ' ' + value.sortOrder); }); jtParams.jtSorting = sorting.join(","); } var params = this._loadPostDataSettings(); for(var name in params) { jtParams[name] = params[name]; } return jtParams; } }); })(jQuery); /************************************************************************ * DYNAMIC COLUMNS extension for jTable * * (Show/hide/resize columns) * *************************************************************************/ (function ($) { //Reference to base object members var base = { _create: $.hik.jtable.prototype._create, _normalizeFieldOptions: $.hik.jtable.prototype._normalizeFieldOptions, _createHeaderCellForField: $.hik.jtable.prototype._createHeaderCellForField, _createCellForRecordField: $.hik.jtable.prototype._createCellForRecordField }; //extension members $.extend(true, $.hik.jtable.prototype, { /************************************************************************ * DEFAULT OPTIONS / EVENTS * *************************************************************************/ options: { tableId: undefined, columnResizable: true, columnSelectable: true }, /************************************************************************ * PRIVATE FIELDS * *************************************************************************/ _$columnSelectionDiv: null, _$columnResizeBar: null, _cookieKeyPrefix: null, _currentResizeArgs: null, /************************************************************************ * OVERRIDED METHODS * *************************************************************************/ /* Overrides _addRowToTableHead method. *************************************************************************/ _create: function () { base._create.apply(this, arguments); this._createColumnResizeBar(); this._createColumnSelection(); if (this.options.saveUserPreferences) { this._loadColumnSettings(); } this._normalizeColumnWidths(); }, /* Normalizes some options for a field (sets default values). *************************************************************************/ _normalizeFieldOptions: function (fieldName, props) { base._normalizeFieldOptions.apply(this, arguments); //columnResizable if (this.options.columnResizable) { props.columnResizable = (props.columnResizable != false); } //visibility if (!props.visibility) { props.visibility = 'visible'; } }, /* Overrides _createHeaderCellForField to make columns dynamic. *************************************************************************/ _createHeaderCellForField: function (fieldName, field) { var $headerCell = base._createHeaderCellForField.apply(this, arguments); //Make data columns resizable except the last one if (this.options.columnResizable && field.columnResizable && (fieldName != this._columnList[this._columnList.length - 1])) { this._makeColumnResizable($headerCell); } //Hide column if needed if (field.visibility == 'hidden') { $headerCell.hide(); } return $headerCell; }, /* Overrides _createHeaderCellForField to decide show or hide a column. *************************************************************************/ _createCellForRecordField: function (record, fieldName) { var $column = base._createCellForRecordField.apply(this, arguments); var field = this.options.fields[fieldName]; if (field.visibility == 'hidden') { $column.hide(); } return $column; }, /************************************************************************ * PUBLIC METHODS * *************************************************************************/ /* Changes visibility of a column. *************************************************************************/ changeColumnVisibility: function (columnName, visibility) { this._changeColumnVisibilityInternal(columnName, visibility); this._normalizeColumnWidths(); if (this.options.saveUserPreferences) { this._saveColumnSettings(); } }, /************************************************************************ * PRIVATE METHODS * *************************************************************************/ /* Changes visibility of a column. *************************************************************************/ _changeColumnVisibilityInternal: function (columnName, visibility) { //Check if there is a column with given name var columnIndex = this._columnList.indexOf(columnName); if (columnIndex < 0) { this._logWarn('Column "' + columnName + '" does not exist in fields!'); return; } //Check if visibility value is valid if (['visible', 'hidden', 'fixed'].indexOf(visibility) < 0) { this._logWarn('Visibility value is not valid: "' + visibility + '"! Options are: visible, hidden, fixed.'); return; } //Get the field var field = this.options.fields[columnName]; if (field.visibility == visibility) { return; //No action if new value is same as old one. } //Hide or show the column if needed var columnIndexInTable = this._firstDataColumnOffset + columnIndex + 1; if (field.visibility != 'hidden' && visibility == 'hidden') { this._$table .find('>thead >tr >th:nth-child(' + columnIndexInTable + '),>tbody >tr >td:nth-child(' + columnIndexInTable + ')') .hide(); } else if (field.visibility == 'hidden' && visibility != 'hidden') { this._$table .find('>thead >tr >th:nth-child(' + columnIndexInTable + '),>tbody >tr >td:nth-child(' + columnIndexInTable + ')') .show() .css('display', 'table-cell'); } field.visibility = visibility; }, /* Prepares dialog to change settings. *************************************************************************/ _createColumnSelection: function () { var self = this; //Create a div for dialog and add to container element this._$columnSelectionDiv = $('<div />') .addClass('jtable-column-selection-container') //.appendTo(self._$mainContainer); .insertAfter('#contentText'); this._$table.children('thead').bind('contextmenu', function (e) { if (!self.options.columnSelectable) { return; } e.preventDefault(); //Make an overlay div to disable page clicks $('<div />') .addClass('jtable-contextmenu-overlay') .click(function () { $(this).remove(); self._$columnSelectionDiv.hide(); }) .bind('contextmenu', function () { return false; }) //.appendTo(document.body); .insertAfter('#contentText'); self._fillColumnSelection(); //Calculate position of column selection list and show it var containerOffset = self._$mainContainer.offset(); var selectionDivTop = e.pageY - containerOffset.top; var selectionDivLeft = e.pageX - containerOffset.left; var containerHeight = self._$columnSelectionDiv.height() - 70; var selectionDivMinWidth = 100; //in pixels var containerWidth = self._$mainContainer.width(); //If user clicks right area of header of the table, show list at a little left if ((containerWidth > selectionDivMinWidth) && (selectionDivLeft > (containerWidth - selectionDivMinWidth))) { selectionDivLeft = containerWidth - selectionDivMinWidth; } self._$columnSelectionDiv.css({ left: selectionDivLeft, top: containerOffset.top, //selectionDivTop, 'min-width': selectionDivMinWidth + 'px', height: containerHeight + 'px', }).css( 'overflow-y', 'scroll' ).show(); }); }, /* Prepares content of settings dialog. *************************************************************************/ _fillColumnSelection: function () { var self = this; var $columnsUl = $('<ul></ul>') .addClass('jtable-column-select-list'); for (var i = 0; i < this._columnList.length; i++) { var columnName = this._columnList[i]; var field = this.options.fields[columnName]; //Crete li element var $columnLi = $('<li></li>').appendTo($columnsUl); //Create label for the checkbox var $label = $('<label for="' + columnName + '"></label>') .append($('<span>' + (field.title || columnName) + '</span>')) .appendTo($columnLi); //Create checkbox var $checkbox = $('<input type="checkbox" name="' + columnName + '">') .prependTo($label) .click(function () { var $clickedCheckbox = $(this); var clickedColumnName = $clickedCheckbox.attr('name'); var clickedField = self.options.fields[clickedColumnName]; if (clickedField.visibility == 'fixed') { return; } self.changeColumnVisibility(clickedColumnName, $clickedCheckbox.is(':checked') ? 'visible' : 'hidden'); }); //Check, if column if shown if (field.visibility != 'hidden') { $checkbox.attr('checked', 'checked'); } //Disable, if column is fixed if (field.visibility == 'fixed') { $checkbox.attr('disabled', 'disabled'); } } this._$columnSelectionDiv.html($columnsUl); }, /* creates a vertical bar that is shown while resizing columns. *************************************************************************/ _createColumnResizeBar: function () { this._$columnResizeBar = $('<div />') .addClass('jtable-column-resize-bar') .appendTo(this._$mainContainer) .hide(); }, /* Makes a column sortable. *************************************************************************/ _makeColumnResizable: function ($columnHeader) { var self = this; //Create a handler to handle mouse click event $('<div />') .addClass('jtable-column-resize-handler') .appendTo($columnHeader.find('.jtable-column-header-container')) //Append the handler to the column .mousedown(function (downevent) { //handle mousedown event for the handler downevent.preventDefault(); downevent.stopPropagation(); var mainContainerOffset = self._$mainContainer.offset(); //Get a reference to the next column var $nextColumnHeader = $columnHeader.nextAll('th.jtable-column-header:visible:first'); if (!$nextColumnHeader.length) { return; } //Store some information to be used on resizing var minimumColumnWidth = 10; //A column's width can not be smaller than 10 pixel. self._currentResizeArgs = { currentColumnStartWidth: $columnHeader.outerWidth(), minWidth: minimumColumnWidth, maxWidth: $columnHeader.outerWidth() + $nextColumnHeader.outerWidth() - minimumColumnWidth, mouseStartX: downevent.pageX, minResizeX: function () { return this.mouseStartX - (this.currentColumnStartWidth - this.minWidth); }, maxResizeX: function () { return this.mouseStartX + (this.maxWidth - this.currentColumnStartWidth); } }; //Handle mouse move event to move resizing bar var resizeonmousemove = function (moveevent) { if (!self._currentResizeArgs) { return; } var resizeBarX = self._normalizeNumber(moveevent.pageX, self._currentResizeArgs.minResizeX(), self._currentResizeArgs.maxResizeX()); self._$columnResizeBar.css('left', (resizeBarX - mainContainerOffset.left) + 'px'); }; //Handle mouse up event to finish resizing of the column var resizeonmouseup = function (upevent) { if (!self._currentResizeArgs) { return; } $(document).unbind('mousemove', resizeonmousemove); $(document).unbind('mouseup', resizeonmouseup); self._$columnResizeBar.hide(); //Calculate new widths in pixels var mouseChangeX = upevent.pageX - self._currentResizeArgs.mouseStartX; var currentColumnFinalWidth = self._normalizeNumber(self._currentResizeArgs.currentColumnStartWidth + mouseChangeX, self._currentResizeArgs.minWidth, self._currentResizeArgs.maxWidth); var nextColumnFinalWidth = $nextColumnHeader.outerWidth() + (self._currentResizeArgs.currentColumnStartWidth - currentColumnFinalWidth); //Calculate widths as percent var pixelToPercentRatio = $columnHeader.data('width-in-percent') / self._currentResizeArgs.currentColumnStartWidth; $columnHeader.data('width-in-percent', currentColumnFinalWidth * pixelToPercentRatio); $nextColumnHeader.data('width-in-percent', nextColumnFinalWidth * pixelToPercentRatio); //Set new widths to columns (resize!) $columnHeader.css('width', $columnHeader.data('width-in-percent') + '%'); $nextColumnHeader.css('width', $nextColumnHeader.data('width-in-percent') + '%'); //Normalize all column widths self._normalizeColumnWidths(); //Finish resizing self._currentResizeArgs = null; //Save current preferences if (self.options.saveUserPreferences) { self._saveColumnSettings(); } }; //Show vertical resize bar self._$columnResizeBar .show() .css({ top: ($columnHeader.offset().top - mainContainerOffset.top) + 'px', left: (downevent.pageX - mainContainerOffset.left) + 'px', height: (self._$table.outerHeight()) + 'px' }); //Bind events $(document).bind('mousemove', resizeonmousemove); $(document).bind('mouseup', resizeonmouseup); }); }, /* Normalizes column widths as percent for current view. *************************************************************************/ _normalizeColumnWidths: function () { //Set command column width var commandColumnHeaders = this._$table .find('>thead th.jtable-command-column-header') .data('width-in-percent', 1) .css('width', '1%'); //Find data columns var headerCells = this._$table.find('>thead th.jtable-column-header'); //Calculate total width of data columns var totalWidthInPixel = 0; headerCells.each(function () { var $cell = $(this); if ($cell.is(':visible')) { totalWidthInPixel += $cell.outerWidth(); } }); //Calculate width of each column var columnWidhts = {}; var availableWidthInPercent = 100.0 - commandColumnHeaders.length; headerCells.each(function () { var $cell = $(this); if ($cell.is(':visible')) { var fieldName = $cell.data('fieldName'); var widthInPercent = $cell.outerWidth() * availableWidthInPercent / totalWidthInPixel; columnWidhts[fieldName] = widthInPercent; } }); //Set width of each column headerCells.each(function () { var $cell = $(this); if ($cell.is(':visible')) { var fieldName = $cell.data('fieldName'); $cell.data('width-in-percent', columnWidhts[fieldName]).css('width', columnWidhts[fieldName] + '%'); } }); }, /* Saves field setting to cookie. * Saved setting will be a string like that: * fieldName1=visible;23|fieldName2=hidden;17|... *************************************************************************/ _saveColumnSettings: function () { var self = this; var fieldSettings = ''; this._$table.find('>thead >tr >th.jtable-column-header').each(function () { var $cell = $(this); var fieldName = $cell.data('fieldName'); var columnWidth = $cell.data('width-in-percent'); var fieldVisibility = self.options.fields[fieldName].visibility; var fieldSetting = fieldName + "=" + fieldVisibility + ';' + columnWidth; fieldSettings = fieldSettings + fieldSetting + '|'; }); this._setCookie('column-settings', fieldSettings.substr(0, fieldSettings.length - 1)); }, /* Loads field settings from cookie that is saved by _saveFieldSettings method. *************************************************************************/ _loadColumnSettings: function () { var self = this; var columnSettingsCookie = this._getCookie('column-settings'); if (!columnSettingsCookie) { return; } var columnSettings = {}; $.each(columnSettingsCookie.split('|'), function (inx, fieldSetting) { var splitted = fieldSetting.split('='); var fieldName = splitted[0]; var settings = splitted[1].split(';'); columnSettings[fieldName] = { columnVisibility: settings[0], columnWidth: settings[1] }; }); var headerCells = this._$table.find('>thead >tr >th.jtable-column-header'); headerCells.each(function () { var $cell = $(this); var fieldName = $cell.data('fieldName'); var field = self.options.fields[fieldName]; if (columnSettings[fieldName]) { if (field.visibility != 'fixed') { self._changeColumnVisibilityInternal(fieldName, columnSettings[fieldName].columnVisibility); } $cell.data('width-in-percent', columnSettings[fieldName].columnWidth).css('width', columnSettings[fieldName].columnWidth + '%'); } }); } }); })(jQuery); /************************************************************************ * MASTER/CHILD tables extension for jTable * *************************************************************************/ (function ($) { //Reference to base object members var base = { _removeRowsFromTable: $.hik.jtable.prototype._removeRowsFromTable }; //extension members $.extend(true, $.hik.jtable.prototype, { /************************************************************************ * DEFAULT OPTIONS / EVENTS * *************************************************************************/ options: { openChildAsAccordion: false }, /************************************************************************ * PUBLIC METHODS * *************************************************************************/ /* Creates and opens a new child table for given row. *************************************************************************/ openChildTable: function ($row, tableOptions, opened) { var self = this; //Apply theming as same as parent table unless explicitily set if (tableOptions.jqueryuiTheme == undefined) { tableOptions.jqueryuiTheme = self.options.jqueryuiTheme; } //Show close button as default tableOptions.showCloseButton = (tableOptions.showCloseButton != false); //Close child table when close button is clicked (default behavior) if (tableOptions.showCloseButton && !tableOptions.closeRequested) { tableOptions.closeRequested = function () { self.closeChildTable($row); }; } //If accordion style, close open child table (if it does exists) if (self.options.openChildAsAccordion) { $row.siblings('.jtable-data-row').each(function () { self.closeChildTable($(this)); }); } //Close child table for this row and open new one for child table self.closeChildTable($row, function () { var $childRowColumn = self.getChildRow($row).children('td').empty(); var $childTableContainer = $('<div />') .addClass('jtable-child-table-container') .appendTo($childRowColumn); $childRowColumn.data('childTable', $childTableContainer); $childTableContainer.jtable(tableOptions); self.openChildRow($row); $childTableContainer.hide().slideDown('fast', function () { if (opened) { opened({ childTable: $childTableContainer }); } }); }); }, /* Closes child table for given row. *************************************************************************/ closeChildTable: function ($row, closed) { var self = this; var $childRowColumn = this.getChildRow($row).children('td'); var $childTable = $childRowColumn.data('childTable'); if (!$childTable) { if (closed) { closed(); } return; } $childRowColumn.data('childTable', null); $childTable.slideUp('fast', function () { $childTable.jtable('destroy'); $childTable.remove(); self.closeChildRow($row); if (closed) { closed(); } }); }, /* Returns a boolean value indicates that if a child row is open for given row. *************************************************************************/ isChildRowOpen: function ($row) { return (this.getChildRow($row).is(':visible')); }, /* Gets child row for given row, opens it if it's closed (Creates if needed). *************************************************************************/ getChildRow: function ($row) { return $row.data('childRow') || this._createChildRow($row); }, /* Creates and opens child row for given row. *************************************************************************/ openChildRow: function ($row) { var $childRow = this.getChildRow($row); if (!$childRow.is(':visible')) { $childRow.show(); } return $childRow; }, /* Closes child row if it's open. *************************************************************************/ closeChildRow: function ($row) { var $childRow = this.getChildRow($row); if ($childRow.is(':visible')) { $childRow.hide(); } }, /************************************************************************ * OVERRIDED METHODS * *************************************************************************/ /* Overrides _removeRowsFromTable method to remove child rows of deleted rows. *************************************************************************/ _removeRowsFromTable: function ($rows, reason) { //var self = this; if (reason == 'deleted') { $rows.each(function () { var $row = $(this); var $childRow = $row.data('childRow'); if ($childRow) { //self.closeChildTable($row); //Removed since it causes "Uncaught Error: cannot call methods on jtable prior to initialization; attempted to call method 'destroy'" $childRow.remove(); } }); } base._removeRowsFromTable.apply(this, arguments); }, /************************************************************************ * PRIVATE METHODS * *************************************************************************/ /* Creates a child row for a row, hides and returns it. *************************************************************************/ _createChildRow: function ($row) { var totalColumnCount = this._$table.find('thead th').length; var $childRow = $('<tr></tr>') .addClass('jtable-child-row') .append('<td colspan="' + totalColumnCount + '"></td>'); $row.after($childRow); $row.data('childRow', $childRow); $childRow.hide(); return $childRow; } }); })(jQuery); ______________________________________________________ * End Part 4 * ______________________________________________________ Quote osC OpenSSL Encryption with jCryptionSupport Forum jQuery/Ajax Advanced Statistics 2.3Support Forum jQuery/Ajax Advanced Order Handler 2.3.3Support ForumjQuery/Ajax Advanced Caching System 2.3.3Support ForumjQuery/Ajax Fast checkout/Shopping Cart/Login/Create Account 2.3.3Support ForumjQuery/Ajax Shopping Cart 2.3.3Support ForumjQuery/Ajax Dynamic Checkout 2.3.3Support ForumjQuery/Ajax Mini Cart for osCommerce 2.3.3Support ForumjQuery Cycle What's New InfoboxAuto Out Of Stock CSS Image OverlayjQuery-UI Autocomplete Product Search with Links & MySQLi support for osCommerce 2.X Link to comment Share on other sites More sharing options...
Dr. Rolex Posted October 6, 2014 Author Share Posted October 6, 2014 Replace ./admin/includes/modules/order_handler/js/01_03_order_handler_rev3_module.js With This: (1/2 Part of this File) /* Advanced Order Handler Rev3 for osCommerce 2.3.3 Copyright (C) 2014 Jonas [email protected] This file is part of Advanced Order Handler Rev3. Advanced Order Handler Rev3 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Advanced Order Handler Rev3 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Advanced Order Handler Rev3. If not, see <http://www.gnu.org/licenses/>. */ // Define Global Variables var self, ajaxRequest, last_order_number = 0, edit_order = false, polling = false, jTableOptions = $.hik.jtable.prototype.options.messages, xmlHttp, loading = $( '#ajax_loader' ).hide(), oHandler = ( function( undefined ) { /* Order Handler: Plugin Configurations *************************************************************************/ config = { message: "Records Loaded: {0} out of {1}", progress: 0, total: 0, clearSelection: true, openChildAsAccordion: false, toggleGritter: true }, init = function( parameters ) { var childRow = function() { var img = $( this ).off( "click", childRow ).find( "span.glyphicon-resize-full" ); $( "#orderTable" ).jtable( "closeChildTable", $( this ) ); $( img ).removeClass( "glyphicon-resize-full" ).addClass( "glyphicon-resize-small" ); }; $( '#orderTable' ).jtable( { title: 'Order Handler', paging: true, pageSize: 10, sorting: true, multiSorting: true, jqueryuiTheme: false, selectOnRowClick: false, selecting: true, //Enable selecting multiselect: true, //Allow multiple selecting selectingCheckboxes: true, //Show checkboxes on first column defaultSorting: 'o.orders_id DESC', openChildAsAccordion: oHandler.config.openChildAsAccordion, ajaxSettings: { type: 'POST', dataType: 'json', //global: false }, deleteConfirmation: function( data ) { data.deleteConfirmMessage = "Order <strong>#" + data.record.orders_id + "</strong> from customer <strong>" + data.record.customers_name + "</strong> will be deleted. Are you sure?" + "<div><input name='restock' type='checkbox' id='restock'><label for='restock' style='float:right;margin-top: 1em;margin-bottom: 0;'>" + TEXT_INFO_RESTOCK_PRODUCT_QUANTITY + "</label></div><script>$( '#restock' ).button();</script>"; }, tableId: 'jTable', actions: { listAction: function( postData, jtParams ) { if ( "undefined" === typeof postData ) postData = { status: "1" }; return $.Deferred( function( $dfd ) { $.ajax( { url: encodeURI( 'get_table.php?action=get_orders&jtStartIndex=' + jtParams.jtStartIndex + '&jtPageSize=' + jtParams.jtPageSize + '&jtSorting=' + jtParams.jtSorting ), type: 'POST', dataType: 'json', data: postData, beforeSend: function( xhr ) { settings = { message: jTableOptions.loadingMessage, }; if ( false === edit_order ) oHandler.showBusy.setup( settings ); }, //global: false, success: function( data ) { $dfd.resolve( data ); }, error: function() { $dfd.reject(); } } ); } ); }, createAction: 'get_table.php?action=create_new_order', updateAction: 'get_table.php?action=update_order_fields', deleteAction: function( postData ) { var restock = $( "#restock" ).prop( "checked" ); postData.restock = restock; return $.Deferred( function( $dfd ) { $.ajax( { url: 'get_table.php?action=delete_order', type: 'POST', //global: false, dataType: 'json', data: postData, success: function( data ) { $dfd.resolve( data ); }, error: function() { $dfd.reject(); } } ) .always( function() { oHandler.showBusy.hide(); } ); } ); } }, toolbar: { items: [ { text: 'Configuration', iconCSS: 'fa-cogs', cssClass: 'configurationModal', }, { text: 'Calculate Orders Totals', iconCSS: 'fa-dollar', click: function() { var orders_total = 0, selectedRows = $( "#orderTable" ).jtable( "selectedRows" ), numRows = selectedRows.length; for ( var i = 0; i < numRows; i++ ) { orders_total += parseFloat( selectedRows.find( "td.order_total" ).eq( i ).text() .replace( /[^0-9\,\.]+/g, "" ) .replace( /(,|\.)(?=[^.]*(,|\.))/, "" ) .replace( /\D/g, "." ) .replace( /\.(?=[^.]*\.)/, "" )); } $.fn.tdialog( { type: "info", content: "Combined Order Totals for selected rows are " + orders_total + ".", title: "Calculate Orders Totals", icon: "info", showOverlay: oHandler.configuration.settings.showOverlay, effect: 'css3', css3EffectIn: '', css3EffectOut: 'bounce', } ); } }, { text: 'Statistics', iconCSS: 'fa-bar-chart-o', cssClass: 'statistics', } ] }, fields: { edit_order: { title: '', width: '1%', sorting: false, edit: false, create: false, display: function( data ) { return data.record.edit_order; } }, orders_id: { title: ENTRY_ORDER_NUMBER, listClass: 'center jtable-selecting-column select_me', edit: false, key: true, create: false, width: '9%', display: function( data ) { return '<strong>' + data.record.orders_id + '</strong>'; } }, customers_name: { title: ENTRY_CUSTOMER, listClass: 'customers_name', edit: true, create: false, width: '13%' }, //CHILD TABLE DEFINITION FOR "ORDER" order: { title: '', width: '1%', sorting: false, edit: false, create: false, listClass: 'expand_order center ajax_disable jtable-command-column', selecting: false, selectOnRowClick: false, display: function( data ) { var img = $( data.record.order ); //Open child table when user clicks the image $( img ).on( "click", function() { var pos = $( "#orderTable" ).jtable( "isChildRowOpen", $( img ).closest( 'tr' ) ), products = data.record.products; this.className = "glyphicon glyphicon-resize-small tooltip_set"; $( this ).closest( "tr" ).off( "click", childRow ); if ( pos === true ) return $( "#orderTable" ).jtable( "closeChildTable", $( img ).closest( 'tr' ) ); $( "#orderTable" ).find( "span.glyphicon-resize-full" ).removeClass( "glyphicon-resize-full" ).addClass( "glyphicon-resize-small" ); this.className = "glyphicon glyphicon-resize-full tooltip_set"; $( "#orderTable" ).jtable( "openChildTable", $( img ).closest( 'tr' ), { title: "Order #<span class='select_me'>" + data.record.orders_id + "</span>", selecting: false, selectOnRowClick: false, jqueryuiTheme: false, tableId: 'productTotals', actions: { listAction: 'get_table.php?action=get_order&oID=' + data.record.orders_id }, fields: { orders_id: { key: true, type: 'hidden' }, customer_address: { title: ENTRY_CUSTOMER, width: '20%' }, shipping_address: { title: ENTRY_SHIPPING_ADDRESS, width: '10%' }, billing_address: { title: ENTRY_BILLING_ADDRESS, width: '10%' }, email_address: { title: ENTRY_EMAIL_ADDRESS, width: '20%' }, telephone: { title: ENTRY_TELEPHONE_NUMBER, width: '10%' }, shipping_method: { listClass: 'ajax_disable', title: ENTRY_SHIPPING_METHOD, width: '20%' }, payment_method: { listClass: 'ajax_disable', title: ENTRY_PAYMENT_METHOD, width: '20%' }, }, recordsLoaded: function( event, data ) { var row = $( this ).find( "tr" ).eq( 1 ), productsRow = $( "#orderTable" ).jtable( "openChildRow", $( row ) ), parentRow = $( this ).closest( "tr" ).prev(), jtable_title = $( parentRow ).next().find( "div.jtable-title-text-next" ); $( productsRow ).children( "td" ) //.css({ opacity:0 }) .css({ width:'100%' }) .css({ position:'absolute' }) .html( data.records[ 0 ].products ).find("#tdb-update").button({icons:{primary:"ui-icon-disk"}}).addClass("ui-priority-primary").parent().removeClass("tdbLink"); $( productsRow ).closest( "table.jtable" ) .find('#change_order_status, #shipping_method_pull_down, #payment_method_pull_down').multiselect({ buttonClass: 'btn btn-xs btn-info' }); var h = $( productsRow ).find( "table" ).eq(0).height() + $( productsRow ).find( "table" ).eq(1).height() + 5; $( productsRow ).animate({ height:h + 'px' }, 400, function( event ) { $( productsRow ).children( "td" ) .css({ position:'static' }); }); //$( productsRow ).children( "td" ).animate({ opacity: 1 }, 400); $( parentRow ).on( "click", childRow ); $( jtable_title ).on( "click", function() { $( img ).removeClass( "glyphicon-resize-full" ).addClass( "glyphicon-resize-small" ); var childRow = $( this ).closest( "tr.jtable-child-row" ).prev(); $( "#orderTable" ).jtable( "closeChildTable", $( childRow ) ); return $( this ).off(); } ); // Initiate Create new field Dialog //oHandler.dialogForm.dialog(); }, closeRequested: function( event, data ) { $( img ).removeClass( "glyphicon-resize-full" ).addClass( "glyphicon-resize-small" ); $( "#orderTable" ).jtable( "closeChildTable", $( img ).closest( 'tr' ) ); } }, function( data ) { //opened handler data.childTable.jtable( 'load' ); } ); } ); // Return image to show on the order row return img; } }, order_total: { title: TABLE_HEADING_ORDER_TOTAL, listClass: 'order_total', edit: false, create: false, width: '10%' }, date_purchased: { title: TABLE_HEADING_DATE_PURCHASED, listClass: 'date_purchased', edit: false, create: false, width: '15%' }, orders_status: { title: TABLE_HEADING_STATUS, listClass: 'ajax_disable', edit: false, create: false, width: '13%', display: function( data ) { return data.record.orders_status; } }, orders_status_text: { title: TABLE_HEADING_STATUS, edit: false, create: false, width: '13%', visibility: 'hidden', display: function( data ) { return data.record.orders_status_text; } }, shipping_method: { title: ENTRY_SHIPPING_METHOD, listClass: 'ajax_disable', width: '8%', edit: false, create: false, display: function( data ) { return data.record.shipping_method; } }, shipping_method_text: { title: ENTRY_SHIPPING_METHOD, width: '8%', edit: false, create: false, visibility: 'hidden', display: function( data ) { return data.record.shipping_method_text; } }, payment_method: { title: ENTRY_PAYMENT_METHOD, listClass: 'ajax_disable', width: '8%', edit: false, create: false, display: function( data ) { return data.record.payment_method; } }, payment_method_text: { title: ENTRY_PAYMENT_METHOD, width: '16%', edit: false, create: false, visibility: 'hidden', display: function( data ) { return data.record.payment_method_text; } }, products_quantity: { title: TABLE_HEADING_QUANTITY, listClass: 'products_purchased center', edit: false, create: false, width: '4%' }, comments: { title: TABLE_HEADING_COMMENTS, edit: false, create: false, width: '14%', display: function( data ) { return data.record.comments; } }, search_customer_orders: { title: '', width: '1%', sorting: false, edit: false, create: false, display: function( data ) { return data.record.search_customer_orders; } }, mail_confirmation: { title: '', width: '1%', sorting: false, edit: false, create: false, display: function( data ) { return data.record.mail_confirmation; } }, duplicate_order: { title: '', width: '1%', sorting: false, edit: false, create: false, display: function( data ) { return data.record.duplicate_order; } }, mail_customer: { title: '', width: '1%', sorting: false, edit: false, create: false, display: function( data ) { return data.record.mail_customer; } }, /* Here Create new Order Begins */ customers_id: { type: 'hidden', edit: false, create: true, sorting: false, display: function( data ) { return data.records.customers_id; } }, search_customer: { title: HEADING_TITLE_SEARCH_CUSTOMERS, visibility: 'hidden', create: true, edit: false, sorting: false }, customers_firstname: { title: ENTRY_FIRST_NAME, visibility: 'hidden', create: true, sorting: false, edit: false }, customers_lastname: { title: ENTRY_LAST_NAME, visibility: 'hidden', create: true, sorting: false, edit: false }, delivery_company: { title: ENTRY_COMPANY, visibility: 'hidden', create: true, edit: true, display: function( data ) { return data.record.customers_company; } }, customers_email_address: { title: ENTRY_EMAIL_ADDRESS, visibility: 'hidden', defultValue: "true", create: true, display: function( data ) { return data.record.customers_email_address; } }, delivery_street_address: { title: ENTRY_STREET_ADDRESS, visibility: 'hidden', create: true, display: function( data ) { return data.record.delivery_street_address; } }, delivery_postcode: { title: ENTRY_POST_CODE, visibility: 'hidden', create: true, display: function( data ) { return data.record.delivery_postcode; } }, delivery_state: { title: ENTRY_STATE, visibility: 'hidden', create: true, display: function( data ) { return data.record.delivery_state; } }, delivery_city: { title: ENTRY_CITY, visibility: 'hidden', create: true, display: function( data ) { return data.record.delivery_city; } }, delivery_country: { title: ENTRY_COUNTRY, visibility: 'hidden', options: country_list, create: true, display: function( data ) { return data.record.delivery_country; } }, customers_telephone: { title: ENTRY_TELEPHONE_NUMBER, visibility: 'hidden', create: true, display: function( data ) { return data.record.customers_telephone; } }, customers_fax: { title: ENTRY_FAX_NUMBER, visibility: 'hidden', create: true, edit: false }, payment_method_code: { title: ENTRY_PAYMENT_METHOD, visibility: 'hidden', options: payment_modules, create: true }, shipping_module: { title: ENTRY_SHIPPING_METHOD, visibility: 'hidden', options: shipping_modules, create: true }, Currency: { title: ENTRY_CURRENCY, visibility: 'hidden', options: currencies, create: true, edit: false } }, loadingRecords: function( event, data ) { //console.log('loadingRecords event fired'); }, recordAdded: function( event, data ) { //console.log( "recordAdded" ); }, recordUpdated: function( event, data ) { //console.log( "recordUpdated" ); }, recordsLoaded: function( event, data ) { // Determine Last Order Number if ( 0 < data.records.length ) { if ( last_order_number < data.records[ 0 ].orders_id ) last_order_number = data.records[ 0 ].orders_id; } else { last_order_number = data.serverResponse.LastOrderNumber; } // Initiate Send Email Modal oHandler.contact.init(); $( "select.orders_status" ).multiselect({ buttonClass: 'btn btn-xs btn-info' }); $( "select.payment_method_pull_down" ).multiselect({ buttonClass: 'btn btn-xs btn-info' }); $( "select.shipping_method_pull_down" ).multiselect({ buttonClass: 'btn btn-xs btn-info' }); // Initiate Ajax Long Polling // oHandler.messagesLongPolling.init( event ); var switchOn = ( true === edit_order ? false : true ); if ( true === polling && undefined !== last_order_number ) oHandler.messagesLongPolling.toggle( event, switchOn ); }, rowInserted: function( event, data ) { $( data.row[ 0 ].firstChild.firstChild ) .attr( "name", "batch_order_numbers[" + data.record.orders_id + "]" ).val( "no" ); $( data.row ).addClass( "contextMenu" ); }, formCreated: function( event, data ) { //console.log( "formCreated" ); // Initiate Bootstrap Multiselect on <select> data.form.find( "select" ) .multiselect({ buttonClass: 'btn btn-xs btn-info', maxHeight: 200, enableCaseInsensitiveFiltering: true, }); // Find Option for Selected Payment Method if ( "edit" == data.formType ) { var payment_method = $( "#payment_method_" + data.record.orders_id )[0].innerText, selected = data.form.find( "#Edit-payment_method_code" ).find( "option" ).filter(function () { return $(this).html() == payment_method; }).val(); $( "#Edit-payment_method_code" ) .multiselect('select', selected ) .multiselect('refresh'); } if ( 0 < $( "#Edit-search_customer" ).length ) { var cache = {}; $( "#Edit-search_customer" ).autocomplete( { minLength: 2, select: function( event, ui ) { window.location = ( ui.item.id ); }, source: function( request, response ) { var term = request.term; if ( term in cache ) { response( cache[ term ] ); return; } $.ajax( { dataType: "json", url: "get_table.php?action=search_customers", data: request, //global: false } ).done( function( data, status, xhr ) { cache[ term ] = data; response( data ); } ); } } ).data( "ui-autocomplete" )._renderItem = function( ul, item ) { return $( "<li></li>" ) .data( "item.autocomplete", item ) .append( "<a href='" + item.id + "' class='search_customer'>" + item.value + "</a>" ) .click( function( e ) { e.preventDefault(); e.stopPropagation(); href = $( this ).find( "a" ).attr( "href" ); $.ajax( { dataType: "json", url: encodeURI( href ), type: 'GET', //global: false } ) .done( function( data, status, xhr ) { $( "#Edit-customers_id" ).val( data.customers_id ); $( "#Edit-customers_firstname" ).val( data.customers_firstname ); $( "#Edit-customers_lastname" ).val( data.customers_lastname ); $( "#Edit-customers_email_address" ).val( data.customers_email_address ); $( "#Edit-delivery_street_address" ).val( data.entry_street_address ); $( "#Edit-delivery_postcode" ).val( data.entry_postcode ); $( "#Edit-delivery_state" ).val( data.entry_state ); $( "#Edit-delivery_city" ).val( data.entry_city ); $( "#Edit-customers_telephone" ).val( data.customers_telephone ); $( "#Edit-customers_fax" ).val( data.customers_fax ); $( "#Edit-delivery_country" ).multiselect('select', $( "#Edit-delivery_country" ).find( "option" ).eq( ( data.entry_country_id - 2 ) )[0].value ); } ) .always( function() { $( "#Edit-search_customer" ).autocomplete( "close" ); }); } ) .appendTo( ul ); }; } }, selectionChanged: function( event, data ) { //console.log( "selectionChanged" ); } } ); // Load all records when page is first shown $( "#orderTable" ).jtable( "load", parameters ); }, /* Display jTable Message *************************************************************************/ showBusy = { setup: function ( settings ) { $.extend( config, settings ); $( "#orderTable" ).jtable( "showBusy", oHandler.showBusy.formatString( config.message, config.progress, config.total ), 0 ); }, update: function ( progress ) { $("#orderTable").jtable( "showBusy", oHandler.showBusy.formatString( config.message, progress, config.total ), 0 ); if ( config.total == progress ) oHandler.showBusy.hide(); }, hide: function () { $( "#orderTable" ).jtable( "hideBusy" ); }, formatString: function () { if ( 0 === arguments.length ) { return null; } var str = arguments[0], length = arguments.length; for ( var i = 1; i < length; i++ ) { var placeHolder = "{" + (i - 1) + "}"; str = str.replace( placeHolder, arguments[i] ); } return str; } }, /* Order Handler Configuration Modal *************************************************************************/ configuration = { settings: { self: $( "#order_handler_config" ), configModal: $( "#configModal" ), PHPMailer: false, printField: $( "#print" ), showOverlay: true, debugTime: false, set: false, newWin: false, key_code: "", }, init: function() { var s = this; $( "body" ).on( "click", "#orderTable span.configurationModal", function( event ) { //s.settings.self.find( "li" ).tooltip('toggle').tooltip('hide'); s.settings.self.simpleModal({ closeHTML: "<a href='#' title='Close' class='modal-close'>x</a>", close: true, persist: true, position: ["15%",], overlayId: 'contact-overlay', overlayClose: true, containerId: 'config-container', onOpen: oHandler.configuration.open, //onShow: oHandler.configuration.show, onClose: oHandler.configuration.close }); }); if ( false === oHandler.configuration.settings.set ) { oHandler.configuration.show(this); oHandler.configuration.settings.set = true; } $( "#orderTable" ).find( "span.statistics" ).on( "click", function( event ) { oHandler.statistics.init(); }); }, open: function(dialog) { if ( "true" == localStorage.debugTime ) $( "#configModal" ).find( "input" ).eq(6).iCheck('check'); if ( true === oHandler.configuration.settings.newWin ) $( "#configModal" ).find( "input" ).eq(7).iCheck('check'); dialog.overlay.fadeIn('fast', function () { dialog.container.slideDown('fast', function () { dialog.data.fadeIn('fast'); }); }); }, close: function(dialog) { $( "#config-container" ).hide( "drop", { direction: "down" }, "fast", function() { $.simpleModal.close(); // must call this! }); }, show: function( s ) { var configButton = $( "#configModal" ).find( "input.configButton, button.configButton" ), enableButton = $( "#enable_button" ), disableButton = $( "#disable_button" ); // Initialize iCheck Radio/Checkbox fields for Configuration Modal configButton.iCheck({ checkboxClass: 'icheckbox_flat-orange', radioClass: 'iradio_flat-orange' }); // Tooltips if ( "true" == localStorage.toolTips ) { s.settings.configModal.find( 'li, button').qtip({ style: { classes: 'qtip-bootstrap', }, content: { title: function( event, api ) { if ( "button" == this[0].tagName.toLowerCase() ) return this.html(); return this.find( "label" ).html(); }, button: true }, position: { my: 'top left', at: 'bottom left', target: 'event', viewport: $(window) }, show: { solo: true, delay: 800, }, hide: { distance: 30 } }); } configButton.eq(0).on( "ifToggled", function( event ) { if ( this.checked ) s.settings.printField.val( true ); else s.settings.printField.val( false ); }); configButton.eq(1).on( "ifToggled", function( event ) { if ( this.checked ) { oHandler.showTooltips( true ); localStorage.toolTips = true; } else { if ( "true" == localStorage.toolTips ) { $( "#jTable" ).find( '.tooltip_set').qtip('destroy'); $( "#navigationBottom" ).find( '.tooltip_set').qtip('destroy'); $( "#navigationTop" ).find( '.tooltip_set').qtip('destroy'); $( "#configModal" ).find( 'li').qtip('destroy'); // Gritter Notification oHandler.gritter( "Tooltips Disabled", "", "fa-wheelchair" ); localStorage.toolTips = false; } } }); configButton.eq(2).on( "ifToggled", function( event ) { if ( this.checked ) s.hideHeader( false ); else s.hideHeader( true ); }); configButton.eq(3).on( "ifToggled", function( event ) { if ( this.checked ) oHandler.config.clearSelection = true; else oHandler.config.clearSelection = false; }); configButton.eq(4).on( "ifToggled", function( event ) { if ( this.checked ) oHandler.config.toggleGritter = true; else oHandler.config.toggleGritter = false; }); configButton.eq(5).on( "ifToggled", function( event ) { if ( this.checked ) s.settings.showOverlay = true; else s.settings.showOverlay = false; }); configButton.eq(6).on( "ifToggled", function( event ) { if ( this.checked ) localStorage.debugTime = true; else localStorage.debugTime = false; }); configButton.eq(7).on( "ifToggled", function( event ) { if ( this.checked ) s.settings.newWin = true; else s.settings.newWin = false; }); configButton.eq(8).on( "ifToggled", function( event ) { if ( this.checked ) s.settings.PHPMailer = true; else s.settings.PHPMailer = false; }); configButton.eq(9).on( "click", function( event ) { s.bindKey( { shortcutName: "jTable Refresh", shortcut: "refreshKey", func: '$( "#orderTable" ).jtable( "reload" )' } ); }); configButton.eq(10).on( "click", function( event ) { var content = '<div class="content" style="min-height: 50px;"><div class="form-control" style="border: none;box-shadow: 0 0;">Enter Function:</div><input class="form-control" type="text" id="new-function"></div>'; $.fn.tdialog({ type:"confirm", content:content, icon:"confirm", titleBar:false, confirmCallback:function() { var size = 0, key; for (key in keyShortcuts) { if (keyShortcuts.hasOwnProperty(key)) size++; } setTimeout( function(){ s.bindKey( { shortcutName: "jTable Custom Function", shortcut: $.trim( $( "#new-function" )[0].value ), func: $( "#new-function" )[0].value } ); },100); } }); }); configButton.eq(11).on( "click", function( event ) { $.fn.tdialog({ type:"confirm", content:"Remove all Keyboard Shortcuts?", icon:"confirm", titleBar:false, confirmCallback:function() { for ( var n in keyShortcuts ) { $( "body" ).off( "keyup." + keyShortcuts[ n ].key ); } localStorage.removeItem('keyShortcuts'); keyShortcuts = {}; } }); }); // Ajax Long Polling Buttons enableButton.on( "click", function( event ) { oHandler.messagesLongPolling.toggle( event ); oHandler.messagesLongPolling.start(); }); disableButton.on( "click", function( event ) { if ( false === polling ) return false; oHandler.messagesLongPolling.toggle( event ); }); $( "#context_menu" ).on( "ifToggled", function( event ) { $.saveCookie( $( this ) ); }); // Save any changes to Cookie configButton.on( "ifToggled", function( event ) { $.saveCookie( $( "#configModal" ) ); }); }, /* Hide Header *************************************************************************/ hideHeader: function( toggle ) { var message = ""; if ( true === toggle ) message = "Hide Header"; else message = "Show Header"; $( "#body_content" ).toggleClass( "toggleHeader" ); $( "#adminAppMenu" ).toggleClass( "toggleHeader" ); $( "#js-switch" ).click(); // Gritter Notification oHandler.gritter( message, "", "fa-header" ); }, /* Bind Keyboard Shortcut *************************************************************************/ bindKey: function( options ) { var s = this, content = '<div class="content" style="min-height: 50px;"><div class="form-control" style="border: none;box-shadow: 0 0;">Enter new Keyboard Shortcut for ' + options.shortcutName + ':</div><input class="form-control" type="text" id="newValue" maxlength="1"></div>', tdialog = $.fn.tdialog({ type:"confirm", content:content, icon:"confirm", titleBar:false, confirmCallback:function() { keyShortcuts[ options.shortcut ] = s.settings.key_code; localStorage.keyShortcuts = JSON.stringify(keyShortcuts); s.restoreKeys(); //$.fn.closeTdialog(); $( "#tdialog" ).remove(); } }); $.when( tdialog ).done(function( event ) { $( "#newValue" ).trigger( "focus" ); }); $( "#newValue" ).on( "keyup", function( event ) { // Remove old Event Handler if ( undefined !== keyShortcuts[ options.shortcut ] ) $( "body" ).off( "keyup." + keyShortcuts[ options.shortcut ].key ); // Settings for new Event Handler s.settings.key_code = { altKey: event.altKey, ctrlKey: event.ctrlKey, key: event.keyCode, shiftKey: event.shiftKey, action: options.func, }; }); // Gritter Notification //this.gritter( message, "", "fa-header" ); }, /* Bind Keyboard Shortcut *************************************************************************/ restoreKeys: function() { var f = {}, key = ""; for ( var n in keyShortcuts ) { if ( "" === keyShortcuts[ n ] ) return false; f[ n ] = new Function( keyShortcuts[ n ].action ); if ( ! keyShortcuts[ n ].action && "function" != typeof f ) return false; $( "body" ).on( "keyup." + keyShortcuts[ n ].key, function( event ) { event.stopImmediatePropagation(); for ( var key in keyShortcuts ) { if ( event.altKey !== keyShortcuts[ key ].altKey || event.ctrlKey !== keyShortcuts[ key ].ctrlKey || event.shiftKey !== keyShortcuts[ key ].shiftKey ) continue; if ( event.keyCode == keyShortcuts[ key ].key && 1 > $( ".edit_order_dialog:visible" ).length && 1 > $( "#tdialog" ).length && 1 > $( ".addProduct:visible" ).length && "TEXTAREA" != $("*:focus").prop( "tagName" ) ) { f[ key ](); break; } } }); } } }, /* Order Handler Statistics *************************************************************************/ statistics = { init: function() { var s = this, // orders_total = 0, // selectedRows = $( "#orderTable" ).jtable( "selectedRows" ), // numRows = selectedRows.length, order_handler_statistics = $( "#order_handler_statistics"); order_handler_statistics.simpleModal({ closeHTML: "<a href='#' title='Close' class='modal-close'>x</a>", close: true, persist: true, position: ["15%",], // minWidth: 1500, // minHeight: 600, overlayId: 'contact-overlay', overlayClose: true, containerId: 'statistics-container', onOpen: s.open, //onShow: s.show, onClose: s.close }, s); }, open: function(dialog, s) { dialog.overlay.fadeIn('fast', function () { dialog.container.slideDown('fast', function () { dialog.data.fadeIn('fast', function () { s.show(); }); }); }); }, close: function(dialog) { $( "#statistics-container" ).hide( "drop", { direction: "down" }, "fast", function() { $.simpleModal.close(); // must call this! }); }, show: function() { function groupByDate(data) { var sortedData, result, n, i; sortedData = {}; for(i in chartData) { if ( undefined === sortedData[ chartData[i]['date'] ] ) sortedData[ chartData[i]['date']] = {order_total: 0, products_purchased: 0}; sortedData[ chartData[i]['date'] ].date = chartData[i]['date']; sortedData[ chartData[i]['date'] ].order_total += chartData[i]['order_total']; sortedData[ chartData[i]['date'] ].products_purchased += chartData[i]['products_purchased']; } result = []; for(i in sortedData) { result.push( sortedData[i] ); } return result; } var s = this, orders_total = 0, // chartData = [], selectedRows = $( "#orderTable" ).jtable( "selectedRows" ), numRows = selectedRows.length, order_handler_statistics = $( "#order_handler_statistics"); chartData = []; for ( var i = 0; i < numRows; i++ ) { // Create UNIX Timestamp from Date var n = numRows - i - 1; var newDate = Date.parse( selectedRows.find( "td.date_purchased" )[ n ].innerHTML.replace( /\s/, "T" ) ); newDate = new Date(newDate); newDate = newDate.getFullYear() + "-" + ('0' + (newDate.getMonth() + 1)).slice(-2) + "-" + ('0' + newDate.getDate()).slice(-2) + " " + ('0' + newDate.getHours()).slice(-2) + ":00:00"; chartData.push({ date: new Date(newDate.replace( /\s/, "T" )), products_purchased: parseInt( selectedRows.find( "td.products_purchased" )[ n ].innerHTML, 10 ), order_total: parseFloat( selectedRows.find( "td.order_total" ).eq( i ).text() .replace( /[^0-9\,\.]+/g, "" ) .replace( /(,|\.)(?=[^.]*(,|\.))/, "" ) .replace( /\D/g, "." ) .replace( /\.(?=[^.]*\.)/, "" ) ), }); } chartData = groupByDate( chartData ); //var chartData = generateChartData(); chart = AmCharts.makeChart("chartdiv", { "type": "serial", "pathToImages": "includes/modules/order_handler/amcharts/images/", "categoryField": "date", "startDuration": 1, "dataDateFormat": "YYYY-MM-DD HH", "categoryAxis": { "minPeriod": "hh", "parseDates": true, }, "chartCursor": { "categoryBalloonDateFormat": "JJ:NN" }, "chartScrollbar": {}, "trendLines": [], "graphs": [ { "bullet": "round", "id": "AmGraph-1", "balloonText": "[[title]] is [[value]]", "title": "Order Total", "type": "smoothedLine", "valueAxis": "ValueAxis-1", "valueField": "order_total", }, { "bullet": "square", "id": "AmGraph-2", "balloonText": "[[value]] [[title]]", "title": "Products Purchased", "type": "smoothedLine", "minimum": 0, "valueAxis": "ValueAxis-2", "valueField": "products_purchased", } ], "guides": [], "valueAxes": [ { "id": "ValueAxis-1", "title": "Order Total", "autoGridCount": false, "lineColor": "#FF6600", "position": "left" }, { "id": "ValueAxis-2", "title": "Products Purchased", "lineColor": "#FCD202", "position": "right" } ], "allLabels": [], "balloon": {}, "legend": { "switchType": "v", "useGraphSettings": true, "valueAlign": "left" }, "titles": [ { "id": "Title-1", "size": 15, "text": "Order Handler Statistics" } ], "dataProvider": chartData } ); // Fix Chart on Dynamically created Pages chart.invalidateSize(); } }, /* SimpleModal - Mail Customer Modal Popup *************************************************************************/ contact = { message: null, init: function () { $( "body" ).on( "click", "a.mail_customer", function( event ) { event.preventDefault(); // load the contact form using ajax $.ajax({ url: this.href, //global: false, dataType: "html" }) .done(function( data ){ // create a modal dialog with the data $( data ).simpleModal({ closeHTML: "<a href='#' title='Close' class='modal-close'>x</a>", position: ["15%",], overlayId: 'contact-overlay', containerId: 'contact-container', onOpen: oHandler.contact.open, onShow: oHandler.contact.show, onClose: oHandler.contact.close }); // Initiate Tooltips $( "#simplemodal-data" ).find( ".contact-input" ).qtip({ style: { classes: 'qtip-rounded qtip-shadow' }, position: { target: 'mouse', // Track the mouse as the positioning target adjust: { x: 5, y: 5 } // Offset it slightly from under the mouse } }); }); }); }, open: function (dialog) { // dynamically determine height var h = 296; //var h = 445; if ($('#contact-subject').length) { h += 26; } if ($('#contact-cc').length) { h += 22; } var title = $('#contact-container .contact-title').html(); $('#contact-container .contact-title').html(ENTRY_CONTACT_LOADING); dialog.overlay.fadeIn(200, function () { dialog.container.fadeIn(200, function () { dialog.data.fadeIn(200, function () { $('#contact-container .contact-content').animate({ height: h }, function () { $('#contact-container .contact-title').html(title); $('#contact-container form').fadeIn(200, function () { $('#contact-container #contact-name').focus(); $('#contact-container .contact-cc').click(function () { var cc = $('#contact-container #contact-cc'); cc.is(':checked') ? cc.attr('checked', '') : cc.attr('checked', 'checked'); }); }); }); }); }); }); }, show: function (dialog) { $('#contact-container .contact-send').click(function (e) { e.preventDefault(); // validate form if (oHandler.contact.validate()) { var msg = $('#contact-container .contact-message'); msg.fadeOut(function () { msg.removeClass('contact-error').empty(); }); $('#contact-container .contact-title').html( ENTRY_CONTACT_SENDING ); $('#contact-container form').fadeOut(200); $('#contact-container .contact-content').animate({ height: '80px' }, function () { $('#contact-container .contact-loading').fadeIn(200, function () { var url = 'contact.php'; if ( true === oHandler.configuration.settings.PHPMailer ) url += "?php_mailer=1"; $.ajax({ url: url, data: $('#contact-container form').serialize() + '&action=send', type: 'post', cache: false, //global: false, dataType: 'html', success: function (data) { $('#contact-container .contact-loading').fadeOut(200, function () { $('#contact-container .contact-title').html( ENTRY_CONTACT_THANK_YOU ); msg.html(data).fadeIn(200); }); }, error: oHandler.contact.error }); }); }); } else { if ($('#contact-container .contact-message:visible').length > 0) { var msg = $('#contact-container .contact-message div'); msg.fadeOut(200, function () { msg.empty(); oHandler.contact.showError(); msg.fadeIn(200); }); } else { $('#contact-container .contact-message').animate({ height: '30px' }, oHandler.contact.showError); } } }); }, close: function (dialog) { $('#contact-container .contact-message').fadeOut(); $('#contact-container .contact-title').html( ENTRY_CONTACT_GOODBYE ); $('#contact-container form').fadeOut(200); $('#contact-container .contact-content').animate({ height: 40 }, function () { dialog.data.fadeOut(200, function () { dialog.container.fadeOut(200, function () { dialog.overlay.fadeOut(200, function () { $.simpleModal.close(); }); }); }); }); }, error: function (xhr) { $.simpleModal.close(); return xhr.statusText; }, validate: function () { oHandler.contact.message = ''; if (!$('#contact-container #contact-name').val()) { oHandler.contact.message += ENTRY_CONTACT_REQUIRED_NAME; } var email = $('#contact-container #contact-email').val(); if (!email) { oHandler.contact.message += ENTRY_CONTACT_REQUIRED_EMAIL; } else { if (!oHandler.contact.validateEmail(email)) { oHandler.contact.message += ENTRY_CONTACT_INVALID_EMAIL; } } if (!$('#contact-container #contact-message').val()) { oHandler.contact.message += ENTRY_CONTACT_REQUIRED_MESSAGE; } if (oHandler.contact.message.length > 0) { return false; } else { return true; } }, validateEmail: function (email) { var at = email.lastIndexOf("@"); // Make sure the at (@) sybmol exists and // it is not the first or last character if (at < 1 || (at + 1) === email.length) return false; // Make sure there aren't multiple periods together if (/(\.{2,})/.test(email)) return false; // Break up the local and domain portions var local = email.substring(0, at); var domain = email.substring(at + 1); // Check lengths if (local.length < 1 || local.length > 64 || domain.length < 4 || domain.length > 255) return false; // Make sure local and domain don't start with or end with a period if (/(^\.|\.$)/.test(local) || /(^\.|\.$)/.test(domain)) return false; // Check for quoted-string addresses // Since almost anything is allowed in a quoted-string address, // we're just going to let them go through if (!/^"(.+)"$/.test(local)) { // It's a dot-string address...check for valid characters if (!/^[-a-zA-Z0-9!#$%*\/?|^{}`~&'+=_\.]*$/.test(local)) return false; } // Make sure domain contains only valid characters and at least one period if (!/^[-a-zA-Z0-9\.]*$/.test(domain) || domain.indexOf(".") === -1) return false; return true; }, showError: function () { $('#contact-container .contact-message') .html($('<div class="contact-error"></div>').append(oHandler.contact.message)) .fadeIn(200); } }, /* Add new Field Dialog *************************************************************************/ dialogForm = { updateTips: function( t ) { tips .text( t ) .addClass( "ui-state-highlight" ); setTimeout( function() { tips.removeClass( "ui-state-highlight", 1500 ); }, 500 ); }, checkLength: function( o, n ) { o.removeClass( "ui-state-error" ); if ( o.val().length <= 0 ) { o.addClass( "ui-state-error" ); this.updateTips( "The " + n + " can not be empty." ); return false; } else { return true; } }, checkNumber: function( o, n ) { if ( isNaN( o.val() ) === true || o.val() === '' ) { o.addClass( "ui-state-error" ); this.updateTips( n ); return false; } else { return true; } }, init: function() { $( "body" ).on( "click", "span.createOrdersTotal", function( event ) { event.preventDefault(); var oID = $( this ).attr( "data-id" ), jtableDataRow = $( "tr.jtable-data-row[data-record-key=" + oID + "]" ).eq( 0 ).next(); // Initiate Create new field Dialog $( "#new_total_oID" ).val( oID ); $( "#dialog-form" ).dialog( "open" ); }); // Initiate Create new field Dialog oHandler.dialogForm.dialog(); }, dialog: function() { var s = this, dialog = $( "#dialog-form" ), cID = "&cID=" + $.urlParam( "cID" ), title = dialog.find( "#title" ), value = dialog.find( "#value" ), allFields = $( [] ).add( title ).add( value ), tips = dialog.find( "p.validateTips" ); dialog.dialog( { autoOpen: false, appendTo: "body", height: "auto", width: 380, modal: oHandler.configuration.settings.showOverlay, buttons: { "Add a field": function() { var bValid = true, oID = $( "#new_total_oID" ).val(), jtableDataRow = $( "tr.jtable-data-row[data-record-key=" + oID + "]" ).eq( 0 ).next(); allFields.removeClass( "ui-state-error" ); bValid = bValid && s.checkLength( title, "Title" ); bValid = bValid && s.checkNumber( value, "Value must contain a number." ); if ( bValid ) { var form = $( this ).find( "form" ), url = "get_table.php?oID=" + oID + "&" + $( form ).serialize() + cID; if ( edit_order === true ) url += "&edit_order=1"; var jqxhr = $.ajax( { type: 'GET', url: decodeURIComponent( url ), async: true, global: ( true === edit_order ? false : true ), dataType: 'json' } ); jqxhr.done( function( payload ) { if ( payload.Result == 'OK' ) { // Send Success Message oHandler.gritter( "Success", payload.Message, "fa-plus-square-o" ); // Find New Order Totals Table var products_total_html = $.parseJSON( payload.products_total_html ); // If on 'Edit Order' Page if ( edit_order === true ) { products_total_html = $( products_total_html ).find( "#productTotals" ).html(); $( "#productTotals" ).html( products_total_html ); } else { // jTable Mode // Order Total Area products_total_html = $( products_total_html ) .find( "#ordersTotalField" ); jtableDataRow .find( "#ordersTotalField" ) .html( products_total_html ); // Replace Order Total Value var order_total = jtableDataRow.prev().find( "td.order_total" )[0], newPrice = $( products_total_html ).find( "#ot_total_value" )[0].innerHTML; order_total.innerHTML = "<strong>" + newPrice + "</strong>"; } return false; } else if ( payload.Result == 'ERROR' ) { // Send Error Message oHandler.gritter( "Error", payload.Message, "fa-warning" ); } } ); $( this ).dialog( "close" ); $( this ).closest( "div.ui-dialog" ).hide(); } }, Cancel: function() { $( this ).dialog( "close" ); $( this ).closest( "div.ui-dialog" ).hide(); } }, close: function() { allFields.val( "" ).removeClass( "ui-state-error" ); } } ); } }, /* Display Batch Delete Orders modal *************************************************************************/ ajaxOrderDelete = function() { $.ajax({ type: "POST", url: encodeURI($( "#batch_orders" ).attr( "action" )), data: $( "#batch_orders" ).serialize() + "&batch_delete_x=1", //global: false, dataType: "html" }) .done(function( data ) { $( "#ajaxOrderDelete" ).show().html( data ); $( "#myModal" ).appendTo("body").modal( "show" ); }); }, /* Batch Delete Orders *************************************************************************/ ajaxDelete = function() { var self = this, restock = $( "input[name=restock]" ).prop( "checked" ), selectedRows = $("#orderTable").jtable("selectedRows"), settings = { message: jTableOptions.deleteProggress, progress: 0, total: selectedRows.length }; jqxhr = $.ajax({ xhr: function() { var xhr = new window.XMLHttpRequest(); oHandler.showBusy.setup( settings ); xhr.addEventListener("progress", function( event ) { oHandler.showBusy.update( event.loaded ); // if (evt.lengthComputable) // { // oHandler.showBusy.update( evt.loaded ); // } }, false); return xhr; }, type: "POST", cache: false, url: "get_table.php?action=delete_confirm", data: $( "#formDelete" ).serialize() + ( true === restock ? "&restock=1" : ""), }); jqxhr.done(function( payload ) { if( 'number' === typeof payload ) { var countOrdersUpdated = payload.toString().length; self.gritter( "Success", countOrdersUpdated + " Orders Deleted.", "fa-eraser" ); } selectedRows.each(function () { var record = $(this).data('record'); $('#orderTable').jtable('deleteRecord', { clientOnly: true, key: record.orders_id }); }); }) .always(function() { $( "#ajaxOrderDelete" ).html( "" ); }); }, /* Replace Content in ID replace_with *************************************************************************/ ajaxLink = function( link, replace_with, global ) { // Test link if ( "undefined" === typeof link ) return; // Replace URL history.pushState( null, null, link ); // Send Request $.ajax({ type: "GET", url: encodeURI( link ), async: true, global: ( typeof( global ) === "undefined" ? true : false ), }) .done(function( data ) { // JSON Response equals Error if ( typeof data == "object" ) return gritter( "Error", data.Message ); // Don't replace element with new Data if ( false === replace_with ) return; // "Edit Order" page requires different filter var replacement = ( true === edit_order ) ? $( data ).find( "#" + replace_with ) : $( data ).closest( "#" + replace_with ), pageHeading = $( data ).filter( "#pageHeading" ); // If nothing found, try again with different filter if ( 0 === replacement.length ) replacement = $( data ).closest( "#" + replace_with ); // Enable any Comments on Element //$( replacement ).find( "span.comments, .tooltip_set" ).tooltip( "toggle" ).tooltip( "hide" ); // Replace Element with new Element from Response $( "#" + replace_with ).replaceWith( replacement ); // Replace Page Heading if defined if ( "undefined" !== typeof pageHeading ) $( "#pageHeading" ).replaceWith( pageHeading ); }); return; }, /* Open Ajax Dialog *************************************************************************/ ajaxDialog = function( data_link ) { var $dialog = $('<div id="ajax_cart_dialog"></div>') .load(data_link, function(){ $('#overlay').fadeOut('slow', function() { $('#overlay').remove(); }); }) .dialog({ resizable: true, modal: oHandler.configuration.settings.showOverlay, draggable: true, autoOpen: false, minWidth: 500, dialogClass: "ajax_cart", closeOnEscape: true, show: {effect: 'fade', duration: 250}, hide: {effect: 'drop', direction: "down", duration: 200}, open: function(event, ui) { //here we can apply unique styling $(this).parent() .css('top', '15%'); $(this).parents("div.ui-dialog:first") .find("div.ui-dialog-titlebar").remove(); $(this).parents("div.ui-dialog") .css("background", '#FFF'); $(this).parents("div.ui-dialog:first").find("div.ui-dialog-content") .css("padding", 0) .css("overflow", 'hidden'); }, close: function( event, ui ) { var checkout_page = $('form[name=checkout_confirmation]').length, url = $( location ).attr( "href" ).split("/"), filename = url[url.length - 1], addProduct = $( "#add-Product" ), orderTable = $( "#orderTable" ); addProduct.insertBefore( orderTable ); filename = filename.split( '?' )[0]; if ( filename == 'checkout_confirmation.php' || filename == 'shopping_cart.php' || checkout_page !== 0) { $('form[name=boxcart_quantity]').submit(); } return $('#ajax_cart_dialog').dialog( "destroy" ).remove(); } }).css('overflow', 'auto').dialog("open"); }, /* Capitalize String *************************************************************************/ capitalizeString = function( element ) { string = element.val(); var names = element[0].value.toLowerCase().match(/([^-\s]+[-]{0,1})/g).slice(), name = ''; for ( var i = 0, l = names.length; i < l; i++ ) { name += names[ i ].charAt(0).toUpperCase() + names[ i ].slice(1); if ( /[^-]$/.test( name ) && i < l - 1 ) name += " "; } element.val( name ); return name; }, /* Format Phone Number * Requires Regex Setup *************************************************************************/ formatPhone = function( element ) { number = element.val(); /*number = number.replace(/\D/g, ''); number = number.replace(/^$/, '$1'); if ( /^$/.test( number ) ) { number = number.replace( /^$/, '' ); } else { number = number.replace( /^$/, '' ); }*/ element.val( number ); return number; }, /* Return tDialog *************************************************************************/ tDialog = function( settings ) { var s = this, tdialog = $.fn.tdialog({ type:"prompt", showOverlay: oHandler.configuration.settings.showOverlay, title:'Enter new value', effect:'css3', css3EffectIn:'', css3EffectOut:'bench-out', content: (typeof settings.content != "undefined" ? settings.content : "<h5>Enter new value</h5>"), promptCallback:function(){ var newValue = $("#newValue"), newValueVal = newValue.val(); if ((newValueVal === null) || (newValueVal === '')) return false; if ( settings.capitalize.id == 'customers_telephone' && settings.capitalize !== false ) { // Formatting Phone Number // Requires Regex Setup settings.formattedValue = oHandler.formatPhone( newValue ); $( settings.capitalize ).html( settings.formattedValue ); } else if ( "ajaxLinkProduct" != settings.capitalize.className && "customers_email_address" != settings.capitalize.id && "payment_method" != settings.capitalize.id && false !== settings.capitalize ) { settings.formattedValue = oHandler.capitalizeString( newValue ); $( settings.capitalize ).html( settings.formattedValue ); } else { settings.formattedValue = newValueVal; if ( "ajaxLink" == settings.capitalize.className ) $( settings.capitalize ).html( settings.formattedValue ); } // Change Customers Name on Row if ( "customers_name" == $( settings.capitalize )[0].getAttribute( "data-field" ) ) { $( settings.capitalize ) .closest( ".jtable-child-row" ) .prev().find( ".customers_name" ) .html( settings.formattedValue ); } // Check if Options Field if ( settings.extended === true ) { if ( ( newValueVal !== null ) && ( newValueVal !== '' ) ) { setTimeout( function() { var tdialog = $.fn.tdialog({ type:"prompt", content:"Price:", title:"Confirm", icon:"confirm", showOverlay: oHandler.configuration.settings.showOverlay, effect:'css3', css3EffectIn:'', css3EffectOut:'bench-out', promptCallback:function(){ newValueVal += "&option_price=" + parseFloat( $( "#newValue" ).val() ); settings.url += "&new_value=" + newValueVal; if ( edit_order === true ) settings.url += "&edit_order=1"; var jqxhr = $.ajax({ type: 'GET', url: encodeURI( settings.url ), async: true, //global: false, dataType: 'json' }); s.tDialogRequest( jqxhr, settings ); } }); $.when( tdialog ).done(function() { var value_pred = settings.capitalize.attributes['data-value-pred'].value; $( "#newValue" ).attr( "placeholder", value_pred ).val( value_pred ).trigger( "focus" ); }); }, 100); return false; } } settings.url += "&new_value=" + settings.formattedValue; if ( edit_order === true ) settings.url += "&edit_order=1"; var jqxhr = $.ajax({ type: 'GET', url: encodeURI( settings.url ), async: true, //global: false, dataType: 'json' }); s.tDialogRequest( jqxhr, settings ); } }); $.when( tdialog ).done(function() { $( "#newValue" ).attr( "placeholder", settings.pred ).val( settings.pred ).trigger( "focus" ); }); }, /* Handle tDialog Response *************************************************************************/ tDialogRequest = function( jqxhr, settings ) { var s = this; jqxhr.done(function( payload ) { if( 'OK' == payload.Result ) { // Send Success Message s.gritter( "Success", payload.Message, "fa-thumbs-o-up" ); if ( settings.refreshTotals === true ) { // Find New Products Table var products_total_html = $.parseJSON( payload.products_total_html ); // If on 'Edit Order' Page if ( edit_order === true ) { products_total_html = $( products_total_html ).find( "#productTotals" ).html(); return $( "#productTotals" ).html( products_total_html ); } else { // jTable Mode var dataField = settings.capitalize.attributes['data-field'].value, jtableDataRow = $( "tr.jtable-data-row[data-record-key=" + settings.orderID + "]" ).eq( 0 ).next(); if ( "products_name" !== dataField ) { // Replace Products & Order Total Area jtableDataRow .find( "tr.jtable-child-row" ) .children( "td" ) .html( $.parseJSON( payload.products_total_html ) ) .find( "#tdb-update" ).button({ icons:{ primary:"ui-icon-disk" } }).addClass( "ui-priority-primary" ).parent().removeClass( "tdbLink" ); jtableDataRow .find('#change_order_status').multiselect({ buttonClass: 'btn btn-xs btn-info' }); var products_purchased = 0, productsRows = $( products_total_html ).closest( "#productsTable" ).find( "tr.dataTableRow" ); // Replace Orders total Product Quantity Field productsRows.each(function() { products_purchased += parseInt( $( this ).find( "span" )[1].attributes['data-pred'].value, 10 ); }); jtableDataRow.prev().find( "td.products_purchased" ).html( products_purchased ); // Replace Order Total Value var order_total = jtableDataRow.prev().find( "td.order_total" )[0], newPrice = $( products_total_html ).find( "#ot_total_value" )[0].innerHTML; order_total.innerHTML = "<strong>" + newPrice + "</strong>"; } else { $( settings.capitalize ).html( settings.formattedValue ); $( settings.capitalize ).attr( "data-pred", settings.formattedValue ); return false; } return false; } } } else if( payload.Result == 'ERROR' ) { // Send Error Message s.gritter( "Error", payload.Message, "fa-thumbs-o-down" ); } }); }, /* Return json_message with jQuery Gritter *************************************************************************/ json_message = function( jqxhr, settings ) { var self = this, config = { Message: "", Title: "Success", }; $.extend( config, settings ); jqxhr.done(function( payload ) { $.extend( config, payload ); if( 'OK' == config.Result ) { self.gritter( config.Title, config.Message ); } else if( "ERROR" == config.Result, "fa-thumbs-o-up" ) { self.gritter( "Error", config.Message, "fa-thumbs-o-down" ); } }); }, /* Update Shipping Method *************************************************************************/ updateShippingMethod = function( e, settings ) { var jqxhr = $.ajax({ type: 'GET', url: encodeURI( settings.url_title ), async: true, dataType: 'json' }); var s = this; jqxhr.done(function( payload ) { if( 'OK' == payload.Result ) { // Send Success Message s.gritter( "Success", payload.Message, "fa-thumbs-o-up" ); if ( settings.refreshTotals === true ) { ______________________________________________________ * End Part 5 * ______________________________________________________ Quote osC OpenSSL Encryption with jCryptionSupport Forum jQuery/Ajax Advanced Statistics 2.3Support Forum jQuery/Ajax Advanced Order Handler 2.3.3Support ForumjQuery/Ajax Advanced Caching System 2.3.3Support ForumjQuery/Ajax Fast checkout/Shopping Cart/Login/Create Account 2.3.3Support ForumjQuery/Ajax Shopping Cart 2.3.3Support ForumjQuery/Ajax Dynamic Checkout 2.3.3Support ForumjQuery/Ajax Mini Cart for osCommerce 2.3.3Support ForumjQuery Cycle What's New InfoboxAuto Out Of Stock CSS Image OverlayjQuery-UI Autocomplete Product Search with Links & MySQLi support for osCommerce 2.X Link to comment Share on other sites
Recommended Posts