Parcourir la source

Merge branch 'feature/async-table' into github

jqh il y a 4 ans
Parent
commit
0417f3cf37

+ 0 - 1
composer.json

@@ -13,7 +13,6 @@
     ],
     "require": {
         "php": ">=7.1.0",
-        "symfony/dom-crawler": "~3.1|~4.0|~5.0",
         "laravel/framework": "~5.5|~6.0|~7.0|~8.0",
         "spatie/eloquent-sortable": "3.*|4.*"
     },

+ 159 - 0
resources/views/grid/async-table.blade.php

@@ -0,0 +1,159 @@
+@if($grid->isAsyncRequest())
+    {!! $grid->renderHeader() !!}
+
+    <div class="{!! $grid->formatTableParentClass() !!}">
+        <table class="{{ $grid->formatTableClass() }}" id="{{ $tableId }}" >
+            <thead>
+            @if ($headers = $grid->getVisibleComplexHeaders())
+                <tr>
+                    @foreach($headers as $header)
+                        {!! $header->render() !!}
+                    @endforeach
+                </tr>
+            @endif
+            <tr>
+                @foreach($grid->getVisibleColumns() as $column)
+                    <th {!! $column->formatTitleAttributes() !!}>{!! $column->getLabel() !!}{!! $column->renderHeader() !!}</th>
+                @endforeach
+            </tr>
+            </thead>
+
+            @if ($grid->hasQuickCreate())
+                {!! $grid->renderQuickCreate() !!}
+            @endif
+
+            <tbody>
+            @foreach($grid->rows() as $row)
+                <tr {!! $row->rowAttributes() !!}>
+                    @foreach($grid->getVisibleColumnNames() as $name)
+                        <td {!! $row->columnAttributes($name) !!}>
+                            {!! $row->column($name) !!}
+                        </td>
+                    @endforeach
+                </tr>
+            @endforeach
+            @if ($grid->rows()->isEmpty())
+                <tr>
+                    <td colspan="{!! count($grid->getVisibleColumnNames()) !!}">
+                        <div style="margin:5px 0 0 10px;"><span class="help-block" style="margin-bottom:0"><i class="feather icon-alert-circle"></i>&nbsp;{{ trans('admin.no_data') }}</span></div>
+                    </td>
+                </tr>
+            @endif
+            </tbody>
+        </table>
+    </div>
+
+    {!! $grid->renderFooter() !!}
+
+    {!! $grid->renderPagination() !!}
+
+@else
+    <div class="dcat-box async-{{ $tableId }}">
+
+        <div class="d-block pb-0">
+            @include('admin::grid.table-toolbar')
+        </div>
+
+        {!! $grid->renderFilter() !!}
+
+        <div class="async-body">
+            <div class="{!! $grid->formatTableParentClass() !!}">
+                <table class="{{ $grid->formatTableClass() }}" id="{{ $tableId }}" >
+                    <thead>
+                    @if ($headers = $grid->getVisibleComplexHeaders())
+                        <tr>
+                            @foreach($headers as $header)
+                                {!! $header->render() !!}
+                            @endforeach
+                        </tr>
+                    @endif
+                    <tr>
+                        @foreach($grid->getVisibleColumns() as $column)
+                            <th {!! $column->formatTitleAttributes() !!}>{!! $column->getLabel() !!}{!! $column->renderHeader() !!}</th>
+                        @endforeach
+                    </tr>
+                    </thead>
+
+                    <tbody>
+                    <tr>
+                        <td colspan="{!! count($grid->getVisibleColumnNames()) !!}">
+                            &nbsp;
+                        </td>
+                    </tr>
+                    </tbody>
+                </table>
+            </div>
+        </div>
+
+    <script>
+    Dcat.ready(function () {
+        var reqName = '{!! Dcat\Admin\Grid::ASYNC_NAME !!}',
+            $box = $('.async-{{ $tableId }}'),
+            $body = $box.find('.async-body'),
+            url = '{!! $asyncUrl !!}',
+            loading = false;
+
+        function render(url) {
+            if (loading || url.indexOf('javascript:') !== -1) {
+                return;
+            }
+            loading = true;
+
+            $body.find('table').loading({style:'height:250px', background:'transparent'});
+
+            if (url.indexOf('?') === -1) {
+                url += '?';
+            }
+
+            if (url.indexOf(reqName) === -1) {
+                url += '&'+reqName+'=1'
+            }
+
+            history.pushState({}, '', url.replace(reqName+'=1', ''));
+
+            $box.data('current', url);
+
+            Dcat.helpers.asyncRender(url, function (html) {
+                loading = false;
+
+                $body.html(html);
+
+                $box.find('.grid-refresh').off('click').on('click', function () {
+                    render($box.data('current'));
+
+                    return false;
+                });
+
+                $box.find('.pagination .page-link').on('click', loadLink);
+                $box.find('.per-pages-selector .dropdown-item a').on('click', loadLink);
+                $box.find('.grid-column-header a').on('click', loadLink);
+
+                $box.find('form').off('submit').on('submit', function () {
+                    var action = $(this).attr('action');
+                    if (action.indexOf('?') === -1) {
+                        action += '?';
+                    }
+
+                    render(action+'&'+$(this).serialize());
+
+                    return false;
+                });
+
+                $box.find('.filter-box .reset').on('click', loadLink);
+
+                $box.find('.grid-selector a').on('click', loadLink);
+            });
+        }
+
+        function loadLink() {
+            render($(this).attr('href'));
+
+            return false;
+        }
+
+        // $table.on('grid:render', render);
+
+        render(url);
+    });
+    </script>
+@endif

