123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516 |
- <?php
- /**
- * A QuickSet object is an unrendered Quicktabs instance, essentially just a
- * container of content items, as defined by its configuration settings and the
- * array of content items it contains.
- */
- class QuickSet {
-
- /**
- * The unique name of the QuickSet object.
- * This corresponds to the machine name as stored in the database or as defined
- * in code.
- * @var string
- */
- protected $name;
-
- /**
- * The contents array.
- * An array of objects that implement the QuickContentRenderable interface.
- * @var array
- */
- protected $contents;
-
- /**
- * An array of settings controlling the behaviour of the QuickSet object. See
- * the getDefaultSettings() static function of this class for the full list of
- * settings.
- * @var array
- */
- protected $settings;
-
- /**
- * Accessors.
- */
-
- public function getName() {
- return $this->name;
- }
-
- public function getContents() {
- return $this->contents;
- }
-
- public function getSettings() {
- return $this->settings;
- }
- public function getTitle() {
- return isset($this->settings['title']) ? $this->translateString($this->settings['title'], 'title') : $this->name;
- }
- /**
- * Instantiate, populate and return a QuickSet object wrapped in a renderer.
- *
- * @param $name
- * The unique name (machine name) of the QuickSet instance.
- *
- * @param $contents
- * The array of content items, each one itself an array with at least a 'type'
- * key, a 'title' key, and the other info necessary for that type.
- *
- * @param $renderer
- * The plugin key for this renderer plugin
- *
- * @param $settings
- * An array of settings determining the behaviour of this QuickSet instance.
- *
- */
- public static function QuickSetRendererFactory($name, $contents, $renderer, $settings) {
- ctools_include('plugins');
- if ($class = ctools_plugin_load_class('quicktabs', 'renderers', $renderer, 'handler')) {
- try {
- $qs = new self($name, $contents, $settings);
- }
- catch (InvalidQuickSetException $e) {
- watchdog('Quicktabs', $e->getMessage());
- return NULL;
- }
- return new $class($qs);
- }
- }
-
- /**
- * Returns a reference to an object that implements the QuickContentRenderable
- * interface.
- */
- public static function getContentRenderer($tab) {
- if ($tab['type'] == 'prerendered') {
- return new QuickPreRenderedContent($tab);
- }
- if ($content = QuickContent::factory($tab['type'], $tab)) {
- return $content;
- }
- return NULL;
- }
-
- /**
- * Static method to retrieve content from an ajax call. This is called by the
- * quicktabs_ajax() callback in quicktabs.module.
- */
- public static function ajaxRenderContent($type, $args) {
- if ($renderer = self::getContentRenderer(array('type' => $type))) {
- $output = $renderer->render(FALSE, $args);
- return !empty($output) ? drupal_render($output) : '';
- }
- return '';
- }
-
- /**
- * Ensure sensible default settings for each QuickSet object.
- */
- private static function getDefaultSettings() {
- return array(
- 'title' => '<none>',
- 'style' => 'nostyle',
- 'hide_empty_tabs' => 0,
- 'ajax' => 0,
- 'default_tab' => 0,
- 'options' => array(),
- );
- }
-
- /**
- * Constructor
- */
- public function __construct($name, $contents, $settings) {
- $this->name = $name;
- $this->contents = array();
- foreach ($contents as $key => $item) {
- // Instantiate a content renderer object and add it to the contents array.
- if ($renderer = self::getContentRenderer($item)) {
- $this->contents[$key] = $renderer;
- }
- }
- $default_settings = self::getDefaultSettings();
- $this->settings = array_merge($default_settings, $settings);
- $this->prepareContents();
- // Set the default style if necessary.
- if ($this->settings['style'] == 'default') {
- $this->settings['style'] = variable_get('quicktabs_tabstyle', 'nostyle');
- }
- }
- /**
- * Returns an ajax path to be used on ajax-enabled tab links.
- *
- * @param $index The index of the tab, i.e where it fits into the QuickSet
- * instance.
- *
- * @param $type The type of content we are providing an ajax path for.
- */
- public function getAjaxPath($index, $type) {
- return 'quicktabs/ajax/'. $this->name .'/'. $index . '/'. $type;
- }
- /**
- * Translates Quicktabs user-defined strings if the i18n module is
- * enabled.
- */
- public function translateString($string, $type = 'tab', $index = 0) {
- switch ($type) {
- case 'tab':
- $name = "tab:{$this->name}-{$index}:title";
- break;
- case 'title':
- $name = "title:{$this->name}";
- break;
- }
- return quicktabs_translate($name, $string);
- }
- /**
- * This method does some initial set-up of the tab contents, such as hiding
- * tabs with no content if the hide_empty_tabs option is set. It also makes sure
- * that prerendered contents are never attempted to be loaded via ajax.
- *
- * @throws InvalidQuickSetException if there are no contents to render.
- */
- protected function prepareContents() {
- if (!count($this->contents)) {
- throw new InvalidQuickSetException('There are no contents to render.');
- }
- if ($this->settings['hide_empty_tabs'] && !$this->settings['ajax']) {
- // Check if any tabs need to be hidden because of empty content.
- $renderable_contents = 0;
- foreach ($this->contents as $key => $tab) {
- $contents = $tab->render(TRUE);
- if (empty($contents)) {
- // Rather than removing the item, we set it to NULL. This way we retain
- // the same indices across tabs, so that permanent links to particular
- // tabs can be relied upon.
- $this->contents[$key] = NULL;
- // The default tab must not be a hidden tab.
- if ($this->settings['default_tab'] == $key) {
- $this->settings['default_tab'] = ($key + 1) % count($this->contents);
- }
- }
- else {
- $renderable_contents++;
- }
- }
- if (!$renderable_contents) {
- throw new InvalidQuickSetException('There are no contents to render.');
- }
- }
- elseif ($this->settings['ajax']) {
- // Make sure that there is at most 1 prerendered tab and it is the default tab.
- // Prerendered content cannot be rendered via ajax.
- $has_prerendered = FALSE; // keep track of whether we have found a prerendered tab.
- foreach ($this->contents as $key => $tab) {
- $type = $tab->getType();
- if ($type == 'prerendered') {
- if (!$has_prerendered) {
- $has_prerendered = TRUE;
- $this->settings['default_tab'] = $key;
- // In the case of a direct link to a different tab, the 'default_tab'
- // will be overridden, so we need to make sure it does not attempt
- // to load a pre-rendered tab via ajax. Turn ajax option off.
- if ($this->getActiveTab() !== $key) {
- $this->settings['ajax'] = 0;
- }
- }
- else {
- // We are on a second custom tab and the ajax option is set, we cannot
- // render custom tabs via ajax, so we skip out of the loop, set the
- // ajax option to off, and call the method again.
- $this->settings['ajax'] = 0;
- $this->prepareContents();
- return;
- }
- }
- }
- }
- }
-
- /**
- * Returns the active tab for a given Quicktabs instance. This could be coming
- * from the URL or just from the settings for this instance. If neither, it
- * defaults to 0.
- */
- public function getActiveTab() {
- $active_tab = isset($this->settings['default_tab']) ? $this->settings['default_tab'] : key($this->contents);
- $active_tab = isset($_GET['qt-' . $this->name]) ? $_GET['qt-' . $this->name] : $active_tab;
- $active_tab = (isset($active_tab) && isset($this->contents[$active_tab])) ? $active_tab : 0;
- return $active_tab;
- }
- }
- /**
- * Abstract base class for QuickSet Renderers.
- *
- * A renderer object contains a reference to a QuickSet object, which it can
- * then render.
- */
- abstract class QuickRenderer {
-
- /**
- * @var QuickSet
- */
- protected $quickset;
- /**
- * Constructor
- */
- public function __construct($quickset) {
- $this->quickset = $quickset;
- }
-
- /**
- * Accessor method for the title.
- */
- public function getTitle() {
- return $this->quickset->getTitle();
- }
-
- /**
- * The only method that renderer plugins must implement.
- *
- * @return A render array to be passed to drupal_render().
- */
- abstract public function render();
-
- /**
- * Method for returning the form elements to display for this renderer type on
- * the admin form.
- * @param $qt An object representing the Quicktabs instance that the tabs are
- * being built for.
- */
- public static function optionsForm($qt) {
- return array();
- }
-
- }
- /*******************************************************
- * The classes below relate to individual tab content *
- *******************************************************/
- /**
- * Each QuickSet object has a "contents" property which is an array of objects
- * that implement the QuickContentRenderable interface.
- */
- interface QuickContentRenderable {
-
- /**
- * Returns the short type name of the content plugin, e.g. 'block', 'node',
- * 'prerendered'.
- */
- public static function getType();
-
- /**
- * Returns the tab title.
- */
- public function getTitle();
- /**
- * Returns an array of settings specific to the type of content.
- */
- public function getSettings();
-
- /**
- * Renders the content.
- *
- * @param $hide_emtpy If set to true, then the renderer should return an empty
- * array if there is no content to display, for example if the user does not
- * have access to the requested content.
- *
- * @param $args Used during an ajax call to pass in the settings necessary to
- * render this type of content.
- */
- public function render($hide_empty = FALSE, $args = array());
- /**
- * Returns an array of keys to use for constructing the correct arguments for
- * an ajax callback to retrieve content of this type. The order of the keys
- * returned affects the order of the args passed in to the render method when
- * called via ajax (see the render() method above).
- */
- public function getAjaxKeys();
-
- }
- /**
- * Abstract base class for content plugins.
- */
- abstract class QuickContent implements QuickContentRenderable {
- /**
- * Used as the title of the tab.
- * @var string
- */
- protected $title;
- /**
- * An array containing the information that defines the tab content, specific
- * to its type.
- * @var array
- */
- protected $settings;
-
- /**
- * A render array of the contents.
- * @var array
- */
- protected $rendered_content;
-
- /**
- * Constructor
- */
- public function __construct($item) {
- $this->title = isset($item['title']) ? $item['title'] : '';
- // We do not need to store title, type or weight in the settings array, which
- // is for type-specific settings.
- unset($item['title'], $item['type'], $item['weight']);
- $this->settings = $item;
- }
-
-
- /**
- * Accessor for the tab title.
- */
- public function getTitle() {
- return $this->title;
- }
- /**
- * Accessor for the tab settings.
- */
- public function getSettings() {
- return $this->settings;
- }
- /**
- * Instantiate a content type object.
- *
- * @param $name
- * The type name of the plugin.
- *
- * @param $item
- * An array containing the item definition
- *
- */
- public static function factory($name, $item) {
- ctools_include('plugins');
- if ($class = ctools_plugin_load_class('quicktabs', 'contents', $name, 'handler')) {
- // We now need to check the plugin's dependencies, to make sure they're installed.
- // This info has already been statically cached at this point so there's no
- // harm in making a call to ctools_get_plugins().
- $plugin = ctools_get_plugins('quicktabs', 'contents', $name);
- if (isset($plugin['dependencies'])) {
- foreach ($plugin['dependencies'] as $dep) {
- // If any dependency is missing we cannot instantiate our class.
- if (!module_exists($dep)) return NULL;
- }
- }
- return new $class($item);
- }
- return NULL;
- }
- /**
- * Method for returning the form elements to display for this tab type on
- * the admin form.
- *
- * @param $delta Integer representing this tab's position in the tabs array.
- *
- * @param $qt An object representing the Quicktabs instance that the tabs are
- * being built for.
- */
- abstract public function optionsForm($delta, $qt);
-
- }
- /**
- * This class implements the same interface that content plugins do but it is not
- * a content plugin. It is a special class for pre-rendered content which is used
- * when "custom" tabs are added to existing Quicktabs instances in a call to
- * quicktabs_build_quicktabs().
- */
- class QuickPreRenderedContent implements QuickContentRenderable {
-
- public static function getType() {
- return 'prerendered';
- }
-
- /**
- * Used as the title of the tab.
- * @var title
- */
- protected $title;
-
- /**
- * A render array of the contents.
- * @var array
- */
- protected $rendered_content;
- /**
- * Constructor
- */
- public function __construct($item) {
- $contents = isset($item['contents']) ? $item['contents'] : array();
- if (!is_array($contents)) {
- $contents = array('#markup' => $contents);
- }
- $this->rendered_content = $contents;
- $this->title = isset($item['title']) ? $item['title'] : '';
- }
-
- /**
- * Accessor for the tab title.
- */
- public function getTitle() {
- return $this->title;
- }
- /**
- * Prerendered content doesn't need any extra settings.
- */
- public function getSettings() {
- return array();
- }
- /**
- * The render method simply returns the contents that were passed in and
- * stored during construction.
- */
- public function render($hide_empty = FALSE, $args = array()) {
- return $this->rendered_content;
- }
-
- /**
- * This content cannot be rendered via ajax so we don't return any ajax keys.
- */
- public function getAjaxKeys() {
- return array();
- }
- }
- /**
- * Create our own exception class.
- */
- class InvalidQuickSetException extends Exception {
-
- }
|