@todo not all elements have a required attribute. This should probably be moved to a trait.

{@inheritdoc}
978818
public function setRequired(bool $required) : Component
    {
        if ($required) {
            $this->getTag()->setAttribute('required', 'required');
        } else {
            $this->getTag()->removeAttribute('required');
        }

        return parent::setRequired($required);
    }
280564
public function attribute(string $key)
    {
        if ($key !== 'value') {
            return parent::attribute($key);
        }

        return array_map(
            function (ElementInterface $element) {
                return $element->value();
            },
            $this->elements()
        );
    }
920296
private function traitAdaptation() {
    /** @var NameNode $qualified_name */
    $qualified_name = $this->name();
    if ($qualified_name->childCount() === 1 && $this->currentType !== T_DOUBLE_COLON) {
      return $this->traitAlias($qualified_name);
    }
    $node = new TraitMethodReferenceNode();
    $node->addChild($qualified_name, 'traitName');
    $this->mustMatch(T_DOUBLE_COLON, $node);
    $this->mustMatch(T_STRING, $node, 'methodReference', TRUE);
    if ($this->currentType === T_AS) {
      return $this->traitAlias($node);
    }
    $method_reference_node = $node;
    $node = new TraitPrecedenceNode();
    $node->addChild($method_reference_node, 'traitMethodReference');
    $this->mustMatch(T_INSTEADOF, $node);
    $trait_names = new CommaListNode();
    do {
      $trait_names->addChild($this->name());
    } while ($this->tryMatch(',', $trait_names));
    $node->addChild($trait_names, 'traitNames');
    $this->endStatement($node);
    return $node;
  }
469036
function setAttribute(element, name, value) {
  assertType(element, Node, false, 'Invalid element specified');
  if (value === undefined || value === null || value === false)
    element.removeAttribute(name);
  else if (value === true)
    element.setAttribute(name, '');
  else
    element.setAttribute(name, value);
  if (name === 'disabled' && element.setDirty)
    element.setDirty(DirtyType.STATE);
}
955407
private static void addAttribute(Element element, Set<Attr> attributes, Object value) {
		Attr attr = (Attr) value;
		if (!attributes.add(attr)) {
			throw new TemplateException("Invalid element |%s|. It has both static attribute |%s| and attribute operator.", element, attr.getName());
		}
	}
769375
protected function ensureRequiredAttributes(array $spec = [])
    {
        if (! isset($spec['attributes'])) {
            throw new MissingAttributeException(
                sprintf('The attribute "attributes" is not defined, but required.')
            );
        }

        $required = ['type', 'name'];
        foreach ($required as $key) {
            if (! isset($spec['attributes'][$key])) {
                throw new MissingAttributeException(
                    sprintf('The attribute "%s" is not defined, but required.', $key)
                );
            }
        }
    }
