forked from moodle/moodle
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MDL-75401 core: sticky footer component
- Loading branch information
1 parent
f8d28e4
commit 3d483ac
Showing
14 changed files
with
476 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
<?php | ||
// This file is part of Moodle - http://moodle.org/ | ||
// | ||
// Moodle is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Moodle is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
namespace core\output; | ||
|
||
use renderable; | ||
|
||
/** | ||
* Class to render a sticky footer element. | ||
* | ||
* Sticky footer can be rendered at any moment if the page (even inside a form) but | ||
* it will be displayed at the bottom of the page. | ||
* | ||
* Important: note that pages can only display one sticky footer at once. | ||
* | ||
* Important: not all themes are compatible with sticky footer. If the current theme | ||
* is not compatible it will be rendered as a standard div element. | ||
* | ||
* @package core | ||
* @category output | ||
* @copyright 2022 Ferran Recio <[email protected]> | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
class sticky_footer implements named_templatable, renderable { | ||
|
||
/** | ||
* @var string content of the sticky footer. | ||
*/ | ||
protected $stickycontent = ''; | ||
|
||
/** | ||
* @var string extra CSS classes. By default, elements are justified to the end. | ||
*/ | ||
protected $stickyclasses = 'justify-content-end'; | ||
|
||
/** | ||
* @var array extra HTML attributes (attribute => value). | ||
*/ | ||
protected $attributes = []; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param string $stickycontent the footer content | ||
* @param string|null $stickyclasses extra CSS classes | ||
* @param array $attributes extra html attributes (attribute => value) | ||
*/ | ||
public function __construct(string $stickycontent = '', ?string $stickyclasses = null, array $attributes = []) { | ||
$this->stickycontent = $stickycontent; | ||
if ($stickyclasses !== null) { | ||
$this->stickyclasses = $stickyclasses; | ||
} | ||
$this->attributes = $attributes; | ||
} | ||
|
||
/** | ||
* Set the footer contents. | ||
* | ||
* @param string $stickycontent the footer content | ||
*/ | ||
public function set_content(string $stickycontent) { | ||
$this->stickycontent = $stickycontent; | ||
} | ||
|
||
/** | ||
* Add extra classes to the sticky footer. | ||
* | ||
* @param string $stickyclasses the extra classes | ||
*/ | ||
public function add_classes(string $stickyclasses) { | ||
if (!empty($this->stickyclasses)) { | ||
$this->stickyclasses .= ' '; | ||
} | ||
$this->stickyclasses = $stickyclasses; | ||
} | ||
|
||
/** | ||
* Add extra attributes to the sticky footer element. | ||
* | ||
* @param string $atribute the attribute | ||
* @param string $value the value | ||
*/ | ||
public function add_attribute(string $atribute, string $value) { | ||
$this->attributes[$atribute] = $value; | ||
} | ||
|
||
/** | ||
* Export this data so it can be used as the context for a mustache template (core/inplace_editable). | ||
* | ||
* @param renderer_base $output typically, the renderer that's calling this function | ||
* @return array data context for a mustache template | ||
*/ | ||
public function export_for_template(\renderer_base $output) { | ||
$extras = []; | ||
foreach ($this->attributes as $attribute => $value) { | ||
$extras[] = [ | ||
'attribute' => $attribute, | ||
'value' => $value, | ||
]; | ||
} | ||
return [ | ||
'stickycontent' => (string)$this->stickycontent, | ||
'stickyclasses' => $this->stickyclasses, | ||
'extras' => $extras, | ||
]; | ||
} | ||
|
||
/** | ||
* Get the name of the template to use for this templatable. | ||
* | ||
* @param \renderer_base $renderer The renderer requesting the template name | ||
* @return string the template name | ||
*/ | ||
public function get_template_name(\renderer_base $renderer): string { | ||
return 'core/sticky_footer'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
{{! | ||
This file is part of Moodle - http://moodle.org/ | ||
Moodle is free software: you can redistribute it and/or modify | ||
it under the terms of the GNU General Public License as published by | ||
the Free Software Foundation, either version 3 of the License, or | ||
(at your option) any later version. | ||
Moodle is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
GNU General Public License for more details. | ||
You should have received a copy of the GNU General Public License | ||
along with Moodle. If not, see <http://www.gnu.org/licenses/>. | ||
}} | ||
{{! | ||
@template core/sticky_footer | ||
Displays a page sticky footer element. | ||
Sticky footer behaviour depends on the theme. The default template is | ||
a regular element. | ||
Example context (json): | ||
{ | ||
"stickycontent" : "<a href=\"#\">Moodle</a>", | ||
"extras" : [ | ||
{ | ||
"attribute" : "data-example", | ||
"value" : "stickyfooter" | ||
} | ||
], | ||
"stickyclasses" : "extraclasses" | ||
} | ||
}} | ||
<div | ||
id="sticky-footer" | ||
class="{{$ stickyclasses }}{{stickyclasses}}{{/ stickyclasses }}" | ||
{{#extras}} | ||
{{attribute}}="{{value}}" | ||
{{/extras}} | ||
> | ||
{{$ stickycontent }} | ||
{{{stickycontent}}} | ||
{{/ stickycontent }} | ||
</div> |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
// This file is part of Moodle - http://moodle.org/ | ||
// | ||
// Moodle is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
// | ||
// Moodle is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
// | ||
// You should have received a copy of the GNU General Public License | ||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
/** | ||
* Sticky footer module. | ||
* | ||
* @module theme_boost/sticky-footer | ||
* @copyright 2022 Ferran Recio <[email protected]> | ||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | ||
*/ | ||
|
||
import Pending from 'core/pending'; | ||
|
||
const SELECTORS = { | ||
STICKYFOOTER: '.stickyfooter', | ||
PAGE: '#page', | ||
}; | ||
|
||
const CLASSES = { | ||
HASSTICKYFOOTER: 'hasstickyfooter', | ||
}; | ||
|
||
let initialized = false; | ||
|
||
let previousScrollPosition = 0; | ||
|
||
/** | ||
* Return the current page scroll position. | ||
* @package | ||
* @returns {number} the current scroll position | ||
*/ | ||
const getScrollPosition = () => { | ||
const page = document.querySelector(SELECTORS.PAGE); | ||
if (page) { | ||
return page.scrollTop; | ||
} | ||
return window.pageYOffset; | ||
}; | ||
|
||
/** | ||
* Scroll handler. | ||
* @package | ||
*/ | ||
const scrollSpy = () => { | ||
// Ignore scroll if page size is not small. | ||
if (document.body.clientWidth >= 768) { | ||
return; | ||
} | ||
// Detect if scroll is going down. | ||
let scrollPosition = getScrollPosition(); | ||
if (scrollPosition > previousScrollPosition) { | ||
disableStickyFooter(); | ||
} else { | ||
enableStickyFooter(); | ||
} | ||
previousScrollPosition = scrollPosition; | ||
}; | ||
|
||
/** | ||
* Enable sticky footer in the page. | ||
*/ | ||
export const enableStickyFooter = () => { | ||
// We need some seconds to make sure the CSS animation is ready. | ||
const pendingPromise = new Pending('theme_boost/sticky-footer:enabling'); | ||
const footer = document.querySelector(SELECTORS.STICKYFOOTER); | ||
const page = document.querySelector(SELECTORS.PAGE); | ||
if (footer && page) { | ||
document.body.classList.add(CLASSES.HASSTICKYFOOTER); | ||
page.classList.add(CLASSES.HASSTICKYFOOTER); | ||
} | ||
setTimeout(() => pendingPromise.resolve(), 1000); | ||
}; | ||
|
||
/** | ||
* Disable sticky footer in the page. | ||
*/ | ||
export const disableStickyFooter = () => { | ||
document.body.classList.remove(CLASSES.HASSTICKYFOOTER); | ||
const page = document.querySelector(SELECTORS.PAGE); | ||
page?.classList.remove(CLASSES.HASSTICKYFOOTER); | ||
}; | ||
|
||
/** | ||
* Initialize the module. | ||
*/ | ||
export const init = () => { | ||
// Prevent sticky footer in behat. | ||
if (initialized || document.body.classList.contains('behat-site')) { | ||
return; | ||
} | ||
initialized = true; | ||
enableStickyFooter(); | ||
const content = document.querySelector(SELECTORS.PAGE) ?? document.body; | ||
content.addEventListener("scroll", scrollSpy); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.