⚠ 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 is an archived forum. ⚠

  •     

profile picture

(Large) Changes to allow for 'Read' mode in GC



steveoc
  • profile picture
  • Member

Posted 04 January 2012 - 04:52 AM

Here is a rather large patch that adds 'Read' record functionality to GC, along with a few other things, following on from this discussion :
http://www.grocerycr...data-read-only/

Just posting it here for convenience for the meantime to see if it is of any use to other developers, and to get some feedback / peer review on the concept.

A number of things mixed up in this patch :[list]
[*]This automatically adds a view icon to each record (next to the edit and delete icons).
[*]Click on the view icon brings up a read-only view of the data for display purposes.
[*]1-n relation fields on a view form display the related data from the related table (as it appears in the drop down list), rather than the key field.
[*]File upload fields are displayed as references to images (In my case, I assume that file uploads are images only ... not necessarily true for all upload fields though, so this needs work)
[*]Fields that contain HTML code allow you to 'attach' all sorts of neat things to database records - I am using it to embed youtube vids against database records for example. This is highly insecure, so may need modification if you intend using this on a public application.
[*]Added a layer of security, so that individual records in a table can be marked as not editable (or delete-able) ... which is determined via a new callback_can_edit() function that is called on each row of data in the list. The callback function receives the primary key value as the first parameter.
[*]Added a new 'view' to the flexigrid theme to layout display only records. Need to do the same with datatables. Laziness on my part !
[*]Added a new function $crud->is_link($fieldname) ... which tells the view form that the data in $fieldname should be displayed as a HTML link. This is a bit of a crude hack, just for my benefit ... I will remove this and do it properly in the next update, as it is not the best coding practice around.
[/list]
Here is the patch, across several files :


diff --git a/application/libraries/grocery_crud.php b/application/libraries/grocery_crud.php
index 56ef943..566c275 100644
--- a/application/libraries/grocery_crud.php
+++ b/application/libraries/grocery_crud.php
@@ -210,7 +210,42 @@ class grocery_Field_Types

return $field_info;
}
+
+ protected function get_field_display($field_info, $value = null)
+ {
+ $real_type = $field_info->crud_type;
+ switch ($real_type) {
+ case 'relation':
+ $field_info->input = $this->get_relation_display($field_info,$value);
+ break;
+
+ case 'upload_file':
+ $path = $field_info->extras->upload_path;
+ $field_info->input = "<a href=/$path/$value target=image><img src=/$path/$value width=400></a>";
+ break;
+
+ default:
+ if ($this->get_is_link($field_info)) {
+ $field_info->input = "<a href=\"$value\" target=\"links\">$value</a>";
+ } else {
+ $field_info->input = "$value";
+ }
+ break;
+ }
+
+ return $field_info;
+ }
+
+ protected function get_is_link($field_info)
+ {
+ if (isset($this->link_fields[$field_info->name])) {
+ return $this->link_fields[$field_info->name];
+ }
+ return false;
+
+ }

