1 Востаннє редагувалося Betterthanyou (23.10.2017 05:02:14)

Тема: Конвертувати таблицю в контейнер

Потрібно адаптувати старий сайт для мобільних телефоні і планшетів, цей сайт містить багато таблицю, які мають в залежності від пристрою адаптуватися під розмір екрану (для планшетів - зменшитися, для телефонів - стати списком), так як таблиця досить не зручна (наприклад, як таблицю можна показати у вигляді списку для мобільних телефонів ?) я вирішив конвертувати її в контейнер.
Написав клас для конвертації, але він досить "сирий" і взагалі я думаю що конвертацію можна зробити за допомогою регулярних виразів, але не знаю як.

class converToDiv
    {
        private $index = 0;
        private $beginTag = -1;
        private $endTag = -1;
        private $tagName = '';
        private $isTagOpened;
        private $HTML_table; 
        private $HTML_tableLen = -1;
        private $replaceTag = array();
        private $standardTags = true;
        private $namespace_ = '';
        private function replaceTagOnDiv()
        {
            if(!isset($this->replaceTag[$this->tagName])) return;
            
            $newTag = '<';
            if($this->isTagOpened)
            {
                $newTag .= 'div class="'.$this->replaceTag[$this->tagName].'"';
            }
            else
            {
                $newTag .= '/div';
            }
            $newTag .= '>';
            
            $pattern = substr(
                $this->HTML_table, 
                $this->beginTag, 
                $this->endTag - $this->beginTag + 1
                );

            $this->HTML_table = 
            str_replace($pattern, $newTag, $this->HTML_table);
            $this->index = $this->beginTag + strlen($newTag) - 1;
        }
        
        private function clearTagVar()
        {
            $this->beginTag = -1;
            $this->endTag = -1;
            $this->tagName = '';
            $this->isTagOpened = 0;
            $this->HTML_tableLen = strlen($this->HTML_table);
        }
        
        private function beginTagFun()
        {
            $this->beginTag = $this->index;
            
            //check that the tag is closed or opened
            if($this->HTML_table[++$this->index]=='/')
            {    
                $this->isTagOpened = false;
                //Go to the next symbol (skip a '/' symbol)
                ++$this->index;
            }
            else
            {
                $this->isTagOpened = true;
            }
            
            //Try to get the name
            do
            {
                if(
                    $this->HTML_table[$this->index] != ' ' &&
                    $this->HTML_table[$this->index] != '>'
                )
                    $this->tagName .= $this->HTML_table[$this->index];
                else
                    break;
                
            }
            while(
                /*If the loop goes beyond the possible values*/
                ++$this->index < $this->HTML_tableLen
            );
        }
        
        private function endTagFun()
        {
            $this->endTag = $this->index;
            //start to replace ...
            $this->replaceTagOnDiv();
            $this->clearTagVar();
        }
        
        private function skipQuotationMarks()
        {
            //determine the type of quotation marks
            $typeOfQuotationMarks = $this->HTML_table[$this->index];
            //skip quotation marks   
            while(
                $this->index < $this->HTML_tableLen &&
                $typeOfQuotationMarks != $this->HTML_table[++$this->index]
                );
        }
        
        private function findTag()
        {
            $insideTag = false;
            for($this->index = 0; $this->index < $this->HTML_tableLen; $this->index++)
            {
                if($this->HTML_table[$this->index]==='<')
                {
                    $this->beginTagFun();
                    $insideTag = true;
                }
                if ($this->HTML_table[$this->index]==='>') 
                {
                    $this->endTagFun();
                    $insideTag = false;
                }
                if (
                    ($this->HTML_table[$this->index]==='\'' ||
                    $this->HTML_table[$this->index]==='"') &&
                    $insideTag
                    ) 
                {
                    $this->skipQuotationMarks();
                }
            }
        }
        
        private function initStandardTags()
        {
            if( !$this->standardTags )
                return;
            $this->replaceTag['table'] = $this->namespace_ . 'styleTable';
            $this->replaceTag['tbody'] = $this->namespace_ . 'styleTbody';
            $this->replaceTag['th'] = $this->namespace_ . 'styleTh';
            $this->replaceTag['tr'] = $this->namespace_ . 'styleTr';
            $this->replaceTag['td'] = $this->namespace_ . 'styleTd';
            $this->replaceTag['caption'] = $this->namespace_ . 'styleCaption';
            $this->replaceTag['colgroup'] = $this->namespace_ . 'styleColgroup';
            $this->replaceTag['col'] = $this->namespace_ . 'styleCol';
            $this->replaceTag['thead'] = $this->namespace_ . 'styleThead';
            $this->replaceTag['tfoot'] = $this->namespace_ . 'styleTfoot';
        }
        
        public function printConvertedTable()
        {
            echo $this->HTML_table;
        }
        
        public function getConvertedTable()
        {
            return $this->HTML_table;
        }
        
        public function functionsetSpecificTags($currentTagName, $replacementTagName)
        {
            $this->replaceTag[strval($currentTagName)] = strval($replacementTagName);
        }
        
        public function setStandardTags($val)
        {
            $this->standardTags = boolval($val);
        }
        
        public function setHTMLTable($HTML_table)
        {
            $this->HTML_table = $HTML_table;
        }
        
        public function setNamespace($namespace_)
        {
            $this->namespace_ = $namespace_;
        }
        
        public function runConverToDiv()
        {
            $this->initStandardTags();
            $this->clearTagVar();
            $this->findTag();
        }

        function __construct($HTML_table, $namespace_ = '') 
        {
            $this->HTML_table = $HTML_table;
            $this->namespace_ = $namespace_;
        }
    }

