Returns a tab-strip and the associated tabs.
The HTML is a standardised format, containing a &lt;ul;

@param array $properties
@return DBHTMLText|string
197632
public function FieldHolder($properties = array())
    {
        $obj = $properties ? $this->customise($properties) : $this;

        return $obj->renderWith($this->getTemplates());
    }
366355
protected function normalizeProperties($properties)
	{
		foreach ($properties as $property => $type)
		{
			if (preg_match('/(.*?)\(\d+\).*/i', $type, $matches))
			{
				$type = $matches[1];

				$properties[$property] = $type;
			}

			switch ($type)
			{
				case 'text':
				case 'tinytext':
				case 'mediumtext':
				case 'longtext':
				case 'blob':
					$properties[$property] = 'text';
				break;

				case 'int':
				case 'integer':
				case 'smallint':
				case 'tinyint':
				case 'bigint':
				case 'mediumint':
				case 'year':
					$properties[$property] = 'integer';
				break;

				case 'datetime':
				case 'date':
				case 'timestamp':
				case 'time':
					$properties[$property] = 'date';
				break;

				case 'varchar':
				case 'char':
				default:
					$properties[$property] = 'string';
				break;
			}
		}

		return $properties;
	}
1000058
public function Field($properties = array())
    {
        $this->addExtraClass('form-control color-swab');

        //Libraries
        Requirements::css(COLOR_SWAB_DIR . '/css/lib/colorswab-iconpicker.css');
        Requirements::javascript(COLOR_SWAB_DIR . '/js/color-swabs.js');
        Requirements::javascript(COLOR_SWAB_DIR . '/js/lib/colorswab-iconpicker.js');

        // Module
        Requirements::css(COLOR_SWAB_DIR . '/css/lib/bootstrap.min.css');
        Requirements::css(COLOR_SWAB_DIR . '/css/color-swab-module.css');
        Requirements::css(COLOR_SWAB_DIR . '/css/color-swabs.css');
        Requirements::javascript(COLOR_SWAB_DIR . '/js/color-swab-module.js');

        Requirements::set_force_js_to_bottom(true);

        return parent::Field($properties);
    }
750599
public function FieldHolder($properties = array())
    {
        $context = $this;

        if (count($properties)) {
            $context = $this->customise($properties);
        }

        return $context->renderWith($this->getTemplates());
    }
184144
protected function ensureFormatProperties(array $properties)
	{
		// defaults keys for transforming
		$properties += [
			'bit_rate'    => 0,
			'duration'    => 0.0,
			'format_name' => '',
			'tags'        => [],
			'codecs'      => []
		];
		
		if ( ! empty($this->options[ServiceFactoryInterface::OPTION_TEST_CODECS]))
		{
			$properties['codecs'] = $this->getAvailableCodecs();
		}
		
		$properties['metadata'] = (array) $properties['tags'];
		$properties['format'] = $properties['format_name'];
		$properties['bitrate'] = $properties['bit_rate'];
		
		unset($properties['tags'], $properties['bit_rate']);
		
		return $properties;
	}
839546
static function tab($tabName, $tabProperty) {
		/** @var Structure $s */
		$s = df_config_structure();
		if (!isset($s->_data['tabs'])) {
			$s->getTabs();
		}
		return dfa(dfa($s->_data['tabs'], $tabName, []), $tabProperty);
	}
429561
public function toArray($properties = null)
    {
        $array = [];

        if (!empty($this->getMeta())) {
            $array['meta'] = $this->getMeta();
        }

        if (!empty($this->getPropertyContainer())) {
            $array['properties'] = [];

            foreach ($this->getPropertyContainer()->getProperties() as $item) {
                if (method_exists(
                    $item,
                    'toArray'
                )) {
                    $array['properties'][] = $item->toArray();
                }
            }
        }
        if (!empty($this->getDatabaseContainer())) {
            $array['database'] = $this->getDatabaseContainer()->getDatabase()->toArray();
        }

        return $array;
    }
395996
public function getTab(): string
	{
		$mailsCount = count($this->traceableMailer->getMails());

		if ($mailsCount === 0) {
			return '';
		}

		ob_start();

		require 'templates/tab.phtml';

		return (string) ob_get_clean();
	}
783031
public function getProperties($properties){
        $values= array();
        foreach ($properties as $key) {
            $values[$key]= $this->getProperty($key);
        }
        return $values;
    }
431725
protected function stripAttributeMarker(array $data)
    {
        foreach ($data as $key => $value) {
            if (substr($key, 0, 5) == '@xml:') {
                $data[substr($key, 5)] = $value;
                unset ($data[$key]);
            } elseif (substr($key, 0, 1) == '@') {
                $data[substr($key, 1)] = $value;
                unset ($data[$key]);
            }

            if (is_array($value)) {
                $data[$key] = $this->stripAttributeMarker($value);
            }
        }

        return $data;
    }
