From b52be14a3de4c657f4af2ec5395a0d6e50ff6f14 Mon Sep 17 00:00:00 2001
From: Eno Mullaraj <emullaraj.a4b@gmail.com>
Date: Tue, 5 Nov 2019 23:54:49 +0100
Subject: [PATCH 1/2] [ADD] extension: FixedHeader extension

---
 Datatable/Extension/FixedHeader.php           | 168 ++++++++++++++++++
 Datatable/Extensions.php                      |  40 +++++
 Resources/doc/extensions.md                   |  62 +++++++
 .../views/datatable/extensions.html.twig      |  18 ++
 4 files changed, 288 insertions(+)
 create mode 100644 Datatable/Extension/FixedHeader.php

diff --git a/Datatable/Extension/FixedHeader.php b/Datatable/Extension/FixedHeader.php
new file mode 100644
index 00000000..1d58f007
--- /dev/null
+++ b/Datatable/Extension/FixedHeader.php
@@ -0,0 +1,168 @@
+<?php
+
+/*
+ * This file is part of the SgDatatablesBundle package.
+ *
+ * (c) stwe <https://github.com/stwe/DatatablesBundle>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Sg\DatatablesBundle\Datatable\Extension;
+
+use Exception;
+use Sg\DatatablesBundle\Datatable\OptionsTrait;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+
+class FixedHeader
+{
+    use OptionsTrait;
+
+    //-------------------------------------------------
+    // DataTables - FixedHeader Extension
+    //-------------------------------------------------
+
+    /**
+     * Enable / disable fixed footer
+     * Enable the fixing of the table footer (true) or disable (false).
+     * Required option.
+     *
+     * @var bool
+     */
+    protected $footer;
+
+    /**
+     * Offset the table's fixed footer
+     * Set the offset (in pixels) of the footer element's offset for the scrolling calculations.
+     * Optional.
+     *
+     * @var int
+     */
+    protected $footerOffset;
+
+    /**
+     * Enable / disable fixed header
+     * Enable the fixing of the table header (true) or disable (false).
+     * Optional.
+     *
+     * @var bool
+     */
+    protected $header;
+
+    /**
+     * Offset the table's fixed header
+     * Set the offset (in pixels) of the header element's offset for the scrolling calculations.
+     * Optional.
+     *
+     * @var int
+     */
+    protected $headerOffset;
+
+    public function __construct()
+    {
+        $this->initOptions();
+    }
+
+    //-------------------------------------------------
+    // Options
+    //-------------------------------------------------
+
+    /**
+     * @return $this
+     */
+    public function configureOptions(OptionsResolver $resolver)
+    {
+        $resolver->setDefined('footer');
+        $resolver->setDefined('footer_offset');
+        $resolver->setDefined('header');
+        $resolver->setDefined('header_offset');
+
+        $resolver->setAllowedTypes('footer', ['bool']);
+        $resolver->setAllowedTypes('footer_offset', ['int']);
+        $resolver->setAllowedTypes('header', ['bool']);
+        $resolver->setAllowedTypes('header_offset', ['int']);
+
+        return $this;
+    }
+
+    //-------------------------------------------------
+    // Getters && Setters
+    //-------------------------------------------------
+
+    /**
+     * @return bool
+     */
+    public function getFooter(): bool
+    {
+        return $this->footer;
+    }
+
+    /**
+     * @param bool $footer
+     * @return FixedHeader
+     */
+    public function setFooter(bool $footer): FixedHeader
+    {
+        $this->footer = $footer;
+
+        return $this;
+    }
+
+    /**
+     * @return int
+     */
+    public function getFooterOffset(): int
+    {
+        return $this->footerOffset;
+    }
+
+    /**
+     * @param int $footerOffset
+     * @return FixedHeader
+     */
+    public function setFooterOffset(int $footerOffset): FixedHeader
+    {
+        $this->footerOffset = $footerOffset;
+
+        return $this;
+    }
+
+    /**
+     * @return bool
+     */
+    public function getHeader(): bool
+    {
+        return $this->header;
+    }
+
+    /**
+     * @param bool $header
+     * @return FixedHeader
+     */
+    public function setHeader(bool $header): FixedHeader
+    {
+        $this->header = $header;
+
+        return $this;
+    }
+
+    /**
+     * @return int
+     */
+    public function getHeaderOffset(): int
+    {
+        return $this->headerOffset;
+    }
+
+    /**
+     * @param int $headerOffset
+     * @return FixedHeader
+     */
+    public function setHeaderOffset(int $headerOffset): FixedHeader
+    {
+        $this->headerOffset = $headerOffset;
+
+        return $this;
+    }
+}
diff --git a/Datatable/Extensions.php b/Datatable/Extensions.php
index 4f17638a..2bfb274c 100644
--- a/Datatable/Extensions.php
+++ b/Datatable/Extensions.php
@@ -15,6 +15,7 @@
 use Sg\DatatablesBundle\Datatable\Extension\Responsive;
 use Sg\DatatablesBundle\Datatable\Extension\RowGroup;
 use Sg\DatatablesBundle\Datatable\Extension\Select;
