(if you don't like the colors, check out the alternate stylesheets or create your own:)

# Special attributes

There are two different kinds of attributes that can be attached to an HTML_Element. One is the regular type which corresponds to the actual attributes given in the parsed document (or added through DOM) the other is special attributes used internally by Opera.
This document is about the latter.

## Getting and setting

There are mainly two methods on HTML_Element used for getting and setting attributes - GetAttr(...) and SetAttr(...).

`HTML_Element::GetAttr(short attr, ItemType item_type, void* def_value, int ns_idx, BOOL is_special); HTML_Element::SetAttr(short attr, ItemType item_type, void* val, BOOL need_free, int ns_idx, BOOL is_special, BOOL strict_ns, BOOL is_id, BOOL is_specified, BOOL is_event);`

Two new ones for getting and setting special attributes

`HTML_Element::GetSpecialAttr(short attr, ItemType item_type, void* def_value, int ns); HTML_Element::SetSpecialAttr(short attr, ItemType item_type, void* val, BOOL need_free, int ns);`

The `attr` argument is used to specify which attribute within the chosen namespace you want to get or set.
If you want to get the special attributes from the HTML_Element just set the `is_special` argument to TRUE.
The `ns_idx` argument is interpreted differently for regular and special attributes. For regular attributes this is an index into the global XML namespace table but for special attributes this specifies one of the module namespaces (see Namespaces)

## Namespaces

The namespace property of HTML_element attributes behaves differently for regular and special attributes. For regular attributes this property tells which XML namespace this attribute belongs to, but for special internal attributes this tells which module namespace the attribute belongs to.

Internal namespaces defines which module or logical unit the attribute belongs to. Each module will have its own namespace and can define its own attributes.
This is done to make it easy for the different modules to add private attributes without necessarily changing the logdoc module.

The internal namespaces are decleared as an enum in the class SpecialNs in the file `modules/logdoc/logdocenum.h`.

When a module wants to add a special attribute, it just adds it to its own list of attributes and Gets/Sets it using the normal methods on HTML_Element with the namespace corresponding to the module. (description of how to add a special attribute)

## Attribute type code

Each special attribute needs a type code that uniquely identifies the attribute within its namespace. Except for a few reserved attribute type codes the values can be any unsigned number that fits into 8 bits.

### Reserved type codes

In the file `modules/logdoc/logdocenum.h` there is an enum starting with the value ATTR_NULL. That value and all other values below ATTR_FIRST_ALLOWED are reserved and should not be used by any attribute codes in any namespace.
When making a new list of attribute codes for your module make sure to start from the ATTR_FIRST_ALLOWED value, like this

`enum { MY_FIRST_ATTR = ATTR_FIRST_ALLOWED }`

## Value types

The same value types of attribute values are valid for special attributes as for regular attributes. That means that the special attributes can have these values.

- Boolean (ITEM_TYPE_BOOL)
- Numeric (ITEM_TYPE_NUM)
- String (ITEM_TYPE_STRING)
- Numeric with string representation if the number cannot directly be mapped back to the string (ITEM_TYPE_NUM_AND_STRING)
- Please avoid if you can, use ITEM_TYPE_URL_AND_STRING URL object (ITEM_TYPE_URL)
- Relative URL represented by string (ITEM_TYPE_URL_AND_STRING)
- Style (ITEM_TYPE_STYLE, ITEM_TYPE_CSS)
- Coordinates (ITEM_TYPE_COORDS_ATTR) (should be special)
- Plugin private attributes (ITEM_TYPE_PRIVATE_ATTRS) (should be special)
- Event data (ITEM_TYPE_XML_EVENTS_REGISTRATION) (should be special)
- Complex, used for non-simple values (ITEM_TYPE_COMPLEX)

The first three are easy to use, the style types will probably not be used much for special attributes, the next three attribute types should be redesigned as the last one which is highly relevant for special attributes and will be explained in detail:

### The complex attribute type

This type is provided for complex attributes containing different data fields, complex structures and operations on them.

`class ComplexAttr { public: enum { T_UNKNOWN, T_LOGDOC }; ComplexAttr() {} virtual ~ComplexAttr() {} virtual BOOL IsA(int type) { return type == T_UNKNOWN; } virtual OP_STATUS CreateCopy(ComplexAttr **copy_to); virtual OP_STATUS ToString(TempBuffer *buf) { return OpStatus::OK; } virtual BOOL MoveToOtherDocument(FramesDocument *old_document, FramesDocument *new_document); virtual BOOL Equals(ComplexAttr *other); };`

#### `IsA()` method

This method is used to figure out if an object is of a special type. Useful for checking if it is safe to cast to a class. The test will return `TRUE` if the object or any of its ancestors are of the type `type`
This method SHOULD be overridden in order to make it possible to check the actual type of the complex attribute.

#### `CreateCopy()` method

The `CreateCopy` method is kinda special. It is used for cloning the complex attribute.
It should create a new complex attribute of the same type and copy the members from the old one if appropriate.
This abstract method SHOULD be overridden.

#### `ToString()` method

This method is used to make a string representation of the object. For instance for the CoordAttr it would mean that it added to the TempBuffer `buf` a string like this: "x,y".
This method MUST be overridden by all regular attributes. Special internal variables NEED NOT override this method since they will not be serialized (except maybe for debugging purposes).

#### `MoveToOtherDocument()` method

This method is used when an element is moved from one document to another, usually through DOM manipulations. MUST be overriden by all attributes that are dependent on the document it belongs to.

#### `Equals()` method

This method is used to compare two attribute values to detect if the attribute has been set to the same value as it already had. It is used as an optimization for skipping operations that would normally be done when the attribute value changes. It's not strictly necessary to implement this method. In that case, setting the attribute will always be considered to be an attribute change.

### Examples

#### Special Numeric attribute

`ATTR_SUB_WIN_ID` is a numeric attribute that specifies which sub-window the element belongs to. Used for FRAME- and FRAMESET elements.

`elm->GetSpecialAttr(ATTR_SUB_WIN_ID, ITEM_TYPE_NUM, (void*)0, SpecialNs::NS_DOCHAND); elm->SetSpecialAttr(ATTR_SUB_WIN_ID, ITEM_TYPE_NUM, (void*)1, FALSE, SpecialNs::NS_DOCHAND);`

#### Special String attribute

`ATTR_XML_NAME` is a string attribute that stores the name of an element.

`elm->GetSpecialAttr(ATTR_XML_NAME, ITEM_TYPE_STRING, (void*)NULL, SpecialNs::NS_LOGDOC); elm->SetSpecialAttr(ATTR_XML_NAME, ITEM_TYPE_STRING, (void*)name, TRUE, SpecialNs::NS_LOGDOC);`

#### Special URL attribute

`ATTR_CSS_LINK` is a url attribute that specifies a CSS defined link on an element.

`elm->GetSpecialAttr(ATTR_CSS_LINK, ITEM_TYPE_URL, (void*)NULL, SpecialNs::NS_LOGDOC); elm->SetSpecialAttr(ATTR_CSS_LINK, ITEM_TYPE_URL, (void*)url, TRUE, SpecialNs::NS_LOGDOC);`

#### Special Complex attribute

`ATTR_FORM_VALUE` is used for storing the values of a form element.

`elm->GetSpecialAttr(ATTR_FORM_VALUE, ITEM_TYPE_COMPLEX, (void*)NULL, SpecialNs::NS_LOGDOC); elm->SetSpecialAttr(ATTR_FORM_VALUE, ITEM_TYPE_COMPLEX, (void*)form_value, SpecialNs::NS_LOGDOC);`

## How to create new attribute

If you want to create a new attribute in your module you have to do the following things:

1. Create module namespace
2. Add attribute code
3. Subclass ComplexAttr
4. Set/Get the new attribute

### Create module namespace

Check the file `modules/logdoc/logdocenum.h` for an internal namespace in the `SpecialNs` class. If there is no namespace for the module you are adding a new attribute to you have to add one.

### Add attribute code

Add a numeric code for your attribute in the special attribute header file for your module (for instance `modules/logdoc/logdocenum.h`). If you don't have such a file, make one.
Make sure your new attribute code is unique to the list in your module and follow the standards set here.

### Subclass ComplexAttr

If you are not going to use one of the existing value types you have to create a subclass of the class `ComplexAttr` that suites your need.

### Set/Get the new attribute

When you have finished the steps above you can start using the attribute. Use the SetSpecialAttr(...) and GetSpecialAttr(...) methods on HTML_Element (see Getting and setting).

2010-01-21, stighal