690226
public function getPropertiesValues($properties)
    {
        $returnValue = array();
        if(!is_array($properties)){
			throw new common_exception_InvalidArgumentType(__CLASS__, __FUNCTION__, 0, 'array', $properties);
        }
        $returnValue = $this->getImplementation()->getPropertiesValues($this, $properties/*, $last*/);
        return (array) $returnValue;
    }
898910
public function FieldHolder($properties=array()) {
        Requirements::css(CB_DIR.'/css/PackageSelectionField.css');
        Requirements::javascript(CB_DIR.'/javascript/PackageSelectionField.js');
        
        return parent::FieldHolder($properties);
    }
276408
public function FieldHolder($properties = array())
    {
        $columns = $this->getColumns();

        $list = $this->getManipulatedList();

        $content = array(
            'before' => '',
            'after' => '',
            'header' => '',
            'footer' => '',
        );

        foreach ($this->getComponents() as $item) {
            if ($item instanceof GridField_HTMLProvider) {
                $fragments = $item->getHTMLFragments($this);

                if ($fragments) {
                    foreach ($fragments as $fragmentKey => $fragmentValue) {
                        $fragmentKey = strtolower($fragmentKey);

                        if (!isset($content[$fragmentKey])) {
                            $content[$fragmentKey] = '';
                        }

                        $content[$fragmentKey] .= $fragmentValue . "\n";
                    }
                }
            }
        }

        foreach ($content as $contentKey => $contentValue) {
            $content[$contentKey] = trim($contentValue);
        }

        // Replace custom fragments and check which fragments are defined. Circular dependencies
        // are detected by disallowing any item to be deferred more than 5 times.

        $fragmentDefined = array(
            'header' => true,
            'footer' => true,
            'before' => true,
            'after' => true,
        );
        $fragmentDeferred = [];

        // TODO: Break the below into separate reducer methods

        // Continue looping if any placeholders exist
        while (array_filter($content, function ($value) {
            return preg_match(self::FRAGMENT_REGEX, $value);
        })) {
            foreach ($content as $contentKey => $contentValue) {
                // Skip if this specific content has no placeholders
                if (!preg_match_all(self::FRAGMENT_REGEX, $contentValue, $matches)) {
                    continue;
                }
                foreach ($matches[1] as $match) {
                    $fragmentName = strtolower($match);
                    $fragmentDefined[$fragmentName] = true;

                    $fragment = '';

                    if (isset($content[$fragmentName])) {
                        $fragment = $content[$fragmentName];
                    }

                    // If the fragment still has a fragment definition in it, when we should defer
                    // this item until later.

                    if (preg_match(self::FRAGMENT_REGEX, $fragment, $matches)) {
                        if (isset($fragmentDeferred[$contentKey]) && $fragmentDeferred[$contentKey] > 5) {
                            throw new LogicException(sprintf(
                                'GridField HTML fragment "%s" and "%s" appear to have a circular dependency.',
                                $fragmentName,
                                $matches[1]
                            ));
                        }

                        unset($content[$contentKey]);

                        $content[$contentKey] = $contentValue;

                        if (!isset($fragmentDeferred[$contentKey])) {
                            $fragmentDeferred[$contentKey] = 0;
                        }

                        $fragmentDeferred[$contentKey]++;

                        break;
                    } else {
                        $content[$contentKey] = preg_replace(
                            sprintf('/\$DefineFragment\(%s\)/i', $fragmentName),
                            $fragment,
                            $content[$contentKey]
                        );
                    }
                }
            }
        }

        // Check for any undefined fragments, and if so throw an exception.
        // While we're at it, trim whitespace off the elements.

        foreach ($content as $contentKey => $contentValue) {
            if (empty($fragmentDefined[$contentKey])) {
                throw new LogicException(sprintf(
                    'GridField HTML fragment "%s" was given content, but not defined. Perhaps there is a supporting GridField component you need to add?',
                    $contentKey
                ));
            }
        }

        $total = count($list);

        if ($total > 0) {
            $rows = array();

            foreach ($list as $index => $record) {
                if ($record->hasMethod('canView') && !$record->canView()) {
                    continue;
                }

                $rowContent = '';

                foreach ($this->getColumns() as $column) {
                    $colContent = $this->getColumnContent($record, $column);

                    // Null means this columns should be skipped altogether.

                    if ($colContent === null) {
                        continue;
                    }

                    $colAttributes = $this->getColumnAttributes($record, $column);

                    $rowContent .= $this->newCell(
                        $total,
                        $index,
                        $record,
                        $colAttributes,
                        $colContent
                    );
                }

                $rowAttributes = $this->getRowAttributes($total, $index, $record);

                $rows[] = $this->newRow($total, $index, $record, $rowAttributes, $rowContent);
            }
            $content['body'] = implode("\n", $rows);
        }

        // Display a message when the grid field is empty.
        if (empty($content['body'])) {
            $cell = HTML::createTag(
                'td',
                array(
                    'colspan' => count($columns),
                ),
                _t('SilverStripe\\Forms\\GridField\\GridField.NoItemsFound', 'No items found')
            );

            $row = HTML::createTag(
                'tr',
                array(
                    'class' => 'ss-gridfield-item ss-gridfield-no-items',
                ),
                $cell
            );

            $content['body'] = $row;
        }

        $header = $this->getOptionalTableHeader($content);
        $body = $this->getOptionalTableBody($content);
        $footer = $this->getOptionalTableFooter($content);

        $this->addExtraClass('ss-gridfield grid-field field');

        $fieldsetAttributes = array_diff_key(
            $this->getAttributes(),
            array(
                'value' => false,
                'type' => false,
                'name' => false,
            )
        );

        $fieldsetAttributes['data-name'] = $this->getName();

        $tableId = null;

        if ($this->id) {
            $tableId = $this->id;
        }

        $tableAttributes = array(
            'id' => $tableId,
            'class' => 'table grid-field__table',
            'cellpadding' => '0',
            'cellspacing' => '0'
        );

        if ($this->getDescription()) {
            $content['after'] .= HTML::createTag(
                'span',
                array('class' => 'description'),
                $this->getDescription()
            );
        }

        $table = HTML::createTag(
            'table',
            $tableAttributes,
            $header . "\n" . $footer . "\n" . $body
        );

        return HTML::createTag(
            'fieldset',
            $fieldsetAttributes,
            $content['before'] . $table . $content['after']
        );
    }