893124
function outputTag( $element, &$siblingParams, $parentParams = array() )
    {
        $tagName = $element->localName;
        if ( isset( $this->OutputTags[$tagName] ) )
        {
            $currentTag = $this->OutputTags[$tagName];
        }
        else
        {
            $currentTag = null;
        }

        // Prepare attributes array
        $attributes = array();
        if ( $element->hasAttributes() )
        {
            $attributeNodes = $element->attributes;

            foreach ( $attributeNodes as $attrNode )
            {
                if ( $attrNode->prefix && $attrNode->prefix != 'custom' )
                {
                    $attrName = $attrNode->prefix . ':' . $attrNode->localName;
                }
                else
                {
                    $attrName = $attrNode->nodeName;
                }

                // classes check
                if ( $attrName == 'class' )
                {
                    $classesList = $this->XMLSchema->getClassesList( $tagName );
                    if ( !in_array( $attrNode->value, $classesList ) )
                    {
                        eZDebug::writeWarning( "Using tag '$tagName' with class '$attrNode->value' is not allowed.", 'XML output handler' );
                        return array( true, '' );
                    }
                }

                $attributes[$attrName] = $attrNode->value;
            }
        }

        // Set default attribute values if not present in the input
        $attrDefaults = $this->XMLSchema->attrDefaultValues( $tagName );
        foreach ( $attrDefaults as $name=>$value )
        {
            if ( !isset( $attributes[$name] ) )
            {
                $attributes[$name] = $value;
            }
        }

        // Init handler returns an array that may contain the following items:
        //
        // 'no_render'       (boolean) :
        //                   If false tag will not be rendered, only it's children (if any).
        // 'design_keys'     array( 'design_key_name_1' => 'value_1', 'design_key_name_2'=>'value_2', ... ) :
        //                   An array of additional design keys.
        // 'tpl_vars'        array( 'var_name_1' => 'value_1', 'var_name_2' => 'value_2', ... ) :
        //                   An array of additional template variables.
        // 'template_name'   (string) :
        //                   Overrides tag template name.

        $result = $this->callTagInitHandler( 'initHandler', $element, $attributes, $siblingParams, $parentParams );

        // Process children
        $childrenOutput = array();
        if ( $element->hasChildNodes() )
        {
            // Initialize sibiling parameters array for the next level children
            // Parent parameters for the children may be modified in the current tag handler.
            $nextSibilingParams = array();

            $this->NestingLevel++;
            foreach( $element->childNodes as $child )
            {
                $childOutput = $this->outputTag( $child, $nextSibilingParams, $parentParams );

                if ( is_array( $childOutput[0] ) )
                {
                    $childrenOutput = array_merge( $childrenOutput, $childOutput );
                }
                else
                {
                    $childrenOutput[] = $childOutput;
                }
            }
            $this->NestingLevel--;
        }
        else
        {
            $childrenOutput = array( array( true, '' ) );
        }

        if ( isset( $result['no_render'] ) && $result['no_render'] )
        {
            return $childrenOutput;
        }

        // Set tpl variables by attributes and rename rules
        $vars = array();

        if ( !isset( $currentTag['quickRender'] ) && isset( $currentTag['attrNamesTemplate'] ) )
        {
            $attrRenameRules = $currentTag['attrNamesTemplate'];
        }
        elseif ( isset( $currentTag['quickRender'] ) && isset( $currentTag['attrNamesQuick'] ) )
        {
            $attrRenameRules = $currentTag['attrNamesQuick'];
        }
        else
        {
            $attrRenameRules = array();
        }

        foreach( $attributes as $name=>$value )
        {
            if ( isset( $attrRenameRules[$name] ) )
            {
                $vars[$attrRenameRules[$name]] = $value;
                continue;
            }

            if ( strpos( $name, 'custom:' ) === 0 )
            {
                $name = substr( $name, 7 );
            }

            $vars[$name] = $value;
        }

        // set missing variables that have rename rules defined
        // but were not present in the element
        foreach( $attrRenameRules as $attrName=>$varName )
        {
            if ( !isset( $attributes[$attrName] ) )
            {
                $vars[$varName] = '';
            }
        }

        $this->TemplateUri = '';

        // In quick render mode we does not use templates and
        // render template variables as tag attributes
        if ( !isset( $currentTag['quickRender'] ) )
        {
            // Set additional variables passed by tag handler
            if ( isset( $result['tpl_vars'] ) )
            {
                $vars = array_merge( $vars, $result['tpl_vars'] );
            }

            foreach( $vars as $name=>$value )
            {
                $this->Tpl->setVariable( $name, $value, 'xmltagns' );
            }

            // Create design keys array (including the ones with no value so they still overwrite values of parent tag)
            $designKeys = array();
            if ( isset( $currentTag['attrDesignKeys'] ) )
            {
                foreach( $currentTag['attrDesignKeys'] as $attrName=>$keyName )
                {
                    if ( isset( $attributes[$attrName] ) )
                    {
                        $designKeys[$keyName] = $attributes[$attrName];
                    }
                }
            }
            // Set additional design keys passed by tag handler
            if ( isset( $result['design_keys'] ) )
            {
                $designKeys = array_merge( $designKeys, $result['design_keys'] );
            }

            $existingKeys = $this->Res->keys();
            $savedKeys = array();

            // Save old keys values and set new design keys
            foreach( $designKeys as $key=>$value )
            {
                if ( isset( $existingKeys[$key] ) )
                {
                    $savedKeys[$key] = $existingKeys[$key];
                }
                $this->Res->setKeys( array( array( $key, $value ) ) );
            }

            // Template name
            if ( isset( $result['template_name'] ) )
            {
                $templateName = $result['template_name'];
            }
            else
            {
                $templateName = $element->nodeName;
            }
            $this->TemplateUri = $this->TemplatesPath . $templateName . '.tpl';
        }

        $output = $this->callTagRenderHandler( 'renderHandler', $element, $childrenOutput, $vars );

        if ( !isset( $currentTag['quickRender'] ) )
        {
            // Restore saved template override keys and remove others
            foreach( $designKeys as $key => $value )
            {
                if ( isset( $savedKeys[$key] ) )
                {
                    $this->Res->setKeys( array( array( $key, $savedKeys[$key] ) ) );
                }
                else
                {
                    $this->Res->removeKey( $key );
                }
            }

            // Unset variables
            foreach ( $vars as $name=>$value )
            {
                if ( $this->Tpl->hasVariable( $name, 'xmltagns' ) )
                {
                    $this->Tpl->unsetVariable( $name, 'xmltagns' );
                }
            }
        }

        $this->callTagInitHandler( 'leavingHandler', $element, $attributes, $siblingParams, $parentParams );

        return $output;
    }
