Attributes VS Properties

I

Ivan S

This is probably stupid question (Thomas, you can skip it :) ), but I
have to ask it ... :)


I think I don't really understand attributes and properties ... and
their difference, probably because their meaning is very similar (if
not the same) when I translate them on my native language. In some
way, I can understand difference in general, but can someone explain
them to me in the world of HTML & JS ... what is attribute, what is
property and what is(are) their difference(s)?


I've found some online resources, but the explanation is very poor. :(



I'm asking this because I've read some discussions about Jquery mixing
attributes and properties ... and I found one problem with Jquery.
This is for David Mark's joy and happiness. :)


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/
TR/html4/strict.dtd">
<html>

<head>
<title>Mylib vs Jquery</title>

<script type="text/javascript" src="mylib.js"></script>
<script type="text/javascript" src="jquery-1.4.js"></script>

<script type="text/javascript">
window.onload = function() {
API.setAttribute(API.getEBI("mylibInput"), "type", "text");
$("#jqueryInput").attr("type", "text");
}
</script>

</head>

<body>

<input type="hidden" id="mylibInput">
<input type="hidden" id="jqueryInput">

</body>
</html>


Mylib sets attribute with no problem and input's type is changed to
"text".
On other hand Jquery throws exception:

uncaught exception: type property can't be changed


First of all ... I see that Jquery is mixing properties and attributes
(attr method tries to set property). And it isn't working (correct me
if my code isn't valid in some way). But, I've noticed that input's
~property~ can't be changed, but ~attribute~ can. And that confused
me, because attribute and property are the same in this case.


So, what's the difference between attribute and property?




Thanks for you answers.




Ivan
 
I

Ivan S

Mylib sets attribute with no problem and input's type is changed to
"text".

It doesn't work on IE7 (I haven't test it on other versions), other
mayor browsers works like charm. :)
 
D

David Mark

This is probably stupid question (Thomas, you can skip it :) ), but I
have to ask it ... :)

There are no stupid questions, just stupid people. :)
I think I don't really understand attributes and properties ... and
their difference, probably because their meaning is very similar (if
not the same) when I translate them on my native language. In some
way, I can understand difference in general, but can someone explain
them to me in the world of HTML & JS ... what is attribute, what is
property and what is(are) their difference(s)?

Attributes are nodes on the document tree. DOM properties provide an
interface to read and write attributes. The attibutes values are
always strings. DOM properties provide a higher-level interface,
converting attribute values (somewhat) according to the DOM specs and
filling in the cracks with browser/user defaults, as well as user data
(e.g. entered form control values).

For example, if there is a TABINDEX attribute node on the element (and
that element allows for that attribute), the tabIndex property
reflects it as a number. If there is no such attribute, the tabIndex
property returns the default tab index (usually 0 or -1, depending on
the type of element).

The attribute methods (e.g. getAttribute/setAttribute/removeAttribute)
provide a lower level interface than DOM properties and are virtually
_never_ needed in an HTML DOM as you can use the higher level DOM
interfaces. As with all of this stuff, the context dictates the
required interfaces. For example, an editor application would need
the attribute methods to convert a document to a canonical form (i.e.
without browser/user defaults or user data.

Also, the attribute methods are Broken as Designed in IE < 8 and IE8
compatibility mode, requiring non-trivial feature testing and evasive
action for the still-popular MS browser. So there's another reason to
avoid those methods entirely.
I've found some online resources, but the explanation is very poor. :(

Shocking. :) You'll find lots of online scripts that de
I'm asking this because I've read some discussions about Jquery mixing
attributes and properties ... and I found one problem with Jquery.

Yes, they have always been completely clueless about the difference.
What's the difference between you and them? You are in here asking
questions and they are over there with their heads in the sand,
pretending that there's no problem (crisis what crisis?) Resig's
"test-driven" development means nobody really understands anything
about browser scripting, so they peer at the latest major browsers
hoping to spot patterns (they've filled in a few cracks here and there
over the years, changing the behavior of the script a little with each
release) and ultimately giving up when the next batch of browsers
comes out (and then bitching at end-users for using "ancient"
browsers). This is how they see the "Real World" of software. No
shock that the end-users see it very differently (e.g. with lots of
script errors, broken pages, memory leaks, etc.)
This is for David Mark's joy and happiness. :)

