CMS своими руками

Глава 2

Построение таблицы данных GRID по JSON файлу с возможностью редактирования

Создадим компонент GRID для редактирования текстовых файлов в формате JSON

В этом компоненте бизнес- логика будет на PHP, ядровая часть на PHP, JQUERY, HTML, CSS

Проект состоит из файлов:

file.json - исходный файл с данными

file_grid.js - Java Script файл с вспомогательными функциями

file_grid.php - файл с бизнес логикой

lib.php - файл с библиотекой

utils.php - файл с общими вспомогательными функциями

jquery-3.7.1.min.js - файл библиотеки Jquery, который можно взять с jquery.com

Все файлы лежат в одной папке. Точкой входа в проект является файл file_grid.php.

При запуске отображается таблица, которую можно редактировать.

Отображение таблицы<br />
Отображение таблицы

Любое значение таблицы можно поменять и сохранить в исходный файл. Войти в редактирование - двойной щелчок мыши, отменить изменение Ctrl+Z, запостить - сместить мышкой фокус на другую ячейку или область экрана. Сохранит данные на сервере - нажатие кнопки “Сохранить”.

редактирование таблицы<br />
редактирование таблицы

При нажатии на кнопку “Сохранить” вызывается событие в PHP файле, в котором происходит сохранение и выдается сообщение “Сохранено!”.

CMS своими руками

Данные в исходном файле file.json:

[ { "name": "Samsung", "price": "51201.62" }, { "name": "Lg", "price": "5400.6" }, { "name": "Alcatel", "price": "4503.6" } ]

Формат исходных данных представляет из себя набор записей с одинаковым количеством столбцов в каждой из них.

Состав файла file_grid.js:

/* grid library source http://xn--80aq1a.xn--p1ai */ $(document).ready(function(){ $( "body" ).delegate( '[change_cell]', "change", function(event) { id = $(this).attr('id'); parentid = $(this).attr('parentid'); val = event.target.value; v = $('JSN').text(); jsn = JSON.parse(v); if(jsn){ jsn[parentid][id] = val; }; s = JSON.stringify(jsn); $('JSN').text(s); }); function getparams($attr){ req = '['; if($attr){ jsn = JSON.parse($attr); var name; var param; var attrname; var value; for (var i = 0; i < jsn.length; i++) { name = jsn[i].name; id = jsn[i].id; param = jsn[i].param; attrname = jsn[i].attrname; var type = jsn[i].type; if(type==="value"){ if(name) value = $('[name='+name+']').val(); if(id) value = $('[id='+id+']').val(); } if(type==="attr"){ if(name) value = $('[name='+name+']').attr(attrname); if(id) value = $('[id='+id+']').attr(attrname); } if(type==="text"){ if(name) value = $('[name='+name+']').text(); if(id) value = $('[id='+id+']').text(); } if(type==="html"){ if(name) value = $('[name='+name+']').html(); if(id) value = $('[id='+id+']').html(); } if(req!=='[') req = req+','; req = req+'{"'+param+'":"'+encodeURI(value)+'"}'; } } req = req+']'; return req; } $( "body" ).delegate( '[click]', "click", function() { req = getparams($(this).attr('request')); $.post( 'file_grid.php', {type:"event", name:$(this).attr('click'), request:req}, onSuccess ); }); function onSuccess(data) { jsn = JSON.parse(data); if(!jsn.exec==''){ eval(jsn.exec); } if(!jsn.message==''){ alert(jsn.message); } } });

В java-script файле file_grid.js реализовано делегирование события изменения ячейки change, при котором записывает значение ячейки в JSON объект HTML формы. JSON объект хранится в теге JSN. Так же реализовано делегирование события click кнопки сохранения таблицы, из него вызывается событие в PHP файле, где и происходит это изменение. Вспомогательная функция getparams формирует JSON для передачи из JS скрипта в PHP событие.

Состав файла file_grid.php:

<?php include('utils.php'); function event_click($data){ $mes = 'Сохранено!'; $text = urldecode(getval($data, 'jsn')); $file = urldecode(getval($data, 'file')); file_put_contents($file, $text); $jsn = json_encode(['result'=>'OK', 'message'=>$mes]); return $jsn; } if(isset($_POST['type'])){ if($_POST['type'] == 'event'){ if(isset($_POST['name'])){ $request = array(); if(isset($_POST['request'])){ $request = $_POST['request']; } echo call_user_func($_POST['name'], $request); } } } else { include('lib.php'); echo '<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>edited grid</title> <script src="jquery-3.7.1.min.js"></script> <script src="file_grid.js"></script> </head> <body>'; $e = new file_grid; $e->id = 'file_grid'; $e->file = 'file.json'; echo $e->print(); echo ' </body> </html>'; }

Файл file_grid.php служит для первоначальной отрисовки таблицы, а так же для обработки событий, которые вызываются из браузера. event_click - событие сохранения таблицы. call_user_func - стандартная функция PHP для CALLBACK вызова event_click. Переменная $e содержит экземпляр класса, который описан в файле lib.php. $e->print() - вывод на экран таблицы данных.

состав файла lib.php:

<?php /* grid library source http://xn--80aq1a.xn--p1ai */ define('STYLE', '<style> grid{ border-top: 1px solid black; border-left: 1px solid black; display: table; } row{ display: table-row; } cell{ display: table-cell; border-right: 1px solid black; border-bottom: 1px solid black; } hrow{ display: table-row; } hcell{ background-color: grey; color: white; display: table-cell; border-right: 1px solid black; border-bottom: 1px solid black; } JSN{ display: none; } </style>'); define('CONTENT', '%content%'); define('ID', '%id%'); define('PARENTID', '%parentid%'); define('ELEMENT', '<div id='.ID.' >' . CONTENT . '</div>'); define('CELL', '<cell name=cell_'.PARENTID.'_'.ID.' '. 'id='.ID.' parentid='.PARENTID.' '. 'change_cell="" '. 'ondblclick=" '. "elem1 = $('[name=cell_".PARENTID."_".ID."]'); ". 'cont = elem1.text(); '. 'elem1.empty(); '. 'elem1.append(&quot;<textarea '. 'name=textarea_'.PARENTID.'_'.ID.' '. "onfocusout=\&quot; ". "elem1 = $('[name=cell_".PARENTID."_".ID."]'); ". "elem2 = $('[name=textarea_".PARENTID."_".ID."]'); ". 'cont = elem2.val(); '. 'elem1.empty(); '. 'elem2.remove(); '. 'elem1.append(cont); '. '\&quot;>&quot;+cont+&quot;</textarea>&quot;); '. 'elem2 = $(&quot;[name=textarea_'.PARENTID.'_'.ID.']&quot;); '. 'elem2.focus(); '. '" '. '>' . CONTENT . '</cell>'); define('ROW', '<row id='.ID.' >' . CONTENT . '</row>'); define('HCELL', '<hcell>' . CONTENT . '</hcell>'); define('HROW', '<hrow id='.ID.' >' . CONTENT . '</hrow>'); define('GRID', STYLE.'<grid id='.ID.' >' . CONTENT . '</grid>'); define('SAVE_CONTENT', 'Сохранить'); define('JSN', '%jsn%'); define('JSN_NAME', 'JSN_NAME'); define('JSN_CONT', '<JSN name='.JSN_NAME.'>'.JSN.'</JSN>'); define('BUTTON_SAVE', '<button name=button_save click=event_click '. 'request=[{"type":"text","name":"'.JSN_NAME.'","param":"jsn"},'. '{"type":"attr","attrname":"file","id":"'.ID.'","param":"file"}] '. '>' . SAVE_CONTENT . '</button>'); define('FILE_NAME', '%file_name%'); define('FILE_GRID', STYLE.'<grid id='.ID.' file= '.FILE_NAME.' >' . CONTENT . JSN_CONT . BUTTON_SAVE. '</grid>'); class element { public $template; public $content; public $child; public $id; public $hasparent; public $parentid; public function __construct() { if(!isset($this->template)){ $this->template = ELEMENT; } $this->content = array(); } function getclass() { if(isset($this->child)){ return new $this->child; } else { return new element; } } public function print($content='') { if (is_array($this->content)) { //$content = ''; foreach ($this->content as $k=>$value) { $e = $this->getclass(); $e->content = $value; $e->id = $k; if($e->hasparent){ $e->parentid = $this->id; } $content .= $e->print(); } } else { $content = $content.$this->content; } $ret = str_replace( array(ID, CONTENT, PARENTID), array($this->id, $content, $this->parentid), $this->template); return $ret; } } class cell extends element { public function __construct() { $this->template = CELL; $this->hasparent = true; parent::__construct(''); } } class row extends element { public function __construct() { $this->template = ROW; $this->child = 'cell'; parent::__construct(); } } class hcell extends element { public function __construct() { $this->template = HCELL; $this->hasparent = true; parent::__construct(''); } } class hrow extends element { public function __construct() { $this->template = HROW; $this->child = 'hcell'; parent::__construct(); } } class grid extends element { public $header; public function __construct() { $this->template = GRID; $this->child = 'row'; parent::__construct(); } public function print($content='') { $e = new hrow; $e->content = $this->header; $content = $e->print(); return parent::print($content); } } class file_grid extends grid { public $file; public $json; public function __construct() { parent::__construct(); $this->template = FILE_GRID; } public function print($content='') { //$this->header = array('1'=>'column1','2'=>'column2'); $this->json = file_get_contents($this->file); $arr = json_decode($this->json, true); foreach ($arr as $key => $value) { foreach ($value as $vkey => $vvalue) { $this->header[] = $vkey; } break; } $this->content = $arr; $ret = parent::print(''); $ret = str_replace( array(JSN, FILE_NAME), array($this->json, $this->file), $ret); return $ret; } }

В файле lib.php описаны базовые константы через стандартную функцию defile, а так же описана иерархия классов. Базовым классом является ELEMENT. Далее от него наследуется ROW, CELL, GRID. От GRID наследуется FILE_GRID. В каждом классе прописана своя специфическая логика. В константах задана как HTML, CSS разметка, так и события JAVA SCRIPT, такие как DBLCLICK и FOCUSOUT. Классы используют эти константы чтоб отрисовывать в статике и динамике HTML разметку.

Состав файла utils.php:

<?php /* grid library source http://xn--80aq1a.xn--p1ai */ function getval($data, $name){ $rjsn = json_decode($data, true); foreach ($rjsn as $vjsn){ foreach ($vjsn as $key => $value) { if($name == $key){ return $value; } } } return 'undefined'; }

Функция getval используется для получения значения параметра по имени внутри PHP события.

Таким образом реализована редактируемая табличная форма данных, получаемая из JSON файла.

Начать дискуссию