+ 0 - 2
resources/views/grid/table.blade.php

@@ -56,5 +56,3 @@
     {!! $grid->renderPagination() !!}
 
 </div>
-
-

+ 50 - 1
src/Admin.php

@@ -13,6 +13,7 @@ use Dcat\Admin\Layout\Navbar;
 use Dcat\Admin\Layout\SectionManager;
 use Dcat\Admin\Repositories\EloquentRepository;
 use Dcat\Admin\Support\Composer;
+use Dcat\Admin\Support\Helper;
 use Dcat\Admin\Traits\HasAssets;
 use Dcat\Admin\Traits\HasHtml;
 use Dcat\Admin\Traits\HasPermissions;
@@ -30,7 +31,7 @@ class Admin
     use HasAssets;
     use HasHtml;
 
-    const VERSION = '2.0.24-beta';
+    const VERSION = '2.0.3-beta';
 
     const SECTION = [
         // 往 <head> 标签内输入内容
@@ -379,6 +380,54 @@ class Admin
         return static::context()->ignoreQueries ?? [];
     }
 
+    /**
+     * 输入直接渲染的内容.
+     *
+     * @param mixed $value
+     */
+    public static function content($value)
+    {
+        static::context()->add('contents', $value);
+    }
+
+    /**
+     * @return bool
+     */
+    public static function hasContents()
+    {
+        return count(static::context()->getArray('contents')) > 0;
+    }
+
+    /**
+     * 渲染内容.
+     *
+     * @return string
+     */
+    public static function renderContents()
+    {
+        $contents = static::context()->getArray('contents');
+
+        $results = '';
+
+        foreach ($contents as $content) {
+            $results .= Helper::render($content);
+        }
+
+        $asset = static::asset();
+
+        Admin::baseCss([], false);
+        Admin::baseJs([], false);
+        Admin::headerJs([], false);
+
+        $results .= Admin::html()
+            .$asset->jsToHtml()
+            .$asset->cssToHtml()
+            .$asset->scriptToHtml()
+            .$asset->styleToHtml();
+
+        return $results;
+    }
+
     /**
      * 响应json数据.
      *

+ 60 - 0
src/Grid.php

@@ -40,6 +40,7 @@ class Grid
 
     const CREATE_MODE_DEFAULT = 'default';
     const CREATE_MODE_DIALOG = 'dialog';
+    const ASYNC_NAME = '_async_';
 
     /**
      * The grid data model instance.
@@ -183,6 +184,11 @@ class Grid
      */
     protected $show = true;
 
+    /**
+     * @var bool
+     */
+    protected $async = false;
+
     /**
      * Create a new grid instance.
      *
@@ -272,6 +278,48 @@ class Grid
         return $this->addColumn('#', $label ?: '#');
     }
 
+    /**
+     * 启用异步渲染功能.
+     *
+     * @param bool $async
+     *
+     * @return $this
+     */
+    public function async(bool $async = true)
+    {
+        $this->async = $async;
+
+        if ($async) {
+            $url = Helper::fullUrlWithoutQuery(['_pjax']);
+
+            $this->view('admin::grid.async-table');
+            $this->addVariables([
+                'currentUrl' => $url,
+                'asyncUrl'   => Helper::urlWithQuery($url, [static::ASYNC_NAME => 1]),
+            ]);
+        }
+
+        return $this;
+    }
+
+    /**
+     * 判断是否允许查询数据.
+     *
+     * @return bool
+     */
+    public function buildable()
+    {
+        return ! $this->async || $this->isAsyncRequest();
+    }
+
+    /**
+     * @return bool
+     */
+    public function isAsyncRequest()
+    {
+        return $this->request->get(static::ASYNC_NAME);
+    }
+
     /**
      * Batch add column to grid.
      *
@@ -431,6 +479,18 @@ class Grid
      */
     public function build()
     {
+        if (! $this->buildable()) {
+            $this->callBuilder();
+            $this->handleExportRequest();
+
+            $this->prependRowSelectorColumn();
+            $this->appendActionsColumn();
+
+            $this->sortHeaders();
+
+            return;
+        }
+
         if ($this->built) {
             return;
         }

+ 1 - 1
src/Grid/LazyRenderable.php

@@ -89,7 +89,7 @@ HTML;
             $visibleColumn && $grid->rowSelector()->titleColumn($visibleColumn);
         }
 