+use Sg\DatatablesBundle\Datatable\Extension\FixedHeader;
 use Symfony\Component\OptionsResolver\OptionsResolver;
 
 class Extensions
@@ -60,6 +61,15 @@ class Extensions
      */
     protected $rowGroup;
 
+    /**
+     * The FixedHeader Extension.
+     * Shows table's header and / or footer fixed to the top or bottom of the scrolling window.
+     * Default: null.
+     *
+     * @var array|bool|RowGroup|null
+     */
+    protected $fixedHeader;
+
     public function __construct()
     {
         $this->initOptions();
@@ -79,12 +89,14 @@ public function configureOptions(OptionsResolver $resolver)
             'responsive' => null,
             'select' => null,
             'row_group' => null,
+            'fixed_header' => null,
         ]);
 
         $resolver->setAllowedTypes('buttons', ['null', 'array', 'bool']);
         $resolver->setAllowedTypes('responsive', ['null', 'array', 'bool']);
         $resolver->setAllowedTypes('select', ['null', 'array', 'bool']);
         $resolver->setAllowedTypes('row_group', ['null', 'array', 'bool']);
+        $resolver->setAllowedTypes('fixed_header', ['null', 'array', 'bool']);
 
         return $this;
     }
@@ -194,4 +206,32 @@ public function setRowGroup($rowGroup)
 
         return $this;
     }
+
+
+
+    /**
+     * @return array|bool|FixedHeader|null
+     */
+    public function getFixedHeader()
+    {
+        return $this->fixedHeader;
+    }
+
+    /**
+     * @param array|bool|null $fixedHeader
+     *
+     * @return $this
+     * @throws \Exception
+     */
+    public function setFixedHeader($fixedHeader)
+    {
+        if (\is_array($fixedHeader)) {
+            $newFixedHeader = new FixedHeader();
+            $this->fixedHeader = $newFixedHeader->set($fixedHeader);
+        } else {
+            $this->fixedHeader = $fixedHeader;
+        }
+
+        return $this;
+    }
 }
