PageRenderTime 70ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/layout/navitable.class.php

https://bitbucket.org/navigatecms/navigatecms
PHP | 1001 lines | 827 code | 132 blank | 42 comment | 70 complexity | 0a77135f52b0d590b0b2e0848285a98f MD5 | raw file
Possible License(s): GPL-2.0, MIT, LGPL-2.1, BSD-3-Clause, AGPL-3.0, Apache-2.0
  1. <?php
  2. class navitable
  3. {
  4. public $cols;
  5. public $id;
  6. public $url;
  7. public $sortname;
  8. public $sortorder;
  9. public $edit_index;
  10. public $edit_url;
  11. public $edit_extra; // extra parameter to include in the edit row url
  12. public $delete_url;
  13. public $quicksearch_url;
  14. public $initial_url;
  15. public $data_index;
  16. public $click_action;
  17. public $add_action;
  18. public $delete_action;
  19. public $search_action;
  20. public $load_callback;
  21. public $disable_select;
  22. public $after_select_callback;
  23. public $after_right_click_col;
  24. public $pager;
  25. public $default_fid;
  26. public $grid_notes_object_name;
  27. public $max_rows;
  28. public function __construct($id="")
  29. {
  30. if(empty($id)) $id = 'navitable-'.time();
  31. $this->cols = array();
  32. $this->id = $id;
  33. $this->data_index = 'id';
  34. $this->click_action = 'redirect';
  35. $this->add_action = false;
  36. $this->delete_action = false;
  37. $this->search_action = false;
  38. $this->disable_select = false;
  39. $this->load_callback = '';
  40. $this->pager = true;
  41. $this->after_select_callback = '';
  42. $this->after_right_click_col = '';
  43. $this->default_fid = $_REQUEST['fid'];
  44. $this->quicksearch_url = '';
  45. $this->max_rows = 30;
  46. }
  47. public function setURL($url)
  48. {
  49. $this->url = $url;
  50. }
  51. public function setQuickSearchURL($url)
  52. {
  53. $this->quicksearch_url = $url;
  54. }
  55. public function setTitle($title)
  56. {
  57. $this->title = $title;
  58. }
  59. public function setLoadCallback($script='')
  60. {
  61. $this->load_callback = $script;
  62. }
  63. public function enableDelete($delete_url = NULL)
  64. {
  65. $this->delete_action = true;
  66. if(!empty($delete_url))
  67. $this->delete_url = $delete_url;
  68. else
  69. $this->delete_url = '?fid='.$this->default_fid.'&act=json&oper=del';
  70. }
  71. public function enableSearch()
  72. {
  73. $this->search_action = true;
  74. }
  75. public function enableAdd()
  76. {
  77. $this->add_action = true;
  78. }
  79. public function disableSelect()
  80. {
  81. $this->disable_select = true;
  82. }
  83. public function disableStatusBar()
  84. {
  85. $this->pager = false;
  86. }
  87. public function setDataIndex($name)
  88. {
  89. $this->data_index = $name;
  90. }
  91. public function setDefaultFID($fid)
  92. {
  93. $this->default_fid = $fid;
  94. }
  95. public function sortBy($name, $order = 'asc')
  96. {
  97. $this->sortname = $name;
  98. $this->sortorder = $order;
  99. }
  100. public function addCol($label, $index, $width="auto", $sortable="false", $align="left", $edit=array(), $hidden="false")
  101. {
  102. /*
  103. http://www.trirand.com/jqgridwiki/doku.php?id=wiki:common_rules
  104. $edit = array(
  105. 'type' => 'text', 'textarea', 'select', 'checkbox', 'password', 'button', 'image', 'file', 'custom'
  106. 'options' => depends on type,
  107. 'rules' => not implemented
  108. 'form' => not implemented
  109. )
  110. */
  111. $sortby = '';
  112. if(!empty($edit))
  113. {
  114. if(empty($edit['options'])) $edit['options'] = '{}';
  115. if(empty($edit['rules'])) $edit['rules'] = '{}';
  116. if(empty($edit['form'])) $edit['form'] = '{}';
  117. $newcol = '{ label: "'.$label.'",
  118. name: "'.$index.'",
  119. index : "'.$sortby.'",
  120. width : "'.$width.'",
  121. sortable : '.$sortable.',
  122. align: "'.$align.'",
  123. hidden: '.$hidden.',
  124. editable: true,
  125. edittype: "'.$edit['type'].'",
  126. editoptions: '.$edit['options'].',
  127. editrules: '.$edit['rules'].',
  128. formoptions: '.$edit['form'].'
  129. }';
  130. $this->click_action = 'jqform';
  131. }
  132. else
  133. {
  134. $newcol = '{ label: "'.$label.'",
  135. name: "'.$index.'",
  136. index : "'.$sortby.'",
  137. width : "'.$width.'",
  138. sortable : '.$sortable.',
  139. align: "'.$align.'",
  140. hidden: '.$hidden.'
  141. }';
  142. }
  143. $newcol = preg_replace("/\n|\r|\t/", " ", $newcol);
  144. $this->cols[] = $newcol;
  145. }
  146. public static function jqgridJson($dataset, $page, $offset, $max, $total, $indexID=0)
  147. {
  148. /* from jQGrid docs
  149. rows the root tag for the grid
  150. page the number of the requested page
  151. total the total pages of the query
  152. records the total records from the query
  153. row a particular row in the grid
  154. cell the actual data. Note that CDATA can be used. This way we can add images, links and check boxes.
  155. */
  156. $obj = new stdClass();
  157. $obj->rows = array();
  158. for($i=0; $i < count($dataset); $i++)
  159. {
  160. $data = $dataset[$i];
  161. if(empty($data)) continue;
  162. unset($row);
  163. $row = array();
  164. $obj->rows[$i]['id'] = $data[$indexID]; // FIRST COLUMN MUST BE THE ID
  165. $obj->rows[$i]['cell'] = array();
  166. if(empty($data)) $data = array();
  167. foreach($data as $key => $value)
  168. {
  169. $row[] = $value;
  170. }
  171. $obj->rows[$i]['cell'] = $row;
  172. }
  173. if(empty($total)) $total = count($obj->rows);
  174. $obj->records = $total;
  175. $obj->total = ceil($obj->records / $max); // pages
  176. $obj->page = $page; // requested page
  177. header('Content-Type: text/json');
  178. echo json_encode($obj);
  179. return true;
  180. }
  181. // compareField is the column name when writing a SQL comparison
  182. // is the column value when doing a PHP comparison
  183. public static function jqgridcompare($compareField, $compareType, $compareValue, $returnResult=false)
  184. {
  185. global $DB;
  186. $compare = '';
  187. $result = false;
  188. switch($compareType)
  189. {
  190. case 'eq': // equal
  191. $compare = $compareField.' = '.protect($compareValue);
  192. if($returnResult)
  193. $result = (strcasecmp($compareField, $compareValue)==0);
  194. break;
  195. case 'ne': // not equal
  196. $compare = $compareField.' != '.protect($compareValue);
  197. if($returnResult)
  198. $result = (strcasecmp($compareField, $compareValue)!=0);
  199. break;
  200. case 'lt': // less
  201. $compare = $compareField.' < '.protect($compareValue);
  202. if($returnResult)
  203. $result = ($compareField < $compareValue);
  204. break;
  205. case 'le': // less or equal
  206. $compare = $compareField.' <= '.protect($compareValue);
  207. if($returnResult)
  208. $result = ($compareField <= $compareValue);
  209. break;
  210. case 'gt': // greater
  211. $compare = $compareField.' > '.protect($compareValue);
  212. if($returnResult)
  213. $result = ($compareField > $compareValue);
  214. break;
  215. case 'ge': // greater or equal
  216. $compare = $compareField.' >= '.protect($compareValue);
  217. if($returnResult)
  218. $result = ($compareField >= $compareValue);
  219. break;
  220. case 'nu': // is null
  221. $compare = $compareField.' IS NULL ';
  222. if($returnResult)
  223. $result = empty($compareField); // or is_null()?
  224. break;
  225. case 'nn': // is not null
  226. $compare = $compareField.' IS NOT NULL ';
  227. if($returnResult)
  228. $result = !empty($compareField);
  229. break;
  230. case 'in': // is in
  231. if(!empty($compareValue) || $compareValue=="0")
  232. {
  233. if(strpos($compareValue, ",")!==false)
  234. {
  235. $compareValue = explode(",", $compareValue);
  236. $compareValue = array_filter($compareValue);
  237. }
  238. else
  239. {
  240. $compareValue = array($compareValue);
  241. }
  242. $compareValue = array_map(
  243. function($v)
  244. {
  245. if(is_integer($v))
  246. return $v;
  247. else
  248. return '"'.$v.'"';
  249. },
  250. $compareValue
  251. );
  252. $compare = $compareField.' IN ('.implode(",", $compareValue).') ';
  253. if($returnResult)
  254. $result = in_array($compareField, $compareValue);
  255. }
  256. else
  257. $compare = ' 1=1 ';
  258. break;
  259. case 'ni': // is not in
  260. $compare = $compareField.' NOT IN ('.$compareField.') ';
  261. if($returnResult)
  262. $result = !in_array($compareField, explode(',', $compareField));
  263. break;
  264. case 'bw': // begins with
  265. $compare = $compareField.' LIKE '.protect($compareValue.'%');
  266. if($returnResult)
  267. $result = (substr_compare($compareField, $compareValue, 0, strlen($compareValue), true)==0);
  268. break;
  269. case 'bn': // not begins with
  270. $compare = $compareField.' NOT LIKE '.protect($compareValue.'%');
  271. if($returnResult)
  272. $result = (substr_compare($compareField, $compareValue, 0, strlen($compareValue), true)!=0);
  273. break;
  274. case 'ew': // ends with
  275. $compare = $compareField.' LIKE '.protect('%'.$compareValue);
  276. if($returnResult)
  277. $result = (substr_compare($compareField, $compareValue, -strlen($compareValue), strlen($compareValue), true)==0);
  278. break;
  279. case 'en': // NOT ends with
  280. $compare = $compareField.' NOT LIKE '.protect('%'.$compareValue);
  281. if($returnResult)
  282. $result = (substr_compare($compareField, $compareValue, -strlen($compareValue), strlen($compareValue), true)!=0);
  283. break;
  284. case 'nc': // NOT contains
  285. $compare = $compareField.' NOT LIKE '.protect('%'.$compareValue.'%');
  286. if($returnResult)
  287. $result = (strpos($compareField, $compareValue)===false);
  288. break;
  289. default:
  290. case 'cn': // contains
  291. if(!empty($compareValue) && !$returnResult)
  292. {
  293. $compare = $compareField.' LIKE '.protect('%'.$compareValue.'%');
  294. if($returnResult)
  295. $result = (strpos($compareField, $compareValue)!==false);
  296. }
  297. else // nothing to search, ignore this filter!
  298. {
  299. $compare = '1 = 1';
  300. }
  301. break;
  302. }
  303. if($returnResult)
  304. return $result;
  305. return $compare;
  306. }
  307. // convert jqgrid search filters to SQL conditions
  308. public static function jqgridsearch($filters)
  309. {
  310. $filters = json_decode($filters);
  311. $groupOp = ' AND ';
  312. if($filters->groupOp=='OR') $groupOp = ' OR ';
  313. $where = '';
  314. foreach($filters->rules as $rule)
  315. {
  316. if(empty($where)) $where = ' AND ( ';
  317. else $where .= $groupOp;
  318. $where.= navitable::jqgridcompare($rule->field, $rule->op, $rule->data);
  319. }
  320. $where .= ') ';
  321. return $where;
  322. }
  323. public static function jqgridCheck($row, $filters)
  324. {
  325. $filters = json_decode($filters);
  326. if($filters->groupOp=='OR')
  327. $result = false;
  328. else
  329. $result = true;
  330. foreach($filters->rules as $rule)
  331. {
  332. if($filters->groupOp=='OR')
  333. $result = $result || navitable::jqgridcompare($row[$rule->field], $rule->op, $rule->data, true);
  334. else
  335. $result = $result && navitable::jqgridcompare($row[$rule->field], $rule->op, $rule->data, true);
  336. }
  337. return $result;
  338. }
  339. public function setEditUrl($index = 'id', $url, $extra=NULL)
  340. {
  341. $this->edit_index = $index;
  342. $this->edit_url = $url;
  343. $this->edit_extra = $extra;
  344. }
  345. public function setInitialURL($url)
  346. {
  347. $this->initial_url = $url;
  348. }
  349. public function setGridNotesObjectName($object_name)
  350. {
  351. $this->grid_notes_object_name = $object_name;
  352. }
  353. public function generate()
  354. {
  355. global $layout;
  356. global $user;
  357. if(empty($this->grid_notes_object_name))
  358. $this->grid_notes_object_name = $this->default_fid;
  359. $grid_notes_control = '?fid=grid_notes&object='.$this->grid_notes_object_name.'&act=';
  360. $html = array();
  361. $html[] = '<table id="'.$this->id.'"></table>';
  362. if($this->pager)
  363. $html[] = '<div id="'.$this->id.'-pager"></div>';
  364. $html[] = '<script language="javascript" type="text/javascript">';
  365. $html[] = 'var navitable_'.$this->id.'_selected_rows = []; ';
  366. $html[] = '$(window).on("load", function() { ';
  367. $html[] = '$("#'.$this->id.'").jqGrid({';
  368. if(!empty($this->initial_url))
  369. $html[] = 'url: "'.$this->initial_url.'",';
  370. else
  371. $html[] = 'url: "'.$this->url.'",';
  372. $html[] = 'editurl: "'.$this->url.'",';
  373. $html[] = 'datatype: "json",';
  374. $html[] = 'mtype: "GET",';
  375. $html[] = 'pager: "#'.$this->id.'-pager",';
  376. $html[] = 'viewrecords: true,'; // display the number of total records in the pager bar
  377. $html[] = 'rowNum: '.$this->max_rows.',';
  378. $html[] = 'rowList: [10,15,20,30,50,100],';
  379. $html[] = 'scroll: 1,';
  380. $html[] = 'iconSet: "fontAwesome",';
  381. $html[] = 'loadonce: false,';
  382. if($this->click_action == 'redirect')
  383. $html[] = 'multiselect: true,';
  384. //$html[] = 'multikey: "ctrlKey",';
  385. $html[] = 'autowidth: true,';
  386. $html[] = 'shrinkToFit: true,';
  387. $html[] = 'forceFit: true,';
  388. $html[] = 'onSelectRow: function(rowid, status, e) {
  389. navitable_'.$this->id.'_selected_rows = $("#'.$this->id.'").jqGrid("getGridParam", "selarrrow");
  390. '.$this->after_select_callback.'
  391. },';
  392. $html[] = 'onSelectAll: function(aRowids, status) {
  393. if(status)
  394. navitable_'.$this->id.'_selected_rows = aRowids;
  395. else
  396. navitable_'.$this->id.'_selected_rows = [];
  397. // restore cells background color
  398. $("#'.$this->id.'").find("tr").trigger("mouseenter").trigger("mouseleave");
  399. '.$this->after_select_callback.'
  400. },';
  401. $html[] = 'onRightClickRow: function(rowid, iRow, iCol, e) {
  402. '.$this->after_right_click_col.'
  403. },';
  404. $html[] = 'gridComplete: function() {
  405. $("td").noSelect(); // requires jQuery no-select plugin
  406. $("#'.$this->id.'").find("tr").not(":first").off().longclick(function()
  407. {
  408. '.$this->id.'_dclick($(this).attr("id"), null, null, null);
  409. });
  410. navigate_grid_bind_color_swatch_notes();
  411. $(navitable_'.$this->id.'_selected_rows).each(function(i, el)
  412. {
  413. //$("#'.$this->id.'").setSelection(el, true);
  414. // update row background
  415. $("#" + el).trigger("mouseenter").trigger("mouseleave");
  416. });
  417. $("#'.$this->id.'").jqGrid("setGridWidth", $("#navigate-content").width());
  418. '.$this->load_callback.'
  419. },';
  420. if(!empty($this->sortname))
  421. {
  422. $html[] = 'sortname: "'.$this->sortname.'",';
  423. $html[] = 'sortorder: "'.$this->sortorder.'",';
  424. }
  425. if(!empty($this->click_action))
  426. $html[] = ' ondblClickRow: '.$this->id.'_dclick, ';
  427. if(!empty($this->title))
  428. $html[] = 'caption: "'.$this->title.'",';
  429. $html[] = 'colModel: ['.implode(",\n", $this->cols).']';
  430. $html[] = '});';
  431. $html[] = '$("#'.$this->id.'").jqGrid(
  432. "navGrid",
  433. "#'.$this->id.'-pager",
  434. {
  435. add: '.($this->add_action && !empty($this->edit_url)? 'true' : 'false').',
  436. edit: '.(($this->click_action=='jqform')? 'true' : 'false').',
  437. del: '.($this->delete_action? 'true' : 'false').',
  438. search:'.(!empty($this->search_action)? 'true' : 'false').',
  439. searchtext:"'.t(41, 'Search').' ",
  440. addfunc: function()
  441. {
  442. window.location.href="?fid='.$this->default_fid.'&act=2";
  443. },
  444. delfunc: function(rownums)
  445. {
  446. // ask confirmation
  447. $(\'<div id="navigate-delete-dialog">'.t(60, 'Do you really want to delete the selected items?').'</div>\')
  448. .dialog(
  449. {
  450. resizable: true,
  451. height: 150,
  452. width: 300,
  453. modal: true,
  454. title: "'.t(59, 'Confirmation').'",
  455. buttons:
  456. {
  457. "'.t(58, 'Cancel').'": function()
  458. {
  459. $(this).dialog("close");
  460. },
  461. "'.t(35, 'Delete').'": function()
  462. {
  463. $(this).dialog("close");
  464. // get row main id
  465. var rowids = [];
  466. for(var rownum in rownums)
  467. {
  468. rowids.push($("#'.$this->id.'").getRowData(rownums[rownum]).'.$this->data_index.');
  469. }
  470. // ajax call
  471. $.ajax(
  472. {
  473. async: false,
  474. data: {ids: rowids},
  475. dataType: "json",
  476. complete: function()
  477. {
  478. // reload table (with or without success)
  479. $("#'.$this->id.'").trigger("reloadGrid", [{current:true}]);
  480. },
  481. type: "post",
  482. url: "'.$this->delete_url.'"
  483. });
  484. }
  485. }
  486. }
  487. );
  488. }
  489. },
  490. {},
  491. {},
  492. {},
  493. { multipleSearch: true }
  494. );';
  495. $html[] = '$("#'.$this->id.'").jqGrid("setGridParam",
  496. {
  497. url: "'.$this->url.'"
  498. });';
  499. // enable multiple row selection with shift key
  500. // the following code is adapted from:
  501. // http://stackoverflow.com/questions/11174499/shift-click-jqgrid-multiselect-missing-last-row
  502. $html[] = '$("#'.$this->id.'").jqGrid("setGridParam",
  503. {
  504. beforeSelectRow: function(rowid, e) {
  505. if('.($this->disable_select? 'true' : 'false').')
  506. return false;
  507. var $this = $(this), rows = this.rows,
  508. // get id of the previous selected row
  509. startId = $this.jqGrid("getGridParam", "selrow"),
  510. startRow, endRow, iStart, iEnd, i, rowidIndex;
  511. if (!e.ctrlKey && !e.shiftKey)
  512. {
  513. // intentionally left here to show differences with
  514. // Oleg\'s solution. Just have normal behavior instead.
  515. // $this.jqGrid("resetSelection");
  516. }
  517. else if (startId && e.shiftKey)
  518. {
  519. // Do not clear existing selections
  520. // get DOM elements of the previous selected and
  521. // the currect selected rows
  522. startRow = rows.namedItem(startId);
  523. endRow = rows.namedItem(rowid);
  524. if (startRow && endRow)
  525. {
  526. // get min and max from the indexes of the previous selected
  527. // and the currect selected rows
  528. iStart = Math.min(startRow.rowIndex, endRow.rowIndex);
  529. rowidIndex = endRow.rowIndex;
  530. iEnd = Math.max(startRow.rowIndex, rowidIndex);
  531. // get the rowids of selected rows
  532. var selected = $this.jqGrid("getGridParam","selarrrow");
  533. for (i = iStart; i <= iEnd; i++)
  534. {
  535. // if this row isn\'t selected, then toggle it.
  536. // jqgrid will select the clicked on row, so just ignore it.
  537. // note that we still go <= iEnd because we don\'t know which is start or end.
  538. if(selected.indexOf(rows[i].id) < 0 && i != rowidIndex)
  539. {
  540. // true is to trigger onSelectRow event, which you may not need
  541. $this.jqGrid("setSelection", rows[i].id, true);
  542. }
  543. }
  544. }
  545. // clear text selection (needed in IE)
  546. if(document.selection && document.selection.empty)
  547. {
  548. document.selection.empty();
  549. }
  550. else if(window.getSelection)
  551. {
  552. window.getSelection().removeAllRanges();
  553. }
  554. }
  555. return true;
  556. },
  557. beforeRequest: function()
  558. {
  559. var filters = $("#'.$this->id.'").jqGrid("getGridParam", "postData").filters;
  560. if(filters)
  561. {
  562. // remove quicksearch text field and restore grid search url
  563. $("#navigate-quicksearch").val("");
  564. $("#'.$this->id.'").jqGrid("setGridParam", { url: "'.$this->url.'" });
  565. }
  566. }
  567. });';
  568. // enable keyboard navigation
  569. $html[] = '$("#'.$this->id.'").jqGrid("bindKeys",
  570. {
  571. onEnter: function(rowid) { '.$this->id.'_dclick(rowid, null, null, null); }
  572. });';
  573. $html[] = '});';
  574. if(!empty($this->edit_url) && ($this->click_action=="redirect"))
  575. {
  576. $html[] = 'function '.$this->id.'_dclick(rowid, iRow, iCol, e)';
  577. $html[] = '{';
  578. $html[] = ' navigate_unselect_text();';
  579. $html[] = ' var data = $("#'.$this->id.'").getRowData(rowid); ';
  580. $html[] = ' var row_edit_url = "'.$this->edit_url.'" + data.'.$this->edit_index.'; ';
  581. if(!empty($this->edit_extra))
  582. {
  583. $html[] = ' row_edit_url = row_edit_url + "&'.$this->edit_extra.'=" + data.'.$this->edit_extra.';';
  584. }
  585. //$html[] = ' console.log(rowid); ';
  586. //$html[] = ' console.log(data);';
  587. $html[] = ' if(e && e.ctrlKey) ';
  588. $html[] = ' {
  589. var nw = window.open(row_edit_url);
  590. nw.blur();
  591. window.focus();
  592. }';
  593. $html[] = ' else';
  594. $html[] = ' { window.location.href = row_edit_url; }';
  595. //$html[] = ' window.location.href = "'.$this->edit_url.'" + rowid;';
  596. //$html[] = ' window.location.href = "'.$this->edit_url.'" + $(this).getCol(1)[iRow];'; // we catch the ID from the first column
  597. //$html[] = ' window.location.href = "'.$this->edit_url.'" + data.id;'; // we catch the ID from the first column
  598. $html[] = '}';
  599. }
  600. else if(!empty($this->edit_url) && ($this->click_action="jqform"))
  601. {
  602. $html[] = 'function '.$this->id.'_dclick(rowid, iRow, iCol, e)';
  603. $html[] = '{';
  604. $html[] = ' navigate_unselect_text(); ';
  605. $html[] = ' $("'.$this->id.'").jqGrid("editGridRow", rowid, {height:280,reloadAfterSubmit:false}); ';
  606. $html[] = '}';
  607. }
  608. else if(!empty($this->click_action))
  609. {
  610. $html[] = 'function '.$this->id.'_dclick(rowid, iRow, iCol, e)';
  611. $html[] = '{';
  612. $html[] = ' navigate_unselect_text(); ';
  613. $html[] = ' if(typeof('.$this->click_action.')!="undefined") '.$this->click_action.'(rowid); ';
  614. $html[] = '}';
  615. }
  616. if(empty($this->quicksearch_url))
  617. {
  618. $this->quicksearch_url = '?fid='.$this->default_fid.'&act=json&_search=true&quicksearch=';
  619. if(strpos($this->default_fid, 'ext_')===0)
  620. $this->quicksearch_url = '?fid='.$this->default_fid.'&mode=json&_search=true&quicksearch=';
  621. }
  622. $html[] = 'function navitable_quicksearch(text)';
  623. $html[] = '{';
  624. $html[] = ' $("#'.$this->id.'").jqGrid("setGridParam", { postData: { filters: null} });'; // remove current search filters
  625. $html[] = ' $("#'.$this->id.'").jqGrid("setGridParam", { url: "'.$this->quicksearch_url.'" + text });';
  626. $html[] = ' $("#'.$this->id.'").trigger("reloadGrid");';
  627. // disable original search URL to allow table sorting based on quicksearch
  628. //$html[] = ' $("#'.$this->id.'").jqGrid("setGridParam", { url: "'.$this->url.'" });';
  629. $html[] = '}';
  630. $html[] = "
  631. var navigate_grid_default_row_background = '#F9FAFB';
  632. function navigate_grid_bind_color_swatch_notes()
  633. {
  634. // update row background color
  635. $('.grid_color_swatch').each(function()
  636. {
  637. if($(this).attr('ng-background') != '')
  638. {
  639. var tr = $(this).parent().parent();
  640. var ngbk = $(this).attr('ng-background');
  641. $(tr).find('td').each(function(i, el)
  642. {
  643. $(el).css('background', ngbk);
  644. });
  645. }
  646. else
  647. {
  648. $(tr).find('td').each(function(i, el)
  649. {
  650. $(el).css('background', navigate_grid_default_row_background);
  651. });
  652. }
  653. });
  654. $('.navigate_grid_notes_span').on('click', function()
  655. {
  656. $(this).next().trigger('click');
  657. });
  658. // prepare grid notes button
  659. $('.grid_note_edit').each(function()
  660. {
  661. if($(this).attr('ng-notes')==0)
  662. {
  663. $(this).css('opacity', 0.5);
  664. $(this).off('mouseenter').off('mouseleave').hover(
  665. function()
  666. { $(this).css('opacity', 1); },
  667. function()
  668. { $(this).css('opacity', 0.5); }
  669. );
  670. }
  671. else
  672. $(this).css('opacity', 1);
  673. $(this).off('click').on('click', function()
  674. {
  675. var row_id = $(this).parent().parent().attr('id');
  676. // open item notes dialog
  677. $('<div><img src=\"".NAVIGATE_URL."/img/loader.gif\" style=\" top: 162px; left: 292px; position: absolute; \" /></div>').dialog({
  678. modal: true,
  679. width: 600,
  680. height: 400,
  681. title: '".t(168, "Notes")."',
  682. open: function(event, ui)
  683. {
  684. var container = this;
  685. $.getJSON('".$grid_notes_control."grid_notes_comments&id=' + row_id, function(data)
  686. {
  687. $(container).html('".
  688. '<div><form action="#" onsubmit="return false;" method="post"><span class=\"grid_note_username\">'.$user->username.'</span><button class="grid_note_save">'.t(34, 'Save').'</button><br /><textarea id="grid_note_comment" class="grid_note_comment"></textarea></form></div>'
  689. ."');
  690. for(d in data)
  691. {
  692. var note = '<div class=\"grid_note ui-corner-all\" grid-note-id=\"'+data[d].id+'\" style=\" background: '+data[d].background+'; \">';
  693. note += '<span class=\"grid_note_username\">'+data[d].username+'</span>';
  694. note += '<span class=\"grid_note_remove\"><img src=\"".NAVIGATE_URL."/img/icons/silk/decline.png\" /></span>';
  695. note += '<span class=\"grid_note_date\">'+data[d].date+'</span>';
  696. note += '<span class=\"grid_note_text\">'+data[d].note+'</span>';
  697. note += '</div>';
  698. $(container).append(note);
  699. }
  700. // TO DO: add color picker selector when adding a comment
  701. // $('.grid_note_save').after('<div style=\"float: right;\"></div>');
  702. $(container).find('.grid_note_remove').on('click', function()
  703. {
  704. var grid_note = $(this).parent();
  705. $.get(
  706. '".$grid_notes_control."grid_note_remove&id=' + $(this).parent().attr('grid-note-id'),
  707. function(result)
  708. {
  709. if(result=='true')
  710. {
  711. $(grid_note).fadeOut();
  712. $('#".$this->id."').trigger('reloadGrid', [{current:true}]);
  713. }
  714. }
  715. );
  716. });
  717. $(container).find('.grid_note_save').button({
  718. icons: { primary: 'ui-icon-disk' }
  719. }).on('click', function()
  720. {
  721. $.post('".$grid_notes_control."grid_notes_add_comment',
  722. {
  723. comment: $(container).find('.grid_note_comment').val(),
  724. id: row_id,
  725. background: $('#' + row_id).find('.grid_color_swatch').attr('ng-background')
  726. },
  727. function(result)
  728. {
  729. if(result=='true') // reload dialog and table
  730. {
  731. $(container).parent().remove();
  732. $('#' + row_id).find('.grid_note_edit').trigger('click');
  733. $('#".$this->id."').trigger('reloadGrid', [{current:true}]);
  734. }
  735. });
  736. });
  737. });
  738. }
  739. });
  740. });
  741. });
  742. // click event on color swatch icon
  743. $('.grid_color_swatch').off('click').on('click', function(e)
  744. {
  745. e.stopPropagation();
  746. var tr = $(this).parent().parent();
  747. var original_background = $(tr).find('td:first').css('background-color');
  748. // assign the item id of the row to the floating div
  749. $('#navigate_grid_color_picker span').attr('data-item-id', $(tr).attr('id'));
  750. $('#navigate_grid_color_picker').css({
  751. left: $(this).offset().left - $('#navigate_grid_color_picker').width() + 2,
  752. top: $(this).offset().top - $('#navigate_grid_color_picker').height() + 3
  753. }).show();
  754. $('#navigate_grid_color_picker span').off('mouseenter').off('mouseleave').hover(
  755. function()
  756. {
  757. var new_background = $(this).css('background-color');
  758. if(new_background=='rgb(255, 255, 255)')
  759. new_background = '';
  760. $(tr).find('td').css('background', new_background);
  761. },
  762. function()
  763. {
  764. $(tr).find('td').css('background', original_background);
  765. }
  766. );
  767. $('#navigate_grid_color_picker span').off('click').on('click', function(e)
  768. {
  769. $('#navigate_grid_color_picker').hide();
  770. // retrieve the grid row by the item id previously saved
  771. var tr = $('tr[id=\"'+$(this).attr('data-item-id')+'\"]');
  772. var new_background = $(this).css('background-color');
  773. if(new_background=='rgb(255, 255, 255)')
  774. new_background = navigate_grid_default_row_background;
  775. // now save this preference
  776. $.ajax({
  777. type: 'POST',
  778. url: '".$grid_notes_control."grid_note_background',
  779. data: {
  780. id: $(this).attr('data-item-id'),
  781. background: new_background
  782. },
  783. success: function(msg)
  784. {
  785. $(tr).find('img.grid_color_swatch').attr('ng-background', new_background);
  786. $(tr).find('td').animate(
  787. {'background-color': new_background},
  788. 500,
  789. 'swing',
  790. function()
  791. {
  792. $(this).trigger('mouseleave');
  793. }
  794. );
  795. }
  796. });
  797. });
  798. var remove_grid_color_picker = function(e)
  799. {
  800. if($(e).target != $('#navigate_grid_color_picker span'))
  801. {
  802. $('#navigate_grid_color_picker').hide();
  803. $(window).off('click', remove_grid_color_picker);
  804. }
  805. };
  806. $(window).off('click', remove_grid_color_picker).on('click', remove_grid_color_picker);
  807. }).css('cursor', 'pointer');
  808. // protect row selected color
  809. $('.grid_color_swatch').parent().parent().each(function(i, row)
  810. {
  811. // for each row, clear the custom background color on mouse enter
  812. $(row).off('mouseenter').on('mouseenter', function()
  813. {
  814. $(this).find('td').css('background', 'transparent');
  815. });
  816. // for each row, restore the custom background color unless row is selected
  817. $(row).off('mouseleave').on('mouseleave', function()
  818. {
  819. if(!$(row).hasClass('ui-state-highlight'))
  820. {
  821. var color_swatch_background = $(this).find('.grid_color_swatch').attr('ng-background');
  822. if(color_swatch_background != '')
  823. {
  824. $(row).find('td').css('background', color_swatch_background);
  825. }
  826. else
  827. {
  828. $(row).find('td').css('background', 'transparent'); //navigate_grid_default_row_background);
  829. }
  830. }
  831. });
  832. });
  833. };
  834. ";
  835. $html[] = '</script>';
  836. $html[] = '
  837. <div id="navigate_grid_color_picker" class="ui-corner-all">
  838. <span style="background-color: #e6ecff;"></span>
  839. <span style="background-color: #dff2f2;"></span>
  840. <span style="background-color: #dff2df;"></span>
  841. <span style="background-color: #ffffdf;"></span>
  842. <span style="background-color: #ffecdf;"></span>
  843. <span style="background-color: #f2dfec;"></span>
  844. <span style="background-color: #ece6f2;"></span>
  845. <span style="background-color: #e6ece6;"></span>
  846. <span style="background-color: #f2f2df;"></span>
  847. <span style="background-color: #fff0df;"></span>
  848. <span style="background-color: #fceddf;"></span>
  849. <span style="background-color: #ffffff;"></span>
  850. </div>
  851. ';
  852. return implode("\n", $html);
  853. }
  854. }
  855. ?>