No it isn't. I can't stand it that _all_ of those miserable
"standard", "major" pieces of shit are written by clueless hobbyists.
Apple, IBM and Yahoo. What do these three behemoths have in common?
They are all using browser sniffing diaries on their Websites, rather
than proper cross-browser scripts. Hard to believe they can't find
_anyone_ but free code monkeys to cobble together the "logic" that
runs their public sites.

Why do they think these "programmers" are free? It's absolute madness
from every perspective (particularly from a business perspective).
It's irritating to me as I have to browse the Web too and I _know_
their sites could have been done right as easily (or easier) as
wrong. But the hacks don't want to hear that as they are not
programmers at all (just pattern memorizers). It's like building a
house and letting the paper hangers draw up the plans.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/
TR/html4/strict.dtd">
<html>

<head>
<title>Mylib vs Jquery</title>

<script type="text/javascript" src="mylib.js"></script>
<script type="text/javascript" src="jquery-1.4.js"></script>

<script type="text/javascript">
window.onload = function() {
API.setAttribute(API.getEBI("mylibInput"), "type", "text");
$("#jqueryInput").attr("type", "text");}

</script>

Also see:-

http://www.cinsoft.net/attributes.html

....for the last pieces of this "puzzle". Those methods will be
transplanted into My Library shortly.
</head>

<body>

<input type="hidden" id="mylibInput">
<input type="hidden" id="jqueryInput">

</body>
</html>

Mylib sets attribute with no problem and input's type is changed to
"text".
On other hand Jquery throws exception:

uncaught exception: type property can't be changed

And actually, you picked the one they got "right". You can only set
the type property once in IE, so I have no problem with throwing an
exception for all. Of course, the My Library core does not use try-
catch at all.

Now, a function that sets multiple attributes should definitely set
the type attribute first. Document that the type property should
always be set first when using the single setter (e.g. setAttribute,
attr) method and recommend the multiple setter for beginners. Still,
the throw above is not a bad way to go.
First of all ... I see that Jquery is mixing properties and attributes
(attr method tries to set property). And it isn't working (correct me
if my code isn't valid in some way).

Do not use the attr method under any circumstances. It uses the above-
mentioned (taboo) attribute methods in some cases and properties for
others. It's a patchwork of observations and the equivalent of a
major fault line for apps built on top of jQuery. The major problem I
see is that virtually every jQuery book and example (typically written
by clueless, gushing journalists) uses the attr method. (!) This is a
DOM scripting library that complicates the hell out of DOM scripting
because the authors don't understand how documents work (and seem
completely unwilling to learn). I know. Who would put a penny on
them? :(
But, I've noticed that input's
~property~ can't be changed, but ~attribute~ can. And that confused
me, because attribute and property are the same in this case.

No, setting the value property does not change the value attribute.
It can't as the value attribute is reflected by the defaultValue
property. The original (default) value specified in the markup cannot
be stepped on by user input. This is the same for selected/
defaultSelected (options) and checked/defaultChecked (checkbox/radio
buttons).
So, what's the difference between attribute and property?

See above.
Thanks for you answers.

NP. Thanks for asking!
 
R

Richard Cornford

It doesn't work on IE7 (I haven't test it on other versions),
other mayor browsers works like charm. :)

From your OP I assume that you don't want Thomas to point out that
"doesn't work" is a worthless failure description, so I will.

If you really are trying to change an existing <input type="hidden">
field into an <input type="text"> field then you are not going to get
that to "work" cross-browser (or even that multi-browser).

Richard.
 
D

David Mark

It doesn't work on IE7 (I haven't test it on other versions), other
mayor browsers works like charm. :)

You can't set the type property (IE mixes up attributes and properties
behind the scenes) once it has been (explicitly or implicitly) set.
But I am sure there is some (soon to be removed) hack-y workaround in
My Library that can do it (replacing and returning a whole new node in
the process). What happened when you tried this in IE7?
 
I

Ivan S

Thanks! Now it's more clearer to me, although I think I'll have to
contemplate over some things for some time. :)
 