595950
protected function attributeElement($key, $value)
    {
        // For numeric keys we will assume that the value is a boolean attribute
        // where the presence of the attribute represents a true value and the
        // absence represents a false value.
        // This will convert HTML attributes such as "required" to a correct
        // form instead of using incorrect numeric.
        if (is_numeric($key)) {
            return $value;
        }
        // Treat boolean attributes as HTML properties
        if (is_bool($value) && $key !== 'value') {
            return $value ? $key : '';
        }
        if (! is_null($value)) {
            return $key.'="'.$this->special($value).'"';
        }

        return null;
    }
20712
protected void checkRequired(String key, AnnotatedElement element) {
        if (isRequired(element)) {
            throw new PropertyLoaderException(String.format("Required property <%s> doesn't exists", key));
        }
    }
973795
private void validateAttributes() {
    if (content == null) {
      throw new NullContentException("RendererBuilder needs content to create Renderer instances");
    }

    if (parent == null) {
      throw new NullParentException("RendererBuilder needs a parent to inflate Renderer instances");
    }

    if (layoutInflater == null) {
      throw new NullLayoutInflaterException(
          "RendererBuilder needs a LayoutInflater to inflate Renderer instances");
    }
  }
841153
private function loadValidatorElement(array &$property, ElementItem $element)
    {
        /* @var $element Element */
        $type = $element->getType();

        $attrs = [];
        $arrayized = strpos($property['type'], 'array<') === 0;

        if ($arrayized) {
            if ($itemOfArray = $this->isArrayNestedElement($type)) {
                $attrs = [
                    'min' => min($element->getMin(), $itemOfArray->getMin()),
                    'max' => $itemOfArray->getMax()
                ];
            }  elseif ($itemOfArray = $this->isArrayType($type)) {
                $attrs = [
                    'min' => min($element->getMin(), $itemOfArray->getMin()),
                    'max' => $itemOfArray->getMax()
                ];
            } elseif ($this->isArrayElement($element)) {
//                $attrs = [
//                    'min' => $element->getMin(),
//                    'max' => $element->getMax()
//                ];
            }
        }

        if (isset($attrs['min']) && $attrs['min'] === 0) {
            unset($attrs['min']);
        }
        if (isset($attrs['max']) && $attrs['max'] === -1) {
            unset($attrs['max']);
        }

        $rules = $this->loadValidatorType($property, $type, $arrayized );


        if ($element->getMin() > 0) {
            $property['validation'][] = [
                'NotNull' => null
            ];
        }

        if ($arrayized && count($attrs) > 0) {
            $property['validation'][] = [
                 'Count' => $attrs
            ];
        }
        if ($arrayized && count($rules) > 0) {
//            $rules[] = ['Valid' => null];
            $property['validation'][] = [
                'All' => ['constraints' => $rules]
            ];
        } elseif ($type instanceof ComplexType) {
            $property['validation'][] = [
                'Valid' => null
            ];
        }
    }
