rebased branch from master
This commit is contained in:
parent
270f4d5653
commit
f2d11021a3
29
CHANGES.rst
29
CHANGES.rst
@ -4,20 +4,39 @@ Changelog
|
|||||||
2.3.0 (unreleased)
|
2.3.0 (unreleased)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
- Corrections and additions to the Danish translation
|
||||||
|
[aputtu]
|
||||||
|
|
||||||
|
- Put defaultUser.png instead of old defaultUser.gif
|
||||||
|
[bsuttor]
|
||||||
|
|
||||||
|
- Remove bbb directory. bbb was never really implemented.
|
||||||
|
[timo]
|
||||||
|
|
||||||
|
- Replace deprecated test assert statements.
|
||||||
|
[timo]
|
||||||
|
|
||||||
|
- Remove portal_discussion tool.
|
||||||
|
[timo]
|
||||||
|
|
||||||
|
- Refactor tests to use the PLONE_APP_CONTENTTYPES_FIXTURE instead of
|
||||||
|
PLONE_FIXTURE.
|
||||||
|
[timo]
|
||||||
|
|
||||||
|
- Fix ownership of comments. [toutpt]
|
||||||
|
|
||||||
- Provide 'delete own comments' as a configurable option
|
- Provide 'delete own comments' as a configurable option
|
||||||
[gyst]
|
[gyst]
|
||||||
|
|
||||||
- Make comments editable.
|
- Make comments editable.
|
||||||
[pjstevns, gyst]
|
[pjstevns, gyst]
|
||||||
|
|
||||||
- Refactor tests to use the PLONE_APP_CONTENTTYPES_FIXTURE instead of the PLONE_FIXTURE.
|
|
||||||
[timo]
|
|
||||||
|
|
||||||
|
|
||||||
2.2.10 (2013-09-24)
|
2.2.10 (2013-09-24)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
- Revert "Refactor tests to use the PLONE_APP_CONTENTTYPES_FIXTURE instead of the PLONE_FIXTURE." that has been accidentially introduced into the 2.2.9 release.
|
- Revert "Refactor tests to use the PLONE_APP_CONTENTTYPES_FIXTURE instead of
|
||||||
|
the PLONE_FIXTURE." that has been accidentially introduced into the 2.2.9
|
||||||
|
release.
|
||||||
[timo]
|
[timo]
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ package-extras = [test]
|
|||||||
parts +=
|
parts +=
|
||||||
mkrelease
|
mkrelease
|
||||||
pocompile
|
pocompile
|
||||||
|
code-analysis
|
||||||
|
|
||||||
[mkrelease]
|
[mkrelease]
|
||||||
recipe = zc.recipe.egg
|
recipe = zc.recipe.egg
|
||||||
@ -14,7 +15,13 @@ eggs = jarn.mkrelease
|
|||||||
recipe = zc.recipe.egg
|
recipe = zc.recipe.egg
|
||||||
eggs = zest.pocompile
|
eggs = zest.pocompile
|
||||||
|
|
||||||
|
[code-analysis]
|
||||||
|
recipe = plone.recipe.codeanalysis
|
||||||
|
directory = ${buildout:directory}/plone/app/discussion
|
||||||
|
flake8-max-complexity = 50
|
||||||
|
|
||||||
[versions]
|
[versions]
|
||||||
plone.app.discussion =
|
plone.app.discussion =
|
||||||
zope.interface = 4.0.5
|
zope.interface = 4.0.5
|
||||||
|
plone.app.portlets = 2.5a1
|
||||||
|
|
||||||
|
@ -196,6 +196,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
|||||||
# Member
|
# Member
|
||||||
member = portal_membership.getAuthenticatedMember()
|
member = portal_membership.getAuthenticatedMember()
|
||||||
username = member.getUserName()
|
username = member.getUserName()
|
||||||
|
user = member.getUser()
|
||||||
email = member.getProperty('email')
|
email = member.getProperty('email')
|
||||||
fullname = member.getProperty('fullname')
|
fullname = member.getProperty('fullname')
|
||||||
if not fullname or fullname == '':
|
if not fullname or fullname == '':
|
||||||
@ -205,6 +206,8 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
|||||||
fullname = unicode(fullname, 'utf-8')
|
fullname = unicode(fullname, 'utf-8')
|
||||||
if email and isinstance(email, str):
|
if email and isinstance(email, str):
|
||||||
email = unicode(email, 'utf-8')
|
email = unicode(email, 'utf-8')
|
||||||
|
comment.changeOwnership(user, recursive=False)
|
||||||
|
comment.manage_setLocalRoles(username, ["Owner"])
|
||||||
comment.creator = username
|
comment.creator = username
|
||||||
comment.author_username = username
|
comment.author_username = username
|
||||||
comment.author_name = fullname
|
comment.author_name = fullname
|
||||||
|
@ -184,38 +184,6 @@ class ICaptcha(Interface):
|
|||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
|
|
||||||
class ICommentingTool(Interface):
|
|
||||||
"""A tool that indexes all comments for usage by the management interface.
|
|
||||||
|
|
||||||
This means the management interface can still work even though we don't
|
|
||||||
index the comments in portal_catalog.
|
|
||||||
|
|
||||||
The default implementation of this interface simply defers to
|
|
||||||
portal_catalog, but a custom version of the tool can be used to provide
|
|
||||||
an alternate indexing mechanism.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def indexObject(comment):
|
|
||||||
"""Indexes a comment
|
|
||||||
"""
|
|
||||||
|
|
||||||
def reindexObject(comment):
|
|
||||||
"""Reindex a comment
|
|
||||||
"""
|
|
||||||
|
|
||||||
def unindexObject(comment):
|
|
||||||
"""Removes a comment from the indexes
|
|
||||||
"""
|
|
||||||
|
|
||||||
def uniqueValuesFor(name):
|
|
||||||
"""Get unique values for FieldIndex name
|
|
||||||
"""
|
|
||||||
|
|
||||||
def searchResults(REQUEST=None, **kw):
|
|
||||||
"""Perform a search over all indexed comments.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class IDiscussionSettings(Interface):
|
class IDiscussionSettings(Interface):
|
||||||
"""Global discussion settings. This describes records stored in the
|
"""Global discussion settings. This describes records stored in the
|
||||||
configuration registry and obtainable via plone.registry.
|
configuration registry and obtainable via plone.registry.
|
||||||
@ -392,3 +360,11 @@ class IDiscussionSettings(Interface):
|
|||||||
class IDiscussionLayer(Interface):
|
class IDiscussionLayer(Interface):
|
||||||
"""Request marker installed via browserlayer.xml.
|
"""Request marker installed via browserlayer.xml.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class ICommentingTool(Interface):
|
||||||
|
"""For backwards-compatibility.
|
||||||
|
|
||||||
|
This can be removed once we no longer support upgrading from versions
|
||||||
|
of Plone that had a portal_discussion tool.
|
||||||
|
"""
|
||||||
|
@ -16,11 +16,11 @@ msgstr ""
|
|||||||
|
|
||||||
#: ../comment.py:311
|
#: ../comment.py:311
|
||||||
msgid "A comment has been posted."
|
msgid "A comment has been posted."
|
||||||
msgstr "En kommentar er gem."
|
msgstr "Der er oprettet en kommentar."
|
||||||
|
|
||||||
#: ../interfaces.py:141
|
#: ../interfaces.py:141
|
||||||
msgid "A comment id unique to this conversation"
|
msgid "A comment id unique to this conversation"
|
||||||
msgstr "En kommentar-id som er unik for denne dialog"
|
msgstr "Et kommentar-id som er unikt for denne dialog"
|
||||||
|
|
||||||
#: ../browser/comments.py:72
|
#: ../browser/comments.py:72
|
||||||
msgid "Add a comment"
|
msgid "Add a comment"
|
||||||
@ -64,7 +64,7 @@ msgstr "Oprettelses-dato"
|
|||||||
|
|
||||||
#: ../interfaces.py:40
|
#: ../interfaces.py:40
|
||||||
msgid "Date of the most recent public comment"
|
msgid "Date of the most recent public comment"
|
||||||
msgstr ""
|
msgstr "Dato for den seneste, offentlige kommentar"
|
||||||
|
|
||||||
#: ../vocabularies.py:44
|
#: ../vocabularies.py:44
|
||||||
msgid "Disabled"
|
msgid "Disabled"
|
||||||
@ -80,7 +80,7 @@ msgstr "Redigering blev afbrudt"
|
|||||||
|
|
||||||
#: ../interfaces.py:153
|
#: ../interfaces.py:153
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "Email"
|
msgstr "E-mail"
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:63
|
#: ../browser/controlpanel.py:63
|
||||||
msgid "Enable Comments"
|
msgid "Enable Comments"
|
||||||
@ -88,7 +88,7 @@ msgstr "Slå kommentarer til"
|
|||||||
|
|
||||||
#: ../interfaces.py:144
|
#: ../interfaces.py:144
|
||||||
msgid "Id of comment this comment is in reply to"
|
msgid "Id of comment this comment is in reply to"
|
||||||
msgstr "Id'en på den kommentar, denne kommentar er et svar til"
|
msgstr "Id'et på den kommentar, denne kommentar er et svar til"
|
||||||
|
|
||||||
#: ../interfaces.py:158
|
#: ../interfaces.py:158
|
||||||
msgid "MIME type"
|
msgid "MIME type"
|
||||||
@ -108,7 +108,7 @@ msgstr "Navn"
|
|||||||
|
|
||||||
#: ../interfaces.py:162
|
#: ../interfaces.py:162
|
||||||
msgid "Notify me of new comments via email."
|
msgid "Notify me of new comments via email."
|
||||||
msgstr "Send besked om nye kommentarer pr. email."
|
msgstr "Send besked om nye kommentarer per e-mail."
|
||||||
|
|
||||||
#: ./plone.app.discussion/plone/app/discussion/configure.zcml
|
#: ./plone.app.discussion/plone/app/discussion/configure.zcml
|
||||||
msgid "Plone Discussions"
|
msgid "Plone Discussions"
|
||||||
@ -128,23 +128,23 @@ msgstr "Liste over kommentatorer (brugernavne)"
|
|||||||
|
|
||||||
#: ../interfaces.py:50
|
#: ../interfaces.py:50
|
||||||
msgid "The set of unique commentators (usernames) of published_comments"
|
msgid "The set of unique commentators (usernames) of published_comments"
|
||||||
msgstr ""
|
msgstr "Gruppen af unikke kommentatorer (brugernavne) fra published_comments"
|
||||||
|
|
||||||
#: ../interfaces.py:34
|
#: ../interfaces.py:34
|
||||||
msgid "Total number of public comments on this item"
|
msgid "Total number of public comments on this item"
|
||||||
msgstr ""
|
msgstr "Det samlede antal offentlige kommentarer til dette element"
|
||||||
|
|
||||||
#: ../comment.py:158
|
#: ../comment.py:158
|
||||||
msgid "Transform '%s' => '%s' not available. Failed to transform comment '%s'."
|
msgid "Transform '%s' => '%s' not available. Failed to transform comment '%s'."
|
||||||
msgstr ""
|
msgstr "Transformation '%s' => '%s' er ikke muligt. Mislykkedes med at transformere kommentaren '%s'."
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:69
|
#: ../browser/controlpanel.py:69
|
||||||
msgid "User Email Notification"
|
msgid "User Email Notification"
|
||||||
msgstr "Email-notificering af brugere"
|
msgstr "E-mail-notificering af brugere"
|
||||||
|
|
||||||
#: ../interfaces.py:166
|
#: ../interfaces.py:166
|
||||||
msgid "Username of the commenter"
|
msgid "Username of the commenter"
|
||||||
msgstr ""
|
msgstr "Kommentatorens brugernavn"
|
||||||
|
|
||||||
#: ../browser/comments.py:244
|
#: ../browser/comments.py:244
|
||||||
msgid "Your comment awaits moderator approval."
|
msgid "Your comment awaits moderator approval."
|
||||||
@ -168,7 +168,7 @@ msgstr "Godkend"
|
|||||||
#. Default: "You can add a comment by filling out the form below. Plain text formatting. Web and email addresses are transformed into clickable links."
|
#. Default: "You can add a comment by filling out the form below. Plain text formatting. Web and email addresses are transformed into clickable links."
|
||||||
#: ../browser/comments.py:57
|
#: ../browser/comments.py:57
|
||||||
msgid "comment_description_intelligent_text"
|
msgid "comment_description_intelligent_text"
|
||||||
msgstr "Du kan tilføje en kommentar ved at udfylde formularen nedenfor. Ren tekst-formattering. Web- og emailadresser bliver automatisk lavet om til klikbare links."
|
msgstr "Du kan tilføje en kommentar ved at udfylde formularen nedenfor. Ren tekst-formattering. Web- og e-mailadresser bliver automatisk lavet om til klikbare links."
|
||||||
|
|
||||||
#. Default: "You can add a comment by filling out the form below. Plain text formatting. You can use the Markdown syntax for links and images."
|
#. Default: "You can add a comment by filling out the form below. Plain text formatting. You can use the Markdown syntax for links and images."
|
||||||
#: ../browser/comments.py:51
|
#: ../browser/comments.py:51
|
||||||
|
@ -2,7 +2,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: plone.app.discussion\n"
|
"Project-Id-Version: plone.app.discussion\n"
|
||||||
"POT-Creation-Date: YEAR-MO-DA HO:MI +ZONE\n"
|
"POT-Creation-Date: YEAR-MO-DA HO:MI +ZONE\n"
|
||||||
"PO-Revision-Date: 2012-02-08 09:14+0100\n"
|
"PO-Revision-Date: 2013-11-14 09:09+0100\n"
|
||||||
"Last-Translator: Mikel Larreategi <mlarreategi@codesyntax.com>\n"
|
"Last-Translator: Mikel Larreategi <mlarreategi@codesyntax.com>\n"
|
||||||
"Language-Team: eu <eu@li.org>\n"
|
"Language-Team: eu <eu@li.org>\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
@ -15,11 +15,11 @@ msgstr ""
|
|||||||
"Domain: DOMAIN\n"
|
"Domain: DOMAIN\n"
|
||||||
"X-Poedit-Language: Basque\n"
|
"X-Poedit-Language: Basque\n"
|
||||||
|
|
||||||
#: ../comment.py:311
|
#: ../comment.py:326
|
||||||
msgid "A comment has been posted."
|
msgid "A comment has been posted."
|
||||||
msgstr "Erantzun bat argitaratu da."
|
msgstr "Erantzun bat argitaratu da."
|
||||||
|
|
||||||
#: ../interfaces.py:141
|
#: ../interfaces.py:143
|
||||||
msgid "A comment id unique to this conversation"
|
msgid "A comment id unique to this conversation"
|
||||||
msgstr "Eztabaida honetarako bakarra den erantzunaren id-a."
|
msgstr "Eztabaida honetarako bakarra den erantzunaren id-a."
|
||||||
|
|
||||||
@ -27,16 +27,16 @@ msgstr "Eztabaida honetarako bakarra den erantzunaren id-a."
|
|||||||
msgid "Add a comment"
|
msgid "Add a comment"
|
||||||
msgstr "Erantzuna gehitu"
|
msgstr "Erantzuna gehitu"
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:64
|
#: ../browser/controlpanel.py:66
|
||||||
msgid "Anonymous Comments"
|
msgid "Anonymous Comments"
|
||||||
msgstr "Erantzun anonimoak"
|
msgstr "Erantzun anonimoak"
|
||||||
|
|
||||||
#: ../browser/comments.py:251
|
#: ../browser/comments.py:258
|
||||||
#: ../browser/controlpanel.py:82
|
#: ../browser/controlpanel.py:84
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Utzi"
|
msgstr "Utzi"
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:78
|
#: ../browser/controlpanel.py:80
|
||||||
msgid "Changes saved"
|
msgid "Changes saved"
|
||||||
msgstr "Aldaketak gordeta"
|
msgstr "Aldaketak gordeta"
|
||||||
|
|
||||||
@ -48,24 +48,24 @@ msgstr "Erantzuna onartuta."
|
|||||||
msgid "Comment deleted."
|
msgid "Comment deleted."
|
||||||
msgstr "Erantzuna ezabatuta."
|
msgstr "Erantzuna ezabatuta."
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:65
|
#: ../browser/controlpanel.py:67
|
||||||
msgid "Commenter Image"
|
msgid "Commenter Image"
|
||||||
msgstr "Erantzuna eman duenaren irudia."
|
msgstr "Erantzuna eman duenaren irudia."
|
||||||
|
|
||||||
msgid "Commenting infrastructure for Plone"
|
msgid "Commenting infrastructure for Plone"
|
||||||
msgstr "Ploneren Erantzunen Azpiegitura"
|
msgstr "Ploneren Erantzunen Azpiegitura"
|
||||||
|
|
||||||
#: ../interfaces.py:136
|
#: ../interfaces.py:138
|
||||||
msgid "Conversation"
|
msgid "Conversation"
|
||||||
msgstr "Eztabaida"
|
msgstr "Eztabaida"
|
||||||
|
|
||||||
#: ../interfaces.py:167
|
#: ../interfaces.py:176
|
||||||
msgid "Creation date"
|
msgid "Creation date"
|
||||||
msgstr "Sorrera data"
|
msgstr "Sorrera data"
|
||||||
|
|
||||||
#: ../interfaces.py:40
|
#: ../interfaces.py:40
|
||||||
msgid "Date of the most recent public comment"
|
msgid "Date of the most recent public comment"
|
||||||
msgstr ""
|
msgstr "Azken erantzunaren data"
|
||||||
|
|
||||||
#: ../vocabularies.py:44
|
#: ../vocabularies.py:44
|
||||||
msgid "Disabled"
|
msgid "Disabled"
|
||||||
@ -75,39 +75,39 @@ msgstr "Desaktibatuta"
|
|||||||
msgid "Discussion settings"
|
msgid "Discussion settings"
|
||||||
msgstr "Eztabaidaren ezarpenak"
|
msgstr "Eztabaidaren ezarpenak"
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:84
|
#: ../browser/controlpanel.py:86
|
||||||
msgid "Edit cancelled"
|
msgid "Edit cancelled"
|
||||||
msgstr "Edizioa utzita"
|
msgstr "Edizioa utzita"
|
||||||
|
|
||||||
#: ../interfaces.py:153
|
#: ../interfaces.py:155
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "E-posta"
|
msgstr "E-posta"
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:63
|
#: ../browser/controlpanel.py:65
|
||||||
msgid "Enable Comments"
|
msgid "Enable Comments"
|
||||||
msgstr "Erantzunak aktibatu"
|
msgstr "Erantzunak aktibatu"
|
||||||
|
|
||||||
#: ../interfaces.py:144
|
#: ../interfaces.py:146
|
||||||
msgid "Id of comment this comment is in reply to"
|
msgid "Id of comment this comment is in reply to"
|
||||||
msgstr "Erantzun honek erreferentzia egiten dion erantzunaren id-a"
|
msgstr "Erantzun honek erreferentzia egiten dion erantzunaren id-a"
|
||||||
|
|
||||||
#: ../interfaces.py:158
|
#: ../interfaces.py:160
|
||||||
msgid "MIME type"
|
msgid "MIME type"
|
||||||
msgstr "MIME mota"
|
msgstr "MIME mota"
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:67
|
#: ../browser/controlpanel.py:69
|
||||||
msgid "Moderator Email Notification"
|
msgid "Moderator Email Notification"
|
||||||
msgstr "Moderatzailea e-postaz abisatu"
|
msgstr "Moderatzailea e-postaz abisatu"
|
||||||
|
|
||||||
#: ../interfaces.py:168
|
#: ../interfaces.py:177
|
||||||
msgid "Modification date"
|
msgid "Modification date"
|
||||||
msgstr "Aldaketa data"
|
msgstr "Aldaketa data"
|
||||||
|
|
||||||
#: ../interfaces.py:138
|
#: ../interfaces.py:140
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Izena"
|
msgstr "Izena"
|
||||||
|
|
||||||
#: ../interfaces.py:162
|
#: ../interfaces.py:169
|
||||||
msgid "Notify me of new comments via email."
|
msgid "Notify me of new comments via email."
|
||||||
msgstr "Erantzun berriak e-postaz bidali"
|
msgstr "Erantzun berriak e-postaz bidali"
|
||||||
|
|
||||||
@ -115,11 +115,11 @@ msgstr "Erantzun berriak e-postaz bidali"
|
|||||||
msgid "Plone Discussions"
|
msgid "Plone Discussions"
|
||||||
msgstr "Plone Eztabaidak"
|
msgstr "Plone Eztabaidak"
|
||||||
|
|
||||||
#: ../interfaces.py:131
|
#: ../interfaces.py:133
|
||||||
msgid "Portal type"
|
msgid "Portal type"
|
||||||
msgstr "Elementu mota"
|
msgstr "Elementu mota"
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:71
|
#: ../browser/controlpanel.py:73
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Gorde"
|
msgstr "Gorde"
|
||||||
|
|
||||||
@ -129,30 +129,30 @@ msgstr "Erantzunak eman dituzten erabiltzaileak (erabiltzaile-izenak)"
|
|||||||
|
|
||||||
#: ../interfaces.py:50
|
#: ../interfaces.py:50
|
||||||
msgid "The set of unique commentators (usernames) of published_comments"
|
msgid "The set of unique commentators (usernames) of published_comments"
|
||||||
msgstr ""
|
msgstr "Erantzun-emaleen erabiltzaile izenak"
|
||||||
|
|
||||||
#: ../interfaces.py:34
|
#: ../interfaces.py:34
|
||||||
msgid "Total number of public comments on this item"
|
msgid "Total number of public comments on this item"
|
||||||
msgstr ""
|
msgstr "Elementu honen erantzun publiko kopurua"
|
||||||
|
|
||||||
#: ../comment.py:158
|
#: ../comment.py:158
|
||||||
msgid "Transform '%s' => '%s' not available. Failed to transform comment '%s'."
|
msgid "Transform '%s' => '%s' not available."
|
||||||
msgstr ""
|
msgstr "'%s' => '%s' eraldaketa ez dago erabilgarri."
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:69
|
#: ../browser/controlpanel.py:71
|
||||||
msgid "User Email Notification"
|
msgid "User Email Notification"
|
||||||
msgstr "E-posta abisuak"
|
msgstr "E-posta abisuak"
|
||||||
|
|
||||||
#: ../interfaces.py:166
|
#: ../interfaces.py:175
|
||||||
msgid "Username of the commenter"
|
msgid "Username of the commenter"
|
||||||
msgstr ""
|
msgstr "Erantzuna utzi duenaren erabiltzaile-izena"
|
||||||
|
|
||||||
#: ../browser/comments.py:244
|
#: ../browser/comments.py:251
|
||||||
msgid "Your comment awaits moderator approval."
|
msgid "Your comment awaits moderator approval."
|
||||||
msgstr "Zure erantzuna moderazio kolan dago."
|
msgstr "Zure erantzuna moderazio kolan dago."
|
||||||
|
|
||||||
#. Default: "Comment"
|
#. Default: "Comment"
|
||||||
#: ../browser/comments.py:131
|
#: ../browser/comments.py:132
|
||||||
msgid "add_comment_button"
|
msgid "add_comment_button"
|
||||||
msgstr "Eman erantzuna"
|
msgstr "Eman erantzuna"
|
||||||
|
|
||||||
@ -188,9 +188,8 @@ msgstr "Erantzuna formulario hau betez utzi dezakezu. Formatua testu arruntarena
|
|||||||
|
|
||||||
#. Default: "${author_name} on ${content}"
|
#. Default: "${author_name} on ${content}"
|
||||||
#: ../comment.py:48
|
#: ../comment.py:48
|
||||||
#, fuzzy
|
|
||||||
msgid "comment_title"
|
msgid "comment_title"
|
||||||
msgstr "${creator} ${content} buruz"
|
msgstr "${content} - ${creator}"
|
||||||
|
|
||||||
#. Default: "Action"
|
#. Default: "Action"
|
||||||
#: ../browser/moderation.pt:85
|
#: ../browser/moderation.pt:85
|
||||||
@ -223,17 +222,17 @@ msgid "heading_moderate_comments"
|
|||||||
msgstr "Erantzunak moderatu"
|
msgstr "Erantzunak moderatu"
|
||||||
|
|
||||||
#. Default: "If selected, anonymous users are able to post comments without loggin in. It is highly recommended to use a captcha solution to prevent spam if this setting is enabled."
|
#. Default: "If selected, anonymous users are able to post comments without loggin in. It is highly recommended to use a captcha solution to prevent spam if this setting is enabled."
|
||||||
#: ../interfaces.py:236
|
#: ../interfaces.py:215
|
||||||
msgid "help_anonymous_comments"
|
msgid "help_anonymous_comments"
|
||||||
msgstr "Aukeratuta badago, erabiltzaile anonimoek erantzunak gehitu ditzakete login egin gabe. Berariaz gomendatzen dizugu Captcha kontrolen bat aktibatzea anonimoen erantzunak baimentzen badituzu."
|
msgstr "Aukeratuta badago, erabiltzaile anonimoek erantzunak gehitu ditzakete login egin gabe. Berariaz gomendatzen dizugu Captcha kontrolen bat aktibatzea anonimoen erantzunak baimentzen badituzu."
|
||||||
|
|
||||||
#. Default: "If selected, anonymous user will have to give their email."
|
#. Default: "If selected, anonymous user will have to give their email."
|
||||||
#: ../interfaces.py:334
|
#: ../interfaces.py:330
|
||||||
msgid "help_anonymous_email_enabled"
|
msgid "help_anonymous_email_enabled"
|
||||||
msgstr ""
|
msgstr "Aukeratuta badago, erabiltzaile anonimoek eposta helbidea idatzi beharko dute"
|
||||||
|
|
||||||
#. Default: "Use this setting to enable or disable Captcha validation for comments. Install plone.formwidget.captcha, plone.formwidget.recaptcha, collective.akismet, or collective.z3cform.norobots if there are no options available."
|
#. Default: "Use this setting to enable or disable Captcha validation for comments. Install plone.formwidget.captcha, plone.formwidget.recaptcha, collective.akismet, or collective.z3cform.norobots if there are no options available."
|
||||||
#: ../interfaces.py:279
|
#: ../interfaces.py:265
|
||||||
msgid "help_captcha"
|
msgid "help_captcha"
|
||||||
msgstr "Erabili aukera hau Captcha aktibatu edo desaktibatzeko. Instalatu plone.formwidget.captcha, plone.formwidget.recaptcha, collective.akismet edo collective.z3cform.norobots aukerarik ez baldin badago."
|
msgstr "Erabili aukera hau Captcha aktibatu edo desaktibatzeko. Instalatu plone.formwidget.captcha, plone.formwidget.recaptcha, collective.akismet edo collective.z3cform.norobots aukerarik ez baldin badago."
|
||||||
|
|
||||||
@ -246,55 +245,55 @@ msgstr ""
|
|||||||
"Erantzunen Moderazio Workflowa aktibatzeko, joan elementu-moten kontrol panelera, aukeratu 'Erantzuna' eta ezarri 'Erantzunen Moderazio Workflowa'."
|
"Erantzunen Moderazio Workflowa aktibatzeko, joan elementu-moten kontrol panelera, aukeratu 'Erantzuna' eta ezarri 'Erantzunen Moderazio Workflowa'."
|
||||||
|
|
||||||
#. Default: "If selected, users are able to post comments on the site. Though, you have to enable comments for specific content types, folders or content objects before users will be able to post comments."
|
#. Default: "If selected, users are able to post comments on the site. Though, you have to enable comments for specific content types, folders or content objects before users will be able to post comments."
|
||||||
#: ../interfaces.py:224
|
#: ../interfaces.py:201
|
||||||
msgid "help_globally_enabled"
|
msgid "help_globally_enabled"
|
||||||
msgstr "Aukeratuta badago, atarian erantzunak gehitu daitezke. Edonola ere, elementu-mota bakoitzarentzat erantzunak baimendu beharko dituzu erabiltzaileak erantzunak ematen hasi aurretik."
|
msgstr "Aukeratuta badago, atarian erantzunak gehitu daitezke. Edonola ere, elementu-mota bakoitzarentzat erantzunak baimendu beharko dituzu erabiltzaileak erantzunak ematen hasi aurretik."
|
||||||
|
|
||||||
#. Default: "If selected, comments will enter a 'Pending' state in which they are invisible to the public. A user with the 'Review comments' permission ('Reviewer' or 'Manager') can approve comments to make them visible to the public. If you want to enable a custom comment workflow, you have to go to the types control panel."
|
#. Default: "If selected, comments will enter a 'Pending' state in which they are invisible to the public. A user with the 'Review comments' permission ('Reviewer' or 'Manager') can approve comments to make them visible to the public. If you want to enable a custom comment workflow, you have to go to the types control panel."
|
||||||
#: ../interfaces.py:248
|
#: ../interfaces.py:231
|
||||||
msgid "help_moderation_enabled"
|
msgid "help_moderation_enabled"
|
||||||
msgstr "Aukeratuta badago, erantzuna 'Zain' izeneko egoeran geldituko da eta ez da argitaratuko. 'Erantzunak errebisatu' baimena duten erabiltzaileek ('Zuzentzailea' edo 'Kudeatzailea') argitaratu ditzakete albisteak. Erantzunen worfklowa pertsonalizatu nahi baduzu, elementu-moten kontrol panelera joan zaitez."
|
msgstr "Aukeratuta badago, erantzuna 'Zain' izeneko egoeran geldituko da eta ez da argitaratuko. 'Erantzunak errebisatu' baimena duten erabiltzaileek ('Zuzentzailea' edo 'Kudeatzailea') argitaratu ditzakete albisteak. Erantzunen worfklowa pertsonalizatu nahi baduzu, elementu-moten kontrol panelera joan zaitez."
|
||||||
|
|
||||||
#. Default: "Address to which moderator notifications will be sent."
|
#. Default: "Address to which moderator notifications will be sent."
|
||||||
#: ../interfaces.py:316
|
#: ../interfaces.py:307
|
||||||
msgid "help_moderator_email"
|
msgid "help_moderator_email"
|
||||||
msgstr "Moderatzailearen notifikazioak bidali behar diren helbidea."
|
msgstr "Moderatzailearen notifikazioak bidali behar diren helbidea."
|
||||||
|
|
||||||
#. Default: "If selected, the moderator is notified if a comment needs attention. The moderator email address can be found in the 'Mail settings' control panel (Site 'From' address)"
|
#. Default: "If selected, the moderator is notified if a comment needs attention. The moderator email address can be found in the 'Mail settings' control panel (Site 'From' address)"
|
||||||
#: ../interfaces.py:304
|
#: ../interfaces.py:292
|
||||||
msgid "help_moderator_notification_enabled"
|
msgid "help_moderator_notification_enabled"
|
||||||
msgstr "Aukeratuta badago, moderatzaileari e-posta abisua helduko zaio erantzun bat gehitzean. Moderatzailearen e-posta atariaren E-postaren konfigurazioan dago (Atariaren 'Nork' helbidea)"
|
msgstr "Aukeratuta badago, moderatzaileari e-posta abisua helduko zaio erantzun bat gehitzean. Moderatzailearen e-posta atariaren E-postaren konfigurazioan dago (Atariaren 'Nork' helbidea)"
|
||||||
|
|
||||||
#. Default: "If selected, an image of the user is shown next to the comment."
|
#. Default: "If selected, an image of the user is shown next to the comment."
|
||||||
#: ../interfaces.py:294
|
#: ../interfaces.py:281
|
||||||
msgid "help_show_commenter_image"
|
msgid "help_show_commenter_image"
|
||||||
msgstr "Aukeratuta badago, erantzuna eman duenaren irudi bat agertuko da testuaren ondoan."
|
msgstr "Aukeratuta badago, erantzuna eman duenaren irudi bat agertuko da testuaren ondoan."
|
||||||
|
|
||||||
#. Default: "Use this setting to choose if the comment text should be transformed in any way. You can choose between 'Plain text' and 'Intelligent text'. 'Intelligent text' converts plain text into HTML where line breaks and indentation is preserved, and web and email addresses are made into clickable links."
|
#. Default: "Use this setting to choose if the comment text should be transformed in any way. You can choose between 'Plain text' and 'Intelligent text'. 'Intelligent text' converts plain text into HTML where line breaks and indentation is preserved, and web and email addresses are made into clickable links."
|
||||||
#: ../interfaces.py:263
|
#: ../interfaces.py:248
|
||||||
msgid "help_text_transform"
|
msgid "help_text_transform"
|
||||||
msgstr "Erabili aukera hau erantzunaren testua nolabait eraldatu behar bada. 'Testu arrunta' edo 'Testu argia'ren artean aukeratu dezakezu. 'Testu argia'-k testu arrunta HTML bihurtzen du lerro saltoak eta espazioak mantenduz, eta web helbideak eta e-postak klikagarri eginez."
|
msgstr "Erabili aukera hau erantzunaren testua nolabait eraldatu behar bada. 'Testu arrunta' edo 'Testu argia'ren artean aukeratu dezakezu. 'Testu argia'-k testu arrunta HTML bihurtzen du lerro saltoak eta espazioak mantenduz, eta web helbideak eta e-postak klikagarri eginez."
|
||||||
|
|
||||||
#. Default: "If selected, users can choose to be notified of new comments by email."
|
#. Default: "If selected, users can choose to be notified of new comments by email."
|
||||||
#: ../interfaces.py:325
|
#: ../interfaces.py:319
|
||||||
msgid "help_user_notification_enabled"
|
msgid "help_user_notification_enabled"
|
||||||
msgstr "Aukeratuta badago, erabiltzaileek euren erantzunen erantzunak e-postaz jasotzea aktibatu dezakete."
|
msgstr "Aukeratuta badago, erabiltzaileek euren erantzunen erantzunak e-postaz jasotzea aktibatu dezakete."
|
||||||
|
|
||||||
#. Default: "Anonymous"
|
#. Default: "Anonymous"
|
||||||
#: ../browser/comments.pt:71
|
#: ../browser/comments.pt:71
|
||||||
#: ../comment.py:173
|
#: ../comment.py:176
|
||||||
msgid "label_anonymous"
|
msgid "label_anonymous"
|
||||||
msgstr "Anonimoak"
|
msgstr "Anonimoak"
|
||||||
|
|
||||||
#. Default: "Enable anonymous comments"
|
#. Default: "Enable anonymous comments"
|
||||||
#: ../interfaces.py:234
|
#: ../interfaces.py:213
|
||||||
msgid "label_anonymous_comments"
|
msgid "label_anonymous_comments"
|
||||||
msgstr "Aktibatu erabiltzaile anonimoen erantzunak"
|
msgstr "Aktibatu erabiltzaile anonimoen erantzunak"
|
||||||
|
|
||||||
#. Default: "Enable anonymous email field"
|
#. Default: "Enable anonymous email field"
|
||||||
#: ../interfaces.py:332
|
#: ../interfaces.py:328
|
||||||
msgid "label_anonymous_email_enabled"
|
msgid "label_anonymous_email_enabled"
|
||||||
msgstr ""
|
msgstr "Aktibatu anonimoentzat eposta eremua"
|
||||||
|
|
||||||
#. Default: "Apply"
|
#. Default: "Apply"
|
||||||
#: ../browser/moderation.pt:71
|
#: ../browser/moderation.pt:71
|
||||||
@ -302,12 +301,12 @@ msgid "label_apply"
|
|||||||
msgstr "Aplikatu"
|
msgstr "Aplikatu"
|
||||||
|
|
||||||
#. Default: "Captcha"
|
#. Default: "Captcha"
|
||||||
#: ../interfaces.py:277
|
#: ../interfaces.py:263
|
||||||
msgid "label_captcha"
|
msgid "label_captcha"
|
||||||
msgstr "Captcha"
|
msgstr "Captcha"
|
||||||
|
|
||||||
#. Default: "Comment"
|
#. Default: "Comment"
|
||||||
#: ../interfaces.py:159
|
#: ../interfaces.py:162
|
||||||
msgid "label_comment"
|
msgid "label_comment"
|
||||||
msgstr "Erantzuna"
|
msgstr "Erantzuna"
|
||||||
|
|
||||||
@ -322,22 +321,22 @@ msgid "label_delete"
|
|||||||
msgstr "Ezabatu"
|
msgstr "Ezabatu"
|
||||||
|
|
||||||
#. Default: "Globally enable comments"
|
#. Default: "Globally enable comments"
|
||||||
#: ../interfaces.py:222
|
#: ../interfaces.py:199
|
||||||
msgid "label_globally_enabled"
|
msgid "label_globally_enabled"
|
||||||
msgstr "Erantzunak globalki aktibatu"
|
msgstr "Erantzunak globalki aktibatu"
|
||||||
|
|
||||||
#. Default: "Enable comment moderation"
|
#. Default: "Enable comment moderation"
|
||||||
#: ../interfaces.py:246
|
#: ../interfaces.py:227
|
||||||
msgid "label_moderation_enabled"
|
msgid "label_moderation_enabled"
|
||||||
msgstr "Erantzunen moderazioa aktibatu."
|
msgstr "Erantzunen moderazioa aktibatu."
|
||||||
|
|
||||||
#. Default: "Moderator Email Address"
|
#. Default: "Moderator Email Address"
|
||||||
#: ../interfaces.py:314
|
#: ../interfaces.py:303
|
||||||
msgid "label_moderator_email"
|
msgid "label_moderator_email"
|
||||||
msgstr "Moderatzailearen e-posta helbidea"
|
msgstr "Moderatzailearen e-posta helbidea"
|
||||||
|
|
||||||
#. Default: "Enable moderator email notification"
|
#. Default: "Enable moderator email notification"
|
||||||
#: ../interfaces.py:302
|
#: ../interfaces.py:290
|
||||||
msgid "label_moderator_notification_enabled"
|
msgid "label_moderator_notification_enabled"
|
||||||
msgstr "Aktibatu moderatzaileari e-postaz abisatzea"
|
msgstr "Aktibatu moderatzaileari e-postaz abisatzea"
|
||||||
|
|
||||||
@ -352,7 +351,7 @@ msgid "label_says"
|
|||||||
msgstr "dio:"
|
msgstr "dio:"
|
||||||
|
|
||||||
#. Default: "Show commenter image"
|
#. Default: "Show commenter image"
|
||||||
#: ../interfaces.py:292
|
#: ../interfaces.py:279
|
||||||
msgid "label_show_commenter_image"
|
msgid "label_show_commenter_image"
|
||||||
msgstr "Erantzuna eman duenaren irudia erakutsi"
|
msgstr "Erantzuna eman duenaren irudia erakutsi"
|
||||||
|
|
||||||
@ -362,17 +361,17 @@ msgid "label_show_full_comment_text"
|
|||||||
msgstr "Erakutsi testu osoa"
|
msgstr "Erakutsi testu osoa"
|
||||||
|
|
||||||
#. Default: "Subject"
|
#. Default: "Subject"
|
||||||
#: ../interfaces.py:155
|
#: ../interfaces.py:157
|
||||||
msgid "label_subject"
|
msgid "label_subject"
|
||||||
msgstr "Gaia"
|
msgstr "Gaia"
|
||||||
|
|
||||||
#. Default: "Comment text transform"
|
#. Default: "Comment text transform"
|
||||||
#: ../interfaces.py:261
|
#: ../interfaces.py:246
|
||||||
msgid "label_text_transform"
|
msgid "label_text_transform"
|
||||||
msgstr "Erantzunari aplikatu beharreko transformazioa"
|
msgstr "Erantzunari aplikatu beharreko transformazioa"
|
||||||
|
|
||||||
#. Default: "Enable user email notification"
|
#. Default: "Enable user email notification"
|
||||||
#: ../interfaces.py:323
|
#: ../interfaces.py:315
|
||||||
msgid "label_user_notification_enabled"
|
msgid "label_user_notification_enabled"
|
||||||
msgstr "Aktibatu erabiltzaileek e-postaz jakinaraztea"
|
msgstr "Aktibatu erabiltzaileek e-postaz jakinaraztea"
|
||||||
|
|
||||||
|
@ -14,11 +14,11 @@ msgstr ""
|
|||||||
"Preferred-Encodings: utf-8 latin1\n"
|
"Preferred-Encodings: utf-8 latin1\n"
|
||||||
"Domain: DOMAIN\n"
|
"Domain: DOMAIN\n"
|
||||||
|
|
||||||
#: ../comment.py:311
|
#: ../comment.py:326
|
||||||
msgid "A comment has been posted."
|
msgid "A comment has been posted."
|
||||||
msgstr "Коментар додано."
|
msgstr "Коментар додано."
|
||||||
|
|
||||||
#: ../interfaces.py:141
|
#: ../interfaces.py:143
|
||||||
msgid "A comment id unique to this conversation"
|
msgid "A comment id unique to this conversation"
|
||||||
msgstr "Унікальний ідентифікатор коментаря для цієї розмови"
|
msgstr "Унікальний ідентифікатор коментаря для цієї розмови"
|
||||||
|
|
||||||
@ -26,16 +26,16 @@ msgstr "Унікальний ідентифікатор коментаря дл
|
|||||||
msgid "Add a comment"
|
msgid "Add a comment"
|
||||||
msgstr "Додати коментар"
|
msgstr "Додати коментар"
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:64
|
#: ../browser/controlpanel.py:66
|
||||||
msgid "Anonymous Comments"
|
msgid "Anonymous Comments"
|
||||||
msgstr "Анонімне коментування"
|
msgstr "Анонімне коментування"
|
||||||
|
|
||||||
#: ../browser/comments.py:251
|
#: ../browser/comments.py:258
|
||||||
#: ../browser/controlpanel.py:82
|
#: ../browser/controlpanel.py:84
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Скасувати"
|
msgstr "Скасувати"
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:78
|
#: ../browser/controlpanel.py:80
|
||||||
msgid "Changes saved"
|
msgid "Changes saved"
|
||||||
msgstr "Зміни збережено"
|
msgstr "Зміни збережено"
|
||||||
|
|
||||||
@ -47,18 +47,18 @@ msgstr "Коментар опубліковано."
|
|||||||
msgid "Comment deleted."
|
msgid "Comment deleted."
|
||||||
msgstr "Коментар знищено."
|
msgstr "Коментар знищено."
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:65
|
#: ../browser/controlpanel.py:67
|
||||||
msgid "Commenter Image"
|
msgid "Commenter Image"
|
||||||
msgstr "Зображення коментатора"
|
msgstr "Зображення коментатора"
|
||||||
|
|
||||||
msgid "Commenting infrastructure for Plone"
|
msgid "Commenting infrastructure for Plone"
|
||||||
msgstr "Інфраструктура коментування в Plone"
|
msgstr "Інфраструктура коментування в Plone"
|
||||||
|
|
||||||
#: ../interfaces.py:136
|
#: ../interfaces.py:138
|
||||||
msgid "Conversation"
|
msgid "Conversation"
|
||||||
msgstr "Розмова"
|
msgstr "Розмова"
|
||||||
|
|
||||||
#: ../interfaces.py:167
|
#: ../interfaces.py:176
|
||||||
msgid "Creation date"
|
msgid "Creation date"
|
||||||
msgstr "Дата створення"
|
msgstr "Дата створення"
|
||||||
|
|
||||||
@ -74,39 +74,39 @@ msgstr "Вимкнено"
|
|||||||
msgid "Discussion settings"
|
msgid "Discussion settings"
|
||||||
msgstr "Налаштуванняя коментування"
|
msgstr "Налаштуванняя коментування"
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:84
|
#: ../browser/controlpanel.py:86
|
||||||
msgid "Edit cancelled"
|
msgid "Edit cancelled"
|
||||||
msgstr "Редагування скасовано"
|
msgstr "Редагування скасовано"
|
||||||
|
|
||||||
#: ../interfaces.py:153
|
#: ../interfaces.py:155
|
||||||
msgid "Email"
|
msgid "Email"
|
||||||
msgstr "Електронна адреса"
|
msgstr "Електронна адреса"
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:63
|
#: ../browser/controlpanel.py:65
|
||||||
msgid "Enable Comments"
|
msgid "Enable Comments"
|
||||||
msgstr "Увімкнути можливість додавати коментарі"
|
msgstr "Увімкнути можливість додавати коментарі"
|
||||||
|
|
||||||
#: ../interfaces.py:144
|
#: ../interfaces.py:146
|
||||||
msgid "Id of comment this comment is in reply to"
|
msgid "Id of comment this comment is in reply to"
|
||||||
msgstr "Id коментаря, відповіддю на який - є цей коментар"
|
msgstr "Id коментаря, відповіддю на який - є цей коментар"
|
||||||
|
|
||||||
#: ../interfaces.py:158
|
#: ../interfaces.py:160
|
||||||
msgid "MIME type"
|
msgid "MIME type"
|
||||||
msgstr "MIME-тип"
|
msgstr "MIME-тип"
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:67
|
#: ../browser/controlpanel.py:69
|
||||||
msgid "Moderator Email Notification"
|
msgid "Moderator Email Notification"
|
||||||
msgstr "Сповіщення модератора електронною поштою"
|
msgstr "Сповіщення модератора електронною поштою"
|
||||||
|
|
||||||
#: ../interfaces.py:168
|
#: ../interfaces.py:177
|
||||||
msgid "Modification date"
|
msgid "Modification date"
|
||||||
msgstr "Дата зміни"
|
msgstr "Дата зміни"
|
||||||
|
|
||||||
#: ../interfaces.py:138
|
#: ../interfaces.py:140
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Ім'я"
|
msgstr "Ім'я"
|
||||||
|
|
||||||
#: ../interfaces.py:162
|
#: ../interfaces.py:169
|
||||||
msgid "Notify me of new comments via email."
|
msgid "Notify me of new comments via email."
|
||||||
msgstr "Повідомляти про нові коментарі поштою."
|
msgstr "Повідомляти про нові коментарі поштою."
|
||||||
|
|
||||||
@ -114,11 +114,11 @@ msgstr "Повідомляти про нові коментарі поштою."
|
|||||||
msgid "Plone Discussions"
|
msgid "Plone Discussions"
|
||||||
msgstr "Коментування в Plone"
|
msgstr "Коментування в Plone"
|
||||||
|
|
||||||
#: ../interfaces.py:131
|
#: ../interfaces.py:133
|
||||||
msgid "Portal type"
|
msgid "Portal type"
|
||||||
msgstr "Портал тип"
|
msgstr "Портал тип"
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:71
|
#: ../browser/controlpanel.py:73
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Зберегти"
|
msgstr "Зберегти"
|
||||||
|
|
||||||
@ -135,23 +135,23 @@ msgid "Total number of public comments on this item"
|
|||||||
msgstr "Загальна кількість публічних коментарів для даного елемента"
|
msgstr "Загальна кількість публічних коментарів для даного елемента"
|
||||||
|
|
||||||
#: ../comment.py:158
|
#: ../comment.py:158
|
||||||
msgid "Transform '%s' => '%s' not available. Failed to transform comment '%s'."
|
msgid "Transform '%s' => '%s' not available."
|
||||||
msgstr "Не доступне перетворення '%s' => '%s'. Не вдалося перетворити коментар '%s'."
|
msgstr "Не доступне перетворення '%s' => '%s'."
|
||||||
|
|
||||||
#: ../browser/controlpanel.py:69
|
#: ../browser/controlpanel.py:71
|
||||||
msgid "User Email Notification"
|
msgid "User Email Notification"
|
||||||
msgstr "Сповіщення користувача електронною поштою"
|
msgstr "Сповіщення користувача електронною поштою"
|
||||||
|
|
||||||
#: ../interfaces.py:166
|
#: ../interfaces.py:175
|
||||||
msgid "Username of the commenter"
|
msgid "Username of the commenter"
|
||||||
msgstr "Ім'я автора коментаря"
|
msgstr "Ім'я автора коментаря"
|
||||||
|
|
||||||
#: ../browser/comments.py:244
|
#: ../browser/comments.py:251
|
||||||
msgid "Your comment awaits moderator approval."
|
msgid "Your comment awaits moderator approval."
|
||||||
msgstr "Ваш коментар очікує затвердження модератором."
|
msgstr "Ваш коментар очікує затвердження модератором."
|
||||||
|
|
||||||
#. Default: "Comment"
|
#. Default: "Comment"
|
||||||
#: ../browser/comments.py:131
|
#: ../browser/comments.py:132
|
||||||
msgid "add_comment_button"
|
msgid "add_comment_button"
|
||||||
msgstr "Коментар"
|
msgstr "Коментар"
|
||||||
|
|
||||||
@ -221,17 +221,17 @@ msgid "heading_moderate_comments"
|
|||||||
msgstr "Модерування коментарів"
|
msgstr "Модерування коментарів"
|
||||||
|
|
||||||
#. Default: "If selected, anonymous users are able to post comments without loggin in. It is highly recommended to use a captcha solution to prevent spam if this setting is enabled."
|
#. Default: "If selected, anonymous users are able to post comments without loggin in. It is highly recommended to use a captcha solution to prevent spam if this setting is enabled."
|
||||||
#: ../interfaces.py:236
|
#: ../interfaces.py:215
|
||||||
msgid "help_anonymous_comments"
|
msgid "help_anonymous_comments"
|
||||||
msgstr "Якщо вибрано - то анонімні користувачі зможуть додавати коментарі без входу в систему. Для таких випадків рекомендуєтсья використовувати капчу, щоб запобігти надсиланню спаму."
|
msgstr "Якщо вибрано - то анонімні користувачі зможуть додавати коментарі без входу в систему. Для таких випадків рекомендуєтсья використовувати капчу, щоб запобігти надсиланню спаму."
|
||||||
|
|
||||||
#. Default: "If selected, anonymous user will have to give their email."
|
#. Default: "If selected, anonymous user will have to give their email."
|
||||||
#: ../interfaces.py:334
|
#: ../interfaces.py:330
|
||||||
msgid "help_anonymous_email_enabled"
|
msgid "help_anonymous_email_enabled"
|
||||||
msgstr "Якщо вибрано, анонімний користувач повинен буде вказати свою електронну пошту."
|
msgstr "Якщо вибрано, анонімний користувач повинен буде вказати свою електронну пошту."
|
||||||
|
|
||||||
#. Default: "Use this setting to enable or disable Captcha validation for comments. Install plone.formwidget.captcha, plone.formwidget.recaptcha, collective.akismet, or collective.z3cform.norobots if there are no options available."
|
#. Default: "Use this setting to enable or disable Captcha validation for comments. Install plone.formwidget.captcha, plone.formwidget.recaptcha, collective.akismet, or collective.z3cform.norobots if there are no options available."
|
||||||
#: ../interfaces.py:279
|
#: ../interfaces.py:265
|
||||||
msgid "help_captcha"
|
msgid "help_captcha"
|
||||||
msgstr "Використовуйте цей параметр, щоб увімкнути або вимкнути капчу для коментарів. Для цього спершу встановіть plone.formwidget.captcha, plone.formwidget.recaptcha, collective.akismet або collective.z3cform.norobots."
|
msgstr "Використовуйте цей параметр, щоб увімкнути або вимкнути капчу для коментарів. Для цього спершу встановіть plone.formwidget.captcha, plone.formwidget.recaptcha, collective.akismet або collective.z3cform.norobots."
|
||||||
|
|
||||||
@ -244,53 +244,53 @@ msgstr ""
|
|||||||
"To enable the moderation workflow for comments, go to the Types Control Panel, choose \"Comment\" and set workflow to \"Comment Review Workflow\".\""
|
"To enable the moderation workflow for comments, go to the Types Control Panel, choose \"Comment\" and set workflow to \"Comment Review Workflow\".\""
|
||||||
|
|
||||||
#. Default: "If selected, users are able to post comments on the site. Though, you have to enable comments for specific content types, folders or content objects before users will be able to post comments."
|
#. Default: "If selected, users are able to post comments on the site. Though, you have to enable comments for specific content types, folders or content objects before users will be able to post comments."
|
||||||
#: ../interfaces.py:224
|
#: ../interfaces.py:201
|
||||||
msgid "help_globally_enabled"
|
msgid "help_globally_enabled"
|
||||||
msgstr "Якщо вибрано, користувачі зможуть додавати коментарі на сайт. Але спочатку необхідно увімкнути можливість коментування для певних типів вмісту, тек, об'єктів."
|
msgstr "Якщо вибрано, користувачі зможуть додавати коментарі на сайт. Але спочатку необхідно увімкнути можливість коментування для певних типів вмісту, тек, об'єктів."
|
||||||
|
|
||||||
#. Default: "If selected, comments will enter a 'Pending' state in which they are invisible to the public. A user with the 'Review comments' permission ('Reviewer' or 'Manager') can approve comments to make them visible to the public. If you want to enable a custom comment workflow, you have to go to the types control panel."
|
#. Default: "If selected, comments will enter a 'Pending' state in which they are invisible to the public. A user with the 'Review comments' permission ('Reviewer' or 'Manager') can approve comments to make them visible to the public. If you want to enable a custom comment workflow, you have to go to the types control panel."
|
||||||
#: ../interfaces.py:248
|
#: ../interfaces.py:231
|
||||||
msgid "help_moderation_enabled"
|
msgid "help_moderation_enabled"
|
||||||
msgstr "Якщо вибрано, коментарі увійде в стан 'В очікуванні', у якому вони невидимі для громадськості. Користувач з правом 'Огляд коментарів' ('Рецензент' або 'Менеджер') може схвалити коментар, щоб зробити їх видимими для громадськості. Якщо ви хочете налаштувати робочий процес коментарів, ви повинні піти в панель керування типів."
|
msgstr "Якщо вибрано, коментарі увійде в стан 'В очікуванні', у якому вони невидимі для громадськості. Користувач з правом 'Огляд коментарів' ('Рецензент' або 'Менеджер') може схвалити коментар, щоб зробити їх видимими для громадськості. Якщо ви хочете налаштувати робочий процес коментарів, ви повинні піти в панель керування типів."
|
||||||
|
|
||||||
#. Default: "Address to which moderator notifications will be sent."
|
#. Default: "Address to which moderator notifications will be sent."
|
||||||
#: ../interfaces.py:316
|
#: ../interfaces.py:307
|
||||||
msgid "help_moderator_email"
|
msgid "help_moderator_email"
|
||||||
msgstr "Адреса, за якою модератору будуть надсилатися повідомлення."
|
msgstr "Адреса, за якою модератору будуть надсилатися повідомлення."
|
||||||
|
|
||||||
#. Default: "If selected, the moderator is notified if a comment needs attention. The moderator email address can be found in the 'Mail settings' control panel (Site 'From' address)"
|
#. Default: "If selected, the moderator is notified if a comment needs attention. The moderator email address can be found in the 'Mail settings' control panel (Site 'From' address)"
|
||||||
#: ../interfaces.py:304
|
#: ../interfaces.py:292
|
||||||
msgid "help_moderator_notification_enabled"
|
msgid "help_moderator_notification_enabled"
|
||||||
msgstr "Якщо вибрано, модератор отримує повідомлення, якщо коментар вимагає уваги. Адресу електронної пошти модератора можна знайти в 'Пошта' панелі керування (Адреса 'Від')"
|
msgstr "Якщо вибрано, модератор отримує повідомлення, якщо коментар вимагає уваги. Адресу електронної пошти модератора можна знайти в 'Пошта' панелі керування (Адреса 'Від')"
|
||||||
|
|
||||||
#. Default: "If selected, an image of the user is shown next to the comment."
|
#. Default: "If selected, an image of the user is shown next to the comment."
|
||||||
#: ../interfaces.py:294
|
#: ../interfaces.py:281
|
||||||
msgid "help_show_commenter_image"
|
msgid "help_show_commenter_image"
|
||||||
msgstr "Якщо вибрано, зображення коментатора буде відображатись поруч з коментарем."
|
msgstr "Якщо вибрано, зображення коментатора буде відображатись поруч з коментарем."
|
||||||
|
|
||||||
#. Default: "Use this setting to choose if the comment text should be transformed in any way. You can choose between 'Plain text' and 'Intelligent text'. 'Intelligent text' converts plain text into HTML where line breaks and indentation is preserved, and web and email addresses are made into clickable links."
|
#. Default: "Use this setting to choose if the comment text should be transformed in any way. You can choose between 'Plain text' and 'Intelligent text'. 'Intelligent text' converts plain text into HTML where line breaks and indentation is preserved, and web and email addresses are made into clickable links."
|
||||||
#: ../interfaces.py:263
|
#: ../interfaces.py:248
|
||||||
msgid "help_text_transform"
|
msgid "help_text_transform"
|
||||||
msgstr "Виберіть як повинен бути перетворений текст коментаря. Ви можете вибрати між 'Звичайний текст' і 'Інтелектуальні тексту'. 'Інтелектуальний текст' перетворює текст в HTML, де рядки і відступи зберігаються, інтернет адреси та адреси електронної пошти перетворяться в активні посилання."
|
msgstr "Виберіть як повинен бути перетворений текст коментаря. Ви можете вибрати між 'Звичайний текст' і 'Інтелектуальні тексту'. 'Інтелектуальний текст' перетворює текст в HTML, де рядки і відступи зберігаються, інтернет адреси та адреси електронної пошти перетворяться в активні посилання."
|
||||||
|
|
||||||
#. Default: "If selected, users can choose to be notified of new comments by email."
|
#. Default: "If selected, users can choose to be notified of new comments by email."
|
||||||
#: ../interfaces.py:325
|
#: ../interfaces.py:319
|
||||||
msgid "help_user_notification_enabled"
|
msgid "help_user_notification_enabled"
|
||||||
msgstr "Якщо вибрано, користувачі зможуть обрати можливість отримувати нотифікації про нові коментарі поштою."
|
msgstr "Якщо вибрано, користувачі зможуть обрати можливість отримувати нотифікації про нові коментарі поштою."
|
||||||
|
|
||||||
#. Default: "Anonymous"
|
#. Default: "Anonymous"
|
||||||
#: ../browser/comments.pt:71
|
#: ../browser/comments.pt:71
|
||||||
#: ../comment.py:173
|
#: ../comment.py:176
|
||||||
msgid "label_anonymous"
|
msgid "label_anonymous"
|
||||||
msgstr "Анонім"
|
msgstr "Анонім"
|
||||||
|
|
||||||
#. Default: "Enable anonymous comments"
|
#. Default: "Enable anonymous comments"
|
||||||
#: ../interfaces.py:234
|
#: ../interfaces.py:213
|
||||||
msgid "label_anonymous_comments"
|
msgid "label_anonymous_comments"
|
||||||
msgstr "Увімкнути можливість анонімного коментування"
|
msgstr "Увімкнути можливість анонімного коментування"
|
||||||
|
|
||||||
#. Default: "Enable anonymous email field"
|
#. Default: "Enable anonymous email field"
|
||||||
#: ../interfaces.py:332
|
#: ../interfaces.py:328
|
||||||
msgid "label_anonymous_email_enabled"
|
msgid "label_anonymous_email_enabled"
|
||||||
msgstr "Увімкнути поле електронної адреси для аноніма"
|
msgstr "Увімкнути поле електронної адреси для аноніма"
|
||||||
|
|
||||||
@ -300,12 +300,12 @@ msgid "label_apply"
|
|||||||
msgstr "Застосувати"
|
msgstr "Застосувати"
|
||||||
|
|
||||||
#. Default: "Captcha"
|
#. Default: "Captcha"
|
||||||
#: ../interfaces.py:277
|
#: ../interfaces.py:263
|
||||||
msgid "label_captcha"
|
msgid "label_captcha"
|
||||||
msgstr "Капча"
|
msgstr "Капча"
|
||||||
|
|
||||||
#. Default: "Comment"
|
#. Default: "Comment"
|
||||||
#: ../interfaces.py:159
|
#: ../interfaces.py:162
|
||||||
msgid "label_comment"
|
msgid "label_comment"
|
||||||
msgstr "Коментар"
|
msgstr "Коментар"
|
||||||
|
|
||||||
@ -320,22 +320,22 @@ msgid "label_delete"
|
|||||||
msgstr "Знищити"
|
msgstr "Знищити"
|
||||||
|
|
||||||
#. Default: "Globally enable comments"
|
#. Default: "Globally enable comments"
|
||||||
#: ../interfaces.py:222
|
#: ../interfaces.py:199
|
||||||
msgid "label_globally_enabled"
|
msgid "label_globally_enabled"
|
||||||
msgstr "Увімкнути коментування для цілого сайту"
|
msgstr "Увімкнути коментування для цілого сайту"
|
||||||
|
|
||||||
#. Default: "Enable comment moderation"
|
#. Default: "Enable comment moderation"
|
||||||
#: ../interfaces.py:246
|
#: ../interfaces.py:227
|
||||||
msgid "label_moderation_enabled"
|
msgid "label_moderation_enabled"
|
||||||
msgstr "Увімкнути модерування коментарів"
|
msgstr "Увімкнути модерування коментарів"
|
||||||
|
|
||||||
#. Default: "Moderator Email Address"
|
#. Default: "Moderator Email Address"
|
||||||
#: ../interfaces.py:314
|
#: ../interfaces.py:303
|
||||||
msgid "label_moderator_email"
|
msgid "label_moderator_email"
|
||||||
msgstr "Електронна адреса модератора"
|
msgstr "Електронна адреса модератора"
|
||||||
|
|
||||||
#. Default: "Enable moderator email notification"
|
#. Default: "Enable moderator email notification"
|
||||||
#: ../interfaces.py:302
|
#: ../interfaces.py:290
|
||||||
msgid "label_moderator_notification_enabled"
|
msgid "label_moderator_notification_enabled"
|
||||||
msgstr "Увімкнути сповіщення модератора"
|
msgstr "Увімкнути сповіщення модератора"
|
||||||
|
|
||||||
@ -350,7 +350,7 @@ msgid "label_says"
|
|||||||
msgstr "каже:"
|
msgstr "каже:"
|
||||||
|
|
||||||
#. Default: "Show commenter image"
|
#. Default: "Show commenter image"
|
||||||
#: ../interfaces.py:292
|
#: ../interfaces.py:279
|
||||||
msgid "label_show_commenter_image"
|
msgid "label_show_commenter_image"
|
||||||
msgstr "Показати зображення коментатора"
|
msgstr "Показати зображення коментатора"
|
||||||
|
|
||||||
@ -360,17 +360,17 @@ msgid "label_show_full_comment_text"
|
|||||||
msgstr "показати повний текст коментаря"
|
msgstr "показати повний текст коментаря"
|
||||||
|
|
||||||
#. Default: "Subject"
|
#. Default: "Subject"
|
||||||
#: ../interfaces.py:155
|
#: ../interfaces.py:157
|
||||||
msgid "label_subject"
|
msgid "label_subject"
|
||||||
msgstr "Тема"
|
msgstr "Тема"
|
||||||
|
|
||||||
#. Default: "Comment text transform"
|
#. Default: "Comment text transform"
|
||||||
#: ../interfaces.py:261
|
#: ../interfaces.py:246
|
||||||
msgid "label_text_transform"
|
msgid "label_text_transform"
|
||||||
msgstr "Перетворення тексту коментаря"
|
msgstr "Перетворення тексту коментаря"
|
||||||
|
|
||||||
#. Default: "Enable user email notification"
|
#. Default: "Enable user email notification"
|
||||||
#: ../interfaces.py:323
|
#: ../interfaces.py:315
|
||||||
msgid "label_user_notification_enabled"
|
msgid "label_user_notification_enabled"
|
||||||
msgstr "Увімкнути надcилання нотифікації користувачу через електронну адресу"
|
msgstr "Увімкнути надcилання нотифікації користувачу через електронну адресу"
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from zope.component import queryUtility
|
from Products.CMFCore.utils import getToolByName
|
||||||
|
|
||||||
from Acquisition import aq_inner, aq_parent
|
from Acquisition import aq_inner, aq_parent
|
||||||
|
|
||||||
@ -8,7 +8,6 @@ from Products.CMFPlone.utils import base_hasattr
|
|||||||
from Products.CMFPlone.utils import safe_callable
|
from Products.CMFPlone.utils import safe_callable
|
||||||
|
|
||||||
from plone.app.discussion.conversation import ANNOTATION_KEY
|
from plone.app.discussion.conversation import ANNOTATION_KEY
|
||||||
from plone.app.discussion.interfaces import ICommentingTool
|
|
||||||
|
|
||||||
|
|
||||||
def patchedClearFindAndRebuild(self):
|
def patchedClearFindAndRebuild(self):
|
||||||
@ -26,14 +25,14 @@ def patchedClearFindAndRebuild(self):
|
|||||||
obj.indexObject()
|
obj.indexObject()
|
||||||
|
|
||||||
annotions = IAnnotations(obj)
|
annotions = IAnnotations(obj)
|
||||||
ctool = queryUtility(ICommentingTool)
|
catalog = getToolByName(obj, "portal_catalog")
|
||||||
if ANNOTATION_KEY in annotions:
|
if ANNOTATION_KEY in annotions:
|
||||||
conversation = annotions[ANNOTATION_KEY]
|
conversation = annotions[ANNOTATION_KEY]
|
||||||
conversation = conversation.__of__(obj)
|
conversation = conversation.__of__(obj)
|
||||||
for comment in conversation.getComments():
|
for comment in conversation.getComments():
|
||||||
try:
|
try:
|
||||||
if ctool:
|
if catalog:
|
||||||
ctool.indexObject(comment)
|
catalog.indexObject(comment)
|
||||||
except StopIteration: # pragma: no cover
|
except StopIteration: # pragma: no cover
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<componentregistry>
|
|
||||||
<utilities>
|
|
||||||
<utility
|
|
||||||
interface="plone.app.discussion.interfaces.ICommentingTool"
|
|
||||||
object="portal_discussion"
|
|
||||||
/>
|
|
||||||
</utilities>
|
|
||||||
</componentregistry>
|
|
@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<tool-setup>
|
|
||||||
<required tool_id="portal_discussion"
|
|
||||||
class="plone.app.discussion.tool.CommentingTool"/>
|
|
||||||
</tool-setup>
|
|
15
plone/app/discussion/subscribers.py
Normal file
15
plone/app/discussion/subscribers.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from Products.CMFCore.utils import getToolByName
|
||||||
|
|
||||||
|
|
||||||
|
def index_object(obj, event):
|
||||||
|
"""Index the object when it is added to the conversation.
|
||||||
|
"""
|
||||||
|
catalog = getToolByName(obj, 'portal_catalog')
|
||||||
|
return catalog.reindexObject(obj)
|
||||||
|
|
||||||
|
|
||||||
|
def unindex_object(obj, event):
|
||||||
|
"""Unindex the object when it is removed from the conversation.
|
||||||
|
"""
|
||||||
|
catalog = getToolByName(obj, 'portal_catalog')
|
||||||
|
return catalog.unindexObject(obj)
|
@ -24,13 +24,13 @@
|
|||||||
<subscriber
|
<subscriber
|
||||||
for="plone.app.discussion.interfaces.IComment
|
for="plone.app.discussion.interfaces.IComment
|
||||||
zope.lifecycleevent.interfaces.IObjectAddedEvent"
|
zope.lifecycleevent.interfaces.IObjectAddedEvent"
|
||||||
handler=".tool.index_object"
|
handler=".subscribers.index_object"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<subscriber
|
<subscriber
|
||||||
for="plone.app.discussion.interfaces.IComment
|
for="plone.app.discussion.interfaces.IComment
|
||||||
zope.lifecycleevent.interfaces.IObjectRemovedEvent"
|
zope.lifecycleevent.interfaces.IObjectRemovedEvent"
|
||||||
handler=".tool.unindex_object"
|
handler=".subscribers.unindex_object"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<subscriber
|
<subscriber
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
plone.app.discussion javascript testsuite
|
|
||||||
=========================================
|
|
||||||
|
|
||||||
Note: This document was shamelessly stolen from the plone.app.deco package.
|
|
||||||
|
|
||||||
We're using QUnit_ for unit testing, the jQuery test runner.
|
|
||||||
|
|
||||||
Simply load index.html directly in the browser with a file:/// url; not via
|
|
||||||
Plone. This way our tests are truely standalone and isolated.
|
|
||||||
|
|
||||||
Coverage testing
|
|
||||||
----------------
|
|
||||||
|
|
||||||
To test code coverage, I can heartily recommend using JSCoverage_. You can
|
|
||||||
download, compile and install it by:
|
|
||||||
|
|
||||||
$ wget http://siliconforks.com/jscoverage/download/jscoverage-0.5.tar.bz2
|
|
||||||
$ tar xfvj jscoverage-0.5.tar.bz2
|
|
||||||
$ cd jscoverage-0.5
|
|
||||||
$ ./configure
|
|
||||||
$ make
|
|
||||||
$ sudo make install
|
|
||||||
|
|
||||||
After that, issue the following command to run it from your Plone buildout:
|
|
||||||
|
|
||||||
$ jscoverage-server -v --ip-address=0.0.0.0 --port=8080 --encoding=UTF-8 \
|
|
||||||
--document-root=plone/app/discussion/ --no-instrument=/tests
|
|
||||||
|
|
||||||
Then point your browser to the now running `coverage server
|
|
||||||
<http://localhost:8080/jscoverage.html?/tests/javascripts/test_comments.html>`__, and
|
|
||||||
the test suite will run instrumented in an iframe. Select the Summary tab to see
|
|
||||||
the results.
|
|
||||||
|
|
||||||
The command-line options ensure that only our tests and the modules being
|
|
||||||
tested are instrumented for coverage, not the testing framework nor jQuery.
|
|
||||||
|
|
||||||
Note that JSCoverage adds instrumentation statements to the code, so don't try
|
|
||||||
to debug your tests when running via the jscoverage server.
|
|
||||||
|
|
||||||
.. _QUnit: http://docs.jquery.com/QUnit
|
|
||||||
.. _JSCoverage: http://siliconforks.com/jscoverage/
|
|
154
plone/app/discussion/tests/javascripts/jquery.js
vendored
154
plone/app/discussion/tests/javascripts/jquery.js
vendored
@ -1,154 +0,0 @@
|
|||||||
/*!
|
|
||||||
* jQuery JavaScript Library v1.4.2
|
|
||||||
* http://jquery.com/
|
|
||||||
*
|
|
||||||
* Copyright 2010, John Resig
|
|
||||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
|
||||||
* http://jquery.org/license
|
|
||||||
*
|
|
||||||
* Includes Sizzle.js
|
|
||||||
* http://sizzlejs.com/
|
|
||||||
* Copyright 2010, The Dojo Foundation
|
|
||||||
* Released under the MIT, BSD, and GPL Licenses.
|
|
||||||
*
|
|
||||||
* Date: Sat Feb 13 22:33:48 2010 -0500
|
|
||||||
*/
|
|
||||||
(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o<i;o++)e(a[o],b,f?d.call(a[o],o,e(a[o],b)):d,j);return a}return i?
|
|
||||||
e(a[0],b):w}function J(){return(new Date).getTime()}function Y(){return false}function Z(){return true}function na(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function oa(a){var b,d=[],f=[],e=arguments,j,i,o,k,n,r;i=c.data(this,"events");if(!(a.liveFired===this||!i||!i.live||a.button&&a.type==="click")){a.liveFired=this;var u=i.live.slice(0);for(k=0;k<u.length;k++){i=u[k];i.origType.replace(O,"")===a.type?f.push(i.selector):u.splice(k--,1)}j=c(a.target).closest(f,a.currentTarget);n=0;for(r=
|
|
||||||
j.length;n<r;n++)for(k=0;k<u.length;k++){i=u[k];if(j[n].selector===i.selector){o=j[n].elem;f=null;if(i.preType==="mouseenter"||i.preType==="mouseleave")f=c(a.relatedTarget).closest(i.selector)[0];if(!f||f!==o)d.push({elem:o,handleObj:i})}}n=0;for(r=d.length;n<r;n++){j=d[n];a.currentTarget=j.elem;a.data=j.handleObj.data;a.handleObj=j.handleObj;if(j.handleObj.origHandler.apply(j.elem,e)===false){b=false;break}}return b}}function pa(a,b){return"live."+(a&&a!=="*"?a+".":"")+b.replace(/\./g,"`").replace(/ /g,
|
|
||||||
"&")}function qa(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function ra(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var f=c.data(a[d++]),e=c.data(this,f);if(f=f&&f.events){delete e.handle;e.events={};for(var j in f)for(var i in f[j])c.event.add(this,j,f[j][i],f[j][i].data)}}})}function sa(a,b,d){var f,e,j;b=b&&b[0]?b[0].ownerDocument||b[0]:s;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===s&&!ta.test(a[0])&&(c.support.checkClone||!ua.test(a[0]))){e=
|
|
||||||
true;if(j=c.fragments[a[0]])if(j!==1)f=j}if(!f){f=b.createDocumentFragment();c.clean(a,b,f,d)}if(e)c.fragments[a[0]]=j?f:1;return{fragment:f,cacheable:e}}function K(a,b){var d={};c.each(va.concat.apply([],va.slice(0,b)),function(){d[this]=a});return d}function wa(a){return"scrollTo"in a&&a.document?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var c=function(a,b){return new c.fn.init(a,b)},Ra=A.jQuery,Sa=A.$,s=A.document,T,Ta=/^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/,
|
|
||||||
Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&&
|
|
||||||
(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this,
|
|
||||||
a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b===
|
|
||||||
"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,
|
|
||||||
function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b<d;b++)if((e=arguments[b])!=null)for(j in e){i=a[j];o=e[j];if(a!==o)if(f&&o&&(c.isPlainObject(o)||c.isArray(o))){i=i&&(c.isPlainObject(i)||
|
|
||||||
c.isArray(i))?i:c.isArray(o)?[]:{};a[j]=c.extend(f,i,o)}else if(o!==w)a[j]=o}return a};c.extend({noConflict:function(a){A.$=Sa;if(a)A.jQuery=Ra;return c},isReady:false,ready:function(){if(!c.isReady){if(!s.body)return setTimeout(c.ready,13);c.isReady=true;if(Q){for(var a,b=0;a=Q[b++];)a.call(s,c);Q=null}c.fn.triggerHandler&&c(s).triggerHandler("ready")}},bindReady:function(){if(!xa){xa=true;if(s.readyState==="complete")return c.ready();if(s.addEventListener){s.addEventListener("DOMContentLoaded",
|
|
||||||
L,false);A.addEventListener("load",c.ready,false)}else if(s.attachEvent){s.attachEvent("onreadystatechange",L);A.attachEvent("onload",c.ready);var a=false;try{a=A.frameElement==null}catch(b){}s.documentElement.doScroll&&a&&ma()}}},isFunction:function(a){return $.call(a)==="[object Function]"},isArray:function(a){return $.call(a)==="[object Array]"},isPlainObject:function(a){if(!a||$.call(a)!=="[object Object]"||a.nodeType||a.setInterval)return false;if(a.constructor&&!aa.call(a,"constructor")&&!aa.call(a.constructor.prototype,
|
|
||||||
"isPrototypeOf"))return false;var b;for(b in a);return b===w||aa.call(a,b)},isEmptyObject:function(a){for(var b in a)return false;return true},error:function(a){throw a;},parseJSON:function(a){if(typeof a!=="string"||!a)return null;a=c.trim(a);if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return A.JSON&&A.JSON.parse?A.JSON.parse(a):(new Function("return "+
|
|
||||||
a))();else c.error("Invalid JSON: "+a)},noop:function(){},globalEval:function(a){if(a&&Va.test(a)){var b=s.getElementsByTagName("head")[0]||s.documentElement,d=s.createElement("script");d.type="text/javascript";if(c.support.scriptEval)d.appendChild(s.createTextNode(a));else d.text=a;b.insertBefore(d,b.firstChild);b.removeChild(d)}},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,b,d){var f,e=0,j=a.length,i=j===w||c.isFunction(a);if(d)if(i)for(f in a){if(b.apply(a[f],
|
|
||||||
d)===false)break}else for(;e<j;){if(b.apply(a[e++],d)===false)break}else if(i)for(f in a){if(b.call(a[f],f,a[f])===false)break}else for(d=a[0];e<j&&b.call(d,e,d)!==false;d=a[++e]);return a},trim:function(a){return(a||"").replace(Wa,"")},makeArray:function(a,b){b=b||[];if(a!=null)a.length==null||typeof a==="string"||c.isFunction(a)||typeof a!=="function"&&a.setInterval?ba.call(b,a):c.merge(b,a);return b},inArray:function(a,b){if(b.indexOf)return b.indexOf(a);for(var d=0,f=b.length;d<f;d++)if(b[d]===
|
|
||||||
a)return d;return-1},merge:function(a,b){var d=a.length,f=0;if(typeof b.length==="number")for(var e=b.length;f<e;f++)a[d++]=b[f];else for(;b[f]!==w;)a[d++]=b[f++];a.length=d;return a},grep:function(a,b,d){for(var f=[],e=0,j=a.length;e<j;e++)!d!==!b(a[e],e)&&f.push(a[e]);return f},map:function(a,b,d){for(var f=[],e,j=0,i=a.length;j<i;j++){e=b(a[j],j,d);if(e!=null)f[f.length]=e}return f.concat.apply([],f)},guid:1,proxy:function(a,b,d){if(arguments.length===2)if(typeof b==="string"){d=a;a=d[b];b=w}else if(b&&
|
|
||||||
!c.isFunction(b)){d=b;b=w}if(!b&&a)b=function(){return a.apply(d||this,arguments)};if(a)b.guid=a.guid=a.guid||b.guid||c.guid++;return b},uaMatch:function(a){a=a.toLowerCase();a=/(webkit)[ \/]([\w.]+)/.exec(a)||/(opera)(?:.*version)?[ \/]([\w.]+)/.exec(a)||/(msie) ([\w.]+)/.exec(a)||!/compatible/.test(a)&&/(mozilla)(?:.*? rv:([\w.]+))?/.exec(a)||[];return{browser:a[1]||"",version:a[2]||"0"}},browser:{}});P=c.uaMatch(P);if(P.browser){c.browser[P.browser]=true;c.browser.version=P.version}if(c.browser.webkit)c.browser.safari=
|
|
||||||
true;if(ya)c.inArray=function(a,b){return ya.call(b,a)};T=c(s);if(s.addEventListener)L=function(){s.removeEventListener("DOMContentLoaded",L,false);c.ready()};else if(s.attachEvent)L=function(){if(s.readyState==="complete"){s.detachEvent("onreadystatechange",L);c.ready()}};(function(){c.support={};var a=s.documentElement,b=s.createElement("script"),d=s.createElement("div"),f="script"+J();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
|
|
||||||
var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected,
|
|
||||||
parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent=
|
|
||||||
false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n=
|
|
||||||
s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,
|
|
||||||
applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando];
|
|
||||||
else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,
|
|
||||||
a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===
|
|
||||||
w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i,
|
|
||||||
cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1)if(e.className){for(var j=" "+e.className+" ",
|
|
||||||
i=e.className,o=0,k=b.length;o<k;o++)if(j.indexOf(" "+b[o]+" ")<0)i+=" "+b[o];e.className=c.trim(i)}else e.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(k){var n=c(this);n.removeClass(a.call(this,k,n.attr("class")))});if(a&&typeof a==="string"||a===w)for(var b=(a||"").split(ca),d=0,f=this.length;d<f;d++){var e=this[d];if(e.nodeType===1&&e.className)if(a){for(var j=(" "+e.className+" ").replace(Aa," "),i=0,o=b.length;i<o;i++)j=j.replace(" "+b[i]+" ",
|
|
||||||
" ");e.className=c.trim(j)}else e.className=""}return this},toggleClass:function(a,b){var d=typeof a,f=typeof b==="boolean";if(c.isFunction(a))return this.each(function(e){var j=c(this);j.toggleClass(a.call(this,e,j.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var e,j=0,i=c(this),o=b,k=a.split(ca);e=k[j++];){o=f?o:!i.hasClass(e);i[o?"addClass":"removeClass"](e)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,"__className__",this.className);this.className=
|
|
||||||
this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(Aa," ").indexOf(a)>-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j<d;j++){var i=
|
|
||||||
e[j];if(i.selected){a=c(i).val();if(b)return a;f.push(a)}}return f}if(Ba.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Za,"")}return w}var o=c.isFunction(a);return this.each(function(k){var n=c(this),r=a;if(this.nodeType===1){if(o)r=a.call(this,k,n.val());if(typeof r==="number")r+="";if(c.isArray(r)&&Ba.test(this.type))this.checked=c.inArray(n.val(),r)>=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected=
|
|
||||||
c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
|
|
||||||
a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g,
|
|
||||||
function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split(".");
|
|
||||||
k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a),
|
|
||||||
C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B<r.length;B++){u=r[B];if(d.guid===u.guid){if(i||k.test(u.namespace)){f==null&&r.splice(B--,1);n.remove&&n.remove.call(a,u)}if(f!=
|
|
||||||
null)break}}if(r.length===0||f!=null&&r.length===1){if(!n.teardown||n.teardown.call(a,o)===false)Ca(a,e,z.handle);delete C[e]}}else for(var B=0;B<r.length;B++){u=r[B];if(i||k.test(u.namespace)){c.event.remove(a,n,u.handler,B);r.splice(B--,1)}}}if(c.isEmptyObject(C)){if(b=z.handle)b.elem=null;delete z.events;delete z.handle;c.isEmptyObject(z)&&c.removeData(a)}}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=
|
|
||||||
e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&&
|
|
||||||
f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;
|
|
||||||
if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e<j;e++){var i=d[e];if(b||f.test(i.namespace)){a.handler=i.handler;a.data=i.data;a.handleObj=i;i=i.handler.apply(this,arguments);if(i!==w){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
|
|
||||||
fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||s;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=s.documentElement;d=s.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
|
|
||||||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==w)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,a.origType,c.extend({},a,{handler:oa}))},remove:function(a){var b=true,d=a.origType.replace(O,"");c.each(c.data(this,
|
|
||||||
"events").live||[],function(){if(d===this.origType.replace(O,""))return b=false});b&&c.event.remove(this,a.origType,oa)}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};var Ca=s.removeEventListener?function(a,b,d){a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=
|
|
||||||
a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,
|
|
||||||
isImmediatePropagationStopped:Y};var Da=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},Ea=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ea:Da,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ea:Da)}}});if(!c.support.submitBubbles)c.event.special.submit=
|
|
||||||
{setup:function(){if(this.nodeName.toLowerCase()!=="form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length)return na("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13)return na("submit",this,arguments)})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};
|
|
||||||
if(!c.support.changeBubbles){var da=/textarea|input|select/i,ea,Fa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",
|
|
||||||
e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,
|
|
||||||
"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a,
|
|
||||||
d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j<o;j++)c.event.add(this[j],d,i,f)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&
|
|
||||||
!a.preventDefault)for(var d in a)this.unbind(d,a[d]);else{d=0;for(var f=this.length;d<f;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,f){return this.live(b,d,f,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},
|
|
||||||
toggle:function(a){for(var b=arguments,d=1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(f){var e=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,e+1);f.preventDefault();return b[e].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Ga={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,f,e,j){var i,o=0,k,n,r=j||this.selector,
|
|
||||||
u=j?this:c(this.context);if(c.isFunction(f)){e=f;f=w}for(d=(d||"").split(" ");(i=d[o++])!=null;){j=O.exec(i);k="";if(j){k=j[0];i=i.replace(O,"")}if(i==="hover")d.push("mouseenter"+k,"mouseleave"+k);else{n=i;if(i==="focus"||i==="blur"){d.push(Ga[i]+k);i+=k}else i=(Ga[i]||i)+k;b==="live"?u.each(function(){c.event.add(this,pa(i,r),{data:f,selector:r,handler:e,origType:i,origHandler:e,preType:n})}):u.unbind(pa(i,r),e)}}return this}});c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),
|
|
||||||
function(a,b){c.fn[b]=function(d){return d?this.bind(b,d):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});A.attachEvent&&!A.addEventListener&&A.attachEvent("onunload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});(function(){function a(g){for(var h="",l,m=0;g[m];m++){l=g[m];if(l.nodeType===3||l.nodeType===4)h+=l.nodeValue;else if(l.nodeType!==8)h+=a(l.childNodes)}return h}function b(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];
|
|
||||||
if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1&&!p){t.sizcache=l;t.sizset=q}if(t.nodeName.toLowerCase()===h){y=t;break}t=t[g]}m[q]=y}}}function d(g,h,l,m,q,p){q=0;for(var v=m.length;q<v;q++){var t=m[q];if(t){t=t[g];for(var y=false;t;){if(t.sizcache===l){y=m[t.sizset];break}if(t.nodeType===1){if(!p){t.sizcache=l;t.sizset=q}if(typeof h!=="string"){if(t===h){y=true;break}}else if(k.filter(h,[t]).length>0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
|
|
||||||
e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift();
|
|
||||||
t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D||
|
|
||||||
g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h<g.length;h++)g[h]===g[h-1]&&g.splice(h--,1)}return g};k.matches=function(g,h){return k(g,null,null,h)};k.find=function(g,h,l){var m,q;if(!g)return[];
|
|
||||||
for(var p=0,v=n.order.length;p<v;p++){var t=n.order[p];if(q=n.leftMatch[t].exec(g)){var y=q[1];q.splice(1,1);if(y.substr(y.length-1)!=="\\"){q[1]=(q[1]||"").replace(/\\/g,"");m=n.find[t](q,h,l);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=h.getElementsByTagName("*"));return{set:m,expr:g}};k.filter=function(g,h,l,m){for(var q=g,p=[],v=h,t,y,S=h&&h[0]&&x(h[0]);g&&h.length;){for(var H in n.filter)if((t=n.leftMatch[H].exec(g))!=null&&t[2]){var M=n.filter[H],I,D;D=t[1];y=false;t.splice(1,1);if(D.substr(D.length-
|
|
||||||
1)!=="\\"){if(v===p)p=[];if(n.preFilter[H])if(t=n.preFilter[H](t,v,l,p,m,S)){if(t===true)continue}else y=I=true;if(t)for(var U=0;(D=v[U])!=null;U++)if(D){I=M(D,t,U,v);var Ha=m^!!I;if(l&&I!=null)if(Ha)y=true;else v[U]=false;else if(Ha){p.push(D);y=true}}if(I!==w){l||(v=p);g=g.replace(n.match[H],"");if(!y)return[];break}}}if(g===q)if(y==null)k.error(g);else break;q=g}return v};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
|
|
||||||
CLASS:/\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},
|
|
||||||
relative:{"+":function(g,h){var l=typeof h==="string",m=l&&!/\W/.test(h);l=l&&!m;if(m)h=h.toLowerCase();m=0;for(var q=g.length,p;m<q;m++)if(p=g[m]){for(;(p=p.previousSibling)&&p.nodeType!==1;);g[m]=l||p&&p.nodeName.toLowerCase()===h?p||false:p===h}l&&k.filter(h,g,true)},">":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m<q;m++){var p=g[m];if(p){l=p.parentNode;g[m]=l.nodeName.toLowerCase()===h?l:false}}}else{m=0;for(q=g.length;m<q;m++)if(p=g[m])g[m]=
|
|
||||||
l?p.parentNode:p.parentNode===h;l&&k.filter(h,g,true)}},"":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("parentNode",h,m,g,p,l)},"~":function(g,h,l){var m=e++,q=d;if(typeof h==="string"&&!/\W/.test(h)){var p=h=h.toLowerCase();q=b}q("previousSibling",h,m,g,p,l)}},find:{ID:function(g,h,l){if(typeof h.getElementById!=="undefined"&&!l)return(g=h.getElementById(g[1]))?[g]:[]},NAME:function(g,h){if(typeof h.getElementsByName!=="undefined"){var l=[];
|
|
||||||
h=h.getElementsByName(g[1]);for(var m=0,q=h.length;m<q;m++)h[m].getAttribute("name")===g[1]&&l.push(h[m]);return l.length===0?null:l}},TAG:function(g,h){return h.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,h,l,m,q,p){g=" "+g[1].replace(/\\/g,"")+" ";if(p)return g;p=0;for(var v;(v=h[p])!=null;p++)if(v)if(q^(v.className&&(" "+v.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},
|
|
||||||
CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m,
|
|
||||||
g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},
|
|
||||||
text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},
|
|
||||||
setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return h<l[3]-0},gt:function(g,h,l){return h>l[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=
|
|
||||||
h[3];l=0;for(m=h.length;l<m;l++)if(h[l]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+q)},CHILD:function(g,h){var l=h[1],m=g;switch(l){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(l==="first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":l=h[2];var q=h[3];if(l===1&&q===0)return true;h=h[0];var p=g.parentNode;if(p&&(p.sizcache!==h||!g.nodeIndex)){var v=0;for(m=p.firstChild;m;m=
|
|
||||||
m.nextSibling)if(m.nodeType===1)m.nodeIndex=++v;p.sizcache=h}g=g.nodeIndex-q;return l===0?g===0:g%l===0&&g/l>=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m===
|
|
||||||
"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g,
|
|
||||||
h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l<m;l++)h.push(g[l]);else for(l=0;g[l];l++)h.push(g[l]);return h}}var B;if(s.documentElement.compareDocumentPosition)B=function(g,h){if(!g.compareDocumentPosition||
|
|
||||||
!h.compareDocumentPosition){if(g==h)i=true;return g.compareDocumentPosition?-1:1}g=g.compareDocumentPosition(h)&4?-1:g===h?0:1;if(g===0)i=true;return g};else if("sourceIndex"in s.documentElement)B=function(g,h){if(!g.sourceIndex||!h.sourceIndex){if(g==h)i=true;return g.sourceIndex?-1:1}g=g.sourceIndex-h.sourceIndex;if(g===0)i=true;return g};else if(s.createRange)B=function(g,h){if(!g.ownerDocument||!h.ownerDocument){if(g==h)i=true;return g.ownerDocument?-1:1}var l=g.ownerDocument.createRange(),m=
|
|
||||||
h.ownerDocument.createRange();l.setStart(g,0);l.setEnd(g,0);m.setStart(h,0);m.setEnd(h,0);g=l.compareBoundaryPoints(Range.START_TO_END,m);if(g===0)i=true;return g};(function(){var g=s.createElement("div"),h="script"+(new Date).getTime();g.innerHTML="<a name='"+h+"'/>";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&&
|
|
||||||
q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML="<a href='#'></a>";
|
|
||||||
if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="<p class='TEST'></p>";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}();
|
|
||||||
(function(){var g=s.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}:
|
|
||||||
function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q<p;q++)k(g,h[q],l);return k.filter(m,l)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=a;c.isXMLDoc=x;c.contains=E})();var eb=/Until$/,fb=/^(?:parents|prevUntil|prevAll)/,
|
|
||||||
gb=/,/;R=Array.prototype.slice;var Ia=function(a,b,d){if(c.isFunction(b))return c.grep(a,function(e,j){return!!b.call(e,j,e)===d});else if(b.nodeType)return c.grep(a,function(e){return e===b===d});else if(typeof b==="string"){var f=c.grep(a,function(e){return e.nodeType===1});if(Ua.test(b))return c.filter(b,f,!d);else b=c.filter(b,f)}return c.grep(a,function(e){return c.inArray(e,b)>=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f<e;f++){d=b.length;
|
|
||||||
c.find(a,this[f],b);if(f>0)for(var j=d;j<b.length;j++)for(var i=0;i<d;i++)if(b[i]===b[j]){b.splice(j--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,f=b.length;d<f;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(Ia(this,a,false),"not",a)},filter:function(a){return this.pushStack(Ia(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j=
|
|
||||||
{},i;if(f&&a.length){e=0;for(var o=a.length;e<o;e++){i=a[e];j[i]||(j[i]=c.expr.match.POS.test(i)?c(i,b||this.context):i)}for(;f&&f.ownerDocument&&f!==b;){for(i in j){e=j[i];if(e.jquery?e.index(f)>-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a===
|
|
||||||
"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",
|
|
||||||
d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?
|
|
||||||
a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType===
|
|
||||||
1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/<tbody/i,jb=/<|&#?\w+;/,ta=/<script|<object|<embed|<option|<style/i,ua=/checked\s*(?:[^=]|=\s*.checked.)/i,Ma=function(a,b,d){return hb.test(d)?
|
|
||||||
a:b+"></"+d+">"},F={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
|
|
||||||
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
|
|
||||||
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
|
|
||||||
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
|
|
||||||
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
|
|
||||||
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja,
|
|
||||||
""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(f){this.empty().append(a)}}else c.isFunction(a)?this.each(function(e){var j=c(this),i=j.html();j.empty().append(function(){return a.call(this,e,i)})}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&
|
|
||||||
this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=c(this),f=d.html();d.replaceWith(a.call(this,b,f))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){function f(u){return c.nodeName(u,"table")?u.getElementsByTagName("tbody")[0]||
|
|
||||||
u.appendChild(u.ownerDocument.createElement("tbody")):u}var e,j,i=a[0],o=[],k;if(!c.support.checkClone&&arguments.length===3&&typeof i==="string"&&ua.test(i))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(i))return this.each(function(u){var z=c(this);a[0]=i.call(this,u,b?z.html():w);z.domManip(a,b,d)});if(this[0]){e=i&&i.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:sa(a,this,o);k=e.fragment;if(j=k.childNodes.length===
|
|
||||||
1?(k=k.firstChild):k.firstChild){b=b&&c.nodeName(j,"tr");for(var n=0,r=this.length;n<r;n++)d.call(b?f(this[n],j):this[n],n>0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]);
|
|
||||||
return this}else{e=0;for(var j=d.length;e<j;e++){var i=(e>0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["",
|
|
||||||
""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]==="<table>"&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e=
|
|
||||||
c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]?
|
|
||||||
c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja=
|
|
||||||
function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter=
|
|
||||||
Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a,
|
|
||||||
"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f=
|
|
||||||
a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=
|
|
||||||
a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=/<script(.|\s)*?\/script>/gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!==
|
|
||||||
"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("<div />").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this},
|
|
||||||
serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),
|
|
||||||
function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,
|
|
||||||
global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&&
|
|
||||||
e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)?
|
|
||||||
"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache===
|
|
||||||
false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B=
|
|
||||||
false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since",
|
|
||||||
c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E||
|
|
||||||
d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x);
|
|
||||||
g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===
|
|
||||||
1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b===
|
|
||||||
"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional;
|
|
||||||
if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");
|
|
||||||
this[a].style.display=d||"";if(c.css(this[a],"display")==="none"){d=this[a].nodeName;var f;if(la[d])f=la[d];else{var e=c("<"+d+" />").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b){if(a||a===0)return this.animate(K("hide",3),a,b);else{a=0;for(b=this.length;a<b;a++){var d=c.data(this[a],"olddisplay");!d&&d!=="none"&&c.data(this[a],
|
|
||||||
"olddisplay",c.css(this[a],"display"))}a=0;for(b=this.length;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b){var d=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||d?this.each(function(){var f=d?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(K("toggle",3),a,b);return this},fadeTo:function(a,b,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d)},
|
|
||||||
animate:function(a,b,d,f){var e=c.speed(b,d,f);if(c.isEmptyObject(a))return this.each(e.complete);return this[e.queue===false?"each":"queue"](function(){var j=c.extend({},e),i,o=this.nodeType===1&&c(this).is(":hidden"),k=this;for(i in a){var n=i.replace(ia,ja);if(i!==n){a[n]=a[i];delete a[i];i=n}if(a[i]==="hide"&&o||a[i]==="show"&&!o)return j.complete.call(this);if((i==="height"||i==="width")&&this.style){j.display=c.css(this,"display");j.overflow=this.style.overflow}if(c.isArray(a[i])){(j.specialEasing=
|
|
||||||
j.specialEasing||{})[i]=a[i][1];a[i]=a[i][0]}}if(j.overflow!=null)this.style.overflow="hidden";j.curAnim=c.extend({},a);c.each(a,function(r,u){var z=new c.fx(k,j,r);if(Ab.test(u))z[u==="toggle"?o?"show":"hide":u](a);else{var C=Bb.exec(u),B=z.cur(true)||0;if(C){u=parseFloat(C[2]);var E=C[3]||"px";if(E!=="px"){k.style[r]=(u||1)+E;B=(u||1)/z.cur(true)*B;k.style[r]=B+E}if(C[1])u=(C[1]==="-="?-1:1)*u+B;z.custom(B,u,E)}else z.custom(B,u,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);
|
|
||||||
this.each(function(){for(var f=d.length-1;f>=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration===
|
|
||||||
"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||
|
|
||||||
c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;
|
|
||||||
this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=
|
|
||||||
this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem,
|
|
||||||
e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||
|
|
||||||
c.fx.stop()},stop:function(){clearInterval(W);W=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===b.elem}).length};c.fn.offset="getBoundingClientRect"in s.documentElement?
|
|
||||||
function(a){var b=this[0];if(a)return this.each(function(e){c.offset.setOffset(this,a,e)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);var d=b.getBoundingClientRect(),f=b.ownerDocument;b=f.body;f=f.documentElement;return{top:d.top+(self.pageYOffset||c.support.boxModel&&f.scrollTop||b.scrollTop)-(f.clientTop||b.clientTop||0),left:d.left+(self.pageXOffset||c.support.boxModel&&f.scrollLeft||b.scrollLeft)-(f.clientLeft||b.clientLeft||0)}}:function(a){var b=
|
|
||||||
this[0];if(a)return this.each(function(r){c.offset.setOffset(this,a,r)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,f=b,e=b.ownerDocument,j,i=e.documentElement,o=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;for(var k=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==o&&b!==i;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;j=e?e.getComputedStyle(b,null):b.currentStyle;
|
|
||||||
k-=b.scrollTop;n-=b.scrollLeft;if(b===d){k+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(b.nodeName))){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=d;d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&j.overflow!=="visible"){k+=parseFloat(j.borderTopWidth)||0;n+=parseFloat(j.borderLeftWidth)||0}f=j}if(f.position==="relative"||f.position==="static"){k+=o.offsetTop;n+=o.offsetLeft}if(c.offset.supportsFixedPosition&&
|
|
||||||
f.position==="fixed"){k+=Math.max(i.scrollTop,o.scrollTop);n+=Math.max(i.scrollLeft,o.scrollLeft)}return{top:k,left:n}};c.offset={initialize:function(){var a=s.body,b=s.createElement("div"),d,f,e,j=parseFloat(c.curCSS(a,"marginTop",true))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";
|
|
||||||
a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b);
|
|
||||||
c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a,
|
|
||||||
d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top-
|
|
||||||
f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset":
|
|
||||||
"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in
|
|
||||||
e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window);
|
|
@ -1,42 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
|
|
||||||
dir="ltr" id="html">
|
|
||||||
<head>
|
|
||||||
<title>plone.app.discussion comments Test Suite</title>
|
|
||||||
|
|
||||||
<!-- qUnit -->
|
|
||||||
<link rel="stylesheet" href="../qunit/qunit.css" type="text/css"
|
|
||||||
media="screen" />
|
|
||||||
<script type="text/javascript" src="../qunit/qunit.js"></script>
|
|
||||||
|
|
||||||
<!-- jQuery -->
|
|
||||||
<script type="text/javascript" src="jquery.js"></script>
|
|
||||||
|
|
||||||
<!-- plone.app.discussion -->
|
|
||||||
<script type="text/javascript" src="../../browser/javascripts/comments.js">
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Tests -->
|
|
||||||
<script type="text/javascript" src="test_comments.js"></script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<h1 id="qunit-header">plone.app.discussion comments Test
|
|
||||||
Suite</h1>
|
|
||||||
|
|
||||||
<h2 id="qunit-banner"></h2>
|
|
||||||
|
|
||||||
<div id="qunit-testrunner-toolbar">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2 id="qunit-userAgent"></h2>
|
|
||||||
|
|
||||||
<ol id="qunit-tests">
|
|
||||||
</ol>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
||||||
|
|
@ -1,146 +0,0 @@
|
|||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
|
|
||||||
/* TEST SETUP */
|
|
||||||
|
|
||||||
module("comments", {
|
|
||||||
setup: function () {
|
|
||||||
|
|
||||||
// Create a comments section with one comment inside
|
|
||||||
//
|
|
||||||
// <div class="discussion">
|
|
||||||
// <div id="1282720906349675" class="comment">
|
|
||||||
// <div class="commentBody">
|
|
||||||
// <p>Lorem ipsum.</p>
|
|
||||||
// </div>
|
|
||||||
// <div class="commentActions">
|
|
||||||
// <button class="reply-to-comment-button"></button>
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
|
|
||||||
var comments = $(document.createElement("div"))
|
|
||||||
.addClass("discussion")
|
|
||||||
.append($(document.createElement("div"))
|
|
||||||
.addClass("comment")
|
|
||||||
.attr("id", "1282720906349675")
|
|
||||||
.append($(document.createElement("div"))
|
|
||||||
.addClass("commentBody")
|
|
||||||
.append($(document.createElement("p"))
|
|
||||||
.text("Lorem ipsum.")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.append($(document.createElement("div"))
|
|
||||||
.addClass("commentActions")
|
|
||||||
.append($(document.createElement("button"))
|
|
||||||
.addClass("reply-to-comment-button")
|
|
||||||
))
|
|
||||||
);
|
|
||||||
$(document.body).append(comments);
|
|
||||||
|
|
||||||
// Create a basic commenting form
|
|
||||||
//
|
|
||||||
// <form class="form">
|
|
||||||
// <div class="formfield-form-widgets-in_reply_to">
|
|
||||||
// <input name="form.widgets.in_reply_to">
|
|
||||||
// </div>
|
|
||||||
// <div class="formfield-form-widgets-author_name">
|
|
||||||
// <input name="form.widgets.author" type="text">
|
|
||||||
// </div>
|
|
||||||
// <div class="formfield-form-widgets-text">
|
|
||||||
// <textarea name="form.widgets.text"></textarea>
|
|
||||||
// </div>
|
|
||||||
// <div class="formControls">
|
|
||||||
// <input name="form.buttons.comment">
|
|
||||||
// <input name="form.buttons.cancel">
|
|
||||||
// </div>
|
|
||||||
// </form>
|
|
||||||
|
|
||||||
var commentform = $(document.createElement("div"))
|
|
||||||
.append($(document.createElement("form"))
|
|
||||||
.addClass("form")
|
|
||||||
.append($(document.createElement("div"))
|
|
||||||
.addClass("formfield-form-widgets-in_reply_to")
|
|
||||||
.append($(document.createElement("input"))
|
|
||||||
.attr("name", "form.widgets.in_reply_to")
|
|
||||||
.val("")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.append($(document.createElement("div"))
|
|
||||||
.addClass("formfield-form-widgets-author_name")
|
|
||||||
.append($(document.createElement("input"))
|
|
||||||
.attr("name", "form.widgets.author")
|
|
||||||
.attr("type", "text")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.append($(document.createElement("div"))
|
|
||||||
.addClass("formfield-form-widgets-text")
|
|
||||||
.append($(document.createElement("textarea"))
|
|
||||||
.attr("name", "form.widgets.text")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.append($(document.createElement("div"))
|
|
||||||
.addClass("formControls")
|
|
||||||
.append($(document.createElement("input"))
|
|
||||||
.attr("name", "form.buttons.comment"))
|
|
||||||
.append($(document.createElement("input"))
|
|
||||||
.attr("name", "form.buttons.cancel"))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.addClass("reply")
|
|
||||||
.attr("id", "commenting");
|
|
||||||
$(document.body).append(commentform);
|
|
||||||
},
|
|
||||||
teardown: function () {
|
|
||||||
$("#commenting").remove();
|
|
||||||
$(".discussion").remove();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
/* TESTS */
|
|
||||||
|
|
||||||
test("Hide the reply and the cancel button for the comment form", function(){
|
|
||||||
expect(1);
|
|
||||||
$(".reply").find("input[name='form.buttons.cancel']").css("display", "none");
|
|
||||||
equals($("input[name='form.buttons.cancel']").css("display"), "none", "The cancel button should be hidden");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Show the reply button only when Javascript is enabled", function(){
|
|
||||||
expect(1);
|
|
||||||
$(".reply-to-comment-button").css("display", "inline");
|
|
||||||
equals($("button[class='reply-to-comment-button']").attr("style"), "display: inline;", "The reply button should show up when Javascript is enabled");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Create a comment reply form.", function() {
|
|
||||||
expect(2);
|
|
||||||
var comment_div = $("#1282720906349675");
|
|
||||||
var reply_button = comment_div.children(".reply-to-comment-button");
|
|
||||||
$.createReplyForm(comment_div);
|
|
||||||
var reply_form = comment_div.children(".reply");
|
|
||||||
ok(reply_form.find("input[name='form.widgets.in_reply_to']"), "Reply form has been copied");
|
|
||||||
same(reply_form.find("input[name='form.widgets.in_reply_to']").val(), "1282720906349675", "The reply for should have the id of the comment in the in_reply_to field");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("Clear all form values from a form.", function() {
|
|
||||||
// Create a reply form with some values
|
|
||||||
var comment_div = $("#1282720906349675");
|
|
||||||
$.createReplyForm(comment_div);
|
|
||||||
var reply_form = comment_div.find(".reply");
|
|
||||||
var author = reply_form.find("input[name='form.widgets.author']");
|
|
||||||
var text = comment_div.find("input[name='form.widgets.text']");
|
|
||||||
author.val("my author");
|
|
||||||
text.val("my text");
|
|
||||||
// Call the clearForm function to clear the form
|
|
||||||
$.clearForm(comment_div);
|
|
||||||
// Check if all form fields have been cleared
|
|
||||||
var author = comment_div.find("input[name='form.widgets.author']");
|
|
||||||
var text = comment_div.find("input[name='form.widgets.text']");
|
|
||||||
equals(author.val(), "", "The author form value should be empty");
|
|
||||||
equals(text.text(), "", "The text form value should be empty");
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
|||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"
|
|
||||||
dir="ltr" id="html">
|
|
||||||
<head>
|
|
||||||
<title>plone.app.discussion moderation Test Suite</title>
|
|
||||||
|
|
||||||
<!-- qUnit -->
|
|
||||||
<link rel="stylesheet" href="../qunit/qunit.css" type="text/css"
|
|
||||||
media="screen" />
|
|
||||||
<script type="text/javascript" src="../qunit/qunit.js"></script>
|
|
||||||
|
|
||||||
<!-- jQuery -->
|
|
||||||
<script type="text/javascript" src="jquery.js"></script>
|
|
||||||
|
|
||||||
<!-- plone.app.discussion -->
|
|
||||||
<script type="text/javascript" src="../../browser/javascripts/moderation.js">
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Tests -->
|
|
||||||
<script type="text/javascript" src="test_moderation.js"></script>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<h1 id="qunit-header">plone.app.discussion moderation Test Suite</h1>
|
|
||||||
|
|
||||||
<h2 id="qunit-banner"></h2>
|
|
||||||
|
|
||||||
<div id="qunit-testrunner-toolbar"></div>
|
|
||||||
|
|
||||||
<h2 id="qunit-userAgent"></h2>
|
|
||||||
|
|
||||||
<ol id="qunit-tests"></ol>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
@ -1,72 +0,0 @@
|
|||||||
/* TEST SETUP */
|
|
||||||
|
|
||||||
module("comments", {
|
|
||||||
setup: function () {
|
|
||||||
// <form>
|
|
||||||
// <table id="review-comments">
|
|
||||||
// <tbody>
|
|
||||||
// <tr>
|
|
||||||
// <td>
|
|
||||||
// <a href="http://localhost:8080/Plone/front-page/++conversation++default/1285339036601284">My comment</a>
|
|
||||||
// </td>
|
|
||||||
// <td class="actions">
|
|
||||||
// <input id="1285339036601284" class="context comment-publish-button" type="submit" value="Publish" name="form.button.Publish" />
|
|
||||||
// <input id="1285339036601284" class="destructive comment-delete-button" type="submit" value="Delete" name="form.button.Delete" />
|
|
||||||
// </td>
|
|
||||||
// </tr>
|
|
||||||
// </tbody>
|
|
||||||
// </table>
|
|
||||||
// </form>
|
|
||||||
var review_table = $(document.createElement("form"))
|
|
||||||
.append($(document.createElement("table"))
|
|
||||||
.attr("id", "review-comments")
|
|
||||||
.append($(document.createElement("tbody"))
|
|
||||||
.append($(document.createElement("tr"))
|
|
||||||
.append($(document.createElement("td"))
|
|
||||||
.append($(document.createElement("a"))
|
|
||||||
.text("My comment.")
|
|
||||||
.attr("href", "http://localhost:8080/Plone/front-page/++conversation++default/1285339036601284")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.append($(document.createElement("td"))
|
|
||||||
.append($(document.createElement("input"))
|
|
||||||
.attr("id", "1285339036601284")
|
|
||||||
.attr("value", "Publish")
|
|
||||||
.attr("name", "form.button.Publish")
|
|
||||||
)
|
|
||||||
.append($(document.createElement("input"))
|
|
||||||
.attr("id", "1285339036601284")
|
|
||||||
.attr("value", "Delete")
|
|
||||||
.attr("name", "form.button.Delete")
|
|
||||||
)
|
|
||||||
.addClass("actions")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$(document.body).append(review_table);
|
|
||||||
},
|
|
||||||
teardown: function () {
|
|
||||||
$("form").remove();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
/* TESTS */
|
|
||||||
|
|
||||||
test("Delete a single comment", function(){
|
|
||||||
expect(1);
|
|
||||||
stop();
|
|
||||||
var delete_button = $(".actions").children("input[name='form.button.Delete']");
|
|
||||||
delete_button.trigger('click');
|
|
||||||
start();
|
|
||||||
equals($("#1285339036601284").attr("name", "form.button.Delete").length, 0, "The comment row should have been deleted.");
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
test("Publish a single comment", function(){
|
|
||||||
expect(1);
|
|
||||||
var publish_button = $(".actions").children("input[name='form.button.Publish']");
|
|
||||||
publish_button.trigger('click');
|
|
||||||
equals($("#1285339036601284").attr("name", "form.button.Publish").length, 0, "The comment row should have been removed since the comment has been published.");
|
|
||||||
});
|
|
@ -1,18 +0,0 @@
|
|||||||
server: http://localhost:9876
|
|
||||||
|
|
||||||
load:
|
|
||||||
# Add these lines to load the equiv function and adapter in order, before the
|
|
||||||
# tests (assuming they are saved to tests/qunit/)
|
|
||||||
- qunit/equiv.js
|
|
||||||
- qunit/QUnitAdapter.js
|
|
||||||
|
|
||||||
# This is where we load the qunit tests
|
|
||||||
- javascripts/*.js
|
|
||||||
|
|
||||||
# And this loads the source files we are testing
|
|
||||||
- ../browser/javascripts/*.js
|
|
||||||
|
|
||||||
plugin:
|
|
||||||
- name: "coverage"
|
|
||||||
jar: "../../../../parts/jstestdriver/coverage.jar"
|
|
||||||
module: "com.google.jstestdriver.coverage.CoverageModule"
|
|
@ -1,5 +0,0 @@
|
|||||||
==============
|
|
||||||
JS TEST DRIVER
|
|
||||||
==============
|
|
||||||
|
|
||||||
java -jar JsTestDriver.jar --port 9876 --config jsTestDriver.conf --browser /usr/bin/firefox --tests all
|
|
@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
QUnitAdapter
|
|
||||||
Version: 1.1.0
|
|
||||||
|
|
||||||
Run qunit tests using JS Test Driver
|
|
||||||
|
|
||||||
This provides almost the same api as qunit.
|
|
||||||
|
|
||||||
Tests must run sychronously, which means no use of stop and start methods.
|
|
||||||
You can use jsUnit Clock object to deal with timeouts and intervals:
|
|
||||||
http://googletesting.blogspot.com/2007/03/javascript-simulating-time-in-jsunit.html
|
|
||||||
|
|
||||||
The qunit #main DOM element is not included. If you need to do any DOM manipulation
|
|
||||||
you need to set it up and tear it down in each test.
|
|
||||||
|
|
||||||
*/
|
|
||||||
(function() {
|
|
||||||
|
|
||||||
if(!(window.equiv)) {
|
|
||||||
throw new Error("QUnitAdapter.js - Unable to find equiv function. Ensure you have added equiv.js to the load section of your jsTestDriver.conf");
|
|
||||||
}
|
|
||||||
|
|
||||||
var QUnitTestCase;
|
|
||||||
|
|
||||||
window.module = function(name, lifecycle) {
|
|
||||||
QUnitTestCase = TestCase(name);
|
|
||||||
QUnitTestCase.prototype.lifecycle = lifecycle || {};
|
|
||||||
};
|
|
||||||
|
|
||||||
window.test = function(name, expected, test) {
|
|
||||||
QUnitTestCase.prototype['test ' + name] = function() {
|
|
||||||
if(this.lifecycle.setup) {
|
|
||||||
this.lifecycle.setup();
|
|
||||||
}
|
|
||||||
if(expected.constructor === Number) {
|
|
||||||
expectAsserts(expected);
|
|
||||||
} else {
|
|
||||||
test = expected;
|
|
||||||
}
|
|
||||||
test.call(this.lifecycle);
|
|
||||||
|
|
||||||
if(this.lifecycle.teardown) {
|
|
||||||
this.lifecycle.teardown();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
window.expect = function(count) {
|
|
||||||
expectAsserts(count);
|
|
||||||
};
|
|
||||||
|
|
||||||
window.ok = function(actual, msg) {
|
|
||||||
assertTrue(msg ? msg : '', !!actual);
|
|
||||||
};
|
|
||||||
|
|
||||||
window.equals = function(a, b, msg) {
|
|
||||||
assertEqual(msg ? msg : '', b, a);
|
|
||||||
};
|
|
||||||
|
|
||||||
window.start = window.stop = function() {
|
|
||||||
fail('start and stop methods are not available when using JS Test Driver.\n' +
|
|
||||||
'Use jsUnit Clock object to deal with timeouts and intervals:\n' +
|
|
||||||
'http://googletesting.blogspot.com/2007/03/javascript-simulating-time-in-jsunit.html.');
|
|
||||||
};
|
|
||||||
|
|
||||||
window.same = function(a, b, msg) {
|
|
||||||
assertTrue(msg ? msg : '', window.equiv(b, a));
|
|
||||||
};
|
|
||||||
|
|
||||||
window.reset = function() {
|
|
||||||
fail('reset method is not available when using JS Test Driver');
|
|
||||||
};
|
|
||||||
|
|
||||||
window.isLocal = function() {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
window.QUnit = {
|
|
||||||
equiv: window.equiv,
|
|
||||||
ok: window.ok
|
|
||||||
};
|
|
||||||
|
|
||||||
module('Default Module');
|
|
||||||
|
|
||||||
})();
|
|
@ -1,185 +0,0 @@
|
|||||||
|
|
||||||
// Tests for equality any JavaScript type and structure without unexpected results.
|
|
||||||
// Discussions and reference: http://philrathe.com/articles/equiv
|
|
||||||
// Test suites: http://philrathe.com/tests/equiv
|
|
||||||
// Author: Philippe Rath <prathe@gmail.com>
|
|
||||||
window.equiv = function () {
|
|
||||||
|
|
||||||
var innerEquiv; // the real equiv function
|
|
||||||
var callers = []; // stack to decide between skip/abort functions
|
|
||||||
|
|
||||||
// Determine what is o.
|
|
||||||
function hoozit(o) {
|
|
||||||
if (typeof o === "string") {
|
|
||||||
return "string";
|
|
||||||
|
|
||||||
} else if (typeof o === "boolean") {
|
|
||||||
return "boolean";
|
|
||||||
|
|
||||||
} else if (typeof o === "number") {
|
|
||||||
|
|
||||||
if (isNaN(o)) {
|
|
||||||
return "nan";
|
|
||||||
} else {
|
|
||||||
return "number";
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (typeof o === "undefined") {
|
|
||||||
return "undefined";
|
|
||||||
|
|
||||||
// consider: typeof null === object
|
|
||||||
} else if (o === null) {
|
|
||||||
return "null";
|
|
||||||
|
|
||||||
// consider: typeof [] === object
|
|
||||||
} else if (o instanceof Array) {
|
|
||||||
return "array";
|
|
||||||
|
|
||||||
// consider: typeof new Date() === object
|
|
||||||
} else if (o instanceof Date) {
|
|
||||||
return "date";
|
|
||||||
|
|
||||||
// consider: /./ instanceof Object;
|
|
||||||
// /./ instanceof RegExp;
|
|
||||||
// typeof /./ === "function"; // => false in IE and Opera,
|
|
||||||
// true in FF and Safari
|
|
||||||
} else if (o instanceof RegExp) {
|
|
||||||
return "regexp";
|
|
||||||
|
|
||||||
} else if (typeof o === "object") {
|
|
||||||
return "object";
|
|
||||||
|
|
||||||
} else if (o instanceof Function) {
|
|
||||||
return "function";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call the o related callback with the given arguments.
|
|
||||||
function bindCallbacks(o, callbacks, args) {
|
|
||||||
var prop = hoozit(o);
|
|
||||||
if (prop) {
|
|
||||||
if (hoozit(callbacks[prop]) === "function") {
|
|
||||||
return callbacks[prop].apply(callbacks, args);
|
|
||||||
} else {
|
|
||||||
return callbacks[prop]; // or undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var callbacks = function () {
|
|
||||||
|
|
||||||
// for string, boolean, number and null
|
|
||||||
function useStrictEquality(b, a) {
|
|
||||||
return a === b;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
"string": useStrictEquality,
|
|
||||||
"boolean": useStrictEquality,
|
|
||||||
"number": useStrictEquality,
|
|
||||||
"null": useStrictEquality,
|
|
||||||
"undefined": useStrictEquality,
|
|
||||||
|
|
||||||
"nan": function (b) {
|
|
||||||
return isNaN(b);
|
|
||||||
},
|
|
||||||
|
|
||||||
"date": function (b, a) {
|
|
||||||
return hoozit(b) === "date" && a.valueOf() === b.valueOf();
|
|
||||||
},
|
|
||||||
|
|
||||||
"regexp": function (b, a) {
|
|
||||||
return hoozit(b) === "regexp" &&
|
|
||||||
a.source === b.source && // the regex itself
|
|
||||||
a.global === b.global && // and its modifers (gmi) ...
|
|
||||||
a.ignoreCase === b.ignoreCase &&
|
|
||||||
a.multiline === b.multiline;
|
|
||||||
},
|
|
||||||
|
|
||||||
// - skip when the property is a method of an instance (OOP)
|
|
||||||
// - abort otherwise,
|
|
||||||
// initial === would have catch identical references anyway
|
|
||||||
"function": function () {
|
|
||||||
var caller = callers[callers.length - 1];
|
|
||||||
return caller !== Object &&
|
|
||||||
typeof caller !== "undefined";
|
|
||||||
},
|
|
||||||
|
|
||||||
"array": function (b, a) {
|
|
||||||
var i;
|
|
||||||
var len;
|
|
||||||
|
|
||||||
// b could be an object literal here
|
|
||||||
if ( ! (hoozit(b) === "array")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = a.length;
|
|
||||||
if (len !== b.length) { // safe and faster
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
if( ! innerEquiv(a[i], b[i])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
"object": function (b, a) {
|
|
||||||
var i;
|
|
||||||
var eq = true; // unless we can proove it
|
|
||||||
var aProperties = [], bProperties = []; // collection of strings
|
|
||||||
|
|
||||||
// comparing constructors is more strict than using instanceof
|
|
||||||
if ( a.constructor !== b.constructor) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// stack constructor before traversing properties
|
|
||||||
callers.push(a.constructor);
|
|
||||||
|
|
||||||
for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
|
|
||||||
|
|
||||||
aProperties.push(i); // collect a's properties
|
|
||||||
|
|
||||||
if ( ! innerEquiv(a[i], b[i])) {
|
|
||||||
eq = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
callers.pop(); // unstack, we are done
|
|
||||||
|
|
||||||
for (i in b) {
|
|
||||||
bProperties.push(i); // collect b's properties
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensures identical properties name
|
|
||||||
return eq && innerEquiv(aProperties.sort(), bProperties.sort());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}();
|
|
||||||
|
|
||||||
innerEquiv = function () { // can take multiple arguments
|
|
||||||
var args = Array.prototype.slice.apply(arguments);
|
|
||||||
if (args.length < 2) {
|
|
||||||
return true; // end transition
|
|
||||||
}
|
|
||||||
|
|
||||||
return (function (a, b) {
|
|
||||||
if (a === b) {
|
|
||||||
return true; // catch the most you can
|
|
||||||
|
|
||||||
} else if (typeof a !== typeof b || a === null || b === null || typeof a === "undefined" || typeof b === "undefined") {
|
|
||||||
return false; // don't lose time with error prone cases
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return bindCallbacks(a, callbacks, [b, a]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply transition with (1..n) arguments
|
|
||||||
})(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));
|
|
||||||
};
|
|
||||||
|
|
||||||
return innerEquiv;
|
|
||||||
}(); // equiv
|
|
@ -1,17 +0,0 @@
|
|||||||
h1#qunit-header { padding: 15px; font-size: large; background-color: #06b; color: white; font-family: 'trebuchet ms', verdana, arial; margin: 0; }
|
|
||||||
h1#qunit-header a { color: white; }
|
|
||||||
|
|
||||||
h2#qunit-banner { height: 2em; border-bottom: 1px solid white; background-color: #eee; margin: 0; font-family: 'trebuchet ms', verdana, arial; }
|
|
||||||
h2#qunit-banner.pass { background-color: green; }
|
|
||||||
h2#qunit-banner.fail { background-color: red; }
|
|
||||||
|
|
||||||
h2#qunit-userAgent { padding: 10px; background-color: #eee; color: black; margin: 0; font-size: small; font-weight: normal; font-family: 'trebuchet ms', verdana, arial; font-size: 10pt; }
|
|
||||||
|
|
||||||
div#qunit-testrunner-toolbar { background: #eee; border-top: 1px solid black; padding: 10px; font-family: 'trebuchet ms', verdana, arial; margin: 0; font-size: 10pt; }
|
|
||||||
|
|
||||||
ol#qunit-tests { font-family: 'trebuchet ms', verdana, arial; font-size: 10pt; }
|
|
||||||
ol#qunit-tests li strong { cursor:pointer; }
|
|
||||||
ol#qunit-tests .pass { color: green; }
|
|
||||||
ol#qunit-tests .fail { color: red; }
|
|
||||||
|
|
||||||
p#qunit-testresult { margin-left: 1em; font-size: 10pt; font-family: 'trebuchet ms', verdana, arial; }
|
|
@ -1,997 +0,0 @@
|
|||||||
/*
|
|
||||||
* QUnit - A JavaScript Unit Testing Framework
|
|
||||||
*
|
|
||||||
* http://docs.jquery.com/QUnit
|
|
||||||
*
|
|
||||||
* Copyright (c) 2009 John Resig, Jörn Zaefferer
|
|
||||||
* Dual licensed under the MIT (MIT-LICENSE.txt)
|
|
||||||
* and GPL (GPL-LICENSE.txt) licenses.
|
|
||||||
*/
|
|
||||||
|
|
||||||
(function(window) {
|
|
||||||
|
|
||||||
var QUnit = {
|
|
||||||
|
|
||||||
// Initialize the configuration options
|
|
||||||
init: function init() {
|
|
||||||
config = {
|
|
||||||
stats: { all: 0, bad: 0 },
|
|
||||||
moduleStats: { all: 0, bad: 0 },
|
|
||||||
started: +new Date,
|
|
||||||
blocking: false,
|
|
||||||
autorun: false,
|
|
||||||
assertions: [],
|
|
||||||
filters: [],
|
|
||||||
queue: []
|
|
||||||
};
|
|
||||||
|
|
||||||
var tests = id("qunit-tests"),
|
|
||||||
banner = id("qunit-banner"),
|
|
||||||
result = id("qunit-testresult");
|
|
||||||
|
|
||||||
if ( tests ) {
|
|
||||||
tests.innerHTML = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( banner ) {
|
|
||||||
banner.className = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( result ) {
|
|
||||||
result.parentNode.removeChild( result );
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// call on start of module test to prepend name to all tests
|
|
||||||
module: function module(name, testEnvironment) {
|
|
||||||
|
|
||||||
synchronize(function() {
|
|
||||||
if ( config.currentModule ) {
|
|
||||||
QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );
|
|
||||||
}
|
|
||||||
|
|
||||||
config.currentModule = name;
|
|
||||||
config.moduleTestEnvironment = testEnvironment;
|
|
||||||
config.moduleStats = { all: 0, bad: 0 };
|
|
||||||
|
|
||||||
QUnit.moduleStart( name, testEnvironment );
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
asyncTest: function asyncTest(testName, expected, callback) {
|
|
||||||
if ( arguments.length === 2 ) {
|
|
||||||
callback = expected;
|
|
||||||
expected = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QUnit.test(testName, expected, callback, true);
|
|
||||||
},
|
|
||||||
|
|
||||||
test: function test(testName, expected, callback, async) {
|
|
||||||
var name = testName, testEnvironment = {};
|
|
||||||
|
|
||||||
if ( arguments.length === 2 ) {
|
|
||||||
callback = expected;
|
|
||||||
expected = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( config.currentModule ) {
|
|
||||||
name = config.currentModule + " module: " + name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !validTest(name) ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
synchronize(function() {
|
|
||||||
QUnit.testStart( testName );
|
|
||||||
|
|
||||||
testEnvironment = extend({
|
|
||||||
setup: function() {},
|
|
||||||
teardown: function() {}
|
|
||||||
}, config.moduleTestEnvironment);
|
|
||||||
|
|
||||||
config.assertions = [];
|
|
||||||
config.expected = null;
|
|
||||||
|
|
||||||
if ( arguments.length >= 3 ) {
|
|
||||||
config.expected = callback;
|
|
||||||
callback = arguments[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if ( !config.pollution ) {
|
|
||||||
saveGlobal();
|
|
||||||
}
|
|
||||||
|
|
||||||
testEnvironment.setup.call(testEnvironment);
|
|
||||||
} catch(e) {
|
|
||||||
QUnit.ok( false, "Setup failed on " + name + ": " + e.message );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( async ) {
|
|
||||||
QUnit.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
callback.call(testEnvironment);
|
|
||||||
} catch(e) {
|
|
||||||
fail("Test " + name + " died, exception and test follows", e, callback);
|
|
||||||
QUnit.ok( false, "Died on test #" + (config.assertions.length + 1) + ": " + e.message );
|
|
||||||
// else next test will carry the responsibility
|
|
||||||
saveGlobal();
|
|
||||||
|
|
||||||
// Restart the tests if they're blocking
|
|
||||||
if ( config.blocking ) {
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
synchronize(function() {
|
|
||||||
try {
|
|
||||||
checkPollution();
|
|
||||||
testEnvironment.teardown.call(testEnvironment);
|
|
||||||
} catch(e) {
|
|
||||||
QUnit.ok( false, "Teardown failed on " + name + ": " + e.message );
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
QUnit.reset();
|
|
||||||
} catch(e) {
|
|
||||||
fail("reset() failed, following Test " + name + ", exception and reset fn follows", e, reset);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( config.expected && config.expected != config.assertions.length ) {
|
|
||||||
QUnit.ok( false, "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" );
|
|
||||||
}
|
|
||||||
|
|
||||||
var good = 0, bad = 0,
|
|
||||||
tests = id("qunit-tests");
|
|
||||||
|
|
||||||
config.stats.all += config.assertions.length;
|
|
||||||
config.moduleStats.all += config.assertions.length;
|
|
||||||
|
|
||||||
if ( tests ) {
|
|
||||||
var ol = document.createElement("ol");
|
|
||||||
ol.style.display = "none";
|
|
||||||
|
|
||||||
for ( var i = 0; i < config.assertions.length; i++ ) {
|
|
||||||
var assertion = config.assertions[i];
|
|
||||||
|
|
||||||
var li = document.createElement("li");
|
|
||||||
li.className = assertion.result ? "pass" : "fail";
|
|
||||||
li.innerHTML = assertion.message || "(no message)";
|
|
||||||
ol.appendChild( li );
|
|
||||||
|
|
||||||
if ( assertion.result ) {
|
|
||||||
good++;
|
|
||||||
} else {
|
|
||||||
bad++;
|
|
||||||
config.stats.bad++;
|
|
||||||
config.moduleStats.bad++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var b = document.createElement("strong");
|
|
||||||
b.innerHTML = name + " <b style='color:black;'>(<b class='fail'>" + bad + "</b>, <b class='pass'>" + good + "</b>, " + config.assertions.length + ")</b>";
|
|
||||||
|
|
||||||
addEvent(b, "click", function() {
|
|
||||||
var next = b.nextSibling, display = next.style.display;
|
|
||||||
next.style.display = display === "none" ? "block" : "none";
|
|
||||||
});
|
|
||||||
|
|
||||||
addEvent(b, "dblclick", function(e) {
|
|
||||||
var target = (e || window.event).target;
|
|
||||||
if ( target.nodeName.toLowerCase() === "strong" ) {
|
|
||||||
var text = "", node = target.firstChild;
|
|
||||||
|
|
||||||
while ( node.nodeType === 3 ) {
|
|
||||||
text += node.nodeValue;
|
|
||||||
node = node.nextSibling;
|
|
||||||
}
|
|
||||||
|
|
||||||
text = text.replace(/(^\s*|\s*$)/g, "");
|
|
||||||
|
|
||||||
if ( window.location ) {
|
|
||||||
window.location.href = window.location.href.match(/^(.+?)(\?.*)?$/)[1] + "?" + encodeURIComponent(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var li = document.createElement("li");
|
|
||||||
li.className = bad ? "fail" : "pass";
|
|
||||||
li.appendChild( b );
|
|
||||||
li.appendChild( ol );
|
|
||||||
tests.appendChild( li );
|
|
||||||
|
|
||||||
if ( bad ) {
|
|
||||||
var toolbar = id("qunit-testrunner-toolbar");
|
|
||||||
if ( toolbar ) {
|
|
||||||
toolbar.style.display = "block";
|
|
||||||
id("qunit-filter-pass").disabled = null;
|
|
||||||
id("qunit-filter-missing").disabled = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
for ( var i = 0; i < config.assertions.length; i++ ) {
|
|
||||||
if ( !config.assertions[i].result ) {
|
|
||||||
bad++;
|
|
||||||
config.stats.bad++;
|
|
||||||
config.moduleStats.bad++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QUnit.testDone( testName, bad, config.assertions.length );
|
|
||||||
|
|
||||||
if ( !window.setTimeout && !config.queue.length ) {
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if ( window.setTimeout && !config.doneTimer ) {
|
|
||||||
config.doneTimer = window.setTimeout(function(){
|
|
||||||
if ( !config.queue.length ) {
|
|
||||||
done();
|
|
||||||
} else {
|
|
||||||
synchronize( done );
|
|
||||||
}
|
|
||||||
}, 13);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through.
|
|
||||||
*/
|
|
||||||
expect: function expect(asserts) {
|
|
||||||
config.expected = asserts;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asserts true.
|
|
||||||
* @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
|
|
||||||
*/
|
|
||||||
ok: function ok(a, msg) {
|
|
||||||
QUnit.log(a, msg);
|
|
||||||
|
|
||||||
config.assertions.push({
|
|
||||||
result: !!a,
|
|
||||||
message: msg
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks that the first two arguments are equal, with an optional message.
|
|
||||||
* Prints out both actual and expected values.
|
|
||||||
*
|
|
||||||
* Prefered to ok( actual == expected, message )
|
|
||||||
*
|
|
||||||
* @example equals( format("Received {0} bytes.", 2), "Received 2 bytes." );
|
|
||||||
*
|
|
||||||
* @param Object actual
|
|
||||||
* @param Object expected
|
|
||||||
* @param String message (optional)
|
|
||||||
*/
|
|
||||||
equals: function equals(actual, expected, message) {
|
|
||||||
push(expected == actual, actual, expected, message);
|
|
||||||
},
|
|
||||||
|
|
||||||
same: function(a, b, message) {
|
|
||||||
push(QUnit.equiv(a, b), a, b, message);
|
|
||||||
},
|
|
||||||
|
|
||||||
start: function start() {
|
|
||||||
// A slight delay, to avoid any current callbacks
|
|
||||||
if ( window.setTimeout ) {
|
|
||||||
window.setTimeout(function() {
|
|
||||||
if ( config.timeout ) {
|
|
||||||
clearTimeout(config.timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
config.blocking = false;
|
|
||||||
process();
|
|
||||||
}, 13);
|
|
||||||
} else {
|
|
||||||
config.blocking = false;
|
|
||||||
process();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
stop: function stop(timeout) {
|
|
||||||
config.blocking = true;
|
|
||||||
|
|
||||||
if ( timeout && window.setTimeout ) {
|
|
||||||
config.timeout = window.setTimeout(function() {
|
|
||||||
QUnit.ok( false, "Test timed out" );
|
|
||||||
QUnit.start();
|
|
||||||
}, timeout);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the test setup. Useful for tests that modify the DOM.
|
|
||||||
*/
|
|
||||||
reset: function reset() {
|
|
||||||
if ( window.jQuery ) {
|
|
||||||
jQuery("#main").html( config.fixture );
|
|
||||||
jQuery.event.global = {};
|
|
||||||
jQuery.ajaxSettings = extend({}, config.ajaxSettings);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger an event on an element.
|
|
||||||
*
|
|
||||||
* @example triggerEvent( document.body, "click" );
|
|
||||||
*
|
|
||||||
* @param DOMElement elem
|
|
||||||
* @param String type
|
|
||||||
*/
|
|
||||||
triggerEvent: function triggerEvent( elem, type, event ) {
|
|
||||||
if ( document.createEvent ) {
|
|
||||||
event = document.createEvent("MouseEvents");
|
|
||||||
event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView,
|
|
||||||
0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
|
||||||
elem.dispatchEvent( event );
|
|
||||||
|
|
||||||
} else if ( elem.fireEvent ) {
|
|
||||||
elem.fireEvent("on"+type);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Logging callbacks
|
|
||||||
done: function done(failures, total) {},
|
|
||||||
log: function log(result, message) {},
|
|
||||||
testStart: function testStart(name) {},
|
|
||||||
testDone: function testDone(name, failures, total) {},
|
|
||||||
moduleStart: function moduleStart(name, testEnvironment) {},
|
|
||||||
moduleDone: function moduleDone(name, failures, total) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Maintain internal state
|
|
||||||
var config = {
|
|
||||||
// The queue of tests to run
|
|
||||||
queue: [],
|
|
||||||
|
|
||||||
// block until document ready
|
|
||||||
blocking: true
|
|
||||||
};
|
|
||||||
|
|
||||||
// Load paramaters
|
|
||||||
(function() {
|
|
||||||
var location = window.location || { search: "", protocol: "file:" },
|
|
||||||
GETParams = location.search.slice(1).split('&');
|
|
||||||
|
|
||||||
for ( var i = 0; i < GETParams.length; i++ ) {
|
|
||||||
GETParams[i] = decodeURIComponent( GETParams[i] );
|
|
||||||
if ( GETParams[i] === "noglobals" ) {
|
|
||||||
GETParams.splice( i, 1 );
|
|
||||||
i--;
|
|
||||||
config.noglobals = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// restrict modules/tests by get parameters
|
|
||||||
config.filters = GETParams;
|
|
||||||
|
|
||||||
// Figure out if we're running the tests from a server or not
|
|
||||||
QUnit.isLocal = !!(location.protocol === 'file:');
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Expose the API as global variables, unless an 'exports'
|
|
||||||
// object exists, in that case we assume we're in CommonJS
|
|
||||||
if ( typeof exports === "undefined" || typeof require === "undefined" ) {
|
|
||||||
extend(window, QUnit);
|
|
||||||
window.QUnit = QUnit;
|
|
||||||
} else {
|
|
||||||
extend(exports, QUnit);
|
|
||||||
exports.QUnit = QUnit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( typeof document === "undefined" || document.readyState === "complete" ) {
|
|
||||||
config.autorun = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
addEvent(window, "load", function() {
|
|
||||||
// Initialize the config, saving the execution queue
|
|
||||||
var oldconfig = extend({}, config);
|
|
||||||
QUnit.init();
|
|
||||||
extend(config, oldconfig);
|
|
||||||
|
|
||||||
config.blocking = false;
|
|
||||||
|
|
||||||
var userAgent = id("qunit-userAgent");
|
|
||||||
if ( userAgent ) {
|
|
||||||
userAgent.innerHTML = navigator.userAgent;
|
|
||||||
}
|
|
||||||
|
|
||||||
var toolbar = id("qunit-testrunner-toolbar");
|
|
||||||
if ( toolbar ) {
|
|
||||||
toolbar.style.display = "none";
|
|
||||||
|
|
||||||
var filter = document.createElement("input");
|
|
||||||
filter.type = "checkbox";
|
|
||||||
filter.id = "qunit-filter-pass";
|
|
||||||
filter.disabled = true;
|
|
||||||
addEvent( filter, "click", function() {
|
|
||||||
var li = document.getElementsByTagName("li");
|
|
||||||
for ( var i = 0; i < li.length; i++ ) {
|
|
||||||
if ( li[i].className.indexOf("pass") > -1 ) {
|
|
||||||
li[i].style.display = filter.checked ? "none" : "block";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
toolbar.appendChild( filter );
|
|
||||||
|
|
||||||
var label = document.createElement("label");
|
|
||||||
label.setAttribute("for", "filter-pass");
|
|
||||||
label.innerHTML = "Hide passed tests";
|
|
||||||
toolbar.appendChild( label );
|
|
||||||
|
|
||||||
var missing = document.createElement("input");
|
|
||||||
missing.type = "checkbox";
|
|
||||||
missing.id = "qunit-filter-missing";
|
|
||||||
missing.disabled = true;
|
|
||||||
addEvent( missing, "click", function() {
|
|
||||||
var li = document.getElementsByTagName("li");
|
|
||||||
for ( var i = 0; i < li.length; i++ ) {
|
|
||||||
if ( li[i].className.indexOf("fail") > -1 && li[i].innerHTML.indexOf('missing test - untested code is broken code') > - 1 ) {
|
|
||||||
li[i].parentNode.parentNode.style.display = missing.checked ? "none" : "block";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
toolbar.appendChild( missing );
|
|
||||||
|
|
||||||
label = document.createElement("label");
|
|
||||||
label.setAttribute("for", "filter-missing");
|
|
||||||
label.innerHTML = "Hide missing tests (untested code is broken code)";
|
|
||||||
toolbar.appendChild( label );
|
|
||||||
}
|
|
||||||
|
|
||||||
var main = id('main');
|
|
||||||
if ( main ) {
|
|
||||||
config.fixture = main.innerHTML;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( window.jQuery ) {
|
|
||||||
config.ajaxSettings = window.jQuery.ajaxSettings;
|
|
||||||
}
|
|
||||||
|
|
||||||
QUnit.start();
|
|
||||||
});
|
|
||||||
|
|
||||||
function done() {
|
|
||||||
if ( config.doneTimer && window.clearTimeout ) {
|
|
||||||
window.clearTimeout( config.doneTimer );
|
|
||||||
config.doneTimer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( config.queue.length ) {
|
|
||||||
config.doneTimer = window.setTimeout(function(){
|
|
||||||
if ( !config.queue.length ) {
|
|
||||||
done();
|
|
||||||
} else {
|
|
||||||
synchronize( done );
|
|
||||||
}
|
|
||||||
}, 13);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
config.autorun = true;
|
|
||||||
|
|
||||||
// Log the last module results
|
|
||||||
if ( config.currentModule ) {
|
|
||||||
QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all );
|
|
||||||
}
|
|
||||||
|
|
||||||
var banner = id("qunit-banner"),
|
|
||||||
tests = id("qunit-tests"),
|
|
||||||
html = ['Tests completed in ',
|
|
||||||
+new Date - config.started, ' milliseconds.<br/>',
|
|
||||||
'<span class="bad">', config.stats.all - config.stats.bad, '</span> tests of <span class="all">', config.stats.all, '</span> passed, ', config.stats.bad,' failed.'].join('');
|
|
||||||
|
|
||||||
if ( banner ) {
|
|
||||||
banner.className += " " + (config.stats.bad ? "fail" : "pass");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( tests ) {
|
|
||||||
var result = id("qunit-testresult");
|
|
||||||
|
|
||||||
if ( !result ) {
|
|
||||||
result = document.createElement("p");
|
|
||||||
result.id = "qunit-testresult";
|
|
||||||
result.className = "result";
|
|
||||||
tests.parentNode.insertBefore( result, tests.nextSibling );
|
|
||||||
}
|
|
||||||
|
|
||||||
result.innerHTML = html;
|
|
||||||
}
|
|
||||||
|
|
||||||
QUnit.done( config.stats.bad, config.stats.all );
|
|
||||||
}
|
|
||||||
|
|
||||||
function validTest( name ) {
|
|
||||||
var i = config.filters.length,
|
|
||||||
run = false;
|
|
||||||
|
|
||||||
if ( !i ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ( i-- ) {
|
|
||||||
var filter = config.filters[i],
|
|
||||||
not = filter.charAt(0) == '!';
|
|
||||||
|
|
||||||
if ( not ) {
|
|
||||||
filter = filter.slice(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( name.indexOf(filter) !== -1 ) {
|
|
||||||
return !not;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( not ) {
|
|
||||||
run = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return run;
|
|
||||||
}
|
|
||||||
|
|
||||||
function push(result, actual, expected, message) {
|
|
||||||
message = message || (result ? "okay" : "failed");
|
|
||||||
QUnit.ok( result, result ? message + ": " + expected : message + ", expected: " + QUnit.jsDump.parse(expected) + " result: " + QUnit.jsDump.parse(actual) );
|
|
||||||
}
|
|
||||||
|
|
||||||
function synchronize( callback ) {
|
|
||||||
config.queue.push( callback );
|
|
||||||
|
|
||||||
if ( config.autorun && !config.blocking ) {
|
|
||||||
process();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function process() {
|
|
||||||
while ( config.queue.length && !config.blocking ) {
|
|
||||||
config.queue.shift()();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveGlobal() {
|
|
||||||
config.pollution = [];
|
|
||||||
|
|
||||||
if ( config.noglobals ) {
|
|
||||||
for ( var key in window ) {
|
|
||||||
config.pollution.push( key );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkPollution( name ) {
|
|
||||||
var old = config.pollution;
|
|
||||||
saveGlobal();
|
|
||||||
|
|
||||||
var newGlobals = diff( old, config.pollution );
|
|
||||||
if ( newGlobals.length > 0 ) {
|
|
||||||
ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
|
|
||||||
config.expected++;
|
|
||||||
}
|
|
||||||
|
|
||||||
var deletedGlobals = diff( config.pollution, old );
|
|
||||||
if ( deletedGlobals.length > 0 ) {
|
|
||||||
ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
|
|
||||||
config.expected++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns a new Array with the elements that are in a but not in b
|
|
||||||
function diff( a, b ) {
|
|
||||||
var result = a.slice();
|
|
||||||
for ( var i = 0; i < result.length; i++ ) {
|
|
||||||
for ( var j = 0; j < b.length; j++ ) {
|
|
||||||
if ( result[i] === b[j] ) {
|
|
||||||
result.splice(i, 1);
|
|
||||||
i--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fail(message, exception, callback) {
|
|
||||||
if ( typeof console !== "undefined" && console.error && console.warn ) {
|
|
||||||
console.error(message);
|
|
||||||
console.error(exception);
|
|
||||||
console.warn(callback.toString());
|
|
||||||
|
|
||||||
} else if ( window.opera && opera.postError ) {
|
|
||||||
opera.postError(message, exception, callback.toString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function extend(a, b) {
|
|
||||||
for ( var prop in b ) {
|
|
||||||
a[prop] = b[prop];
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
function addEvent(elem, type, fn) {
|
|
||||||
if ( elem.addEventListener ) {
|
|
||||||
elem.addEventListener( type, fn, false );
|
|
||||||
} else if ( elem.attachEvent ) {
|
|
||||||
elem.attachEvent( "on" + type, fn );
|
|
||||||
} else {
|
|
||||||
fn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function id(name) {
|
|
||||||
return !!(typeof document !== "undefined" && document && document.getElementById) &&
|
|
||||||
document.getElementById( name );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test for equality any JavaScript type.
|
|
||||||
// Discussions and reference: http://philrathe.com/articles/equiv
|
|
||||||
// Test suites: http://philrathe.com/tests/equiv
|
|
||||||
// Author: Philippe Rathé <prathe@gmail.com>
|
|
||||||
QUnit.equiv = function () {
|
|
||||||
|
|
||||||
var innerEquiv; // the real equiv function
|
|
||||||
var callers = []; // stack to decide between skip/abort functions
|
|
||||||
|
|
||||||
|
|
||||||
// Determine what is o.
|
|
||||||
function hoozit(o) {
|
|
||||||
if (o.constructor === String) {
|
|
||||||
return "string";
|
|
||||||
|
|
||||||
} else if (o.constructor === Boolean) {
|
|
||||||
return "boolean";
|
|
||||||
|
|
||||||
} else if (o.constructor === Number) {
|
|
||||||
|
|
||||||
if (isNaN(o)) {
|
|
||||||
return "nan";
|
|
||||||
} else {
|
|
||||||
return "number";
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (typeof o === "undefined") {
|
|
||||||
return "undefined";
|
|
||||||
|
|
||||||
// consider: typeof null === object
|
|
||||||
} else if (o === null) {
|
|
||||||
return "null";
|
|
||||||
|
|
||||||
// consider: typeof [] === object
|
|
||||||
} else if (o instanceof Array) {
|
|
||||||
return "array";
|
|
||||||
|
|
||||||
// consider: typeof new Date() === object
|
|
||||||
} else if (o instanceof Date) {
|
|
||||||
return "date";
|
|
||||||
|
|
||||||
// consider: /./ instanceof Object;
|
|
||||||
// /./ instanceof RegExp;
|
|
||||||
// typeof /./ === "function"; // => false in IE and Opera,
|
|
||||||
// true in FF and Safari
|
|
||||||
} else if (o instanceof RegExp) {
|
|
||||||
return "regexp";
|
|
||||||
|
|
||||||
} else if (typeof o === "object") {
|
|
||||||
return "object";
|
|
||||||
|
|
||||||
} else if (o instanceof Function) {
|
|
||||||
return "function";
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call the o related callback with the given arguments.
|
|
||||||
function bindCallbacks(o, callbacks, args) {
|
|
||||||
var prop = hoozit(o);
|
|
||||||
if (prop) {
|
|
||||||
if (hoozit(callbacks[prop]) === "function") {
|
|
||||||
return callbacks[prop].apply(callbacks, args);
|
|
||||||
} else {
|
|
||||||
return callbacks[prop]; // or undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var callbacks = function () {
|
|
||||||
|
|
||||||
// for string, boolean, number and null
|
|
||||||
function useStrictEquality(b, a) {
|
|
||||||
if (b instanceof a.constructor || a instanceof b.constructor) {
|
|
||||||
// to catch short annotaion VS 'new' annotation of a declaration
|
|
||||||
// e.g. var i = 1;
|
|
||||||
// var j = new Number(1);
|
|
||||||
return a == b;
|
|
||||||
} else {
|
|
||||||
return a === b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
"string": useStrictEquality,
|
|
||||||
"boolean": useStrictEquality,
|
|
||||||
"number": useStrictEquality,
|
|
||||||
"null": useStrictEquality,
|
|
||||||
"undefined": useStrictEquality,
|
|
||||||
|
|
||||||
"nan": function (b) {
|
|
||||||
return isNaN(b);
|
|
||||||
},
|
|
||||||
|
|
||||||
"date": function (b, a) {
|
|
||||||
return hoozit(b) === "date" && a.valueOf() === b.valueOf();
|
|
||||||
},
|
|
||||||
|
|
||||||
"regexp": function (b, a) {
|
|
||||||
return hoozit(b) === "regexp" &&
|
|
||||||
a.source === b.source && // the regex itself
|
|
||||||
a.global === b.global && // and its modifers (gmi) ...
|
|
||||||
a.ignoreCase === b.ignoreCase &&
|
|
||||||
a.multiline === b.multiline;
|
|
||||||
},
|
|
||||||
|
|
||||||
// - skip when the property is a method of an instance (OOP)
|
|
||||||
// - abort otherwise,
|
|
||||||
// initial === would have catch identical references anyway
|
|
||||||
"function": function () {
|
|
||||||
var caller = callers[callers.length - 1];
|
|
||||||
return caller !== Object &&
|
|
||||||
typeof caller !== "undefined";
|
|
||||||
},
|
|
||||||
|
|
||||||
"array": function (b, a) {
|
|
||||||
var i;
|
|
||||||
var len;
|
|
||||||
|
|
||||||
// b could be an object literal here
|
|
||||||
if ( ! (hoozit(b) === "array")) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = a.length;
|
|
||||||
if (len !== b.length) { // safe and faster
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
if ( ! innerEquiv(a[i], b[i])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
"object": function (b, a) {
|
|
||||||
var i;
|
|
||||||
var eq = true; // unless we can proove it
|
|
||||||
var aProperties = [], bProperties = []; // collection of strings
|
|
||||||
|
|
||||||
// comparing constructors is more strict than using instanceof
|
|
||||||
if ( a.constructor !== b.constructor) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// stack constructor before traversing properties
|
|
||||||
callers.push(a.constructor);
|
|
||||||
|
|
||||||
for (i in a) { // be strict: don't ensures hasOwnProperty and go deep
|
|
||||||
|
|
||||||
aProperties.push(i); // collect a's properties
|
|
||||||
|
|
||||||
if ( ! innerEquiv(a[i], b[i])) {
|
|
||||||
eq = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
callers.pop(); // unstack, we are done
|
|
||||||
|
|
||||||
for (i in b) {
|
|
||||||
bProperties.push(i); // collect b's properties
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensures identical properties name
|
|
||||||
return eq && innerEquiv(aProperties.sort(), bProperties.sort());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}();
|
|
||||||
|
|
||||||
innerEquiv = function () { // can take multiple arguments
|
|
||||||
var args = Array.prototype.slice.apply(arguments);
|
|
||||||
if (args.length < 2) {
|
|
||||||
return true; // end transition
|
|
||||||
}
|
|
||||||
|
|
||||||
return (function (a, b) {
|
|
||||||
if (a === b) {
|
|
||||||
return true; // catch the most you can
|
|
||||||
} else if (a === null || b === null || typeof a === "undefined" || typeof b === "undefined" || hoozit(a) !== hoozit(b)) {
|
|
||||||
return false; // don't lose time with error prone cases
|
|
||||||
} else {
|
|
||||||
return bindCallbacks(a, callbacks, [b, a]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// apply transition with (1..n) arguments
|
|
||||||
})(args[0], args[1]) && arguments.callee.apply(this, args.splice(1, args.length -1));
|
|
||||||
};
|
|
||||||
|
|
||||||
return innerEquiv;
|
|
||||||
|
|
||||||
}();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* jsDump
|
|
||||||
* Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
|
|
||||||
* Licensed under BSD (http://www.opensource.org/licenses/bsd-license.php)
|
|
||||||
* Date: 5/15/2008
|
|
||||||
* @projectDescription Advanced and extensible data dumping for Javascript.
|
|
||||||
* @version 1.0.0
|
|
||||||
* @author Ariel Flesler
|
|
||||||
* @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
|
|
||||||
*/
|
|
||||||
QUnit.jsDump = (function() {
|
|
||||||
function quote( str ) {
|
|
||||||
return '"' + str.toString().replace(/"/g, '\\"') + '"';
|
|
||||||
};
|
|
||||||
function literal( o ) {
|
|
||||||
return o + '';
|
|
||||||
};
|
|
||||||
function join( pre, arr, post ) {
|
|
||||||
var s = jsDump.separator(),
|
|
||||||
base = jsDump.indent(),
|
|
||||||
inner = jsDump.indent(1);
|
|
||||||
if ( arr.join )
|
|
||||||
arr = arr.join( ',' + s + inner );
|
|
||||||
if ( !arr )
|
|
||||||
return pre + post;
|
|
||||||
return [ pre, inner + arr, base + post ].join(s);
|
|
||||||
};
|
|
||||||
function array( arr ) {
|
|
||||||
var i = arr.length, ret = Array(i);
|
|
||||||
this.up();
|
|
||||||
while ( i-- )
|
|
||||||
ret[i] = this.parse( arr[i] );
|
|
||||||
this.down();
|
|
||||||
return join( '[', ret, ']' );
|
|
||||||
};
|
|
||||||
|
|
||||||
var reName = /^function (\w+)/;
|
|
||||||
|
|
||||||
var jsDump = {
|
|
||||||
parse:function( obj, type ) { //type is used mostly internally, you can fix a (custom)type in advance
|
|
||||||
var parser = this.parsers[ type || this.typeOf(obj) ];
|
|
||||||
type = typeof parser;
|
|
||||||
|
|
||||||
return type == 'function' ? parser.call( this, obj ) :
|
|
||||||
type == 'string' ? parser :
|
|
||||||
this.parsers.error;
|
|
||||||
},
|
|
||||||
typeOf:function( obj ) {
|
|
||||||
var type = typeof obj,
|
|
||||||
f = 'function';//we'll use it 3 times, save it
|
|
||||||
return type != 'object' && type != f ? type :
|
|
||||||
!obj ? 'null' :
|
|
||||||
obj.exec ? 'regexp' :// some browsers (FF) consider regexps functions
|
|
||||||
obj.getHours ? 'date' :
|
|
||||||
obj.scrollBy ? 'window' :
|
|
||||||
obj.nodeName == '#document' ? 'document' :
|
|
||||||
obj.nodeName ? 'node' :
|
|
||||||
obj.item ? 'nodelist' : // Safari reports nodelists as functions
|
|
||||||
obj.callee ? 'arguments' :
|
|
||||||
obj.call || obj.constructor != Array && //an array would also fall on this hack
|
|
||||||
(obj+'').indexOf(f) != -1 ? f : //IE reports functions like alert, as objects
|
|
||||||
'length' in obj ? 'array' :
|
|
||||||
type;
|
|
||||||
},
|
|
||||||
separator:function() {
|
|
||||||
return this.multiline ? this.HTML ? '<br />' : '\n' : this.HTML ? ' ' : ' ';
|
|
||||||
},
|
|
||||||
indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
|
|
||||||
if ( !this.multiline )
|
|
||||||
return '';
|
|
||||||
var chr = this.indentChar;
|
|
||||||
if ( this.HTML )
|
|
||||||
chr = chr.replace(/\t/g,' ').replace(/ /g,' ');
|
|
||||||
return Array( this._depth_ + (extra||0) ).join(chr);
|
|
||||||
},
|
|
||||||
up:function( a ) {
|
|
||||||
this._depth_ += a || 1;
|
|
||||||
},
|
|
||||||
down:function( a ) {
|
|
||||||
this._depth_ -= a || 1;
|
|
||||||
},
|
|
||||||
setParser:function( name, parser ) {
|
|
||||||
this.parsers[name] = parser;
|
|
||||||
},
|
|
||||||
// The next 3 are exposed so you can use them
|
|
||||||
quote:quote,
|
|
||||||
literal:literal,
|
|
||||||
join:join,
|
|
||||||
//
|
|
||||||
_depth_: 1,
|
|
||||||
// This is the list of parsers, to modify them, use jsDump.setParser
|
|
||||||
parsers:{
|
|
||||||
window: '[Window]',
|
|
||||||
document: '[Document]',
|
|
||||||
error:'[ERROR]', //when no parser is found, shouldn't happen
|
|
||||||
unknown: '[Unknown]',
|
|
||||||
'null':'null',
|
|
||||||
undefined:'undefined',
|
|
||||||
'function':function( fn ) {
|
|
||||||
var ret = 'function',
|
|
||||||
name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
|
|
||||||
if ( name )
|
|
||||||
ret += ' ' + name;
|
|
||||||
ret += '(';
|
|
||||||
|
|
||||||
ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join('');
|
|
||||||
return join( ret, this.parse(fn,'functionCode'), '}' );
|
|
||||||
},
|
|
||||||
array: array,
|
|
||||||
nodelist: array,
|
|
||||||
arguments: array,
|
|
||||||
object:function( map ) {
|
|
||||||
var ret = [ ];
|
|
||||||
this.up();
|
|
||||||
for ( var key in map )
|
|
||||||
ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) );
|
|
||||||
this.down();
|
|
||||||
return join( '{', ret, '}' );
|
|
||||||
},
|
|
||||||
node:function( node ) {
|
|
||||||
var open = this.HTML ? '<' : '<',
|
|
||||||
close = this.HTML ? '>' : '>';
|
|
||||||
|
|
||||||
var tag = node.nodeName.toLowerCase(),
|
|
||||||
ret = open + tag;
|
|
||||||
|
|
||||||
for ( var a in this.DOMAttrs ) {
|
|
||||||
var val = node[this.DOMAttrs[a]];
|
|
||||||
if ( val )
|
|
||||||
ret += ' ' + a + '=' + this.parse( val, 'attribute' );
|
|
||||||
}
|
|
||||||
return ret + close + open + '/' + tag + close;
|
|
||||||
},
|
|
||||||
functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
|
|
||||||
var l = fn.length;
|
|
||||||
if ( !l ) return '';
|
|
||||||
|
|
||||||
var args = Array(l);
|
|
||||||
while ( l-- )
|
|
||||||
args[l] = String.fromCharCode(97+l);//97 is 'a'
|
|
||||||
return ' ' + args.join(', ') + ' ';
|
|
||||||
},
|
|
||||||
key:quote, //object calls it internally, the key part of an item in a map
|
|
||||||
functionCode:'[code]', //function calls it internally, it's the content of the function
|
|
||||||
attribute:quote, //node calls it internally, it's an html attribute value
|
|
||||||
string:quote,
|
|
||||||
date:quote,
|
|
||||||
regexp:literal, //regex
|
|
||||||
number:literal,
|
|
||||||
'boolean':literal
|
|
||||||
},
|
|
||||||
DOMAttrs:{//attributes to dump from nodes, name=>realName
|
|
||||||
id:'id',
|
|
||||||
name:'name',
|
|
||||||
'class':'className'
|
|
||||||
},
|
|
||||||
HTML:true,//if true, entities are escaped ( <, >, \t, space and \n )
|
|
||||||
indentChar:' ',//indentation unit
|
|
||||||
multiline:true //if true, items in a collection, are separated by a \n, else just a space.
|
|
||||||
};
|
|
||||||
|
|
||||||
return jsDump;
|
|
||||||
})();
|
|
||||||
|
|
||||||
})(this);
|
|
@ -19,8 +19,6 @@ from plone.app.discussion.testing import (
|
|||||||
|
|
||||||
from plone.app.discussion.interfaces import IConversation
|
from plone.app.discussion.interfaces import IConversation
|
||||||
|
|
||||||
from plone.app.discussion.testing import COLLECTION_TYPE
|
|
||||||
|
|
||||||
|
|
||||||
class CatalogSetupTest(unittest.TestCase):
|
class CatalogSetupTest(unittest.TestCase):
|
||||||
|
|
||||||
@ -48,6 +46,8 @@ class CatalogSetupTest(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_collection_criteria_installed(self):
|
def test_collection_criteria_installed(self):
|
||||||
|
if 'portal_atct' not in self.portal:
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
self.portal.portal_atct.getIndex('commentators')
|
self.portal.portal_atct.getIndex('commentators')
|
||||||
self.portal.portal_atct.getIndex('total_comments')
|
self.portal.portal_atct.getIndex('total_comments')
|
||||||
@ -459,6 +459,9 @@ class CommentCatalogTest(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_clear_and_rebuild_catalog(self):
|
def test_clear_and_rebuild_catalog(self):
|
||||||
|
brains = self.catalog.searchResults({'portal_type': 'Discussion Item'})
|
||||||
|
self.assertTrue(brains)
|
||||||
|
|
||||||
# Clear and rebuild catalog
|
# Clear and rebuild catalog
|
||||||
self.catalog.clearFindAndRebuild()
|
self.catalog.clearFindAndRebuild()
|
||||||
|
|
||||||
@ -529,31 +532,6 @@ class CommentCatalogTest(unittest.TestCase):
|
|||||||
self.assertTrue(brains)
|
self.assertTrue(brains)
|
||||||
self.assertEqual(len(brains), 6)
|
self.assertEqual(len(brains), 6)
|
||||||
|
|
||||||
def test_collection(self):
|
|
||||||
if COLLECTION_TYPE == "Topic":
|
|
||||||
self.portal.invokeFactory('Topic', id='topic')
|
|
||||||
topic = self.portal.topic
|
|
||||||
crit = topic.addCriterion('Type', 'ATSimpleStringCriterion')
|
|
||||||
crit.setValue('Comment')
|
|
||||||
query = topic.buildQuery()
|
|
||||||
|
|
||||||
self.assertEqual(len(query), 1)
|
|
||||||
self.assertEqual(query['Type'], 'Comment')
|
|
||||||
self.assertEqual(len(topic.queryCatalog()), 1)
|
|
||||||
else:
|
|
||||||
self.portal.invokeFactory('Collection', id='collection')
|
|
||||||
collection = self.portal.collection
|
|
||||||
collection.query = [{
|
|
||||||
'i': 'Type',
|
|
||||||
'o': 'plone.app.querystring.operation.string.is',
|
|
||||||
'v': 'Comment',
|
|
||||||
}]
|
|
||||||
|
|
||||||
self.assertEqual(collection.results().length, 1)
|
|
||||||
self.assertEqual(collection.results()[0].text, 'Comment text')
|
|
||||||
self.assertEqual(collection.results()[0].creator, 'jim')
|
|
||||||
self.assertEqual(collection.results()[0].author_name, 'Jim')
|
|
||||||
|
|
||||||
|
|
||||||
class NoConversationCatalogTest(unittest.TestCase):
|
class NoConversationCatalogTest(unittest.TestCase):
|
||||||
|
|
||||||
@ -591,6 +569,3 @@ class NoConversationCatalogTest(unittest.TestCase):
|
|||||||
IAnnotations(self.portal.doc1)
|
IAnnotations(self.portal.doc1)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
|
||||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
|
||||||
|
@ -509,6 +509,3 @@ class RepliesTest(unittest.TestCase):
|
|||||||
re_re_re_comment.absolute_url()
|
re_re_re_comment.absolute_url()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
|
||||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
|
||||||
|
@ -63,12 +63,7 @@ class TestCommentForm(unittest.TestCase):
|
|||||||
typetool.constructContent('Document', self.portal, 'doc1')
|
typetool.constructContent('Document', self.portal, 'doc1')
|
||||||
wftool = getToolByName(self.portal, "portal_workflow")
|
wftool = getToolByName(self.portal, "portal_workflow")
|
||||||
wftool.doActionFor(self.portal.doc1, action='publish')
|
wftool.doActionFor(self.portal.doc1, action='publish')
|
||||||
self.discussionTool = getToolByName(
|
self.portal.doc1.allow_discussion = True
|
||||||
self.portal,
|
|
||||||
'portal_discussion',
|
|
||||||
None
|
|
||||||
)
|
|
||||||
self.discussionTool.overrideDiscussionFor(self.portal.doc1, False)
|
|
||||||
self.membershipTool = getToolByName(self.folder, 'portal_membership')
|
self.membershipTool = getToolByName(self.folder, 'portal_membership')
|
||||||
self.memberdata = self.portal.portal_memberdata
|
self.memberdata = self.portal.portal_memberdata
|
||||||
self.context = getattr(self.portal, 'doc1')
|
self.context = getattr(self.portal, 'doc1')
|
||||||
@ -83,7 +78,7 @@ class TestCommentForm(unittest.TestCase):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Allow discussion
|
# Allow discussion
|
||||||
self.discussionTool.overrideDiscussionFor(self.portal.doc1, True)
|
self.portal.doc1.allow_discussion = True
|
||||||
self.viewlet = CommentsViewlet(self.context, self.request, None, None)
|
self.viewlet = CommentsViewlet(self.context, self.request, None, None)
|
||||||
|
|
||||||
def make_request(form={}):
|
def make_request(form={}):
|
||||||
@ -186,8 +181,23 @@ class TestCommentForm(unittest.TestCase):
|
|||||||
comment = [x for x in conversation.getComments()][-1]
|
comment = [x for x in conversation.getComments()][-1]
|
||||||
self.assertEquals(comment.text, u"foobar")
|
self.assertEquals(comment.text, u"foobar")
|
||||||
|
|
||||||
|
comments = IConversation(commentForm.context).getComments()
|
||||||
|
comments = [comment for comment in comments] # consume itertor
|
||||||
|
self.assertEqual(len(comments), 1)
|
||||||
|
|
||||||
|
for comment in comments:
|
||||||
|
self.assertEqual(comment.text, u"bar")
|
||||||
|
self.assertEqual(comment.creator, "test-user")
|
||||||
|
self.assertEqual(comment.getOwner().getUserName(), "test-user")
|
||||||
|
local_roles = comment.get_local_roles()
|
||||||
|
self.assertEqual(len(local_roles), 1)
|
||||||
|
userid, roles = local_roles[0]
|
||||||
|
self.assertEqual(userid, 'test-user')
|
||||||
|
self.assertEqual(len(roles), 1)
|
||||||
|
self.assertEqual(roles[0], 'Owner')
|
||||||
|
|
||||||
def test_add_anonymous_comment(self):
|
def test_add_anonymous_comment(self):
|
||||||
self.discussionTool.overrideDiscussionFor(self.portal.doc1, True)
|
self.portal.doc1.allow_discussion = True
|
||||||
|
|
||||||
self.viewlet = CommentsViewlet(self.context, self.request, None, None)
|
self.viewlet = CommentsViewlet(self.context, self.request, None, None)
|
||||||
|
|
||||||
@ -226,11 +236,24 @@ class TestCommentForm(unittest.TestCase):
|
|||||||
self.assertEqual(len(errors), 0)
|
self.assertEqual(len(errors), 0)
|
||||||
self.assertFalse(commentForm.handleComment(commentForm, "action"))
|
self.assertFalse(commentForm.handleComment(commentForm, "action"))
|
||||||
|
|
||||||
|
comments = IConversation(commentForm.context).getComments()
|
||||||
|
comments = [comment for comment in comments] # consume itertor
|
||||||
|
self.assertEqual(len(comments), 1)
|
||||||
|
|
||||||
|
for comment in IConversation(commentForm.context).getComments():
|
||||||
|
self.assertEqual(comment.text, u"bar")
|
||||||
|
self.assertIsNone(comment.creator)
|
||||||
|
roles = comment.get_local_roles()
|
||||||
|
self.assertEqual(len(roles), 0)
|
||||||
|
|
||||||
def test_can_not_add_comments_if_discussion_is_not_allowed(self):
|
def test_can_not_add_comments_if_discussion_is_not_allowed(self):
|
||||||
"""Make sure that comments can't be posted if discussion is disabled.
|
"""Make sure that comments can't be posted if discussion is disabled.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Discussion is disabled by default
|
# Disable discussion
|
||||||
|
registry = queryUtility(IRegistry)
|
||||||
|
settings = registry.forInterface(IDiscussionSettings)
|
||||||
|
settings.globally_enabled = False
|
||||||
|
|
||||||
def make_request(form={}):
|
def make_request(form={}):
|
||||||
request = TestRequest()
|
request = TestRequest()
|
||||||
@ -256,6 +279,7 @@ class TestCommentForm(unittest.TestCase):
|
|||||||
# No form errors, but raise unauthorized because discussion is not
|
# No form errors, but raise unauthorized because discussion is not
|
||||||
# allowed
|
# allowed
|
||||||
self.assertEqual(len(errors), 0)
|
self.assertEqual(len(errors), 0)
|
||||||
|
|
||||||
self.assertRaises(Unauthorized,
|
self.assertRaises(Unauthorized,
|
||||||
commentForm.handleComment,
|
commentForm.handleComment,
|
||||||
commentForm,
|
commentForm,
|
||||||
@ -318,11 +342,6 @@ class TestCommentsViewlet(unittest.TestCase):
|
|||||||
|
|
||||||
typetool = self.portal.portal_types
|
typetool = self.portal.portal_types
|
||||||
typetool.constructContent('Document', self.portal, 'doc1')
|
typetool.constructContent('Document', self.portal, 'doc1')
|
||||||
self.portal_discussion = getToolByName(
|
|
||||||
self.portal,
|
|
||||||
'portal_discussion',
|
|
||||||
None
|
|
||||||
)
|
|
||||||
self.membershipTool = getToolByName(self.folder, 'portal_membership')
|
self.membershipTool = getToolByName(self.folder, 'portal_membership')
|
||||||
self.memberdata = self.portal.portal_memberdata
|
self.memberdata = self.portal.portal_memberdata
|
||||||
context = getattr(self.portal, 'doc1')
|
context = getattr(self.portal, 'doc1')
|
||||||
@ -372,8 +391,7 @@ class TestCommentsViewlet(unittest.TestCase):
|
|||||||
# By default, discussion is disabled
|
# By default, discussion is disabled
|
||||||
self.assertFalse(self.viewlet.is_discussion_allowed())
|
self.assertFalse(self.viewlet.is_discussion_allowed())
|
||||||
# Enable discussion
|
# Enable discussion
|
||||||
portal_discussion = getToolByName(self.portal, 'portal_discussion')
|
self.portal.doc1.allow_discussion = True
|
||||||
portal_discussion.overrideDiscussionFor(self.portal.doc1, True)
|
|
||||||
# Test if discussion has been enabled
|
# Test if discussion has been enabled
|
||||||
self.assertTrue(self.viewlet.is_discussion_allowed())
|
self.assertTrue(self.viewlet.is_discussion_allowed())
|
||||||
|
|
||||||
@ -520,11 +538,11 @@ class TestCommentsViewlet(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_get_commenter_portrait_is_none(self):
|
def test_get_commenter_portrait_is_none(self):
|
||||||
self.assertTrue(
|
|
||||||
self.viewlet.get_commenter_portrait() in (
|
self.assertEqual(
|
||||||
'defaultUser.png',
|
self.viewlet.get_commenter_portrait(),
|
||||||
'defaultUser.gif',
|
'defaultUser.png'
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_get_commenter_portrait_without_userimage(self):
|
def test_get_commenter_portrait_without_userimage(self):
|
||||||
@ -604,6 +622,3 @@ class TestCommentsViewlet(unittest.TestCase):
|
|||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
localized_time in ['Feb 01, 2009 11:32 PM', '2009-02-01 23:32'])
|
localized_time in ['Feb 01, 2009 11:32 PM', '2009-02-01 23:32'])
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
|
||||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
|
||||||
|
@ -230,6 +230,3 @@ class ConfigurationChangedSubscriberTest(unittest.TestCase):
|
|||||||
# setting itself remains unchanged.
|
# setting itself remains unchanged.
|
||||||
self.settings.moderation_enabled = True
|
self.settings.moderation_enabled = True
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
|
||||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
|
||||||
|
@ -91,10 +91,10 @@ class ConversationTest(unittest.TestCase):
|
|||||||
comment.author_username = "nobody"
|
comment.author_username = "nobody"
|
||||||
conversation.addComment(comment)
|
conversation.addComment(comment)
|
||||||
comment.manage_permission("View", roles=tuple())
|
comment.manage_permission("View", roles=tuple())
|
||||||
self.assertEquals(0, conversation.total_comments)
|
self.assertEqual(0, conversation.total_comments)
|
||||||
self.assertEquals(None, conversation.last_comment_date)
|
self.assertEqual(None, conversation.last_comment_date)
|
||||||
self.assertEquals(["nobody"], list(conversation.commentators))
|
self.assertEqual(["nobody"], list(conversation.commentators))
|
||||||
self.assertEquals([], list(conversation.public_commentators))
|
self.assertEqual([], list(conversation.public_commentators))
|
||||||
|
|
||||||
def test_delete_comment(self):
|
def test_delete_comment(self):
|
||||||
# Create a conversation. In this case we doesn't assign it to an
|
# Create a conversation. In this case we doesn't assign it to an
|
||||||
@ -308,12 +308,12 @@ class ConversationTest(unittest.TestCase):
|
|||||||
|
|
||||||
# Create a folder
|
# Create a folder
|
||||||
self.typetool.constructContent('Folder', self.portal, 'f1')
|
self.typetool.constructContent('Folder', self.portal, 'f1')
|
||||||
f1 = self.portal.f1
|
|
||||||
# Usually we don't create a conversation on a folder
|
# Usually we don't create a conversation on a folder
|
||||||
conversation = self.portal.f1.restrictedTraverse('@@conversation_view')
|
conversation = self.portal.f1.restrictedTraverse('@@conversation_view')
|
||||||
|
|
||||||
# Allow discussion for the folder
|
# Allow discussion for the folder
|
||||||
self.portal_discussion.overrideDiscussionFor(f1, True)
|
self.portal.f1.allow_discussion = True
|
||||||
|
|
||||||
# Allow discussion on Folder content type
|
# Allow discussion on Folder content type
|
||||||
portal_types = getToolByName(self.portal, 'portal_types')
|
portal_types = getToolByName(self.portal, 'portal_types')
|
||||||
@ -334,12 +334,12 @@ class ConversationTest(unittest.TestCase):
|
|||||||
self.assertEqual(conversation.enabled(), False)
|
self.assertEqual(conversation.enabled(), False)
|
||||||
|
|
||||||
# Allow discussion on content object
|
# Allow discussion on content object
|
||||||
self.portal_discussion.overrideDiscussionFor(self.portal.doc1, True)
|
self.portal.doc1.allow_discussion = True
|
||||||
|
|
||||||
# Check if discussion is now allowed on the content object
|
# Check if discussion is now allowed on the content object
|
||||||
self.assertEqual(conversation.enabled(), True)
|
self.assertEqual(conversation.enabled(), True)
|
||||||
|
|
||||||
self.portal_discussion.overrideDiscussionFor(self.portal.doc1, False)
|
self.portal.doc1.allow_discussion = False
|
||||||
self.assertEqual(conversation.enabled(), False)
|
self.assertEqual(conversation.enabled(), False)
|
||||||
|
|
||||||
def test_dict_operations(self):
|
def test_dict_operations(self):
|
||||||
@ -874,6 +874,3 @@ class RepliesTest(unittest.TestCase):
|
|||||||
self.assertEqual(len(replies_to_comment1_1), 1)
|
self.assertEqual(len(replies_to_comment1_1), 1)
|
||||||
self.assertEqual(len(replies_to_comment2), 1)
|
self.assertEqual(len(replies_to_comment2), 1)
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
|
||||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
|
||||||
|
@ -204,6 +204,3 @@ class CommentIndexersTest(unittest.TestCase):
|
|||||||
# object the comment was added to
|
# object the comment was added to
|
||||||
self.assertEqual(catalog.in_response_to(self.comment)(), 'Document 1')
|
self.assertEqual(catalog.in_response_to(self.comment)(), 'Document 1')
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
|
||||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
|
||||||
|
@ -1,328 +0,0 @@
|
|||||||
from datetime import datetime
|
|
||||||
from DateTime import DateTime
|
|
||||||
|
|
||||||
import unittest2 as unittest
|
|
||||||
|
|
||||||
from zope.annotation.interfaces import IAnnotations
|
|
||||||
|
|
||||||
from Products.CMFCore.utils import getToolByName
|
|
||||||
|
|
||||||
from plone.app.testing import TEST_USER_ID, setRoles
|
|
||||||
|
|
||||||
from plone.app.discussion.testing import (
|
|
||||||
PLONE_APP_DISCUSSION_INTEGRATION_TESTING
|
|
||||||
)
|
|
||||||
|
|
||||||
from plone.app.discussion.browser.migration import View
|
|
||||||
|
|
||||||
from plone.app.discussion.interfaces import IConversation, IComment
|
|
||||||
|
|
||||||
|
|
||||||
class MigrationTest(unittest.TestCase):
|
|
||||||
|
|
||||||
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
|
|
||||||
|
|
||||||
def _publish(self, reply):
|
|
||||||
# publish the reply
|
|
||||||
status = self.portal.portal_workflow.getStatusOf(
|
|
||||||
'comment_review_workflow', reply
|
|
||||||
).copy()
|
|
||||||
status['review_state'] = 'published'
|
|
||||||
self.portal.portal_workflow.setStatusOf(
|
|
||||||
'comment_review_workflow',
|
|
||||||
reply,
|
|
||||||
status,
|
|
||||||
)
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.portal = self.layer['portal']
|
|
||||||
self.request = self.layer['request']
|
|
||||||
setRoles(self.portal, TEST_USER_ID, ['Manager'])
|
|
||||||
|
|
||||||
self.portal.invokeFactory(
|
|
||||||
id='doc',
|
|
||||||
title='Document 1',
|
|
||||||
type_name='Document'
|
|
||||||
)
|
|
||||||
# Create a document
|
|
||||||
self.discussion = getToolByName(self.portal, 'portal_discussion', None)
|
|
||||||
self.discussion.overrideDiscussionFor(self.portal.doc, 1)
|
|
||||||
# Publish it
|
|
||||||
self.workflowTool = getToolByName(self.portal, 'portal_workflow')
|
|
||||||
self.workflowTool.setDefaultChain('simple_publication_workflow')
|
|
||||||
self.workflowTool.doActionFor(self.portal.doc, 'publish')
|
|
||||||
|
|
||||||
self.request.set("test", True)
|
|
||||||
self.view = View(self.portal, self.request)
|
|
||||||
self.workflowTool.setChainForPortalTypes(
|
|
||||||
('Discussion Item',),
|
|
||||||
'comment_review_workflow'
|
|
||||||
)
|
|
||||||
|
|
||||||
# Create a user Jimmy Jones so comments creator migration can work?
|
|
||||||
acl_users = getToolByName(self.portal, 'acl_users')
|
|
||||||
acl_users.userFolderAddUser('Jim', 'secret', ['Member'], [])
|
|
||||||
mt = getToolByName(self.portal, 'portal_membership')
|
|
||||||
member = mt.getMemberById('Jim')
|
|
||||||
member.fullname = 'Jimmy Jones'
|
|
||||||
|
|
||||||
self.doc = self.portal.doc
|
|
||||||
|
|
||||||
def test_migrate_comment(self):
|
|
||||||
|
|
||||||
# Create a comment
|
|
||||||
talkback = self.discussion.getDiscussionFor(self.doc)
|
|
||||||
self.doc.talkback.createReply('My Title', 'My Text', Creator='Jim')
|
|
||||||
reply = talkback.getReplies()[0]
|
|
||||||
reply.setReplyTo(self.doc)
|
|
||||||
reply.creation_date = DateTime(2003, 3, 11, 9, 28, 6, 'GMT')
|
|
||||||
reply.modification_date = DateTime(2009, 7, 12, 19, 38, 7, 'GMT')
|
|
||||||
|
|
||||||
self._publish(reply)
|
|
||||||
self.assertEqual(reply.Title(), 'My Title')
|
|
||||||
self.assertEqual(reply.EditableBody(), 'My Text')
|
|
||||||
self.assertTrue('Jim' in reply.listCreators())
|
|
||||||
self.assertEqual(talkback.replyCount(self.doc), 1)
|
|
||||||
self.assertEqual(reply.inReplyTo(), self.doc)
|
|
||||||
|
|
||||||
# Call migration script
|
|
||||||
self.view()
|
|
||||||
|
|
||||||
# Make sure a conversation has been created
|
|
||||||
self.assertTrue(
|
|
||||||
'plone.app.discussion:conversation' in IAnnotations(self.doc)
|
|
||||||
)
|
|
||||||
conversation = IConversation(self.doc)
|
|
||||||
|
|
||||||
# Check migration
|
|
||||||
self.assertEqual(conversation.total_comments, 1)
|
|
||||||
self.assertTrue(conversation.getComments().next())
|
|
||||||
comment1 = conversation.values()[0]
|
|
||||||
self.assertTrue(IComment.providedBy(comment1))
|
|
||||||
self.assertEqual(comment1.Title(), 'My Title')
|
|
||||||
self.assertEqual(comment1.text, '<p>My Text</p>\n')
|
|
||||||
self.assertEqual(comment1.mime_type, 'text/html')
|
|
||||||
self.assertEqual(comment1.Creator(), 'Jim')
|
|
||||||
self.assertEqual(
|
|
||||||
comment1.creation_date,
|
|
||||||
datetime(2003, 3, 11, 9, 28, 6)
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
comment1.modification_date,
|
|
||||||
datetime(2009, 7, 12, 19, 38, 7)
|
|
||||||
)
|
|
||||||
self.assertEqual([
|
|
||||||
{'comment': comment1, 'depth': 0, 'id': long(comment1.id)}
|
|
||||||
], list(conversation.getThreads()))
|
|
||||||
self.assertFalse(self.doc.talkback)
|
|
||||||
|
|
||||||
def test_migrate_comment_with_creator(self):
|
|
||||||
# Create a comment
|
|
||||||
talkback = self.discussion.getDiscussionFor(self.doc)
|
|
||||||
self.doc.talkback.createReply('My Title', 'My Text', Creator='Jim')
|
|
||||||
reply = talkback.getReplies()[0]
|
|
||||||
reply.setReplyTo(self.doc)
|
|
||||||
reply.creation_date = DateTime(2003, 3, 11, 9, 28, 6, 'GMT')
|
|
||||||
reply.modification_date = DateTime(2009, 7, 12, 19, 38, 7, 'GMT')
|
|
||||||
reply.author_username = 'Jim'
|
|
||||||
reply.email = 'jimmy@jones.xyz'
|
|
||||||
|
|
||||||
self._publish(reply)
|
|
||||||
self.assertEqual(reply.Title(), 'My Title')
|
|
||||||
self.assertEqual(reply.EditableBody(), 'My Text')
|
|
||||||
self.assertTrue('Jim' in reply.listCreators())
|
|
||||||
self.assertEqual(talkback.replyCount(self.doc), 1)
|
|
||||||
self.assertEqual(reply.inReplyTo(), self.doc)
|
|
||||||
self.assertEqual(reply.author_username, 'Jim')
|
|
||||||
self.assertEqual(reply.email, 'jimmy@jones.xyz')
|
|
||||||
|
|
||||||
# Call migration script
|
|
||||||
self.view()
|
|
||||||
|
|
||||||
# Make sure a conversation has been created
|
|
||||||
self.assertTrue(
|
|
||||||
'plone.app.discussion:conversation' in IAnnotations(self.doc)
|
|
||||||
)
|
|
||||||
conversation = IConversation(self.doc)
|
|
||||||
|
|
||||||
# Check migration
|
|
||||||
self.assertEqual(conversation.total_comments, 1)
|
|
||||||
self.assertTrue(conversation.getComments().next())
|
|
||||||
comment1 = conversation.values()[0]
|
|
||||||
self.assertTrue(IComment.providedBy(comment1))
|
|
||||||
self.assertEqual(comment1.Title(), 'My Title')
|
|
||||||
self.assertEqual(comment1.text, '<p>My Text</p>\n')
|
|
||||||
self.assertEqual(comment1.mime_type, 'text/html')
|
|
||||||
self.assertEqual(comment1.Creator(), 'Jim')
|
|
||||||
self.assertEqual(
|
|
||||||
comment1.creation_date,
|
|
||||||
datetime(2003, 3, 11, 9, 28, 6)
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
comment1.modification_date,
|
|
||||||
datetime(2009, 7, 12, 19, 38, 7)
|
|
||||||
)
|
|
||||||
self.assertEqual([
|
|
||||||
{'comment': comment1, 'depth': 0, 'id': long(comment1.id)}
|
|
||||||
], list(conversation.getThreads()))
|
|
||||||
self.assertFalse(self.doc.talkback)
|
|
||||||
|
|
||||||
# Though this should be Jimmy, but looks like getProperty won't pick
|
|
||||||
# up 'author_username' (reply.author_username is not None), so it's
|
|
||||||
# propagating Creator()..?
|
|
||||||
self.assertEqual(comment1.author_username, 'Jim')
|
|
||||||
|
|
||||||
self.assertEqual(comment1.author_name, 'Jimmy Jones')
|
|
||||||
self.assertEqual(comment1.author_email, 'jimmy@jones.xyz')
|
|
||||||
|
|
||||||
def test_migrate_nested_comments(self):
|
|
||||||
# Create some nested comments and migrate them
|
|
||||||
#
|
|
||||||
# self.doc
|
|
||||||
# +- First comment
|
|
||||||
# +- Re: First comment
|
|
||||||
# + Re: Re: First comment
|
|
||||||
# + Re: Re: Re: First comment
|
|
||||||
# +- Re: First comment (2)
|
|
||||||
# +- Re: First comment (3)
|
|
||||||
# +- Re: First comment (4)
|
|
||||||
# +- Second comment
|
|
||||||
|
|
||||||
talkback = self.discussion.getDiscussionFor(self.doc)
|
|
||||||
|
|
||||||
# First comment
|
|
||||||
talkback.createReply(title='First comment',
|
|
||||||
text='This is my first comment.')
|
|
||||||
comment1 = talkback.getReplies()[0]
|
|
||||||
self._publish(comment1)
|
|
||||||
|
|
||||||
talkback_comment1 = self.discussion.getDiscussionFor(comment1)
|
|
||||||
|
|
||||||
# Re: First comment
|
|
||||||
talkback_comment1.createReply(title='Re: First comment',
|
|
||||||
text='This is my first reply.')
|
|
||||||
comment1_1 = talkback_comment1.getReplies()[0]
|
|
||||||
self._publish(comment1_1)
|
|
||||||
|
|
||||||
talkback_comment1_1 = self.discussion.getDiscussionFor(comment1_1)
|
|
||||||
|
|
||||||
self.assertEqual(len(talkback.getReplies()), 1)
|
|
||||||
self.assertEqual(len(talkback_comment1.getReplies()), 1)
|
|
||||||
self.assertEqual(len(talkback_comment1_1.getReplies()), 0)
|
|
||||||
|
|
||||||
#Re: Re: First comment
|
|
||||||
talkback_comment1_1.createReply(title='Re: Re: First comment',
|
|
||||||
text='This is my first re-reply.')
|
|
||||||
comment1_1_1 = talkback_comment1_1.getReplies()[0]
|
|
||||||
self._publish(comment1_1_1)
|
|
||||||
|
|
||||||
talkback_comment1_1_1 = self.discussion.getDiscussionFor(comment1_1_1)
|
|
||||||
|
|
||||||
# Re: Re: Re: First comment
|
|
||||||
talkback_comment1_1_1.createReply(title='Re: Re: Re: First comment',
|
|
||||||
text='This is my first re-re-reply.')
|
|
||||||
self._publish(talkback_comment1_1_1.getReplies()[0])
|
|
||||||
|
|
||||||
# Re: First comment (2)
|
|
||||||
talkback_comment1.createReply(title='Re: First comment (2)',
|
|
||||||
text='This is my first reply (2).')
|
|
||||||
self._publish(talkback_comment1.getReplies()[1])
|
|
||||||
|
|
||||||
# Re: First comment (3)
|
|
||||||
talkback_comment1.createReply(title='Re: First comment (3)',
|
|
||||||
text='This is my first reply (3).')
|
|
||||||
self._publish(talkback_comment1.getReplies()[2])
|
|
||||||
|
|
||||||
# Re: First comment (4)
|
|
||||||
talkback_comment1.createReply(title='Re: First comment (4)',
|
|
||||||
text='This is my first reply (4).')
|
|
||||||
self._publish(talkback_comment1.getReplies()[3])
|
|
||||||
|
|
||||||
# Second comment
|
|
||||||
talkback.createReply(title='Second comment',
|
|
||||||
text='This is my second comment.')
|
|
||||||
self._publish(talkback.getReplies()[1])
|
|
||||||
|
|
||||||
# Call migration script
|
|
||||||
self.view()
|
|
||||||
|
|
||||||
# Check migration
|
|
||||||
conversation = IConversation(self.doc)
|
|
||||||
self.assertEqual(conversation.total_comments, 8)
|
|
||||||
|
|
||||||
comment1 = conversation.values()[0]
|
|
||||||
comment1_1 = conversation.values()[1]
|
|
||||||
comment1_1_1 = conversation.values()[2]
|
|
||||||
comment1_1_1_1 = conversation.values()[3]
|
|
||||||
comment1_2 = conversation.values()[4]
|
|
||||||
comment1_3 = conversation.values()[5]
|
|
||||||
comment1_4 = conversation.values()[6]
|
|
||||||
comment2 = conversation.values()[7]
|
|
||||||
|
|
||||||
self.assertEqual([
|
|
||||||
{'comment': comment1, 'depth': 0, 'id': long(comment1.id)},
|
|
||||||
{'comment': comment1_1, 'depth': 1, 'id': long(comment1_1.id)},
|
|
||||||
{'comment': comment1_1_1, 'depth': 2, 'id': long(comment1_1_1.id)},
|
|
||||||
{'comment': comment1_1_1_1, 'depth': 3,
|
|
||||||
'id': long(comment1_1_1_1.id)},
|
|
||||||
{'comment': comment1_2, 'depth': 1, 'id': long(comment1_2.id)},
|
|
||||||
{'comment': comment1_3, 'depth': 1, 'id': long(comment1_3.id)},
|
|
||||||
{'comment': comment1_4, 'depth': 1, 'id': long(comment1_4.id)},
|
|
||||||
{'comment': comment2, 'depth': 0, 'id': long(comment2.id)},
|
|
||||||
], list(conversation.getThreads()))
|
|
||||||
|
|
||||||
talkback = self.discussion.getDiscussionFor(self.doc)
|
|
||||||
self.assertEqual(len(talkback.getReplies()), 0)
|
|
||||||
|
|
||||||
def test_migrate_nested_comments_with_filter(self):
|
|
||||||
# Create some nested comments and migrate them.
|
|
||||||
# But use a filter that filters the top-level comment.
|
|
||||||
# All the comments should be removed, but not migrated.
|
|
||||||
#
|
|
||||||
# self.doc
|
|
||||||
# +- First comment
|
|
||||||
# +- Re: First comment
|
|
||||||
|
|
||||||
talkback = self.discussion.getDiscussionFor(self.doc)
|
|
||||||
|
|
||||||
# First comment
|
|
||||||
talkback.createReply(title='First comment',
|
|
||||||
text='This is my first comment.')
|
|
||||||
comment1 = talkback.getReplies()[0]
|
|
||||||
talkback_comment1 = self.discussion.getDiscussionFor(comment1)
|
|
||||||
|
|
||||||
# Re: First comment
|
|
||||||
talkback_comment1.createReply(title='Re: First comment',
|
|
||||||
text='This is my first reply.')
|
|
||||||
comment1_1 = talkback_comment1.getReplies()[0]
|
|
||||||
talkback_comment1_1 = self.discussion.getDiscussionFor(comment1_1)
|
|
||||||
|
|
||||||
self.assertEqual(len(talkback.getReplies()), 1)
|
|
||||||
self.assertEqual(len(talkback_comment1.getReplies()), 1)
|
|
||||||
self.assertEqual(len(talkback_comment1_1.getReplies()), 0)
|
|
||||||
|
|
||||||
def deny_comments(reply):
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Call migration script
|
|
||||||
self.view(filter_callback=deny_comments)
|
|
||||||
|
|
||||||
# Check migration
|
|
||||||
conversation = IConversation(self.doc)
|
|
||||||
self.assertEqual(conversation.total_comments, 0)
|
|
||||||
talkback = self.discussion.getDiscussionFor(self.doc)
|
|
||||||
self.assertEqual(len(talkback.getReplies()), 0)
|
|
||||||
|
|
||||||
def test_migrate_no_comment(self):
|
|
||||||
|
|
||||||
# Call migration script
|
|
||||||
self.view()
|
|
||||||
|
|
||||||
# Make sure no conversation has been created
|
|
||||||
self.assertTrue(
|
|
||||||
'plone.app.discussion:conversation' not in IAnnotations(self.doc)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
|
||||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
|
@ -1,8 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from DateTime import DateTime
|
|
||||||
|
|
||||||
from zope.component import createObject
|
from zope.component import createObject
|
||||||
|
|
||||||
from Products.CMFCore.utils import getToolByName
|
from Products.CMFCore.utils import getToolByName
|
||||||
@ -58,29 +56,6 @@ class ModerationViewTest(unittest.TestCase):
|
|||||||
('comment_review_workflow,'))
|
('comment_review_workflow,'))
|
||||||
self.assertEqual(self.view.moderation_enabled(), True)
|
self.assertEqual(self.view.moderation_enabled(), True)
|
||||||
|
|
||||||
def test_old_comments_not_shown_in_moderation_view(self):
|
|
||||||
# Create old comment
|
|
||||||
discussion = getToolByName(self.portal, 'portal_discussion', None)
|
|
||||||
discussion.overrideDiscussionFor(self.portal.doc1, 1)
|
|
||||||
talkback = discussion.getDiscussionFor(self.portal.doc1)
|
|
||||||
self.portal.doc1.talkback.createReply('My Title',
|
|
||||||
'My Text',
|
|
||||||
Creator='Jim')
|
|
||||||
reply = talkback.getReplies()[0]
|
|
||||||
reply.setReplyTo(self.portal.doc1)
|
|
||||||
reply.creation_date = DateTime(2003, 3, 11, 9, 28, 6)
|
|
||||||
reply.modification_date = DateTime(2009, 7, 12, 19, 38, 7)
|
|
||||||
self.assertEqual(reply.Title(), 'My Title')
|
|
||||||
self.assertEqual(reply.EditableBody(), 'My Text')
|
|
||||||
self.assertTrue('Jim' in reply.listCreators())
|
|
||||||
self.assertEqual(talkback.replyCount(self.portal.doc1), 1)
|
|
||||||
self.assertEqual(reply.inReplyTo(), self.portal.doc1)
|
|
||||||
|
|
||||||
view = self.view()
|
|
||||||
|
|
||||||
self.assertTrue('No comments to moderate' in view)
|
|
||||||
self.assertEqual(len(self.view.comments), 0)
|
|
||||||
|
|
||||||
|
|
||||||
class ModerationBulkActionsViewTest(unittest.TestCase):
|
class ModerationBulkActionsViewTest(unittest.TestCase):
|
||||||
|
|
||||||
@ -189,6 +164,3 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
|
|||||||
self.assertTrue(comment)
|
self.assertTrue(comment)
|
||||||
self.assertEqual(comment, self.comment2)
|
self.assertEqual(comment, self.comment2)
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
|
||||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
|
||||||
|
@ -42,7 +42,6 @@ class TestUserNotificationUnit(unittest.TestCase):
|
|||||||
'.user_notification_enabled'] = True
|
'.user_notification_enabled'] = True
|
||||||
# Create test content
|
# Create test content
|
||||||
self.portal.invokeFactory('Document', 'doc1')
|
self.portal.invokeFactory('Document', 'doc1')
|
||||||
self.portal_discussion = self.portal.portal_discussion
|
|
||||||
# Archetypes content types store data as utf-8 encoded strings
|
# Archetypes content types store data as utf-8 encoded strings
|
||||||
# The missing u in front of a string is therefor not missing
|
# The missing u in front of a string is therefor not missing
|
||||||
self.portal.doc1.title = 'Kölle Alaaf' # What is "Fasching"?
|
self.portal.doc1.title = 'Kölle Alaaf' # What is "Fasching"?
|
||||||
@ -189,7 +188,6 @@ class TestModeratorNotificationUnit(unittest.TestCase):
|
|||||||
] = True
|
] = True
|
||||||
# Create test content
|
# Create test content
|
||||||
self.portal.invokeFactory('Document', 'doc1')
|
self.portal.invokeFactory('Document', 'doc1')
|
||||||
self.portal_discussion = self.portal.portal_discussion
|
|
||||||
# Archetypes content types store data as utf-8 encoded strings
|
# Archetypes content types store data as utf-8 encoded strings
|
||||||
# The missing u in front of a string is therefor not missing
|
# The missing u in front of a string is therefor not missing
|
||||||
self.portal.doc1.title = 'Kölle Alaaf' # What is "Fasching"?
|
self.portal.doc1.title = 'Kölle Alaaf' # What is "Fasching"?
|
||||||
@ -278,6 +276,3 @@ class TestModeratorNotificationUnit(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(len(self.mailhost.messages), 0)
|
self.assertEqual(len(self.mailhost.messages), 0)
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
|
||||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
import unittest2 as unittest
|
|
||||||
|
|
||||||
from zope.component import queryUtility, createObject
|
|
||||||
|
|
||||||
from plone.app.testing import TEST_USER_ID, setRoles
|
|
||||||
|
|
||||||
from plone.app.discussion.testing import \
|
|
||||||
PLONE_APP_DISCUSSION_INTEGRATION_TESTING
|
|
||||||
|
|
||||||
from plone.app.discussion.interfaces import ICommentingTool, IConversation
|
|
||||||
|
|
||||||
|
|
||||||
class ToolTest(unittest.TestCase):
|
|
||||||
|
|
||||||
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.portal = self.layer['portal']
|
|
||||||
setRoles(self.portal, TEST_USER_ID, ['Manager'])
|
|
||||||
self.portal.invokeFactory(id='doc1',
|
|
||||||
title='Document 1',
|
|
||||||
type_name='Document')
|
|
||||||
|
|
||||||
def test_tool_indexing(self):
|
|
||||||
# Create a conversation. In this case we doesn't assign it to an
|
|
||||||
# object, as we just want to check the Conversation object API.
|
|
||||||
conversation = IConversation(self.portal.doc1)
|
|
||||||
|
|
||||||
# Add a comment.
|
|
||||||
comment = createObject('plone.Comment')
|
|
||||||
comment.creator = 'jim'
|
|
||||||
comment.author_name = "Jim"
|
|
||||||
comment.text = 'Comment text'
|
|
||||||
|
|
||||||
conversation.addComment(comment)
|
|
||||||
|
|
||||||
# Check that the comment got indexed in the tool:
|
|
||||||
tool = queryUtility(ICommentingTool)
|
|
||||||
comment = list(tool.searchResults())
|
|
||||||
self.assertTrue(
|
|
||||||
len(comment) == 1,
|
|
||||||
"There is only one comment, but we got"
|
|
||||||
" %s results in the search" % len(comment)
|
|
||||||
)
|
|
||||||
self.assertEqual(comment[0].Title, 'Jim on Document 1')
|
|
||||||
|
|
||||||
def test_unindexing(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def test_search(self):
|
|
||||||
# search returns only comments
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
|
||||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
|
@ -32,7 +32,6 @@ class WorkflowSetupTest(unittest.TestCase):
|
|||||||
self.portal.invokeFactory('Folder', 'test-folder')
|
self.portal.invokeFactory('Folder', 'test-folder')
|
||||||
self.folder = self.portal['test-folder']
|
self.folder = self.portal['test-folder']
|
||||||
self.portal.portal_types['Document'].allow_discussion = True
|
self.portal.portal_types['Document'].allow_discussion = True
|
||||||
self.portal_discussion = self.portal.portal_discussion
|
|
||||||
self.folder.invokeFactory('Document', 'doc1')
|
self.folder.invokeFactory('Document', 'doc1')
|
||||||
self.doc = self.folder.doc1
|
self.doc = self.folder.doc1
|
||||||
|
|
||||||
@ -190,7 +189,6 @@ class CommentReviewWorkflowTest(unittest.TestCase):
|
|||||||
|
|
||||||
# Create a Document
|
# Create a Document
|
||||||
self.portal.invokeFactory('Document', 'doc1')
|
self.portal.invokeFactory('Document', 'doc1')
|
||||||
self.portal_discussion = self.portal.portal_discussion
|
|
||||||
|
|
||||||
# Create a conversation for this Document
|
# Create a conversation for this Document
|
||||||
conversation = IConversation(self.portal.doc1)
|
conversation = IConversation(self.portal.doc1)
|
||||||
@ -277,6 +275,3 @@ class CommentReviewWorkflowTest(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
|
||||||
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|
|
||||||
|
Loading…
Reference in New Issue
Block a user