MDL-82183 core: Migrate all output classes to autoloaded
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* This class keeps track of which HTML tags are currently open.
|
||||
*
|
||||
* This makes it much easier to always generate well formed XHTML output, even
|
||||
* if execution terminates abruptly. Any time you output some opening HTML
|
||||
* without the matching closing HTML, you should push the necessary close tags
|
||||
* onto the stack.
|
||||
*
|
||||
* @copyright 2009 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since Moodle 2.0
|
||||
* @package core
|
||||
* @category output
|
||||
*/
|
||||
class xhtml_container_stack {
|
||||
/**
|
||||
* @var array Stores the list of open containers.
|
||||
*/
|
||||
protected $opencontainers = array();
|
||||
|
||||
/**
|
||||
* @var array In developer debug mode, stores a stack trace of all opens and
|
||||
* closes, so we can output helpful error messages when there is a mismatch.
|
||||
*/
|
||||
protected $log = array();
|
||||
|
||||
/**
|
||||
* @var boolean Store whether we are developer debug mode. We need this in
|
||||
* several places including in the destructor where we may not have access to $CFG.
|
||||
*/
|
||||
protected $isdebugging;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
global $CFG;
|
||||
$this->isdebugging = $CFG->debugdeveloper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the close HTML for a recently opened container onto the stack.
|
||||
*
|
||||
* @param string $type The type of container. This is checked when {@link pop()}
|
||||
* is called and must match, otherwise a developer debug warning is output.
|
||||
* @param string $closehtml The HTML required to close the container.
|
||||
*/
|
||||
public function push($type, $closehtml) {
|
||||
$container = new stdClass;
|
||||
$container->type = $type;
|
||||
$container->closehtml = $closehtml;
|
||||
if ($this->isdebugging) {
|
||||
$this->log('Open', $type);
|
||||
}
|
||||
array_push($this->opencontainers, $container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop the HTML for the next closing container from the stack. The $type
|
||||
* must match the type passed when the container was opened, otherwise a
|
||||
* warning will be output.
|
||||
*
|
||||
* @param string $type The type of container.
|
||||
* @return ?string the HTML required to close the container.
|
||||
*/
|
||||
public function pop($type) {
|
||||
if (empty($this->opencontainers)) {
|
||||
debugging('<p>There are no more open containers. This suggests there is a nesting problem.</p>' .
|
||||
$this->output_log(), DEBUG_DEVELOPER);
|
||||
return;
|
||||
}
|
||||
|
||||
$container = array_pop($this->opencontainers);
|
||||
if ($container->type != $type) {
|
||||
debugging('<p>The type of container to be closed (' . $container->type .
|
||||
') does not match the type of the next open container (' . $type .
|
||||
'). This suggests there is a nesting problem.</p>' .
|
||||
$this->output_log(), DEBUG_DEVELOPER);
|
||||
}
|
||||
if ($this->isdebugging) {
|
||||
$this->log('Close', $type);
|
||||
}
|
||||
return $container->closehtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all but the last open container. This is useful in places like error
|
||||
* handling, where you want to close all the open containers (apart from <body>)
|
||||
* before outputting the error message.
|
||||
*
|
||||
* @param bool $shouldbenone assert that the stack should be empty now - causes a
|
||||
* developer debug warning if it isn't.
|
||||
* @return string the HTML required to close any open containers inside <body>.
|
||||
*/
|
||||
public function pop_all_but_last($shouldbenone = false) {
|
||||
if ($shouldbenone && count($this->opencontainers) != 1) {
|
||||
debugging('<p>Some HTML tags were opened in the body of the page but not closed.</p>' .
|
||||
$this->output_log(), DEBUG_DEVELOPER);
|
||||
}
|
||||
$output = '';
|
||||
while (count($this->opencontainers) > 1) {
|
||||
$container = array_pop($this->opencontainers);
|
||||
$output .= $container->closehtml;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* You can call this function if you want to throw away an instance of this
|
||||
* class without properly emptying the stack (for example, in a unit test).
|
||||
* Calling this method stops the destruct method from outputting a developer
|
||||
* debug warning. After calling this method, the instance can no longer be used.
|
||||
*/
|
||||
public function discard() {
|
||||
$this->opencontainers = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an entry to the log.
|
||||
*
|
||||
* @param string $action The name of the action
|
||||
* @param string $type The type of action
|
||||
*/
|
||||
protected function log($action, $type) {
|
||||
$this->log[] = '<li>' . $action . ' ' . $type . ' at:' .
|
||||
format_backtrace(debug_backtrace()) . '</li>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the log's contents as a HTML list.
|
||||
*
|
||||
* @return string HTML list of the log
|
||||
*/
|
||||
protected function output_log() {
|
||||
return '<ul>' . implode("\n", $this->log) . '</ul>';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user