528308
function _createElements() {
        $attributes = $this->getAttributes();
        if (is_null($attributes)) {
            $attributes = array();
        }
        if (!isset($attributes['size'])) {
            $attributes['size'] = 3;
        }
        $this->_elements = array();
        // E_STRICT creating elements without forms is nasty because it internally uses $this
        $number = $this->createFormElement('text', 'number', get_string('time', 'form'), $attributes, true);
        $number->set_force_ltr(true);
        $this->_elements[] = $number;
        unset($attributes['size']);
        $this->_elements[] = $this->createFormElement('select', 'timeunit', get_string('timeunit', 'form'), $this->get_units(), $attributes, true);
        // If optional we add a checkbox which the user can use to turn if on
        if($this->_options['optional']) {
            $this->_elements[] = $this->createFormElement('checkbox', 'enabled', null, get_string('enable'), $this->getAttributes(), true);
        }
        foreach ($this->_elements as $element){
            if (method_exists($element, 'setHiddenLabel')){
                $element->setHiddenLabel(true);
            }
        }
    }
1148820
function validateIsRequired()
    {
        $classAttribute = $this->contentClassAttribute();
        $validationParameters = $this->validationParameters();
        if ( !( isset( $validationParameters['skip-isRequired'] ) && $validationParameters['skip-isRequired'] === true ) && $classAttribute->attribute( "is_required" ) )
            return true;

        return false;
    }
1196058
function(element, attrs) {

            var $element = $(element);

            joint.util.forIn(attrs, function(attrs, selector) {
                var $elements = $element.find(selector).addBack().filter(selector);
                // Make a special case for setting classes.
                // We do not want to overwrite any existing class.
                if (joint.util.has(attrs, 'class')) {
                    $elements.addClass(attrs['class']);
                    attrs = joint.util.omit(attrs, 'class');
                }
                $elements.attr(attrs);
            });
        }
549451
public function attrs(DOMElement &$element, $value = [])
    {
        if (empty($value)) {
            // Get current attributes
            $attrs = [];
            foreach ($element->attributes as $attr) {
                $attrs[$attr->name] = $attr->value;
            }

            // Return the current attributes
            return $attrs;
        } elseif (is_array($value) && count($value) > 0) {
            // Set the given attributes
            foreach ($value as $key => $val) {
                $this->attr($element, $key, $val);
            }
        }

        return [];
    }
