⚠ In case you've missed it we have migrated to our new website, with a brand new forum. For more details about the migration you can read our blog post for website migration. This forum is read-only and soon will be archived. ⚠


DrPaul

Member Since 08 Dec 2013
Offline Last Active Dec 09 2015 06:20 PM
-----

#13454 Bug in the search

Posted DrPaul on 01 December 2015 - 09:59 PM

Oh dear, this one's a bit of a deal-breaker isn't it?

 

The problem goes all the way down to the CodeIgniter query builder class and the way in which GC is using it.

 

GC is calling ci->where() when you have a where() defined.

 

Do a search from that list, and GC makes repeated calls to ci->or_like() which CodeIgniter just chains together.

 

Result? Search in GC is completely broken if you use ->where()

 

This looks like a structural problem in GC and I can't see it being fixed any time soon :-(




#11462 Timepicker Implementation

Posted DrPaul on 10 August 2014 - 02:46 PM

Here's my translation and update of the French web page above (all the code was appearing as HTML entities, so it's far from a cut-and-paste exercise):

 

Before you start making changes to the library, you must first make sure you have a version of Grocery Crud containing the jQuery library with the TimePicker. If it does not, you must either update Grocery Crud or manually add the library in the installation directory of the library.

 

The first thing is to set up the file jquery-ui-timepicker-addon.config.js in the config directory of your installation of Grocery Crud (usually: / assets / grocery_crud / js / jquery_plugins / config). Several options are available to configure the TimePicker. To explore them, we advise you to refer to the official documentation.

Here is an example of the setup I am using:

$(function(){
    $('.datetime-input').datetimepicker({
    	timeFormat: 'hh:mm:ss',
	dateFormat: js_date_format,
	showButtonPanel: true,
	changeMonth: true,
	changeYear: true
    });
    
	$('.datetime-input-clear').button();
	
	$('.datetime-input-clear').click(function(){
		$(this).parent().find('.datetime-input').val("");
		return false;
	});	

	$('.time-input').timepicker({
		stepMinute: 5,
		timeFormat: 'HH:mm',
		hourMin: 0,
		hourMax: 23,
		addSliderAccess: true,
		sliderAccessArgs: { touchonly: false }
	});
	
	$('.time-input-clear').button();
	
	$('.time-input-clear').click(function(){
		$(this).parent().find('.time-input').val("");
		return false;
	});
	
});

Now, proceed to the modification of the core GC library code. Open the library file Grocery_CRUD.php in the directory of your installation (Usually in: / application / libraries / ). Edit the file and locate the function get_field_input() (around line 225 in the latest version of GC). Then add the following line inside the definition of variable $types_array :

'time',

Then search for the definition of function change_list_value() (around line 255 in the latest version of the file) and in the main function loop, add the following lines of code:

case 'time':
	if(!empty($value) && $value != '00:00:00') {
		list($hours,$minutes) = explode(":",substr($value,0));
		$value = $hours.':'.$minutes;
	} else {
		$value = '';
	}
break;

The next thing to do is to add a new function later on in Grocery_CRUD.php. Search for the function get_datetime_input() (around line 2222 of the latest version of the file) and add the following function definition nearby:

protected function get_time_input($field_info,$value) {
	$this->set_css($this->default_css_path.'/ui/simple/'.grocery_CRUD::JQUERY_UI_CSS);
	$this->set_css($this->default_css_path.'/jquery_plugins/jquery.ui.datetime.css');
	$this->set_css($this->default_css_path.'/jquery_plugins/jquery-ui-timepicker-addon.css');
	$this->set_js_lib($this->default_javascript_path.'/jquery_plugins/ui/'.grocery_CRUD::JQUERY_UI_JS);
	$this->set_js_lib($this->default_javascript_path.'/jquery_plugins/jquery-ui-timepicker-addon.js');
		
	if($this->language !== 'english') {
		include($this->default_config_path.'/language_alias.php');
			
		if(array_key_exists($this->language, $language_alias)) {
			$i18n_date_js_file = $this->default_javascript_path.'/jquery_plugins/ui/i18n/datepicker/jquery.ui.datepicker-'.$language_alias[$this->language].'.js';
				
			if(file_exists($i18n_date_js_file)) {
				$this->set_js_lib($i18n_date_js_file);
			}
				
			$i18n_datetime_js_file = $this->default_javascript_path.'/jquery_plugins/ui/i18n/timepicker/jquery-ui-timepicker-'.$language_alias[$this->language].'.js';
				
			if(file_exists($i18n_datetime_js_file)){
				$this->set_js_lib($i18n_datetime_js_file);
			}
				
		}
			
	}
		
	$this->set_js_config($this->default_javascript_path.'/jquery_plugins/config/jquery-ui-timepicker-addon.config.js');
		
	if(!empty($value) && $value != '00:00:00') {
		list($hours,$minutes) = explode(":",substr($value,0,6));
		$datetime = $hours.':'.$minutes;
	} else {
		$datetime = '';
	}
		
	$input = "<input id='field-{$field_info->name}' name='{$field_info->name}' type='text' value='$datetime' maxlength='5' class='time-input' /> <a class='time-input-clear' tabindex='-1'>".$this->l('form_button_clear')."</a> (hh:mm)";
	return $input;
}