D

David Mark

You can't set the type property (IE mixes up attributes and properties
behind the scenes) once it has been (explicitly or implicitly) set.
But I am sure there is some (soon to be removed) hack-y workaround in
My Library that can do it (replacing and returning a whole new node in
the process). What happened when you tried this in IE7?

Oops, there was a typo short-circuiting the hack. Not that I care
about this particular behavior, but it had the potential to break more
meaningful workarounds. So it's fixed and you can actually change the
type attribute in IE (except IE8 standards mode, of course). As
mentioned, this hack will be gone shortly (and replaced with
documentation for setAttribute).

The typo was not present in the attributes test page, so this bug (and
a few others) would have been squashed on transplant anyway.
 
I

Ivan S

From your OP I assume that you don't want Thomas to point out that
"doesn't work" is a worthless failure description, so I will.

:)

That post was only for mr. Mark, I thought that was a bug in his
library (or IE7 only) ... but the bug was in my code. Nevermind that.

I'll try to post an error message in the future, I forgot it this
time.
If you really are trying to change an existing <input type="hidden">
field into an <input type="text"> field then you are not going to get
that to "work" cross-browser (or even that multi-browser).

Yes, I was trying to do that.
Ok, tnx, I'll find other solution.




Ivan
 
D

David Mark

Thanks! Now it's more clearer to me, although I think I'll have to
contemplate over some things for some time. :)


NP. Contemplation (and research) trumps ignorance every time. ;)
 
T

Thomas 'PointedEars' Lahn

Ivan said:
I think I don't really understand attributes and properties ... and
their difference, probably because their meaning is very similar (if
not the same) when I translate them on my native language. In some
way, I can understand difference in general, but can someone explain
them to me in the world of HTML & JS ... what is attribute, what is
property and what is(are) their difference(s)?

Skipping the differences between My Library and jQuery (you can find out
yourself why one works and the other does not by debugging), an attempt at
an explanation. Please read this carefully, do not hesistate to ask if
there are any further questions (and CMIIW):

Elements, as provided by an SGML-based markup language, have _attributes_.

<http://www.w3.org/TR/html4/intro/sgmltut.html#h-3.2>

For example, A elements have an attribute named `href':

<a href="http://foo.example/">...</a>

That attribute is declared in one of the HTML DTDs:

<!ATTLIST A
...
href CDATA #IMPLIED
...>

and defined in the HTML Specifications, for example in HTML 4.01:

<http://www.w3.org/TR/html4/struct/links.html#h-12.2>


Objects, as provided by an ECMAScript-based programming language, have
_properties_. For example, the object created with the Object initializer

{foo: "bar"}

has a property named `foo' with string value "bar".

In DOM implementations, elements are represented by host objects, called
"element objects". (They are termed "host objects" per the ECMAScript
Specifications as they are provided by the *host* runtime environment, not
the programming language [native, built-in] or the user [native, user-
defined]. Certain freedoms are afforded to host objects by the ECMAScript
Specifications as compared to other objects.) Those element objects can
implement certain interfaces (a common set of named values and behaviors).
Those element objects, like other objects, have properties.

Element objects can have "normal" properties: Properties that do not relate
to an attribute of the represented element. For example, most element
objects have a proprietary `offsetWidth' property. ("Proprietary" means
here that, although maybe widely implemented, there is no public standard
to specify that feature.)

Element objects also can have attribute properties: Properties that relate,
directly or indirectly, to the value of an attribute of the represented
element. Many, if not all of them, are standardized. An example would be
the `type' attribute property that relates to the `type' attribute in the
markup. Another common example is the `className' property that relates to
the `class' attribute of HTML elements.

And here is probably the major source of the confusion:

The W3C DOM API Specifications define interfaces. Interfaces have
attributes. But those attributes are not to be confused with the
attributes in the markup. Instead, they are implemented as properties on
the (element) object that implements the interface (if the term "property"
is used for those values in the programming language used to implement
them, as in the programming languages we are dealing with here).

However, as I said before, some of those *API* attributes, and consequently
some of the element object's properties, relate to the *markup* attributes
of the represented element.