+
protected function change_list_value($field_info, $value = null)
{
$real_type = $field_info->crud_type;
@@ -1086,8 +1121,9 @@ class grocery_Layout extends grocery_Model_Driver
$data->add_url = $this->getAddUrl();
$data->edit_url = $this->getEditUrl();
$data->delete_url = $this->getDeleteUrl();
- $data->ajax_list_url = $this->getAjaxListUrl();
- $data->ajax_list_info_url = $this->getAjaxListInfoUrl();
+ $data->view_url = $this->getViewUrl();
+ $data->ajax_list_url = $this->getAjaxListUrl();
+ $data->ajax_list_info_url = $this->getAjaxListInfoUrl();
$data->actions = $this->actions;
$data->unique_hash = $this->get_method_hash();

@@ -1103,8 +1139,18 @@ class grocery_Layout extends grocery_Model_Driver

foreach($data->list as $num_row => $row)
{
- $data->list[$num_row]->edit_url = $data->edit_url.'/'.$row->{$data->primary_key};
- $data->list[$num_row]->delete_url = $data->delete_url.'/'.$row->{$data->primary_key};
+ $can_edit = true;
+ if (isset($this->callback_can_edit)) {
+ $can_edit = call_user_func($this->callback_can_edit,$row->{$data->primary_key});
+ }
+ if ($can_edit) {
+ $data->list[$num_row]->edit_url = $data->edit_url.'/'.$row->{$data->primary_key};
+ $data->list[$num_row]->delete_url = $data->delete_url.'/'.$row->{$data->primary_key};
+ } else {
+ $data->list[$num_row]->edit_url = null;
+ $data->list[$num_row]->delete_url = null;
+ }
+ $data->list[$num_row]->view_url = $data->view_url.'/'.$row->{$data->primary_key};
}

if(!$ajax)
@@ -1235,7 +1281,29 @@ class grocery_Layout extends grocery_Model_Driver

$this->_theme_view('edit.php',$data);
}
+
+ protected function showViewForm($state_info)
+ {
+ $this->set_js('assets/grocery_crud/themes/datatables/js/jquery-1.6.2.min.js');
+
+ $data = $this->get_common_data();
+ $data->types = $this->get_field_types();
+
+ $data->field_values = $this->get_edit_values($state_info->primary_key);
+
+ $data->add_url = $this->getAddUrl();
+
+ $data->list_url = $this->getListUrl();
+ $data->input_fields = $this->get_view_display_fields($data->field_values);
+
+ $data->fields = $this->get_edit_fields();
+
+ $data->validation_url = $this->getValidationUpdateUrl();
+
+ $this->_theme_view('view.php',$data);
+ }

+
protected function delete_layout($delete_result = true)
{
if($delete_result === false)
@@ -1491,6 +1559,22 @@ class grocery_Layout extends grocery_Model_Driver
$input .= "</select>";
return $input;
}
+
+ protected function get_relation_display($field_info,$value)
+ {
+ if (empty($value)) {
+ return '';
+ }
+ $options_array = $this->get_relation_array($field_info->extras);
+ foreach($options_array as $option_value => $option)
+ {
+ if ($value == $option_value) {
+ return $option;
+ }
+ }
+
+ return "Unknown - $value";
+ }

protected function get_relation_n_n_input($field_info_type, $selected_values)
{
@@ -1648,7 +1732,51 @@ class grocery_Layout extends grocery_Model_Driver

return $input_fields;
}
+
+ protected function get_view_display_fields($field_values = null)
+ {
+ $fields = $this->get_edit_fields();
+ $types = $this->get_field_types();
+
+ $input_fields = array();
+
+ foreach($fields as $field_num => $field)
+ {
+ $field_info = $types[$field->field_name];
+
+ $field_value = !empty($field_values) && isset($field_values->{$field->field_name}) ? $field_values->{$field->field_name} : null;
+ //if(!isset($this->callback_edit_field[$field->field_name]))
+ //{
+ $field_input = $this->get_field_display($field_info, $field_value);
+ //}
+ //else
+ //{
+ //$primary_key = $this->getStateInfo()->primary_key;
+ //$field_input = $field_info;
+ //$field_input->input = call_user_func($this->callback_edit_field[$field->field_name], $field_value, $primary_key);
+ //}
+
+ switch ($field_info->crud_type) {
+ case 'invisible':
+ unset($this->edit_fields[$field_num]);
+ unset($fields[$field_num]);
+ continue;
+ break;
+ case 'hidden':
+ $this->edit_hidden_fields[] = $field_input;
+ unset($this->edit_fields[$field_num]);
+ unset($fields[$field_num]);
+ continue;
+ break;
+ }
+
+ $input_fields[$field->field_name] = $field_input;
+ }
+
+ return $input_fields;
+ }

+
protected function setThemeBasics()
{
$this->theme_path = $this->default_theme_path;
@@ -1756,7 +1884,8 @@ class grocery_States extends grocery_Layout
9 => 'insert_validation',
10 => 'update_validation',
11 => 'upload_file',
- 12 => 'delete_file'
+ 12 => 'delete_file',
+ 13 => 'view'
);