And that's it, now you just need to set the field type in your controller code where necessary:

$crud->field_type('field_name','time');



#11402 Multiple parallel edits using flexigrid

Posted DrPaul on 24 July 2014 - 02:10 PM

I've found GC an excellent framework for building a number of systems, and after producing 3 or 4 of them, there are some user requests which seem to be common across a range of applications. The biggest of these for me was a request to be able to edit more than one table row at a time - at the "bottom" of a typical database hierarchy, people often end up wanting to edit a small group of related rows at the same time.

 

In a "standard" GC implementation, you render a list view of the different rows, then "dip in" to edit one, "back out" to the list to select another, then edit that and so on. That has been a big usability issue for a couple of clients.

 

I had thought that I would need to break out into some custom code to achieve this, but finally worked out how to achieve it completely within GC - no mods required. In this specific instance, I'm modelling an event management scenario - where a given event will have an arbitrary number of staff positions, and each staff position will have a separate booking for each day of the event. So from the "staff position" list view we want to be able to edit every daily booking for a given position on a single edit screen.

 

You will need to create two controllers and two views - one pair will be used to provide the outer view, the other will provide the content of the inner multiple edit views.

 

In the outer view you will need some code like this, where I read in the primary keys for the bookings for a given position primary key (passed into the view in the controller code as detailed elsewhere):

 

  $bookings = get_pos_bookings_as_string($pwkdata['pid']);
  $book_array = array();
  $book_array = explode(',', $bookings);
  $iframes = '<table><tr>';
  
  foreach($book_array as $bid) {
  $iframes .= '<td><iframe src="'.site_url('/booking/bookings_multi_item/edit/'.$bid).'" width="560" height="1" name="frame_'.$bid.'" id="frame_'.$bid.'" scrolling="auto" frameborder="1"></iframe></td>';
  }
  
  $iframes .= '</tr></table>';
 

 

(I set the iframe height to 1 as I resize it dynamically later on in the code)

 

Then later in the outer view template you just replace echo $output with echo $iframes and that part is done. For a given position id you will get an edit screen with however many iframes are needed for every booking related to that position. Now we just need to fill the iframes...

 

The key code for the inner controller is as follows, based around the core $crud->render() call:

 

$crud->unset_back_to_list();
        $output = $crud->render();
$state = $crud->getState();
 
if($state == 'edit') {
    $state_info = $crud->getStateInfo();
        $primary_key = $state_info->primary_key;
    } else {
        $primary_key = 0;
    }
$pwkdata = array();
$pwkdata['bid'] = $primary_key;
$output->pwkdata = $pwkdata;
 
Unset back-to-list, we don't want that within an iframe. I've also included how I pass the booking primary key into the inner view from the controller - I use this for some JavaScript trickery later on.

 

All that is left is the inner view template, used within each iframe. This is essentially an "empty" template - we don't want any of the outer template appearing more than once. Here is the entire body of my inner template (you keep all of the stuff in the head, that's where all the jQuery trickery resides):

 

<body>
    <div id="fairway_empty">
       <?php echo $output; ?>
    </div>
</body>
 

An entry for the div id in flexigrid.css sorts out odds and ends like the top margin.

 

The JavaScript trickery with that primary key? A combination of JS in both inner and outer views (constructed via PHP) means that all of the iframes scroll simultaneously when any one of them is scrolled.

 

If any of this is of interest to others, I'm happy to try and flesh it out further.