950783
protected function initElements()
    {
        
        
    	parent::initElements();
    	
    	$elements = $this->form->getElements();
    	$this->form->setElements(array());
    	
    	
    	$currentLangElt = tao_helpers_form_FormFactory::getElement('current_lang', 'Textbox');
		$currentLangElt->setDescription(__('Current language'));
		$currentLangElt->setAttributes(array('readonly' => 'true'));
		$currentLangElt->setValue(\common_session_SessionManager::getSession()->getDataLanguage());	//API lang /data lang
		$this->form->addElement($currentLangElt);
		
		$dataLangElement = tao_helpers_form_FormFactory::getElement('translate_lang', 'Combobox');
		$dataLangElement->setDescription(__('Translate to'));
		$dataLangElement->setOptions(tao_helpers_I18n::getAvailableLangsByUsage(new core_kernel_classes_Resource(tao_models_classes_LanguageService::INSTANCE_LANGUAGE_USAGE_DATA)));
		$dataLangElement->setEmptyOption(__('Select a language'));
		$dataLangElement->addValidator( tao_helpers_form_FormFactory::getValidator('NotEmpty') );
		$this->form->addElement($dataLangElement);
		
		$this->form->createGroup('translation_info', __('Translation parameters'), array('current_lang', 'translate_lang'));
    	
		$dataGroup = array();
		foreach($elements as $element){
			
			if( $element instanceof tao_helpers_form_elements_Hidden ||
				$element->getName() == 'uri' || $element->getName() == 'classUri'){
					
				$this->form->addElement($element);
				
			}
			else{
				
				$propertyUri = tao_helpers_Uri::decode($element->getName());
				$property = new core_kernel_classes_Property($propertyUri);
				
				//translate only language dependent properties or Labels
				//supported widget are: Textbox, TextArea, HtmlArea
				//@todo support other widgets
				if(	( $property->isLgDependent() && 
					  ($element instanceof tao_helpers_form_elements_Textbox ||
					   $element instanceof tao_helpers_form_elements_TextArea ||
					   $element instanceof tao_helpers_form_elements_HtmlArea
					  ) ) ||
					$propertyUri == OntologyRdfs::RDFS_LABEL){
				
					$translatedElt = clone $element;
					
					$viewElt = tao_helpers_form_FormFactory::getElement('view_'.$element->getName(), 'Label');
					$viewElt->setDescription($element->getDescription());
					$viewElt->setValue($element->getValue());
					$viewElt->setAttribute('no-format', true);
					if ($element instanceof tao_helpers_form_elements_HtmlArea){
						$viewElt->setAttribute('htmlentities', false);
					}
					
					$this->form->addElement($viewElt);
					
					$dataGroup[] = $viewElt->getName();
					
					$translatedElt->setDescription(' ');
					$translatedElt->setValue('');
					if($propertyUri == OntologyRdfs::RDFS_LABEL){
						$translatedElt->setForcedValid();
					}
				
					$this->form->addElement($translatedElt);
					
					$dataGroup[] = $translatedElt->getName();
				}
			}
		}
		
		$this->form->createGroup('translation_form', __('Translate'), $dataGroup);
		
        
    }
360261
protected function unmarshall(DOMElement $element)
    {
        if (($shape = $this->getDOMElementAttributeAs($element, 'shape')) !== null) {

            $shapeVal = QtiShape::getConstantByName($shape);

            if ($shapeVal !== false) {

                if (($coords = $this->getDOMElementAttributeAs($element, 'coords')) !== null) {

                    try {
                        $coords = Utils::stringToCoords($coords, $shapeVal);

                        if (($mappedValue = $this->getDOMElementAttributeAs($element, 'mappedValue', 'float')) !== null) {
                            return new AreaMapEntry($shapeVal, $coords, $mappedValue);
                        } else {
                            $msg = "The mandatory attribute 'mappedValue' is missing from element '" . $element->localName . "'.";
                            throw new UnmarshallingException($msg, $element);
                        }
                    } catch (Exception $e) {
                        if (!$e instanceof UnmarshallingException) {
                            $msg = "The attribute 'coords' with value '${coords}' has an invalid value.";
                            throw new UnmarshallingException($msg, $element, $e);
                        } else {
                            throw $e;
                        }
                    }
                } else {
                    $msg = "The mandatory attribute 'coords' is missing from element '" . $element->localName . "'.";
                    throw new UnmarshallingException($msg, $element);
                }
            } else {
                $msg = "The 'shape' attribute value '${shape}' is not a valid value to represent QTI shapes.";
                throw new UnmarshallingException($msg, $element);
            }

        } else {
            $msg = "The mandatory attribute 'shape' is missing from element '" . $element->localName . "'.";
            throw new UnmarshallingException($msg, $element);
        }
    }