protected function getStateCode()
@@ -1894,6 +2023,14 @@ class grocery_States extends grocery_Layout
else
return $this->state_url('delete/'.$state_info->primary_key);
}
+
+ protected function getViewUrl($state_info = null)
+ {
+ if(empty($state_info))
+ return $this->state_url('view');
+ else
+ return $this->state_url('view/'.$state_info->primary_key);
+ }

protected function getUploadUrl($field_name)
{
@@ -1922,6 +2059,7 @@ class grocery_States extends grocery_Layout
break;

case 3:
+ case 13:
if($first_parameter != null)
{
$state_info = (object)array('primary_key' => $first_parameter);
@@ -2086,6 +2224,7 @@ class grocery_CRUD extends grocery_States
protected $required_fields = array();
protected $unset_columns = null;
protected $validation_rules = array();
+ protected $link_fields = array();
protected $relation = array();
protected $relation_n_n = array();
protected $upload_fields = array();
@@ -2111,6 +2250,7 @@ class grocery_CRUD extends grocery_States
protected $callback_before_delete = null;
protected $callback_after_delete = null;
protected $callback_escape_delete = null;
+ protected $callback_can_edit = null;
protected $callback_column = array();
protected $callback_add_field = array();
protected $callback_edit_field = array();
@@ -2175,6 +2315,24 @@ class grocery_CRUD extends grocery_States
}

/**
+ * Set Is This Field a Link ?
+ *
+ * Important note: If the $field is an array then no automated crud fields will take apart
+ *
+ * @access public
+ * @param mixed
+ * @param string
+ * @return void
+ */
+
+ function is_link($field)
+ {
+ if (is_string($field)) {
+ $this->link_fields[$field] = true;
+ }
+ }
+
+ /**
*
* Changes the default field type
* @param string $field
@@ -2616,7 +2774,7 @@ class grocery_CRUD extends grocery_States
}
return $this->edit_fields;
}
-
+
public function order_by($order_by, $direction = '')
{
if($direction == '')
@@ -2706,6 +2864,26 @@ class grocery_CRUD extends grocery_States
$this->showAddForm();

break;
+
+ case 13://view
+ if($this->unset_edit)
+ {
+ throw new Exception('This user is not allowed to do this operation', 14);
+ die();
+ }
+
+ $this->set_basic_db_table($this->get_table());
+ if($this->theme === null)
+ $this->set_theme($this->default_theme);
+ $this->setThemeBasics();
+
+ $this->set_basic_Layout();
+
+ $state_info = $this->getStateInfo();
+
+ $this->showViewForm($state_info);
+
+ break;

case 3://edit
if($this->unset_edit)
@@ -2835,6 +3013,8 @@ class grocery_CRUD extends grocery_States

$this->delete_file_layout($delete_file_result);
break;
+
+

}

@@ -2859,6 +3039,16 @@ class grocery_CRUD extends grocery_States
{
$this->callback_before_insert = $callback;
}
+
+ /**
+ *
+ * Enter description here ...
+ */
+ public function callback_can_edit($callback = null)
+ {
+ $this->callback_can_edit = $callback;
+ }
+
/**
*
@@ -3157,9 +3347,9 @@ class grocery_CRUD extends grocery_States
* @param string $related_table
* @param string $related_title_field
*/
- public function set_relation($field_name , $related_table, $related_title_field)
+ public function set_relation($field_name , $related_table, $related_title_field, $link=null)
{
- $this->relation[$field_name] = array($field_name, $related_table,$related_title_field);
+ $this->relation[$field_name] = array($field_name, $related_table,$related_title_field,$link);
return $this;
}

@@ -4566,4 +4756,4 @@ class grocery_Form_validation {
}

}
-// END Form Validation Class
\ No newline at end of file
+// END Form Validation Class
diff --git a/assets/grocery_crud/themes/flexigrid/views/list.php b/assets/grocery_crud/themes/flexigrid/views/list.php
index 0935d86..6519fe1 100644
--- a/assets/grocery_crud/themes/flexigrid/views/list.php
+++ b/assets/grocery_crud/themes/flexigrid/views/list.php
@@ -38,14 +38,15 @@
<?php if(!$unset_delete || !$unset_edit || !empty($actions)){?>
<td align="left" width='20%'>
<div class='tools'>
- <?php if(!$unset_delete){?>
+ <?php if(!$unset_delete && $row->delete_url){?>
<a href='<?php echo $row->delete_url?>' title='<?php echo $this->l('list_delete')?> <?php echo $subject?>' class="delete-row" >
<span class='delete-icon'></span>
</a>
<?php }?>
- <?php if(!$unset_edit){?>
+ <?php if(!$unset_edit && $row->edit_url){?>
<a href='<?php echo $row->edit_url?>' title='<?php echo $this->l('list_edit')?> <?php echo $subject?>'><span class='edit-icon'></span></a>
<?php }?>
+ <a href='<?php echo $row->view_url?>' title='<?php echo $this->l('list_view')?> <?php echo $subject?>'><span class='view-icon'></span></a>
<?php
if(!empty($row->action_urls)){
foreach($row->action_urls as $action_unique_id => $action_url){
@@ -74,4 +75,4 @@
&nbsp;&nbsp;&nbsp;&nbsp; <?php echo $this->l('list_no_items'); ?>
<br/>
<br/>
-<?php }?>
\ No newline at end of file
+<?php }?>
diff --git a/assets/grocery_crud/themes/flexigrid/views/view.php b/assets/grocery_crud/themes/flexigrid/views/view.php
new file mode 100644
index 0000000..af7f51e
--- /dev/null
+++ b/assets/grocery_crud/themes/flexigrid/views/view.php
@@ -0,0 +1,73 @@
+<?php
+ if (!defined('BASEPATH')) exit('No direct script access allowed');
+
+ $this->set_css('assets/grocery_crud/themes/flexigrid/css/flexigrid.css');
+ $this->set_js('assets/grocery_crud/themes/flexigrid/js/jquery.form.js');
+ $this->set_js('assets/grocery_crud/themes/flexigrid/js/flexigrid-edit.js');
+?>
+<script type='text/javascript'>
+ var base_url = '<?php echo base_url();?>';
+
+ var upload_a_file_string = '<?php echo $this->l('form_upload_a_file');?>';
+</script>
+<div class="flexigrid" style='width: 100%;'>
+ <div class="mDiv">
+ <div class="ftitle">
+ <div class='ftitle-left'>
+ <?php echo $this->l('form_view'); ?> <?php echo $subject?>
+ </div>
+ <div class='ftitle-right'>
+ <a href='<?php echo $list_url?>' onclick='javascript: return goToList()'><?php echo $this->l('form_back_to_list'); ?></a>
+ </div>
+ <div class='clear'></div>
+ </div>
+ <div title="Minimize/Maximize Table" class="ptogtitle">
+ <span></span>
+ </div>
+ </div>
+<div id='main-table-box'>
+ <div class='form-div'>
+ <?php
+ $counter = 0;
+ foreach($fields as $field)
+ {
+ $even_odd = $counter % 2 == 0 ? 'odd' : 'even';
+ $counter++;
+ ?>
+ <div class='form-field-box <?php echo $even_odd?>'>
+ <div class='form-display-as-box'>
+ <?php echo $input_fields[$field->field_name]->display_as?><?php echo ($input_fields[$field->field_name]->required)? "* " : ""?> :
+ </div>
+ <div class='form-input-box'>
+ <?php echo $input_fields[$field->field_name]->input?>
+ </div>
+ <div class='clear'></div>
+ </div>
+ <?php }?>
+ <?php if(!empty($hidden_fields)){?>
+ <!-- Start of hidden inputs -->
+ <?php
+ foreach($hidden_fields as $hidden_field){
+ echo $hidden_field->input;
+ }
+ ?>
+ <!-- End of hidden inputs -->
+ <?php }?>
+ <div id='report-error' class='report-div error'></div>
+ <div id='report-success' class='report-div success'></div>
+ </div>
+ <div class="pDiv">
+ <div class='form-button-box'>
+ <div class='small-loading' id='FormLoading'><?php echo $this->l('form_update_loading'); ?></div>
+ </div>
+ <div class='clear'></div>
+ </div>
+ </form>
+</div>
+<script>
+ var validation_url = '<?php echo $validation_url?>';
+ var list_url = '<?php echo $list_url?>';
+
+ var message_alert_edit_form = "<?php echo $this->l('alert_edit_form')?>";
+ var message_update_error = "<?php echo $this->l('update_error')?>";
+</script>



[attachment=8:changes.txt]

Unfortunately, in my haste to get this developed, I have backed myself into a corner on github ! I have my whole project hosted on github (including grocery crud embedded into it), where I realise now that I should have pulled the official code down from its own git repository, and only hosted my own application specific code on my own repository.

Being new to git, I don't know if git can manage having an application where the sources for the application are pulled from multiple remote repositories (ie - Grocery CRUD, Custom Application, plus other bits, all in the same directory tree). Thats something I need to read up on offline from this forum, as its nothing to do with this library really. More reading for me !

Ah well - I will get around to fixing my git setup soon enough :(

Hope you find the above code patches useful.

Steve

steveoc
  • profile picture
  • Member

Posted 04 January 2012 - 05:04 AM

Changes to a couple of other files as well :

assets/grocery_crud/languages/english.php

@@ -20,6 +20,7 @@
$lang['list_loading'] = 'Loading...';
$lang['form_edit'] = 'Edit';
+ $lang['form_view'] = 'View';
$lang['form_back_to_list'] = 'Back to list';
$lang['form_update_changes'] = 'Update changes';
$lang['form_cancel'] = 'Cancel';
@@ -41,9 +42,9 @@
$lang['delete_error_message'] = 'Your data was not deleted from the database.';

/* Javascript messages */
- $lang['alert_add_form'] = 'The data you had insert may not be saved.\\nAre you sure you want to go back to list?';
- $lang['alert_edit_form'] = 'The data you had change may not be saved.\\nAre you sure you want to go back to list?';
+ $lang['alert_add_form'] = 'The data you had inserted may not be saved.\\nAre you sure you want to go back to list?';
+ $lang['alert_edit_form'] = 'The data you had changed may not be saved.\\nAre you sure you want to go back to list?';
$lang['alert_delete'] = 'Are you sure that you want to delete this record?';

$lang['insert_error'] = 'An error has been occured at the insert.';
- $lang['update_error'] = 'An error has been occured on Saving.';
\ No newline at end of file
+ $lang['update_error'] = 'An error has been occured on Saving.';


assets/grocery_crud/themes/flexigrid/css/flexigrid.css

@@ -619,6 +619,20 @@ div.pGroup {
margin-left:5px;
display: block;
}
+.flexigrid .view-icon
+{
+ background:url(images/magnifier.png) no-repeat;
+ cursor: pointer;
+ width: 16px;
+ height:16px;
+ float:right;
+ border: none !important;
+ padding:0px !important;
+ padding-bottom:0px !important;
+ margin-left:5px;
+ display: block;
+}
+
.flexigrid .delete-icon
{
background:url(images/close.png) no-repeat;
@@ -770,4 +784,4 @@ a:hover
margin-left:5px;
padding:0px;
margin-right: 3px;
-}
\ No newline at end of file
+}



I think thats about all ....

web-johnny
  • profile picture
  • Administrator
  • 1,166 posts

Posted 04 January 2012 - 07:16 AM

That's great @steveoc and thanks for your contribution actually.
For the git hub actually I don't know if you can do it with the way you say it. The only thing you can do is to have just many forks for all the projects that you want to develop. I don't know if anything else exist, as git-hub has really many features and I don't know if to pull from others projects is good for your project cause it will have many conflicts and other problems in my opinion.
Keep reading offline and If you find something just PM me, It's really interesting if you find something like that.
Kind Regards
John Skoumbourdis