-        return $grid;
+        return $grid->async(false);
     }
 
     /**

+ 1 - 1
src/Grid/Tools/PerPageSelector.php

@@ -86,7 +86,7 @@ class PerPageSelector implements Renderable
             ->render();
 
         return <<<EOT
-<label class="pull-right d-none d-sm-inline" style="margin-right: 10px">
+<label class="pull-right d-none d-sm-inline per-pages-selector" style="margin-right: 10px">
     $dropdown
 </label>
 EOT;

+ 0 - 68
src/Http/Middleware/Pjax.php

@@ -6,7 +6,6 @@ use Closure;
 use Dcat\Admin\Admin;
 use Illuminate\Http\Request;
 use Illuminate\Support\MessageBag;
-use Symfony\Component\DomCrawler\Crawler;
 use Symfony\Component\HttpFoundation\Response;
 
 class Pjax
@@ -64,73 +63,6 @@ class Pjax
         return back()->withInput()->withErrors($error, 'exception');
     }
 
-    /**
-     * Prepare the PJAX-specific response content.
-     *
-     * @param Response $response
-     * @param string   $container
-     *
-     * @return $this
-     */
-    protected function filterResponse(Response $response, $container)
-    {
-        $crawler = new Crawler($response->getContent());
-
-        $response->setContent(
-            $this->makeTitle($crawler).
-            $this->fetchContents($crawler, $container)
-        );
-
-        return $this;
-    }
-
-    /**
-     * Prepare an HTML title tag.
-     *
-     * @param Crawler $crawler
-     *
-     * @return string
-     */
-    protected function makeTitle($crawler)
-    {
-        $pageTitle = $crawler->filter('head > title')->html();
-
-        return "<title>{$pageTitle}</title>";
-    }
-
-    /**
-     * Fetch the PJAX-specific HTML from the response.
-     *
-     * @param Crawler $crawler
-     * @param string  $container
-     *
-     * @return string
-     */
-    protected function fetchContents($crawler, $container)
-    {
-        $content = $crawler->filter($container);
-
-        if (! $content->count()) {
-            abort(422);
-        }
-
-        return $this->decodeUtf8HtmlEntities($content->html());
-    }
-
-    /**
-     * Decode utf-8 characters to html entities.
-     *
-     * @param string $html
-     *
-     * @return string
-     */
-    protected function decodeUtf8HtmlEntities($html)
-    {
-        return preg_replace_callback('/(&#[0-9]+;)/', function ($html) {
-            return mb_convert_encoding($html[1], 'UTF-8', 'HTML-ENTITIES');
-        }, $html);
-    }
-
     /**
      * Set the PJAX-URL header to the current uri.
      *

+ 5 - 5
src/Layout/Asset.php

@@ -587,13 +587,13 @@ class Asset
      *
      * @param string|array $js
      */
-    public function headerJs($js)
+    public function headerJs($js, bool $merge = true)
     {
-        if (! $js) {
-            return;
+        if ($merge) {
+            $this->headerJs = $js ? array_merge($this->headerJs, (array) $js) : $this->headerJs;
+        } else {
+            $this->headerJs = (array) $js;
         }
-
-        $this->headerJs = array_merge($this->headerJs, (array) $js);
     }
 
     /**

+ 7 - 0
src/Layout/Column.php

@@ -2,6 +2,8 @@
 
 namespace Dcat\Admin\Layout;
 
+use Dcat\Admin\Admin;
+use Dcat\Admin\Grid;
 use Dcat\Admin\Support\Helper;
 use Illuminate\Contracts\Support\Renderable;
 
@@ -97,6 +99,11 @@ class Column implements Renderable
         $html = $this->startColumn();
 
         foreach ($this->contents as $content) {
+            if ($content instanceof Grid && $content->isAsyncRequest()) {
+                Admin::content($content->render());
+
+                continue;
+            }
             $html .= Helper::render($content);
         }
 

+ 4 - 0
src/Layout/Content.php

@@ -535,6 +535,10 @@ class Content implements Renderable
 
         $this->callComposed();
 
+        if (Admin::hasContents()) {
+            return Admin::renderContents();
+        }
+
         return view($this->view, $this->variables())->render();
     }
 

+ 1 - 0
src/Support/Context.php

@@ -15,6 +15,7 @@ use Illuminate\Support\Fluent;
  * @property array|null $ignoreQueries
  * @property array|null $jsVariables
  * @property string $translation
+ * @property array $contents
  */
 class Context extends Fluent
 {

+ 3 - 2
src/Traits/HasAssets.php

@@ -62,12 +62,13 @@ trait HasAssets
      * Add js.
      *
      * @param string|array $js
+     * @param bool $merge
      *
      * @return void
      */
-    public static function headerJs($js)
+    public static function headerJs($js, bool $merge = true)
     {
-        static::asset()->headerJs($js);
+        static::asset()->headerJs($js, $merge);
     }
 
     /**