Which is why the API terms them "property attributes"; while we, when
talking about DOM implementations, term them "attribute properties".
A less careful observer could easily get the idea that attributes and
properties are all the same.

<http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-642250288>
<http://www.w3.org/TR/DOM-Level-2-HTML/ecma-script-binding.html>

In addition, element objects implement methods that set or retrieve markup
attribute values. Those are the methods provided by the Element interface
of the W3C DOM Level 2+ Core Specifications: getAttribute(),
getAttributeNS(), setAttribute(), and setAttributeNS().

For historical reasons ("DOM Level 0"), attribute properties are usually
"live", meaning that their value would reflect the current status of the
element object. In most cases, attributes values as not retrieved using
attribute properties instead reflect the original state of the element as
it is in the markup. Example:

Let `o' be a reference to the object that represents the following element:

<input value="foo">

Now

o.value

would reflect the current status of the element object; that is, suppose
the user has replaced the control's value with "bar", it would yield "bar".
However,

o.getAttribute("value")

should still return "foo".

Finally, there are DOM implementations, most notably the MSHTML DOM, that
are not fully standards-compliant: They access attributes as if you would
access the attribute property and vice-versa. This adds to the confusion.


HTH

PointedEars
 
I

Ivan S

IE7 thrown an error saying:

Char: 11154
Error: Could not get the type property. This command is not supported.
Code: 0

As mentioned, this hack will be gone shortly (and replaced with documentation for setAttribute).


I think that's a great thing! :)
 
D

David Mark

IE7 thrown an error saying:

Char: 11154
Error: Could not get the type property. This command is not supported.
Code: 0

If you build a new library, it will now "work" for all but IE8
standards mode. But I don't want it to work like that, so soon it
will fail for all. Always set the type attribute/property _first_ (or
use a wrapper that does that for you).
I think that's a great thing! :)

Thanks!
 
I

Ivan S

Ivan said:
I think I don't really understand attributes and properties ... and
their difference, probably because their meaning is very similar (if
not the same) when I translate them on my native language. In some
way, I can understand difference in general, but can someone explain
them to me in the world of HTML & JS ... what is attribute, what is
property and what is(are) their difference(s)?

Skipping the differences between My Library and jQuery (you can find out
yourself why one works and the other does not by debugging), an attempt at
an explanation.  Please read this carefully, do not hesistate to ask if
there are any further questions (and CMIIW):

Elements, as provided by an SGML-based markup language, have _attributes_..

<http://www.w3.org/TR/html4/intro/sgmltut.html#h-3.2>

For example, A elements have an attribute named `href':

  <a href="http://foo.example/">...</a>

That attribute is declared in one of the HTML DTDs:

  <!ATTLIST A
     ...
     href  CDATA  #IMPLIED
     ...>

and defined in the HTML Specifications, for example in HTML 4.01:

<http://www.w3.org/TR/html4/struct/links.html#h-12.2>

Objects, as provided by an ECMAScript-based programming language, have
_properties_.  For example, the object created with the Object initializer

  {foo: "bar"}

has a property named `foo' with string value "bar".

In DOM implementations, elements are represented by host objects, called
"element objects".   (They are termed "host objects" per the ECMAScript
Specifications as they are provided by the *host* runtime environment, not
the programming language [native, built-in] or the user [native, user-
defined].  Certain freedoms are afforded to host objects by the ECMAScript
Specifications as compared to other objects.)  Those element objects can
implement certain interfaces (a common set of named values and behaviors)..  
Those element objects, like other objects, have properties.

Element objects can have "normal" properties: Properties that do not relate
to an attribute of the represented element.  For example, most element
objects have a proprietary `offsetWidth' property.  ("Proprietary" means
here that, although maybe widely implemented, there is no public standard
to specify that feature.)

Element objects also can have attribute properties: Properties that relate,
directly or indirectly, to the value of an attribute of the represented
element.  Many, if not all of them, are standardized.  An example would be
the `type' attribute property that relates to the `type' attribute in the
markup.  Another common example is the `className' property that relates to
the `class' attribute of HTML elements.

And here is probably the major source of the confusion:

The W3C DOM API Specifications define interfaces.  Interfaces have
attributes.  But those attributes are not to be confused with the
attributes in the markup.  Instead, they are implemented as properties on
the (element) object that implements the interface (if the term "property"
is used for those values in the programming language used to implement
them, as in the programming languages we are dealing with here).

However, as I said before, some of those *API* attributes, and consequently
some of the element object's properties, relate to the *markup* attributes
of the represented element.

Which is why the API terms them "property attributes"; while we, when
talking about DOM implementations, term them "attribute properties".
A less careful observer could easily get the idea that attributes and
properties are all the same.

<http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-642250288>
<http://www.w3.org/TR/DOM-Level-2-HTML/ecma-script-binding.html>

In addition, element objects implement methods that set or retrieve markup
attribute values.  Those are the methods provided by the Element interface
of the W3C DOM Level 2+ Core Specifications: getAttribute(),
getAttributeNS(), setAttribute(), and setAttributeNS().

For historical reasons ("DOM Level 0"), attribute properties are usually
"live", meaning that their value would reflect the current status of the
element object.  In most cases, attributes values as not retrieved using
attribute properties instead reflect the original state of the element as
it is in the markup.  Example:

Let `o' be a reference to the object that represents the following element:

  <input value="foo">

Now

  o.value

would reflect the current status of the element object; that is, suppose
the user has replaced the control's value with "bar", it would yield "bar".  
However,

  o.getAttribute("value")

should still return "foo".

Finally, there are DOM implementations, most notably the MSHTML DOM, that
are not fully standards-compliant: They access attributes as if you would
access the attribute property and vice-versa.  This adds to the confusion.

HTH

PointedEars


Thanks for very technical answer. :)


I'll read it all carefully once more very soon (I don't have much time
right now) and shall return if I'll have more question.
 
D

David Mark

If you build a new library, it will now "work" for all but IE8
standards mode. But I don't want it to work like that, so soon it
will fail for all. Always set the type attribute/property _first_ (or
use a wrapper that does that for you).

And that wrapper is API.createElementWithAttributes:-

var el = API.createElementWithAttributes('input', {
name:'hello'
type:'hidden'
value:'world'
});

The type attribute will be set first, so that's one less thing for you
to worry about (and renders the aforementioned hack superfluous).

There is a similar issue with the name attribute/property in that it
must be set after appending the element if it is to show up in the
appropriate DOM collection (e.g. document.forms, document.images,
window.frames). That is an issue best handled with a wrapper that
creates _and_ appends an element. Call it
createAndAppendElementWithAttributes perhaps? Yes, the typical
library devotee will cry foul at all of that typing. Of course, I
call a foul any time I have to read their "concise" (read illegible)
bullshit. :)
 
I

Ivan S

If you build a new library, it will now "work" for all but IE8
standards mode.  But I don't want it to work like that, so soon it
will fail for all.  Always set the type attribute/property _first_ (or
use a wrapper that does that for you).

The problem is that I already have a markup with hidden input fields
which now has to be shown to the user if he clicks on the checkbox
(nevermind why).
The simplest solution was to change type property using javascript ...
but it didn't work (I didn't know that I can't change type property
once it is set).

I could replace that ("hidden") element with new one ("text") when
user clicks checkbox using DOM methods, but I think simpler solution
is to change markup ("hidden" to "text") and than simply hide that
input elements and show them when user clicks on checkbox.
 
T

Thomas 'PointedEars' Lahn

David said:
And that wrapper is API.createElementWithAttributes:-

You can't be serious. What's wrong with `API.createElement', the `API'
aside (see below)?
[...]
There is a similar issue with the name attribute/property in that it
must be set after appending the element if it is to show up in the
appropriate DOM collection (e.g. document.forms, document.images,
window.frames). That is an issue best handled with a wrapper that
creates _and_ appends an element. Call it
createAndAppendElementWithAttributes perhaps?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
No, thanks.
Yes, the typical library devotee will cry foul at all of that typing.

You forgot to consider the shades of gray. It is not just about typing.
Of course, I call a foul any time I have to read their "concise" (read
illegible) bullshit. :)

You can make code readable and concise.