475927
public function normalize($tabs, $format = null, array $context = [])
    {
        $data = [
            'theme'        => $tabs->getTheme(),
            'align'        => $tabs->getAlign(),
            'translations' => [],
            'tabs'         => [],
        ];

        /** @var Model\TabsTranslation $translation */
        foreach ($tabs->getTranslations() as $translation) {
            $data['translations'][$translation->getLocale()] = [
                'locale'       => $translation->getLocale(),
                'title'        => $translation->getTitle(),
                'content'      => $translation->getContent(),
                'media'        => $translation->getMedia() ? $translation->getMedia()->getId() : null,
                'button_label' => $translation->getButtonLabel(),
                'button_url'   => $translation->getButtonUrl(),
            ];
        }

        $list = $tabs->getTabs()->toArray();
        usort($list, function (Model\Tab $a, Model\Tab $b) {
            return $a->getPosition() - $b->getPosition();
        });

        /** @var Model\Tab $tab */
        foreach ($list as $tab) {
            $datum = [
                'position'     => $tab->getPosition(),
                'anchor'       => $tab->getAnchor(),
                'translations' => [],
            ];

            /** @var Model\TabTranslation $translation */
            foreach ($tab->getTranslations() as $translation) {
                $datum['translations'][$translation->getLocale()] = [
                    'locale'       => $translation->getLocale(),
                    'title'        => $translation->getTitle(),
                    'media'        => $translation->getMedia() ? $translation->getMedia()->getId() : null,
                    'button_label' => $translation->getButtonLabel(),
                    'button_url'   => $translation->getButtonUrl(),
                ];
            }

            $data['tabs'][$tab->getPosition()] = $datum;
        }

        return $data;
    }
600585
public function properties (array $properties = array())
    {
        $res = '';
        
        if (!empty($properties)) {
            foreach ($properties as $key => $property) {
                $res .= ' ' . $key . '="' . $property . '"';
            }
        }

        return $res;
    }
61702
public function Field($properties=array()) {
        $siteKey=$this->getSiteKey();
        $secretKey=$this->_secretKey ? $this->_secretKey : self::config()->secret_key;

        if(empty($siteKey) || empty($secretKey)) {
            user_error('You must configure Nocaptcha.site_key and Nocaptcha.secret_key, you can retrieve these at https://google.com/recaptcha', E_USER_ERROR);
        }

        Requirements::javascript('undefinedoffset/silverstripe-nocaptcha:javascript/NocaptchaField.js');
        Requirements::customScript(
            "var _noCaptchaFields=_noCaptchaFields || [];_noCaptchaFields.push('".$this->ID()."');",
            "NocaptchaField-" . $this->ID()
        );
        Requirements::customScript(
            "(function() {\n" .
                "var gr = document.createElement('script'); gr.type = 'text/javascript'; gr.async = true;\n" .
                "gr.src = ('https:' == document.location.protocol ? 'https://www' : 'http://www') + " .
                "'.google.com/recaptcha/api.js?render=explicit&hl=" .
                Locale::getPrimaryLanguage(i18n::get_locale()) .
                "&onload=noCaptchaFieldRender';\n" .
                "var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(gr, s);\n" .
            "})();\n",
            'NocaptchaField-lib'
        );

        return parent::Field($properties);
    }
968387
protected function arrayToHtmlAttributes(array $values)
    {
        $output = "";
        ksort($values);

        foreach ($values as $key => $value) {
            $output .=  sprintf('%s="%s" ', htmlentities($key), htmlentities($value));
        }

        return $output;
    }