Browse Source

[UPDATE] Utils/Tray module to version 2.0

experimental
Georgi Hristov 2 years ago
parent
commit
29e2520d66
9 changed files with 786 additions and 441 deletions
  1. +119
    -0
      modules/Utils/Tray/Box.php
  2. +249
    -0
      modules/Utils/Tray/Slot.php
  3. +87
    -116
      modules/Utils/Tray/TrayCommon_0.php
  4. +16
    -14
      modules/Utils/Tray/TrayInstall.php
  5. +192
    -172
      modules/Utils/Tray/Tray_0.php
  6. BIN
      modules/Utils/Tray/theme/Thumbs.db
  7. +88
    -71
      modules/Utils/Tray/theme/tray.css
  8. +35
    -46
      modules/Utils/Tray/theme/tray.tpl
  9. +0
    -22
      modules/Utils/Tray/tray.js

+ 119
- 0
modules/Utils/Tray/Box.php View File

@@ -0,0 +1,119 @@
<?php

/*
* @author Georgi Hristov <ghristov@gmx.de>
* @copyright Copyright &copy; 2019, Georgi Hristov
* @license MIT
* @version 2.0
* @package epesi-tray
*
*/

defined("_VALID_ACCESS") || die('Direct access forbidden');

class Utils_Tray_Box {
protected $title;
protected $weight = 5;
protected $slots = [];
protected $slotsLimit = false;
protected $limitSlotsDisabled = false;
protected $ignoreLimit = false;
public function __construct($settings) {
$this->setPropertiesFromArray($settings);
}
public function setPropertiesFromArray($settings) {
if (!is_array($settings)) return;
foreach ($settings as $key=>$value) {
$key = str_ireplace(' ', '', ucwords(str_ireplace('_', ' ', trim($key, '__'))));
if (is_callable([$this, 'set' . $key]))
call_user_func([$this, 'set' . $key], $value);
}
}

public function getTitle() {
return $this->title;
}

public function setTitle($title) {
$this->title = $title;
return $this;
}

public function getWeight() {
return $this->weight;
}

public function setWeight($weight) {
$this->weight = $weight;
return $this;
}

/**
* @return Utils_Tray_Slot[]
*/
public function getSlots() {
if (!$this->getSlotsLimit()) return $this->slots;
$ret = [];
foreach ($this->slots as $id=>$slot) {
if (!$slot->getIgnoreLimit() && $id >= $this->getSlotsLimit()) continue;
$ret[] = $slot;
}
return $ret;
}

public function setSlots($module, $tab, $slotDefinitions, $transCallbacks= []) {
foreach ($slotDefinitions as $definition) {
$slotModule = $definition['__module__']?? $module;
if ($slotFunction = $definition['__func__']?? null) {
$slotModule = [$slotModule, $slotFunction];
}
$slot = new Utils_Tray_Slot($this, $slotModule, $tab, $definition, $transCallbacks);
$this->slots[$slot->getId()] = $slot;
}
uasort($this->slots, function (Utils_Tray_Slot $a, Utils_Tray_Slot $b) {
return $a->getWeight() - $b->getWeight();
});

return $this;
}
public function getSlotsLimit() {
if ($this->limitSlotsDisabled) return false;
return $this->slotsLimit;
}

public function setSlotsLimit($slotsLimit) {
$this->slotsLimit = is_numeric($slotsLimit)? $slotsLimit: false;
return $this;
}

public function getLimitSlotsDisabled() {
return $this->limitSlotsDisabled;
}

public function setLimitSlotsDisabled($limitSlotsDisabled) {
$this->limitSlotsDisabled = $limitSlotsDisabled;
return $this;
}

public function getIgnoreLimit() {
return $this->ignoreLimit;
}

public function setIgnoreLimit($ignoreLimit) {
$this->ignoreLimit = $ignoreLimit;
return $this;
}
}

?>

+ 249
- 0
modules/Utils/Tray/Slot.php View File

@@ -0,0 +1,249 @@
<?php

/*
* @author Georgi Hristov <ghristov@gmx.de>
* @copyright Copyright &copy; 2019, Georgi Hristov
* @license MIT
* @version 2.0
* @package epesi-tray
*
*/

defined("_VALID_ACCESS") || die('Direct access forbidden');