BTW, I don't think the container object should be referrable through `API',
but something less ambiguous (and less error-prone?), say `MyLib', instead.
Is it even intended to be a constructor?


PointedEars
 
T

Thomas 'PointedEars' Lahn

Ivan said:
The problem is that I already have a markup with hidden input fields
which now has to be shown to the user if he clicks on the checkbox
(nevermind why).
The simplest solution was to change type property using javascript ...
but it didn't work (I didn't know that I can't change type property
once it is set).

But you can, just not in the MSHTML DOM. Instead of dealing with the
`value' attribute/property security issue as reasonable implementations like
Gecko, M$ throws exceptions on setting `type' afterwards. We've been over
this.

The obvious solution is not to toggle the `type' of the control but the
visibility of the element: Use the `visibility' or `display' style
properties to hide/show it.

Either one is poor UI design, though. Disable/enable the always visible
input element instead; if the default state is disabled, disable it onload
the document body so that it is still usable without scripting (unless, of
course, a real form submission is needed anyway to re-enable it).


PointedEars
 
D

David Mark

And that wrapper is API.createElementWithAttributes:-

You can't be serious. What's wrong with `API.createElement', the `API'
aside (see below)?
[...]
There is a similar issue with the name attribute/property in that it
must be set after appending the element if it is to show up in the
appropriate DOM collection (e.g. document.forms, document.images,
window.frames). That is an issue best handled with a wrapper that
creates _and_ appends an element. Call it
createAndAppendElementWithAttributes perhaps?

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
No, thanks.
Yes, the typical library devotee will cry foul at all of that typing.

You forgot to consider the shades of gray. It is not just about typing.

Absolutely. It isn't about typing at all. That's what I find so
humorous about the whole "do more, type less, debug forever" mantra.
The amount of "typing" (quotes indicate macros, Intellisense, etc. may
be used) is irrelevant.
You can make code readable and concise.

Absolutely. I don't think the length of an identifier makes it any
more or less concise. The question is whether it describes the value.
BTW, I don't think the container object should be referrable through `API',
but something less ambiguous (and less error-prone?), say `MyLib', instead.

Possibly. Of course, that's more typing. :)
Is it even intended to be a constructor?

No, it is a reference to an Object object that is a (mostly) flat
"namespace" of methods (and a few non-method properties). I stopped
short of creating a hierarchical namespace as it was determined that
it would add overhead with no benefit to the user. You know at build
(or pre-build test) time what interfaces are possible (from the
documentation or console), so there is no need to provide an
indication of which modules provided each. In other words, there is
no concept of modules once the library is built. It's just a single
(dynamic at run time) API at that point.

And all caps means global to me. I know, why isn't my "global" call
caps? That's just the way I wrote it back then. I use "GLOBAL" now.
 
D

David Mark

You can't be serious.

I assure you I am. :)
What's wrong with `API.createElement', the `API'
aside (see below)?

It's not a contest and those are apples and oranges. The
createElementWithAttributes method is built on top of createElement.
I think the names make that clear and the longer wrapper takes care of
the issue with the type property. ;)
[...]
There is a similar issue with the name attribute/property in that it
must be set after appending the element if it is to show up in the
appropriate DOM collection (e.g. document.forms, document.images,
window.frames). That is an issue best handled with a wrapper that
creates _and_ appends an element. Call it
createAndAppendElementWithAttributes perhaps?

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
No, thanks.

Because it is a long name? Then do this:-

var myCoolMethod = API.createAndAppendElementWithAttributes;

myCoolMethod('input', { name:'test', type:'button', value='test' },
document.forms['myform']);

Then you know that the type and name issues are taken care of. For
the latter issue, the wrapper will set the name property _after_
appending the element. I believe for IFRAME elements, it is necessary
to set el.contentWindow.name as well. That's about it. I'll add it
when I get a chance.
 
T

Thomas 'PointedEars' Lahn

David said:
Absolutely. I don't think the length of an identifier makes it any
more or less concise. The question is whether it describes the value.

Last I checked, shortness was one attribute that defined "concise".
And all caps means global to me. I know, why isn't my "global" call
caps? That's just the way I wrote it back then. I use "GLOBAL" now.

I don't think that's a good idea.


PointedEars
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top