Як з ним працювати:
1) Спочатку створюється об'єкт
в якості параметрів можна передати (перший параметр) весь HTML код, в такому випадку тегі що не відносяться до таблиці будуть пропущені, або HTML код таблиці
(другий параметр) простір імен для CSS. (не обов'язково)

$ob = new converToDiv($str, 'st_');

або створити об'єкт, і встановити функціями HTML код і простір імен

$ob = new converToDiv();
$ob->setHTMLTable($str);
$ob->setNamespace( 'st_' );

2) (не обов'язково) Вказати чи використовувати стандартні тегі, які відносяться до таблиці. Під стандартними тегами мається на увазі:
table, tbody, th, tr, td, caption, colgroup, col, thead, tfoot

$ob->setStandardTags(true);

якщо встановити false - масив тегів буде пустий
3) (не обов'язково) Додати нові тегі які потрібно замінити
$currentTagName - який тег потрібно знайти і замінити
$replacementTagName - на що потрібно замінити

$ob->setSpecificTags($currentTagName, $replacementTagName);

4) Виконати конвертацію

$ob->runConverToDiv();

5) Отримати результат
Вивести результат

$ob->printConvertedTable(); 

Або
Отримати у вигляді рядка

$ob->getConvertedTable();

CSS класи будуть називатися
[простір імен]_style[тег, перший символ великий];
наприклад:
[простір імен] = my_,
[тег, перший символ великий] = table,
my_styleTable;

Ну, а дальше пишіть CSS стилі, наприклад так

.st_styleTr 
{
    display: -webkit-flex;
    display: flex;
    -webkit-justify-content: center;
    justify-content: center;
    border-color: red;
    border-style: solid;
    border-width: 1px;
}
.st_styleTd
{
    height: auto;
    margin: 1px auto;
    padding: 2px;
    border-color: green;
    border-style: solid;
    border-width: 1px;
    width: -webkit-fill-available;
}

Замітка:
- Звичайно, цей клас потрібно використати для заміні таблиці, але не фільтрації вмісту при відкриті сторінки, тому що цей клас забирає багато ресурсів і сповільнює роботу сторінки
- Щоб цей клас нічого "зайвого" не зробив, варто зробити резервну копію сайту і попередньо перевірити чи точно сторінка має таблиці

if( strpos($content, '<table') === false ) return $content;
$ob = new converToDiv($str, 'st_');
...

- Клас не розрахований на помилки, тобто якщо якийсь тег не буде закриватися, чи ще щось подібне станеться, результат буде непередбачуваний

Можливо хтось стикався з проблемою адаптації таблиці під мобільні телефони і планшети, як це вирішується ?

Якщо хтось зацікавлений в цьому класі, допоможіть доробити "об'єднання комірок", поки що цей клас ніяк не реагує на об'єднання комірок, і можливо зробити його "біль продуманим".
Клас не прокоментований, бо він відносно малий, думаю вам буде зрозуміло як він працює і без коментарів.

Подякували: 221VOLT1