class Utils_Tray_Slot {
/**
* @var Utils_Tray_Box
*/
protected $box;
protected $module;
protected $function = null;
protected $tab;
protected $id;
protected $name;
protected $weight = 5;
protected $filters = [];
protected $transCallbacks = [];
protected $crits = null;
protected $count = null;
protected $visible = true;
protected $ignoreLimit = false;
public function __construct(Utils_Tray_Box $box, $module, $tab, $settings, $transCallbacks=[]) {
$this->setBox($box);
$this->setModule($module);
$this->setTab($tab);
$this->setTransCallbacks($transCallbacks);
$this->setPropertiesFromArray($settings);
}
public function setPropertiesFromArray($settings) {
if (!is_array($settings)) return;
foreach ($settings as $key=>$value) {
$key = str_ireplace(' ', '', ucwords(str_ireplace('_', ' ', trim($key, '__'))));
if (is_callable([$this, 'set' . $key]))
call_user_func([$this, 'set' . $key], $value);
}
}
public function isVisible($hideEmpty = true) {
return $this->visible && (!$this->isEmpty() || !$hideEmpty);
}
public function isEmpty() {
return empty($this->getCount());
}
public function getCount() {
return $this->count?? $this->count = Utils_RecordBrowserCommon::get_records_count($this->getTab(), $this->getCrits());
}

public function getBox() {
return $this->box;
}

public function setBox($box) {
$this->box = $box;
return $this;
}

public function getId() {
return $this->id;
}

public function setId($id) {
$this->id = Utils_RecordBrowserCommon::get_field_id($id);;
return $this;
}

public function getName() {
return $this->name;
}

public function setName($name) {
$this->name = $name;
$this->setId($name);
return $this;
}

public function getWeight() {
return $this->weight;
}

public function setWeight($weight) {
$this->weight = $weight;
return $this;
}

public function getFilters() {
return $this->filters;
}

public function setFilters($filters) {
$this->filters = $filters;
return $this;
}

public function getCrits() {
if ($this->crits) {
return is_callable($this->crits)? call_user_func($this->crits): $this->crits;
}
$this->count = null;
$crits = [];
foreach ($this->getFilters() as $field=>$val) {
$trans_callback = $this->getTransCallback($field);

$record_crits = is_callable($trans_callback)? call_user_func($trans_callback, $val, $field, $this->getTab()): [$field=>$val];

$crits = Utils_RecordBrowserCommon::merge_crits($crits, $record_crits);
}
// foreach ($crits as $k=>$c) if ($c==='__PERSPECTIVE__') {
// $crits[$k] = explode(',',trim(CRM_FiltersCommon::get(),'()'));
// if (isset($crits[$k][0]) && $crits[$k][0]=='') unset($crits[$k]);
// }

return $this->crits = $crits;
}

public function setCrits($crits) {
$this->crits = $crits;
return $this;
}
public function getTransCallback($field) {
return $this->transCallbacks[$field]?? [];
}

public function getTransCallbacks() {
return $this->transCallbacks;
}

public function setTransCallbacks($transCallbacks) {
$this->transCallbacks = $transCallbacks;
return $this;
}
public function getHtml() {
$tray_count_width = ($this->getCount() > 99)? 'style="width:28px;"':'';
return '<a '.Base_BoxCommon::create_href(null, $this->getModule(), $this->getFunction(), [$this->getTab()], null, ['tray_slot'=>$this->getId()]).'><div class="Utils_Tray__slot">'.
Utils_TooltipCommon::create('<img src="'.$this->getIcon().'">
<div class="Utils_Tray__slot_count" ' .$tray_count_width . '>' . $this->getCount().'</div><div class="Utils_Tray__slot_name">'._V($this->getName()).'</div>', $this->getTip()).'</div></a>';
}
public function getTip() {
return __('Click to view %s items from %s<br><br>%d item(s)',[_V($this->getName()),_V($this->getBox()->getTitle()), $this->getCount()]);
}
public function getIcon() {
$limits = [10=>'pile3', 5=>'pile2', 1=>'pile1', 0=>'pile0'];
foreach ($limits as $limit=>$file) {
if ($this->getCount() >= $limit) break;
}
return Base_ThemeCommon::get_template_file('Utils_Tray', $file.'.png');
}

public function getModule() {
return $this->module;
}

public function setModule($module) {
if (is_array($module)) {
$this->setFunction($module[1]);
$module = $module[0];
}
$this->module = $module;
return $this;
}
public function getFunction() {
return $this->function;
}

public function setFunction($function) {
$this->function = $function;
return $this;
}

public function getTab() {
return $this->tab;
}

public function setTab($tab) {
$this->tab = $tab;
return $this;
}
public function filtersExist() {
return $this->filters? true: false;
}
public function filtersMatch() {
if (!$this->filtersExist()) return false;
$filtered = false;
foreach ($_REQUEST as $id=>$value) {
if (stripos($id, 'filter__')!==false) {
$filtered = true;
break;
}
}
if (!$filtered) return false;
$filter_changed = false;
foreach ($this->getFilters() as $id=>$value) {
if ($_REQUEST['filter__'.$id]!= $value) {
$filter_changed=true;
break;
}
}
return !$filter_changed;
}

public function getIgnoreLimit() {
return $this->ignoreLimit;
}
public function setIgnoreLimit($ignoreLimit) {
$this->ignoreLimit = $ignoreLimit;
return $this;
}
public function setVisible($visible) {
$this->visible = $visible;
return $this;
}
}

?>

+ 87
- 116
modules/Utils/Tray/TrayCommon_0.php View File

@@ -1,11 +1,12 @@
<?php
/**
* @author Georgi Hristov <ghristov@gmx.de>
* @copyright Copyright &copy; 2014, Xoff Software GmbH
* @license MIT
* @version 1.0
* @package epesi-tray
*/
/*
* @author Georgi Hristov <ghristov@gmx.de>
* @copyright Copyright &copy; 2019, Georgi Hristov
* @license MIT
* @version 2.0
* @package epesi-tray
*/

defined("_VALID_ACCESS") || die('Direct access forbidden');

class Utils_TrayCommon extends ModuleCommon {
@@ -14,10 +15,12 @@ class Utils_TrayCommon extends ModuleCommon {
private static $tmp_trays;

public static function menu() {
if(Base_AclCommon::check_permission('Dashboard')) {
$tray_settings = Utils_TrayCommon::get_trays();
if (count($tray_settings)>0)
return array(_M('Tray')=>array('__icon__'=>'pile_small.png'));
if (Base_AclCommon::check_permission('Dashboard')) {
if (ModuleManager::check_common_methods('tray')) return array(
_M('Tray') => array(
'__icon__' => 'icon.png'
)
);
}
return array();
}
@@ -36,15 +39,62 @@ class Utils_TrayCommon extends ModuleCommon {

public static function applet_settings() {
return array(
array(
'name'=>'title','label'=>__('Title'),'type'=>'text','default'=>__('Tray'),
'rule'=>array(array('message'=>__('Field required'), 'type'=>'required'))),
array(
'name'=>'max_trays','label'=>__('Tray Limit'),'type'=>'select','values'=>array('__NULL__'=>__('No Limit'),4=>4,6=>6,8=>8,10=>10),'default'=>6),
array(
'name'=>'max_slots','label'=>__('Slots Limit'),'type'=>'select','values'=>array('__NULL__'=>__('No Limit'),2=>2,3=>3,4=>4,5=>5,6=>6),'default'=>3),
array(
'name' => 'title',
'label' => __('Title'),
'type' => 'text',
'default' => __('Tray'),
'rule' => array(
array(
'message' => __('Field required'),
'type' => 'required'
)
)
),
array(
'name' => 'max_trays',
'label' => __('Tray Limit'),
'type' => 'select',
'values' => array(
'__NULL__' => __('No Limit'),
4 => 4,
6 => 6,
8 => 8,
10 => 10
),
'default' => 6
),
array(
'name' => 'max_slots',
'label' => __('Slots Limit'),
'type' => 'select',
'values' => array(
'__NULL__' => __('No Limit'),
2 => 2,
3 => 3,
4 => 4,
5 => 5,
6 => 6,
10 => 10
),
'default' => 5
),
array(
'name' => 'hide_empty_slots',
'label' => __('Hide Empty Slots'),
'type' => 'checkbox',
'default' => 1
)
);
}
public static function enable($tab) {
Utils_RecordBrowserCommon::new_browse_mode_details_callback($tab, 'Utils_Tray', 'tray_tab_browse_details');
}
public static function disable($tab) {
Utils_RecordBrowserCommon::delete_browse_mode_details_callback($tab, 'Utils_Tray', 'tray_tab_browse_details');
}

public static function get_trays() {
static $trays;
@@ -56,104 +106,25 @@ class Utils_TrayCommon extends ModuleCommon {
return $trays;
}

public static function are_filters_changed($tray_slot_filters) {
$filtered = false;
foreach ($_REQUEST as $id=>$value) {
if (stripos($id, 'filter__')!==false) {
$filtered = true;
break;
}
}

if (!$filtered) return false;

$filter_changed = false;
foreach ($tray_slot_filters as $id=>$value) {
if ($_REQUEST['filter__'.$id]!= $value) {
$filter_changed=true;
break;
}
}

return $filter_changed;
}

public static function get_tray($tab, $tray_settings) {
if (!isset($tab) || !isset($tray_settings['__title__']) || !isset($tray_settings['__slots__'])) return array();

$slot_defs = self::get_slots($tab, $tray_settings);
$weight = isset($tray_settings['__weight__'])? $tray_settings['__weight__']: 0;

return array('__title__'=>$tray_settings['__title__'], '__weight__'=> $weight, '__slots__'=>$slot_defs);
}

public static function get_slots($tab, $tray_settings) {
if (!isset($tray_settings['__title__']) || !isset($tray_settings['__slots__'])) return array();

$ret = array();
foreach ($tray_settings['__slots__'] as $slot) {
if (!isset($slot['__name__'])) continue;

$crits = self::get_slot_crits($slot, $tray_settings);
$slot_id = Utils_RecordBrowserCommon::get_field_id($slot['__name__']);

$ret[$slot_id] = $slot + array('__id__'=>$slot_id, '__count__'=>Utils_RecordBrowserCommon::get_records_count($tab, $crits) ,'__crits__'=>$crits);
}

return $ret;
}

public static function get_slot_crits($slot, $tray_settings) {
$crits = array();
$trans_callbacks = isset($tray_settings['__trans_callbacks__'])? $tray_settings['__trans_callbacks__']:null;

$record_filters = isset($slot['__filters__']) ? $slot['__filters__'] : array();

foreach ($record_filters as $field=>$val) {
$trans_callback = null;
if (isset($trans_callbacks[$field])) {
$trans_callback = is_array($trans_callbacks[$field])? implode('::', $trans_callbacks[$field]): $trans_callbacks[$field];
}

$record_crits = is_callable($trans_callback)? call_user_func($trans_callback, $val, $field): array($field=>$val);

$crits += is_array($record_crits)? $record_crits: array();
}

foreach ($crits as $k=>$c) if ($c==='__PERSPECTIVE__') {
$crits[$k] = explode(',',trim(CRM_FiltersCommon::get(),'()'));
if (isset($crits[$k][0]) && $crits[$k][0]=='') unset($crits[$k]);
}

return $crits;
}

public static function sort_tray_cmp($a, $b) {
$aw = isset(self::$tmp_trays[$a]['__weight__']) ? self::$tmp_trays[$a]['__weight__']:0;
$bw = isset(self::$tmp_trays[$b]['__weight__']) ? self::$tmp_trays[$b]['__weight__']:0;
if(!isset($aw) || !is_numeric($aw)) $aw=0;
if(!isset($bw) || !is_numeric($bw)) $bw=0;
if($aw==$bw)
return strcasecmp($a, $b);
return $aw-$bw;
}

public static function sort_trays(& $trays, $include_slots = true) {
self::$tmp_trays = $trays;
uksort($trays, array('Utils_TrayCommon','sort_tray_cmp'));

foreach($trays as &$t) {
if(is_array($t) && array_key_exists('__slots__',$t) && $include_slots) {
self::sort_trays($t['__slots__']);
}
}
unset($trays['__weight__']);
}

public static function user_settings(){
return array(__('Tray settings')=>array(
array('name'=>'tray_cols','label'=>__('Tray Columns'),'type'=>'select','values'=>Utils_TrayCommon::$tray_cols,'default'=>3),
array('name'=>'tray_layout','label'=>__('Tray Layout'),'type'=>'select','values'=>Utils_TrayCommon::$tray_layout,'default'=>'checkered')));
public static function user_settings() {
return array(
__('Tray settings') => array(
array(
'name' => 'tray_cols',
'label' => __('Tray Columns'),
'type' => 'select',
'values' => Utils_TrayCommon::$tray_cols,
'default' => 3
),
array(
'name' => 'tray_layout',
'label' => __('Tray Layout'),
'type' => 'select',
'values' => Utils_TrayCommon::$tray_layout,
'default' => 'checkered'
)
)
);
}

//////////////////////////


+ 16
- 14
modules/Utils/Tray/TrayInstall.php View File

@@ -1,15 +1,16 @@
<?php
/**
* @author Georgi Hristov <ghristov@gmx.de>
* @copyright Copyright &copy; 2014, Xoff Software GmbH
* @license MIT
* @version 1.0
* @package epesi-tray
*/
/*
* @author Georgi Hristov <ghristov@gmx.de>
* @copyright Copyright &copy; 2019, Georgi Hristov
* @license MIT
* @version 2.0
* @package epesi-tray
*
*/
defined("_VALID_ACCESS") || die('Direct access forbidden');

class Utils_TrayInstall extends ModuleInstall {
const version = '1.0';
const version = '2.0';

public function install() {
Base_ThemeCommon::install_default_theme($this->get_type());
@@ -30,15 +31,16 @@ class Utils_TrayInstall extends ModuleInstall {
array('name'=>Utils_RecordBrowserInstall::module_name(), 'version'=>0),
array('name'=>Base_LangInstall::module_name(), 'version'=>0),
array('name'=>Base_User_SettingsInstall::module_name(),'version'=>0),
array('name'=>Base_ThemeInstall::module_name(),'version'=>0));
array('name'=>Base_ThemeInstall::module_name(),'version'=>0)
);
}
public static function info() {
$html="Displays overview pending items in recordsets";
return array(
'Description'=>$html,
'Author'=>'<a href="mailto:ghristov@gmx.de">Georgi Hristov</a>',
'License'=>'MIT');
'Description' => "Displays overview pending items in recordsets",
'Author' => '<a href="mailto:ghristov@gmx.de">Georgi Hristov</a>',
'License' => 'MIT'
);
}
public function simple_setup() {


+ 192
- 172
modules/Utils/Tray/Tray_0.php View File

@@ -10,14 +10,19 @@
* - __title__ setting determines the tray that slots will be included in.
* Make sure the title is defined using _M('title') function.
*
* - __slots__ setting defines the slot settings: __name__, __filters__, __weight__
* - __slots__ setting defines the slot settings: __name__, __filters__, __crits__, __weight__, __module__
* = __name__ setting determines the tray display title.
* Make sure the name is defined using _M('name') function
* = __weight__ setting defines the order in which the slots are displayed
* = __filters__ setting defines the default filter values that represent the records contained in each slot
* = __crits__ setting is crits or a callback that defines crits for the slot
* = __module__ setting defines the module to jump to, default is the module where tray method was called from
* = __ignore_limit__ - boolean - the slot is displayed irrelevant of slot limit set - can be used for important slots
*
* - __weight__ setting defines the order in which the trays are displayed
*
* - __ignore_limit__ - boolean - the box is displayed irrelevant of box limit set - can be used for important boxes
*
* - __trans_callbacks__ setting is the list of callback functions for each field that has custom filter defined
*
* - __mobile__ setting defines the columns and sort order when displaying the records in the mobile version
@@ -41,6 +46,15 @@
* }
*
*
* To initiate tray for a recordset use the Utils_TrayCommon::enable method. It makes sure the tray filters are set when navigating with tray slot click
*
* Sample (in the install() method of the module:
*
* Utils_TrayCommon::enable('premium_projects'); *
*
*
* ****** Below is the DEPRECATED method of initiating Tray ******
*
* Initiate the tray module in the body method of your module and call the set_filters method as per sample.
*
* Sample:
@@ -58,9 +72,9 @@
* }
*
* @author Georgi Hristov <ghristov@gmx.de>
* @copyright Copyright &copy; 2014, Xoff Software GmbH
* @copyright Copyright &copy; 2019, Georgi Hristov
* @license MIT
* @version 1.0
* @version 2.0
* @package epesi-tray
*
*/
@@ -70,241 +84,247 @@ defined("_VALID_ACCESS") || die('Direct access forbidden');
class Utils_Tray extends Module {
private $max_trays = '__NULL__';
private $max_slots = '__NULL__';
private $hide_empty_slots = 0;
/**
* @var Utils_Tray_Box[]
*/
private $boxes = [];
public function body() {
if(!Base_AclCommon::check_permission('Dashboard')) return;
Base_ActionBarCommon::add('settings',__('Settings'), $this->create_callback_href(array($this, 'push_settings'), array('Tray settings')), __('Click to edit tray settings'));
Base_ActionBarCommon::add('settings',__('Settings'), $this->create_callback_href([$this, 'push_settings'], ['Tray settings']), __('Click to edit tray settings'));

$this->output();
}
public function tray_tab_browse_details($form, & $external_filters, & $vals, & $filter_crits, $rb_obj) {
if (!Acl::check_permission('Dashboard')) return;

$this->navigate();
$this->set_inline_display();

/**
* @var Utils_Tray_Slot|boolean $slot
*/
$slot = $this->get_selected_slot($rb_obj);
if (!$slot) return;

if ($slot->filtersMatch() || $slot->getCrits()) {
$rb_obj->set_additional_caption($slot->getName());
foreach ( $slot->getFilters() as $field => $value ) {
$vals['filter__' . $field] = $value;
}
$form->setDefaults($vals);
}
if (!$slot->filtersExist() && $slot->getCrits())
$filter_crits = $slot->getCrits();
}
public function navigate() {
$this->set_module_variable('navigated', false);
if ($this->is_back())
return Base_BoxCommon::pop_main();

if (isset($_REQUEST['tray_slot'])) {
Base_ActionBarCommon::add('back', __('Back'), $this->create_back_href());
$this->set_module_variable('tray_slot', $_REQUEST['tray_slot']);
$this->set_module_variable('navigated', true);
}
}

public function applet($conf, & $opts) {
$opts['go'] = true; // enable/disable full screen
$opts['title'] = $conf['title'];
$this->max_trays = $conf['max_trays'];
$this->max_slots = $conf['max_slots'];
$this->hide_empty_slots = $conf['hide_empty_slots'];

$this->output(true);
}

private function output($applet = false) {
Base_ThemeCommon::load_css($this->get_type(), 'tray');

$tray_settings = Utils_TrayCommon::get_trays();

$tray_def = array();
$total_pending = 0;
$displayed = 0;

foreach ($tray_settings as $module=>$module_settings) {
foreach ($module_settings as $tab=>$tab_settings) {
if (!isset($tab_settings['__title__'])) continue;

$tray = Utils_TrayCommon::get_tray($tab, $tab_settings);

if (!isset($tray['__slots__']) || count($tray['__slots__'])==0) continue;

$tray_id = $this->get_type().'__'.Utils_RecordBrowserCommon::get_field_id($tray['__title__']);

$tray_def += array($tray_id =>array('__title__' => $tray['__title__'], '__weight__'=>isset($tray['__weight__'])?$tray['__weight__']:0));

foreach ($tray['__slots__'] as $slot_id=>$slot_def) {
$total_pending += $slot_def['__count__'];
$displayed += $slot_def['__count__'];

$tray_def[$tray_id]['__slots__'][$slot_id]['__weight__'] = isset($slot_def['__weight__'])? $slot_def['__weight__']: 0;

$icon = $this->get_icon($slot_def['__count__']);
$tray_count_width = ($slot_def['__count__']>99)? 'style="width:28px;"':'';

$tip_text = __('Click to view %s items from %s<br><br>%d item(s)', array(_V($slot_def['__name__']),_V($tray['__title__']), $slot_def['__count__']));

$tray_def[$tray_id]['__slots__'][$slot_id]['__html__'] = '<td><a '.$this->create_main_href($module, null, array($tab), null, array('tray_slot'=>$slot_id)).'><div class="Utils_Tray__slot">'.
Utils_TooltipCommon::create('<img src="'.$icon.'">
<div class="Utils_Tray__count" '.$tray_count_width.'>'.$slot_def['__count__'].'</div><div>'._V($slot_def['__name__']).'</div>',$tip_text).'</div></a></td>';
}
}
}

Utils_TrayCommon::sort_trays($tray_def);

$trays = array();
$tray_slots_html = array();
$current_tray = 0;
$this->init_boxes();

$tray_cols = $applet? 2:$this->get_tray_cols();

foreach ($tray_def as $tray_id=>$def) {
$current_tray += 1;
$current_row = max(array(round($current_tray/$tray_cols), 1));
$current_col = $current_tray - $tray_cols*($current_row-1);

if (isset($this->max_trays) && $this->max_trays != '__NULL__') {
$boxes = [];
foreach ($this->boxes as $box) {
if (is_numeric($this->max_trays)) {
//allow only trays in applet mode as per setting
if (count($trays) >= $this->max_trays) break;
if (count($boxes) >= $this->max_trays && !$box->getIgnoreLimit()) continue;
}

if (self::get_tray_layout()=='checkered')
$class = (($current_row+$current_col) % 2)?'Utils_Tray__group_even':'Utils_Tray__group_odd';
else
$class = 'Utils_Tray__group_even';

$trays[] = array(
'class' => $class,
'col'=>$current_col,
'title'=>_V($def['__title__']),
'id'=>$tray_id);

foreach ($def['__slots__'] as $slot) {
$tray_slots_html[$tray_id][] = $slot['__html__'];

if (isset($this->max_slots) && $this->max_slots != '__NULL__') {
//allow slots in applet mode as per setting
if (count($tray_slots_html[$tray_id]) >= $this->max_slots) continue 2;
}
$slots = [];
foreach ( $box->setSlotsLimit($this->max_slots)->getSlots() as $slot ) {
if (!$slot->isVisible($this->hide_empty_slots)) continue;
$slots[] = $slot->getHtml();
}
if (!$slots) continue;
$boxes[] = [
'title' => _V($box->getTitle()),
'slots' => $slots
];
}

eval_js(
'function Utils_Tray__trays() {
var trays = '.json_encode($tray_slots_html).';
return trays;
}
jq( document ).ready(function() {
var resizeId;
jq(window).resize(function(){
clearTimeout(resizeId);
resizeId = setTimeout(Utils_Tray__resize, 300);
});
Utils_Tray__resize();
});');

load_js($this->get_module_dir().'tray.js');

$theme = $this->init_module(Base_Theme::module_name());
$icon = Base_ThemeCommon::get_template_file($this->get_type(),'pile2.png');

$theme->assign('main_page', !$applet);
$theme->assign('caption', Utils_TrayCommon::caption());
$theme->assign('icon', $icon);
$theme->assign('trays', $trays);
$theme->assign('tray_cols', $tray_cols);

if ($total_pending!=$displayed) {
print (__('Displaying %d of %d pending', array($displayed, $total_pending)));
}
$theme->assign('icon', Base_ThemeCommon::get_template_file($this->get_type(),'pile2.png'));
$theme->assign('boxes', $boxes);
$theme->assign('box_cols', $applet? 2:$this->get_tray_cols());

$theme->display('tray');
}
public function init_boxes() {
$tray_settings = Utils_TrayCommon::get_trays();

public function set_filters($rb, $display_tray_select = true, $filter_defaults = array()) {
if(!Base_AclCommon::check_permission('Dashboard')) return;
if($this->is_back()) {
$x = ModuleManager::get_instance('/Base_Box|0');
if(!$x) trigger_error('There is no base box module instance',E_USER_ERROR);
return $x->push_main('Utils_Tray');
}

if (isset($_REQUEST['tray_slot'])) {
Base_ActionBarCommon::add('back', __('Back'), $this->create_back_href());
$this->set_module_variable('tray_slot', $_REQUEST['tray_slot']);
}

$tray_func = $this->parent->get_type().'Common::tray';
if (!is_callable($tray_func)) return;

$settings = call_user_func($tray_func);

if (!isset($settings[$rb->tab])) return;

$slot_defs = Utils_TrayCommon::get_slots($rb->tab, $settings[$rb->tab]);
Utils_TrayCommon::sort_trays($slot_defs);

if ($display_tray_select) {
$tray_slot_select_options = array('__NULL__'=>'---');
foreach ($slot_defs as $slot_id=>$slot_def) {
$tray_slot_select_options[$slot_id] = _V($slot_def['__name__']);
}

$form = $this->init_module(Libs_QuickForm::module_name());
$form->addElement('select', 'tray_slot_select', __('Tray'), $tray_slot_select_options, array('style'=>'width: 130px','onchange'=>$form->get_submit_form_js()));
if ($form->validate()) {
$tray_slot = $form->exportValue('tray_slot_select');
$this->set_module_variable('tray_slot',$tray_slot);
foreach ($tray_settings as $module=>$module_settings) {
foreach ($module_settings as $tab=>$box_settings) {
if (!isset($box_settings['__title__'])) continue;
$box_id = $this->get_type() . '__' . Utils_RecordBrowserCommon::get_field_id($box_settings['__title__']);
$slot_definitions = $box_settings['__slots__'];
unset($box_settings['__slots__']);
$rb->unset_module_variable('def_filter');
if (!isset($this->boxes[$box_id]))
$this->boxes[$box_id] = new Utils_Tray_Box($box_settings);
$this->boxes[$box_id]->setSlots($module, $tab, $slot_definitions, $box_settings['__trans_callbacks__']?? []);
}
}

$tray_slot = $this->get_module_variable('tray_slot');
if (isset($slot_defs[$tray_slot]['__filters__'])) {
$filters_changed = Utils_TrayCommon::are_filters_changed($slot_defs[$tray_slot]['__filters__']);
}
else {
$filters_changed = true;
}
if (!isset($_REQUEST['__location']) && ($tray_slot!='__NULL__') && isset($tray_slot) && !$filters_changed){
$rb->set_additional_caption(_V($slot_defs[$tray_slot]['__name__']));
}
else {
$this->unset_module_variable('tray_slot');
$tray_slot='__NULL__';
uasort($this->boxes, function (Utils_Tray_Box $a, Utils_Tray_Box $b) {
return $a->getWeight() - $b->getWeight();
});
}
public function get_tab_slots($tab) {
if (!$this->boxes) $this->init_boxes();
$ret = [];
foreach ($this->boxes as $box) {
foreach ($box->getSlots() as $slot) {
if ($slot->getTab() == $tab) $ret[$slot->getId()] = $slot;
}
}
return $ret;
}

if ($display_tray_select) {
$form->setDefaults(array('tray_slot_select'=>$tray_slot));
/**
* @param Utils_RecordBrowser $rb_obj
* @param string $display_tray_select
* @param array $filter_defaults
*
* Deprecated method, use Utils_TrayCommon::enable instead
*/
public function set_filters($rb_obj, $display_tray_select = true, $filter_defaults = array()) {
if(!Acl::check_permission('Dashboard')) return;
$this->navigate();

ob_start();
$form->display_as_row();
$html = ob_get_clean();
print('<div style="position: absolute;right:120px;">'.$html.'</div>');
$filter_defaults = $this->get_filter_values($rb_obj, $display_tray_select)?: $filter_defaults;
$rb_obj->set_filters_defaults($filter_defaults);
}
public function get_selected_slot($rb_obj) {
$this->init_boxes();
$slots = $this->get_tab_slots($rb_obj->tab);
if (! $slots) return false;
$tray_slot_select_options = [
'__NULL__' => '---'
];
foreach ( $slots as $slot_id => $slot ) {
$tray_slot_select_options[$slot_id] = _V($slot->getName());
}
if (is_null($tray_slot) || $tray_slot=='__NULL__') {
$rb->set_filters_defaults($filter_defaults);
return;
$form = $this->init_module(Libs_QuickForm::module_name());
$form->addElement('select', 'tray_slot_select', __('Tray'), $tray_slot_select_options, array(
'style' => 'width: 130px',
'onchange' => $form->get_submit_form_js()
));
if ($form->validate()) {
$tray_slot = $form->exportValue('tray_slot_select');
$this->set_module_variable('tray_slot', $tray_slot);
$this->set_module_variable('navigated', true);
$rb_obj->unset_module_variable('def_filter');
}
$rb->disable_browse_mode_switch();

$rb->set_filters($slot_defs[$tray_slot]['__filters__'], true, true);
$tray_slot = $this->get_module_variable('tray_slot');
$form->setDefaults(array(
'tray_slot_select' => $tray_slot
));
$ret = (! is_null($tray_slot) && ($tray_slot != '__NULL__') && isset($tray_slot)) ? $slots[$tray_slot]: false;
if ($ret instanceof Utils_Tray_Slot && !$this->get_module_variable('navigated', false) && !$ret->filtersMatch()) {
$this->set_module_variable('tray_slot', '__NULL__');
$form->setDefaults([
'tray_slot_select' => '__NULL__'
]);
$ret = false;
}
ob_start();
$form->display_as_row();
$html = ob_get_clean();
print('<div style="position: absolute;right:120px;">' . $html . '</div>');
return $ret;
}

public function get_tray_cols() {
$tray_cols = Base_User_SettingsCommon::get('Utils/Tray','tray_cols');
$tray_cols = Base_User_SettingsCommon::get($this->module_name(),'tray_cols');
if (!isset(Utils_TrayCommon::$tray_cols[$tray_cols])) {
$tray_cols = 3;
Base_User_SettingsCommon::save('Utils/Tray','tray_cols', 3);
Base_User_SettingsCommon::save($this->module_name(),'tray_cols', 3);
}
return $tray_cols;
}

public function get_tray_layout() {
$tray_layout = Base_User_SettingsCommon::get('Utils/Tray','tray_layout');
$tray_layout = Base_User_SettingsCommon::get($this->module_name(),'tray_layout');
if (!isset(Utils_TrayCommon::$tray_layout[$tray_layout])) {
$tray_layout = 'checkered';
Base_User_SettingsCommon::save('Utils/Tray','tray_layout', 'checkered');
Base_User_SettingsCommon::save($this->module_name(),'tray_layout', 'checkered');
}
return $tray_layout;
}

private function get_icon($records_count) {
$limits = array(10=>'pile3', 5=>'pile2', 1=>'pile1', 0=>'pile0');
$limits = [
10 => 'pile3',
5 => 'pile2',
1 => 'pile1',
0 => 'pile0'
];

foreach ($limits as $limit=>$file) {
if ($records_count >= $limit) break;
}

return Base_ThemeCommon::get_template_file($this->get_type(),$file.'.png');
return Base_ThemeCommon::get_template_file($this->get_type(), $file.'.png');
}

public function push_settings($s) {
$x = ModuleManager::get_instance('/Base_Box|0');
if(!$x) trigger_error('There is no base box module instance',E_USER_ERROR);
$x->push_main('Base_User_Settings',null,array(_V($s)));
Base_BoxCommon::push_module('Base_User_Settings', null, [_V($s)]);
}
public function caption() {


BIN
modules/Utils/Tray/theme/Thumbs.db View File


+ 88
- 71
modules/Utils/Tray/theme/tray.css View File

@@ -1,14 +1,44 @@
.Utils_Tray__table {
border-collapse: collapse;
width:100%;
padding: 0px;
.Utils_Tray__wrap {
overflow: auto;
white-space: nowrap;
}

.Utils_Tray__box {
float: left;
min-width: 120px;
}

.Utils_Tray__box_wrap {
overflow: auto;
white-space: nowrap;
}

.Utils_Tray__slot {
float: left;
width:55px;
cursor: pointer;
/*border-collapse: collapse;*/
border: 1px solid transparent;
padding:0px;
text-align: center;
}

.Utils_Tray__slot:hover {
border: 1px solid gray;
background-color:rgba(200,200,200,0.7);
}

.Utils_Tray__table {
border-collapse: collapse;
width: 100%;
padding: 0px;
}

.Utils_Tray__table td, .Utils_Tray__table th {
border: 1px solid lightgray;
padding: 0px;
border-top: 0;
border-bottom: 1px solid lightgray;
border: 1px solid lightgray;
padding: 0px;
border-top: 0;
border-bottom: 1px solid lightgray;
}

.Utils_Tray__table tr:first-child td {
@@ -28,61 +58,50 @@
.Utils_Tray__table tr th:last-child {
border-right: 0;
}
.Utils_Tray__group_odd {
height:100%;
vertical-align: top;
background-color:rgba(230,230,230,1);
}
.Utils_Tray__group_even {
height:100%;
vertical-align: top;
background-color:rgba(255,255,255,1);

.Utils_Tray__box_table {
width: 100%;
height: 100%;
padding: 0px;
border-collapse: collapse;
}
/*.tray-group-odd th, .tray-group-even th,
.tray-group-odd td, .tray-group-even td {
border: 0px;
} */
.Utils_Tray__group_table {
width:100%;
height:100%;
padding: 0px;
border-collapse: collapse;

.Utils_Tray__box_table th {
font-weight: normal;
height: 20px;
border: 0px;
background-repeat: repeat-x;
text-align: left;
min-height: 25px;
/*border-top: 1px solid #B3B3B3;*/
border-right: 1px solid #B3B3B3;
border-bottom: 1px solid #FFFFFF;
color: #FFFFFF;
vertical-align: middle;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
/* css3 blue gradient */
background: #3f6a8c; /* Old browsers */
background: -moz-linear-gradient(top, #3f6a8c 0%, #5087b2 50%, #3f6a8c 51%, #335772
100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #3f6a8c),
color-stop(50%, #5087b2), color-stop(51%, #3f6a8c),
color-stop(100%, #335772)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #3f6a8c 0%, #5087b2 50%, #3f6a8c 51%,
#335772 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #3f6a8c 0%, #5087b2 50%, #3f6a8c 51%, #335772
100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #3f6a8c 0%, #5087b2 50%, #3f6a8c 51%, #335772
100%); /* IE10+ */
background: linear-gradient(top, #3f6a8c 0%, #5087b2 50%, #3f6a8c 51%, #335772 100%);
/* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr=\'
#3f6a8c\', endColorstr=\' #335772\', GradientType=0); /* IE6-9 */
/* end css3 gradient */
}
.Utils_Tray__group_table th {
font-weight: normal;
height: 20px;
border: 0px;
background-repeat: repeat-x;
text-align: left;
min-height: 25px;
/*border-top: 1px solid #B3B3B3;*/
border-right: 1px solid #B3B3B3;
border-bottom: 1px solid #FFFFFF;
color: #FFFFFF;
vertical-align: middle;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
/* css3 blue gradient */
background: #3f6a8c; /* Old browsers */
background: -moz-linear-gradient(top, #3f6a8c 0%, #5087b2 50%, #3f6a8c 51%, #335772 100%); /* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#3f6a8c), color-stop(50%,#5087b2), color-stop(51%,#3f6a8c), color-stop(100%,#335772)); /* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #3f6a8c 0%,#5087b2 50%,#3f6a8c 51%,#335772 100%); /* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #3f6a8c 0%,#5087b2 50%,#3f6a8c 51%,#335772 100%); /* Opera 11.10+ */
background: -ms-linear-gradient(top, #3f6a8c 0%,#5087b2 50%,#3f6a8c 51%,#335772 100%); /* IE10+ */
background: linear-gradient(top, #3f6a8c 0%,#5087b2 50%,#3f6a8c 51%,#335772 100%); /* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr=\'#3f6a8c\', endColorstr=\'#335772\',GradientType=0 ); /* IE6-9 */
/* end css3 gradient */
}
.Utils_Tray__group_table td {

.Utils_Tray__box_table td {
border: 0px;
padding: 2px;
vertical-align: top;
@@ -159,7 +178,7 @@
}


.Utils_Tray__count {
.Utils_Tray__slot_count {
position:absolute;
top:35px;
left:20px;
@@ -178,11 +197,9 @@
}

.Utils_Tray__slot_name {
position:absolute;
top:0px;
left:0px;
width:100%;
height:50%;
z-index:4;
font-weight:bold;
}
white-space: pre-wrap;
white-space: -moz-pre-wrap; /* Firefox */
white-space: -pre-wrap; /* Opera <7 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* IE */
}

+ 35
- 46
modules/Utils/Tray/theme/tray.tpl View File

@@ -1,59 +1,48 @@
{if $main_page}
<table class="Utils_Tray__title" border="0" cellpadding="0" cellspacing="0">
<table class="Utils_Tray__title" border="0" cellpadding="0"
cellspacing="0">
<tbody>
<tr>
<td style="width:100px;">
<td style="width: 100px;">
<div class="name">
<img alt="&nbsp;" class="icon" src="{$icon}" width="32" height="32" border="0">
<img alt="&nbsp;" class="icon" src="{$icon}" width="32" height="32"
border="0">
<div class="label">{$caption}</div>
</div>
</td>
<td class="required_fav_info">
</td>
<td class="required_fav_info"></td>
</tr>
</tbody>
</table>
<br>
<div class="table">
<div class="layer">
<div class="css3_content_shadow">
<div class="margin2px">
{/if}
<table class="Utils_Tray__table">
<tbody>
{foreach from=$trays item=tray}
{if $tray.col==1}
<tr>
{/if}
<td class="{$tray.class}">
<table class="Utils_Tray__group_table">
<thead>
<th colspan="{$tray.slots}"><span style="margin-left:5px">{$tray.title}</span></th>
</thead>
<tbody>
<tr>
<td>
<table id="{$tray.id}">
<tbody>
<tr>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
{if $tray.col==$tray_cols}
</tr>
{/if}
{/foreach}
</tbody>
</table>
{if $main_page}
</div>
</div>
</div>
<div class="layer">
<div class="css3_content_shadow">
<div class="margin2px">
{/if}
<div class="Utils_Tray__wrap">
{foreach from=$boxes item=box}
<div style="width: {math equation="
(100/$box_cols)"}%" class="Utils_Tray__box">
<table class="Utils_Tray__box_table">
<thead>
<th><span style="margin-left: 5px">{$box.title}</span></th>
</thead>
<tbody>
<tr>
<td>
<div class="Utils_Tray__box_wrap">{foreach from=$box.slots
item=slot} {$slot} {/foreach}</div>
</td>
</tr>
</tbody>
</table>
</div>
{/foreach}
</div>
{if $main_page}
</div>
</div>
</div>
</div>
{/if}
{/if}

+ 0
- 22
modules/Utils/Tray/tray.js View File

@@ -1,22 +0,0 @@
function Utils_Tray__resize() {
if (typeof Utils_Tray__trays!=='function') return;
var trays=Utils_Tray__trays();

jq.each(trays, function(id, slots) {
if (id=='title') return;
jq('#'+id+' tr:not(:first)').remove();
jq('#'+id+' tr:first').children().remove();
var maxWidth=jq('#'+id).closest('.Utils_Tray__group_table').width();
var slotWidth = 62;
var width = 0;
jq.each(slots, function(i, html) {
width += slotWidth;
if (width >= maxWidth) {
width = slotWidth;
jq('#'+id+' tr:last').after('<tr></tr>');
}
jq('#'+id+' tr:last').append(html);
});
});
}

Loading…
Cancel
Save