diff --git a/Resources/doc/extensions.md b/Resources/doc/extensions.md
index eadb003f..31c1e6e9 100644
--- a/Resources/doc/extensions.md
+++ b/Resources/doc/extensions.md
@@ -4,6 +4,7 @@
 2. [Responsive](#2-responsive)
 3. [Select](#3-select)
 4. [RowGroup](#4-rowgroup)
+5. [FixedHeader](#5-fixedheader)
 
 ## 1. Buttons
 
@@ -360,3 +361,64 @@ With the RowGroup class you can set the following options, for details see the [
 | endRender         | array or null   | null  | Provide a function that can be used to control the data shown in the end grouping row. |
 | startRender       | array or null   | null  | Provide a function that can be used to control the data shown in the start grouping row. |
 ___
+
+## 5. FixedHeader
+
+**Be sure to install the [FixedHeader Extension](https://datatables.net/extensions/fixedheader/) before using.**
+
+### Template
+
+@SgDatatables/datatable/extensions.html.twig
+
+### Initialisation
+
+#### The easiest way
+
+The easiest way is to add `fixed_header` to your extensions options with the header/footer option defined respectively with `header` and `footer`.
+
+``` php
+public function buildDatatable(array $options = array())
+{
+    // ...
+
+    $this->extensions->set(array(
+        'fixed_header' => array(
+            'header' => true
+        ),
+    ));
+    
+    // ...
+}
+```
+
+#### Advanced example
+
+This example adds an offset to the header:
+
+``` php
+public function buildDatatable(array $options = array())
+{
+    // ...
+
+    $this->extensions->set(array(
+        'fixed_header' => array(
+            'header' => true,
+            'header_offset' => 50,
+        ),
+    ));
+    
+    // ...
+}
+```
+
+### FixedHeader class options
+
+With the FixedHeader class you can set the following options, for details see the [Plugin documentation](https://datatables.net/reference/option/#fixedheader).
+
+| Option    | Type            | Default |  Description                       |
+|-----------|-----------------|---------|------------------------------------|
+| footer           | boolean         | false  | Enable the fixing of the table footer (`true`) or disable (`false`) |
+| footerOffset     | integer         | 0      | Set the offset (in pixels) of the footer element's offset for the scrolling calculations |
+| header           | boolean         | false  | Enable the fixing of the table header (`true`) or disable (`false`) |
+| headerOffset     | integer         | 0      | Set the offset (in pixels) of the header element's offset for the scrolling calculations |
+___
diff --git a/Resources/views/datatable/extensions.html.twig b/Resources/views/datatable/extensions.html.twig
index 66dcba4e..fc428290 100644
--- a/Resources/views/datatable/extensions.html.twig
+++ b/Resources/views/datatable/extensions.html.twig
@@ -135,4 +135,22 @@
         startClassName: '{{ sg_datatables_view.extensions.rowGroup.startClassName }}'
     {% endif %}
     },
+{% endif %}
+
+{# FixedHeader Extension #}
+{% if sg_datatables_view.extensions.fixedHeader is not same as(null) %}
+    fixedHeader: {
+    {% if sg_datatables_view.extensions.fixedHeader.header is defined and sg_datatables_view.extensions.fixedHeader.header is same as(true) %}
+        header: true,
+    {% endif %}
+    {% if sg_datatables_view.extensions.fixedHeader.headerOffset is defined and sg_datatables_view.extensions.fixedHeader.headerOffset is not same as(null) %}
+        headerOffset: '{{ sg_datatables_view.extensions.fixedHeader.headerOffset }}',
+    {% endif %}
+    {% if sg_datatables_view.extensions.fixedHeader.footer is defined and sg_datatables_view.extensions.fixedHeader.footer is same as(true) %}
+        footer: true,
+    {% endif %}
+    {% if sg_datatables_view.extensions.fixedHeader.footerOffset is defined and sg_datatables_view.extensions.fixedHeader.footerOffset is not same as(null) %}
+        footerOffset: '{{ sg_datatables_view.extensions.fixedHeader.footerOffset }}',
+    {% endif %}
+    },
 {% endif %}
\ No newline at end of file

From f7b1225de2cd1f0a1719d5a19abbd9c86c1061da Mon Sep 17 00:00:00 2001
From: Eno Mullaraj <emullaraj.a4b@gmail.com>
Date: Wed, 6 Nov 2019 21:32:38 +0100
Subject: [PATCH 2/2] [IMP] extension: FixedHeader set default option values

---
 Datatable/Extension/FixedHeader.php            | 5 +++++
 Resources/views/datatable/extensions.html.twig | 8 ++++----
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/Datatable/Extension/FixedHeader.php b/Datatable/Extension/FixedHeader.php
index 1d58f007..e8cf3acf 100644
--- a/Datatable/Extension/FixedHeader.php
+++ b/Datatable/Extension/FixedHeader.php
@@ -83,6 +83,11 @@ public function configureOptions(OptionsResolver $resolver)
         $resolver->setAllowedTypes('header', ['bool']);
         $resolver->setAllowedTypes('header_offset', ['int']);
 
+        $resolver->setDefault('footer', false);
+        $resolver->setDefault('footer_offset', 0);
+        $resolver->setDefault('header', false);
+        $resolver->setDefault('header_offset', 0);
+
         return $this;
     }
 
diff --git a/Resources/views/datatable/extensions.html.twig b/Resources/views/datatable/extensions.html.twig
index fc428290..9972e77a 100644
--- a/Resources/views/datatable/extensions.html.twig
+++ b/Resources/views/datatable/extensions.html.twig
@@ -140,16 +140,16 @@
 {# FixedHeader Extension #}
 {% if sg_datatables_view.extensions.fixedHeader is not same as(null) %}
     fixedHeader: {
-    {% if sg_datatables_view.extensions.fixedHeader.header is defined and sg_datatables_view.extensions.fixedHeader.header is same as(true) %}
+    {% if sg_datatables_view.extensions.fixedHeader.header %}
         header: true,
     {% endif %}
-    {% if sg_datatables_view.extensions.fixedHeader.headerOffset is defined and sg_datatables_view.extensions.fixedHeader.headerOffset is not same as(null) %}
+    {% if sg_datatables_view.extensions.fixedHeader.headerOffset > 0 %}
         headerOffset: '{{ sg_datatables_view.extensions.fixedHeader.headerOffset }}',
     {% endif %}
-    {% if sg_datatables_view.extensions.fixedHeader.footer is defined and sg_datatables_view.extensions.fixedHeader.footer is same as(true) %}
+    {% if sg_datatables_view.extensions.fixedHeader.footer %}
         footer: true,
     {% endif %}
-    {% if sg_datatables_view.extensions.fixedHeader.footerOffset is defined and sg_datatables_view.extensions.fixedHeader.footerOffset is not same as(null) %}
+    {% if sg_datatables_view.extensions.fixedHeader.footerOffset > 0 %}
         footerOffset: '{{ sg_datatables_view.extensions.fixedHeader.footerOffset }}',
     {% endif %}
     },