summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x.gitignore1
-rw-r--r--askbot/__init__.py20
-rw-r--r--askbot/api.py4
-rw-r--r--askbot/conf/__init__.py9
-rw-r--r--askbot/conf/access_control.py38
-rw-r--r--askbot/conf/email.py8
-rw-r--r--askbot/conf/flatpages.py11
-rw-r--r--askbot/conf/forum_data_rules.py56
-rw-r--r--askbot/conf/group_settings.py25
-rw-r--r--askbot/conf/ldap.py135
-rw-r--r--askbot/conf/minimum_reputation.py14
-rw-r--r--askbot/conf/moderation.py9
-rw-r--r--askbot/conf/user_settings.py37
-rw-r--r--askbot/conf/widgets.py99
-rw-r--r--askbot/const/__init__.py84
-rw-r--r--askbot/const/message_keys.py4
-rw-r--r--askbot/context.py43
-rw-r--r--askbot/deps/django_authopenid/backends.py126
-rw-r--r--askbot/deps/django_authopenid/forms.py4
-rw-r--r--askbot/deps/django_authopenid/ldap_auth.py208
-rw-r--r--askbot/deps/django_authopenid/urls.py14
-rw-r--r--askbot/deps/django_authopenid/util.py7
-rw-r--r--askbot/deps/django_authopenid/views.py573
-rw-r--r--askbot/deps/livesettings/models.py58
-rw-r--r--askbot/deps/livesettings/overrides.py4
-rw-r--r--askbot/doc/source/changelog.rst25
-rw-r--r--askbot/doc/source/contributors.rst1
-rw-r--r--askbot/doc/source/customizing-skin-in-askbot.rst9
-rw-r--r--askbot/doc/source/debugging.rst35
-rw-r--r--askbot/doc/source/intranet-setup.rst7
-rw-r--r--askbot/doc/source/live-settings.rst37
-rw-r--r--askbot/doc/source/management-commands.rst2
-rw-r--r--askbot/doc/source/optional-modules.rst109
-rw-r--r--askbot/doc/source/settings.rst14
-rw-r--r--askbot/exceptions.py5
-rw-r--r--askbot/forms.py835
-rw-r--r--askbot/mail/__init__.py88
-rw-r--r--askbot/mail/lamson_handlers.py33
-rw-r--r--askbot/mail/messages.py11
-rw-r--r--askbot/management/commands/askbot_add_test_content.py48
-rw-r--r--askbot/management/commands/build_livesettings_cache.py12
-rw-r--r--askbot/management/commands/clean_session.py52
-rw-r--r--askbot/management/commands/delete_unused_tags.py14
-rw-r--r--askbot/management/commands/rename_tags_id.py16
-rw-r--r--askbot/management/commands/sample_command.py6
-rw-r--r--askbot/management/commands/send_accept_answer_reminders.py21
-rw-r--r--askbot/management/commands/send_email_alerts.py29
-rw-r--r--askbot/management/commands/send_unanswered_question_reminders.py26
-rw-r--r--askbot/media/bootstrap/bootstrap.zip (renamed from askbot/skins/default/media/bootstrap/bootstrap.zip)bin273108 -> 273108 bytes
-rw-r--r--askbot/media/bootstrap/css/bootstrap.css4559
-rw-r--r--askbot/media/bootstrap/css/bootstrap.min.css (renamed from askbot/skins/default/media/bootstrap/css/bootstrap.min.css)0
-rw-r--r--askbot/media/bootstrap/img/glyphicons-halflings-white.png (renamed from askbot/skins/default/media/bootstrap/img/glyphicons-halflings-white.png)bin4352 -> 4352 bytes
-rw-r--r--askbot/media/bootstrap/img/glyphicons-halflings.png (renamed from askbot/skins/default/media/bootstrap/img/glyphicons-halflings.png)bin4352 -> 4352 bytes
-rw-r--r--askbot/media/bootstrap/js/bootstrap.js (renamed from askbot/skins/default/media/bootstrap/js/bootstrap.js)0
-rw-r--r--askbot/media/bootstrap/js/bootstrap.min.js (renamed from askbot/skins/default/media/bootstrap/js/bootstrap.min.js)0
-rw-r--r--askbot/media/images/OFL.txt (renamed from askbot/skins/default/media/images/OFL.txt)0
-rw-r--r--askbot/media/images/OpenSans-CondBold.ttfbin0 -> 264372 bytes
-rw-r--r--askbot/media/images/OpenSans-CondLight.ttfbin0 -> 221108 bytes
-rw-r--r--askbot/media/images/OpenSans-CondLightItalic.ttfbin0 -> 210804 bytes
-rw-r--r--askbot/media/images/YanoneKaffeesatz-Bold.ttf (renamed from askbot/skins/default/media/images/YanoneKaffeesatz-Bold.ttf)bin73000 -> 73000 bytes
-rw-r--r--askbot/media/images/YanoneKaffeesatz-ExtraLight.ttf (renamed from askbot/skins/default/media/images/YanoneKaffeesatz-ExtraLight.ttf)bin77024 -> 77024 bytes
-rw-r--r--askbot/media/images/YanoneKaffeesatz-Light.ttf (renamed from askbot/skins/default/media/images/YanoneKaffeesatz-Light.ttf)bin77296 -> 77296 bytes
-rw-r--r--askbot/media/images/YanoneKaffeesatz-Regular.ttf (renamed from askbot/skins/default/media/images/YanoneKaffeesatz-Regular.ttf)bin76588 -> 76588 bytes
-rw-r--r--askbot/media/images/Yanone_Kaffeesatz.zip (renamed from askbot/skins/default/media/images/Yanone_Kaffeesatz.zip)bin154362 -> 154362 bytes
-rw-r--r--askbot/media/images/accept.png (renamed from askbot/skins/default/media/images/accept.png)bin727 -> 727 bytes
-rw-r--r--askbot/media/images/anon.png (renamed from askbot/skins/common/media/images/anon.png)bin687 -> 687 bytes
-rw-r--r--askbot/media/images/answers-background.png (renamed from askbot/skins/default/media/images/answers-background.png)bin235 -> 235 bytes
-rw-r--r--askbot/media/images/attachment.pngbin0 -> 3142 bytes
-rw-r--r--askbot/media/images/background-user-info.png (renamed from askbot/skins/default/media/images/background-user-info.png)bin361 -> 361 bytes
-rw-r--r--askbot/media/images/bigbutton.png (renamed from askbot/skins/common/media/images/bigbutton.png)bin263 -> 263 bytes
-rw-r--r--askbot/media/images/bigbuttonhover.png (renamed from askbot/skins/common/media/images/bigbuttonhover.png)bin236 -> 236 bytes
-rwxr-xr-xaskbot/media/images/blue-up-arrow-h18px.png (renamed from askbot/skins/common/media/images/blue-up-arrow-h18px.png)bin593 -> 593 bytes
-rwxr-xr-xaskbot/media/images/box-arrow.gif (renamed from askbot/skins/common/media/images/box-arrow.gif)bin69 -> 69 bytes
-rwxr-xr-xaskbot/media/images/bullet_green.gif (renamed from askbot/skins/common/media/images/bullet_green.gif)bin64 -> 64 bytes
-rwxr-xr-xaskbot/media/images/cc-88x31.png (renamed from askbot/skins/common/media/images/cc-88x31.png)bin5460 -> 5460 bytes
-rw-r--r--askbot/media/images/cc-by-sa.png (renamed from askbot/skins/common/media/images/cc-by-sa.png)bin5083 -> 5083 bytes
-rw-r--r--askbot/media/images/close-small-dark.png (renamed from askbot/skins/default/media/images/close-small-dark.png)bin879 -> 879 bytes
-rwxr-xr-xaskbot/media/images/close-small-hover.png (renamed from askbot/skins/common/media/images/close-small-hover.png)bin337 -> 337 bytes
-rwxr-xr-xaskbot/media/images/close-small.png (renamed from askbot/skins/common/media/images/close-small.png)bin293 -> 293 bytes
-rw-r--r--askbot/media/images/close.png (renamed from askbot/skins/default/media/images/close.png)bin469 -> 469 bytes
-rw-r--r--askbot/media/images/comment-background.png (renamed from askbot/skins/default/media/images/comment-background.png)bin250 -> 250 bytes
-rw-r--r--askbot/media/images/comment.png (renamed from askbot/skins/default/media/images/comment.png)bin606 -> 606 bytes
-rw-r--r--askbot/media/images/contributorsback.png (renamed from askbot/skins/common/media/images/contributorsback.png)bin714 -> 714 bytes
-rwxr-xr-xaskbot/media/images/dash.gif (renamed from askbot/skins/common/media/images/dash.gif)bin44 -> 44 bytes
-rw-r--r--askbot/media/images/delete.png (renamed from askbot/skins/default/media/images/delete.png)bin434 -> 434 bytes
-rw-r--r--askbot/media/images/dialog-warning-off.png (renamed from askbot/skins/common/media/images/dialog-warning-off.png)bin419 -> 419 bytes
-rw-r--r--askbot/media/images/dialog-warning.png (renamed from askbot/skins/common/media/images/dialog-warning.png)bin603 -> 603 bytes
-rwxr-xr-xaskbot/media/images/djangomade124x25_grey.gif (renamed from askbot/skins/common/media/images/djangomade124x25_grey.gif)bin2035 -> 2035 bytes
-rwxr-xr-xaskbot/media/images/dot-g.gif (renamed from askbot/skins/common/media/images/dot-g.gif)bin61 -> 61 bytes
-rwxr-xr-xaskbot/media/images/dot-list.gif (renamed from askbot/skins/common/media/images/dot-list.gif)bin56 -> 56 bytes
-rwxr-xr-xaskbot/media/images/edit.png (renamed from askbot/skins/common/media/images/edit.png)bin758 -> 758 bytes
-rw-r--r--askbot/media/images/edit2.png (renamed from askbot/skins/default/media/images/edit2.png)bin498 -> 498 bytes
-rwxr-xr-xaskbot/media/images/expander-arrow-hide.gif (renamed from askbot/skins/common/media/images/expander-arrow-hide.gif)bin126 -> 126 bytes
-rwxr-xr-xaskbot/media/images/expander-arrow-show.gif (renamed from askbot/skins/common/media/images/expander-arrow-show.gif)bin135 -> 135 bytes
-rw-r--r--askbot/media/images/favicon.gif (renamed from askbot/skins/common/media/images/favicon.gif)bin898 -> 898 bytes
-rw-r--r--askbot/media/images/favicon.ico (renamed from askbot/skins/common/media/images/favicon.ico)bin1150 -> 1150 bytes
-rw-r--r--askbot/media/images/feed-icon-small.png (renamed from askbot/skins/common/media/images/feed-icon-small.png)bin669 -> 669 bytes
-rw-r--r--askbot/media/images/flag.png (renamed from askbot/skins/default/media/images/flag.png)bin515 -> 515 bytes
-rwxr-xr-xaskbot/media/images/flags/ad.gif (renamed from askbot/skins/common/media/images/flags/ad.gif)bin371 -> 371 bytes
-rwxr-xr-xaskbot/media/images/flags/ae.gif (renamed from askbot/skins/common/media/images/flags/ae.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/af.gif (renamed from askbot/skins/common/media/images/flags/af.gif)bin369 -> 369 bytes
-rwxr-xr-xaskbot/media/images/flags/ag.gif (renamed from askbot/skins/common/media/images/flags/ag.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/ai.gif (renamed from askbot/skins/common/media/images/flags/ai.gif)bin369 -> 369 bytes
-rwxr-xr-xaskbot/media/images/flags/al.gif (renamed from askbot/skins/common/media/images/flags/al.gif)bin370 -> 370 bytes
-rwxr-xr-xaskbot/media/images/flags/am.gif (renamed from askbot/skins/common/media/images/flags/am.gif)bin363 -> 363 bytes
-rwxr-xr-xaskbot/media/images/flags/an.gif (renamed from askbot/skins/common/media/images/flags/an.gif)bin368 -> 368 bytes
-rw-r--r--askbot/media/images/flags/ao.gif (renamed from askbot/skins/common/media/images/flags/ao.gif)bin244 -> 244 bytes
-rwxr-xr-xaskbot/media/images/flags/ar.gif (renamed from askbot/skins/common/media/images/flags/ar.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/as.gif (renamed from askbot/skins/common/media/images/flags/as.gif)bin365 -> 365 bytes
-rwxr-xr-xaskbot/media/images/flags/at.gif (renamed from askbot/skins/common/media/images/flags/at.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/au.gif (renamed from askbot/skins/common/media/images/flags/au.gif)bin378 -> 378 bytes
-rwxr-xr-xaskbot/media/images/flags/aw.gif (renamed from askbot/skins/common/media/images/flags/aw.gif)bin365 -> 365 bytes
-rwxr-xr-xaskbot/media/images/flags/ax.gif (renamed from askbot/skins/common/media/images/flags/ax.gif)bin376 -> 376 bytes
-rwxr-xr-xaskbot/media/images/flags/az.gif (renamed from askbot/skins/common/media/images/flags/az.gif)bin370 -> 370 bytes
-rwxr-xr-xaskbot/media/images/flags/ba.gif (renamed from askbot/skins/common/media/images/flags/ba.gif)bin363 -> 363 bytes
-rwxr-xr-xaskbot/media/images/flags/bb.gif (renamed from askbot/skins/common/media/images/flags/bb.gif)bin368 -> 368 bytes
-rwxr-xr-xaskbot/media/images/flags/bd.gif (renamed from askbot/skins/common/media/images/flags/bd.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/be.gif (renamed from askbot/skins/common/media/images/flags/be.gif)bin359 -> 359 bytes
-rwxr-xr-xaskbot/media/images/flags/bf.gif (renamed from askbot/skins/common/media/images/flags/bf.gif)bin358 -> 358 bytes
-rwxr-xr-xaskbot/media/images/flags/bg.gif (renamed from askbot/skins/common/media/images/flags/bg.gif)bin360 -> 360 bytes
-rwxr-xr-xaskbot/media/images/flags/bh.gif (renamed from askbot/skins/common/media/images/flags/bh.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/bi.gif (renamed from askbot/skins/common/media/images/flags/bi.gif)bin374 -> 374 bytes
-rwxr-xr-xaskbot/media/images/flags/bj.gif (renamed from askbot/skins/common/media/images/flags/bj.gif)bin368 -> 368 bytes
-rwxr-xr-xaskbot/media/images/flags/bm.gif (renamed from askbot/skins/common/media/images/flags/bm.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/bn.gif (renamed from askbot/skins/common/media/images/flags/bn.gif)bin373 -> 373 bytes
-rwxr-xr-xaskbot/media/images/flags/bo.gif (renamed from askbot/skins/common/media/images/flags/bo.gif)bin359 -> 359 bytes
-rwxr-xr-xaskbot/media/images/flags/br.gif (renamed from askbot/skins/common/media/images/flags/br.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/bs.gif (renamed from askbot/skins/common/media/images/flags/bs.gif)bin351 -> 351 bytes
-rwxr-xr-xaskbot/media/images/flags/bt.gif (renamed from askbot/skins/common/media/images/flags/bt.gif)bin377 -> 377 bytes
-rwxr-xr-xaskbot/media/images/flags/bv.gif (renamed from askbot/skins/common/media/images/flags/bv.gif)bin376 -> 376 bytes
-rwxr-xr-xaskbot/media/images/flags/bw.gif (renamed from askbot/skins/common/media/images/flags/bw.gif)bin364 -> 364 bytes
-rwxr-xr-xaskbot/media/images/flags/by.gif (renamed from askbot/skins/common/media/images/flags/by.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/bz.gif (renamed from askbot/skins/common/media/images/flags/bz.gif)bin368 -> 368 bytes
-rwxr-xr-xaskbot/media/images/flags/ca.gif (renamed from askbot/skins/common/media/images/flags/ca.gif)bin376 -> 376 bytes
-rw-r--r--askbot/media/images/flags/catalonia.gif (renamed from askbot/skins/common/media/images/flags/catalonia.gif)bin238 -> 238 bytes
-rwxr-xr-xaskbot/media/images/flags/cc.gif (renamed from askbot/skins/common/media/images/flags/cc.gif)bin371 -> 371 bytes
-rw-r--r--askbot/media/images/flags/cd.gif (renamed from askbot/skins/common/media/images/flags/cd.gif)bin243 -> 243 bytes
-rwxr-xr-xaskbot/media/images/flags/cf.gif (renamed from askbot/skins/common/media/images/flags/cf.gif)bin364 -> 364 bytes
-rwxr-xr-xaskbot/media/images/flags/cg.gif (renamed from askbot/skins/common/media/images/flags/cg.gif)bin359 -> 359 bytes
-rwxr-xr-xaskbot/media/images/flags/ch.gif (renamed from askbot/skins/common/media/images/flags/ch.gif)bin332 -> 332 bytes
-rwxr-xr-xaskbot/media/images/flags/ci.gif (renamed from askbot/skins/common/media/images/flags/ci.gif)bin368 -> 368 bytes
-rwxr-xr-xaskbot/media/images/flags/ck.gif (renamed from askbot/skins/common/media/images/flags/ck.gif)bin362 -> 362 bytes
-rwxr-xr-xaskbot/media/images/flags/cl.gif (renamed from askbot/skins/common/media/images/flags/cl.gif)bin364 -> 364 bytes
-rwxr-xr-xaskbot/media/images/flags/cm.gif (renamed from askbot/skins/common/media/images/flags/cm.gif)bin369 -> 369 bytes
-rwxr-xr-xaskbot/media/images/flags/cn.gif (renamed from askbot/skins/common/media/images/flags/cn.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/co.gif (renamed from askbot/skins/common/media/images/flags/co.gif)bin353 -> 353 bytes
-rwxr-xr-xaskbot/media/images/flags/cr.gif (renamed from askbot/skins/common/media/images/flags/cr.gif)bin359 -> 359 bytes
-rwxr-xr-xaskbot/media/images/flags/cs.gif (renamed from askbot/skins/common/media/images/flags/cs.gif)bin364 -> 364 bytes
-rwxr-xr-xaskbot/media/images/flags/cu.gif (renamed from askbot/skins/common/media/images/flags/cu.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/cv.gif (renamed from askbot/skins/common/media/images/flags/cv.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/cx.gif (renamed from askbot/skins/common/media/images/flags/cx.gif)bin363 -> 363 bytes
-rwxr-xr-xaskbot/media/images/flags/cy.gif (renamed from askbot/skins/common/media/images/flags/cy.gif)bin365 -> 365 bytes
-rwxr-xr-xaskbot/media/images/flags/cz.gif (renamed from askbot/skins/common/media/images/flags/cz.gif)bin362 -> 362 bytes
-rwxr-xr-xaskbot/media/images/flags/de.gif (renamed from askbot/skins/common/media/images/flags/de.gif)bin362 -> 362 bytes
-rwxr-xr-xaskbot/media/images/flags/dj.gif (renamed from askbot/skins/common/media/images/flags/dj.gif)bin369 -> 369 bytes
-rwxr-xr-xaskbot/media/images/flags/dk.gif (renamed from askbot/skins/common/media/images/flags/dk.gif)bin374 -> 374 bytes
-rwxr-xr-xaskbot/media/images/flags/dm.gif (renamed from askbot/skins/common/media/images/flags/dm.gif)bin368 -> 368 bytes
-rwxr-xr-xaskbot/media/images/flags/do.gif (renamed from askbot/skins/common/media/images/flags/do.gif)bin362 -> 362 bytes
-rwxr-xr-xaskbot/media/images/flags/dz.gif (renamed from askbot/skins/common/media/images/flags/dz.gif)bin370 -> 370 bytes
-rwxr-xr-xaskbot/media/images/flags/ec.gif (renamed from askbot/skins/common/media/images/flags/ec.gif)bin362 -> 362 bytes
-rwxr-xr-xaskbot/media/images/flags/ee.gif (renamed from askbot/skins/common/media/images/flags/ee.gif)bin364 -> 364 bytes
-rwxr-xr-xaskbot/media/images/flags/eg.gif (renamed from askbot/skins/common/media/images/flags/eg.gif)bin363 -> 363 bytes
-rwxr-xr-xaskbot/media/images/flags/eh.gif (renamed from askbot/skins/common/media/images/flags/eh.gif)bin359 -> 359 bytes
-rwxr-xr-xaskbot/media/images/flags/england.gif (renamed from askbot/skins/common/media/images/flags/england.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/er.gif (renamed from askbot/skins/common/media/images/flags/er.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/es.gif (renamed from askbot/skins/common/media/images/flags/es.gif)bin360 -> 360 bytes
-rwxr-xr-xaskbot/media/images/flags/et.gif (renamed from askbot/skins/common/media/images/flags/et.gif)bin364 -> 364 bytes
-rw-r--r--askbot/media/images/flags/europeanunion.gif (renamed from askbot/skins/common/media/images/flags/europeanunion.gif)bin171 -> 171 bytes
-rwxr-xr-xaskbot/media/images/flags/fam.gif (renamed from askbot/skins/common/media/images/flags/fam.gif)bin370 -> 370 bytes
-rwxr-xr-xaskbot/media/images/flags/fi.gif (renamed from askbot/skins/common/media/images/flags/fi.gif)bin371 -> 371 bytes
-rwxr-xr-xaskbot/media/images/flags/fj.gif (renamed from askbot/skins/common/media/images/flags/fj.gif)bin370 -> 370 bytes
-rwxr-xr-xaskbot/media/images/flags/fk.gif (renamed from askbot/skins/common/media/images/flags/fk.gif)bin372 -> 372 bytes
-rwxr-xr-xaskbot/media/images/flags/fm.gif (renamed from askbot/skins/common/media/images/flags/fm.gif)bin377 -> 377 bytes
-rwxr-xr-xaskbot/media/images/flags/fo.gif (renamed from askbot/skins/common/media/images/flags/fo.gif)bin370 -> 370 bytes
-rwxr-xr-xaskbot/media/images/flags/fr.gif (renamed from askbot/skins/common/media/images/flags/fr.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/ga.gif (renamed from askbot/skins/common/media/images/flags/ga.gif)bin359 -> 359 bytes
-rw-r--r--askbot/media/images/flags/gb.gif (renamed from askbot/skins/common/media/images/flags/gb.gif)bin260 -> 260 bytes
-rwxr-xr-xaskbot/media/images/flags/gd.gif (renamed from askbot/skins/common/media/images/flags/gd.gif)bin364 -> 364 bytes
-rwxr-xr-xaskbot/media/images/flags/ge.gif (renamed from askbot/skins/common/media/images/flags/ge.gif)bin379 -> 379 bytes
-rwxr-xr-xaskbot/media/images/flags/gf.gif (renamed from askbot/skins/common/media/images/flags/gf.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/gh.gif (renamed from askbot/skins/common/media/images/flags/gh.gif)bin358 -> 358 bytes
-rwxr-xr-xaskbot/media/images/flags/gi.gif (renamed from askbot/skins/common/media/images/flags/gi.gif)bin370 -> 370 bytes
-rwxr-xr-xaskbot/media/images/flags/gl.gif (renamed from askbot/skins/common/media/images/flags/gl.gif)bin368 -> 368 bytes
-rwxr-xr-xaskbot/media/images/flags/gm.gif (renamed from askbot/skins/common/media/images/flags/gm.gif)bin362 -> 362 bytes
-rwxr-xr-xaskbot/media/images/flags/gn.gif (renamed from askbot/skins/common/media/images/flags/gn.gif)bin363 -> 363 bytes
-rwxr-xr-xaskbot/media/images/flags/gp.gif (renamed from askbot/skins/common/media/images/flags/gp.gif)bin357 -> 357 bytes
-rwxr-xr-xaskbot/media/images/flags/gq.gif (renamed from askbot/skins/common/media/images/flags/gq.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/gr.gif (renamed from askbot/skins/common/media/images/flags/gr.gif)bin368 -> 368 bytes
-rwxr-xr-xaskbot/media/images/flags/gs.gif (renamed from askbot/skins/common/media/images/flags/gs.gif)bin363 -> 363 bytes
-rwxr-xr-xaskbot/media/images/flags/gt.gif (renamed from askbot/skins/common/media/images/flags/gt.gif)bin374 -> 374 bytes
-rwxr-xr-xaskbot/media/images/flags/gu.gif (renamed from askbot/skins/common/media/images/flags/gu.gif)bin370 -> 370 bytes
-rwxr-xr-xaskbot/media/images/flags/gw.gif (renamed from askbot/skins/common/media/images/flags/gw.gif)bin358 -> 358 bytes
-rwxr-xr-xaskbot/media/images/flags/gy.gif (renamed from askbot/skins/common/media/images/flags/gy.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/hk.gif (renamed from askbot/skins/common/media/images/flags/hk.gif)bin373 -> 373 bytes
-rwxr-xr-xaskbot/media/images/flags/hm.gif (renamed from askbot/skins/common/media/images/flags/hm.gif)bin378 -> 378 bytes
-rwxr-xr-xaskbot/media/images/flags/hn.gif (renamed from askbot/skins/common/media/images/flags/hn.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/hr.gif (renamed from askbot/skins/common/media/images/flags/hr.gif)bin364 -> 364 bytes
-rwxr-xr-xaskbot/media/images/flags/ht.gif (renamed from askbot/skins/common/media/images/flags/ht.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/hu.gif (renamed from askbot/skins/common/media/images/flags/hu.gif)bin357 -> 357 bytes
-rwxr-xr-xaskbot/media/images/flags/id.gif (renamed from askbot/skins/common/media/images/flags/id.gif)bin362 -> 362 bytes
-rwxr-xr-xaskbot/media/images/flags/ie.gif (renamed from askbot/skins/common/media/images/flags/ie.gif)bin371 -> 371 bytes
-rwxr-xr-xaskbot/media/images/flags/il.gif (renamed from askbot/skins/common/media/images/flags/il.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/in.gif (renamed from askbot/skins/common/media/images/flags/in.gif)bin363 -> 363 bytes
-rwxr-xr-xaskbot/media/images/flags/io.gif (renamed from askbot/skins/common/media/images/flags/io.gif)bin373 -> 373 bytes
-rwxr-xr-xaskbot/media/images/flags/iq.gif (renamed from askbot/skins/common/media/images/flags/iq.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/ir.gif (renamed from askbot/skins/common/media/images/flags/ir.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/is.gif (renamed from askbot/skins/common/media/images/flags/is.gif)bin373 -> 373 bytes
-rwxr-xr-xaskbot/media/images/flags/it.gif (renamed from askbot/skins/common/media/images/flags/it.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/jm.gif (renamed from askbot/skins/common/media/images/flags/jm.gif)bin365 -> 365 bytes
-rwxr-xr-xaskbot/media/images/flags/jo.gif (renamed from askbot/skins/common/media/images/flags/jo.gif)bin360 -> 360 bytes
-rwxr-xr-xaskbot/media/images/flags/jp.gif (renamed from askbot/skins/common/media/images/flags/jp.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/ke.gif (renamed from askbot/skins/common/media/images/flags/ke.gif)bin360 -> 360 bytes
-rwxr-xr-xaskbot/media/images/flags/kg.gif (renamed from askbot/skins/common/media/images/flags/kg.gif)bin373 -> 373 bytes
-rwxr-xr-xaskbot/media/images/flags/kh.gif (renamed from askbot/skins/common/media/images/flags/kh.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/ki.gif (renamed from askbot/skins/common/media/images/flags/ki.gif)bin371 -> 371 bytes
-rwxr-xr-xaskbot/media/images/flags/km.gif (renamed from askbot/skins/common/media/images/flags/km.gif)bin358 -> 358 bytes
-rwxr-xr-xaskbot/media/images/flags/kn.gif (renamed from askbot/skins/common/media/images/flags/kn.gif)bin370 -> 370 bytes
-rwxr-xr-xaskbot/media/images/flags/kp.gif (renamed from askbot/skins/common/media/images/flags/kp.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/kr.gif (renamed from askbot/skins/common/media/images/flags/kr.gif)bin385 -> 385 bytes
-rwxr-xr-xaskbot/media/images/flags/kw.gif (renamed from askbot/skins/common/media/images/flags/kw.gif)bin362 -> 362 bytes
-rwxr-xr-xaskbot/media/images/flags/ky.gif (renamed from askbot/skins/common/media/images/flags/ky.gif)bin373 -> 373 bytes
-rwxr-xr-xaskbot/media/images/flags/kz.gif (renamed from askbot/skins/common/media/images/flags/kz.gif)bin374 -> 374 bytes
-rwxr-xr-xaskbot/media/images/flags/la.gif (renamed from askbot/skins/common/media/images/flags/la.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/lb.gif (renamed from askbot/skins/common/media/images/flags/lb.gif)bin366 -> 366 bytes
-rw-r--r--askbot/media/images/flags/lc.gif (renamed from askbot/skins/common/media/images/flags/lc.gif)bin259 -> 259 bytes
-rwxr-xr-xaskbot/media/images/flags/li.gif (renamed from askbot/skins/common/media/images/flags/li.gif)bin359 -> 359 bytes
-rwxr-xr-xaskbot/media/images/flags/lk.gif (renamed from askbot/skins/common/media/images/flags/lk.gif)bin377 -> 377 bytes
-rwxr-xr-xaskbot/media/images/flags/lr.gif (renamed from askbot/skins/common/media/images/flags/lr.gif)bin360 -> 360 bytes
-rwxr-xr-xaskbot/media/images/flags/ls.gif (renamed from askbot/skins/common/media/images/flags/ls.gif)bin369 -> 369 bytes
-rwxr-xr-xaskbot/media/images/flags/lt.gif (renamed from askbot/skins/common/media/images/flags/lt.gif)bin362 -> 362 bytes
-rwxr-xr-xaskbot/media/images/flags/lu.gif (renamed from askbot/skins/common/media/images/flags/lu.gif)bin368 -> 368 bytes
-rwxr-xr-xaskbot/media/images/flags/lv.gif (renamed from askbot/skins/common/media/images/flags/lv.gif)bin363 -> 363 bytes
-rwxr-xr-xaskbot/media/images/flags/ly.gif (renamed from askbot/skins/common/media/images/flags/ly.gif)bin362 -> 362 bytes
-rwxr-xr-xaskbot/media/images/flags/ma.gif (renamed from askbot/skins/common/media/images/flags/ma.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/mc.gif (renamed from askbot/skins/common/media/images/flags/mc.gif)bin359 -> 359 bytes
-rwxr-xr-xaskbot/media/images/flags/md.gif (renamed from askbot/skins/common/media/images/flags/md.gif)bin367 -> 367 bytes
-rw-r--r--askbot/media/images/flags/me.gif (renamed from askbot/skins/common/media/images/flags/me.gif)bin238 -> 238 bytes
-rwxr-xr-xaskbot/media/images/flags/mg.gif (renamed from askbot/skins/common/media/images/flags/mg.gif)bin372 -> 372 bytes
-rwxr-xr-xaskbot/media/images/flags/mh.gif (renamed from askbot/skins/common/media/images/flags/mh.gif)bin370 -> 370 bytes
-rwxr-xr-xaskbot/media/images/flags/mk.gif (renamed from askbot/skins/common/media/images/flags/mk.gif)bin382 -> 382 bytes
-rwxr-xr-xaskbot/media/images/flags/ml.gif (renamed from askbot/skins/common/media/images/flags/ml.gif)bin363 -> 363 bytes
-rwxr-xr-xaskbot/media/images/flags/mm.gif (renamed from askbot/skins/common/media/images/flags/mm.gif)bin365 -> 365 bytes
-rwxr-xr-xaskbot/media/images/flags/mn.gif (renamed from askbot/skins/common/media/images/flags/mn.gif)bin368 -> 368 bytes
-rwxr-xr-xaskbot/media/images/flags/mo.gif (renamed from askbot/skins/common/media/images/flags/mo.gif)bin378 -> 378 bytes
-rwxr-xr-xaskbot/media/images/flags/mp.gif (renamed from askbot/skins/common/media/images/flags/mp.gif)bin368 -> 368 bytes
-rwxr-xr-xaskbot/media/images/flags/mq.gif (renamed from askbot/skins/common/media/images/flags/mq.gif)bin379 -> 379 bytes
-rwxr-xr-xaskbot/media/images/flags/mr.gif (renamed from askbot/skins/common/media/images/flags/mr.gif)bin377 -> 377 bytes
-rwxr-xr-xaskbot/media/images/flags/ms.gif (renamed from askbot/skins/common/media/images/flags/ms.gif)bin371 -> 371 bytes
-rwxr-xr-xaskbot/media/images/flags/mt.gif (renamed from askbot/skins/common/media/images/flags/mt.gif)bin369 -> 369 bytes
-rwxr-xr-xaskbot/media/images/flags/mu.gif (renamed from askbot/skins/common/media/images/flags/mu.gif)bin358 -> 358 bytes
-rwxr-xr-xaskbot/media/images/flags/mv.gif (renamed from askbot/skins/common/media/images/flags/mv.gif)bin372 -> 372 bytes
-rwxr-xr-xaskbot/media/images/flags/mw.gif (renamed from askbot/skins/common/media/images/flags/mw.gif)bin364 -> 364 bytes
-rwxr-xr-xaskbot/media/images/flags/mx.gif (renamed from askbot/skins/common/media/images/flags/mx.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/my.gif (renamed from askbot/skins/common/media/images/flags/my.gif)bin375 -> 375 bytes
-rwxr-xr-xaskbot/media/images/flags/mz.gif (renamed from askbot/skins/common/media/images/flags/mz.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/na.gif (renamed from askbot/skins/common/media/images/flags/na.gif)bin371 -> 371 bytes
-rwxr-xr-xaskbot/media/images/flags/nc.gif (renamed from askbot/skins/common/media/images/flags/nc.gif)bin364 -> 364 bytes
-rwxr-xr-xaskbot/media/images/flags/ne.gif (renamed from askbot/skins/common/media/images/flags/ne.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/nf.gif (renamed from askbot/skins/common/media/images/flags/nf.gif)bin375 -> 375 bytes
-rwxr-xr-xaskbot/media/images/flags/ng.gif (renamed from askbot/skins/common/media/images/flags/ng.gif)bin371 -> 371 bytes
-rwxr-xr-xaskbot/media/images/flags/ni.gif (renamed from askbot/skins/common/media/images/flags/ni.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/nl.gif (renamed from askbot/skins/common/media/images/flags/nl.gif)bin360 -> 360 bytes
-rwxr-xr-xaskbot/media/images/flags/no.gif (renamed from askbot/skins/common/media/images/flags/no.gif)bin376 -> 376 bytes
-rwxr-xr-xaskbot/media/images/flags/np.gif (renamed from askbot/skins/common/media/images/flags/np.gif)bin302 -> 302 bytes
-rwxr-xr-xaskbot/media/images/flags/nr.gif (renamed from askbot/skins/common/media/images/flags/nr.gif)bin364 -> 364 bytes
-rwxr-xr-xaskbot/media/images/flags/nu.gif (renamed from askbot/skins/common/media/images/flags/nu.gif)bin369 -> 369 bytes
-rwxr-xr-xaskbot/media/images/flags/nz.gif (renamed from askbot/skins/common/media/images/flags/nz.gif)bin369 -> 369 bytes
-rwxr-xr-xaskbot/media/images/flags/om.gif (renamed from askbot/skins/common/media/images/flags/om.gif)bin364 -> 364 bytes
-rwxr-xr-xaskbot/media/images/flags/pa.gif (renamed from askbot/skins/common/media/images/flags/pa.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/pe.gif (renamed from askbot/skins/common/media/images/flags/pe.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/pf.gif (renamed from askbot/skins/common/media/images/flags/pf.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/pg.gif (renamed from askbot/skins/common/media/images/flags/pg.gif)bin360 -> 360 bytes
-rwxr-xr-xaskbot/media/images/flags/ph.gif (renamed from askbot/skins/common/media/images/flags/ph.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/pk.gif (renamed from askbot/skins/common/media/images/flags/pk.gif)bin377 -> 377 bytes
-rwxr-xr-xaskbot/media/images/flags/pl.gif (renamed from askbot/skins/common/media/images/flags/pl.gif)bin360 -> 360 bytes
-rwxr-xr-xaskbot/media/images/flags/pm.gif (renamed from askbot/skins/common/media/images/flags/pm.gif)bin374 -> 374 bytes
-rwxr-xr-xaskbot/media/images/flags/pn.gif (renamed from askbot/skins/common/media/images/flags/pn.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/pr.gif (renamed from askbot/skins/common/media/images/flags/pr.gif)bin369 -> 369 bytes
-rwxr-xr-xaskbot/media/images/flags/ps.gif (renamed from askbot/skins/common/media/images/flags/ps.gif)bin358 -> 358 bytes
-rwxr-xr-xaskbot/media/images/flags/pt.gif (renamed from askbot/skins/common/media/images/flags/pt.gif)bin369 -> 369 bytes
-rwxr-xr-xaskbot/media/images/flags/pw.gif (renamed from askbot/skins/common/media/images/flags/pw.gif)bin374 -> 374 bytes
-rwxr-xr-xaskbot/media/images/flags/py.gif (renamed from askbot/skins/common/media/images/flags/py.gif)bin363 -> 363 bytes
-rwxr-xr-xaskbot/media/images/flags/qa.gif (renamed from askbot/skins/common/media/images/flags/qa.gif)bin364 -> 364 bytes
-rwxr-xr-xaskbot/media/images/flags/re.gif (renamed from askbot/skins/common/media/images/flags/re.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/ro.gif (renamed from askbot/skins/common/media/images/flags/ro.gif)bin363 -> 363 bytes
-rw-r--r--askbot/media/images/flags/rs.gif (renamed from askbot/skins/common/media/images/flags/rs.gif)bin238 -> 238 bytes
-rwxr-xr-xaskbot/media/images/flags/ru.gif (renamed from askbot/skins/common/media/images/flags/ru.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/rw.gif (renamed from askbot/skins/common/media/images/flags/rw.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/sa.gif (renamed from askbot/skins/common/media/images/flags/sa.gif)bin370 -> 370 bytes
-rwxr-xr-xaskbot/media/images/flags/sb.gif (renamed from askbot/skins/common/media/images/flags/sb.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/sc.gif (renamed from askbot/skins/common/media/images/flags/sc.gif)bin357 -> 357 bytes
-rwxr-xr-xaskbot/media/images/flags/scotland.gif (renamed from askbot/skins/common/media/images/flags/scotland.gif)bin378 -> 378 bytes
-rwxr-xr-xaskbot/media/images/flags/sd.gif (renamed from askbot/skins/common/media/images/flags/sd.gif)bin355 -> 355 bytes
-rwxr-xr-xaskbot/media/images/flags/se.gif (renamed from askbot/skins/common/media/images/flags/se.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/sg.gif (renamed from askbot/skins/common/media/images/flags/sg.gif)bin364 -> 364 bytes
-rwxr-xr-xaskbot/media/images/flags/sh.gif (renamed from askbot/skins/common/media/images/flags/sh.gif)bin371 -> 371 bytes
-rwxr-xr-xaskbot/media/images/flags/si.gif (renamed from askbot/skins/common/media/images/flags/si.gif)bin362 -> 362 bytes
-rwxr-xr-xaskbot/media/images/flags/sj.gif (renamed from askbot/skins/common/media/images/flags/sj.gif)bin376 -> 376 bytes
-rwxr-xr-xaskbot/media/images/flags/sk.gif (renamed from askbot/skins/common/media/images/flags/sk.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/sl.gif (renamed from askbot/skins/common/media/images/flags/sl.gif)bin363 -> 363 bytes
-rwxr-xr-xaskbot/media/images/flags/sm.gif (renamed from askbot/skins/common/media/images/flags/sm.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/sn.gif (renamed from askbot/skins/common/media/images/flags/sn.gif)bin364 -> 364 bytes
-rwxr-xr-xaskbot/media/images/flags/so.gif (renamed from askbot/skins/common/media/images/flags/so.gif)bin376 -> 376 bytes
-rwxr-xr-xaskbot/media/images/flags/sr.gif (renamed from askbot/skins/common/media/images/flags/sr.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/st.gif (renamed from askbot/skins/common/media/images/flags/st.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/sv.gif (renamed from askbot/skins/common/media/images/flags/sv.gif)bin363 -> 363 bytes
-rwxr-xr-xaskbot/media/images/flags/sy.gif (renamed from askbot/skins/common/media/images/flags/sy.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/sz.gif (renamed from askbot/skins/common/media/images/flags/sz.gif)bin363 -> 363 bytes
-rwxr-xr-xaskbot/media/images/flags/tc.gif (renamed from askbot/skins/common/media/images/flags/tc.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/td.gif (renamed from askbot/skins/common/media/images/flags/td.gif)bin368 -> 368 bytes
-rwxr-xr-xaskbot/media/images/flags/tf.gif (renamed from askbot/skins/common/media/images/flags/tf.gif)bin365 -> 365 bytes
-rwxr-xr-xaskbot/media/images/flags/tg.gif (renamed from askbot/skins/common/media/images/flags/tg.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/th.gif (renamed from askbot/skins/common/media/images/flags/th.gif)bin360 -> 360 bytes
-rwxr-xr-xaskbot/media/images/flags/tj.gif (renamed from askbot/skins/common/media/images/flags/tj.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/tk.gif (renamed from askbot/skins/common/media/images/flags/tk.gif)bin372 -> 372 bytes
-rwxr-xr-xaskbot/media/images/flags/tl.gif (renamed from askbot/skins/common/media/images/flags/tl.gif)bin360 -> 360 bytes
-rwxr-xr-xaskbot/media/images/flags/tm.gif (renamed from askbot/skins/common/media/images/flags/tm.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/tn.gif (renamed from askbot/skins/common/media/images/flags/tn.gif)bin375 -> 375 bytes
-rwxr-xr-xaskbot/media/images/flags/to.gif (renamed from askbot/skins/common/media/images/flags/to.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/tr.gif (renamed from askbot/skins/common/media/images/flags/tr.gif)bin371 -> 371 bytes
-rwxr-xr-xaskbot/media/images/flags/tt.gif (renamed from askbot/skins/common/media/images/flags/tt.gif)bin377 -> 377 bytes
-rwxr-xr-xaskbot/media/images/flags/tv.gif (renamed from askbot/skins/common/media/images/flags/tv.gif)bin361 -> 361 bytes
-rwxr-xr-xaskbot/media/images/flags/tw.gif (renamed from askbot/skins/common/media/images/flags/tw.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/tz.gif (renamed from askbot/skins/common/media/images/flags/tz.gif)bin366 -> 366 bytes
-rwxr-xr-xaskbot/media/images/flags/ua.gif (renamed from askbot/skins/common/media/images/flags/ua.gif)bin360 -> 360 bytes
-rwxr-xr-xaskbot/media/images/flags/ug.gif (renamed from askbot/skins/common/media/images/flags/ug.gif)bin359 -> 359 bytes
-rwxr-xr-xaskbot/media/images/flags/um.gif (renamed from askbot/skins/common/media/images/flags/um.gif)bin371 -> 371 bytes
-rwxr-xr-xaskbot/media/images/flags/us.gif (renamed from askbot/skins/common/media/images/flags/us.gif)bin367 -> 367 bytes
-rwxr-xr-xaskbot/media/images/flags/uy.gif (renamed from askbot/skins/common/media/images/flags/uy.gif)bin373 -> 373 bytes
-rwxr-xr-xaskbot/media/images/flags/uz.gif (renamed from askbot/skins/common/media/images/flags/uz.gif)bin364 -> 364 bytes
-rwxr-xr-xaskbot/media/images/flags/va.gif (renamed from askbot/skins/common/media/images/flags/va.gif)bin369 -> 369 bytes
-rwxr-xr-xaskbot/media/images/flags/vc.gif (renamed from askbot/skins/common/media/images/flags/vc.gif)bin370 -> 370 bytes
-rwxr-xr-xaskbot/media/images/flags/ve.gif (renamed from askbot/skins/common/media/images/flags/ve.gif)bin364 -> 364 bytes
-rwxr-xr-xaskbot/media/images/flags/vg.gif (renamed from askbot/skins/common/media/images/flags/vg.gif)bin368 -> 368 bytes
-rwxr-xr-xaskbot/media/images/flags/vi.gif (renamed from askbot/skins/common/media/images/flags/vi.gif)bin376 -> 376 bytes
-rwxr-xr-xaskbot/media/images/flags/vn.gif (renamed from askbot/skins/common/media/images/flags/vn.gif)bin370 -> 370 bytes
-rwxr-xr-xaskbot/media/images/flags/vu.gif (renamed from askbot/skins/common/media/images/flags/vu.gif)bin365 -> 365 bytes
-rwxr-xr-xaskbot/media/images/flags/wales.gif (renamed from askbot/skins/common/media/images/flags/wales.gif)bin372 -> 372 bytes
-rwxr-xr-xaskbot/media/images/flags/wf.gif (renamed from askbot/skins/common/media/images/flags/wf.gif)bin377 -> 377 bytes
-rwxr-xr-xaskbot/media/images/flags/ws.gif (renamed from askbot/skins/common/media/images/flags/ws.gif)bin365 -> 365 bytes
-rwxr-xr-xaskbot/media/images/flags/ye.gif (renamed from askbot/skins/common/media/images/flags/ye.gif)bin356 -> 356 bytes
-rwxr-xr-xaskbot/media/images/flags/yt.gif (renamed from askbot/skins/common/media/images/flags/yt.gif)bin382 -> 382 bytes
-rwxr-xr-xaskbot/media/images/flags/za.gif (renamed from askbot/skins/common/media/images/flags/za.gif)bin363 -> 363 bytes
-rwxr-xr-xaskbot/media/images/flags/zm.gif (renamed from askbot/skins/common/media/images/flags/zm.gif)bin358 -> 358 bytes
-rwxr-xr-xaskbot/media/images/flags/zw.gif (renamed from askbot/skins/common/media/images/flags/zw.gif)bin365 -> 365 bytes
-rw-r--r--askbot/media/images/go-up-grey.png (renamed from askbot/skins/common/media/images/go-up-grey.png)bin563 -> 563 bytes
-rw-r--r--askbot/media/images/go-up-orange.png (renamed from askbot/skins/common/media/images/go-up-orange.png)bin586 -> 586 bytes
-rwxr-xr-xaskbot/media/images/gray-up-arrow-h18px.png (renamed from askbot/skins/common/media/images/gray-up-arrow-h18px.png)bin383 -> 383 bytes
-rwxr-xr-xaskbot/media/images/grippie.png (renamed from askbot/skins/common/media/images/grippie.png)bin162 -> 162 bytes
-rwxr-xr-xaskbot/media/images/indicator.gif (renamed from askbot/skins/common/media/images/indicator.gif)bin2545 -> 2545 bytes
-rw-r--r--askbot/media/images/link.png (renamed from askbot/skins/default/media/images/link.png)bin601 -> 601 bytes
-rw-r--r--askbot/media/images/logo.gif (renamed from askbot/skins/default/media/images/logo.gif)bin2249 -> 2249 bytes
-rw-r--r--askbot/media/images/logo.png (renamed from askbot/skins/common/media/images/logo.png)bin5841 -> 5841 bytes
-rwxr-xr-xaskbot/media/images/logo1.png (renamed from askbot/skins/common/media/images/logo1.png)bin2752 -> 2752 bytes
-rwxr-xr-xaskbot/media/images/logo2.png (renamed from askbot/skins/common/media/images/logo2.png)bin2124 -> 2124 bytes
-rw-r--r--askbot/media/images/mail-envelope-empty.png (renamed from askbot/skins/common/media/images/mail-envelope-empty.png)bin547 -> 547 bytes
-rw-r--r--askbot/media/images/mail-envelope-full.png (renamed from askbot/skins/common/media/images/mail-envelope-full.png)bin482 -> 482 bytes
-rwxr-xr-xaskbot/media/images/medala.gif (renamed from askbot/skins/common/media/images/medala.gif)bin801 -> 801 bytes
-rwxr-xr-xaskbot/media/images/medala_on.gif (renamed from askbot/skins/common/media/images/medala_on.gif)bin957 -> 957 bytes
-rw-r--r--askbot/media/images/medium-button.png (renamed from askbot/skins/default/media/images/medium-button.png)bin217 -> 217 bytes
-rwxr-xr-xaskbot/media/images/new.gif (renamed from askbot/skins/common/media/images/new.gif)bin635 -> 635 bytes
-rwxr-xr-xaskbot/media/images/nophoto.png (renamed from askbot/skins/common/media/images/nophoto.png)bin696 -> 696 bytes
-rw-r--r--askbot/media/images/notification.png (renamed from askbot/skins/default/media/images/notification.png)bin217 -> 217 bytes
-rwxr-xr-xaskbot/media/images/openid.gif (renamed from askbot/skins/common/media/images/openid.gif)bin910 -> 910 bytes
-rwxr-xr-xaskbot/media/images/openid/aol.gif (renamed from askbot/skins/common/media/images/openid/aol.gif)bin2205 -> 2205 bytes
-rwxr-xr-xaskbot/media/images/openid/blogger.ico (renamed from askbot/skins/common/media/images/openid/blogger.ico)bin3638 -> 3638 bytes
-rwxr-xr-xaskbot/media/images/openid/claimid.ico (renamed from askbot/skins/common/media/images/openid/claimid.ico)bin3638 -> 3638 bytes
-rwxr-xr-xaskbot/media/images/openid/facebook.gif (renamed from askbot/skins/common/media/images/openid/facebook.gif)bin2075 -> 2075 bytes
-rwxr-xr-xaskbot/media/images/openid/flickr.ico (renamed from askbot/skins/common/media/images/openid/flickr.ico)bin1150 -> 1150 bytes
-rwxr-xr-xaskbot/media/images/openid/google.gif (renamed from askbot/skins/common/media/images/openid/google.gif)bin1596 -> 1596 bytes
-rwxr-xr-xaskbot/media/images/openid/livejournal.ico (renamed from askbot/skins/common/media/images/openid/livejournal.ico)bin5222 -> 5222 bytes
-rwxr-xr-xaskbot/media/images/openid/myopenid.ico (renamed from askbot/skins/common/media/images/openid/myopenid.ico)bin2862 -> 2862 bytes
-rwxr-xr-xaskbot/media/images/openid/openid-inputicon.gif (renamed from askbot/skins/common/media/images/openid/openid-inputicon.gif)bin237 -> 237 bytes
-rwxr-xr-xaskbot/media/images/openid/openid.gif (renamed from askbot/skins/common/media/images/openid/openid.gif)bin740 -> 740 bytes
-rwxr-xr-xaskbot/media/images/openid/technorati.ico (renamed from askbot/skins/common/media/images/openid/technorati.ico)bin2294 -> 2294 bytes
-rwxr-xr-xaskbot/media/images/openid/twitter.png (renamed from askbot/skins/common/media/images/openid/twitter.png)bin3130 -> 3130 bytes
-rwxr-xr-xaskbot/media/images/openid/verisign.ico (renamed from askbot/skins/common/media/images/openid/verisign.ico)bin4710 -> 4710 bytes
-rwxr-xr-xaskbot/media/images/openid/vidoop.ico (renamed from askbot/skins/common/media/images/openid/vidoop.ico)bin1406 -> 1406 bytes
-rwxr-xr-xaskbot/media/images/openid/wordpress.ico (renamed from askbot/skins/common/media/images/openid/wordpress.ico)bin1150 -> 1150 bytes
-rwxr-xr-xaskbot/media/images/openid/yahoo.gif (renamed from askbot/skins/common/media/images/openid/yahoo.gif)bin1510 -> 1510 bytes
-rw-r--r--askbot/media/images/print.png (renamed from askbot/skins/common/media/images/print.png)bin1391 -> 1391 bytes
-rw-r--r--askbot/media/images/publish.pngbin0 -> 282 bytes
-rw-r--r--askbot/media/images/pw-login.gif (renamed from askbot/skins/common/media/images/pw-login.gif)bin1818 -> 1818 bytes
-rwxr-xr-xaskbot/media/images/quest-bg.gif (renamed from askbot/skins/common/media/images/quest-bg.gif)bin294 -> 294 bytes
-rw-r--r--askbot/media/images/retag.png (renamed from askbot/skins/default/media/images/retag.png)bin474 -> 474 bytes
-rw-r--r--askbot/media/images/scopearrow.png (renamed from askbot/skins/common/media/images/scopearrow.png)bin538 -> 538 bytes
-rw-r--r--askbot/media/images/small-button-blue.png (renamed from askbot/skins/default/media/images/small-button-blue.png)bin202 -> 202 bytes
-rw-r--r--askbot/media/images/small-button-cancel.png (renamed from askbot/skins/default/media/images/small-button-cancel.png)bin211 -> 211 bytes
-rw-r--r--askbot/media/images/socialsprite.png (renamed from askbot/skins/default/media/images/socialsprite.png)bin3030 -> 3030 bytes
-rw-r--r--askbot/media/images/sprite.png (renamed from askbot/skins/common/media/images/sprite.png)bin5325 -> 5325 bytes
-rw-r--r--askbot/media/images/sprites.pngbin0 -> 12478 bytes
-rw-r--r--askbot/media/images/sprites_source/graphics.svg (renamed from askbot/skins/default/media/images/sprites_source/graphics.svg)0
-rw-r--r--askbot/media/images/sprites_source/other.svg (renamed from askbot/skins/common/media/images/sprites_source/sprites.svg)0
-rw-r--r--askbot/media/images/sprites_source/sprites.svg519
-rw-r--r--askbot/media/images/summary-background.png (renamed from askbot/skins/default/media/images/summary-background.png)bin233 -> 233 bytes
-rw-r--r--askbot/media/images/tag-left.png (renamed from askbot/skins/default/media/images/tag-left.png)bin488 -> 488 bytes
-rw-r--r--askbot/media/images/tag-right.png (renamed from askbot/skins/default/media/images/tag-right.png)bin365 -> 365 bytes
-rw-r--r--askbot/media/images/tips.png (renamed from askbot/skins/default/media/images/tips.png)bin716 -> 716 bytes
-rw-r--r--askbot/media/images/unpublish.pngbin0 -> 294 bytes
-rw-r--r--askbot/media/images/view-background.png (renamed from askbot/skins/default/media/images/view-background.png)bin265 -> 265 bytes
-rwxr-xr-xaskbot/media/images/vote-accepted-on.png (renamed from askbot/skins/common/media/images/vote-accepted-on.png)bin1124 -> 1124 bytes
-rwxr-xr-xaskbot/media/images/vote-accepted.png (renamed from askbot/skins/common/media/images/vote-accepted.png)bin1058 -> 1058 bytes
-rw-r--r--askbot/media/images/vote-arrow-down-new.png (renamed from askbot/skins/default/media/images/vote-arrow-down-new.png)bin1458 -> 1458 bytes
-rw-r--r--askbot/media/images/vote-arrow-down-on-new.png (renamed from askbot/skins/default/media/images/vote-arrow-down-on-new.png)bin980 -> 980 bytes
-rwxr-xr-xaskbot/media/images/vote-arrow-down-on.png (renamed from askbot/skins/common/media/images/vote-arrow-down-on.png)bin905 -> 905 bytes
-rwxr-xr-xaskbot/media/images/vote-arrow-down.png (renamed from askbot/skins/common/media/images/vote-arrow-down.png)bin876 -> 876 bytes
-rw-r--r--askbot/media/images/vote-arrow-up-new.png (renamed from askbot/skins/default/media/images/vote-arrow-up-new.png)bin979 -> 979 bytes
-rw-r--r--askbot/media/images/vote-arrow-up-on-new.png (renamed from askbot/skins/default/media/images/vote-arrow-up-on-new.png)bin1029 -> 1029 bytes
-rwxr-xr-xaskbot/media/images/vote-arrow-up-on.png (renamed from askbot/skins/common/media/images/vote-arrow-up-on.png)bin906 -> 906 bytes
-rwxr-xr-xaskbot/media/images/vote-arrow-up.png (renamed from askbot/skins/common/media/images/vote-arrow-up.png)bin843 -> 843 bytes
-rw-r--r--askbot/media/images/vote-background.png (renamed from askbot/skins/default/media/images/vote-background.png)bin225 -> 225 bytes
-rwxr-xr-xaskbot/media/images/vote-favorite-off.png (renamed from askbot/skins/common/media/images/vote-favorite-off.png)bin930 -> 930 bytes
-rwxr-xr-xaskbot/media/images/vote-favorite-on.png (renamed from askbot/skins/common/media/images/vote-favorite-on.png)bin1023 -> 1023 bytes
-rw-r--r--askbot/media/images/wiki.png (renamed from askbot/skins/common/media/images/wiki.png)bin5178 -> 5178 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/aol.gif (renamed from askbot/skins/common/media/jquery-openid/images/aol.gif)bin1872 -> 1872 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/blogger-1.png (renamed from askbot/skins/common/media/jquery-openid/images/blogger-1.png)bin432 -> 432 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/blogger.ico (renamed from askbot/skins/common/media/jquery-openid/images/blogger.ico)bin3638 -> 3638 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/claimid-0.png (renamed from askbot/skins/common/media/jquery-openid/images/claimid-0.png)bin629 -> 629 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/claimid.ico (renamed from askbot/skins/common/media/jquery-openid/images/claimid.ico)bin3638 -> 3638 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/facebook.gif (renamed from askbot/skins/common/media/jquery-openid/images/facebook.gif)bin1737 -> 1737 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/flickr.ico (renamed from askbot/skins/common/media/jquery-openid/images/flickr.ico)bin1150 -> 1150 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/flickr.png (renamed from askbot/skins/common/media/jquery-openid/images/flickr.png)bin426 -> 426 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/google.gif (renamed from askbot/skins/common/media/jquery-openid/images/google.gif)bin1528 -> 1528 bytes
-rw-r--r--askbot/media/jquery-openid/images/identica.png (renamed from askbot/skins/common/media/jquery-openid/images/identica.png)bin6601 -> 6601 bytes
-rw-r--r--askbot/media/jquery-openid/images/linkedin.gif (renamed from askbot/skins/common/media/jquery-openid/images/linkedin.gif)bin1530 -> 1530 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/livejournal-1.png (renamed from askbot/skins/common/media/jquery-openid/images/livejournal-1.png)bin713 -> 713 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/livejournal.ico (renamed from askbot/skins/common/media/jquery-openid/images/livejournal.ico)bin5222 -> 5222 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/myopenid-2.png (renamed from askbot/skins/common/media/jquery-openid/images/myopenid-2.png)bin511 -> 511 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/myopenid.ico (renamed from askbot/skins/common/media/jquery-openid/images/myopenid.ico)bin2862 -> 2862 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/openid-inputicon.gif (renamed from askbot/skins/common/media/jquery-openid/images/openid-inputicon.gif)bin237 -> 237 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/openid.gif (renamed from askbot/skins/common/media/jquery-openid/images/openid.gif)bin1473 -> 1473 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/openidico.png (renamed from askbot/skins/common/media/jquery-openid/images/openidico.png)bin654 -> 654 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/openidico16.png (renamed from askbot/skins/common/media/jquery-openid/images/openidico16.png)bin554 -> 554 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/technorati-1.png (renamed from askbot/skins/common/media/jquery-openid/images/technorati-1.png)bin606 -> 606 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/technorati.ico (renamed from askbot/skins/common/media/jquery-openid/images/technorati.ico)bin2294 -> 2294 bytes
-rw-r--r--askbot/media/jquery-openid/images/twitter.gif (renamed from askbot/skins/common/media/jquery-openid/images/twitter.gif)bin1913 -> 1913 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/verisign-2.png (renamed from askbot/skins/common/media/jquery-openid/images/verisign-2.png)bin859 -> 859 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/verisign.ico (renamed from askbot/skins/common/media/jquery-openid/images/verisign.ico)bin4710 -> 4710 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/vidoop.ico (renamed from askbot/skins/common/media/jquery-openid/images/vidoop.ico)bin1406 -> 1406 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/vidoop.png (renamed from askbot/skins/common/media/jquery-openid/images/vidoop.png)bin499 -> 499 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/wordpress.ico (renamed from askbot/skins/common/media/jquery-openid/images/wordpress.ico)bin1150 -> 1150 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/wordpress.png (renamed from askbot/skins/common/media/jquery-openid/images/wordpress.png)bin566 -> 566 bytes
-rwxr-xr-xaskbot/media/jquery-openid/images/yahoo.gif (renamed from askbot/skins/common/media/jquery-openid/images/yahoo.gif)bin1607 -> 1607 bytes
-rw-r--r--askbot/media/jquery-openid/jquery.openid.js (renamed from askbot/skins/common/media/jquery-openid/jquery.openid.js)0
-rw-r--r--askbot/media/jquery-openid/openid.css (renamed from askbot/skins/common/media/jquery-openid/openid.css)0
-rw-r--r--askbot/media/js/autocompleter.js794
-rw-r--r--askbot/media/js/compress.bat (renamed from askbot/skins/common/media/js/compress.bat)0
-rw-r--r--askbot/media/js/editor.js80
-rw-r--r--askbot/media/js/excanvas.min.js (renamed from askbot/skins/common/media/js/excanvas.min.js)0
-rw-r--r--askbot/media/js/flot-build.bat (renamed from askbot/skins/common/media/js/flot-build.bat)0
-rw-r--r--askbot/media/js/group_messaging.js672
-rw-r--r--askbot/media/js/jquery-1.4.3.js (renamed from askbot/skins/common/media/js/jquery-1.4.3.js)0
-rw-r--r--askbot/media/js/jquery-1.7.2.min.js (renamed from askbot/skins/common/media/js/jquery-1.7.2.min.js)0
-rw-r--r--askbot/media/js/jquery-fieldselection.js (renamed from askbot/skins/common/media/js/jquery-fieldselection.js)0
-rw-r--r--askbot/media/js/jquery-fieldselection.min.js (renamed from askbot/skins/common/media/js/jquery-fieldselection.min.js)0
-rw-r--r--askbot/media/js/jquery.ajaxfileupload.js186
-rw-r--r--askbot/media/js/jquery.animate-colors.js (renamed from askbot/skins/common/media/js/jquery.animate-colors.js)0
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/ajax.txt6
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/10_b.jpgbin0 -> 39922 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/10_s.jpgbin0 -> 2725 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/11_b.jpgbin0 -> 39422 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/11_s.jpgbin0 -> 2548 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/12_b.jpgbin0 -> 39950 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/12_s.jpgbin0 -> 3109 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/1_b.jpgbin0 -> 30700 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/1_s.jpgbin0 -> 4258 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/2_b.jpgbin0 -> 44175 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/2_s.jpgbin0 -> 2929 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/3_b.jpgbin0 -> 36756 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/3_s.jpgbin0 -> 3720 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/4_b.jpgbin0 -> 44606 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/4_s.jpgbin0 -> 3840 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/5_b.jpgbin0 -> 44793 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/5_s.jpgbin0 -> 4208 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/6_b.jpgbin0 -> 52956 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/6_s.jpgbin0 -> 3552 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/7_b.jpgbin0 -> 47087 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/7_s.jpgbin0 -> 3644 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/8_b.jpgbin0 -> 40470 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/8_s.jpgbin0 -> 3020 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/9_b.jpgbin0 -> 51690 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/example/9_s.jpgbin0 -> 3226 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/blank.gifbin0 -> 43 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_close.pngbin0 -> 1517 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_loading.pngbin0 -> 10195 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_nav_left.pngbin0 -> 1446 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_nav_right.pngbin0 -> 1454 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_e.pngbin0 -> 107 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_n.pngbin0 -> 106 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_ne.pngbin0 -> 347 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_nw.pngbin0 -> 324 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_s.pngbin0 -> 111 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_se.pngbin0 -> 352 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_sw.pngbin0 -> 340 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_w.pngbin0 -> 103 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_title_left.pngbin0 -> 503 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_title_main.pngbin0 -> 96 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_title_over.pngbin0 -> 70 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_title_right.pngbin0 -> 506 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancybox-x.pngbin0 -> 203 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancybox-y.pngbin0 -> 176 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancybox.pngbin0 -> 15287 bytes
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.easing-1.3.pack.js72
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.fancybox-1.3.4.css359
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.fancybox-1.3.4.js1156
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.fancybox-1.3.4.pack.js46
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.mousewheel-3.0.4.pack.js14
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/index.html165
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/jquery-1.4.3.min.js166
-rw-r--r--askbot/media/js/jquery.fancybox-1.3.4/style.css65
-rw-r--r--askbot/media/js/jquery.flot.js (renamed from askbot/skins/common/media/js/jquery.flot.js)0
-rw-r--r--askbot/media/js/jquery.flot.min.js (renamed from askbot/skins/common/media/js/jquery.flot.min.js)0
-rw-r--r--askbot/media/js/jquery.form.js (renamed from askbot/skins/common/media/js/jquery.form.js)0
-rw-r--r--askbot/media/js/jquery.history.js (renamed from askbot/skins/common/media/js/jquery.history.js)0
-rw-r--r--askbot/media/js/jquery.i18n.js (renamed from askbot/skins/common/media/js/jquery.i18n.js)0
-rw-r--r--askbot/media/js/jquery.openid.js (renamed from askbot/skins/common/media/js/jquery.openid.js)0
-rw-r--r--askbot/media/js/jquery.validate.js (renamed from askbot/skins/common/media/js/jquery.validate.js)0
-rw-r--r--askbot/media/js/jquery.validate.min.js (renamed from askbot/skins/common/media/js/jquery.validate.min.js)0
-rw-r--r--askbot/media/js/jquery.validate.pack.js (renamed from askbot/skins/common/media/js/jquery.validate.pack.js)0
-rw-r--r--askbot/media/js/less.min.js (renamed from askbot/skins/common/media/js/less.min.js)0
-rw-r--r--askbot/media/js/live_search.js (renamed from askbot/skins/common/media/js/live_search.js)0
-rw-r--r--askbot/media/js/live_search_new_thread.js93
-rw-r--r--askbot/media/js/modernizr.custom.js (renamed from askbot/skins/common/media/js/modernizr.custom.js)0
-rw-r--r--askbot/media/js/output-words.html (renamed from askbot/skins/common/media/js/output-words.html)0
-rw-r--r--askbot/media/js/output-words.js (renamed from askbot/skins/common/media/js/output-words.js)0
-rw-r--r--askbot/media/js/post.js4081
-rw-r--r--askbot/media/js/se_hilite.js (renamed from askbot/skins/common/media/js/se_hilite.js)0
-rw-r--r--askbot/media/js/se_hilite_src.js (renamed from askbot/skins/common/media/js/se_hilite_src.js)0
-rw-r--r--askbot/media/js/tag_moderation.js217
-rw-r--r--askbot/media/js/tag_selector.js402
-rw-r--r--askbot/media/js/tinymce/langs/en.js1
-rw-r--r--askbot/media/js/tinymce/license.txt504
-rw-r--r--askbot/media/js/tinymce/plugins/advhr/css/advhr.css5
-rw-r--r--askbot/media/js/tinymce/plugins/advhr/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/advhr/editor_plugin_src.js57
-rw-r--r--askbot/media/js/tinymce/plugins/advhr/js/rule.js43
-rw-r--r--askbot/media/js/tinymce/plugins/advhr/langs/en_dlg.js1
-rw-r--r--askbot/media/js/tinymce/plugins/advhr/rule.htm58
-rw-r--r--askbot/media/js/tinymce/plugins/advimage/css/advimage.css13
-rw-r--r--askbot/media/js/tinymce/plugins/advimage/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/advimage/editor_plugin_src.js50
-rw-r--r--askbot/media/js/tinymce/plugins/advimage/image.htm235
-rw-r--r--askbot/media/js/tinymce/plugins/advimage/img/sample.gifbin0 -> 1624 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/advimage/js/image.js462
-rw-r--r--askbot/media/js/tinymce/plugins/advimage/langs/en_dlg.js1
-rw-r--r--askbot/media/js/tinymce/plugins/advlink/css/advlink.css8
-rw-r--r--askbot/media/js/tinymce/plugins/advlink/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/advlink/editor_plugin_src.js61
-rw-r--r--askbot/media/js/tinymce/plugins/advlink/js/advlink.js539
-rw-r--r--askbot/media/js/tinymce/plugins/advlink/langs/en_dlg.js1
-rw-r--r--askbot/media/js/tinymce/plugins/advlink/link.htm338
-rw-r--r--askbot/media/js/tinymce/plugins/advlist/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/advlist/editor_plugin_src.js176
-rw-r--r--askbot/media/js/tinymce/plugins/askbot_attachment/editor_plugin.js117
-rw-r--r--askbot/media/js/tinymce/plugins/askbot_attachment/langs/en.js3
-rw-r--r--askbot/media/js/tinymce/plugins/askbot_attachment/langs/en_dlg.js3
-rw-r--r--askbot/media/js/tinymce/plugins/askbot_imageuploader/editor_plugin.js117
-rw-r--r--askbot/media/js/tinymce/plugins/askbot_imageuploader/langs/en.js3
-rw-r--r--askbot/media/js/tinymce/plugins/askbot_imageuploader/langs/en_dlg.js3
-rw-r--r--askbot/media/js/tinymce/plugins/autolink/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/autolink/editor_plugin_src.js181
-rw-r--r--askbot/media/js/tinymce/plugins/autoresize/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/autoresize/editor_plugin_src.js119
-rw-r--r--askbot/media/js/tinymce/plugins/autosave/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/autosave/editor_plugin_src.js433
-rw-r--r--askbot/media/js/tinymce/plugins/autosave/langs/en.js4
-rw-r--r--askbot/media/js/tinymce/plugins/bbcode/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/bbcode/editor_plugin_src.js120
-rw-r--r--askbot/media/js/tinymce/plugins/contextmenu/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/contextmenu/editor_plugin_src.js161
-rw-r--r--askbot/media/js/tinymce/plugins/directionality/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/directionality/editor_plugin_src.js82
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/editor_plugin_src.js43
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/emotions.htm42
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/img/smiley-cool.gifbin0 -> 354 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/img/smiley-cry.gifbin0 -> 329 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/img/smiley-embarassed.gifbin0 -> 331 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/img/smiley-foot-in-mouth.gifbin0 -> 342 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/img/smiley-frown.gifbin0 -> 340 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/img/smiley-innocent.gifbin0 -> 336 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/img/smiley-kiss.gifbin0 -> 338 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/img/smiley-laughing.gifbin0 -> 343 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/img/smiley-money-mouth.gifbin0 -> 321 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/img/smiley-sealed.gifbin0 -> 323 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/img/smiley-smile.gifbin0 -> 344 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/img/smiley-surprised.gifbin0 -> 338 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/img/smiley-tongue-out.gifbin0 -> 328 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/img/smiley-undecided.gifbin0 -> 337 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/img/smiley-wink.gifbin0 -> 350 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/img/smiley-yell.gifbin0 -> 336 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/js/emotions.js43
-rw-r--r--askbot/media/js/tinymce/plugins/emotions/langs/en_dlg.js1
-rw-r--r--askbot/media/js/tinymce/plugins/example/dialog.htm22
-rw-r--r--askbot/media/js/tinymce/plugins/example/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/example/editor_plugin_src.js84
-rw-r--r--askbot/media/js/tinymce/plugins/example/img/example.gifbin0 -> 87 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/example/js/dialog.js19
-rw-r--r--askbot/media/js/tinymce/plugins/example/langs/en.js3
-rw-r--r--askbot/media/js/tinymce/plugins/example/langs/en_dlg.js3
-rw-r--r--askbot/media/js/tinymce/plugins/example_dependency/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/example_dependency/editor_plugin_src.js50
-rw-r--r--askbot/media/js/tinymce/plugins/fullpage/css/fullpage.css143
-rw-r--r--askbot/media/js/tinymce/plugins/fullpage/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/fullpage/editor_plugin_src.js405
-rw-r--r--askbot/media/js/tinymce/plugins/fullpage/fullpage.htm259
-rw-r--r--askbot/media/js/tinymce/plugins/fullpage/js/fullpage.js232
-rw-r--r--askbot/media/js/tinymce/plugins/fullpage/langs/en_dlg.js1
-rw-r--r--askbot/media/js/tinymce/plugins/fullscreen/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/fullscreen/editor_plugin_src.js159
-rw-r--r--askbot/media/js/tinymce/plugins/fullscreen/fullscreen.htm110
-rw-r--r--askbot/media/js/tinymce/plugins/iespell/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/iespell/editor_plugin_src.js54
-rw-r--r--askbot/media/js/tinymce/plugins/inlinepopups/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/inlinepopups/editor_plugin_src.js699
-rw-r--r--askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/alert.gifbin0 -> 810 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/button.gifbin0 -> 272 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gifbin0 -> 1195 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/confirm.gifbin0 -> 907 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/corners.gifbin0 -> 909 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gifbin0 -> 769 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/vertical.gifbin0 -> 84 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/window.css90
-rw-r--r--askbot/media/js/tinymce/plugins/inlinepopups/template.htm387
-rw-r--r--askbot/media/js/tinymce/plugins/insertdatetime/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/insertdatetime/editor_plugin_src.js83
-rw-r--r--askbot/media/js/tinymce/plugins/layer/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/layer/editor_plugin_src.js262
-rw-r--r--askbot/media/js/tinymce/plugins/legacyoutput/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/legacyoutput/editor_plugin_src.js139
-rw-r--r--askbot/media/js/tinymce/plugins/lists/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/lists/editor_plugin_src.js952
-rw-r--r--askbot/media/js/tinymce/plugins/media/css/media.css17
-rw-r--r--askbot/media/js/tinymce/plugins/media/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/media/editor_plugin_src.js890
-rw-r--r--askbot/media/js/tinymce/plugins/media/js/embed.js73
-rw-r--r--askbot/media/js/tinymce/plugins/media/js/media.js470
-rw-r--r--askbot/media/js/tinymce/plugins/media/langs/en_dlg.js1
-rw-r--r--askbot/media/js/tinymce/plugins/media/media.htm922
-rw-r--r--askbot/media/js/tinymce/plugins/media/moxieplayer.swfbin0 -> 19980 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/nonbreaking/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/nonbreaking/editor_plugin_src.js54
-rw-r--r--askbot/media/js/tinymce/plugins/noneditable/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/noneditable/editor_plugin_src.js540
-rw-r--r--askbot/media/js/tinymce/plugins/pagebreak/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/pagebreak/editor_plugin_src.js74
-rw-r--r--askbot/media/js/tinymce/plugins/paste/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/paste/editor_plugin_src.js871
-rw-r--r--askbot/media/js/tinymce/plugins/paste/js/pastetext.js36
-rw-r--r--askbot/media/js/tinymce/plugins/paste/js/pasteword.js51
-rw-r--r--askbot/media/js/tinymce/plugins/paste/langs/en_dlg.js1
-rw-r--r--askbot/media/js/tinymce/plugins/paste/pastetext.htm27
-rw-r--r--askbot/media/js/tinymce/plugins/paste/pasteword.htm21
-rw-r--r--askbot/media/js/tinymce/plugins/preview/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/preview/editor_plugin_src.js53
-rw-r--r--askbot/media/js/tinymce/plugins/preview/example.html28
-rw-r--r--askbot/media/js/tinymce/plugins/preview/jscripts/embed.js73
-rw-r--r--askbot/media/js/tinymce/plugins/preview/preview.html17
-rw-r--r--askbot/media/js/tinymce/plugins/print/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/print/editor_plugin_src.js34
-rw-r--r--askbot/media/js/tinymce/plugins/save/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/save/editor_plugin_src.js101
-rw-r--r--askbot/media/js/tinymce/plugins/searchreplace/css/searchreplace.css6
-rw-r--r--askbot/media/js/tinymce/plugins/searchreplace/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/searchreplace/editor_plugin_src.js61
-rw-r--r--askbot/media/js/tinymce/plugins/searchreplace/js/searchreplace.js142
-rw-r--r--askbot/media/js/tinymce/plugins/searchreplace/langs/en_dlg.js1
-rw-r--r--askbot/media/js/tinymce/plugins/searchreplace/searchreplace.htm100
-rw-r--r--askbot/media/js/tinymce/plugins/spellchecker/css/content.css1
-rw-r--r--askbot/media/js/tinymce/plugins/spellchecker/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/spellchecker/editor_plugin_src.js436
-rw-r--r--askbot/media/js/tinymce/plugins/spellchecker/img/wline.gifbin0 -> 46 bytes
-rw-r--r--askbot/media/js/tinymce/plugins/style/css/props.css14
-rw-r--r--askbot/media/js/tinymce/plugins/style/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/style/editor_plugin_src.js71
-rw-r--r--askbot/media/js/tinymce/plugins/style/js/props.js709
-rw-r--r--askbot/media/js/tinymce/plugins/style/langs/en_dlg.js1
-rw-r--r--askbot/media/js/tinymce/plugins/style/props.htm845
-rw-r--r--askbot/media/js/tinymce/plugins/style/readme.txt19
-rw-r--r--askbot/media/js/tinymce/plugins/tabfocus/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/tabfocus/editor_plugin_src.js122
-rw-r--r--askbot/media/js/tinymce/plugins/table/cell.htm180
-rw-r--r--askbot/media/js/tinymce/plugins/table/css/cell.css17
-rw-r--r--askbot/media/js/tinymce/plugins/table/css/row.css25
-rw-r--r--askbot/media/js/tinymce/plugins/table/css/table.css13
-rw-r--r--askbot/media/js/tinymce/plugins/table/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/table/editor_plugin_src.js1449
-rw-r--r--askbot/media/js/tinymce/plugins/table/js/cell.js319
-rw-r--r--askbot/media/js/tinymce/plugins/table/js/merge_cells.js27
-rw-r--r--askbot/media/js/tinymce/plugins/table/js/row.js237
-rw-r--r--askbot/media/js/tinymce/plugins/table/js/table.js501
-rw-r--r--askbot/media/js/tinymce/plugins/table/langs/en_dlg.js1
-rw-r--r--askbot/media/js/tinymce/plugins/table/merge_cells.htm32
-rw-r--r--askbot/media/js/tinymce/plugins/table/row.htm158
-rw-r--r--askbot/media/js/tinymce/plugins/table/table.htm188
-rw-r--r--askbot/media/js/tinymce/plugins/template/blank.htm12
-rw-r--r--askbot/media/js/tinymce/plugins/template/css/template.css23
-rw-r--r--askbot/media/js/tinymce/plugins/template/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/template/editor_plugin_src.js159
-rw-r--r--askbot/media/js/tinymce/plugins/template/js/template.js106
-rw-r--r--askbot/media/js/tinymce/plugins/template/langs/en_dlg.js1
-rw-r--r--askbot/media/js/tinymce/plugins/template/template.htm31
-rw-r--r--askbot/media/js/tinymce/plugins/visualblocks/css/visualblocks.css21
-rw-r--r--askbot/media/js/tinymce/plugins/visualblocks/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/visualblocks/editor_plugin_src.js63
-rw-r--r--askbot/media/js/tinymce/plugins/visualchars/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/visualchars/editor_plugin_src.js83
-rw-r--r--askbot/media/js/tinymce/plugins/wordcount/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/wordcount/editor_plugin_src.js122
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/abbr.htm142
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/acronym.htm142
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/attributes.htm149
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/cite.htm142
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/css/attributes.css11
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/css/popup.css9
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/del.htm162
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/editor_plugin.js1
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/editor_plugin_src.js132
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/ins.htm162
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/js/abbr.js28
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/js/acronym.js28
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/js/attributes.js111
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/js/cite.js28
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/js/del.js53
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/js/element_common.js229
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/js/ins.js53
-rw-r--r--askbot/media/js/tinymce/plugins/xhtmlxtras/langs/en_dlg.js1
-rw-r--r--askbot/media/js/tinymce/themes/advanced/about.htm52
-rw-r--r--askbot/media/js/tinymce/themes/advanced/anchor.htm26
-rw-r--r--askbot/media/js/tinymce/themes/advanced/charmap.htm55
-rw-r--r--askbot/media/js/tinymce/themes/advanced/color_picker.htm70
-rw-r--r--askbot/media/js/tinymce/themes/advanced/editor_template.js1
-rw-r--r--askbot/media/js/tinymce/themes/advanced/editor_template_src.js1487
-rw-r--r--askbot/media/js/tinymce/themes/advanced/image.htm80
-rw-r--r--askbot/media/js/tinymce/themes/advanced/img/colorpicker.jpgbin0 -> 2584 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/img/flash.gifbin0 -> 239 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/img/icons.gifbin0 -> 11982 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/img/iframe.gifbin0 -> 600 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/img/pagebreak.gifbin0 -> 325 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/img/quicktime.gifbin0 -> 301 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/img/realmedia.gifbin0 -> 439 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/img/shockwave.gifbin0 -> 384 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/img/trans.gifbin0 -> 43 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/img/video.gifbin0 -> 597 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/img/windowsmedia.gifbin0 -> 415 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/js/about.js73
-rw-r--r--askbot/media/js/tinymce/themes/advanced/js/anchor.js56
-rw-r--r--askbot/media/js/tinymce/themes/advanced/js/charmap.js363
-rw-r--r--askbot/media/js/tinymce/themes/advanced/js/color_picker.js345
-rw-r--r--askbot/media/js/tinymce/themes/advanced/js/image.js253
-rw-r--r--askbot/media/js/tinymce/themes/advanced/js/link.js159
-rw-r--r--askbot/media/js/tinymce/themes/advanced/js/source_editor.js78
-rw-r--r--askbot/media/js/tinymce/themes/advanced/langs/en.js1
-rw-r--r--askbot/media/js/tinymce/themes/advanced/langs/en_dlg.js1
-rw-r--r--askbot/media/js/tinymce/themes/advanced/link.htm57
-rw-r--r--askbot/media/js/tinymce/themes/advanced/shortcuts.htm47
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/default/content.css50
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/default/dialog.css118
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/default/img/buttons.pngbin0 -> 3133 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/default/img/items.gifbin0 -> 64 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/default/img/menu_arrow.gifbin0 -> 68 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/default/img/menu_check.gifbin0 -> 70 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/default/img/progress.gifbin0 -> 1787 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/default/img/tabs.gifbin0 -> 1322 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/default/ui.css219
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/highcontrast/content.css24
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/highcontrast/dialog.css106
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/highcontrast/ui.css106
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/o2k7/content.css48
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/o2k7/dialog.css118
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/o2k7/img/button_bg.pngbin0 -> 2766 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/o2k7/img/button_bg_black.pngbin0 -> 651 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/o2k7/img/button_bg_silver.pngbin0 -> 2084 bytes
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/o2k7/ui.css222
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/o2k7/ui_black.css8
-rw-r--r--askbot/media/js/tinymce/themes/advanced/skins/o2k7/ui_silver.css5
-rw-r--r--askbot/media/js/tinymce/themes/advanced/source_editor.htm25
-rw-r--r--askbot/media/js/tinymce/themes/simple/editor_template.js1
-rw-r--r--askbot/media/js/tinymce/themes/simple/editor_template_src.js84
-rw-r--r--askbot/media/js/tinymce/themes/simple/img/icons.gifbin0 -> 806 bytes
-rw-r--r--askbot/media/js/tinymce/themes/simple/langs/en.js1
-rw-r--r--askbot/media/js/tinymce/themes/simple/skins/default/content.css25
-rw-r--r--askbot/media/js/tinymce/themes/simple/skins/default/ui.css32
-rw-r--r--askbot/media/js/tinymce/themes/simple/skins/o2k7/content.css17
-rw-r--r--askbot/media/js/tinymce/themes/simple/skins/o2k7/img/button_bg.pngbin0 -> 5102 bytes
-rw-r--r--askbot/media/js/tinymce/themes/simple/skins/o2k7/ui.css35
-rw-r--r--askbot/media/js/tinymce/tiny_mce.js1
-rw-r--r--askbot/media/js/tinymce/tiny_mce_popup.js5
-rw-r--r--askbot/media/js/tinymce/tiny_mce_src.js18576
-rw-r--r--askbot/media/js/tinymce/utils/editable_selects.js70
-rw-r--r--askbot/media/js/tinymce/utils/form_utils.js210
-rw-r--r--askbot/media/js/tinymce/utils/mctabs.js162
-rw-r--r--askbot/media/js/tinymce/utils/validate.js252
-rw-r--r--askbot/media/js/user.js1014
-rw-r--r--askbot/media/js/utils.js2959
-rw-r--r--askbot/media/js/wmd/images/editor-toolbar-background.png (renamed from askbot/skins/common/media/js/wmd/images/editor-toolbar-background.png)bin282 -> 282 bytes
-rwxr-xr-xaskbot/media/js/wmd/images/wmd-buttons.png (renamed from askbot/skins/common/media/js/wmd/images/wmd-buttons.png)bin11480 -> 11480 bytes
-rw-r--r--askbot/media/js/wmd/showdown-min.js (renamed from askbot/skins/common/media/js/wmd/showdown-min.js)0
-rw-r--r--askbot/media/js/wmd/showdown.js (renamed from askbot/skins/common/media/js/wmd/showdown.js)0
-rw-r--r--askbot/media/js/wmd/wmd-min.js (renamed from askbot/skins/common/media/js/wmd/wmd-min.js)0
-rw-r--r--askbot/media/js/wmd/wmd-test.html (renamed from askbot/skins/common/media/js/wmd/wmd-test.html)0
-rw-r--r--askbot/media/js/wmd/wmd.css (renamed from askbot/skins/common/media/js/wmd/wmd.css)0
-rw-r--r--askbot/media/js/wmd/wmd.js2510
-rw-r--r--askbot/media/style/auth.css (renamed from askbot/skins/common/media/style/auth.css)0
-rw-r--r--askbot/media/style/jquery.autocomplete.css (renamed from askbot/skins/default/media/style/jquery.autocomplete.css)0
-rw-r--r--askbot/media/style/lib_style.css (renamed from askbot/skins/default/media/style/lib_style.css)0
-rw-r--r--askbot/media/style/lib_style.less101
-rw-r--r--askbot/media/style/openid.css (renamed from askbot/skins/common/media/style/openid.css)0
-rw-r--r--askbot/media/style/prettify.css27
-rw-r--r--askbot/media/style/style.css4114
-rw-r--r--askbot/media/style/style.less4005
-rw-r--r--askbot/media/style/tinymce/content.css58
-rw-r--r--askbot/middleware/forum_mode.py4
-rw-r--r--askbot/migrations/0001_initial.py26
-rw-r--r--askbot/migrations/0124_auto__add_field_post_is_private__add_field_replyaddress_reply_action.py7
-rw-r--r--askbot/migrations/0126_add_field__auth_user__is_fake.py19
-rw-r--r--askbot/migrations/0127_save_category_tree_as_json.py385
-rw-r--r--askbot/migrations/0128_add_groups_field__to__thread_and_post.py335
-rw-r--r--askbot/migrations/0129_auto__del_field_post_is_private.py322
-rw-r--r--askbot/migrations/0130_auto__del_field_postrevision_revision_type.py321
-rw-r--r--askbot/migrations/0131_auto__add_field_tag_status.py335
-rw-r--r--askbot/migrations/0132_auto__add_draftquestion__add_draftanswer.py356
-rw-r--r--askbot/migrations/0133_apply_global_group_to_posts_and_users.py453
-rw-r--r--askbot/migrations/0134_create_personal_groups_for_all_users.py378
-rw-r--r--askbot/migrations/0135_auto__add_questionwidget__add_askwidget.py393
-rw-r--r--askbot/migrations/0136_auto__add_group__add_threadtogroup__add_unique_threadtogroup_thread_ta.py417
-rw-r--r--askbot/migrations/0137_create_groups_from_relevant_tags.py447
-rw-r--r--askbot/migrations/0138_auto__del_groupprofile__del_groupmembership__del_unique_groupmembershi.py441
-rw-r--r--askbot/migrations/0139_add__openness__field_to_group.py359
-rw-r--r--askbot/migrations/0140_move_group_field__is_open__to_openness.py380
-rw-r--r--askbot/migrations/0141_auto__del_field_group_is_open.py358
-rw-r--r--askbot/migrations/0142_auto__add_groupmembership.py371
-rw-r--r--askbot/migrations/0143_populate_group_memberships.py378
-rw-r--r--askbot/migrations/0144_auto__add_field_questionwidget_group__add_field_askwidget_group.py384
-rw-r--r--askbot/migrations/0145_add_moderate_answers_to_enquirers__to_askbot_group.py378
-rw-r--r--askbot/migrations/0146_auto__add_field_threadtogroup_visibility.py379
-rw-r--r--askbot/migrations/0147_auto__add_field_group_description.py380
-rw-r--r--askbot/migrations/0148_rename_personal_groups.py405
-rw-r--r--askbot/migrations_api/__init__.py17
-rw-r--r--askbot/models/__init__.py481
-rw-r--r--askbot/models/base.py2
-rw-r--r--askbot/models/post.py608
-rw-r--r--askbot/models/question.py656
-rw-r--r--askbot/models/tag.py255
-rw-r--r--askbot/models/user.py230
-rw-r--r--askbot/models/widgets.py38
-rw-r--r--askbot/search/postgresql/thread_and_post_models_05222012.plsql225
-rw-r--r--askbot/search/postgresql/user_profile_search_08312012.plsql93
-rw-r--r--askbot/search/state_manager.py4
-rw-r--r--askbot/setup_templates/settings.py36
-rw-r--r--askbot/setup_templates/settings.py.mustache39
-rw-r--r--askbot/setup_templates/tinymce_sample_config.py27
-rw-r--r--askbot/skins/README4
-rwxr-xr-xaskbot/skins/common/media/images/close-small-dark.pngbin226 -> 0 bytes
-rw-r--r--askbot/skins/common/media/images/logo.gifbin3792 -> 0 bytes
-rw-r--r--askbot/skins/common/media/images/sprites.pngbin12545 -> 0 bytes
-rw-r--r--askbot/skins/common/media/images/summary-background.pngbin291 -> 0 bytes
-rw-r--r--askbot/skins/common/media/images/tag-left.pngbin290 -> 0 bytes
-rw-r--r--askbot/skins/common/media/images/tag-right.pngbin187 -> 0 bytes
-rw-r--r--askbot/skins/common/media/js/autocompleter.js766
-rw-r--r--askbot/skins/common/media/js/editor.js80
-rw-r--r--askbot/skins/common/media/js/jquery.ajaxfileupload.js195
-rw-r--r--askbot/skins/common/media/js/live_search_new_thread.js82
-rw-r--r--askbot/skins/common/media/js/post.js2418
-rw-r--r--askbot/skins/common/media/js/tag_selector.js394
-rw-r--r--askbot/skins/common/media/js/user.js854
-rw-r--r--askbot/skins/common/media/js/utils.js1268
-rw-r--r--askbot/skins/common/media/js/wmd/wmd.js2492
-rw-r--r--askbot/skins/common/media/style/jquery.autocomplete.css37
-rw-r--r--askbot/skins/common/media/style/lib_style.less38
-rw-r--r--askbot/skins/common/media/style/prettify.css27
-rw-r--r--askbot/skins/common/media/style/style.css2616
-rw-r--r--askbot/skins/common/templates/authopenid/complete.html71
-rw-r--r--askbot/skins/common/templates/authopenid/signin.html227
-rw-r--r--askbot/skins/common/templates/authopenid/signup_with_password.html64
-rw-r--r--askbot/skins/common/templates/question/answer_controls.html45
-rw-r--r--askbot/skins/common/templates/widgets/edit_post.html65
-rw-r--r--askbot/skins/default/media/bootstrap/css/bootstrap.css4635
-rw-r--r--askbot/skins/default/media/images/anon.pngbin687 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/bigbutton.pngbin263 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/bigbuttonhover.pngbin236 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/blue-up-arrow-h18px.pngbin593 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/box-arrow.gifbin69 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/bullet_green.gifbin64 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/cc-88x31.pngbin5460 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/cc-by-sa.pngbin5083 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/close-small-hover.pngbin337 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/close-small.pngbin293 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/contributorsback.pngbin714 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/dash.gifbin44 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/dialog-warning-off.pngbin419 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/dialog-warning.pngbin603 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/djangomade124x25_grey.gifbin2035 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/dot-g.gifbin61 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/dot-list.gifbin56 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/edit.pngbin758 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/expander-arrow-hide.gifbin126 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/expander-arrow-show.gifbin135 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/favicon.gifbin898 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/favicon.icobin1150 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/feed-icon-small.pngbin669 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/go-up-grey.pngbin563 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/go-up-orange.pngbin586 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/gray-up-arrow-h18px.pngbin383 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/grippie.pngbin162 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/indicator.gifbin2545 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/logo.pngbin5841 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/logo1.pngbin2752 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/logo2.pngbin2124 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/mail-envelope-empty.pngbin547 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/mail-envelope-full.pngbin482 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/medala.gifbin801 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/medala_on.gifbin957 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/new.gifbin635 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/nophoto.pngbin696 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/openid.gifbin910 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/print.pngbin1391 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/pw-login.gifbin1818 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/quest-bg.gifbin294 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/scopearrow.pngbin538 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/sprite.pngbin5325 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/sprites.pngbin12705 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/sprites_source/sprites.svg507
-rwxr-xr-xaskbot/skins/default/media/images/vote-accepted-on.pngbin1124 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/vote-accepted.pngbin1058 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/vote-arrow-down-on.pngbin905 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/vote-arrow-down.pngbin876 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/vote-arrow-up-on.pngbin906 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/vote-arrow-up.pngbin843 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/vote-favorite-off.pngbin930 -> 0 bytes
-rwxr-xr-xaskbot/skins/default/media/images/vote-favorite-on.pngbin1023 -> 0 bytes
-rw-r--r--askbot/skins/default/media/images/wiki.pngbin5178 -> 0 bytes
-rw-r--r--askbot/skins/default/media/style/auth.css48
-rw-r--r--askbot/skins/default/media/style/lib_style.less102
-rw-r--r--askbot/skins/default/media/style/openid.css45
-rw-r--r--askbot/skins/default/media/style/prettify.css27
-rw-r--r--askbot/skins/default/media/style/style.css3591
-rw-r--r--askbot/skins/default/media/style/style.less3513
-rw-r--r--askbot/skins/default/templates/500.html5
-rw-r--r--askbot/skins/default/templates/answer_edit.html85
-rw-r--r--askbot/skins/default/templates/ask.html67
-rw-r--r--askbot/skins/default/templates/base.html55
-rw-r--r--askbot/skins/default/templates/email/ask_for_signature.html11
-rw-r--r--askbot/skins/default/templates/email/insufficient_rep_to_post_by_email.html15
-rw-r--r--askbot/skins/default/templates/email/macros.html96
-rw-r--r--askbot/skins/default/templates/email/notify_author_about_approved_post.html21
-rw-r--r--askbot/skins/default/templates/email/post_as_subthread.html17
-rw-r--r--askbot/skins/default/templates/email/re_welcome_lamson_on.html7
-rw-r--r--askbot/skins/default/templates/email/welcome_lamson_on.html15
-rw-r--r--askbot/skins/default/templates/groups.html48
-rw-r--r--askbot/skins/default/templates/help.html33
-rw-r--r--askbot/skins/default/templates/instant_notification.html7
-rw-r--r--askbot/skins/default/templates/macros.html753
-rw-r--r--askbot/skins/default/templates/main_page/headline.html43
-rw-r--r--askbot/skins/default/templates/main_page/javascript.html30
-rw-r--r--askbot/skins/default/templates/main_page/questions_loop.html15
-rw-r--r--askbot/skins/default/templates/meta/bottom_scripts.html95
-rw-r--r--askbot/skins/default/templates/meta/editor_data.html15
-rw-r--r--askbot/skins/default/templates/meta/fonts.html20
-rw-r--r--askbot/skins/default/templates/meta/html_head_javascript.html21
-rw-r--r--askbot/skins/default/templates/meta/html_head_meta.html8
-rw-r--r--askbot/skins/default/templates/meta/html_head_stylesheets.html19
-rw-r--r--askbot/skins/default/templates/question.html194
-rw-r--r--askbot/skins/default/templates/question/answer_card.html29
-rw-r--r--askbot/skins/default/templates/question/content.html41
-rw-r--r--askbot/skins/default/templates/question/javascript.html100
-rw-r--r--askbot/skins/default/templates/question/new_answer_form.html52
-rw-r--r--askbot/skins/default/templates/question/question_card.html32
-rw-r--r--askbot/skins/default/templates/question/sidebar.html78
-rw-r--r--askbot/skins/default/templates/question_edit.html98
-rw-r--r--askbot/skins/default/templates/question_widget.html21
-rw-r--r--askbot/skins/default/templates/reopen.html39
-rw-r--r--askbot/skins/default/templates/revisions.html102
-rw-r--r--askbot/skins/default/templates/tags.html78
-rw-r--r--askbot/skins/default/templates/user_profile/reject_post_dialog.html108
-rw-r--r--askbot/skins/default/templates/user_profile/user.html46
-rw-r--r--askbot/skins/default/templates/user_profile/user_inbox.html99
-rw-r--r--askbot/skins/default/templates/user_profile/user_info.html105
-rw-r--r--askbot/skins/default/templates/user_profile/user_stats.html182
-rw-r--r--askbot/skins/default/templates/user_profile/users_questions.html8
-rw-r--r--askbot/skins/default/templates/users.html142
-rw-r--r--askbot/skins/default/templates/widgets/answer_edit_tips.html67
-rw-r--r--askbot/skins/default/templates/widgets/ask_button.html6
-rw-r--r--askbot/skins/default/templates/widgets/ask_form.html46
-rw-r--r--askbot/skins/default/templates/widgets/group_info.html82
-rw-r--r--askbot/skins/default/templates/widgets/meta_nav.html25
-rw-r--r--askbot/skins/default/templates/widgets/question_edit_tips.html63
-rw-r--r--askbot/skins/default/templates/widgets/question_summary.html57
-rw-r--r--askbot/skins/default/templates/widgets/user_list.html28
-rw-r--r--askbot/skins/default/templates/widgets/user_navigation.html25
-rw-r--r--askbot/skins/loaders.py20
-rw-r--r--askbot/skins/utils.py48
-rw-r--r--askbot/startup_procedures.py179
-rw-r--r--askbot/tasks.py141
-rw-r--r--askbot/templates/404.html (renamed from askbot/skins/default/templates/404.html)0
-rw-r--r--askbot/templates/404.jinja.html (renamed from askbot/skins/default/templates/404.jinja.html)0
-rw-r--r--askbot/templates/500.jinja.html (renamed from askbot/skins/default/templates/500.jinja.html)0
-rw-r--r--askbot/templates/answer_edit.html99
-rw-r--r--askbot/templates/ask.html83
-rw-r--r--askbot/templates/ask_by_widget.html16
-rw-r--r--askbot/templates/ask_widget_complete.html8
-rw-r--r--askbot/templates/authopenid/authopenid_macros.html (renamed from askbot/skins/common/templates/authopenid/authopenid_macros.html)0
-rw-r--r--askbot/templates/authopenid/changeemail.html (renamed from askbot/skins/common/templates/authopenid/changeemail.html)0
-rw-r--r--askbot/templates/authopenid/complete.html63
-rw-r--r--askbot/templates/authopenid/confirm_email.txt (renamed from askbot/skins/common/templates/authopenid/confirm_email.txt)0
-rw-r--r--askbot/templates/authopenid/email_validation.html20
-rw-r--r--askbot/templates/authopenid/email_validation.txt (renamed from askbot/skins/common/templates/authopenid/email_validation.txt)0
-rw-r--r--askbot/templates/authopenid/logout.html (renamed from askbot/skins/common/templates/authopenid/logout.html)0
-rw-r--r--askbot/templates/authopenid/providers_javascript.html (renamed from askbot/skins/common/templates/authopenid/providers_javascript.html)0
-rw-r--r--askbot/templates/authopenid/signin.html231
-rw-r--r--askbot/templates/authopenid/signup_with_password.html55
-rw-r--r--askbot/templates/authopenid/verify_email.html14
-rw-r--r--askbot/templates/authopenid/widget_signin.html231
-rw-r--r--askbot/templates/avatar/add.html (renamed from askbot/skins/common/templates/avatar/add.html)0
-rw-r--r--askbot/templates/avatar/change.html (renamed from askbot/skins/common/templates/avatar/change.html)0
-rw-r--r--askbot/templates/avatar/confirm_delete.html (renamed from askbot/skins/common/templates/avatar/confirm_delete.html)0
-rw-r--r--askbot/templates/badge.html (renamed from askbot/skins/default/templates/badge.html)0
-rw-r--r--askbot/templates/badges.html (renamed from askbot/skins/default/templates/badges.html)0
-rw-r--r--askbot/templates/base.html58
-rw-r--r--askbot/templates/close.html (renamed from askbot/skins/default/templates/close.html)0
-rw-r--r--askbot/templates/debug_header.html (renamed from askbot/skins/common/templates/debug_header.html)0
-rw-r--r--askbot/templates/django_error.html31
-rw-r--r--askbot/templates/email/accept_answer_reminder.html14
-rw-r--r--askbot/templates/email/ask_for_signature.html19
-rw-r--r--askbot/templates/email/base_mail.html183
-rw-r--r--askbot/templates/email/feedback_email.txt (renamed from askbot/skins/default/templates/email/feedback_email.txt)0
-rw-r--r--askbot/templates/email/footer.html (renamed from askbot/skins/default/templates/email/footer.html)0
-rw-r--r--askbot/templates/email/instant_notification.html18
-rw-r--r--askbot/templates/email/insufficient_rep_to_post_by_email.html20
-rw-r--r--askbot/templates/email/macros.html96
-rw-r--r--askbot/templates/email/notify_admins_about_new_tags.html8
-rw-r--r--askbot/templates/email/notify_author_about_approved_post.html30
-rw-r--r--askbot/templates/email/post_as_subthread.html18
-rw-r--r--askbot/templates/email/quoted_post.html (renamed from askbot/skins/default/templates/email/quoted_post.html)0
-rw-r--r--askbot/templates/email/re_welcome_lamson_on.html13
-rw-r--r--askbot/templates/email/rejected_post.html12
-rw-r--r--askbot/templates/email/reply_by_email_error.html (renamed from askbot/skins/default/templates/email/reply_by_email_error.html)0
-rw-r--r--askbot/templates/email/unanswered_question_reminder.html14
-rw-r--r--askbot/templates/email/welcome_lamson_off.html15
-rw-r--r--askbot/templates/email/welcome_lamson_on.html20
-rw-r--r--askbot/templates/embed/ask_by_widget.html225
-rw-r--r--askbot/templates/embed/ask_widget_complete.html8
-rwxr-xr-xaskbot/templates/embed/askbot_widget.css38
-rwxr-xr-xaskbot/templates/embed/askbot_widget.js74
-rw-r--r--askbot/templates/embed/delete_widget.html14
-rw-r--r--askbot/templates/embed/list_widgets.html45
-rw-r--r--askbot/templates/embed/question_widget.html20
-rw-r--r--askbot/templates/embed/widget_form.html23
-rw-r--r--askbot/templates/embed/widgets.html36
-rw-r--r--askbot/templates/faq_static.html (renamed from askbot/skins/default/templates/faq_static.html)0
-rw-r--r--askbot/templates/feedback.html (renamed from askbot/skins/default/templates/feedback.html)0
-rw-r--r--askbot/templates/group_messaging/home.html14
-rw-r--r--askbot/templates/group_messaging/macros.html16
-rw-r--r--askbot/templates/group_messaging/senders_list.html14
-rw-r--r--askbot/templates/group_messaging/stored_message.html2
-rw-r--r--askbot/templates/group_messaging/thread_details.html7
-rw-r--r--askbot/templates/group_messaging/threads_list.html18
-rw-r--r--askbot/templates/groups.html58
-rw-r--r--askbot/templates/help.html57
-rw-r--r--askbot/templates/import_data.html (renamed from askbot/skins/default/templates/import_data.html)0
-rw-r--r--askbot/templates/list_suggested_tags.html67
-rw-r--r--askbot/templates/macros.html782
-rw-r--r--askbot/templates/main_page.html (renamed from askbot/skins/default/templates/main_page.html)0
-rw-r--r--askbot/templates/main_page/content.html (renamed from askbot/skins/default/templates/main_page/content.html)0
-rw-r--r--askbot/templates/main_page/headline.html41
-rw-r--r--askbot/templates/main_page/javascript.html51
-rw-r--r--askbot/templates/main_page/nothing_found.html (renamed from askbot/skins/default/templates/main_page/nothing_found.html)0
-rw-r--r--askbot/templates/main_page/paginator.html (renamed from askbot/skins/default/templates/main_page/paginator.html)0
-rw-r--r--askbot/templates/main_page/questions_loop.html13
-rw-r--r--askbot/templates/main_page/sidebar.html (renamed from askbot/skins/default/templates/main_page/sidebar.html)0
-rw-r--r--askbot/templates/main_page/tab_bar.html (renamed from askbot/skins/default/templates/main_page/tab_bar.html)0
-rw-r--r--askbot/templates/main_page/tag_search.html (renamed from askbot/skins/default/templates/main_page/tag_search.html)0
-rw-r--r--askbot/templates/meta/bottom_scripts.html98
-rw-r--r--askbot/templates/meta/category_tree_js.html26
-rw-r--r--askbot/templates/meta/editor_data.html16
-rw-r--r--askbot/templates/meta/fonts.html8
-rw-r--r--askbot/templates/meta/html_head_javascript.html34
-rw-r--r--askbot/templates/meta/html_head_stylesheets.html26
-rw-r--r--askbot/templates/meta/mandatory_tags_js.html (renamed from askbot/skins/default/templates/meta/mandatory_tags_js.html)0
-rw-r--r--askbot/templates/meta/tinymce_css.html20
-rw-r--r--askbot/templates/one_column_body.html (renamed from askbot/skins/common/templates/one_column_body.html)0
-rw-r--r--askbot/templates/question.html245
-rw-r--r--askbot/templates/question/answer_author_info.html (renamed from askbot/skins/common/templates/question/answer_author_info.html)0
-rw-r--r--askbot/templates/question/answer_card.html32
-rw-r--r--askbot/templates/question/answer_comments.html (renamed from askbot/skins/common/templates/question/answer_comments.html)0
-rw-r--r--askbot/templates/question/answer_controls.html69
-rw-r--r--askbot/templates/question/answer_tab_bar.html (renamed from askbot/skins/default/templates/question/answer_tab_bar.html)0
-rw-r--r--askbot/templates/question/answer_vote_buttons.html (renamed from askbot/skins/common/templates/question/answer_vote_buttons.html)0
-rw-r--r--askbot/templates/question/closed_question_info.html (renamed from askbot/skins/common/templates/question/closed_question_info.html)0
-rw-r--r--askbot/templates/question/content.html49
-rw-r--r--askbot/templates/question/javascript.html110
-rw-r--r--askbot/templates/question/new_answer_form.html59
-rw-r--r--askbot/templates/question/question_author_info.html (renamed from askbot/skins/common/templates/question/question_author_info.html)0
-rw-r--r--askbot/templates/question/question_card.html38
-rw-r--r--askbot/templates/question/question_comments.html (renamed from askbot/skins/common/templates/question/question_comments.html)0
-rw-r--r--askbot/templates/question/question_controls.html (renamed from askbot/skins/common/templates/question/question_controls.html)0
-rw-r--r--askbot/templates/question/question_tags.html (renamed from askbot/skins/common/templates/question/question_tags.html)0
-rw-r--r--askbot/templates/question/question_vote_buttons.html (renamed from askbot/skins/common/templates/question/question_vote_buttons.html)0
-rw-r--r--askbot/templates/question/share_buttons.html (renamed from askbot/skins/common/templates/question/share_buttons.html)0
-rw-r--r--askbot/templates/question/sharing_prompt_phrase.html (renamed from askbot/skins/default/templates/question/sharing_prompt_phrase.html)0
-rw-r--r--askbot/templates/question/sidebar.html176
-rw-r--r--askbot/templates/question/subscribe_by_email_prompt.html (renamed from askbot/skins/default/templates/question/subscribe_by_email_prompt.html)0
-rw-r--r--askbot/templates/question_edit.html114
-rw-r--r--askbot/templates/question_retag.html (renamed from askbot/skins/default/templates/question_retag.html)0
-rw-r--r--askbot/templates/reopen.html39
-rw-r--r--askbot/templates/revisions.html101
-rw-r--r--askbot/templates/static_page.html (renamed from askbot/skins/default/templates/static_page.html)0
-rw-r--r--askbot/templates/subscribe_for_tags.html (renamed from askbot/skins/default/templates/subscribe_for_tags.html)0
-rw-r--r--askbot/templates/tags.html55
-rw-r--r--askbot/templates/tags/header.html38
-rw-r--r--askbot/templates/two_column_body.html (renamed from askbot/skins/common/templates/two_column_body.html)0
-rw-r--r--askbot/templates/user_inbox/base.html65
-rw-r--r--askbot/templates/user_inbox/group_join_requests.html50
-rw-r--r--askbot/templates/user_inbox/messages.html100
-rw-r--r--askbot/templates/user_inbox/responses_and_flags.html43
-rw-r--r--askbot/templates/user_profile/custom_tab.html (renamed from askbot/skins/default/templates/user_profile/custom_tab.html)0
-rw-r--r--askbot/templates/user_profile/macros.html (renamed from askbot/skins/default/templates/user_profile/macros.html)0
-rw-r--r--askbot/templates/user_profile/reject_post_dialog.html109
-rw-r--r--askbot/templates/user_profile/user.html46
-rw-r--r--askbot/templates/user_profile/user_edit.html (renamed from askbot/skins/default/templates/user_profile/user_edit.html)0
-rw-r--r--askbot/templates/user_profile/user_email_subscriptions.html (renamed from askbot/skins/default/templates/user_profile/user_email_subscriptions.html)0
-rw-r--r--askbot/templates/user_profile/user_favorites.html (renamed from askbot/skins/default/templates/user_profile/user_favorites.html)0
-rw-r--r--askbot/templates/user_profile/user_info.html121
-rw-r--r--askbot/templates/user_profile/user_moderate.html (renamed from askbot/skins/default/templates/user_profile/user_moderate.html)0
-rw-r--r--askbot/templates/user_profile/user_network.html (renamed from askbot/skins/default/templates/user_profile/user_network.html)0
-rw-r--r--askbot/templates/user_profile/user_recent.html (renamed from askbot/skins/default/templates/user_profile/user_recent.html)0
-rw-r--r--askbot/templates/user_profile/user_reputation.html (renamed from askbot/skins/default/templates/user_profile/user_reputation.html)0
-rw-r--r--askbot/templates/user_profile/user_stats.html165
-rw-r--r--askbot/templates/user_profile/user_tabs.html (renamed from askbot/skins/default/templates/user_profile/user_tabs.html)0
-rw-r--r--askbot/templates/user_profile/user_votes.html (renamed from askbot/skins/default/templates/user_profile/user_votes.html)0
-rw-r--r--askbot/templates/user_profile/users_questions.html14
-rw-r--r--askbot/templates/users.html146
-rw-r--r--askbot/templates/widget_base.html22
-rw-r--r--askbot/templates/widgets/answer_edit_tips.html27
-rw-r--r--askbot/templates/widgets/ask_button.html9
-rw-r--r--askbot/templates/widgets/ask_form.html52
-rw-r--r--askbot/templates/widgets/contributors.html (renamed from askbot/skins/default/templates/widgets/contributors.html)0
-rw-r--r--askbot/templates/widgets/edit_post.html115
-rw-r--r--askbot/templates/widgets/footer.html (renamed from askbot/skins/default/templates/widgets/footer.html)0
-rw-r--r--askbot/templates/widgets/group_info.html103
-rw-r--r--askbot/templates/widgets/group_snippet.html (renamed from askbot/skins/default/templates/widgets/group_snippet.html)0
-rw-r--r--askbot/templates/widgets/groups_list.html4
-rw-r--r--askbot/templates/widgets/header.html (renamed from askbot/skins/default/templates/widgets/header.html)0
-rw-r--r--askbot/templates/widgets/logo.html (renamed from askbot/skins/default/templates/widgets/logo.html)0
-rw-r--r--askbot/templates/widgets/markdown_help.html42
-rw-r--r--askbot/templates/widgets/meta_nav.html28
-rw-r--r--askbot/templates/widgets/question_edit_tips.html22
-rw-r--r--askbot/templates/widgets/question_summary.html59
-rw-r--r--askbot/templates/widgets/related_tags.html (renamed from askbot/skins/common/templates/widgets/related_tags.html)0
-rw-r--r--askbot/templates/widgets/scope_nav.html (renamed from askbot/skins/default/templates/widgets/scope_nav.html)0
-rw-r--r--askbot/templates/widgets/search_bar.html (renamed from askbot/skins/common/templates/widgets/search_bar.html)0
-rw-r--r--askbot/templates/widgets/secondary_header.html (renamed from askbot/skins/default/templates/widgets/secondary_header.html)0
-rw-r--r--askbot/templates/widgets/system_messages.html (renamed from askbot/skins/default/templates/widgets/system_messages.html)0
-rw-r--r--askbot/templates/widgets/tag_category_selector.html3
-rw-r--r--askbot/templates/widgets/tag_editor.html31
-rw-r--r--askbot/templates/widgets/tag_selector.html (renamed from askbot/skins/common/templates/widgets/tag_selector.html)0
-rw-r--r--askbot/templates/widgets/three_column_category_selector.html22
-rw-r--r--askbot/templates/widgets/user_list.html28
-rw-r--r--askbot/templates/widgets/user_long_score_and_badge_summary.html (renamed from askbot/skins/default/templates/widgets/user_long_score_and_badge_summary.html)0
-rw-r--r--askbot/templates/widgets/user_navigation.html26
-rw-r--r--askbot/templates/widgets/user_score_and_badge_summary.html (renamed from askbot/skins/default/templates/widgets/user_score_and_badge_summary.html)0
-rw-r--r--askbot/templatetags/extra_filters_jinja.py13
-rw-r--r--askbot/tests/__init__.py9
-rw-r--r--askbot/tests/badge_tests.py10
-rw-r--r--askbot/tests/cache_tests.py17
-rw-r--r--askbot/tests/category_tree_tests.py134
-rw-r--r--askbot/tests/db_api_tests.py240
-rw-r--r--askbot/tests/email_alert_tests.py93
-rw-r--r--askbot/tests/email_parsing_tests.py25
-rw-r--r--askbot/tests/form_tests.py49
-rw-r--r--askbot/tests/haystack_search_tests.py2
-rw-r--r--askbot/tests/management_command_tests.py2
-rw-r--r--askbot/tests/misc_tests.py76
-rw-r--r--askbot/tests/page_load_tests.py137
-rw-r--r--askbot/tests/permission_assertion_tests.py14
-rw-r--r--askbot/tests/post_model_tests.py137
-rw-r--r--askbot/tests/reply_by_email_tests.py21
-rw-r--r--askbot/tests/templatefilter_tests.py21
-rw-r--r--askbot/tests/thread_model_tests.py129
-rw-r--r--askbot/tests/user_model_tests.py17
-rw-r--r--askbot/tests/utils.py118
-rw-r--r--askbot/tests/utils_tests.py57
-rw-r--r--askbot/tests/view_context_tests.py30
-rw-r--r--askbot/tests/widget_tests.py169
-rw-r--r--askbot/urls.py253
-rw-r--r--askbot/utils/category_tree.py149
-rw-r--r--askbot/utils/console.py30
-rw-r--r--askbot/utils/decorators.py1
-rw-r--r--askbot/utils/forms.py114
-rw-r--r--askbot/utils/html.py27
-rw-r--r--askbot/utils/slug.py71
-rw-r--r--askbot/utils/url_utils.py33
-rw-r--r--askbot/views/__init__.py1
-rw-r--r--askbot/views/commands.py649
-rw-r--r--askbot/views/context.py52
-rw-r--r--askbot/views/meta.py67
-rw-r--r--askbot/views/readers.py131
-rw-r--r--askbot/views/users.py175
-rw-r--r--askbot/views/widgets.py274
-rw-r--r--askbot/views/writers.py215
-rw-r--r--askbot_requirements.txt3
-rw-r--r--group_messaging/__init__.py14
-rw-r--r--group_messaging/migrations/0001_initial.py177
-rw-r--r--group_messaging/migrations/0002_auto__add_lastvisittime__add_unique_lastvisittime_user_message__add_fi.py142
-rw-r--r--group_messaging/migrations/__init__.py (renamed from askbot/db)0
-rw-r--r--group_messaging/models.py249
-rw-r--r--group_messaging/tests.py118
-rw-r--r--group_messaging/urls.py32
-rw-r--r--group_messaging/views.py214
1209 files changed, 95670 insertions, 29678 deletions
diff --git a/.gitignore b/.gitignore
index 08e42e57..425fd569 100755
--- a/.gitignore
+++ b/.gitignore
@@ -48,3 +48,4 @@ recaptcha
/.ve
/db.sq3
*.DS_Store
+htmlcov
diff --git a/askbot/__init__.py b/askbot/__init__.py
index 859b2695..3107c689 100644
--- a/askbot/__init__.py
+++ b/askbot/__init__.py
@@ -5,9 +5,7 @@ Functions in the askbot module perform various
basic actions on behalf of the forum application
"""
import os
-import smtplib
-import sys
-import logging
+import platform
VERSION = (0, 7, 43)
@@ -33,27 +31,34 @@ REQUIREMENTS = {
'recaptcha_works': 'django-recaptcha-works',
'openid': 'python-openid',
'pystache': 'pystache==0.3.1',
- 'lamson': 'Lamson',
'pytz': 'pytz',
+ 'tinymce': 'django-tinymce',
+ 'longerusername': 'longerusername',
+ 'bs4': 'beautifulsoup4'
}
+if platform.system() != 'Windows':
+ REQUIREMENTS['lamson'] = 'Lamson'
+
#necessary for interoperability of django and coffin
try:
from askbot import patches
from askbot.deployment.assertions import assert_package_compatibility
assert_package_compatibility()
patches.patch_django()
- patches.patch_coffin()#must go after django
+ patches.patch_coffin() # must go after django
except ImportError:
pass
+
def get_install_directory():
"""returns path to directory
- where code of the askbot django application
+ where code of the askbot django application
is installed
"""
return os.path.dirname(__file__)
+
def get_path_to(relative_path):
"""returns absolute path to a file
relative to ``askbot`` directory
@@ -72,10 +77,11 @@ def get_version():
"""
return '.'.join([str(subversion) for subversion in VERSION])
+
def get_database_engine_name():
"""returns name of the database engine,
independently of the version of django
- - for django >=1.2 looks into ``settings.DATABASES['default']``,
+ - for django >=1.2 looks into ``settings.DATABASES['default']``,
(i.e. assumes that askbot uses database named 'default')
, and for django 1.1 and below returns settings.DATABASE_ENGINE
"""
diff --git a/askbot/api.py b/askbot/api.py
index 57d5c1aa..9f37995e 100644
--- a/askbot/api.py
+++ b/askbot/api.py
@@ -9,7 +9,7 @@ from askbot import models
from askbot import const
def get_info_on_moderation_items(user):
- """returns a dictionary with
+ """returns a dictionary with
counts of new and seen moderation items for a given user
if user is not a moderator or admin, returns None
"""
@@ -48,7 +48,7 @@ def get_admin(seed_user_id = None):
if the user is not found, or there are no moderators/admins
User.DoesNotExist will be raised
-
+
The reason this function is here and not on a manager of
the user object is because we still patch the django-auth User table
and it's probably better not to patch the manager
diff --git a/askbot/conf/__init__.py b/askbot/conf/__init__.py
index 8378fca3..3e80877c 100644
--- a/askbot/conf/__init__.py
+++ b/askbot/conf/__init__.py
@@ -26,7 +26,6 @@ import askbot.conf.badges
import askbot.conf.login_providers
import askbot.conf.access_control
import askbot.conf.site_modes
-import askbot.conf.widgets
#import main settings object
from askbot.conf.settings_wrapper import settings
@@ -37,3 +36,11 @@ def should_show_sort_by_relevance():
questions by search relevance
"""
return ('postgresql_psycopg2' in askbot.get_database_engine_name())
+
+def get_tag_display_filter_strategy_choices():
+ from askbot import const
+ from askbot.conf import settings as askbot_settings
+ if askbot_settings.SUBSCRIBED_TAG_SELECTOR_ENABLED:
+ return const.TAG_DISPLAY_FILTER_STRATEGY_CHOICES
+ else:
+ return const.TAG_DISPLAY_FILTER_STRATEGY_MINIMAL_CHOICES
diff --git a/askbot/conf/access_control.py b/askbot/conf/access_control.py
index cd2364b5..5da88936 100644
--- a/askbot/conf/access_control.py
+++ b/askbot/conf/access_control.py
@@ -13,9 +13,45 @@ settings.register(
livesettings.BooleanValue(
ACCESS_CONTROL,
'ASKBOT_CLOSED_FORUM_MODE',
- default = False,
+ default=False,
description=_('Allow only registered user to access the forum'),
)
)
+EMAIL_VALIDATION_CASE_CHOICES = (
+ ('nothing', _('nothing - not required')),
+ ('see-content', _('access to content')),
+ #'post-content', _('posting content'),
+)
+
+settings.register(
+ livesettings.StringValue(
+ ACCESS_CONTROL,
+ 'REQUIRE_VALID_EMAIL_FOR',
+ default='nothing',
+ choices=EMAIL_VALIDATION_CASE_CHOICES,
+ description=_(
+ 'Require valid email for'
+ )
+ )
+)
+settings.register(
+ livesettings.LongStringValue(
+ ACCESS_CONTROL,
+ 'ALLOWED_EMAILS',
+ default='',
+ description=_('Allowed email addresses'),
+ help_text=_('Please use space to separate the entries')
+ )
+)
+
+settings.register(
+ livesettings.LongStringValue(
+ ACCESS_CONTROL,
+ 'ALLOWED_EMAIL_DOMAINS',
+ default='',
+ description=_('Allowed email domain names'),
+ help_text=_('Please use space to separate the entries, do not use the @ symbol!')
+ )
+)
diff --git a/askbot/conf/email.py b/askbot/conf/email.py
index 1b81fa96..9330e638 100644
--- a/askbot/conf/email.py
+++ b/askbot/conf/email.py
@@ -66,7 +66,7 @@ settings.register(
livesettings.StringValue(
EMAIL,
'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_Q_ASK',
- default='w',
+ default='i',
choices=const.NOTIFICATION_DELIVERY_SCHEDULE_CHOICES,
description=_('Default notification frequency questions asked by the user'),
help_text=_(
@@ -80,7 +80,7 @@ settings.register(
livesettings.StringValue(
EMAIL,
'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_Q_ANS',
- default='w',
+ default='d',
choices=const.NOTIFICATION_DELIVERY_SCHEDULE_CHOICES,
description=_('Default notification frequency questions answered by the user'),
help_text=_(
@@ -94,7 +94,7 @@ settings.register(
livesettings.StringValue(
EMAIL,
'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_Q_SEL',
- default='w',
+ default='i',
choices=const.NOTIFICATION_DELIVERY_SCHEDULE_CHOICES,
description=_('Default notification frequency questions individually \
selected by the user'),
@@ -109,7 +109,7 @@ settings.register(
livesettings.StringValue(
EMAIL,
'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_M_AND_C',
- default='w',
+ default='i',
choices=const.NOTIFICATION_DELIVERY_SCHEDULE_CHOICES,
description=_('Default notification frequency for mentions \
and comments'),
diff --git a/askbot/conf/flatpages.py b/askbot/conf/flatpages.py
index 62413797..543da67d 100644
--- a/askbot/conf/flatpages.py
+++ b/askbot/conf/flatpages.py
@@ -51,3 +51,14 @@ settings.register(
)
)
)
+
+#todo: merge this with mandatory tags
+settings.register(#this field is not editable manually
+ LongStringValue(
+ FLATPAGES,
+ 'CATEGORY_TREE',
+ description = 'Category tree',#no need to translate
+ default = '',#empty array of arrays in json
+ #hidden = True
+ )
+)
diff --git a/askbot/conf/forum_data_rules.py b/askbot/conf/forum_data_rules.py
index a26aa4b3..46a1fe08 100644
--- a/askbot/conf/forum_data_rules.py
+++ b/askbot/conf/forum_data_rules.py
@@ -13,6 +13,21 @@ FORUM_DATA_RULES = livesettings.ConfigurationGroup(
super_group = DATA_AND_FORMATTING
)
+EDITOR_CHOICES = (
+ ('markdown', 'markdown'),
+ ('tinymce', 'WISYWIG (tinymce)')
+)
+
+settings.register(
+ livesettings.StringValue(
+ FORUM_DATA_RULES,
+ 'EDITOR_TYPE',
+ default = 'markdown',
+ choices = EDITOR_CHOICES,
+ description = _('Editor for the posts')
+ )
+)
+
settings.register(
livesettings.BooleanValue(
FORUM_DATA_RULES,
@@ -122,6 +137,17 @@ settings.register(
settings.register(
livesettings.BooleanValue(
FORUM_DATA_RULES,
+ 'LIMIT_ONE_ANSWER_PER_USER',
+ default = True,
+ description = _(
+ 'Limit one answer per question per user'
+ )
+ )
+)
+
+settings.register(
+ livesettings.BooleanValue(
+ FORUM_DATA_RULES,
'TAGS_ARE_REQUIRED',
description = _('Are tags required?'),
default = False,
@@ -129,6 +155,36 @@ settings.register(
)
settings.register(
+ livesettings.BooleanValue(
+ FORUM_DATA_RULES,
+ 'ENABLE_TAG_MODERATION',
+ default = False,
+ description = _('Enable tag moderation'),
+ help_text = _(
+ 'If enabled, any new tags will not be applied '
+ 'to the questions, but emailed to the moderators. '
+ 'To use this feature, tags must be optional.'
+ )
+ )
+)
+
+TAG_SOURCE_CHOICES = (
+ ('category-tree', _('category tree')),
+ ('user-input', _('user input')),
+)
+
+settings.register(
+ livesettings.StringValue(
+ FORUM_DATA_RULES,
+ 'TAG_SOURCE',
+ description = _('Source of tags'),
+ #hidden = True,
+ choices = TAG_SOURCE_CHOICES,
+ default = 'user-input'
+ )
+)
+
+settings.register(
livesettings.StringValue(
FORUM_DATA_RULES,
'MANDATORY_TAGS',
diff --git a/askbot/conf/group_settings.py b/askbot/conf/group_settings.py
index b3c0069c..2933b831 100644
--- a/askbot/conf/group_settings.py
+++ b/askbot/conf/group_settings.py
@@ -19,6 +19,31 @@ settings.register(
)
)
+def group_name_update_callback(old_name, new_name):
+ from askbot.models.tag import get_global_group, clean_group_name
+ cleaned_new_name = clean_group_name(new_name.strip())
+
+ if new_name == '':
+ #name cannot be empty
+ return old_name
+
+ group = get_global_group()
+ group.name = cleaned_new_name
+ group.save()
+ return new_name
+
+
+settings.register(
+ livesettings.StringValue(
+ GROUP_SETTINGS,
+ 'GLOBAL_GROUP_NAME',
+ default = _('everyone'),
+ description = _('Global user group name'),
+ help_text = _('All users belong to this group automatically'),
+ update_callback=group_name_update_callback
+ )
+)
+
settings.register(
livesettings.BooleanValue(
GROUP_SETTINGS,
diff --git a/askbot/conf/ldap.py b/askbot/conf/ldap.py
index 077ff792..5c37adb1 100644
--- a/askbot/conf/ldap.py
+++ b/askbot/conf/ldap.py
@@ -20,6 +20,39 @@ settings.register(
)
settings.register(
+ livesettings.BooleanValue(
+ LDAP_SETTINGS,
+ 'LDAP_AUTOCREATE_USERS',
+ description = _('Automatically create user accounts when possible'),
+ default = False,
+ help_text = _(
+ 'Potentially reduces number of steps in the registration process '
+ 'but can expose personal information, e.g. when LDAP login name is '
+ 'the same as email address or real name.'
+ )
+ )
+)
+
+LDAP_PROTOCOL_VERSION_CHOICES = (
+ ('3', _('Version 3')),
+ ('2', _('Version 2 (insecure and deprecated)!!!'))
+)
+
+settings.register(
+ livesettings.StringValue(
+ LDAP_SETTINGS,
+ 'LDAP_PROTOCOL_VERSION',
+ default = '3',
+ choices = LDAP_PROTOCOL_VERSION_CHOICES,
+ description = _('LDAP protocol version'),
+ help_text = _(
+ 'Note that Version 2 protocol is not secure!!! '
+ 'Do not use it on unprotected network.'
+ )
+ )
+)
+
+settings.register(
livesettings.StringValue(
LDAP_SETTINGS,
'LDAP_URL',
@@ -31,35 +64,110 @@ settings.register(
settings.register(
livesettings.StringValue(
LDAP_SETTINGS,
- 'LDAP_BASEDN',
- description=_('LDAP BASE DN')
+ 'LDAP_ENCODING',
+ description = _('LDAP encoding'),
+ default = 'utf-8',
+ help_text = _(
+ 'This value in almost all cases is "utf-8". '
+ 'Change it if yours is different. '
+ 'This field is required'
+ )
+ )
+)
+
+settings.register(
+ livesettings.StringValue(
+ LDAP_SETTINGS,
+ 'LDAP_BASE_DN',
+ description=_('Base DN (distinguished name)'),
+ default = '',
+ help_text = _(
+ 'Usually base DN mirrors domain name of your organization, '
+ 'e.g. "dn=example,dn=com" when your site url is "example.com".'
+ 'This value is the "root" address of your LDAP directory.'
+ )
)
)
settings.register(
livesettings.StringValue(
LDAP_SETTINGS,
- 'LDAP_SEARCH_SCOPE',
- description=_('LDAP Search Scope'),
- default="subs"
+ 'LDAP_USER_FILTER_TEMPLATE',
+ description = _('User search filter template'),
+ default = '(%s=%s)',
+ help_text = _(
+ 'Python string format template, must have two string placeholders, '
+ 'which should be left in the intact format. '
+ 'First placeholder will be used for the user id field name, '
+ 'and the second - for the user id value. '
+ 'The template can be extended to match schema of your '
+ 'LDAP directory.'
+ )
+ )
+)
+
+settings.register(
+ livesettings.StringValue(
+ LDAP_SETTINGS,
+ 'LDAP_LOGIN_NAME_FIELD',
+ description = _('UserID/login field'),
+ default = 'uid',
+ help_text = _(
+ 'This field is required. '
+ 'For Microsoft Active Directory this value usually '
+ 'is "sAMAccountName".'
+ )
+ )
+)
+
+settings.register(
+ livesettings.StringValue(
+ LDAP_SETTINGS,
+ 'LDAP_COMMON_NAME_FIELD',
+ description=_('"Common Name" field'),
+ help_text=_(
+ 'Common name is a formal or informal name '
+ 'of a person, can be blank. '
+ 'Use it only if surname and given names are not '
+ 'available.'
+ ),
+ default = 'cn'
+ )
+)
+
+COMMON_NAME_FIELD_FORMAT_CHOICES = (
+ ('first,last', _('First name, Last name')),
+ ('last,first', _('Last name, First name')),
+)
+
+settings.register(
+ livesettings.StringValue(
+ LDAP_SETTINGS,
+ 'LDAP_COMMON_NAME_FIELD_FORMAT',
+ description = _('"Common Name" field format'),
+ default = 'first,last',
+ choices = COMMON_NAME_FIELD_FORMAT_CHOICES,
+ help_text = _('Use this only if "Common Name" field is used.')
)
)
settings.register(
livesettings.StringValue(
LDAP_SETTINGS,
- 'LDAP_USERID_FIELD',
- description=_('LDAP Server USERID field name'),
- default="uid"
+ 'LDAP_GIVEN_NAME_FIELD',
+ description = _('Given (First) name'),
+ default = 'givenName',
+ help_text = _('This field can be blank')
)
)
settings.register(
livesettings.StringValue(
LDAP_SETTINGS,
- 'LDAP_COMMONNAME_FIELD',
- description=_('LDAP Server "Common Name" field name'),
- default="cn"
+ 'LDAP_SURNAME_FIELD',
+ description = _('Surname (last) name'),
+ default = 'sn',
+ help_text = _('This field can be blank')
)
)
@@ -67,8 +175,9 @@ settings.register(
livesettings.StringValue(
LDAP_SETTINGS,
'LDAP_EMAIL_FIELD',
- description=_('LDAP Server EMAIL field name'),
- default="mail"
+ description = _('LDAP Server EMAIL field name'),
+ default = 'mail',
+ help_text = _('This field is required')
)
)
diff --git a/askbot/conf/minimum_reputation.py b/askbot/conf/minimum_reputation.py
index 54ba0f65..2c3a3496 100644
--- a/askbot/conf/minimum_reputation.py
+++ b/askbot/conf/minimum_reputation.py
@@ -181,7 +181,6 @@ settings.register(
)
)
-
settings.register(
livesettings.IntegerValue(
MIN_REP,
@@ -190,3 +189,16 @@ settings.register(
description=_('Post answers and comments by email')
)
)
+
+settings.register(
+ livesettings.IntegerValue(
+ MIN_REP,
+ 'MIN_REP_TO_TRIGGER_EMAIL',
+ default=15,
+ description=_('Trigger email notifications'),
+ help_text=_(
+ 'Reduces spam as notifications wont\'t be sent '
+ 'to regular users for posts of low karma users'
+ )
+ )
+)
diff --git a/askbot/conf/moderation.py b/askbot/conf/moderation.py
index 9f8e24c7..8e77385f 100644
--- a/askbot/conf/moderation.py
+++ b/askbot/conf/moderation.py
@@ -4,8 +4,16 @@ from askbot.conf.settings_wrapper import settings
from askbot.conf.super_groups import DATA_AND_FORMATTING
from askbot.deps.livesettings import ConfigurationGroup
from askbot.deps.livesettings import BooleanValue
+from django.core.cache import cache
from django.utils.translation import ugettext as _
+def empty_cache_callback(old_value, new_value):
+ """used to clear cache on change of certain values"""
+ if old_value != new_value:
+ #todo: change this to warmup cache
+ cache.clear()
+ return new_value
+
MODERATION = ConfigurationGroup(
'MODERATION',
_('Content moderation'),
@@ -18,5 +26,6 @@ settings.register(
'ENABLE_CONTENT_MODERATION',
default = False,
description = _('Enable content moderation'),
+ update_callback = empty_cache_callback
)
)
diff --git a/askbot/conf/user_settings.py b/askbot/conf/user_settings.py
index 9077a720..adbdd5ff 100644
--- a/askbot/conf/user_settings.py
+++ b/askbot/conf/user_settings.py
@@ -16,6 +16,24 @@ USER_SETTINGS = livesettings.ConfigurationGroup(
)
settings.register(
+ livesettings.LongStringValue(
+ USER_SETTINGS,
+ 'NEW_USER_GREETING',
+ default='',
+ description=_('On-screen greeting shown to the new users')
+ )
+)
+
+settings.register(
+ livesettings.BooleanValue(
+ USER_SETTINGS,
+ 'ALLOW_ANONYMOUS_FEEDBACK',
+ default=True,
+ description=_('Allow anonymous users send feedback')
+ )
+)
+
+settings.register(
livesettings.BooleanValue(
USER_SETTINGS,
'EDITABLE_SCREEN_NAME',
@@ -27,6 +45,16 @@ settings.register(
settings.register(
livesettings.BooleanValue(
USER_SETTINGS,
+ 'AUTOFILL_USER_DATA',
+ default = True,
+ description = _('Auto-fill user name, email, etc on registration'),
+ help_text = _('Implemented only for LDAP logins at this point')
+ )
+)
+
+settings.register(
+ livesettings.BooleanValue(
+ USER_SETTINGS,
'EDITABLE_EMAIL',
default = True,
description = _('Allow users change own email addresses')
@@ -36,6 +64,15 @@ settings.register(
settings.register(
livesettings.BooleanValue(
USER_SETTINGS,
+ 'ALLOW_EMAIL_ADDRESS_IN_USERNAME',
+ default=True,
+ description=_('Allow email address in user name')
+ )
+)
+
+settings.register(
+ livesettings.BooleanValue(
+ USER_SETTINGS,
'ALLOW_ACCOUNT_RECOVERY_BY_EMAIL',
default = True,
description = _('Allow account recovery by email')
diff --git a/askbot/conf/widgets.py b/askbot/conf/widgets.py
deleted file mode 100644
index d704ea12..00000000
--- a/askbot/conf/widgets.py
+++ /dev/null
@@ -1,99 +0,0 @@
-"""
-Settings for embeddable widgets
-"""
-from django.utils.translation import ugettext as _
-from django.utils.html import escape
-from askbot.conf.settings_wrapper import settings
-from askbot.deps.livesettings import ConfigurationGroup
-from askbot.deps.livesettings import values
-from askbot.conf.super_groups import CONTENT_AND_UI
-
-EMBEDDABLE_WIDGETS = ConfigurationGroup(
- 'EMBEDDABLE_WIDGETS',
- _('Embeddable widgets'),
- super_group = CONTENT_AND_UI
-)
-
-#we need better capabilities for the settings here
-#
-
-settings.register(
- values.IntegerValue(
- EMBEDDABLE_WIDGETS,
- 'QUESTIONS_WIDGET_MAX_QUESTIONS',
- default = 7,
- description = _('Number of questions to show'),
- help_text = escape(
- _(
- 'To embed the widget, add the following code '
- 'to your site (and fill in correct base url, preferred tags, width and height):'
- '<iframe '
- 'src="{{base_url}}/widgets/questions?tags={{comma-separated-tags}}" '
- 'width="100%" '
- 'height="300"'
- 'scrolling="no">'
- '<p>Your browser does not support iframes.</p>'
- '</iframe>'
- )
- )
- )
-)
-settings.register(
- values.LongStringValue(
- EMBEDDABLE_WIDGETS,
- 'QUESTIONS_WIDGET_CSS',
- default = """
-body {
- overflow: hidden;
-}
-#container {
- width: 200px;
- height: 350px;
-}
-ul {
- list-style: none;
- padding: 5px;
- margin: 5px;
-}
-li {
- border-bottom: #CCC 1px solid;
- padding-bottom: 5px;
- padding-top: 5px;
-}
-li:last-child {
- border: none;
-}
-a {
- text-decoration: none;
- color: #464646;
- font-family: 'Yanone Kaffeesatz', sans-serif;
- font-size: 15px;
-}
-""",
- descripton = _('CSS for the questions widget')
- )
-)
-
-settings.register(
- values.LongStringValue(
- EMBEDDABLE_WIDGETS,
- 'QUESTIONS_WIDGET_HEADER',
- description = _('Header for the questions widget'),
- default = ''
- )
-)
-
-settings.register(
- values.LongStringValue(
- EMBEDDABLE_WIDGETS,
- 'QUESTIONS_WIDGET_FOOTER',
- description = _('Footer for the questions widget'),
- default = """
-<link
- href='http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700'
- rel='stylesheet'
- type='text/css'
->
-"""
- )
-)
diff --git a/askbot/const/__init__.py b/askbot/const/__init__.py
index e693a63c..5f47bb79 100644
--- a/askbot/const/__init__.py
+++ b/askbot/const/__init__.py
@@ -139,11 +139,13 @@ UNANSWERED_QUESTION_MEANING_CHOICES = (
#however it will be hard to expect that people will type
#correct regexes - plus this must be an anchored regex
#to do full string match
+#IMPRTANT: tag related regexes must be portable between js and python
TAG_CHARS = r'\w+.#-'
TAG_REGEX_BARE = r'[%s]+' % TAG_CHARS
TAG_REGEX = r'^%s$' % TAG_REGEX_BARE
TAG_SPLIT_REGEX = r'[ ,]+'
TAG_SEP = ',' # has to be valid TAG_SPLIT_REGEX char and MUST NOT be in const.TAG_CHARS
+#!!! see const.message_keys.TAG_WRONG_CHARS_MESSAGE
EMAIL_REGEX = re.compile(r'\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b', re.I)
TYPE_ACTIVITY_ASK_QUESTION = 1
@@ -174,6 +176,8 @@ TYPE_ACTIVITY_MODERATED_POST_EDIT = 25
TYPE_ACTIVITY_CREATE_REJECT_REASON = 26
TYPE_ACTIVITY_UPDATE_REJECT_REASON = 27
TYPE_ACTIVITY_VALIDATION_EMAIL_SENT = 28
+TYPE_ACTIVITY_POST_SHARED = 29
+TYPE_ACTIVITY_ASK_TO_JOIN_GROUP = 30
#TYPE_ACTIVITY_EDIT_QUESTION = 17
#TYPE_ACTIVITY_EDIT_ANSWER = 18
@@ -197,6 +201,7 @@ TYPE_ACTIVITY = (
(TYPE_ACTIVITY_FAVORITE, _('selected favorite')),
(TYPE_ACTIVITY_USER_FULL_UPDATED, _('completed user profile')),
(TYPE_ACTIVITY_EMAIL_UPDATE_SENT, _('email update sent to user')),
+ (TYPE_ACTIVITY_POST_SHARED, _('a post was shared')),
(
TYPE_ACTIVITY_UNANSWERED_REMINDER_SENT,
_('reminder about unanswered questions sent'),
@@ -242,6 +247,7 @@ RESPONSE_ACTIVITY_TYPES_FOR_INSTANT_NOTIFICATIONS = (
TYPE_ACTIVITY_UPDATE_QUESTION,
TYPE_ACTIVITY_ANSWER,
TYPE_ACTIVITY_ASK_QUESTION,
+ TYPE_ACTIVITY_POST_SHARED
)
@@ -254,6 +260,7 @@ RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY = (
TYPE_ACTIVITY_COMMENT_ANSWER,
TYPE_ACTIVITY_UPDATE_ANSWER,
TYPE_ACTIVITY_UPDATE_QUESTION,
+ TYPE_ACTIVITY_POST_SHARED,
# TYPE_ACTIVITY_PRIZE,
# TYPE_ACTIVITY_MARK_ANSWER,
# TYPE_ACTIVITY_VOTE_UP,
@@ -265,15 +272,15 @@ RESPONSE_ACTIVITY_TYPES_FOR_DISPLAY = (
# TYPE_ACTIVITY_FAVORITE,
)
-
RESPONSE_ACTIVITY_TYPE_MAP_FOR_TEMPLATES = {
- TYPE_ACTIVITY_COMMENT_QUESTION: 'question_comment',
- TYPE_ACTIVITY_COMMENT_ANSWER: 'answer_comment',
- TYPE_ACTIVITY_UPDATE_ANSWER: 'answer_update',
- TYPE_ACTIVITY_UPDATE_QUESTION: 'question_update',
- TYPE_ACTIVITY_ANSWER: 'new_answer',
- TYPE_ACTIVITY_ASK_QUESTION: 'new_question',
- }
+ TYPE_ACTIVITY_COMMENT_QUESTION: 'question_comment',
+ TYPE_ACTIVITY_COMMENT_ANSWER: 'answer_comment',
+ TYPE_ACTIVITY_UPDATE_ANSWER: 'answer_update',
+ TYPE_ACTIVITY_UPDATE_QUESTION: 'question_update',
+ TYPE_ACTIVITY_ANSWER: 'new_answer',
+ TYPE_ACTIVITY_ASK_QUESTION: 'new_question',
+ TYPE_ACTIVITY_POST_SHARED: 'post_shared'
+}
assert(
set(RESPONSE_ACTIVITY_TYPES_FOR_INSTANT_NOTIFICATIONS) \
@@ -288,21 +295,28 @@ TYPE_RESPONSE = {
}
POST_STATUS = {
- 'closed' : _('[closed]'),
- 'deleted' : _('[deleted]'),
- 'default_version' : _('initial version'),
- 'retagged' : _('retagged'),
+ 'closed': _('[closed]'),
+ 'deleted': _('[deleted]'),
+ 'default_version': _('initial version'),
+ 'retagged': _('retagged'),
+ 'private': _('[private]')
}
#choices used in email and display filters
INCLUDE_ALL = 0
EXCLUDE_IGNORED = 1
INCLUDE_INTERESTING = 2
-TAG_DISPLAY_FILTER_STRATEGY_CHOICES = (
+INCLUDE_SUBSCRIBED = 3
+TAG_DISPLAY_FILTER_STRATEGY_MINIMAL_CHOICES = (
(INCLUDE_ALL, _('show all tags')),
(EXCLUDE_IGNORED, _('exclude ignored tags')),
- (INCLUDE_INTERESTING, _('only interesting tags')),
+ (INCLUDE_INTERESTING, _('only interesting tags'))
)
+TAG_DISPLAY_FILTER_STRATEGY_CHOICES = \
+ TAG_DISPLAY_FILTER_STRATEGY_MINIMAL_CHOICES + \
+ ((INCLUDE_SUBSCRIBED, _('only subscribed tags')),)
+
+
TAG_EMAIL_FILTER_STRATEGY_CHOICES = (
(INCLUDE_ALL, _('email for all tags')),
(EXCLUDE_IGNORED, _('exclude ignored tags')),
@@ -390,5 +404,47 @@ AVATAR_STATUS_CHOICE = (
('a', _('Uploaded Avatar')),#avatar uploaded locally - with django-avatar app
)
+SEARCH_ORDER_BY = (
+ ('-added_at', _('date descendant')),
+ ('added_at', _('date ascendant')),
+ ('-last_activity_at', _('activity descendant')),
+ ('last_activity_at', _('activity ascendant')),
+ ('-answer_count', _('answers descendant')),
+ ('answer_count', _('answers ascendant')),
+ ('-score', _('votes descendant')),
+ ('score', _('votes ascendant')),
+ )
+
+DEFAULT_QUESTION_WIDGET_STYLE = """
+@import url('http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700');
+body {
+ overflow: hidden;
+}
+
+#container {
+ width: 200px;
+ height: 350px;
+}
+ul {
+ list-style: none;
+ padding: 5px;
+ margin: 5px;
+}
+li {
+ border-bottom: #CCC 1px solid;
+ padding-bottom: 5px;
+ padding-top: 5px;
+}
+li:last-child {
+ border: none;
+}
+a {
+ text-decoration: none;
+ color: #464646;
+ font-family: 'Yanone Kaffeesatz', sans-serif;
+ font-size: 15px;
+}
+"""
+
#an exception import * because that file has only strings
from askbot.const.message_keys import *
diff --git a/askbot/const/message_keys.py b/askbot/const/message_keys.py
index 9ac82e57..74fcbf7f 100644
--- a/askbot/const/message_keys.py
+++ b/askbot/const/message_keys.py
@@ -36,6 +36,10 @@ _('click to see most voted questions')
_('interesting')
_('ignored')
_('subscribed')
+TAGS_ARE_REQUIRED_MESSAGE = _('tags are required')
+TAG_WRONG_CHARS_MESSAGE = _(
+ 'please use letters, numbers and characters "-+.#"'
+)
def get_i18n_message(key):
messages = {
diff --git a/askbot/context.py b/askbot/context.py
index 03a2d1d8..5e53febc 100644
--- a/askbot/context.py
+++ b/askbot/context.py
@@ -4,12 +4,17 @@ and the application available for the templates
"""
import sys
from django.conf import settings
+from django.core.urlresolvers import reverse
+from django.utils import simplejson
+
import askbot
from askbot import api
+from askbot import models
from askbot import const
from askbot.conf import settings as askbot_settings
from askbot.skins.loaders import get_skin
from askbot.utils import url_utils
+from askbot.utils.slug import slugify
def application_settings(request):
"""The context processor function"""
@@ -24,6 +29,8 @@ def application_settings(request):
return {}
my_settings = askbot_settings.as_dict()
my_settings['LANGUAGE_CODE'] = getattr(request, 'LANGUAGE_CODE', settings.LANGUAGE_CODE)
+ my_settings['ALLOWED_UPLOAD_FILE_TYPES'] = \
+ settings.ASKBOT_ALLOWED_UPLOAD_FILE_TYPES
my_settings['ASKBOT_URL'] = settings.ASKBOT_URL
my_settings['STATIC_URL'] = settings.STATIC_URL
my_settings['ASKBOT_CSS_DEVEL'] = getattr(
@@ -44,9 +51,43 @@ def application_settings(request):
my_settings['LOGOUT_REDIRECT_URL'] = url_utils.get_logout_redirect_url()
my_settings['USE_ASKBOT_LOGIN_SYSTEM'] = 'askbot.deps.django_authopenid' \
in settings.INSTALLED_APPS
- return {
+ context = {
'settings': my_settings,
'skin': get_skin(request),
'moderation_items': api.get_info_on_moderation_items(request.user),
'noscript_url': const.DEPENDENCY_URLS['noscript'],
}
+
+ if askbot_settings.GROUPS_ENABLED:
+ #calculate context needed to list all the groups
+ def _get_group_url(group):
+ """calculates url to the group based on its id and name"""
+ group_slug = slugify(group['name'])
+ return reverse(
+ 'users_by_group',
+ kwargs={'group_id': group['id'], 'group_slug': group_slug}
+ )
+
+ #load id's and names of all groups
+ global_group = models.tag.get_global_group()
+ groups = models.Group.objects.exclude_personal()
+ groups = groups.exclude(id=global_group.id)
+ groups_data = list(groups.values('id', 'name'))
+
+ #sort groups_data alphanumerically, but case-insensitive
+ groups_data = sorted(
+ groups_data,
+ lambda x, y: cmp(x['name'].lower(), y['name'].lower())
+ )
+
+ #insert data for the global group at the first position
+ groups_data.insert(0, {'id': global_group.id, 'name': global_group.name})
+
+ #build group_list for the context
+ group_list = list()
+ for group in groups_data:
+ link = _get_group_url(group)
+ group_list.append({'name': group['name'], 'link': link})
+ context['group_list'] = simplejson.dumps(group_list)
+
+ return context
diff --git a/askbot/deps/django_authopenid/backends.py b/askbot/deps/django_authopenid/backends.py
index ed99e44f..1e8626ac 100644
--- a/askbot/deps/django_authopenid/backends.py
+++ b/askbot/deps/django_authopenid/backends.py
@@ -6,89 +6,16 @@ import datetime
import logging
from django.contrib.auth.models import User
from django.core.exceptions import ImproperlyConfigured
+from django.conf import settings as django_settings
from django.utils.translation import ugettext as _
from askbot.deps.django_authopenid.models import UserAssociation
from askbot.deps.django_authopenid import util
+from askbot.deps.django_authopenid.ldap_auth import ldap_authenticate
+from askbot.deps.django_authopenid.ldap_auth import ldap_create_user
from askbot.conf import settings as askbot_settings
from askbot.models.signals import user_registered
-log = logging.getLogger('configuration')
-
-
-def ldap_authenticate(username, password):
- """
- Authenticate using ldap
-
- python-ldap must be installed
- http://pypi.python.org/pypi/python-ldap/2.4.6
- """
- import ldap
- user_information = None
- try:
- ldap_session = ldap.initialize(askbot_settings.LDAP_URL)
- ldap_session.protocol_version = ldap.VERSION3
- user_filter = "({0}={1})".format(askbot_settings.LDAP_USERID_FIELD,
- username)
- # search ldap directory for user
- res = ldap_session.search_s(askbot_settings.LDAP_BASEDN, ldap.SCOPE_SUBTREE, user_filter, None)
- if res: # User found in LDAP Directory
- user_dn = res[0][0]
- user_information = res[0][1]
- ldap_session.simple_bind_s(user_dn, password) # <-- will throw ldap.INVALID_CREDENTIALS if fails
- ldap_session.unbind_s()
-
- exact_username = user_information[askbot_settings.LDAP_USERID_FIELD][0]
-
- # Assuming last, first order
- # --> may be different
- last_name, first_name = user_information[askbot_settings.LDAP_COMMONNAME_FIELD][0].rsplit(" ", 1)
- email = user_information[askbot_settings.LDAP_EMAIL_FIELD][0]
- try:
- user = User.objects.get(username__exact=exact_username)
- # always update user profile to synchronize with ldap server
- user.set_password(password)
- user.first_name = first_name
- user.last_name = last_name
- user.email = email
- user.save()
- except User.DoesNotExist:
- # create new user in local db
- user = User()
- user.username = exact_username
- user.set_password(password)
- user.first_name = first_name
- user.last_name = last_name
- user.email = email
- user.is_staff = False
- user.is_superuser = False
- user.is_active = True
- user.save()
- user_registered.send(None, user = user)
-
- log.info('Created New User : [{0}]'.format(exact_username))
- return user
- else:
- # Maybe a user created internally (django admin user)
- try:
- user = User.objects.get(username__exact=username)
- if user.check_password(password):
- return user
- else:
- return None
- except User.DoesNotExist:
- return None
-
- except ldap.INVALID_CREDENTIALS, e:
- return None # Will fail login on return of None
- except ldap.LDAPError, e:
- log.error("LDAPError Exception")
- log.exception(e)
- return None
- except Exception, e:
- log.error("Unexpected Exception Occurred")
- log.exception(e)
- return None
-
+LOG = logging.getLogger(__name__)
class AuthBackend(object):
"""Authenticator's authentication backend class
@@ -98,6 +25,8 @@ class AuthBackend(object):
the reason there is only one class - for simplicity of
adding this application to a django project - users only need
to extend the AUTHENTICATION_BACKENDS with a single line
+
+ todo: it is not good to have one giant do all 'authenticate' function
"""
def authenticate(
@@ -137,7 +66,7 @@ class AuthBackend(object):
except User.DoesNotExist:
return None
except User.MultipleObjectsReturned:
- logging.critical(
+ LOG.critical(
('have more than one user with email %s ' +
'he/she will not be able to authenticate with ' +
'the email address in the place of user name') % email_address
@@ -190,15 +119,17 @@ class AuthBackend(object):
assoc.openid_url = username + '@' + provider_name#has to be this way for external pw logins
elif method == 'openid':
- provider_name = util.get_provider_name(openid_url)
try:
- assoc = UserAssociation.objects.get(
- openid_url = openid_url,
- provider_name = provider_name
- )
+ assoc = UserAssociation.objects.get(openid_url=openid_url)
user = assoc.user
except UserAssociation.DoesNotExist:
return None
+ except UserAssociation.MultipleObjectsReturned:
+ logging.critical(
+ 'duplicate openid url in the database!!! %s' % openid_url
+ )
+ return None
+
elif method == 'email':
#with this method we do no use user association
@@ -238,7 +169,34 @@ class AuthBackend(object):
return None
elif method == 'ldap':
- user = ldap_authenticate(username, password)
+ user_info = ldap_authenticate(username, password)
+ if user_info['success'] == False:
+ # Maybe a user created internally (django admin user)
+ try:
+ user = User.objects.get(username__exact=username)
+ if user.check_password(password):
+ return user
+ else:
+ return None
+ except User.DoesNotExist:
+ return None
+ else:
+ #load user by association or maybe auto-create one
+ ldap_username = user_info['ldap_username']
+ try:
+ #todo: provider_name is hardcoded - possible conflict
+ assoc = UserAssociation.objects.get(
+ openid_url = ldap_username + '@ldap',
+ provider_name = 'ldap'
+ )
+ user = assoc.user
+ except UserAssociation.DoesNotExist:
+ #email address is required
+ if 'email' in user_info and askbot_settings.LDAP_AUTOCREATE_USERS:
+ assoc = ldap_create_user(user_info)
+ user = assoc.user
+ else:
+ return None
elif method == 'wordpress_site':
try:
diff --git a/askbot/deps/django_authopenid/forms.py b/askbot/deps/django_authopenid/forms.py
index db2afcd8..fbc5c6ff 100644
--- a/askbot/deps/django_authopenid/forms.py
+++ b/askbot/deps/django_authopenid/forms.py
@@ -308,14 +308,14 @@ class LoginForm(forms.Form):
class OpenidRegisterForm(forms.Form):
""" openid signin form """
next = NextUrlField()
- username = UserNameField()
+ username = UserNameField(widget_attrs={'tabindex': 0})
email = UserEmailField()
class ClassicRegisterForm(SetPasswordForm):
""" legacy registration form """
next = NextUrlField()
- username = UserNameField()
+ username = UserNameField(widget_attrs={'tabindex': 0})
email = UserEmailField()
login_provider = PasswordLoginProviderField()
#fields password1 and password2 are inherited
diff --git a/askbot/deps/django_authopenid/ldap_auth.py b/askbot/deps/django_authopenid/ldap_auth.py
new file mode 100644
index 00000000..a633aa3b
--- /dev/null
+++ b/askbot/deps/django_authopenid/ldap_auth.py
@@ -0,0 +1,208 @@
+import logging
+from django.conf import settings as django_settings
+from django.contrib.auth.models import User
+from django.forms import EmailField, ValidationError
+from askbot.conf import settings as askbot_settings
+from askbot.deps.django_authopenid.models import UserAssociation
+from askbot.models.signals import user_registered
+from askbot.utils.loading import load_module
+
+LOG = logging.getLogger(__name__)
+
+def split_name(full_name, name_format):
+ """splits full name into first and last,
+ according to the order given in the name_format parameter"""
+ bits = full_name.strip().split()
+ if len(bits) == 1:
+ bits.push('')
+ elif len(bits) == 0:
+ bits = ['', '']
+
+ if name_format == 'first,last':
+ return bits[0], bits[1]
+ elif name_format == 'last,first':
+ return bits[1], bits[0]
+ else:
+ raise ValueError('Unexpected value of name_format')
+
+
+def ldap_authenticate_default(username, password):
+ """
+ Authenticate using ldap.
+ LDAP parameter setup is described in
+ askbot/doc/source/optional-modules.rst
+ See section about LDAP.
+
+ returns a dict with keys:
+
+ * first_name
+ * last_name
+ * ldap_username
+ * email (optional only if there is valid email)
+ * success - boolean, True if authentication succeeded
+
+ python-ldap must be installed
+ http://pypi.python.org/pypi/python-ldap/2.4.6
+
+ NOTE: if you are planning to implement a custom
+ LDAP authenticate function (python path to which can
+ be provided via setting `ASKBOT_LDAP_AUTHENTICATE`
+ setting in the settings.py file) - implement
+ the function just like this - accepting user name
+ and password and returning dict with the same values.
+ The returned dictionary can contain additional values
+ that you might find useful.
+ """
+ import ldap
+ user_information = None
+ user_info = {}#the return value
+ try:
+ ldap_session = ldap.initialize(askbot_settings.LDAP_URL)
+
+ #set protocol version
+ if askbot_settings.LDAP_PROTOCOL_VERSION == '2':
+ ldap_session.protocol_version = ldap.VERSION2
+ elif askbot_settings.LDAP_PROTOCOL_VERSION == '3':
+ ldap_session.protocol_version = ldap.VERSION3
+ else:
+ raise NotImplementedError('unsupported version of ldap protocol')
+
+ ldap.set_option(ldap.OPT_REFERRALS, 0)
+
+ #set extra ldap options, if given
+ if hasattr(django_settings, 'LDAP_EXTRA_OPTIONS'):
+ options = django_settings.LDAP_EXTRA_OPTIONS
+ for key, value in options:
+ if key.startswith('OPT_'):
+ ldap_key = getattr(ldap, key)
+ ldap.set_option(ldap_key, value)
+ else:
+ raise ValueError('Invalid LDAP option %s' % key)
+
+ #add optional "master" LDAP authentication, if required
+ master_username = getattr(django_settings, 'LDAP_LOGIN_DN', None)
+ master_password = getattr(django_settings, 'LDAP_PASSWORD', None)
+
+ login_name_field = askbot_settings.LDAP_LOGIN_NAME_FIELD
+ base_dn = askbot_settings.LDAP_BASE_DN
+ login_template = login_name_field + '=%s,' + base_dn
+ encoding = askbot_settings.LDAP_ENCODING
+
+ if master_username and master_password:
+ ldap_session.simple_bind_s(
+ master_username.encode(encoding),
+ master_password.encode(encoding)
+ )
+
+ user_filter = askbot_settings.LDAP_USER_FILTER_TEMPLATE % (
+ askbot_settings.LDAP_LOGIN_NAME_FIELD,
+ username
+ )
+
+ email_field = askbot_settings.LDAP_EMAIL_FIELD
+
+ get_attrs = [
+ email_field.encode(encoding),
+ login_name_field.encode(encoding)
+ #str(askbot_settings.LDAP_USERID_FIELD)
+ #todo: here we have a chance to get more data from LDAP
+ #maybe a point for some plugin
+ ]
+
+ common_name_field = askbot_settings.LDAP_COMMON_NAME_FIELD.strip()
+ given_name_field = askbot_settings.LDAP_GIVEN_NAME_FIELD.strip()
+ surname_field = askbot_settings.LDAP_SURNAME_FIELD.strip()
+
+ if given_name_field and surname_field:
+ get_attrs.append(given_name_field.encode(encoding))
+ get_attrs.append(surname_field.encode(encoding))
+ elif common_name_field:
+ get_attrs.append(common_name_field.encode(encoding))
+
+ # search ldap directory for user
+ user_search_result = ldap_session.search_s(
+ askbot_settings.LDAP_BASE_DN.encode(encoding),
+ ldap.SCOPE_SUBTREE,
+ user_filter.encode(encoding),
+ get_attrs
+ )
+ if user_search_result: # User found in LDAP Directory
+ user_dn = user_search_result[0][0]
+ user_information = user_search_result[0][1]
+ ldap_session.simple_bind_s(user_dn, password.encode(encoding)) #raises INVALID_CREDENTIALS
+ ldap_session.unbind_s()
+
+ if given_name_field and surname_field:
+ last_name = user_information.get(surname_field, [''])[0]
+ first_name = user_information.get(given_name_field, [''])[0]
+ elif surname_field:
+ common_name_format = askbot_settings.LDAP_COMMON_NAME_FIELD_FORMAT
+ common_name = user_information.get(common_name_field, [''])[0]
+ first_name, last_name = split_name(common_name, common_name_format)
+
+ user_info = {
+ 'first_name': first_name,
+ 'last_name': last_name,
+ 'ldap_username': user_information[login_name_field][0],
+ 'success': True
+ }
+
+ try:
+ email = user_information.get(email_field, [''])[0]
+ user_info['email'] = EmailField().clean(email)
+ except ValidationError:
+ pass
+ else:
+ user_info['success'] = False
+
+ except ldap.INVALID_CREDENTIALS, e:
+ user_info['success'] = False
+ except ldap.LDAPError, e:
+ LOG.error("LDAPError Exception")
+ LOG.exception(e)
+ user_info['success'] = False
+ except Exception, e:
+ LOG.error("Unexpected Exception Occurred")
+ LOG.exception(e)
+ user_info['success'] = False
+
+ return user_info
+
+
+def ldap_create_user_default(user_info):
+ """takes the result returned by the :func:`ldap_authenticate`
+
+ and returns a :class:`UserAssociation` object
+ """
+ # create new user in local db
+ user = User()
+ user.username = user_info.get('django_username', user_info['ldap_username'])
+ user.set_unusable_password()
+ user.first_name = user_info['first_name']
+ user.last_name = user_info['last_name']
+ user.email = user_info['email']
+ user.is_staff = False
+ user.is_superuser = False
+ user.is_active = True
+ user.save()
+ user_registered.send(None, user = user)
+ LOG.info('Created New User : [{0}]'.format(user_info['ldap_username']))
+
+ assoc = UserAssociation()
+ assoc.user = user
+ assoc.openid_url = user_info['ldap_username'] + '@ldap'
+ assoc.provider_name = 'ldap'
+ assoc.save()
+ return assoc
+
+LDAP_AUTH_FUNC_PATH = getattr(django_settings, 'LDAP_AUTHENTICATE_FUNCTION', None)
+if LDAP_AUTH_FUNC_PATH:
+ ldap_authenticate = load_module(LDAP_AUTH_FUNC_PATH)
+else:
+ ldap_authenticate = ldap_authenticate_default
+
+LDAP_CREATE_FUNC_PATH = getattr(django_settings, 'LDAP_CREATE_USER_FUNCTION', None)
+if LDAP_CREATE_FUNC_PATH:
+ ldap_create_user = load_module(LDAP_CREATE_FUNC_PATH)
+else:
+ ldap_create_user = ldap_create_user_default
diff --git a/askbot/deps/django_authopenid/urls.py b/askbot/deps/django_authopenid/urls.py
index f51939ab..1b7d0b01 100644
--- a/askbot/deps/django_authopenid/urls.py
+++ b/askbot/deps/django_authopenid/urls.py
@@ -7,13 +7,16 @@ urlpatterns = patterns('askbot.deps.django_authopenid.views',
url(r'^yadis.xrdf$', 'xrdf', name='yadis_xrdf'),
# manage account registration
url(r'^%s$' % _('signin/'), 'signin', name='user_signin'),
+ url(r'^%s$' % _('widget/signin/'), 'signin',
+ {'template_name': 'authopenid/widget_signin.html'},
+ name='widget_signin'),
url(r'^%s$' % _('signout/'), 'signout', name='user_signout'),
#this view is "complete-openid" signin
- url(r'^%s%s$' % (_('signin/'), _('complete/')), 'complete_signin',
+ url(r'^%s%s$' % (_('signin/'), _('complete/')), 'complete_signin',
name='user_complete_signin'),
url(
r'^%s%s$' % (_('signin/'), _('complete-oauth/')),
- 'complete_oauth_signin',
+ 'complete_oauth_signin',
name='user_complete_oauth_signin'
),
url(r'^%s$' % _('register/'), 'register', name='user_register'),
@@ -27,7 +30,12 @@ urlpatterns = patterns('askbot.deps.django_authopenid.views',
#but the setting is disabled right now
#url(r'^%s%s$' % (_('email/'), _('sendkey/')), 'send_email_key', name='send_email_key'),
#url(r'^%s%s(?P<id>\d+)/(?P<key>[\dabcdef]{32})/$' % (_('email/'), _('verify/')), 'verifyemail', name='user_verifyemail'),
- url(r'^%s(?P<key>[\dabcdef]{32})?$' % _('recover/'), 'account_recover', name='user_account_recover'),
+ url(r'^%s$' % _('recover/'), 'account_recover', name='user_account_recover'),
+ url(
+ r'^%s$' % _('verify-email/'),
+ 'verify_email_and_register',
+ name='verify_email_and_register'
+ ),
url(
r'^delete_login_method/$',#this method is ajax only
'delete_login_method',
diff --git a/askbot/deps/django_authopenid/util.py b/askbot/deps/django_authopenid/util.py
index 28f6b2dd..9f02050d 100644
--- a/askbot/deps/django_authopenid/util.py
+++ b/askbot/deps/django_authopenid/util.py
@@ -1,8 +1,10 @@
# -*- coding: utf-8 -*-
import cgi
import urllib
+import urllib2
import functools
import re
+import random
from openid.store.interface import OpenIDStore
from openid.association import Association as OIDAssociation
from openid.extensions import sreg
@@ -412,6 +414,7 @@ def get_enabled_major_login_providers():
token = oauth.Token(data['oauth_token'], data['oauth_token_secret'])
client = oauth.Client(consumer, token=token)
url = 'https://identi.ca/api/account/verify_credentials.json'
+ content = urllib2.urlopen(url).read()
json = simplejson.loads(content)
return json['id']
if askbot_settings.IDENTICA_KEY and askbot_settings.IDENTICA_SECRET:
@@ -848,3 +851,7 @@ def ldap_check_password(username, password):
except ldap.LDAPError, e:
logging.critical(unicode(e))
return False
+
+def generate_random_key():
+ random.seed()
+ return '%032x' % random.getrandbits(128)
diff --git a/askbot/deps/django_authopenid/views.py b/askbot/deps/django_authopenid/views.py
index 2f80d366..040d837c 100644
--- a/askbot/deps/django_authopenid/views.py
+++ b/askbot/deps/django_authopenid/views.py
@@ -1,13 +1,13 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2007, 2008, Benoît Chesneau
# Copyright (c) 2007 Simon Willison, original work on django-openid
-#
+#
# All rights reserved.
-#
+#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
-#
+#
# * Redistributions of source code must retain the above copyright
# * notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
@@ -17,7 +17,7 @@
# * of its contributors may be used to endorse or promote products
# * derived from this software without specific prior written
# * permission.
-#
+#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
@@ -34,20 +34,24 @@ import datetime
from django.http import HttpResponseRedirect, get_host, Http404
from django.http import HttpResponse
from django.template import RequestContext, Context
-from django.conf import settings
+from django.conf import settings as django_settings
from askbot.conf import settings as askbot_settings
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.contrib.auth import authenticate
from django.core.urlresolvers import reverse
+from django.forms.util import ErrorList
from django.views.decorators import csrf
from django.utils.encoding import smart_unicode
from django.utils.html import escape
from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe
-from django.core.mail import send_mail
+from askbot.mail import send_mail
from recaptcha_works.decorators import fix_recaptcha_remote_ip
from askbot.skins.loaders import render_into_skin, get_template
+from askbot.deps.django_authopenid.ldap_auth import ldap_create_user
+from askbot.deps.django_authopenid.ldap_auth import ldap_authenticate
+from askbot.utils.loading import load_module
from urlparse import urlparse
from openid.consumer.consumer import Consumer, \
@@ -80,15 +84,70 @@ from askbot.utils.forms import get_next_url
from askbot.utils.http import get_request_info
from askbot.models.signals import user_logged_in, user_registered
+def create_authenticated_user_account(
+ username=None, email=None, password=None,
+ user_identifier=None, login_provider_name=None
+):
+ """creates a user account, user association with
+ the login method and the the default email subscriptions
+ """
+
+ user = User.objects.create_user(username, email)
+ user_registered.send(None, user=user)
+
+ logging.debug('creating new openid user association for %s')
+
+ if password:
+ user.set_password(password)
+ user.save()
+ else:
+ UserAssociation(
+ openid_url = user_identifier,
+ user = user,
+ provider_name = login_provider_name,
+ last_used_timestamp = datetime.datetime.now()
+ ).save()
+
+ subscribe_form = askbot_forms.SimpleEmailSubscribeForm({'subscribe': 'y'})
+ subscribe_form.full_clean()
+ logging.debug('saving email feed settings')
+ subscribe_form.save(user)
+
+ logging.debug('logging the user in')
+ user = authenticate(method='force', user_id=user.id)
+ if user is None:
+ error_message = 'please make sure that ' + \
+ 'askbot.deps.django_authopenid.backends.AuthBackend' + \
+ 'is in your settings.AUTHENTICATION_BACKENDS'
+ raise Exception(error_message)
+
+ return user
+
+
+def cleanup_post_register_session(request):
+ """delete keys from session after registration is complete"""
+ keys = (
+ 'user_identifier',
+ 'login_provider_name',
+ 'username',
+ 'email',
+ 'password',
+ 'validation_code'
+ )
+ for key in keys:
+ if key in request.session:
+ del request.session[key]
+
+
#todo: decouple from askbot
-def login(request,user):
+def login(request, user):
from django.contrib.auth import login as _login
# get old session key
session_key = request.session.session_key
# login and get new session key
- _login(request,user)
+ _login(request, user)
# send signal with old session key as argument
logging.debug('logged in user %s with session key %s' % (user.username, session_key))
@@ -132,12 +191,12 @@ def ask_openid(
):
""" basic function to ask openid and return response """
on_failure = on_failure or signin_failure
-
+
trust_root = getattr(
- settings, 'OPENID_TRUST_ROOT', get_url_host(request) + '/'
+ django_settings, 'OPENID_TRUST_ROOT', get_url_host(request) + '/'
)
if xri.identifierScheme(openid_url) == 'XRI' and getattr(
- settings, 'OPENID_DISALLOW_INAMES', False
+ django_settings, 'OPENID_DISALLOW_INAMES', False
):
msg = _("i-names are not supported")
logging.debug('openid failed because i-names are not supported')
@@ -162,9 +221,9 @@ def complete(request, on_success=None, on_failure=None, return_to=None):
""" complete openid signin """
assert(on_success is not None)
assert(on_failure is not None)
-
+
logging.debug('in askbot.deps.django_authopenid.complete')
-
+
consumer = Consumer(request.session, util.DjangoOpenIDStore())
# make sure params are encoded in utf8
params = dict((k,smart_unicode(v)) for k, v in request.GET.items())
@@ -174,7 +233,7 @@ def complete(request, on_success=None, on_failure=None, return_to=None):
logging.debug(u'returned openid parameters were: %s' % unicode(params))
except Exception, e:
logging.critical(u'fix logging statement above ' + unicode(e))
-
+
if openid_response.status == SUCCESS:
logging.debug('openid response status is SUCCESS')
return on_success(
@@ -267,25 +326,24 @@ def complete_oauth_signin(request):
#@not_authenticated
@csrf.csrf_protect
-def signin(request):
+def signin(request, template_name='authopenid/signin.html'):
"""
- signin page. It manages the legacy authentification (user/password)
+ signin page. It manages the legacy authentification (user/password)
and openid authentification
-
+
url: /signin/
-
+
template : authopenid/signin.htm
"""
logging.debug('in signin view')
on_failure = signin_failure
- email_feeds_form = askbot_forms.SimpleEmailSubscribeForm()
#we need a special priority on where to redirect on successful login
#here:
#1) url parameter "next" - if explicitly set
#2) url from django setting LOGIN_REDIRECT_URL
#3) home page of the forum
- login_redirect_url = getattr(settings, 'LOGIN_REDIRECT_URL', None)
+ login_redirect_url = getattr(django_settings, 'LOGIN_REDIRECT_URL', None)
next_url = get_next_url(request, default = login_redirect_url)
logging.debug('next url is %s' % next_url)
@@ -312,24 +370,57 @@ def signin(request):
assert(password_action == 'login')
username = login_form.cleaned_data['username']
password = login_form.cleaned_data['password']
- # will be None if authentication fails
+
user = authenticate(
username=username,
password=password,
method = 'ldap'
)
- if user is not None:
+
+ if user:
login(request, user)
return HttpResponseRedirect(next_url)
else:
- return finalize_generic_signin(
- request = request,
- user = user,
- user_identifier = username,
- login_provider_name = provider_name,
- redirect_url = next_url
- )
+ #try to login again via LDAP
+ user_info = ldap_authenticate(username, password)
+ if user_info['success']:
+ if askbot_settings.LDAP_AUTOCREATE_USERS:
+ #create new user or
+ user = ldap_create_user(user_info).user
+ user = authenticate(method='force', user_id=user.id)
+ assert(user is not None)
+ login(request, user)
+ return HttpResponseRedirect(next_url)
+ else:
+ #continue with proper registration
+ ldap_username = user_info['ldap_username']
+ request.session['email'] = user_info['email']
+ request.session['ldap_user_info'] = user_info
+ if askbot_settings.AUTOFILL_USER_DATA:
+ request.session['username'] = ldap_username
+ request.session['first_name'] = \
+ user_info['first_name']
+ request.session['last_name'] = \
+ user_info['last_name']
+ return finalize_generic_signin(
+ request,
+ login_provider_name = 'ldap',
+ user_identifier = ldap_username + '@ldap',
+ redirect_url = next_url
+ )
+ else:
+ auth_fail_func_path = getattr(
+ django_settings,
+ 'LDAP_AUTHENTICATE_FAILURE_FUNCTION',
+ None
+ )
+ if auth_fail_func_path:
+ auth_fail_func = load_module(auth_fail_func_path)
+ auth_fail_func(user_info, login_form)
+ else:
+ login_form.set_password_login_error()
+ #return HttpResponseRedirect(request.path)
else:
if password_action == 'login':
user = authenticate(
@@ -373,11 +464,11 @@ def signin(request):
sreg_req = sreg.SRegRequest(optional=['nickname', 'email'])
redirect_to = "%s%s?%s" % (
get_url_host(request),
- reverse('user_complete_signin'),
+ reverse('user_complete_signin'),
urllib.urlencode({'next':next_url})
)
return ask_openid(
- request,
+ request,
login_form.cleaned_data['openid_url'],
redirect_to,
on_failure=signin_failure,
@@ -448,7 +539,7 @@ def signin(request):
user = authenticate(
method = 'wordpress_site',
wordpress_url = wp.url,
- wp_user_id = wp_user.user_id
+ wp_user_id = wp_user.user_id
)
return finalize_generic_signin(
request = request,
@@ -477,8 +568,9 @@ def signin(request):
return show_signin_view(
request,
login_form = login_form,
- view_subtype = view_subtype
- )
+ view_subtype = view_subtype,
+ template_name=template_name
+ )
@csrf.csrf_protect
def show_signin_view(
@@ -487,7 +579,8 @@ def show_signin_view(
account_recovery_form = None,
account_recovery_message = None,
sticky = False,
- view_subtype = 'default'
+ view_subtype = 'default',
+ template_name='authopenid/signin.html'
):
"""url-less utility function that populates
context of template 'authopenid/signin.html'
@@ -495,12 +588,12 @@ def show_signin_view(
"""
allowed_subtypes = (
- 'default', 'add_openid',
+ 'default', 'add_openid',
'email_sent', 'change_openid',
'bad_key'
)
- assert(view_subtype in allowed_subtypes)
+ assert(view_subtype in allowed_subtypes)
if sticky:
next_url = reverse('user_signin')
@@ -614,7 +707,7 @@ def show_signin_view(
data['existing_login_methods'] = existing_login_methods
active_provider_names = [
item.provider_name for item in existing_login_methods
- ]
+ ]
util.set_login_provider_tooltips(
major_login_providers,
@@ -628,7 +721,7 @@ def show_signin_view(
data['major_login_providers'] = major_login_providers.values()
data['minor_login_providers'] = minor_login_providers.values()
- return render_into_skin('authopenid/signin.html', data, request)
+ return render_into_skin(template_name, data, request)
@login_required
def delete_login_method(request):
@@ -660,8 +753,8 @@ def complete_signin(request):
""" in case of complete signin with openid """
logging.debug('')#blank log just for the trace
return complete(
- request,
- on_success = signin_success,
+ request,
+ on_success = signin_success,
on_failure = signin_failure,
return_to = get_url_host(request) + reverse('user_complete_signin')
)
@@ -703,7 +796,7 @@ def signin_success(request, identity_url, openid_response):
)
def finalize_generic_signin(
- request = None,
+ request = None,
user = None,
login_provider_name = None,
user_identifier = None,
@@ -717,14 +810,34 @@ def finalize_generic_signin(
if request.user.is_authenticated():
#this branch is for adding a new association
if user is None:
- #register new association
- UserAssociation(
- user = request.user,
- provider_name = login_provider_name,
- openid_url = user_identifier,
- last_used_timestamp = datetime.datetime.now()
- ).save()
- return HttpResponseRedirect(redirect_url)
+ try:
+ #see if currently logged in user has login with the given provider
+ assoc = UserAssociation.objects.get(
+ user=request.user,
+ provider_name=login_provider_name
+ )
+ logging.critical('switching account or open id changed???')
+ #did openid url change? or we are dealing with a brand new open id?
+ message1 = _(
+ 'If you are trying to sign in to another account, '
+ 'please sign out first.'
+ )
+ request.user.message_set.create(message=message1)
+ message2 = _(
+ 'Otherwise, please report the incident '
+ 'to the site administrator.'
+ )
+ request.user.message_set.create(message=message2)
+ return HttpResponseRedirect(redirect_url)
+ except UserAssociation.DoesNotExist:
+ #register new association
+ UserAssociation(
+ user=request.user,
+ provider_name=login_provider_name,
+ openid_url=user_identifier,
+ last_used_timestamp=datetime.datetime.now()
+ ).save()
+ return HttpResponseRedirect(redirect_url)
elif user != request.user:
#prevent theft of account by another pre-existing user
@@ -746,22 +859,21 @@ def finalize_generic_signin(
{'provider': login_provider_name}
request.user.message_set.create(message = msg)
return HttpResponseRedirect(redirect_url)
+ elif user:
+ #login branch
+ login(request, user)
+ logging.debug('login success')
+ return HttpResponseRedirect(redirect_url)
else:
- if user is None:
- #need to register
- request.method = 'GET'#this is not a good thing to do
- #but necessary at the moment to reuse the register()
- #method
- return register(
- request,
- login_provider_name=login_provider_name,
- user_identifier=user_identifier
- )
- else:
- #login branch
- login(request, user)
- logging.debug('login success')
- return HttpResponseRedirect(redirect_url)
+ #need to register
+ request.method = 'GET'#this is not a good thing to do
+ #but necessary at the moment to reuse the register()
+ #method
+ return register(
+ request,
+ login_provider_name=login_provider_name,
+ user_identifier=user_identifier
+ )
@not_authenticated
@csrf.csrf_protect
@@ -772,17 +884,19 @@ def register(request, login_provider_name=None, user_identifier=None):
in which case request.method must ge 'GET'
and login_provider_name and user_identifier arguments must not be None
+ user_identifier will be stored in the UserAssociation as openid_url
+ login_provider_name - as provider_name
+
this function may need to be refactored to simplify the usage pattern
-
+
template : authopenid/complete.html
"""
-
+
logging.debug('')
next_url = get_next_url(request)
user = None
- is_redirect = False
username = request.session.get('username', '')
email = request.session.get('email', '')
logging.debug('request method is %s' % request.method)
@@ -794,7 +908,6 @@ def register(request, login_provider_name=None, user_identifier=None):
'email': request.session.get('email', ''),
}
)
- email_feeds_form = askbot_forms.SimpleEmailSubscribeForm()
if request.method == 'GET':
assert(login_provider_name is not None)
@@ -817,64 +930,45 @@ def register(request, login_provider_name=None, user_identifier=None):
logging.debug('trying to create new account associated with openid')
register_form = forms.OpenidRegisterForm(request.POST)
- email_feeds_form = askbot_forms.SimpleEmailSubscribeForm(request.POST)
if not register_form.is_valid():
logging.debug('OpenidRegisterForm is INVALID')
- elif not email_feeds_form.is_valid():
- logging.debug('SimpleEmailSubscribeForm is INVALID')
else:
- logging.debug('OpenidRegisterForm and SimpleEmailSubscribeForm are valid')
- is_redirect = True
username = register_form.cleaned_data['username']
email = register_form.cleaned_data['email']
- user = User.objects.create_user(username, email)
- user_registered.send(None, user = user)
-
- logging.debug('creating new openid user association for %s')
-
- UserAssociation(
- openid_url = user_identifier,
- user = user,
- provider_name = login_provider_name,
- last_used_timestamp = datetime.datetime.now()
- ).save()
-
- del request.session['user_identifier']
- del request.session['login_provider_name']
-
- logging.debug('logging the user in')
-
- user = authenticate(method = 'force', user_id = user.id)
- if user is None:
- error_message = 'please make sure that ' + \
- 'askbot.deps.django_authopenid.backends.AuthBackend' + \
- 'is in your settings.AUTHENTICATION_BACKENDS'
- raise Exception(error_message)
+ if 'ldap_user_info' in request.session:
+ user_info = request.session['ldap_user_info']
+ #we take this info from the user input where
+ #they can override the default provided by LDAP
+ user_info['django_username'] = username
+ user_info['email'] = email
+ user = ldap_create_user(user_info).user
+ del request.session['ldap_user_info']
+ login(request, user)
+ cleanup_post_register_session(request)
+ return HttpResponseRedirect(next_url)
- login(request, user)
+ elif askbot_settings.REQUIRE_VALID_EMAIL_FOR == 'nothing':
- logging.debug('saving email feed settings')
- email_feeds_form.save(user)
-
- #check if we need to post a question that was added anonymously
- #this needs to be a function call becase this is also done
- #if user just logged in and did not need to create the new account
-
- if user != None:
- if askbot_settings.EMAIL_VALIDATION == True:
- logging.debug('sending email validation')
- send_new_email_key(user, nomessage=True)
- output = validation_email_sent(request)
- set_email_validation_message(user) #message set after generating view
- return output
- if user.is_authenticated():
- logging.debug('success, send user to main page')
- return HttpResponseRedirect(reverse('index'))
+ user = create_authenticated_user_account(
+ username=username,
+ email=email,
+ user_identifier=user_identifier,
+ login_provider_name=login_provider_name,
+ )
+ login(request, user)
+ cleanup_post_register_session(request)
+ return HttpResponseRedirect(next_url)
else:
- logging.debug('have really strange error')
- raise Exception('openid login failed')#should not ever get here
-
+ request.session['username'] = username
+ request.session['email'] = email
+ key = util.generate_random_key()
+ email = request.session['email']
+ send_email_key(email, key, handler_url_name='verify_email_and_register')
+ request.session['validation_code'] = key
+ redirect_url = reverse('verify_email_and_register') + '?next=' + next_url
+ return HttpResponseRedirect(redirect_url)
+
providers = {
'yahoo':'<font color="purple">Yahoo!</font>',
'flickr':'<font color="#0063dc">flick</font><font color="#ff0084">r</font>&trade;',
@@ -887,11 +981,11 @@ def register(request, login_provider_name=None, user_identifier=None):
logging.error('openid provider named "%s" has no pretty customized logo' % login_provider_name)
else:
provider_logo = providers[login_provider_name]
-
+
logging.debug('printing authopenid/complete.html output')
data = {
'openid_register_form': register_form,
- 'email_feeds_form': email_feeds_form,
+ 'default_form_action': django_settings.LOGIN_URL,
'provider':mark_safe(provider_logo),
'username': username,
'email': email,
@@ -908,6 +1002,58 @@ def signin_failure(request, message):
return show_signin_view(request)
@not_authenticated
+@csrf.csrf_protect
+def verify_email_and_register(request):
+ """for POST request - check the validation code,
+ and if correct - create an account an log in the user
+
+ for GET - give a field to paste the activation code
+ and a button to send another validation email.
+ """
+ presented_code = request.REQUEST.get('validation_code', None)
+ if presented_code:
+ try:
+ #we get here with post if button is pushed
+ #or with "get" if emailed link is clicked
+ expected_code = request.session['validation_code']
+ assert(presented_code == expected_code)
+ #create an account!
+ username = request.session['username']
+ email = request.session['email']
+ password = request.session.get('password', None)
+ user_identifier = request.session.get('user_identifier', None)
+ login_provider_name = request.session.get('login_provider_name', None)
+ if password:
+ user = create_authenticated_user_account(
+ username=username,
+ email=email,
+ password=password,
+ )
+ elif user_identifier and login_provider_name:
+ user = create_authenticated_user_account(
+ username=username,
+ email=email,
+ user_identifier=user_identifier,
+ login_provider_name=login_provider_name,
+ )
+ else:
+ raise NotImplementedError()
+
+ login(request, user)
+ cleanup_post_register_session(request)
+ return HttpResponseRedirect(get_next_url(request))
+ except Exception, e:
+ message = _(
+ 'Sorry, registration failed. '
+ 'Please ask the site administrator for help.'
+ )
+ request.user.message_set.create(message=message)
+ return HttpResponseRedirect(reverse('index'))
+ else:
+ data = {'page_class': 'validate-email-page'}
+ return render_into_skin('authopenid/verify_email.html', data, request)
+
+@not_authenticated
@decorators.valid_password_login_provider_required
@csrf.csrf_protect
@fix_recaptcha_remote_ip
@@ -915,10 +1061,9 @@ def signup_with_password(request):
"""Create a password-protected account
template: authopenid/signup_with_password.html
"""
-
+
logging.debug(get_request_info(request))
- next = get_next_url(request)
- login_form = forms.LoginForm(initial = {'next': next})
+ login_form = forms.LoginForm(initial = {'next': get_next_url(request)})
#this is safe because second decorator cleans this field
provider_name = request.REQUEST['login_provider']
@@ -930,8 +1075,7 @@ def signup_with_password(request):
logging.debug('request method was %s' % request.method)
if request.method == 'POST':
form = RegisterForm(request.POST)
- email_feeds_form = askbot_forms.SimpleEmailSubscribeForm(request.POST)
-
+
#validation outside if to remember form values
logging.debug('validating classic register form')
form1_is_valid = form.is_valid()
@@ -939,53 +1083,36 @@ def signup_with_password(request):
logging.debug('classic register form validated')
else:
logging.debug('classic register form is not valid')
- form2_is_valid = email_feeds_form.is_valid()
- if form2_is_valid:
- logging.debug('email feeds form validated')
- else:
- logging.debug('email feeds form is not valid')
- if form1_is_valid and form2_is_valid:
+
+ if form1_is_valid:
logging.debug('both forms are valid')
next = form.cleaned_data['next']
username = form.cleaned_data['username']
password = form.cleaned_data['password1']
email = form.cleaned_data['email']
- provider_name = form.cleaned_data['login_provider']
-
- new_user = User.objects.create_user(username, email, password)
- user_registered.send(None, user = new_user)
-
- logging.debug('new user %s created' % username)
- if provider_name != 'local':
- raise NotImplementedError('must run create external user code')
-
- user = authenticate(
- username = username,
- password = password,
- provider_name = provider_name,
- method = 'password'
- )
- login(request, user)
- logging.debug('new user logged in')
- email_feeds_form.save(user)
- logging.debug('email feeds form saved')
-
- # send email
- #subject = _("Welcome email subject line")
- #message_template = get_emplate(
- # 'authopenid/confirm_email.txt'
- #)
- #message_context = Context({
- # 'signup_url': askbot_settings.APP_URL + reverse('user_signin'),
- # 'username': username,
- # 'password': password,
- #})
- #message = message_template.render(message_context)
- #send_mail(subject, message, settings.DEFAULT_FROM_EMAIL,
- # [user.email])
- #logging.debug('new password acct created, confirmation email sent!')
- return HttpResponseRedirect(next)
+ if askbot_settings.REQUIRE_VALID_EMAIL_FOR == 'nothing':
+ user = create_authenticated_user_account(
+ username=username,
+ email=email,
+ password=password,
+ )
+ login(request, user)
+ cleanup_post_register_session(request)
+ return HttpResponseRedirect(get_next_url(request))
+ else:
+ request.session['username'] = username
+ request.session['email'] = email
+ request.session['password'] = password
+ #todo: generate a key and save it in the session
+ key = util.generate_random_key()
+ email = request.session['email']
+ send_email_key(email, key, handler_url_name='verify_email_and_register')
+ request.session['validation_code'] = key
+ redirect_url = reverse('verify_email_and_register') + \
+ '?next=' + get_next_url(request)
+ return HttpResponseRedirect(redirect_url)
+
else:
#todo: this can be solved with a decorator, maybe
form.initial['login_provider'] = provider_name
@@ -994,20 +1121,18 @@ def signup_with_password(request):
#todo: here we have duplication of get_password_login_provider...
form = RegisterForm(
initial={
- 'next':next,
+ 'next': get_next_url(request),
'login_provider': provider_name
}
)
- email_feeds_form = askbot_forms.SimpleEmailSubscribeForm()
logging.debug('printing legacy signup form')
major_login_providers = util.get_enabled_major_login_providers()
minor_login_providers = util.get_enabled_minor_login_providers()
context_data = {
- 'form': form,
+ 'form': form,
'page_class': 'openid-signin',
- 'email_feeds_form': email_feeds_form,
'major_login_providers': major_login_providers.values(),
'minor_login_providers': minor_login_providers.values(),
'login_form': login_form
@@ -1049,95 +1174,41 @@ XRDF_TEMPLATE = """<?xml version='1.0' encoding='UTF-8'?>
</Service>
</XRD>
</xrds:XRDS>"""
-
+
def xrdf(request):
url_host = get_url_host(request)
return_to = "%s%s" % (url_host, reverse('user_complete_signin'))
return HttpResponse(XRDF_TEMPLATE % {'return_to': return_to})
-def find_email_validation_messages(user):
- msg_text = _('your email needs to be validated see %(details_url)s') \
- % {'details_url':reverse('faq') + '#validate'}
- return user.message_set.filter(message__exact=msg_text)
-
-def set_email_validation_message(user):
- messages = find_email_validation_messages(user)
- msg_text = _('your email needs to be validated see %(details_url)s') \
- % {'details_url':reverse('faq') + '#validate'}
- if len(messages) == 0:
- user.message_set.create(message=msg_text)
-
-def clear_email_validation_message(user):
- messages = find_email_validation_messages(user)
- messages.delete()
-
-def set_new_email(user, new_email, nomessage=False):
+def set_new_email(user, new_email):
if new_email != user.email:
user.email = new_email
user.email_isvalid = False
user.save()
- if askbot_settings.EMAIL_VALIDATION == True:
- send_new_email_key(user,nomessage=nomessage)
-def _send_email_key(user):
+def send_email_key(email, key, handler_url_name='user_account_recover'):
"""private function. sends email containing validation key
to user's email address
"""
- subject = _("Recover your %(site)s account") % {'site': askbot_settings.APP_SHORT_NAME}
+ subject = _("Recover your %(site)s account") % \
+ {'site': askbot_settings.APP_SHORT_NAME}
url = urlparse(askbot_settings.APP_URL)
data = {
'validation_link': url.scheme + '://' + url.netloc + \
- reverse(
- 'user_account_recover',
- kwargs={'key':user.email_key}
- )
+ reverse(handler_url_name) +\
+ '?validation_code=' + key
}
- template = get_template('authopenid/email_validation.txt')
+ template = get_template('authopenid/email_validation.html')
message = template.render(data)
- send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [user.email])
+ send_mail(subject, message, django_settings.DEFAULT_FROM_EMAIL, [email])
-def send_new_email_key(user,nomessage=False):
- import random
- random.seed()
- user.email_key = '%032x' % random.getrandbits(128)
+def send_user_new_email_key(user):
+ user.email_key = util.generate_random_key()
user.save()
- _send_email_key(user)
- if nomessage==False:
- set_email_validation_message(user)
-
-@login_required
-@csrf.csrf_protect
-def send_email_key(request):
- """
- url = /email/sendkey/
-
- view that is shown right after sending email key
- email sending is called internally
-
- raises 404 if email validation is off
- if current email is valid shows 'key_not_sent' view of
- authopenid/changeemail.html template
- """
- if askbot_settings.EMAIL_VALIDATION == True:
- if request.user.email_isvalid:
- data = {
- 'email': request.user.email,
- 'action_type': 'key_not_sent',
- 'change_link': reverse('user_changeemail')
- }
- return render_into_skin(
- 'authopenid/changeemail.html',
- data,
- request
- )
- else:
- send_new_email_key(request.user)
- return validation_email_sent(request)
- else:
- raise Http404
+ send_email_key(user.email, user.email_key)
-def account_recover(request, key = None):
+def account_recover(request):
"""view similar to send_email_key, except
it allows user to recover an account by entering
his/her email address
@@ -1153,7 +1224,7 @@ def account_recover(request, key = None):
form = forms.AccountRecoveryForm(request.POST)
if form.is_valid():
user = form.cleaned_data['user']
- send_new_email_key(user, nomessage = True)
+ send_user_new_email_key(user)
message = _(
'Please check your email and visit the enclosed link.'
)
@@ -1168,6 +1239,7 @@ def account_recover(request, key = None):
account_recovery_form = form
)
else:
+ key = request.GET.get('validation_code', None)
if key is None:
return HttpResponseRedirect(reverse('user_signin'))
@@ -1187,7 +1259,7 @@ def account_recover(request, key = None):
)
else:
return show_signin_view(request, view_subtype = 'bad_key')
-
+
#internal server view used as return value by other views
def validation_email_sent(request):
@@ -1201,26 +1273,3 @@ def validation_email_sent(request):
'action_type': 'validate'
}
return render_into_skin('authopenid/changeemail.html', data, request)
-
-def verifyemail(request,id=None,key=None):
- """
- view that is shown when user clicks email validation link
- url = /email/verify/{{user.id}}/{{user.email_key}}/
- """
- logging.debug('')
- if askbot_settings.EMAIL_VALIDATION == True:
- user = User.objects.get(id=id)
- if user:
- if user.email_key == key:
- user.email_isvalid = True
- clear_email_validation_message(user)
- user.save()
- data = {'action_type': 'validation_complete'}
- return render_into_skin(
- 'authopenid/changeemail.html',
- data,
- request
- )
- else:
- logging.error('hmm, no user found for email validation message - foul play?')
- raise Http404
diff --git a/askbot/deps/livesettings/models.py b/askbot/deps/livesettings/models.py
index 1a57dfc5..71db8acf 100644
--- a/askbot/deps/livesettings/models.py
+++ b/askbot/deps/livesettings/models.py
@@ -25,14 +25,20 @@ def _safe_get_siteid(site):
def find_setting(group, key, site=None):
"""Get a setting or longsetting by group and key, cache and return it."""
-
+
siteid = _safe_get_siteid(site)
setting = None
-
+
use_db, overrides = get_overrides(siteid)
ck = cache_key('Setting', siteid, group, key)
-
- if use_db:
+
+ grp = overrides.get(group, None)
+
+ if grp and key in grp:
+ val = grp[key]
+ setting = ImmutableSetting(key=key, group=group, value=val)
+ log.debug('Returning overridden: %s', setting)
+ elif use_db:
try:
setting = cache_get(ck)
@@ -45,10 +51,10 @@ def find_setting(group, key, site=None):
# maybe it is a "long setting"
try:
setting = LongSetting.objects.get(site__id__exact=siteid, key__exact=key, group__exact=group)
-
+
except LongSetting.DoesNotExist:
pass
-
+
cache_set(ck, value=setting)
else:
@@ -57,13 +63,13 @@ def find_setting(group, key, site=None):
val = grp[key]
setting = ImmutableSetting(key=key, group=group, value=val)
log.debug('Returning overridden: %s', setting)
-
+
if not setting:
raise SettingNotSet(key, cachekey=ck)
return setting
-class SettingNotSet(Exception):
+class SettingNotSet(Exception):
def __init__(self, k, cachekey=None):
self.key = k
self.cachekey = cachekey
@@ -77,22 +83,22 @@ class SettingManager(models.Manager):
class ImmutableSetting(object):
-
+
def __init__(self, group="", key="", value="", site=1):
self.site = site
self.group = group
self.key = key
self.value = value
-
+
def cache_key(self, *args, **kwargs):
return cache_key('OverrideSetting', self.site, self.group, self.key)
-
+
def delete(self):
pass
-
+
def save(self, *args, **kwargs):
pass
-
+
def __repr__(self):
return "ImmutableSetting: %s.%s=%s" % (self.group, self.key, self.value)
@@ -120,11 +126,18 @@ class Setting(models.Model, CachedObjectMixin):
site = self.site
except Site.DoesNotExist:
self.site = Site.objects.get_current()
-
+
super(Setting, self).save(force_insert=force_insert, force_update=force_update)
-
+
self.cache_set()
-
+
+ def cache_set(self, *args, **kwargs):
+ val = kwargs.pop('value', self)
+ key = self.cache_key(*args, **kwargs)
+ #TODO: fix this with Django's > 1.3 CACHE dict setting support
+ length = getattr(settings, 'LIVESETTINGS_CACHE_TIMEOUT', settings.CACHE_TIMEOUT)
+ cache_set(key, value=val, length=length)
+
class Meta:
unique_together = ('site', 'group', 'key')
@@ -149,7 +162,7 @@ class LongSetting(models.Model, CachedObjectMixin):
def cache_key(self, *args, **kwargs):
# note same cache pattern as Setting. This is so we can look up in one check.
- # they can't overlap anyway, so this is moderately safe. At the worst, the
+ # they can't overlap anyway, so this is moderately safe. At the worst, the
# Setting will override a LongSetting.
return cache_key('Setting', self.site, self.group, self.key)
@@ -164,7 +177,14 @@ class LongSetting(models.Model, CachedObjectMixin):
self.site = Site.objects.get_current()
super(LongSetting, self).save(force_insert=force_insert, force_update=force_update)
self.cache_set()
-
+
+ def cache_set(self, *args, **kwargs):
+ val = kwargs.pop('value', self)
+ key = self.cache_key(*args, **kwargs)
+ #TODO: fix this with Django's > 1.3 CACHE dict setting support
+ length = getattr(settings, 'LIVESETTINGS_CACHE_TIMEOUT', settings.CACHE_TIMEOUT)
+ cache_set(key, value=val, length=length)
+
class Meta:
unique_together = ('site', 'group', 'key')
-
+
diff --git a/askbot/deps/livesettings/overrides.py b/askbot/deps/livesettings/overrides.py
index f3dc3355..c2fc09df 100644
--- a/askbot/deps/livesettings/overrides.py
+++ b/askbot/deps/livesettings/overrides.py
@@ -35,7 +35,7 @@ def get_overrides(siteid=-1):
}
}
- In the settings dict above, the "val" entries must exactly match the format
+ In the settings dict above, the "val" entries must exactly match the format
stored in the database for a setting. Do not use a literal True or an integer,
it needs to be the string representation of them.
@@ -45,7 +45,7 @@ def get_overrides(siteid=-1):
if hasattr(djangosettings, 'LIVESETTINGS_OPTIONS'):
if siteid == -1:
siteid = _safe_get_siteid(None)
-
+
opts = djangosettings.LIVESETTINGS_OPTIONS
if opts.has_key(siteid):
opts = opts[siteid]
diff --git a/askbot/doc/source/changelog.rst b/askbot/doc/source/changelog.rst
index 430d98de..82f46e32 100644
--- a/askbot/doc/source/changelog.rst
+++ b/askbot/doc/source/changelog.rst
@@ -3,6 +3,31 @@ Changes in Askbot
Development version
-------------------
+* Added setting `NOTIFICATION_DELAY_TIME` to use with enabled celery daemon (Adolfo)
+* Added setting `ASKBOT_INTERNAL_IPS` - to allow anonymous access to
+ closed sites from dedicated IP addresses (Evgeny)
+* Moved default skin from `askbot/skins/default` to simply `askbot` (Evgeny)
+* Repost comment as answer (Adolfo)
+* Question list widget (Adolfo)
+* Ask a question widget (Adolfo)
+* Embeddable widget generator (Adolfo)
+* Groups are shown in the dropdown menu in the header (Adolfo)
+* Added group moderation requests to the moderators inboxes (Evgeny)
+* Group joining may be open/closed or moderated (Evgeny)
+* Adding "extra options" to the ldap session (Evgeny)
+* Tag moderation (Evgeny)
+* Editable optional three level category selector for the tags (Evgeny)
+* Tag editor adding tags as they are typed (Evgeny)
+* Added optional support for unicode slugs (Evgeny)
+* Allow switching comment with answer and answer with question comment (Adolfo)
+* Allow user names longer than 30 characters (Evgeny)
+* Option to disable feedback form for the anonymos users (Evgeny)
+* Optional restriction to have confirmed email address to join forum (Evgeny)
+* Optional list of allowed email addresses and email domain name for the new users (Evgeny)
+* Optional support for unicode slugs (Evgeny)
+* Optionally allow limiting one answer per question per person (Evgeny)
+* Added management command `build_livesettings_cache` (Adolfo)
+* Administrators can post under fictional user accounts without logging out (jtrain, Evgeny)
* Welcome email for the case when replying by email is enabled (Evgeny)
* Detection of email signature based on the response to the welcome email (Evgeny)
* Hide "website" and "about" section of the blocked user profiles
diff --git a/askbot/doc/source/contributors.rst b/askbot/doc/source/contributors.rst
index 69348b84..ce8656ea 100644
--- a/askbot/doc/source/contributors.rst
+++ b/askbot/doc/source/contributors.rst
@@ -41,6 +41,7 @@ Programming and documentation
* Silvio Heuberger
* `Alexandros <https://github.com/alexandros-z>`_
* `Paul Backhouse <https://github.com/powlo>`_
+* `jtrain <https://github.com/jtrain>`_
Translations
------------
diff --git a/askbot/doc/source/customizing-skin-in-askbot.rst b/askbot/doc/source/customizing-skin-in-askbot.rst
index 09ea0dbb..e384a314 100644
--- a/askbot/doc/source/customizing-skin-in-askbot.rst
+++ b/askbot/doc/source/customizing-skin-in-askbot.rst
@@ -15,8 +15,7 @@ of better performance and flexibility of coding.
What are skins made of
======================
-Skin is a directory either within ``askbot/skins``
-or in a directory, pointed to by ``ASKBOT_EXTRA_SKINS_DIR``
+Skin is a directory, pointed to by ``ASKBOT_EXTRA_SKINS_DIR``
parameter of your ``settings.py`` file.
Skin name is the same as the name of its directory,
@@ -37,7 +36,7 @@ A skin consists of HTML templates, css and javascript
and all of these resources are looked up first within currently active skin,
then in "default".
-Names "default" and "common" are reserved and should not be used to
+Name "default" is reserved and should not be used to
name custom skins.
Current state of skin system
@@ -108,7 +107,7 @@ In addition, it will help if your copy of askbot code is installed
in the django project directory (use ``python setup.py develop`` method
to install askbot in the first place).
-Then edit anything in directory ``askbot/skins/default``
+Then edit anything in directories ``askbot/templates`` and ``askbot/media``
and commit to your own repository.
If the askbot app is installed in the `site-packages` or `dist-packages`
@@ -156,7 +155,7 @@ Git makes this task quite simple and manageable.
Skin templates
==============
-The first template to look at is `askbot/skins/default/templates/base.html`, it is quite simple and you can substantially change the appearance by modifying that template in the combination with adding some custom css.
+The first template to look at is `askbot/templates/base.html`, it is quite simple and you can substantially change the appearance by modifying that template in the combination with adding some custom css.
More detailed description of templates will follow.
diff --git a/askbot/doc/source/debugging.rst b/askbot/doc/source/debugging.rst
index 4b46ee58..af865b12 100644
--- a/askbot/doc/source/debugging.rst
+++ b/askbot/doc/source/debugging.rst
@@ -7,6 +7,41 @@ Debugging Askbot (and other Django applications)
This document describes techniques that can be used to debug Askbot and other Django projects
If you discover new debugging techniques, please add here.
+.. _runserver:
+Use development server for debugging
+------------------------------------
+
+Django comes with a handy development webserver that can be started with the command::
+
+ python manage.py runserver
+
+With the combination of runserver,
+the :ref:`python debugger <pdb>`,
+and even inserted "print" statements directly in the code
+it is possible to "look into" the program as it runs.
+
+Inspect the log file
+--------------------
+
+By default askbot will log errors into file `log/askbot.log` within the
+project directory. See what's inside that file.
+
+Note that in the production setups there are many log files - for the
+production webserver, database, etc.
+
+.. _pdb:
+Use Python debugger
+-------------------
+
+In the problematic portion of the code, insert lines::
+
+ import pdb
+ pdb.set_trace()
+
+Then fire up the :ref:`runserver <runserver>` and step through the program.
+When you see prompt starting with `(pdb)`
+type `help` and see what options there are.
+
Use logging in code
---------------------
diff --git a/askbot/doc/source/intranet-setup.rst b/askbot/doc/source/intranet-setup.rst
index 224ffb89..2711b376 100644
--- a/askbot/doc/source/intranet-setup.rst
+++ b/askbot/doc/source/intranet-setup.rst
@@ -12,3 +12,10 @@ Please change the following settings in your ``settings.py`` file::
In addition, in the "live settings":
* disable gravatar in "settings->User settings"
+
+If you would like to password/protect your site
+(achievable via "access control settings" -> "allow only registered users..."),
+and at the same time be able to have some dedicated service
+to read your site without authentication, add
+IP addresses of that service to a tuple ``ASKBOT_INTERNAL_IPS``
+in your ``settings.py`` file.
diff --git a/askbot/doc/source/live-settings.rst b/askbot/doc/source/live-settings.rst
index e154a257..12546e6c 100644
--- a/askbot/doc/source/live-settings.rst
+++ b/askbot/doc/source/live-settings.rst
@@ -19,3 +19,40 @@ No-one but the site administrators can change those settings.
At the moment this command is not available from the web-interface
but this will be fixed in the future.
+.. _live-settings-options:
+Entering live settings in settings.py file
+==========================================
+
+You might want to bypass live settings and enter them directly
+in the ``settings.py`` file in the ``LIVESETTINGS_OPTIONS`` dictionary.
+
+Having live settings overridden from the ``settings.py`` file may
+somewhat speed up your site
+and
+decrease a chance that the values could be accessed
+by an unauthorized person.
+
+Please see an example below::
+
+ LIVESETTINGS_OPTIONS = {
+ 1: {
+ 'DB' : True,
+ 'SETTINGS': {
+ 'EMAIL': {
+ 'REPLY_BY_EMAIL': True
+ }
+ }
+ }
+
+Firstly, the number "1" is site id. Most
+likely the number should be the same as the value of ``SITE_ID`` setting.
+
+The value for the site id key is a nested dictionary with two keys:
+``'DB'`` (if True - then the rest of settings will be taken from the database)
+and ``'SETTINGS'`` - a dictionary with the actual settings.
+In this example ``'EMAIL'`` is the settings group
+and
+``'REPLY_BY_EMAIL'`` is the setting name, with ``True`` being the value.
+
+Setting group names and setting names can be looked up in files within
+``askbot/conf`` directory.
diff --git a/askbot/doc/source/management-commands.rst b/askbot/doc/source/management-commands.rst
index b96251dc..2755bcf5 100644
--- a/askbot/doc/source/management-commands.rst
+++ b/askbot/doc/source/management-commands.rst
@@ -80,6 +80,8 @@ The bulk of the management commands fall into this group and will probably be th
+---------------------------------+-------------------------------------------------------------+
| `build_thread_summary_cache` | Rebuilds cache for the question summary snippet. |
+---------------------------------+-------------------------------------------------------------+
+| `build_livesettings_cache` | Rebuilds cache for the live settings. |
++---------------------------------+-------------------------------------------------------------+
| `delete_contextless_...` | `delete_contextless_badge_award_activities` |
| | Deletes Activity objects of type badge award where the |
| | related context object is lost. |
diff --git a/askbot/doc/source/optional-modules.rst b/askbot/doc/source/optional-modules.rst
index 25bb5cc8..3337ef0c 100644
--- a/askbot/doc/source/optional-modules.rst
+++ b/askbot/doc/source/optional-modules.rst
@@ -83,24 +83,84 @@ To enable authentication via LDAP
pip install python-ldap
-After that, add configuration parameters in :ref:`live settings <live-settings>`, section
-"Keys to connect the site with external services ..."
-(url ``/settings/EXTERNAL_KEYS``, relative to the domain name)
+After that, add configuration parameters in :ref:`live settings <live-settings>`,
+section "LDAP settings"
+(url ``/settings/LDAP_SETTINGS``, relative to the forum base url)
.. note::
- Location of these parameters is likely to change in the future.
- When that happens, an update notice will appear in the documentation.
-
-The parameters are:
-
-* "Use LDAP authentication for the password login" - enable/disable the feature.
- When enabled, the user name and password will be routed to use the LDAP protocol.
- Default system password authentication will be overridden.
-* "LDAP service provider name" - any string - just come up with a name for the provider service.
-* "URL fro the LDAP service" - a correct url to access the service.
-* "Explain how to change the LDAP password"
- - askbot does not provide a method to change LDAP passwords
- , therefore - use this field to explain users how they can change their passwords.
+ While it is possible to configure LDAP via web interface,
+ it is actually more safe to add them in your ``settings.py`` file in the
+ :ref:`LIVESETTINGS_OPTIONS <live-settings-options>` dictionary.
+ Consider that a breach in security of your forum might open
+ malicious access into your LDAP directory.
+
+The parameters are (note that some have pre-set defaults that might work for you)::
+
+* in Login Provider Settings select "enable local login"
+ - this makes login/password form available
+* enable/disable LDAP for password login -
+ must check that, to connect the login/password form to LDAP flow
+* create accounts automatically or not (``LDAP_AUTOCREATE_USERS``)
+* protocol version (``LDAP_PROTOCOL_VERSION``) (version 2 is insecure and deprecated)
+* ldap url (``LDAP_URL``)
+* base distinguished name, 'dn' in LDAP parlance (``LDAP_BASEDN``)
+* user id field name (``LDAP_USERID_FIELD``)
+* email field name (``LDAP_EMAIL_FIELD``)
+* user name filter template (``LDAP_USERNAME_FILTER_TEMPLATE``)
+ must have two string placeholders.
+* given (first) name field (``LDAP_GIVEN_NAME_FIELD``)
+* surname (last name) field (``LDAP_SURNAME_FIELD``)
+* common name field (``LDAP_COMMON_NAME_FIELD``)
+ either given and surname should be used or common name.
+ All three are not necessary - either first two or common.
+ These fields are used to extract users first and last names.
+* Format of common name (``LDAP_COMMON_NAME_FIELD_FORMAT``)
+ values can be only 'first,last' or 'last,first' - used to
+ extract last and first names from common name
+
+There are three more optional parameters that must go to the ``settings.py`` file::
+
+* ``LDAP_LOGIN_DN``
+* ``LDAP_PASSWORD``
+* ``LDAP_EXTRA_OPTIONS``, a list of two-item tuples - of names and values of
+ the options. Option names must be upper case strings all starting with ``OPT_``
+ as described in the `python ldap library documentation <http://www.python-ldap.org/doc/html/ldap.html#options>`_. An often used option is (`OPT_REFERRALS`, 0).
+* ``LDAP_AUTHENTICATE_FUNCTION`` - dotted python path to optional function that
+ can override the default `ldap_authenticate` function. This function allows to
+ completely customize the LDAP login procedure.
+ To see what is expected of this function (input parameters and the return value) -
+ look at the end of the doc string at
+ `askbot.deps.django_authopenid.ldap_auth.ldap_authenticate_default`.
+ One use case for the custom function is determining to which group
+ a user might belong or check any additional access rules that might be
+ stored in your LDAP directory. Another use case - is the case when
+ the default procedure just does not work for you.
+* ``LDAP_AUTHENICATE_FAILURE_FUNCTION`` - python dotted path to an additional function
+ that may be called after a unsuccessful authentication.
+ This function can be used to set custom error messages to the login form.
+ The function should take two parameters (in the following order): user_info, login_form.
+ user_info - is the same dictionary
+ that is returned by the `ldap_authenticate` function.
+* ``LDAP_CREATE_USER_FUNCTION`` - python dotted path to function that will create
+ the ldap user, should actually return a user association object, like
+ ``askbot.deps.django_authopenid.ldap_auth.ldap_create_user_default``.
+ Function takes return value of the ldap authenticate function as a sole parameter.
+
+
+Use these when you have the "directory master passsword" -
+for a specific user who can access the rest of the directory,
+these were not added to the live settings due to security concerns.
+
+``LDAP_USER`` and ``LDAP_PASSWORD`` will be used only if both are provided!
+
+Since LDAP authentication requires so many parameters,
+you might need to :ref:`debug <debugging>` the settings.
+The function to look at is `askbot.deps.django_authopenid.backends.ldap_authenticate`.
+If you have problems with LDAP please contact us at support@askbot.com.
+
+The easiest way to debug - insert ``import pdb; pdb.set_trace()`` line into function
+`askbot.deps.django_authopenid.backends.ldap_authenticate`,
+start the ``runserver`` and step through.
Uploaded avatars
================
@@ -216,29 +276,32 @@ Askbot supports posting replies by email. For this feature to work ``Lamson`` a
pip install django-lamson
+.. note::
+ On Windows installation of the Lamson module may require
+ additional work. Askbot does not support this feature
+ on Windows automatically.
+
The lamson daemon needs a folder to store it's mail queue files and a folder to store log files, create the folders folder named ``run`` and ``logs`` within your project folder by executing the following commands:
mkdir run
mkdir logs
-The minimum settings required to enable this feature are defining the port and binding address for the lamson SMTP daemon and the email handlers within askbot. Edit your settings.py file to include the following:
+The minimum settings required to enable this feature are defining the port and binding address for the lamson SMTP daemon and the email handlers within askbot. Edit your settings.py file to include the following::
LAMSON_RECEIVER_CONFIG = {'host': 'your.ip.address', 'port': 25}
-
LAMSON_HANDLERS = ['askbot.mail.lamson_handlers']
-
LAMSON_ROUTER_DEFAULTS = {'host': '.+'}
-In the list of ``installed_apps`` add the app ``django-lamson``.
+In the list of ``installed_apps`` add the app ``django_lamson``.
The ``LAMSON_RECEIVER_CONFIG`` parameter defines the binding address/port for the SMTP daemon. To recieve internet email you will need to bind to your external ip address and port 25. If you just want to test the feature by sending eamil from the same system you could bind to 127.0.0.1 and any higher port.
-To run the lamson SMTP daemon you will need to execute the following management command:
+To run the lamson SMTP daemon you will need to execute the following management command::
python manage.py lamson_start
-To stop the daemon issue the following command
+To stop the daemon issue the following command::
python manage.py lamson_stop
@@ -251,7 +314,7 @@ Within the askbot admin interface there are 4 significant configuration points f
* The last setting in this section controls the threshold for minimum length of the reply that is posted as an answer to a question. If the user is replying to a notification for a question and the reply body is shorter than this threshold the reply will be posted as a comment to the question.
* In the karma thresholds section the "Post answers and comments by email" defines the minimum karma for users to be able to post replies by email.
-If the system where lamson is hosted also acts as an email server or you simply want some of the emails to be ignored and sent to another server you can define forward rules. Any emails matching these rules will be sent to another smtp server, bypassing the reply by email function. As an example by adding the following in your settings.py file:
+If the system where lamson is hosted also acts as an email server or you simply want some of the emails to be ignored and sent to another server you can define forward rules. Any emails matching these rules will be sent to another smtp server, bypassing the reply by email function. As an example by adding the following in your settings.py file::
LAMSON_FORWARD = (
{
diff --git a/askbot/doc/source/settings.rst b/askbot/doc/source/settings.rst
new file mode 100644
index 00000000..d07e697b
--- /dev/null
+++ b/askbot/doc/source/settings.rst
@@ -0,0 +1,14 @@
+=================================
+Settings for ``settings.py`` file
+=================================
+
+* ``ALLOW_UNICODE_SLUGS`` - if ``True``, slugs will use unicode, default - ``False``
+
+There are more settings that are not documented yet,
+but most are described in the ``settings.py`` template:
+
+ askbot/setup_templates/settings.py.mustache
+
+TODO: describe all of them here.
+
+
diff --git a/askbot/exceptions.py b/askbot/exceptions.py
index d2d5ddf0..12802e7e 100644
--- a/askbot/exceptions.py
+++ b/askbot/exceptions.py
@@ -19,6 +19,11 @@ class InsufficientReputation(exceptions.PermissionDenied):
"""
pass
+class AnswerAlreadyGiven(exceptions.PermissionDenied):
+ """Raised when user attempts to post a second answer
+ to the same question"""
+ pass
+
class DuplicateCommand(exceptions.PermissionDenied):
"""exception class to indicate that something
that can happen only once was attempted for the second time
diff --git a/askbot/forms.py b/askbot/forms.py
index 81382a2c..0659e338 100644
--- a/askbot/forms.py
+++ b/askbot/forms.py
@@ -1,18 +1,25 @@
+"""Forms, custom form fields and related utility functions
+used in AskBot"""
import re
from django import forms
from askbot import const
+from askbot.const import message_keys
+from django.forms.util import ErrorList
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext_lazy, string_concat
from django.utils.text import get_text_list
from django.contrib.auth.models import User
-from django.contrib.contenttypes.models import ContentType
from django_countries import countries
from askbot.utils.forms import NextUrlField, UserNameField
from askbot.mail import extract_first_email_address
+from askbot.models.tag import get_groups
from recaptcha_works.fields import RecaptchaField
from askbot.conf import settings as askbot_settings
+from askbot.conf import get_tag_display_filter_strategy_choices
+from tinymce.widgets import TinyMCE
import logging
+
def cleanup_dict(dictionary, key, empty_value):
"""deletes key from dictionary if it exists
and the corresponding value equals the empty_value
@@ -20,13 +27,27 @@ def cleanup_dict(dictionary, key, empty_value):
if key in dictionary and dictionary[key] == empty_value:
del dictionary[key]
+
def format_form_errors(form):
+ """Formats form errors in HTML
+ if there is only one error - returns a plain string
+ if more than one, returns an unordered list of errors
+ in HTML format.
+ If there are no errors, returns empty string
+ """
if form.errors:
errors = form.errors.values()
if len(errors) == 1:
return errors[0]
else:
- return 'hahahahah'
+ result = '<ul>'
+ for error in errors:
+ result += '<li>%s</li>' % error
+ result += '</ul>'
+ return result
+ else:
+ return ''
+
def clean_marked_tagnames(tagnames):
"""return two strings - one containing tagnames
@@ -35,7 +56,7 @@ def clean_marked_tagnames(tagnames):
wildcard tags are those that have an asterisk at the end
the function does not verify that the tag names are valid
"""
- if askbot_settings.USE_WILDCARD_TAGS == False:
+ if askbot_settings.USE_WILDCARD_TAGS is False:
return tagnames, list()
pure_tags = list()
@@ -53,7 +74,8 @@ def clean_marked_tagnames(tagnames):
return pure_tags, wildcards
-def filter_choices(remove_choices = None, from_choices = None):
+
+def filter_choices(remove_choices=None, from_choices=None):
"""a utility function that will remove choice tuples
usable for the forms.ChoicesField from
``from_choices``, the removed ones will be those given
@@ -73,12 +95,47 @@ def filter_choices(remove_choices = None, from_choices = None):
if choice == choice_to_test[0]:
remove = True
break
- if remove == False:
- filtered_choices += ( choice_to_test, )
+ if remove is False:
+ filtered_choices += (choice_to_test, )
return filtered_choices
-COUNTRY_CHOICES = (('unknown',_('select country')),) + countries.COUNTRIES
+
+def need_mandatory_tags():
+ """true, if list of mandatory tags is not empty"""
+ from askbot import models
+ return (
+ askbot_settings.TAGS_ARE_REQUIRED
+ and len(models.tag.get_mandatory_tags()) > 0
+ )
+
+
+def mandatory_tag_missing_in_list(tag_strings):
+ """true, if mandatory tag is not present in the list
+ of ``tag_strings``"""
+ from askbot import models
+ mandatory_tags = models.tag.get_mandatory_tags()
+ for mandatory_tag in mandatory_tags:
+ for tag_string in tag_strings:
+ if tag_strings_match(tag_string, mandatory_tag):
+ return False
+ return True
+
+
+def tag_strings_match(tag_string, mandatory_tag):
+ """true if tag string matches the mandatory tag,
+ the comparison is not symmetric if tag_string ends with a
+ wildcard (asterisk)
+ """
+ if mandatory_tag.endswith('*'):
+ return tag_string.startswith(mandatory_tag[:-1])
+ else:
+ return tag_string == mandatory_tag
+
+
+
+COUNTRY_CHOICES = (('unknown', _('select country')),) + countries.COUNTRIES
+
class CountryField(forms.ChoiceField):
"""this is better placed into the django_coutries app"""
@@ -100,10 +157,13 @@ class CountryField(forms.ChoiceField):
return None
return value
+
class CountedWordsField(forms.CharField):
-
+ """a field where a number of words is expected
+ to be in a certain range"""
+
def __init__(
- self, min_words = 0, max_words = 9999, field_name = None,
+ self, min_words=0, max_words=9999, field_name=None,
*args, **kwargs
):
self.min_words = min_words
@@ -144,28 +204,38 @@ class CountedWordsField(forms.CharField):
class DomainNameField(forms.CharField):
+ """Field for Internet Domain Names
+ todo: maybe there is a standard field for this?
+ """
def clean(self, value):
#find a better regex, taking into account tlds
domain_re = re.compile(r'[a-zA-Z\d]+(\.[a-zA-Z\d]+)+')
if domain_re.match(value):
return value
else:
- raise forms.ValidationError('%s is not a valid domain name' % value)
+ raise forms.ValidationError(
+ '%s is not a valid domain name' % value
+ )
class TitleField(forms.CharField):
+ """Fild receiving question title"""
def __init__(self, *args, **kwargs):
super(TitleField, self).__init__(*args, **kwargs)
- self.required = True
+ self.required = kwargs.get('required', True)
self.widget = forms.TextInput(
- attrs={'size' : 70, 'autocomplete' : 'off'}
- )
+ attrs={'size': 70, 'autocomplete': 'off'}
+ )
self.max_length = 255
- self.label = _('title')
- self.help_text = _('please enter a descriptive title for your question')
+ self.label = _('title')
+ self.help_text = _(
+ 'please enter a descriptive title for your question'
+ )
self.initial = ''
def clean(self, value):
+ """cleans the field for minimum and maximum length
+ also is supposed to work for unicode non-ascii characters"""
if value is None:
value = ''
if len(value) < askbot_settings.MIN_TITLE_LENGTH:
@@ -192,20 +262,26 @@ class TitleField(forms.CharField):
) % self.max_length
)
- return value.strip() # TODO: test me
+ return value.strip() # TODO: test me
+
class EditorField(forms.CharField):
- """EditorField is subclassed by the
+ """EditorField is subclassed by the
:class:`QuestionEditorField` and :class:`AnswerEditorField`
"""
length_error_template_singular = 'post content must be > %d character',
length_error_template_plural = 'post content must be > %d characters',
- min_length = 10#sentinel default value
+ min_length = 10 # sentinel default value
def __init__(self, *args, **kwargs):
+ editor_attrs = kwargs.pop('editor_attrs', {})
super(EditorField, self).__init__(*args, **kwargs)
self.required = True
- self.widget = forms.Textarea(attrs={'id':'editor'})
+ widget_attrs = {'id': 'editor'}
+ if askbot_settings.EDITOR_TYPE == 'markdown':
+ self.widget = forms.Textarea(attrs=widget_attrs)
+ elif askbot_settings.EDITOR_TYPE == 'tinymce':
+ self.widget = TinyMCE(attrs=widget_attrs, mce_attrs=editor_attrs)
self.label = _('content')
self.help_text = u''
self.initial = ''
@@ -218,32 +294,82 @@ class EditorField(forms.CharField):
self.length_error_template_singular,
self.length_error_template_plural,
self.min_length
- ) % self.min_length
+ ) % self.min_length
raise forms.ValidationError(msg)
return value
+
class QuestionEditorField(EditorField):
+ """Editor field for the questions"""
+
def __init__(self, *args, **kwargs):
super(QuestionEditorField, self).__init__(*args, **kwargs)
- self.length_error_template_singular = 'question body must be > %d character'
- self.length_error_template_plural = 'question body must be > %d characters'
+ self.length_error_template_singular = \
+ 'question body must be > %d character'
+ self.length_error_template_plural = \
+ 'question body must be > %d characters'
self.min_length = askbot_settings.MIN_QUESTION_BODY_LENGTH
+
class AnswerEditorField(EditorField):
+ """Editor field for answers"""
+
def __init__(self, *args, **kwargs):
super(AnswerEditorField, self).__init__(*args, **kwargs)
self.length_error_template_singular = 'answer must be > %d character'
self.length_error_template_plural = 'answer must be > %d characters'
self.min_length = askbot_settings.MIN_ANSWER_BODY_LENGTH
+
+def clean_tag(tag_name):
+ """a function that cleans a single tag name"""
+ tag_length = len(tag_name)
+ if tag_length > askbot_settings.MAX_TAG_LENGTH:
+ #singular form is odd in english, but required for pluralization
+ #in other languages
+ msg = ungettext_lazy(
+ #odd but added for completeness
+ 'each tag must be shorter than %(max_chars)d character',
+ 'each tag must be shorter than %(max_chars)d characters',
+ tag_length
+ ) % {'max_chars': tag_length}
+ raise forms.ValidationError(msg)
+
+ #todo - this needs to come from settings
+ tagname_re = re.compile(const.TAG_REGEX, re.UNICODE)
+ if not tagname_re.search(tag_name):
+ raise forms.ValidationError(
+ _(message_keys.TAG_WRONG_CHARS_MESSAGE)
+ )
+
+ if askbot_settings.FORCE_LOWERCASE_TAGS:
+ #a simpler way to handle tags - just lowercase thew all
+ return tag_name.lower()
+ else:
+ try:
+ from askbot import models
+ stored_tag = models.Tag.objects.get(name__iexact=tag_name)
+ return stored_tag.name
+ except models.Tag.DoesNotExist:
+ return tag_name
+
+
class TagNamesField(forms.CharField):
+ """field that receives AskBot tag names"""
+
def __init__(self, *args, **kwargs):
super(TagNamesField, self).__init__(*args, **kwargs)
- self.required = askbot_settings.TAGS_ARE_REQUIRED
- self.widget = forms.TextInput(attrs={'size' : 50, 'autocomplete' : 'off'})
+ self.required = kwargs.get('required',
+ askbot_settings.TAGS_ARE_REQUIRED)
+ self.widget = forms.TextInput(
+ attrs={'size': 50, 'autocomplete': 'off'}
+ )
self.max_length = 255
+ self.error_messages['max_length'] = _(
+ 'We ran out of space for recording the tags. '
+ 'Please shorten or delete some of them.'
+ )
self.label = _('tags')
- #self.help_text = _('please use space to separate tags (this enables autocomplete feature)')
self.help_text = ungettext_lazy(
'Tags are short keywords, with no spaces within. '
'Up to %(max_tags)d tag can be used.',
@@ -253,38 +379,18 @@ class TagNamesField(forms.CharField):
) % {'max_tags': askbot_settings.MAX_TAGS_PER_POST}
self.initial = ''
- def need_mandatory_tags(self):
- """true, if list of mandatory tags is not empty"""
- from askbot import models
- return askbot_settings.TAGS_ARE_REQUIRED and len(models.tag.get_mandatory_tags()) > 0
-
- def tag_string_matches(self, tag_string, mandatory_tag):
- """true if tag string matches the mandatory tag"""
- if mandatory_tag.endswith('*'):
- return tag_string.startswith(mandatory_tag[:-1])
- else:
- return tag_string == mandatory_tag
-
- def mandatory_tag_missing(self, tag_strings):
- """true, if mandatory tag is not present in the list
- of ``tag_strings``"""
- from askbot import models
- mandatory_tags = models.tag.get_mandatory_tags()
- for mandatory_tag in mandatory_tags:
- for tag_string in tag_strings:
- if self.tag_string_matches(tag_string, mandatory_tag):
- return False
- return True
-
def clean(self, value):
from askbot import models
value = super(TagNamesField, self).clean(value)
data = value.strip()
if len(data) < 1:
if askbot_settings.TAGS_ARE_REQUIRED:
- raise forms.ValidationError(_('tags are required'))
+ raise forms.ValidationError(
+ _(message_keys.TAGS_ARE_REQUIRED_MESSAGE)
+ )
else:
- return ''#don't test for required characters when tags is ''
+ #don't test for required characters when tags is ''
+ return ''
split_re = re.compile(const.TAG_SPLIT_REGEX)
tag_strings = split_re.split(data)
entered_tags = []
@@ -294,85 +400,88 @@ class TagNamesField(forms.CharField):
msg = ungettext_lazy(
'please use %(tag_count)d tag or less',
'please use %(tag_count)d tags or less',
- tag_count) % {'tag_count':max_tags}
+ tag_count) % {'tag_count': max_tags}
raise forms.ValidationError(msg)
- if self.need_mandatory_tags():
- if self.mandatory_tag_missing(tag_strings):
+ if need_mandatory_tags():
+ if mandatory_tag_missing_in_list(tag_strings):
msg = _(
'At least one of the following tags is required : %(tags)s'
) % {'tags': get_text_list(models.tag.get_mandatory_tags())}
raise forms.ValidationError(msg)
+ cleaned_entered_tags = list()
for tag in tag_strings:
- tag_length = len(tag)
- if tag_length > askbot_settings.MAX_TAG_LENGTH:
- #singular form is odd in english, but required for pluralization
- #in other languages
- msg = ungettext_lazy('each tag must be shorter than %(max_chars)d character',#odd but added for completeness
- 'each tag must be shorter than %(max_chars)d characters',
- tag_length) % {'max_chars':tag_length}
- raise forms.ValidationError(msg)
+ cleaned_tag = clean_tag(tag)
+ if cleaned_tag not in cleaned_entered_tags:
+ cleaned_entered_tags.append(clean_tag(tag))
- #todo - this needs to come from settings
- tagname_re = re.compile(const.TAG_REGEX, re.UNICODE)
- if not tagname_re.search(tag):
- raise forms.ValidationError(_(
- 'In tags, please use letters, numbers and characters "-+.#"'
- ))
- #only keep unique tags
- if tag not in entered_tags:
- entered_tags.append(tag)
-
- #normalize character case of tags
- cleaned_entered_tags = list()
- if askbot_settings.FORCE_LOWERCASE_TAGS:
- #a simpler way to handle tags - just lowercase thew all
- for name in entered_tags:
- lowercased_name = name.lower()
- if lowercased_name not in cleaned_entered_tags:
- cleaned_entered_tags.append(lowercased_name)
- else:
- #make names of tags in the input to agree with the database
- for entered_tag in entered_tags:
- try:
- #looks like we have to load tags one-by one
- #because we need tag name cases to be the same
- #as those stored in the database
- stored_tag = models.Tag.objects.get(
- name__iexact = entered_tag
- )
- if stored_tag.name not in cleaned_entered_tags:
- cleaned_entered_tags.append(stored_tag.name)
- except models.Tag.DoesNotExist:
- cleaned_entered_tags.append(entered_tag)
+ result = u' '.join(cleaned_entered_tags)
+
+ if len(result) > 125:#magic number!, the same as max_length in db
+ raise forms.ValidationError(self.error_messages['max_length'])
return u' '.join(cleaned_entered_tags)
+
class WikiField(forms.BooleanField):
+ """Rendered as checkbox turning post into
+ "community wiki"
+ """
+
def __init__(self, *args, **kwargs):
super(WikiField, self).__init__(*args, **kwargs)
self.required = False
self.initial = False
- self.label = _('community wiki (karma is not awarded & many others can edit wiki post)')
- self.help_text = _('if you choose community wiki option, the question and answer do not generate points and name of author will not be shown')
+ self.label = _(
+ 'community wiki (karma is not awarded & '
+ 'many others can edit wiki post)'
+ )
+ self.help_text = _(
+ 'if you choose community wiki option, the question '
+ 'and answer do not generate points and name of '
+ 'author will not be shown'
+ )
+
def clean(self, value):
return value and askbot_settings.WIKI_ON
+
class EmailNotifyField(forms.BooleanField):
+ """Rendered as checkbox which turns on
+ email notifications on the post"""
def __init__(self, *args, **kwargs):
super(EmailNotifyField, self).__init__(*args, **kwargs)
self.required = False
self.widget.attrs['class'] = 'nomargin'
+
class SummaryField(forms.CharField):
+
def __init__(self, *args, **kwargs):
super(SummaryField, self).__init__(*args, **kwargs)
self.required = False
- self.widget = forms.TextInput(attrs={'size' : 50, 'autocomplete' : 'off'})
+ self.widget = forms.TextInput(
+ attrs={'size': 50, 'autocomplete': 'off'}
+ )
self.max_length = 300
- self.label = _('update summary:')
- self.help_text = _('enter a brief summary of your revision (e.g. fixed spelling, grammar, improved style, this field is optional)')
+ self.label = _('update summary:')
+ self.help_text = _(
+ 'enter a brief summary of your revision (e.g. '
+ 'fixed spelling, grammar, improved style, this '
+ 'field is optional)'
+ )
+
+
+class EditorForm(forms.Form):
+ """form with one field - `editor`
+ the field must be created dynamically, so it's added
+ in the __init__() function"""
+
+ def __init__(self, editor_attrs=None):
+ super(EditorForm, self).__init__()
+ editor_attrs = editor_attrs or {}
+ self.fields['editor'] = EditorField(editor_attrs=editor_attrs)
class DumpUploadForm(forms.Form):
@@ -382,6 +491,7 @@ class DumpUploadForm(forms.Form):
"""
dump_file = forms.FileField()
+
class ShowQuestionForm(forms.Form):
"""Cleans data necessary to access answers and comments
by the respective comment or answer id - necessary
@@ -389,10 +499,10 @@ class ShowQuestionForm(forms.Form):
on the page other than the first page of answers to a question.
Same for the answers that are shown on the later pages.
"""
- answer = forms.IntegerField(required = False)
- comment = forms.IntegerField(required = False)
- page = forms.IntegerField(required = False)
- sort = forms.CharField(required = False)
+ answer = forms.IntegerField(required=False)
+ comment = forms.IntegerField(required=False)
+ page = forms.IntegerField(required=False)
+ sort = forms.CharField(required=False)
def __init__(self, data, default_sort_method):
super(ShowQuestionForm, self).__init__(data)
@@ -436,6 +546,7 @@ class ShowQuestionForm(forms.Form):
self.cleaned_data = out_data
return out_data
+
class ChangeUserReputationForm(forms.Form):
"""Form that allows moderators and site administrators
to adjust reputation of users.
@@ -445,13 +556,15 @@ class ChangeUserReputationForm(forms.Form):
"""
user_reputation_delta = forms.IntegerField(
- min_value = 1,
- label = _('Enter number of points to add or subtract')
- )
- comment = forms.CharField(max_length = 128)
+ min_value=1,
+ label=_(
+ 'Enter number of points to add or subtract'
+ )
+ )
+ comment = forms.CharField(max_length=128)
def clean_comment(self):
- if 'comment' in self.cleaned_data:
+ if 'comment' in self.cleaned_data:
comment = self.cleaned_data['comment'].strip()
if comment == '':
del self.cleaned_data['comment']
@@ -485,9 +598,7 @@ class ChangeUserStatusForm(forms.Form):
"moderation" tab
"""
- user_status = forms.ChoiceField(
- label = _('Change status to'),
- )
+ user_status = forms.ChoiceField(label=_('Change status to'))
def __init__(self, *arg, **kwarg):
@@ -508,12 +619,12 @@ class ChangeUserStatusForm(forms.Form):
#remove current status of the "subject" user from choices
user_status_choices = filter_choices(
- remove_choices = [subject.status, ],
- from_choices = user_status_choices
+ remove_choices=[subject.status, ],
+ from_choices=user_status_choices
)
#add prompt option
- user_status_choices = ( ('select', _('which one?')), ) \
+ user_status_choices = (('select', _('which one?')), ) \
+ user_status_choices
self.fields['user_status'].choices = user_status_choices
@@ -561,41 +672,39 @@ class ChangeUserStatusForm(forms.Form):
msg = _(
'If you wish to change %(username)s\'s status, '
'please make a meaningful selection.'
- ) % {'username': self.subject.username }
+ ) % {'username': self.subject.username}
raise forms.ValidationError(msg)
return self.cleaned_data
+
class SendMessageForm(forms.Form):
subject_line = forms.CharField(
- label = _('Subject line'),
- max_length = 64,
- widget = forms.TextInput(
- attrs = {'size':64},
- )
- )
+ label=_('Subject line'),
+ max_length=64,
+ widget=forms.TextInput(attrs={'size': 64}, )
+ )
body_text = forms.CharField(
- label = _('Message text'),
- max_length = 1600,
- widget = forms.Textarea(
- attrs = {'cols':64}
- )
+ label=_('Message text'),
+ max_length=1600,
+ widget=forms.Textarea(attrs={'cols': 64})
)
class NotARobotForm(forms.Form):
recaptcha = RecaptchaField(
- private_key = askbot_settings.RECAPTCHA_SECRET,
- public_key = askbot_settings.RECAPTCHA_KEY
+ private_key=askbot_settings.RECAPTCHA_SECRET,
+ public_key=askbot_settings.RECAPTCHA_KEY
)
+
class FeedbackForm(forms.Form):
name = forms.CharField(label=_('Your name (optional):'), required=False)
email = forms.EmailField(label=_('Email:'), required=False)
message = forms.CharField(
label=_('Your message:'),
max_length=800,
- widget=forms.Textarea(attrs={'cols':60})
+ widget=forms.Textarea(attrs={'cols': 60})
)
no_email = forms.BooleanField(
label=_("I don't want to give my email or receive a response:"),
@@ -612,19 +721,21 @@ class FeedbackForm(forms.Form):
def _add_recaptcha_field(self):
self.fields['recaptcha'] = RecaptchaField(
- private_key = askbot_settings.RECAPTCHA_SECRET,
- public_key = askbot_settings.RECAPTCHA_KEY
- )
+ private_key=askbot_settings.RECAPTCHA_SECRET,
+ public_key=askbot_settings.RECAPTCHA_KEY
+ )
def clean(self):
super(FeedbackForm, self).clean()
if not self.is_auth:
- if not self.cleaned_data['no_email'] and not self.cleaned_data['email']:
+ if not self.cleaned_data['no_email'] \
+ and not self.cleaned_data['email']:
msg = _('Please mark "I dont want to give my mail" field.')
self._errors['email'] = self.error_class([msg])
return self.cleaned_data
+
class FormWithHideableFields(object):
"""allows to swap a field widget to HiddenInput() and back"""
@@ -646,7 +757,122 @@ class FormWithHideableFields(object):
if name in self.__hidden_fields:
self.fields[name] = self.__hidden_fields.pop(name)
-class AskForm(forms.Form, FormWithHideableFields):
+
+class PostPrivatelyForm(forms.Form, FormWithHideableFields):
+ """has a single field `post_privately` with
+ two related methods"""
+
+ post_privately = forms.BooleanField(
+ label = _('keep private within your groups'),
+ required = False
+ )
+ def __init__(self, *args, **kwargs):
+ user = kwargs.pop('user', None)
+ self._user = user
+ super(PostPrivatelyForm, self).__init__(*args, **kwargs)
+ if self.allows_post_privately() == False:
+ self.hide_field('post_privately')
+
+ def allows_post_privately(self):
+ user = self._user
+ return (
+ user and user.is_authenticated() and \
+ user.can_make_group_private_posts()
+ )
+
+ def clean_post_privately(self):
+ if self.allows_post_privately() == False:
+ self.cleaned_data['post_privately'] = False
+ return self.cleaned_data['post_privately']
+
+
+class DraftQuestionForm(forms.Form):
+ """No real validation required for this form"""
+ title = forms.CharField(required=False)
+ text = forms.CharField(required=False)
+ tagnames = forms.CharField(required=False)
+
+
+class DraftAnswerForm(forms.Form):
+ """Only thread_id is required"""
+ thread_id = forms.IntegerField()
+ text = forms.CharField(required=False)
+
+
+class PostAsSomeoneForm(forms.Form):
+ post_author_username = forms.CharField(
+ initial=_('User name:'),
+ help_text=_(
+ 'Enter name to post on behalf of someone else. '
+ 'Can create new accounts.'
+ ),
+ required=False,
+ widget=forms.TextInput()
+ )
+ post_author_email = forms.CharField(
+ initial=_('Email address:'),
+ required=False,
+ widget=forms.TextInput(attrs={'class': 'tipped-input'})
+ )
+
+ def get_post_user(self, user):
+ """returns user on whose behalf the post or a revision
+ is being made
+ """
+ username = self.cleaned_data['post_author_username']
+ email= self.cleaned_data['post_author_email']
+ if user.is_administrator() and username and email:
+ post_user = user.get_or_create_fake_user(username, email)
+ else:
+ post_user = user
+ return post_user
+
+ def clean_post_author_username(self):
+ """if value is the same as initial, it is reset to
+ empty string
+ todo: maybe better to have field where initial value is invalid,
+ then we would not have to have two almost identical clean functions?
+ """
+ username = self.cleaned_data.get('post_author_username', '')
+ initial_username = unicode(self.fields['post_author_username'].initial)
+ if username == initial_username:
+ self.cleaned_data['post_author_username'] = ''
+ return self.cleaned_data['post_author_username']
+
+ def clean_post_author_email(self):
+ """if value is the same as initial, it is reset to
+ empty string"""
+ email = self.cleaned_data.get('post_author_email', '')
+ initial_email = unicode(self.fields['post_author_email'].initial)
+ if email == initial_email:
+ email = ''
+ if email != '':
+ email = forms.EmailField().clean(email)
+ self.cleaned_data['post_author_email'] = email
+ return email
+
+ def clean(self):
+ """requires email address if user name is given"""
+ username = self.cleaned_data.get('post_author_username', '')
+ email = self.cleaned_data.get('post_author_email', '')
+ if username == '' and email:
+ username_errors = self._errors.get(
+ 'post_author_username',
+ ErrorList()
+ )
+ username_errors.append(_('User name is required with the email'))
+ self._errors['post_author_username'] = username_errors
+ raise forms.ValidationError('missing user name')
+ elif email == '' and username:
+ email_errors = self._errors.get('post_author_email', ErrorList())
+ email_errors.append(_('Email is required if user name is added'))
+ self._errors['post_author_email'] = email_errors
+ raise forms.ValidationError('missing email')
+
+ return self.cleaned_data
+
+
+class AskForm(PostAsSomeoneForm, PostPrivatelyForm):
"""the form used to askbot questions
field ask_anonymously is shown to the user if the
if ALLOW_ASK_ANONYMOUSLY live setting is True
@@ -654,40 +880,118 @@ class AskForm(forms.Form, FormWithHideableFields):
in the cleaned data, and will evaluate to False if the
settings forbids anonymous asking
"""
- title = TitleField()
- text = QuestionEditorField()
- tags = TagNamesField()
+ title = TitleField()
+ tags = TagNamesField()
wiki = WikiField()
+ group_id = forms.IntegerField(required = False, widget = forms.HiddenInput)
ask_anonymously = forms.BooleanField(
- label = _('ask anonymously'),
- help_text = _(
+ label=_('ask anonymously'),
+ help_text=_(
'Check if you do not want to reveal your name '
'when asking this question'
),
- required = False,
+ required=False,
+ )
+ openid = forms.CharField(
+ required=False, max_length=255,
+ widget=forms.TextInput(attrs={'size': 40, 'class': 'openid-input'})
)
- openid = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 40, 'class':'openid-input'}))
- user = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35}))
- email = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35}))
def __init__(self, *args, **kwargs):
super(AskForm, self).__init__(*args, **kwargs)
+ #it's important that this field is set up dynamically
+ self.fields['text'] = QuestionEditorField()
#hide ask_anonymously field
- if askbot_settings.ALLOW_ASK_ANONYMOUSLY == False:
+ if askbot_settings.ALLOW_ASK_ANONYMOUSLY is False:
self.hide_field('ask_anonymously')
def clean_ask_anonymously(self):
"""returns false if anonymous asking is not allowed
"""
- if askbot_settings.ALLOW_ASK_ANONYMOUSLY == False:
+ if askbot_settings.ALLOW_ASK_ANONYMOUSLY is False:
self.cleaned_data['ask_anonymously'] = False
return self.cleaned_data['ask_anonymously']
+
ASK_BY_EMAIL_SUBJECT_HELP = _(
'Subject line is expected in the format: '
'[tag1, tag2, tag3,...] question title'
)
+#widgetforms
+class AskWidgetForm(forms.Form, FormWithHideableFields):
+ '''Simple form with just the title to ask a question'''
+
+ title = TitleField()
+ ask_anonymously = forms.BooleanField(
+ label=_('ask anonymously'),
+ help_text=_(
+ 'Check if you do not want to reveal your name '
+ 'when asking this question'
+ ),
+ required=False,
+ )
+
+ def __init__(self, include_text=True, *args, **kwargs):
+ super(AskWidgetForm, self).__init__(*args, **kwargs)
+ #hide ask_anonymously field
+ if not askbot_settings.ALLOW_ASK_ANONYMOUSLY:
+ self.hide_field('ask_anonymously')
+ self.fields['text'] = QuestionEditorField()
+ if not include_text:
+ self.hide_field('text')
+ #hack to make it validate
+ self.fields['text'].required = False
+ self.fields['text'].min_length = 0
+
+class CreateAskWidgetForm(forms.Form, FormWithHideableFields):
+ title = forms.CharField(max_length=100)
+ include_text_field = forms.BooleanField(required=False)
+
+ inner_style = forms.CharField(
+ widget=forms.Textarea,
+ required=False
+ )
+ outer_style = forms.CharField(
+ widget=forms.Textarea,
+ required=False
+ )
+
+ def __init__(self, *args, **kwargs):
+ from askbot.models import Tag
+ super(CreateAskWidgetForm, self).__init__(*args, **kwargs)
+ self.fields['group'] = forms.ModelChoiceField(
+ queryset=get_groups().exclude_personal(),
+ required=False
+ )
+ self.fields['tag'] = forms.ModelChoiceField(queryset=Tag.objects.get_content_tags(),
+ required=False)
+ if not askbot_settings.GROUPS_ENABLED:
+ self.hide_field('group')
+
+class CreateQuestionWidgetForm(forms.Form, FormWithHideableFields):
+ title = forms.CharField(max_length=100)
+ question_number = forms.CharField(initial='7')
+ tagnames = forms.CharField(label=_('tags'), max_length=50)
+ search_query = forms.CharField(max_length=50, required=False)
+ order_by = forms.ChoiceField(
+ choices=const.SEARCH_ORDER_BY,
+ initial='-added_at'
+ )
+ style = forms.CharField(
+ widget=forms.Textarea,
+ initial=const.DEFAULT_QUESTION_WIDGET_STYLE,
+ required=False
+ )
+
+ def __init__(self, *args, **kwargs):
+ super(CreateQuestionWidgetForm, self).__init__(*args, **kwargs)
+ self.fields['tagnames'] = TagNamesField()
+ self.fields['group'] = forms.ModelChoiceField(
+ queryset=get_groups().exclude(name__startswith='_internal'),
+ required=False
+ )
+
class AskByEmailForm(forms.Form):
""":class:`~askbot.forms.AskByEmailForm`
validates question data, where question was posted
@@ -706,12 +1010,13 @@ class AskByEmailForm(forms.Form):
* ``email`` - email address
* ``title`` - question title
* ``tagnames`` - tag names all in one string
- * ``body_text`` - body of question text - a pass-through, no extra validation
+ * ``body_text`` - body of question text -
+ a pass-through, no extra validation
"""
- sender = forms.CharField(max_length = 255)
+ sender = forms.CharField(max_length=255)
subject = forms.CharField(
- max_length = 255,
- error_messages = {
+ max_length=255,
+ error_messages={
'required': ASK_BY_EMAIL_SUBJECT_HELP
}
)
@@ -743,17 +1048,19 @@ class AskByEmailForm(forms.Form):
match = subject_re.match(raw_subject)
if match:
#make raw tags comma-separated
- if match.group(1) is None:#no tags
+ if match.group(1) is None: # no tags
self.cleaned_data['tagnames'] = ''
else:
- tagnames = match.group(1).replace(';',',')
+ tagnames = match.group(1).replace(';', ',')
#pre-process tags
tag_list = [tag.strip() for tag in tagnames.split(',')]
tag_list = [re.sub(r'\s+', ' ', tag) for tag in tag_list]
+
if askbot_settings.REPLACE_SPACE_WITH_DASH_IN_EMAILED_TAGS:
tag_list = [tag.replace(' ', '-') for tag in tag_list]
- tagnames = ' '.join(tag_list)#todo: use tag separator char here
+ #todo: use tag separator char here
+ tagnames = ' '.join(tag_list)
#clean tags - may raise ValidationError
self.cleaned_data['tagnames'] = TagNamesField().clean(tagnames)
@@ -765,22 +1072,29 @@ class AskByEmailForm(forms.Form):
raise forms.ValidationError(ASK_BY_EMAIL_SUBJECT_HELP)
return self.cleaned_data['subject']
-class AnswerForm(forms.Form):
- text = AnswerEditorField()
- wiki = WikiField()
- openid = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 40, 'class':'openid-input'}))
- user = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35}))
- email = forms.CharField(required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35}))
- email_notify = EmailNotifyField(initial = False)
+
+class AnswerForm(PostAsSomeoneForm, PostPrivatelyForm):
+ text = AnswerEditorField()
+ wiki = WikiField()
+ openid = forms.CharField(
+ required=False, max_length=255,
+ widget=forms.TextInput(attrs={'size': 40, 'class': 'openid-input'})
+ )
+ email_notify = EmailNotifyField(initial=False)
+
def __init__(self, *args, **kwargs):
super(AnswerForm, self).__init__(*args, **kwargs)
- self.fields['email_notify'].widget.attrs['id'] = 'question-subscribe-updates'
+ self.fields['text'] = AnswerEditorField()
+ self.fields['email_notify'].widget.attrs['id'] = \
+ 'question-subscribe-updates'
+
class VoteForm(forms.Form):
"""form used in ajax vote view (only comment_upvote so far)
"""
post_id = forms.IntegerField()
- cancel_vote = forms.CharField()#char because it is 'true' or 'false' as string
+ # char because it is 'true' or 'false' as string
+ cancel_vote = forms.CharField()
def clean_cancel_vote(self):
val = self.cleaned_data['cancel_vote']
@@ -790,7 +1104,9 @@ class VoteForm(forms.Form):
result = False
else:
del self.cleaned_data['cancel_vote']
- raise forms.ValidationError('either "true" or "false" strings expected')
+ raise forms.ValidationError(
+ 'either "true" or "false" strings expected'
+ )
self.cleaned_data['cancel_vote'] = result
return self.cleaned_data['cancel_vote']
@@ -798,52 +1114,66 @@ class VoteForm(forms.Form):
class CloseForm(forms.Form):
reason = forms.ChoiceField(choices=const.CLOSE_REASONS)
+
class RetagQuestionForm(forms.Form):
tags = TagNamesField()
- # initialize the default values
+
def __init__(self, question, *args, **kwargs):
+ """initialize the default values"""
super(RetagQuestionForm, self).__init__(*args, **kwargs)
self.fields['tags'].initial = question.thread.tagnames
+
class RevisionForm(forms.Form):
"""
Lists revisions of a Question or Answer
"""
- revision = forms.ChoiceField(widget=forms.Select(attrs={'style' : 'width:520px'}))
+ revision = forms.ChoiceField(
+ widget=forms.Select(
+ attrs={'style': 'width:520px'}
+ )
+ )
def __init__(self, post, latest_revision, *args, **kwargs):
super(RevisionForm, self).__init__(*args, **kwargs)
revisions = post.revisions.values_list(
- 'revision', 'author__username', 'revised_at', 'summary')
+ 'revision', 'author__username', 'revised_at', 'summary'
+ )
date_format = '%c'
- self.fields['revision'].choices = [
- (r[0], u'%s - %s (%s) %s' % (r[0], r[1], r[2].strftime(date_format), r[3]))
- for r in revisions]
+ rev_choices = list()
+ for r in revisions:
+ rev_details = u'%s - %s (%s) %s' % (
+ r[0], r[1], r[2].strftime(date_format), r[3]
+ )
+ rev_choices.append((r[0], rev_details))
+
+ self.fields['revision'].choices = rev_choices
self.fields['revision'].initial = latest_revision.revision
-class EditQuestionForm(forms.Form, FormWithHideableFields):
- title = TitleField()
- text = QuestionEditorField()
- tags = TagNamesField()
+class EditQuestionForm(PostAsSomeoneForm, PostPrivatelyForm):
+ title = TitleField()
+ tags = TagNamesField()
summary = SummaryField()
wiki = WikiField()
reveal_identity = forms.BooleanField(
- help_text = _(
+ help_text=_(
'You have asked this question anonymously, '
'if you decide to reveal your identity, please check '
'this box.'
),
- label = _('reveal identity'),
- required = False,
+ label=_('reveal identity'),
+ required=False,
)
#todo: this is odd that this form takes question as an argument
def __init__(self, *args, **kwargs):
"""populate EditQuestionForm with initial data"""
self.question = kwargs.pop('question')
- self.user = kwargs.pop('user')
+ self.user = kwargs['user']#preserve for superclass
revision = kwargs.pop('revision')
super(EditQuestionForm, self).__init__(*args, **kwargs)
+ #it is important to add this field dynamically
+ self.fields['text'] = QuestionEditorField()
self.fields['title'].initial = revision.title
self.fields['text'].initial = revision.text
self.fields['tags'].initial = revision.tagnames
@@ -852,11 +1182,20 @@ class EditQuestionForm(forms.Form, FormWithHideableFields):
if not self.can_stay_anonymous():
self.hide_field('reveal_identity')
+ def has_changed(self):
+ if super(EditQuestionForm, self).has_changed():
+ return True
+ if askbot_settings.GROUPS_ENABLED:
+ return self.question.is_private() \
+ != self.cleaned_data['post_privately']
+ else:
+ return False
+
def can_stay_anonymous(self):
"""determines if the user cat keep editing the question
anonymously"""
- return (askbot_settings.ALLOW_ASK_ANONYMOUSLY \
- and self.question.is_anonymous \
+ return (askbot_settings.ALLOW_ASK_ANONYMOUSLY
+ and self.question.is_anonymous
and self.user.is_owner_of(self.question)
)
@@ -882,7 +1221,7 @@ class EditQuestionForm(forms.Form, FormWithHideableFields):
"""
value = self.cleaned_data['reveal_identity']
if self.question.is_anonymous:
- if value == True:
+ if value is True:
if self.user.is_owner_of(self.question):
#regardless of the ALLOW_ASK_ANONYMOUSLY
return True
@@ -900,7 +1239,7 @@ class EditQuestionForm(forms.Form, FormWithHideableFields):
else:
can_ask_anon = askbot_settings.ALLOW_ASK_ANONYMOUSLY
is_owner = self.user.is_owner_of(self.question)
- if can_ask_anon == False and is_owner:
+ if can_ask_anon is False and is_owner:
self.show_field('reveal_identity')
raise forms.ValidationError(
_(
@@ -922,57 +1261,72 @@ class EditQuestionForm(forms.Form, FormWithHideableFields):
field edit_anonymously. It relies on correct cleaning
if the "reveal_identity" field
"""
+ super(EditQuestionForm, self).clean()
reveal_identity = self.cleaned_data.get('reveal_identity', False)
stay_anonymous = False
- if reveal_identity == False and self.can_stay_anonymous():
+ if reveal_identity is False and self.can_stay_anonymous():
stay_anonymous = True
self.cleaned_data['stay_anonymous'] = stay_anonymous
return self.cleaned_data
-class EditAnswerForm(forms.Form):
- text = AnswerEditorField()
+class EditAnswerForm(PostAsSomeoneForm, PostPrivatelyForm):
summary = SummaryField()
wiki = WikiField()
def __init__(self, answer, revision, *args, **kwargs):
+ self.answer = answer
super(EditAnswerForm, self).__init__(*args, **kwargs)
+ #it is important to add this field dynamically
+ self.fields['text'] = AnswerEditorField()
self.fields['text'].initial = revision.text
self.fields['wiki'].initial = answer.wiki
+ def has_changed(self):
+ #todo: this function is almost copy/paste of EditQuestionForm.has_changed()
+ if super(EditAnswerForm, self).has_changed():
+ return True
+ if askbot_settings.GROUPS_ENABLED:
+ return self.answer.is_private() \
+ != self.cleaned_data['post_privately']
+ else:
+ return False
+
+
class EditTagWikiForm(forms.Form):
- text = forms.CharField(required = False)
+ text = forms.CharField(required=False)
tag_id = forms.IntegerField()
+
class EditUserForm(forms.Form):
email = forms.EmailField(
label=u'Email',
required=True,
max_length=255,
- widget=forms.TextInput(attrs={'size' : 35})
+ widget=forms.TextInput(attrs={'size': 35})
)
realname = forms.CharField(
label=_('Real name'),
required=False,
max_length=255,
- widget=forms.TextInput(attrs={'size' : 35})
+ widget=forms.TextInput(attrs={'size': 35})
)
website = forms.URLField(
label=_('Website'),
required=False,
max_length=255,
- widget=forms.TextInput(attrs={'size' : 35})
+ widget=forms.TextInput(attrs={'size': 35})
)
city = forms.CharField(
label=_('City'),
required=False,
max_length=255,
- widget=forms.TextInput(attrs={'size' : 35})
+ widget=forms.TextInput(attrs={'size': 35})
)
- country = CountryField(required = False)
+ country = CountryField(required=False)
show_country = forms.BooleanField(
label=_('Show country'),
@@ -986,15 +1340,18 @@ class EditUserForm(forms.Form):
birthday = forms.DateField(
label=_('Date of birth'),
- help_text=_('will not be shown, used to calculate age, format: YYYY-MM-DD'),
+ help_text=_(
+ 'will not be shown, used to calculate '
+ 'age, format: YYYY-MM-DD'
+ ),
required=False,
- widget=forms.TextInput(attrs={'size' : 35})
+ widget=forms.TextInput(attrs={'size': 35})
)
about = forms.CharField(
label=_('Profile'),
required=False,
- widget=forms.Textarea(attrs={'cols' : 60})
+ widget=forms.Textarea(attrs={'cols': 60})
)
def __init__(self, user, *args, **kwargs):
@@ -1008,7 +1365,7 @@ class EditUserForm(forms.Form):
self.fields['realname'].initial = user.real_name
self.fields['website'].initial = user.website
self.fields['city'].initial = user.location
- if user.country == None:
+ if user.country is None:
country = 'unknown'
else:
country = user.country
@@ -1026,24 +1383,35 @@ class EditUserForm(forms.Form):
"""For security reason one unique email in database"""
if self.user.email != self.cleaned_data['email']:
#todo dry it, there is a similar thing in openidauth
- if askbot_settings.EMAIL_UNIQUE == True:
+ if askbot_settings.EMAIL_UNIQUE is True:
if 'email' in self.cleaned_data:
try:
- User.objects.get(email = self.cleaned_data['email'])
+ User.objects.get(email=self.cleaned_data['email'])
except User.DoesNotExist:
return self.cleaned_data['email']
except User.MultipleObjectsReturned:
- raise forms.ValidationError(_('this email has already been registered, please use another one'))
- raise forms.ValidationError(_('this email has already been registered, please use another one'))
+ raise forms.ValidationError(_(
+ 'this email has already been registered, '
+ 'please use another one')
+ )
+ raise forms.ValidationError(_(
+ 'this email has already been registered, '
+ 'please use another one')
+ )
return self.cleaned_data['email']
+
class TagFilterSelectionForm(forms.ModelForm):
email_tag_filter_strategy = forms.ChoiceField(
- choices = const.TAG_DISPLAY_FILTER_STRATEGY_CHOICES,
initial = const.EXCLUDE_IGNORED,
label = _('Choose email tag filter'),
widget = forms.RadioSelect
)
+ def __init__(self, *args, **kwargs):
+ super(TagFilterSelectionForm, self).__init__(*args, **kwargs)
+ choices = get_tag_display_filter_strategy_choices()
+ self.fields['email_tag_filter_strategy'].choices = choices
+
class Meta:
model = User
fields = ('email_tag_filter_strategy',)
@@ -1060,31 +1428,31 @@ class TagFilterSelectionForm(forms.ModelForm):
class EmailFeedSettingField(forms.ChoiceField):
def __init__(self, *arg, **kwarg):
kwarg['choices'] = const.NOTIFICATION_DELIVERY_SCHEDULE_CHOICES
- #kwarg['initial'] = askbot_settings.DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE
kwarg['widget'] = forms.RadioSelect
super(EmailFeedSettingField, self).__init__(*arg, **kwarg)
+
class EditUserEmailFeedsForm(forms.Form):
FORM_TO_MODEL_MAP = {
- 'all_questions':'q_all',
- 'asked_by_me':'q_ask',
- 'answered_by_me':'q_ans',
- 'individually_selected':'q_sel',
- 'mentions_and_comments':'m_and_c',
+ 'all_questions': 'q_all',
+ 'asked_by_me': 'q_ask',
+ 'answered_by_me': 'q_ans',
+ 'individually_selected': 'q_sel',
+ 'mentions_and_comments': 'm_and_c',
}
NO_EMAIL_INITIAL = {
- 'all_questions':'n',
- 'asked_by_me':'n',
- 'answered_by_me':'n',
- 'individually_selected':'n',
- 'mentions_and_comments':'n',
+ 'all_questions': 'n',
+ 'asked_by_me': 'n',
+ 'answered_by_me': 'n',
+ 'individually_selected': 'n',
+ 'mentions_and_comments': 'n',
}
INSTANT_EMAIL_INITIAL = {
- 'all_questions':'i',
- 'asked_by_me':'i',
- 'answered_by_me':'i',
- 'individually_selected':'i',
- 'mentions_and_comments':'i',
+ 'all_questions': 'i',
+ 'asked_by_me': 'i',
+ 'answered_by_me': 'i',
+ 'individually_selected': 'i',
+ 'mentions_and_comments': 'i',
}
asked_by_me = EmailFeedSettingField(
@@ -1107,7 +1475,7 @@ class EditUserEmailFeedsForm(forms.Form):
def set_initial_values(self, user=None):
from askbot import models
KEY_MAP = dict([(v, k) for k, v in self.FORM_TO_MODEL_MAP.iteritems()])
- if user != None:
+ if user is not None:
settings = models.EmailFeedSetting.objects.filter(subscriber=user)
initial_values = {}
for setting in settings:
@@ -1137,7 +1505,7 @@ class EditUserEmailFeedsForm(forms.Form):
"""
return self.FORM_TO_MODEL_MAP.values()
- def set_frequency(self, frequency = 'n'):
+ def set_frequency(self, frequency='n'):
data = {
'all_questions': frequency,
'asked_by_me': frequency,
@@ -1149,9 +1517,9 @@ class EditUserEmailFeedsForm(forms.Form):
self.cleaned_data = data
self.initial = data
- def save(self,user,save_unbound=False):
- """
- with save_unbound==True will bypass form validation and save initial values
+ def save(self, user, save_unbound=False):
+ """with save_unbound==True will bypass form
+ validation and save initial values
"""
from askbot import models
changed = False
@@ -1179,23 +1547,25 @@ class EditUserEmailFeedsForm(forms.Form):
user.followed_threads.clear()
return changed
+
class SubscribeForEmailUpdatesField(forms.ChoiceField):
"""a simple yes or no field to subscribe for email or not"""
def __init__(self, **kwargs):
kwargs['widget'] = forms.widgets.RadioSelect
kwargs['error_messages'] = {
- 'required':_('please choose one of the options above')
+ 'required': _('please choose one of the options above')
}
kwargs['choices'] = (
- ('y',_('okay, let\'s try!')),
+ ('y', _('okay, let\'s try!')),
(
'n',
- _('no %(sitename)s email please, thanks') \
+ _('no %(sitename)s email please, thanks')
% {'sitename': askbot_settings.APP_SHORT_NAME}
)
)
super(SubscribeForEmailUpdatesField, self).__init__(**kwargs)
+
class SimpleEmailSubscribeForm(forms.Form):
subscribe = SubscribeForEmailUpdatesField()
@@ -1211,11 +1581,13 @@ class SimpleEmailSubscribeForm(forms.Form):
email_settings_form = EFF(initial=EFF.NO_EMAIL_INITIAL)
email_settings_form.save(user, save_unbound=True)
+
class GroupLogoURLForm(forms.Form):
"""form for saving group logo url"""
group_id = forms.IntegerField()
image_url = forms.CharField()
+
class EditGroupMembershipForm(forms.Form):
"""a form for adding or removing users
to and from user groups"""
@@ -1231,11 +1603,26 @@ class EditGroupMembershipForm(forms.Form):
raise forms.ValidationError('invalid action')
return action
+
class EditRejectReasonForm(forms.Form):
- reason_id = forms.IntegerField(required = False)
+ reason_id = forms.IntegerField(required=False)
title = CountedWordsField(
- min_words = 1, max_words = 4, field_name = _('Title')
+ min_words=1, max_words=4, field_name=_('Title')
)
details = CountedWordsField(
- min_words = 6, field_name = _('Description')
+ min_words=6, field_name=_('Description')
)
+
+class ModerateTagForm(forms.Form):
+ tag_id = forms.IntegerField()
+ thread_id = forms.IntegerField(required = False)
+ action = forms.CharField()
+
+ def clean_action(self):
+ action = self.cleaned_data['action']
+ assert(action in ('accept', 'reject'))
+ return action
+
+class ShareQuestionForm(forms.Form):
+ thread_id = forms.IntegerField()
+ recipient_name = forms.CharField()
diff --git a/askbot/mail/__init__.py b/askbot/mail/__init__.py
index 7ff8a2d3..74aa27e9 100644
--- a/askbot/mail/__init__.py
+++ b/askbot/mail/__init__.py
@@ -11,11 +11,15 @@ from django.forms import ValidationError
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import string_concat
from django.template import Context
+from django.utils.html import strip_tags
from askbot import exceptions
from askbot import const
from askbot.conf import settings as askbot_settings
from askbot.utils import url_utils
from askbot.utils.file_utils import store_file
+from askbot.utils.html import absolutize_urls
+
+from bs4 import BeautifulSoup
#todo: maybe send_mail functions belong to models
#or the future API
def prefix_the_subject_line(subject):
@@ -77,6 +81,19 @@ def thread_headers(post, orig_post, update):
return headers
+def clean_html_email(email_body):
+ '''needs more clenup might not work for other email templates
+ that does not use table layout'''
+
+ remove_linejump = lambda s: s.replace('\n', '')
+
+ soup = BeautifulSoup(email_body)
+ table_tds = soup.find('body')
+ phrases = map(lambda s: s.strip(),
+ filter(bool, table_tds.get_text().split('\n')))
+
+ return '\n\n'.join(phrases)
+
def send_mail(
subject_line = None,
body_text = None,
@@ -100,17 +117,18 @@ def send_mail(
if raise_on_failure is True, exceptions.EmailNotSent is raised
"""
+ body_text = absolutize_urls(body_text)
try:
assert(subject_line is not None)
subject_line = prefix_the_subject_line(subject_line)
- msg = mail.EmailMessage(
- subject_line,
- body_text,
+ msg = mail.EmailMultiAlternatives(
+ subject_line,
+ clean_html_email(body_text),
from_email,
recipient_list,
headers = headers
)
- msg.content_subtype = 'html'
+ msg.attach_alternative(body_text, "text/html")
msg.send()
if related_object is not None:
assert(activity_type is not None)
@@ -122,9 +140,12 @@ def send_mail(
def mail_moderators(
subject_line = '',
body_text = '',
- raise_on_failure = False):
+ raise_on_failure = False,
+ headers = None
+ ):
"""sends email to forum moderators and admins
"""
+ body_text = absolutize_urls(body_text)
from django.db.models import Q
from askbot.models import User
recipient_list = User.objects.filter(
@@ -139,7 +160,15 @@ def mail_moderators(
from_email = django_settings.DEFAULT_FROM_EMAIL
try:
- mail.send_mail(subject_line, body_text, from_email, recipient_list)
+ msg = mail.EmailMessage(
+ subject_line,
+ body_text,
+ from_email,
+ recipient_list,
+ headers = headers or {}
+ )
+ msg.content_subtype = 'html'
+ msg.send()
except smtplib.SMTPException, error:
logging.critical(unicode(error))
if raise_on_failure == True:
@@ -227,7 +256,7 @@ def bounce_email(
headers = {}
if reply_to:
headers['Reply-To'] = reply_to
-
+
send_mail(
recipient_list = (email,),
subject_line = 'Re: ' + subject,
@@ -261,10 +290,11 @@ def process_attachment(attachment):
def extract_user_signature(text, reply_code):
"""extracts email signature as text trailing
the reply code"""
- if reply_code in text:
+ striped_text = strip_tags(text)
+ if reply_code in striped_text:
#extract the signature
tail = list()
- for line in reversed(text.splitlines()):
+ for line in reversed(striped_text.splitlines()):
#scan backwards from the end until the magic line
if reply_code in line:
break
@@ -284,7 +314,7 @@ def process_parts(parts, reply_code = None):
"""Process parts will upload the attachments and parse out the
body, if body is multipart. Secondly - links to attachments
will be added to the body of the question.
- Returns ready to post body of the message and the list
+ Returns ready to post body of the message and the list
of uploaded files.
"""
body_markdown = ''
@@ -302,7 +332,7 @@ def process_parts(parts, reply_code = None):
stored_files.append(stored_file)
body_markdown += markdown
- #if the response separator is present -
+ #if the response separator is present -
#split the body with it, and discard the "so and so wrote:" part
if reply_code:
signature = extract_user_signature(body_markdown, reply_code)
@@ -315,7 +345,8 @@ def process_parts(parts, reply_code = None):
def process_emailed_question(
- from_address, subject, body_text, stored_files, tags = None
+ from_address, subject, body_text, stored_files,
+ tags=None, group_id=None
):
"""posts question received by email or bounces the message"""
#a bunch of imports here, to avoid potential circular import issues
@@ -334,14 +365,21 @@ def process_emailed_question(
form = AskByEmailForm(data)
if form.is_valid():
email_address = form.cleaned_data['email']
- user = User.objects.get(
- email__iexact = email_address
- )
+ user = User.objects.get(email__iexact = email_address)
- if user.can_post_by_email() == False:
+ if user.can_post_by_email() is False:
raise PermissionDenied(messages.insufficient_reputation(user))
- if user.email_isvalid == False:
+ body_text = form.cleaned_data['body_text']
+ stripped_body_text = user.strip_email_signature(body_text)
+ signature_not_detected = (
+ stripped_body_text == body_text and user.email_signature
+ )
+
+ #ask for signature response if user's email has not been
+ #validated yet or if email signature could not be found
+ if user.email_isvalid is False or signature_not_detected:
+
reply_to = ReplyAddress.objects.create_new(
user = user,
reply_action = 'validate_email'
@@ -351,23 +389,19 @@ def process_emailed_question(
tagnames = form.cleaned_data['tagnames']
title = form.cleaned_data['title']
- body_text = form.cleaned_data['body_text']
#defect - here we might get "too many tags" issue
if tags:
tagnames += ' ' + ' '.join(tags)
- stripped_body_text = user.strip_email_signature(body_text)
- if stripped_body_text == body_text and user.email_signature:
- #todo: send an email asking to update the signature
- raise ValueError('email signature changed')
user.post_question(
- title = title,
- tags = tagnames.strip(),
- body_text = stripped_body_text,
- by_email = True,
- email_address = from_address
+ title=title,
+ tags=tagnames.strip(),
+ body_text=stripped_body_text,
+ by_email=True,
+ email_address=from_address,
+ group_id=group_id
)
else:
raise ValidationError()
diff --git a/askbot/mail/lamson_handlers.py b/askbot/mail/lamson_handlers.py
index f7053414..da09eec2 100644
--- a/askbot/mail/lamson_handlers.py
+++ b/askbot/mail/lamson_handlers.py
@@ -6,12 +6,11 @@ from django.template import Context
from django.utils.translation import ugettext as _
from lamson.routing import route, stateless
from lamson.server import Relay
-from askbot.models import ReplyAddress, Tag
+from askbot.models import ReplyAddress, Group, Tag
from askbot import mail
from askbot.conf import settings as askbot_settings
from askbot.skins.loaders import get_template
-
#we might end up needing to use something like this
#to distinguish the reply text from the quoted original message
"""
@@ -66,7 +65,7 @@ def is_inline_attachment(part):
def format_attachment(part):
"""takes message part and turns it into SimpleUploadedFile object"""
- att_info = get_attachment_info(part)
+ att_info = get_attachment_info(part)
name = att_info.get('filename', None)
content_type = get_content_type(part)
return SimpleUploadedFile(name, part.body, content_type)
@@ -127,10 +126,11 @@ def process_reply(func):
"""processes forwarding rules, and run the handler
in the case of error, send a bounce email
"""
+
try:
for rule in django_settings.LAMSON_FORWARD:
if re.match(rule['pattern'], message.base['to']):
- relay = Relay(host=rule['host'],
+ relay = Relay(host=rule['host'],
port=rule['port'], debug=1)
relay.deliver(message)
return
@@ -138,6 +138,7 @@ def process_reply(func):
pass
error = None
+
try:
reply_address = ReplyAddress.objects.get(
address = address,
@@ -145,10 +146,18 @@ def process_reply(func):
)
#here is the business part of this function
+ parts = get_parts(message)
+ for part_type, content in parts:
+ if part_type == 'body':
+ print '==============================='
+ print 'message :', content
+ break
+ else:
+ continue
func(
from_address = message.From,
subject_line = message['Subject'],
- parts = get_parts(message),
+ parts = parts,
reply_address_object = reply_address
)
@@ -169,7 +178,7 @@ def process_reply(func):
subject_line = "Error posting your reply",
body_text = body_text,
recipient_list = [message.From],
- )
+ )
return wrapped
@@ -195,18 +204,16 @@ def ASK(message, host = None, addr = None):
from_address, subject, body_text, stored_files
)
else:
+ #this is the Ask the group branch
if askbot_settings.GROUP_EMAIL_ADDRESSES_ENABLED == False:
return
try:
- group_tag = Tag.group_tags.get(
- deleted = False,
- name__iexact = addr
- )
+ group = Group.objects.get(name__iexact=addr)
mail.process_emailed_question(
from_address, subject, body_text, stored_files,
- tags = [group_tag.name, ]
+ group_id = group.id
)
- except Tag.DoesNotExist:
+ except Group.DoesNotExist:
#do nothing because this handler will match all emails
return
except Tag.MultipleObjectsReturned:
@@ -267,7 +274,7 @@ def PROCESS(
"""handler to process the emailed message
and make a post to askbot based on the contents of
the email, including the text body and the file attachments"""
- #1) get actual email content
+ #1) get actual email content
# todo: factor this out into the process_reply decorator
reply_code = reply_address_object.address
body_text, stored_files, signature = mail.process_parts(parts, reply_code)
diff --git a/askbot/mail/messages.py b/askbot/mail/messages.py
index 24091971..3ab3ff2f 100644
--- a/askbot/mail/messages.py
+++ b/askbot/mail/messages.py
@@ -32,6 +32,17 @@ def ask_for_signature(user, footer_code = None):
'footer_code': footer_code
}
+@message(template = 'email/notify_admins_about_new_tags.html')
+def notify_admins_about_new_tags(
+ tags = None, thread = None, user = None
+):
+ thread_url = thread.get_absolute_url()
+ return {
+ 'thread_url': html_utils.site_url(thread_url),
+ 'tags': tags,
+ 'user': user
+ }
+
@message(template = 'email/insufficient_rep_to_post_by_email.html')
def insufficient_reputation(user):
"""tells user that he does not have
diff --git a/askbot/management/commands/askbot_add_test_content.py b/askbot/management/commands/askbot_add_test_content.py
index ace629d0..7867fcec 100644
--- a/askbot/management/commands/askbot_add_test_content.py
+++ b/askbot/management/commands/askbot_add_test_content.py
@@ -2,6 +2,7 @@ from django.core.management.base import NoArgsCommand
from askbot.models import User
from optparse import make_option
from askbot.utils.console import choice_dialog
+from askbot.conf import settings as askbot_settings
NUM_USERS = 40
@@ -20,7 +21,8 @@ BAD_STUFF = "<script>alert('hohoho')</script>"
USERNAME_TEMPLATE = BAD_STUFF + "test_user_%s"
PASSWORD_TEMPLATE = "test_password_%s"
EMAIL_TEMPLATE = "test_user_%s@askbot.org"
-TITLE_TEMPLATE = "Test question title No.%s" + BAD_STUFF
+TITLE_TEMPLATE = "Question No.%s" + BAD_STUFF
+LONG_TITLE_TEMPLATE = TITLE_TEMPLATE + 'a lot more text a lot more text a lot more text '*5
TAGS_TEMPLATE = [BAD_STUFF + "tag-%s-0", BAD_STUFF + "tag-%s-1"] # len(TAGS_TEMPLATE) tags per question
CONTENT_TEMPLATE = BAD_STUFF + """Lorem lean startup ipsum product market fit customer
@@ -33,6 +35,13 @@ ANSWER_TEMPLATE = BAD_STUFF + """Accelerator photo sharing business school drop
COMMENT_TEMPLATE = BAD_STUFF + """Main differentiators business model micro economics
marketplace equity augmented reality human computer"""
+ALERT_SETTINGS_KEYS = (
+ 'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_Q_ASK',
+ 'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_Q_ANS',
+ 'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_Q_ALL',
+ 'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_Q_SEL',
+ 'DEFAULT_NOTIFICATION_DELIVERY_SCHEDULE_M_AND_C',
+)
class Command(NoArgsCommand):
option_list = NoArgsCommand.option_list + (
@@ -40,6 +49,20 @@ class Command(NoArgsCommand):
help='Do not prompt the user for input of any kind.'),
)
+ def save_alert_settings(self):
+ settings = {}
+ for key in ALERT_SETTINGS_KEYS:
+ settings[key] = getattr(askbot_settings, key)
+ self.alert_settings = settings
+
+ def stop_alerts(self):
+ for key in ALERT_SETTINGS_KEYS:
+ askbot_settings.update(key, 'n')
+
+ def restore_saved_alert_settings(self):
+ for key in ALERT_SETTINGS_KEYS:
+ askbot_settings.update(key, self.alert_settings[key])
+
def print_if_verbose(self, text):
"Only print if user chooses verbose output"
if self.verbosity > 0:
@@ -49,12 +72,19 @@ class Command(NoArgsCommand):
"Create the users and return an array of created users"
users = []
- #add admin with the same password
+ #add admin with the same password - this user will be admin automatically
admin = User.objects.create_user('admin', 'admin@example.com')
admin.set_password('admin')
+ admin.save()
self.print_if_verbose("Created User 'admin'")
users.append(admin)
+ #this user will have regular privileges, because it's second
+ joe = User.objects.create_user('joe', 'joe@example.com')
+ joe.set_password('joe')
+ joe.save()
+ self.print_if_verbose("Created User 'joe'")
+
# Keeping the created users in array - we will iterate over them
# several times, we don't want querying the model each and every time.
for i in range(NUM_USERS):
@@ -99,11 +129,18 @@ class Command(NoArgsCommand):
tags = " ".join([t%user.id for t in TAGS_TEMPLATE])
if i < NUM_QUESTIONS/2:
tags += ' one-tag'
+
+ if i % 2 == 0:
+ question_template = TITLE_TEMPLATE
+ else:
+ question_template = LONG_TITLE_TEMPLATE
+
active_question = user.post_question(
- title = TITLE_TEMPLATE % user.id,
+ title = question_template % user.id,
body_text = CONTENT_TEMPLATE,
tags = tags,
)
+
self.print_if_verbose("Created Question '%s' with tags: '%s'" % (
active_question.thread.title, tags,)
)
@@ -199,7 +236,8 @@ class Command(NoArgsCommand):
if answer != "yes":
return
-
+ self.save_alert_settings()
+ self.stop_alerts()# saves time on running the command
# Create Users
users = self.create_users()
@@ -251,4 +289,6 @@ class Command(NoArgsCommand):
)
self.print_if_verbose("User has accepted a best answer")
+ self.restore_saved_alert_settings()
+
self.print_if_verbose("DONE")
diff --git a/askbot/management/commands/build_livesettings_cache.py b/askbot/management/commands/build_livesettings_cache.py
new file mode 100644
index 00000000..1898fc6a
--- /dev/null
+++ b/askbot/management/commands/build_livesettings_cache.py
@@ -0,0 +1,12 @@
+from django.core.management.base import NoArgsCommand
+
+class Command(NoArgsCommand):
+ '''Loads livesettings values to cache helping speed up
+ initial load time for the users'''
+
+ def handle_noargs(self, **options):
+ from askbot.conf import settings
+ #Just loads all the settings that way they will be in the cache
+ for key, value in settings._ConfigSettings__instance.items():
+ empty1 = getattr(settings, key)
+ print 'cache pre-loaded'
diff --git a/askbot/management/commands/clean_session.py b/askbot/management/commands/clean_session.py
index 6ba9352c..2e663b22 100644
--- a/askbot/management/commands/clean_session.py
+++ b/askbot/management/commands/clean_session.py
@@ -1,13 +1,18 @@
+"""deletes expired sessions from the session database table
+works only when sessions are stored in the database
+"""
from django.core.management.base import NoArgsCommand
from django.contrib.sessions.models import Session
from django.db import transaction
from optparse import make_option
-from askbot.utils.console import print_progress
+from askbot.utils.console import ProgressBar
from datetime import datetime
-DELETE_LIMIT = 1000
+ITEMS_PER_TRANSACTION = 1000
class Command(NoArgsCommand):
+ """Django management command class"""
+
option_list = NoArgsCommand.option_list + (
make_option('--quiet',
action='store_true',
@@ -19,32 +24,23 @@ class Command(NoArgsCommand):
@transaction.commit_manually
def handle_noargs(self, **options):
- '''deletes old sessions'''
+ """deletes old sessions"""
quiet = options.get('quiet', False)
- expired_session_count = Session.objects.filter(expire_date__lt=datetime.now()).count()
- expired_session_list= Session.objects.filter(expire_date__lt=datetime.now()).values_list('session_key', flat=True)
- transaction.commit()
-
- if not quiet:
- print "There are %d expired sessions" % expired_session_count
- range_limit = len(expired_session_list) - 1
- higher_limit = lower_limit = 0
+ expired_sessions = Session.objects.filter(
+ expire_date__lt=datetime.now()
+ )
+ count = expired_sessions.count()
+ expired_sessions = expired_sessions.iterator()
+ if quiet is False:
+ message = 'There are %d expired sessions' % count
+ expired_sessions = ProgressBar(expired_sessions, count, message)
+
+ deleted_count = 0
+ for session in expired_sessions:
+ session.delete()
+ deleted_count += 1
+ if deleted_count % ITEMS_PER_TRANSACTION == 0:
+ transaction.commit()
- for i in range(DELETE_LIMIT, range_limit, DELETE_LIMIT):
- lower_limit = i
- higher_limit = lower_limit + DELETE_LIMIT
- sublist = expired_session_list[lower_limit:higher_limit]
- Session.objects.filter(session_key__in = sublist).delete()
- transaction.commit()
- if not quiet:
- print_progress(higher_limit-1, expired_session_count)
-
- if higher_limit < expired_session_list:
- sublist = expired_session_list[higher_limit:expired_session_count]
- Session.objects.filter(session_key__in = sublist).delete()
- print_progress(expired_session_count, expired_session_count)
- transaction.commit()
-
- if not quiet:
- print "sessions cleared"
+ transaction.commit()
diff --git a/askbot/management/commands/delete_unused_tags.py b/askbot/management/commands/delete_unused_tags.py
index 9b7c3c1b..9bcf191b 100644
--- a/askbot/management/commands/delete_unused_tags.py
+++ b/askbot/management/commands/delete_unused_tags.py
@@ -1,26 +1,23 @@
from django.core.management.base import NoArgsCommand
from django.db import transaction
from askbot import models
-from askbot.utils import console
+from askbot.utils.console import ProgressBar
+from askbot.conf import settings as askbot_settings
import sys
class Command(NoArgsCommand):
@transaction.commit_manually
def handle_noargs(self, **options):
tags = models.Tag.objects.all()
- count = 0
- print "Searching for unused tags:",
+ message = 'Searching for unused tags:'
total = tags.count()
+ tags = tags.iterator()
deleted_tags = list()
- for tag in tags:
+ for tag in ProgressBar(tags, total, message):
if not tag.threads.exists():
deleted_tags.append(tag.name)
tag.delete()
transaction.commit()
- count += 1
- progress = 100*float(count)/float(total)
- console.print_progress('%6.2f%%', progress)
- print '%6.2f%%' % 100
if deleted_tags:
found_count = len(deleted_tags)
@@ -36,4 +33,3 @@ class Command(NoArgsCommand):
print "Deleted."
else:
print "Did not find any."
-
diff --git a/askbot/management/commands/rename_tags_id.py b/askbot/management/commands/rename_tags_id.py
index 90dc2916..f6fe05ae 100644
--- a/askbot/management/commands/rename_tags_id.py
+++ b/askbot/management/commands/rename_tags_id.py
@@ -27,8 +27,8 @@ def get_similar_tags_from_strings(tag_strings, tag_name):
"""returns a list of tags, similar to tag_name from a set of questions"""
grab_pattern = r'\b([%(ch)s]*%(nm)s[%(ch)s]*)\b' % \
- {'ch': const.TAG_CHARS, 'nm': from_tag.name}
- grab_re = re.compile(grab_pattern, RE.IGNORECASE)
+ {'ch': const.TAG_CHARS, 'nm': tag_name}
+ grab_re = re.compile(grab_pattern, re.IGNORECASE)
similar_tags = set()
for tag_string in tag_strings:
@@ -103,9 +103,9 @@ rename_tags, but using tag id's
to_tags = get_tags_by_ids(to_tag_ids)
admin = get_admin(options['user_id'])
- questions = models.Question.objects.all()
+ questions = models.Thread.objects.all()
for from_tag in from_tags:
- questions = questions.filter(tags = from_tag)
+ questions = questions.filter(tags=from_tag)
#print some feedback here and give a chance to bail out
question_count = questions.count()
@@ -121,7 +121,7 @@ or repost a bug, if that does not help"""
print "%d questions match." % question_count
print "First 10 are:"
for question in questions[:10]:
- print '* %s' % question.thread.title.strip()
+ print '* %s' % question.title.strip()
from_tag_names = format_tag_name_list(from_tags)
to_tag_names = format_tag_name_list(to_tags)
@@ -145,7 +145,7 @@ or repost a bug, if that does not help"""
tag_names.difference_update(from_tag_names)
admin.retag_question(
- question = question,
+ question = question._question_post(),
tags = u' '.join(tag_names),
#silent = True #do we want to timestamp activity on question
)
@@ -159,8 +159,8 @@ or repost a bug, if that does not help"""
#may need to run assertions on that there are
#print 'Searching for similar tags...',
- #leftover_questions = models.Question.objects.filter(
- # icontains = from_tag.name
+ #leftover_questions = models.Thread.objects.filter(
+ # icontains=from_tag.name
# )
#if leftover_questions.count() > 0:
# tag_strings = leftover_questions.values_list('tagnames', flat=True)
diff --git a/askbot/management/commands/sample_command.py b/askbot/management/commands/sample_command.py
index bcdcb58e..40debe63 100644
--- a/askbot/management/commands/sample_command.py
+++ b/askbot/management/commands/sample_command.py
@@ -1,7 +1,7 @@
from django.core.management.base import NoArgsCommand
-from askbot.models import Comment
+from askbot.models import Post
class Command(NoArgsCommand):
def handle_noargs(self, **options):
- objs = Comment.objects.all()
- print objs \ No newline at end of file
+ objs = Post.objects.all()
+ print objs
diff --git a/askbot/management/commands/send_accept_answer_reminders.py b/askbot/management/commands/send_accept_answer_reminders.py
index 3a20ba27..119d7611 100644
--- a/askbot/management/commands/send_accept_answer_reminders.py
+++ b/askbot/management/commands/send_accept_answer_reminders.py
@@ -8,6 +8,8 @@ from django.utils.translation import ugettext as _
from django.utils.translation import ungettext
from askbot import mail
from askbot.utils.classes import ReminderSchedule
+from askbot.skins.loaders import get_template
+from django.template import Context
DEBUG_THIS_COMMAND = False
@@ -63,16 +65,15 @@ class Command(NoArgsCommand):
reminder_phrase = _('Please accept the best answer for this question:')
else:
reminder_phrase = _('Please accept the best answer for these questions:')
- body_text = '<p>' + reminder_phrase + '</p>'
- body_text += '<ul>'
- for question in final_question_list:
- body_text += '<li><a href="%s%s?sort=latest">%s</a></li>' \
- % (
- askbot_settings.APP_URL,
- question.get_absolute_url(),
- question.thread.title
- )
- body_text += '</ul>'
+
+ data = {
+ 'site_url': askbot_settings.APP_URL,
+ 'questions': final_question_list,
+ 'reminder_phrase': reminder_phrase
+ }
+
+ template = get_template('email/accept_answer_reminder.html')
+ body_text = template.render(Context(data))
if DEBUG_THIS_COMMAND:
print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \
diff --git a/askbot/management/commands/send_email_alerts.py b/askbot/management/commands/send_email_alerts.py
index e890452d..26f475a1 100644
--- a/askbot/management/commands/send_email_alerts.py
+++ b/askbot/management/commands/send_email_alerts.py
@@ -84,7 +84,7 @@ class Command(NoArgsCommand):
finally:
connection.close()
- def get_updated_questions_for_user(self,user):
+ def get_updated_questions_for_user(self, user):
"""
retreive relevant question updates for the user
according to their subscriptions and recorded question
@@ -338,11 +338,7 @@ class Command(NoArgsCommand):
#collect info on all sorts of news that happened after
#the most recent emailing to the user about this question
- q_rev = PostRevision.objects.question_revisions().filter(
- post=q,
- revised_at__gt=emailed_at
- )
-
+ q_rev = q.revisions.filter(revised_at__gt=emailed_at)
q_rev = q_rev.exclude(author=user)
#now update all sorts of metadata per question
@@ -353,22 +349,23 @@ class Command(NoArgsCommand):
else:
meta_data['new_q'] = False
- new_ans = Post.objects.get_answers().filter(
+ new_ans = Post.objects.get_answers(user).filter(
thread=q.thread,
added_at__gt=emailed_at,
deleted=False,
)
-
new_ans = new_ans.exclude(author=user)
meta_data['new_ans'] = len(new_ans)
- ans_rev = PostRevision.objects.answer_revisions().filter(
- # answer__question = q
- post__thread=q.thread,
-
- post__deleted = False,
- revised_at__gt = emailed_at
- ).distinct()
- ans_rev = ans_rev.exclude(author=user)
+
+ ans_ids = Post.objects.get_answers(user).filter(
+ thread=q.thread,
+ added_at__gt=emailed_at,
+ deleted=False,
+ ).values_list(
+ 'id', flat = True
+ )
+ ans_rev = PostRevision.objects.filter(post__id__in = ans_ids)
+ ans_rev = ans_rev.exclude(author=user).distinct()
meta_data['ans_rev'] = len(ans_rev)
comments = meta_data.get('comments', 0)
diff --git a/askbot/management/commands/send_unanswered_question_reminders.py b/askbot/management/commands/send_unanswered_question_reminders.py
index 82b6ecd8..3fa390ad 100644
--- a/askbot/management/commands/send_unanswered_question_reminders.py
+++ b/askbot/management/commands/send_unanswered_question_reminders.py
@@ -6,11 +6,13 @@ from django.utils.translation import ungettext
from askbot import mail
from askbot.utils.classes import ReminderSchedule
from askbot.models.question import Thread
+from askbot.skins.loaders import get_template
+from django.template import Context
DEBUG_THIS_COMMAND = False
class Command(NoArgsCommand):
- """management command that sends reminders
+ """management command that sends reminders
about unanswered questions to all users
"""
def handle_noargs(self, **options):
@@ -43,6 +45,10 @@ class Command(NoArgsCommand):
user_questions = questions.exclude(author = user)
user_questions = user.get_tag_filtered_questions(user_questions)
+ if askbot_settings.GROUPS_ENABLED:
+ user_groups = user.get_groups()
+ user_questions = user_questions.filter(groups__in = user_groups)
+
final_question_list = user_questions.get_questions_needing_reminder(
user = user,
activity_type = const.TYPE_ACTIVITY_UNANSWERED_REMINDER_SENT,
@@ -65,15 +71,15 @@ class Command(NoArgsCommand):
'topics': tag_summary
}
- body_text = '<ul>'
- for question in final_question_list:
- body_text += '<li><a href="%s%s?sort=latest">%s</a></li>' \
- % (
- askbot_settings.APP_URL,
- question.get_absolute_url(),
- question.thread.title
- )
- body_text += '</ul>'
+ data = {
+ 'site_url': askbot_settings.APP_URL,
+ 'questions': final_question_list,
+ 'subject_line': subject_line
+ }
+
+ template = get_template('email/unanswered_question_reminder.html')
+ body_text = template.render(Context(data))
+
if DEBUG_THIS_COMMAND:
print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \
diff --git a/askbot/skins/default/media/bootstrap/bootstrap.zip b/askbot/media/bootstrap/bootstrap.zip
index 86a13bb9..86a13bb9 100644
--- a/askbot/skins/default/media/bootstrap/bootstrap.zip
+++ b/askbot/media/bootstrap/bootstrap.zip
Binary files differ
diff --git a/askbot/media/bootstrap/css/bootstrap.css b/askbot/media/bootstrap/css/bootstrap.css
new file mode 100644
index 00000000..e6190005
--- /dev/null
+++ b/askbot/media/bootstrap/css/bootstrap.css
@@ -0,0 +1,4559 @@
+/*!
+ * Bootstrap v2.0.2
+ * This file was modified for Askbot
+ * some styles were deleted, others added at the bottom
+ * of this file. Also some fixes to bootstrap are added
+ * at the bottom of askbot's style.less.
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */
+.clearfix {
+ *zoom: 1;
+}
+.clearfix:before,
+.clearfix:after {
+ display: table;
+ content: "";
+}
+.clearfix:after {
+ clear: both;
+}
+.hide-text {
+ overflow: hidden;
+ text-indent: 100%;
+ white-space: nowrap;
+}
+.input-block-level {
+ display: block;
+ width: 100%;
+ min-height: 28px;
+ /* Make inputs at least the height of their button counterpart */
+
+ /* Makes inputs behave like true block-level elements */
+
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+}
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+nav,
+section {
+ display: block;
+}
+audio,
+canvas,
+video {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+}
+audio:not([controls]) {
+ display: none;
+}
+html {
+ font-size: 100%;
+ -webkit-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
+}
+a:focus {
+ outline: thin dotted #333;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+a:hover,
+a:active {
+ outline: 0;
+}
+sub,
+sup {
+ position: relative;
+ font-size: 75%;
+ line-height: 0;
+ vertical-align: baseline;
+}
+sup {
+ top: -0.5em;
+}
+sub {
+ bottom: -0.25em;
+}
+img {
+ height: auto;
+ border: 0;
+ -ms-interpolation-mode: bicubic;
+ vertical-align: middle;
+}
+button,
+input {
+ *overflow: visible;
+ line-height: normal;
+}
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+button,
+input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+ cursor: pointer;
+ -webkit-appearance: button;
+}
+input[type="search"] {
+ -webkit-appearance: textfield;
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+input[type="search"]::-webkit-search-decoration,
+input[type="search"]::-webkit-search-cancel-button {
+ -webkit-appearance: none;
+}
+textarea {
+ overflow: auto;
+ vertical-align: top;
+}
+a {
+ color: #0088cc;
+ text-decoration: none;
+}
+a:hover {
+ color: #005580;
+ text-decoration: underline;
+}
+.row {
+ margin-left: -20px;
+ *zoom: 1;
+}
+.row:before,
+.row:after {
+ display: table;
+ content: "";
+}
+.row:after {
+ clear: both;
+}
+[class*="span"] {
+ float: left;
+ margin-left: 20px;
+}
+.container,
+.navbar-fixed-top .container,
+.navbar-fixed-bottom .container {
+ width: 940px;
+}
+.span12 {
+ width: 940px;
+}
+.span11 {
+ width: 860px;
+}
+.span10 {
+ width: 780px;
+}
+.span9 {
+ width: 700px;
+}
+.span8 {
+ width: 620px;
+}
+.span7 {
+ width: 540px;
+}
+.span6 {
+ width: 460px;
+}
+.span5 {
+ width: 380px;
+}
+.span4 {
+ width: 300px;
+}
+.span3 {
+ width: 220px;
+}
+.span2 {
+ width: 140px;
+}
+.span1 {
+ width: 60px;
+}
+.offset12 {
+ margin-left: 980px;
+}
+.offset11 {
+ margin-left: 900px;
+}
+.offset10 {
+ margin-left: 820px;
+}
+.offset9 {
+ margin-left: 740px;
+}
+.offset8 {
+ margin-left: 660px;
+}
+.offset7 {
+ margin-left: 580px;
+}
+.offset6 {
+ margin-left: 500px;
+}
+.offset5 {
+ margin-left: 420px;
+}
+.offset4 {
+ margin-left: 340px;
+}
+.offset3 {
+ margin-left: 260px;
+}
+.offset2 {
+ margin-left: 180px;
+}
+.offset1 {
+ margin-left: 100px;
+}
+.row-fluid {
+ width: 100%;
+ *zoom: 1;
+}
+.row-fluid:before,
+.row-fluid:after {
+ display: table;
+ content: "";
+}
+.row-fluid:after {
+ clear: both;
+}
+.row-fluid > [class*="span"] {
+ float: left;
+ margin-left: 2.127659574%;
+}
+.row-fluid > [class*="span"]:first-child {
+ margin-left: 0;
+}
+.row-fluid > .span12 {
+ width: 99.99999998999999%;
+}
+.row-fluid > .span11 {
+ width: 91.489361693%;
+}
+.row-fluid > .span10 {
+ width: 82.97872339599999%;
+}
+.row-fluid > .span9 {
+ width: 74.468085099%;
+}
+.row-fluid > .span8 {
+ width: 65.95744680199999%;
+}
+.row-fluid > .span7 {
+ width: 57.446808505%;
+}
+.row-fluid > .span6 {
+ width: 48.93617020799999%;
+}
+.row-fluid > .span5 {
+ width: 40.425531911%;
+}
+.row-fluid > .span4 {
+ width: 31.914893614%;
+}
+.row-fluid > .span3 {
+ width: 23.404255317%;
+}
+.row-fluid > .span2 {
+ width: 14.89361702%;
+}
+.row-fluid > .span1 {
+ width: 6.382978723%;
+}
+.container {
+ margin-left: auto;
+ margin-right: auto;
+ *zoom: 1;
+}
+.container:before,
+.container:after {
+ display: table;
+ content: "";
+}
+.container:after {
+ clear: both;
+}
+.container-fluid {
+ padding-left: 20px;
+ padding-right: 20px;
+ *zoom: 1;
+}
+.container-fluid:before,
+.container-fluid:after {
+ display: table;
+ content: "";
+}
+.container-fluid:after {
+ clear: both;
+}
+p {
+ margin: 0 0 9px;
+ font-family: Arial, sans-serif;
+ font-size: 13px;
+ line-height: 18px;
+}
+p small {
+ font-size: 11px;
+ color: #999999;
+}
+.lead {
+ margin-bottom: 18px;
+ font-size: 20px;
+ font-weight: 200;
+ line-height: 27px;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ margin: 0;
+ font-family: inherit;
+ font-weight: bold;
+ color: inherit;
+ text-rendering: optimizelegibility;
+}
+h1 small,
+h2 small,
+h3 small,
+h4 small,
+h5 small,
+h6 small {
+ font-weight: normal;
+ color: #999999;
+}
+h1 {
+ font-size: 30px;
+ line-height: 36px;
+}
+h1 small {
+ font-size: 18px;
+}
+h2 {
+ font-size: 24px;
+ line-height: 36px;
+}
+h2 small {
+ font-size: 18px;
+}
+h3 {
+ line-height: 27px;
+ font-size: 18px;
+}
+h3 small {
+ font-size: 14px;
+}
+h4,
+h5,
+h6 {
+ line-height: 18px;
+}
+h4 {
+ font-size: 14px;
+}
+h4 small {
+ font-size: 12px;
+}
+h5 {
+ font-size: 12px;
+}
+h6 {
+ font-size: 11px;
+ color: #999999;
+ text-transform: uppercase;
+}
+.page-header {
+ padding-bottom: 17px;
+ margin: 18px 0;
+ border-bottom: 1px solid #eeeeee;
+}
+.page-header h1 {
+ line-height: 1;
+}
+ul,
+ol {
+ padding: 0;
+ margin: 0 0 9px 25px;
+}
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+ margin-bottom: 0;
+}
+ul {
+ list-style: disc;
+}
+ol {
+ list-style: decimal;
+}
+li {
+ line-height: 18px;
+}
+ul.unstyled,
+ol.unstyled {
+ margin-left: 0;
+ list-style: none;
+}
+dl {
+ margin-bottom: 18px;
+}
+dt,
+dd {
+ line-height: 18px;
+}
+dt {
+ font-weight: bold;
+ line-height: 17px;
+}
+dd {
+ margin-left: 9px;
+}
+.dl-horizontal dt {
+ float: left;
+ clear: left;
+ width: 120px;
+ text-align: right;
+}
+.dl-horizontal dd {
+ margin-left: 130px;
+}
+hr {
+ margin: 18px 0;
+ border: 0;
+ border-top: 1px solid #eeeeee;
+ border-bottom: 1px solid #ffffff;
+}
+strong {
+ font-weight: bold;
+}
+em {
+ font-style: italic;
+}
+.muted {
+ color: #999999;
+}
+abbr[title] {
+ border-bottom: 1px dotted #ddd;
+ cursor: help;
+}
+abbr.initialism {
+ font-size: 90%;
+ text-transform: uppercase;
+}
+blockquote {
+ padding: 0 0 0 15px;
+ margin: 0 0 18px;
+ border-left: 5px solid #eeeeee;
+}
+blockquote p {
+ margin-bottom: 0;
+ font-size: 16px;
+ font-weight: 300;
+ line-height: 22.5px;
+}
+blockquote small {
+ display: block;
+ line-height: 18px;
+ color: #999999;
+}
+blockquote small:before {
+ content: '\2014 \00A0';
+}
+blockquote.pull-right {
+ float: right;
+ padding-left: 0;
+ padding-right: 15px;
+ border-left: 0;
+ border-right: 5px solid #eeeeee;
+}
+blockquote.pull-right p,
+blockquote.pull-right small {
+ text-align: right;
+}
+q:before,
+q:after,
+blockquote:before,
+blockquote:after {
+ content: "";
+}
+address {
+ display: block;
+ margin-bottom: 18px;
+ line-height: 18px;
+ font-style: normal;
+}
+small {
+ font-size: 100%;
+}
+cite {
+ font-style: normal;
+}
+code,
+pre {
+ padding: 0 3px 2px;
+ font-family: Menlo, Monaco, "Courier New", monospace;
+ font-size: 12px;
+ color: #333333;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+code {
+ padding: 2px 4px;
+ color: #d14;
+ background-color: #f7f7f9;
+ border: 1px solid #e1e1e8;
+}
+pre {
+ display: block;
+ padding: 8.5px;
+ margin: 0 0 9px;
+ font-size: 12.025px;
+ line-height: 18px;
+ background-color: #f5f5f5;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0, 0, 0, 0.15);
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ white-space: pre;
+ white-space: pre-wrap;
+ word-break: break-all;
+ word-wrap: break-word;
+}
+pre.prettyprint {
+ margin-bottom: 18px;
+}
+pre code {
+ padding: 0;
+ color: inherit;
+ background-color: transparent;
+ border: 0;
+}
+.pre-scrollable {
+ max-height: 340px;
+ overflow-y: scroll;
+}
+/*.label {
+ padding: 1px 4px 2px;
+ font-size: 10.998px;
+ font-weight: bold;
+ line-height: 13px;
+ color: #ffffff;
+ vertical-align: middle;
+ white-space: nowrap;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ background-color: #999999;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+.label:hover {
+ color: #ffffff;
+ text-decoration: none;
+}*/
+.label-important {
+ background-color: #b94a48;
+}
+.label-important:hover {
+ background-color: #953b39;
+}
+.label-warning {
+ background-color: #f89406;
+}
+.label-warning:hover {
+ background-color: #c67605;
+}
+.label-success {
+ background-color: #468847;
+}
+.label-success:hover {
+ background-color: #356635;
+}
+.label-info {
+ background-color: #3a87ad;
+}
+.label-info:hover {
+ background-color: #2d6987;
+}
+.label-inverse {
+ background-color: #333333;
+}
+.label-inverse:hover {
+ background-color: #1a1a1a;
+}
+.badge {
+ padding: 1px 9px 2px;
+ font-size: 12.025px;
+ font-weight: bold;
+ white-space: nowrap;
+ color: #ffffff;
+ background-color: #999999;
+ -webkit-border-radius: 9px;
+ -moz-border-radius: 9px;
+ border-radius: 9px;
+}
+.badge:hover {
+ color: #ffffff;
+ text-decoration: none;
+ cursor: pointer;
+}
+.badge-error {
+ background-color: #b94a48;
+}
+.badge-error:hover {
+ background-color: #953b39;
+}
+.badge-warning {
+ background-color: #f89406;
+}
+.badge-warning:hover {
+ background-color: #c67605;
+}
+.badge-success {
+ background-color: #468847;
+}
+.badge-success:hover {
+ background-color: #356635;
+}
+.badge-info {
+ background-color: #3a87ad;
+}
+.badge-info:hover {
+ background-color: #2d6987;
+}
+.badge-inverse {
+ background-color: #333333;
+}
+.badge-inverse:hover {
+ background-color: #1a1a1a;
+}
+table {
+ max-width: 100%;
+ border-collapse: collapse;
+ border-spacing: 0;
+ background-color: transparent;
+}
+.table {
+ width: 100%;
+ margin-bottom: 18px;
+}
+.table th,
+.table td {
+ padding: 8px;
+ line-height: 18px;
+ text-align: left;
+ vertical-align: top;
+ border-top: 1px solid #dddddd;
+}
+.table th {
+ font-weight: bold;
+}
+.table thead th {
+ vertical-align: bottom;
+}
+.table colgroup + thead tr:first-child th,
+.table colgroup + thead tr:first-child td,
+.table thead:first-child tr:first-child th,
+.table thead:first-child tr:first-child td {
+ border-top: 0;
+}
+.table tbody + tbody {
+ border-top: 2px solid #dddddd;
+}
+.table-condensed th,
+.table-condensed td {
+ padding: 4px 5px;
+}
+.table-bordered {
+ border: 1px solid #dddddd;
+ border-left: 0;
+ border-collapse: separate;
+ *border-collapse: collapsed;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+.table-bordered th,
+.table-bordered td {
+ border-left: 1px solid #dddddd;
+}
+.table-bordered thead:first-child tr:first-child th,
+.table-bordered tbody:first-child tr:first-child th,
+.table-bordered tbody:first-child tr:first-child td {
+ border-top: 0;
+}
+.table-bordered thead:first-child tr:first-child th:first-child,
+.table-bordered tbody:first-child tr:first-child td:first-child {
+ -webkit-border-radius: 4px 0 0 0;
+ -moz-border-radius: 4px 0 0 0;
+ border-radius: 4px 0 0 0;
+}
+.table-bordered thead:first-child tr:first-child th:last-child,
+.table-bordered tbody:first-child tr:first-child td:last-child {
+ -webkit-border-radius: 0 4px 0 0;
+ -moz-border-radius: 0 4px 0 0;
+ border-radius: 0 4px 0 0;
+}
+.table-bordered thead:last-child tr:last-child th:first-child,
+.table-bordered tbody:last-child tr:last-child td:first-child {
+ -webkit-border-radius: 0 0 0 4px;
+ -moz-border-radius: 0 0 0 4px;
+ border-radius: 0 0 0 4px;
+}
+.table-bordered thead:last-child tr:last-child th:last-child,
+.table-bordered tbody:last-child tr:last-child td:last-child {
+ -webkit-border-radius: 0 0 4px 0;
+ -moz-border-radius: 0 0 4px 0;
+ border-radius: 0 0 4px 0;
+}
+.table-striped tbody tr:nth-child(odd) td,
+.table-striped tbody tr:nth-child(odd) th {
+ background-color: #f9f9f9;
+}
+.table tbody tr:hover td,
+.table tbody tr:hover th {
+ background-color: #f5f5f5;
+}
+table .span1 {
+ float: none;
+ width: 44px;
+ margin-left: 0;
+}
+table .span2 {
+ float: none;
+ width: 124px;
+ margin-left: 0;
+}
+table .span3 {
+ float: none;
+ width: 204px;
+ margin-left: 0;
+}
+table .span4 {
+ float: none;
+ width: 284px;
+ margin-left: 0;
+}
+table .span5 {
+ float: none;
+ width: 364px;
+ margin-left: 0;
+}
+table .span6 {
+ float: none;
+ width: 444px;
+ margin-left: 0;
+}
+table .span7 {
+ float: none;
+ width: 524px;
+ margin-left: 0;
+}
+table .span8 {
+ float: none;
+ width: 604px;
+ margin-left: 0;
+}
+table .span9 {
+ float: none;
+ width: 684px;
+ margin-left: 0;
+}
+table .span10 {
+ float: none;
+ width: 764px;
+ margin-left: 0;
+}
+table .span11 {
+ float: none;
+ width: 844px;
+ margin-left: 0;
+}
+table .span12 {
+ float: none;
+ width: 924px;
+ margin-left: 0;
+}
+table .span13 {
+ float: none;
+ width: 1004px;
+ margin-left: 0;
+}
+table .span14 {
+ float: none;
+ width: 1084px;
+ margin-left: 0;
+}
+table .span15 {
+ float: none;
+ width: 1164px;
+ margin-left: 0;
+}
+table .span16 {
+ float: none;
+ width: 1244px;
+ margin-left: 0;
+}
+table .span17 {
+ float: none;
+ width: 1324px;
+ margin-left: 0;
+}
+table .span18 {
+ float: none;
+ width: 1404px;
+ margin-left: 0;
+}
+table .span19 {
+ float: none;
+ width: 1484px;
+ margin-left: 0;
+}
+table .span20 {
+ float: none;
+ width: 1564px;
+ margin-left: 0;
+}
+table .span21 {
+ float: none;
+ width: 1644px;
+ margin-left: 0;
+}
+table .span22 {
+ float: none;
+ width: 1724px;
+ margin-left: 0;
+}
+table .span23 {
+ float: none;
+ width: 1804px;
+ margin-left: 0;
+}
+table .span24 {
+ float: none;
+ width: 1884px;
+ margin-left: 0;
+}
+form {
+ margin: 0 0 18px;
+}
+fieldset {
+ padding: 0;
+ margin: 0;
+ border: 0;
+}
+legend {
+ display: block;
+ width: 100%;
+ padding: 0;
+ margin-bottom: 27px;
+ font-size: 19.5px;
+ line-height: 36px;
+ color: #333333;
+ border: 0;
+ border-bottom: 1px solid #eee;
+}
+legend small {
+ font-size: 13.5px;
+ color: #999999;
+}
+label {
+ /*display: block;
+ margin-bottom: 5px;
+ color: #333333;*/
+}
+input,
+textarea,
+select,
+.uneditable-input {
+}
+.uneditable-textarea {
+ width: auto;
+ height: auto;
+}
+label input,
+label textarea,
+label select {
+ display: block;
+}
+input[type="image"] {
+ border: 0;
+}
+input[type="file"] {
+ width: auto;
+ padding: initial;
+ line-height: initial;
+ border: initial;
+ background-color: #ffffff;
+ background-color: initial;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+}
+input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+ width: auto;
+ /*height: auto;*/
+}
+select,
+input[type="file"] {
+ height: 28px;
+ /* In IE7, the height of the select element cannot be changed by height, only font-size */
+
+ *margin-top: 4px;
+ /* For IE7, add top margin to align select with labels */
+
+ line-height: 28px;
+}
+input[type="file"] {
+ line-height: 18px \9;
+}
+select {
+ width: 220px;
+ background-color: #ffffff;
+}
+select[multiple],
+select[size] {
+ height: auto;
+}
+input[type="image"] {
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+}
+textarea {
+ height: auto;
+}
+input[type="hidden"] {
+ display: none;
+}
+.radio.inline + .radio.inline,
+.checkbox.inline + .checkbox.inline {
+ margin-left: 10px;
+}
+input,
+textarea {
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+ -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
+ -moz-transition: border linear 0.2s, box-shadow linear 0.2s;
+ -ms-transition: border linear 0.2s, box-shadow linear 0.2s;
+ -o-transition: border linear 0.2s, box-shadow linear 0.2s;
+ transition: border linear 0.2s, box-shadow linear 0.2s;
+}
+input:focus,
+textarea:focus {
+ border-color: rgba(82, 168, 236, 0.8);
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
+ outline: 0;
+ outline: thin dotted \9;
+ /* IE6-9 */
+
+}
+input[type="file"]:focus,
+input[type="radio"]:focus,
+input[type="checkbox"]:focus,
+select:focus {
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+ outline: thin dotted #333;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+.input-mini {
+ width: 60px;
+}
+.input-small {
+ width: 90px;
+}
+.input-medium {
+ width: 150px;
+}
+.input-large {
+ width: 210px;
+}
+.input-xlarge {
+ width: 270px;
+}
+.input-xxlarge {
+ width: 530px;
+}
+input.span12, textarea.span12, .uneditable-input.span12 {
+ width: 930px;
+}
+input.span11, textarea.span11, .uneditable-input.span11 {
+ width: 850px;
+}
+input.span10, textarea.span10, .uneditable-input.span10 {
+ width: 770px;
+}
+input.span9, textarea.span9, .uneditable-input.span9 {
+ width: 690px;
+}
+input.span8, textarea.span8, .uneditable-input.span8 {
+ width: 610px;
+}
+input.span7, textarea.span7, .uneditable-input.span7 {
+ width: 530px;
+}
+input.span6, textarea.span6, .uneditable-input.span6 {
+ width: 450px;
+}
+input.span5, textarea.span5, .uneditable-input.span5 {
+ width: 370px;
+}
+input.span4, textarea.span4, .uneditable-input.span4 {
+ width: 290px;
+}
+input.span3, textarea.span3, .uneditable-input.span3 {
+ width: 210px;
+}
+input.span2, textarea.span2, .uneditable-input.span2 {
+ width: 130px;
+}
+input.span1, textarea.span1, .uneditable-input.span1 {
+ width: 50px;
+}
+input[disabled],
+select[disabled],
+textarea[disabled],
+input[readonly],
+select[readonly],
+textarea[readonly] {
+ background-color: #eeeeee;
+ border-color: #ddd;
+ cursor: not-allowed;
+}
+.control-group.warning > label,
+.control-group.warning .help-block,
+.control-group.warning .help-inline {
+ color: #c09853;
+}
+.control-group.warning input,
+.control-group.warning select,
+.control-group.warning textarea {
+ color: #c09853;
+ border-color: #c09853;
+}
+.control-group.warning input:focus,
+.control-group.warning select:focus,
+.control-group.warning textarea:focus {
+ border-color: #a47e3c;
+ -webkit-box-shadow: 0 0 6px #dbc59e;
+ -moz-box-shadow: 0 0 6px #dbc59e;
+ box-shadow: 0 0 6px #dbc59e;
+}
+.control-group.warning .input-prepend .add-on,
+.control-group.warning .input-append .add-on {
+ color: #c09853;
+ background-color: #fcf8e3;
+ border-color: #c09853;
+}
+.control-group.error > label,
+.control-group.error .help-block,
+.control-group.error .help-inline {
+ color: #b94a48;
+}
+.control-group.error input,
+.control-group.error select,
+.control-group.error textarea {
+ color: #b94a48;
+ border-color: #b94a48;
+}
+.control-group.error input:focus,
+.control-group.error select:focus,
+.control-group.error textarea:focus {
+ border-color: #953b39;
+ -webkit-box-shadow: 0 0 6px #d59392;
+ -moz-box-shadow: 0 0 6px #d59392;
+ box-shadow: 0 0 6px #d59392;
+}
+.control-group.error .input-prepend .add-on,
+.control-group.error .input-append .add-on {
+ color: #b94a48;
+ background-color: #f2dede;
+ border-color: #b94a48;
+}
+.control-group.success > label,
+.control-group.success .help-block,
+.control-group.success .help-inline {
+ color: #468847;
+}
+.control-group.success input,
+.control-group.success select,
+.control-group.success textarea {
+ color: #468847;
+ border-color: #468847;
+}
+.control-group.success input:focus,
+.control-group.success select:focus,
+.control-group.success textarea:focus {
+ border-color: #356635;
+ -webkit-box-shadow: 0 0 6px #7aba7b;
+ -moz-box-shadow: 0 0 6px #7aba7b;
+ box-shadow: 0 0 6px #7aba7b;
+}
+.control-group.success .input-prepend .add-on,
+.control-group.success .input-append .add-on {
+ color: #468847;
+ background-color: #dff0d8;
+ border-color: #468847;
+}
+input:focus:required:invalid,
+textarea:focus:required:invalid,
+select:focus:required:invalid {
+ color: #b94a48;
+ border-color: #ee5f5b;
+}
+input:focus:required:invalid:focus,
+textarea:focus:required:invalid:focus,
+select:focus:required:invalid:focus {
+ border-color: #e9322d;
+ -webkit-box-shadow: 0 0 6px #f8b9b7;
+ -moz-box-shadow: 0 0 6px #f8b9b7;
+ box-shadow: 0 0 6px #f8b9b7;
+}
+.form-actions {
+ padding: 17px 20px 18px;
+ margin-top: 18px;
+ margin-bottom: 18px;
+ background-color: #eeeeee;
+ border-top: 1px solid #ddd;
+ *zoom: 1;
+}
+.form-actions:before,
+.form-actions:after {
+ display: table;
+ content: "";
+}
+.form-actions:after {
+ clear: both;
+}
+:-moz-placeholder {
+ color: #999999;
+}
+::-webkit-input-placeholder {
+ color: #999999;
+}
+.help-block,
+.help-inline {
+ color: #555555;
+}
+.help-block {
+ display: block;
+ margin-bottom: 9px;
+}
+.help-inline {
+ display: inline-block;
+ *display: inline;
+ /* IE7 inline-block hack */
+
+ *zoom: 1;
+ vertical-align: middle;
+ padding-left: 5px;
+}
+.input-prepend,
+.input-append {
+ margin-bottom: 5px;
+}
+.input-prepend input:focus,
+.input-append input:focus,
+.input-prepend select:focus,
+.input-append select:focus,
+.input-prepend .uneditable-input:focus,
+.input-append .uneditable-input:focus {
+ position: relative;
+ z-index: 2;
+}
+.input-prepend .uneditable-input,
+.input-append .uneditable-input {
+ border-left-color: #ccc;
+}
+.input-prepend .add-on,
+.input-append .add-on {
+ display: inline-block;
+ width: auto;
+ min-width: 16px;
+ height: 18px;
+ padding: 4px 5px;
+ font-weight: normal;
+ line-height: 18px;
+ text-align: center;
+ text-shadow: 0 1px 0 #ffffff;
+ vertical-align: middle;
+ background-color: #eeeeee;
+ border: 1px solid #ccc;
+}
+.input-prepend .add-on,
+.input-append .add-on,
+.input-prepend .btn,
+.input-append .btn {
+ -webkit-border-radius: 3px 0 0 3px;
+ -moz-border-radius: 3px 0 0 3px;
+ border-radius: 3px 0 0 3px;
+}
+.input-prepend .active,
+.input-append .active {
+ background-color: #a9dba9;
+ border-color: #46a546;
+}
+.input-prepend .add-on,
+.input-prepend .btn {
+ margin-right: -1px;
+}
+.input-append input,
+.input-append select .uneditable-input {
+ -webkit-border-radius: 3px 0 0 3px;
+ -moz-border-radius: 3px 0 0 3px;
+ border-radius: 3px 0 0 3px;
+}
+.input-append .uneditable-input {
+ border-left-color: #eee;
+ border-right-color: #ccc;
+}
+.input-append .add-on,
+.input-append .btn {
+ margin-left: -1px;
+ -webkit-border-radius: 0 3px 3px 0;
+ -moz-border-radius: 0 3px 3px 0;
+ border-radius: 0 3px 3px 0;
+}
+.input-prepend.input-append input,
+.input-prepend.input-append select,
+.input-prepend.input-append .uneditable-input {
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+.input-prepend.input-append .add-on:first-child,
+.input-prepend.input-append .btn:first-child {
+ margin-right: -1px;
+ -webkit-border-radius: 3px 0 0 3px;
+ -moz-border-radius: 3px 0 0 3px;
+ border-radius: 3px 0 0 3px;
+}
+.input-prepend.input-append .add-on:last-child,
+.input-prepend.input-append .btn:last-child {
+ margin-left: -1px;
+ -webkit-border-radius: 0 3px 3px 0;
+ -moz-border-radius: 0 3px 3px 0;
+ border-radius: 0 3px 3px 0;
+}
+.search-query {
+ padding-left: 14px;
+ padding-right: 14px;
+ margin-bottom: 0;
+ -webkit-border-radius: 14px;
+ -moz-border-radius: 14px;
+ border-radius: 14px;
+}
+.form-search input,
+.form-inline input,
+.form-horizontal input,
+.form-search textarea,
+.form-inline textarea,
+.form-horizontal textarea,
+.form-search select,
+.form-inline select,
+.form-horizontal select,
+.form-search .help-inline,
+.form-inline .help-inline,
+.form-horizontal .help-inline,
+.form-search .uneditable-input,
+.form-inline .uneditable-input,
+.form-horizontal .uneditable-input,
+.form-search .input-prepend,
+.form-inline .input-prepend,
+.form-horizontal .input-prepend,
+.form-search .input-append,
+.form-inline .input-append,
+.form-horizontal .input-append {
+ display: inline-block;
+ margin-bottom: 0;
+}
+.form-search .hide,
+.form-inline .hide,
+.form-horizontal .hide {
+ display: none;
+}
+.form-search label,
+.form-inline label {
+ display: inline-block;
+}
+.form-search .input-append,
+.form-inline .input-append,
+.form-search .input-prepend,
+.form-inline .input-prepend {
+ margin-bottom: 0;
+}
+.form-search .radio,
+.form-search .checkbox,
+.form-inline .radio,
+.form-inline .checkbox {
+ padding-left: 0;
+ margin-bottom: 0;
+ vertical-align: middle;
+}
+.form-search .radio input[type="radio"],
+.form-search .checkbox input[type="checkbox"],
+.form-inline .radio input[type="radio"],
+.form-inline .checkbox input[type="checkbox"] {
+ float: left;
+ margin-left: 0;
+ margin-right: 3px;
+}
+.control-group {
+ margin-bottom: 9px;
+}
+legend + .control-group {
+ margin-top: 18px;
+ -webkit-margin-top-collapse: separate;
+}
+.form-horizontal .control-group {
+ margin-bottom: 18px;
+ *zoom: 1;
+}
+.form-horizontal .control-group:before,
+.form-horizontal .control-group:after {
+ display: table;
+ content: "";
+}
+.form-horizontal .control-group:after {
+ clear: both;
+}
+.form-horizontal .control-label {
+ float: left;
+ width: 140px;
+ padding-top: 5px;
+ text-align: right;
+}
+.form-horizontal .controls {
+ margin-left: 160px;
+ /* Super jank IE7 fix to ensure the inputs in .input-append and input-prepend don't inherit the margin of the parent, in this case .controls */
+
+ *display: inline-block;
+ *margin-left: 0;
+ *padding-left: 20px;
+}
+.form-horizontal .help-block {
+ margin-top: 9px;
+ margin-bottom: 0;
+}
+.form-horizontal .form-actions {
+ padding-left: 160px;
+}
+.btn {
+ display: inline-block;
+ *display: inline;
+ /* IE7 inline-block hack */
+
+ *zoom: 1;
+ padding: 4px 10px 4px;
+ margin-bottom: 0;
+ font-size: 13px;
+ line-height: 18px;
+ color: #333333;
+ text-align: center;
+ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+ vertical-align: middle;
+ background-color: #f5f5f5;
+ background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
+ background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: linear-gradient(top, #ffffff, #e6e6e6);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);
+ border-color: #e6e6e6 #e6e6e6 #bfbfbf;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+ border: 1px solid #cccccc;
+ border-bottom-color: #b3b3b3;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ cursor: pointer;
+ *margin-left: .3em;
+}
+.btn:hover,
+.btn:active,
+.btn.active,
+.btn.disabled,
+.btn[disabled] {
+ background-color: #e6e6e6;
+}
+.btn:active,
+.btn.active {
+ background-color: #cccccc \9;
+}
+.btn:first-child {
+ *margin-left: 0;
+}
+.btn:hover {
+ color: #333333;
+ text-decoration: none;
+ background-color: #e6e6e6;
+ background-position: 0 -15px;
+ -webkit-transition: background-position 0.1s linear;
+ -moz-transition: background-position 0.1s linear;
+ -ms-transition: background-position 0.1s linear;
+ -o-transition: background-position 0.1s linear;
+ transition: background-position 0.1s linear;
+}
+.btn:focus {
+ outline: thin dotted #333;
+ outline: 5px auto -webkit-focus-ring-color;
+ outline-offset: -2px;
+}
+.btn.active,
+.btn:active {
+ background-image: none;
+ -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+ background-color: #e6e6e6;
+ background-color: #d9d9d9 \9;
+ outline: 0;
+}
+.btn.disabled,
+.btn[disabled] {
+ cursor: default;
+ background-image: none;
+ background-color: #e6e6e6;
+ opacity: 0.65;
+ filter: alpha(opacity=65);
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+}
+.btn-large {
+ padding: 9px 14px;
+ font-size: 15px;
+ line-height: normal;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+.btn-large [class^="icon-"] {
+ margin-top: 1px;
+}
+.btn-small {
+ padding: 5px 9px;
+ font-size: 11px;
+ line-height: 16px;
+}
+.btn-small [class^="icon-"] {
+ margin-top: -1px;
+}
+.btn-mini {
+ padding: 2px 6px;
+ font-size: 11px;
+ line-height: 14px;
+}
+.btn-primary,
+.btn-primary:hover,
+.btn-warning,
+.btn-warning:hover,
+.btn-danger,
+.btn-danger:hover,
+.btn-success,
+.btn-success:hover,
+.btn-info,
+.btn-info:hover,
+.btn-inverse,
+.btn-inverse:hover {
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ color: #ffffff;
+}
+.btn-primary.active,
+.btn-warning.active,
+.btn-danger.active,
+.btn-success.active,
+.btn-info.active,
+.btn-inverse.active {
+ color: rgba(255, 255, 255, 0.75);
+}
+.btn-primary {
+ background-color: #0074cc;
+ background-image: -moz-linear-gradient(top, #0088cc, #0055cc);
+ background-image: -ms-linear-gradient(top, #0088cc, #0055cc);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc));
+ background-image: -webkit-linear-gradient(top, #0088cc, #0055cc);
+ background-image: -o-linear-gradient(top, #0088cc, #0055cc);
+ background-image: linear-gradient(top, #0088cc, #0055cc);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0);
+ border-color: #0055cc #0055cc #003580;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+.btn-primary:hover,
+.btn-primary:active,
+.btn-primary.active,
+.btn-primary.disabled,
+.btn-primary[disabled] {
+ background-color: #0055cc;
+}
+.btn-primary:active,
+.btn-primary.active {
+ background-color: #004099 \9;
+}
+.btn-warning {
+ background-color: #faa732;
+ background-image: -moz-linear-gradient(top, #fbb450, #f89406);
+ background-image: -ms-linear-gradient(top, #fbb450, #f89406);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
+ background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
+ background-image: -o-linear-gradient(top, #fbb450, #f89406);
+ background-image: linear-gradient(top, #fbb450, #f89406);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);
+ border-color: #f89406 #f89406 #ad6704;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+.btn-warning:hover,
+.btn-warning:active,
+.btn-warning.active,
+.btn-warning.disabled,
+.btn-warning[disabled] {
+ background-color: #f89406;
+}
+.btn-warning:active,
+.btn-warning.active {
+ background-color: #c67605 \9;
+}
+.btn-danger {
+ background-color: #da4f49;
+ background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f);
+ background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));
+ background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f);
+ background-image: -o-linear-gradient(top, #ee5f5b, #bd362f);
+ background-image: linear-gradient(top, #ee5f5b, #bd362f);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);
+ border-color: #bd362f #bd362f #802420;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+.btn-danger:hover,
+.btn-danger:active,
+.btn-danger.active,
+.btn-danger.disabled,
+.btn-danger[disabled] {
+ background-color: #bd362f;
+}
+.btn-danger:active,
+.btn-danger.active {
+ background-color: #942a25 \9;
+}
+.btn-success {
+ background-color: #5bb75b;
+ background-image: -moz-linear-gradient(top, #62c462, #51a351);
+ background-image: -ms-linear-gradient(top, #62c462, #51a351);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));
+ background-image: -webkit-linear-gradient(top, #62c462, #51a351);
+ background-image: -o-linear-gradient(top, #62c462, #51a351);
+ background-image: linear-gradient(top, #62c462, #51a351);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);
+ border-color: #51a351 #51a351 #387038;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+.btn-success:hover,
+.btn-success:active,
+.btn-success.active,
+.btn-success.disabled,
+.btn-success[disabled] {
+ background-color: #51a351;
+}
+.btn-success:active,
+.btn-success.active {
+ background-color: #408140 \9;
+}
+.btn-info {
+ background-color: #49afcd;
+ background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4);
+ background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));
+ background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4);
+ background-image: -o-linear-gradient(top, #5bc0de, #2f96b4);
+ background-image: linear-gradient(top, #5bc0de, #2f96b4);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);
+ border-color: #2f96b4 #2f96b4 #1f6377;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+.btn-info:hover,
+.btn-info:active,
+.btn-info.active,
+.btn-info.disabled,
+.btn-info[disabled] {
+ background-color: #2f96b4;
+}
+.btn-info:active,
+.btn-info.active {
+ background-color: #24748c \9;
+}
+.btn-inverse {
+ background-color: #414141;
+ background-image: -moz-linear-gradient(top, #555555, #222222);
+ background-image: -ms-linear-gradient(top, #555555, #222222);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222));
+ background-image: -webkit-linear-gradient(top, #555555, #222222);
+ background-image: -o-linear-gradient(top, #555555, #222222);
+ background-image: linear-gradient(top, #555555, #222222);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0);
+ border-color: #222222 #222222 #000000;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+.btn-inverse:hover,
+.btn-inverse:active,
+.btn-inverse.active,
+.btn-inverse.disabled,
+.btn-inverse[disabled] {
+ background-color: #222222;
+}
+.btn-inverse:active,
+.btn-inverse.active {
+ background-color: #080808 \9;
+}
+button.btn,
+input[type="submit"].btn {
+ *padding-top: 2px;
+ *padding-bottom: 2px;
+}
+button.btn::-moz-focus-inner,
+input[type="submit"].btn::-moz-focus-inner {
+ padding: 0;
+ border: 0;
+}
+button.btn.btn-large,
+input[type="submit"].btn.btn-large {
+ *padding-top: 7px;
+ *padding-bottom: 7px;
+}
+button.btn.btn-small,
+input[type="submit"].btn.btn-small {
+ *padding-top: 3px;
+ *padding-bottom: 3px;
+}
+button.btn.btn-mini,
+input[type="submit"].btn.btn-mini {
+ *padding-top: 1px;
+ *padding-bottom: 1px;
+}
+[class^="icon-"],
+[class*=" icon-"] {
+ display: inline-block;
+ width: 14px;
+ height: 14px;
+ line-height: 14px;
+ vertical-align: text-top;
+ background-image: url("../img/glyphicons-halflings.png");
+ background-position: 14px 14px;
+ background-repeat: no-repeat;
+ *margin-right: .3em;
+}
+[class^="icon-"]:last-child,
+[class*=" icon-"]:last-child {
+ *margin-left: 0;
+}
+.icon-white {
+ background-image: url("../img/glyphicons-halflings-white.png");
+}
+.icon-glass {
+ background-position: 0 0;
+}
+.icon-music {
+ background-position: -24px 0;
+}
+.icon-search {
+ background-position: -48px 0;
+}
+.icon-envelope {
+ background-position: -72px 0;
+}
+.icon-heart {
+ background-position: -96px 0;
+}
+.icon-star {
+ background-position: -120px 0;
+}
+.icon-star-empty {
+ background-position: -144px 0;
+}
+.icon-user {
+ background-position: -168px 0;
+}
+.icon-film {
+ background-position: -192px 0;
+}
+.icon-th-large {
+ background-position: -216px 0;
+}
+.icon-th {
+ background-position: -240px 0;
+}
+.icon-th-list {
+ background-position: -264px 0;
+}
+.icon-ok {
+ background-position: -288px 0;
+}
+.icon-remove {
+ background-position: -312px 0;
+}
+.icon-zoom-in {
+ background-position: -336px 0;
+}
+.icon-zoom-out {
+ background-position: -360px 0;
+}
+.icon-off {
+ background-position: -384px 0;
+}
+.icon-signal {
+ background-position: -408px 0;
+}
+.icon-cog {
+ background-position: -432px 0;
+}
+.icon-trash {
+ background-position: -456px 0;
+}
+.icon-home {
+ background-position: 0 -24px;
+}
+.icon-file {
+ background-position: -24px -24px;
+}
+.icon-time {
+ background-position: -48px -24px;
+}
+.icon-road {
+ background-position: -72px -24px;
+}
+.icon-download-alt {
+ background-position: -96px -24px;
+}
+.icon-download {
+ background-position: -120px -24px;
+}
+.icon-upload {
+ background-position: -144px -24px;
+}
+.icon-inbox {
+ background-position: -168px -24px;
+}
+.icon-play-circle {
+ background-position: -192px -24px;
+}
+.icon-repeat {
+ background-position: -216px -24px;
+}
+.icon-refresh {
+ background-position: -240px -24px;
+}
+.icon-list-alt {
+ background-position: -264px -24px;
+}
+.icon-lock {
+ background-position: -287px -24px;
+}
+.icon-flag {
+ background-position: -312px -24px;
+}
+.icon-headphones {
+ background-position: -336px -24px;
+}
+.icon-volume-off {
+ background-position: -360px -24px;
+}
+.icon-volume-down {
+ background-position: -384px -24px;
+}
+.icon-volume-up {
+ background-position: -408px -24px;
+}
+.icon-qrcode {
+ background-position: -432px -24px;
+}
+.icon-barcode {
+ background-position: -456px -24px;
+}
+.icon-tag {
+ background-position: 0 -48px;
+}
+.icon-tags {
+ background-position: -25px -48px;
+}
+.icon-book {
+ background-position: -48px -48px;
+}
+.icon-bookmark {
+ background-position: -72px -48px;
+}
+.icon-print {
+ background-position: -96px -48px;
+}
+.icon-camera {
+ background-position: -120px -48px;
+}
+.icon-font {
+ background-position: -144px -48px;
+}
+.icon-bold {
+ background-position: -167px -48px;
+}
+.icon-italic {
+ background-position: -192px -48px;
+}
+.icon-text-height {
+ background-position: -216px -48px;
+}
+.icon-text-width {
+ background-position: -240px -48px;
+}
+.icon-align-left {
+ background-position: -264px -48px;
+}
+.icon-align-center {
+ background-position: -288px -48px;
+}
+.icon-align-right {
+ background-position: -312px -48px;
+}
+.icon-align-justify {
+ background-position: -336px -48px;
+}
+.icon-list {
+ background-position: -360px -48px;
+}
+.icon-indent-left {
+ background-position: -384px -48px;
+}
+.icon-indent-right {
+ background-position: -408px -48px;
+}
+.icon-facetime-video {
+ background-position: -432px -48px;
+}
+.icon-picture {
+ background-position: -456px -48px;
+}
+.icon-pencil {
+ background-position: 0 -72px;
+}
+.icon-map-marker {
+ background-position: -24px -72px;
+}
+.icon-adjust {
+ background-position: -48px -72px;
+}
+.icon-tint {
+ background-position: -72px -72px;
+}
+.icon-edit {
+ background-position: -96px -72px;
+}
+.icon-share {
+ background-position: -120px -72px;
+}
+.icon-check {
+ background-position: -144px -72px;
+}
+.icon-move {
+ background-position: -168px -72px;
+}
+.icon-step-backward {
+ background-position: -192px -72px;
+}
+.icon-fast-backward {
+ background-position: -216px -72px;
+}
+.icon-backward {
+ background-position: -240px -72px;
+}
+.icon-play {
+ background-position: -264px -72px;
+}
+.icon-pause {
+ background-position: -288px -72px;
+}
+.icon-stop {
+ background-position: -312px -72px;
+}
+.icon-forward {
+ background-position: -336px -72px;
+}
+.icon-fast-forward {
+ background-position: -360px -72px;
+}
+.icon-step-forward {
+ background-position: -384px -72px;
+}
+.icon-eject {
+ background-position: -408px -72px;
+}
+.icon-chevron-left {
+ background-position: -432px -72px;
+}
+.icon-chevron-right {
+ background-position: -456px -72px;
+}
+.icon-plus-sign {
+ background-position: 0 -96px;
+}
+.icon-minus-sign {
+ background-position: -24px -96px;
+}
+.icon-remove-sign {
+ background-position: -48px -96px;
+}
+.icon-ok-sign {
+ background-position: -72px -96px;
+}
+.icon-question-sign {
+ background-position: -96px -96px;
+}
+.icon-info-sign {
+ background-position: -120px -96px;
+}
+.icon-screenshot {
+ background-position: -144px -96px;
+}
+.icon-remove-circle {
+ background-position: -168px -96px;
+}
+.icon-ok-circle {
+ background-position: -192px -96px;
+}
+.icon-ban-circle {
+ background-position: -216px -96px;
+}
+.icon-arrow-left {
+ background-position: -240px -96px;
+}
+.icon-arrow-right {
+ background-position: -264px -96px;
+}
+.icon-arrow-up {
+ background-position: -289px -96px;
+}
+.icon-arrow-down {
+ background-position: -312px -96px;
+}
+.icon-share-alt {
+ background-position: -336px -96px;
+}
+.icon-resize-full {
+ background-position: -360px -96px;
+}
+.icon-resize-small {
+ background-position: -384px -96px;
+}
+.icon-plus {
+ background-position: -408px -96px;
+}
+.icon-minus {
+ background-position: -433px -96px;
+}
+.icon-asterisk {
+ background-position: -456px -96px;
+}
+.icon-exclamation-sign {
+ background-position: 0 -120px;
+}
+.icon-gift {
+ background-position: -24px -120px;
+}
+.icon-leaf {
+ background-position: -48px -120px;
+}
+.icon-fire {
+ background-position: -72px -120px;
+}
+.icon-eye-open {
+ background-position: -96px -120px;
+}
+.icon-eye-close {
+ background-position: -120px -120px;
+}
+.icon-warning-sign {
+ background-position: -144px -120px;
+}
+.icon-plane {
+ background-position: -168px -120px;
+}
+.icon-calendar {
+ background-position: -192px -120px;
+}
+.icon-random {
+ background-position: -216px -120px;
+}
+.icon-comment {
+ background-position: -240px -120px;
+}
+.icon-magnet {
+ background-position: -264px -120px;
+}
+.icon-chevron-up {
+ background-position: -288px -120px;
+}
+.icon-chevron-down {
+ background-position: -313px -119px;
+}
+.icon-retweet {
+ background-position: -336px -120px;
+}
+.icon-shopping-cart {
+ background-position: -360px -120px;
+}
+.icon-folder-close {
+ background-position: -384px -120px;
+}
+.icon-folder-open {
+ background-position: -408px -120px;
+}
+.icon-resize-vertical {
+ background-position: -432px -119px;
+}
+.icon-resize-horizontal {
+ background-position: -456px -118px;
+}
+.btn-group {
+ position: relative;
+ *zoom: 1;
+ *margin-left: .3em;
+}
+.btn-group:before,
+.btn-group:after {
+ display: table;
+ content: "";
+}
+.btn-group:after {
+ clear: both;
+}
+.btn-group:first-child {
+ *margin-left: 0;
+}
+.btn-group + .btn-group {
+ margin-left: 5px;
+}
+.btn-toolbar {
+ margin-top: 9px;
+ margin-bottom: 9px;
+}
+.btn-toolbar .btn-group {
+ display: inline-block;
+ *display: inline;
+ /* IE7 inline-block hack */
+
+ *zoom: 1;
+}
+.btn-group .btn {
+ position: relative;
+ float: left;
+ margin-left: -1px;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+.btn-group .btn:first-child {
+ margin-left: 0;
+ -webkit-border-top-left-radius: 4px;
+ -moz-border-radius-topleft: 4px;
+ border-top-left-radius: 4px;
+ -webkit-border-bottom-left-radius: 4px;
+ -moz-border-radius-bottomleft: 4px;
+ border-bottom-left-radius: 4px;
+}
+.btn-group .btn:last-child,
+.btn-group .dropdown-toggle {
+ -webkit-border-top-right-radius: 4px;
+ -moz-border-radius-topright: 4px;
+ border-top-right-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+ -moz-border-radius-bottomright: 4px;
+ border-bottom-right-radius: 4px;
+}
+.btn-group .btn.large:first-child {
+ margin-left: 0;
+ -webkit-border-top-left-radius: 6px;
+ -moz-border-radius-topleft: 6px;
+ border-top-left-radius: 6px;
+ -webkit-border-bottom-left-radius: 6px;
+ -moz-border-radius-bottomleft: 6px;
+ border-bottom-left-radius: 6px;
+}
+.btn-group .btn.large:last-child,
+.btn-group .large.dropdown-toggle {
+ -webkit-border-top-right-radius: 6px;
+ -moz-border-radius-topright: 6px;
+ border-top-right-radius: 6px;
+ -webkit-border-bottom-right-radius: 6px;
+ -moz-border-radius-bottomright: 6px;
+ border-bottom-right-radius: 6px;
+}
+.btn-group .btn:hover,
+.btn-group .btn:focus,
+.btn-group .btn:active,
+.btn-group .btn.active {
+ z-index: 2;
+}
+.btn-group .dropdown-toggle:active,
+.btn-group.open .dropdown-toggle {
+ outline: 0;
+}
+.btn-group .dropdown-toggle {
+ padding-left: 8px;
+ padding-right: 8px;
+ -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+ *padding-top: 3px;
+ *padding-bottom: 3px;
+}
+.btn-group .btn-mini.dropdown-toggle {
+ padding-left: 5px;
+ padding-right: 5px;
+ *padding-top: 1px;
+ *padding-bottom: 1px;
+}
+.btn-group .btn-small.dropdown-toggle {
+ *padding-top: 4px;
+ *padding-bottom: 4px;
+}
+.btn-group .btn-large.dropdown-toggle {
+ padding-left: 12px;
+ padding-right: 12px;
+}
+.btn-group.open {
+ *z-index: 1000;
+}
+.btn-group.open .dropdown-menu {
+ display: block;
+ margin-top: 1px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+.btn-group.open .dropdown-toggle {
+ background-image: none;
+ -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+.btn .caret {
+ margin-top: 7px;
+ margin-left: 0;
+}
+.btn:hover .caret,
+.open.btn-group .caret {
+ opacity: 1;
+ filter: alpha(opacity=100);
+}
+.btn-mini .caret {
+ margin-top: 5px;
+}
+.btn-small .caret {
+ margin-top: 6px;
+}
+.btn-large .caret {
+ margin-top: 6px;
+ border-left: 5px solid transparent;
+ border-right: 5px solid transparent;
+ border-top: 5px solid #000000;
+}
+.btn-primary .caret,
+.btn-warning .caret,
+.btn-danger .caret,
+.btn-info .caret,
+.btn-success .caret,
+.btn-inverse .caret {
+ border-top-color: #ffffff;
+ border-bottom-color: #ffffff;
+ opacity: 0.75;
+ filter: alpha(opacity=75);
+}
+.nav {
+ margin-left: 0;
+ margin-bottom: 18px;
+ list-style: none;
+}
+.nav > li > a {
+ display: block;
+}
+.nav > li > a:hover {
+ text-decoration: none;
+ background-color: #eeeeee;
+}
+.nav .nav-header {
+ display: block;
+ padding: 3px 15px;
+ font-size: 11px;
+ font-weight: bold;
+ line-height: 18px;
+ color: #999999;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+ text-transform: uppercase;
+}
+.nav li + .nav-header {
+ margin-top: 9px;
+}
+.nav-list {
+ padding-left: 15px;
+ padding-right: 15px;
+ margin-bottom: 0;
+}
+.nav-list > li > a,
+.nav-list .nav-header {
+ margin-left: -15px;
+ margin-right: -15px;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+}
+.nav-list > li > a {
+ padding: 3px 15px;
+}
+.nav-list > .active > a,
+.nav-list > .active > a:hover {
+ color: #ffffff;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
+ background-color: #0088cc;
+}
+.nav-list [class^="icon-"] {
+ margin-right: 2px;
+}
+.nav-list .divider {
+ height: 1px;
+ margin: 8px 1px;
+ overflow: hidden;
+ background-color: #e5e5e5;
+ border-bottom: 1px solid #ffffff;
+ *width: 100%;
+ *margin: -5px 0 5px;
+}
+.nav-tabs,
+.nav-pills {
+ *zoom: 1;
+}
+.nav-tabs:before,
+.nav-pills:before,
+.nav-tabs:after,
+.nav-pills:after {
+ display: table;
+ content: "";
+}
+.nav-tabs:after,
+.nav-pills:after {
+ clear: both;
+}
+.nav-tabs > li,
+.nav-pills > li {
+ float: left;
+}
+.nav-tabs > li > a,
+.nav-pills > li > a {
+ padding-right: 12px;
+ padding-left: 12px;
+ margin-right: 2px;
+ line-height: 14px;
+}
+.nav-tabs {
+ border-bottom: 1px solid #ddd;
+}
+.nav-tabs > li {
+ margin-bottom: -1px;
+}
+.nav-tabs > li > a {
+ padding-top: 8px;
+ padding-bottom: 8px;
+ line-height: 18px;
+ border: 1px solid transparent;
+ -webkit-border-radius: 4px 4px 0 0;
+ -moz-border-radius: 4px 4px 0 0;
+ border-radius: 4px 4px 0 0;
+}
+.nav-tabs > li > a:hover {
+ border-color: #eeeeee #eeeeee #dddddd;
+}
+.nav-tabs > .active > a,
+.nav-tabs > .active > a:hover {
+ color: #555555;
+ background-color: #ffffff;
+ border: 1px solid #ddd;
+ border-bottom-color: transparent;
+ cursor: default;
+}
+.nav-pills > li > a {
+ padding-top: 8px;
+ padding-bottom: 8px;
+ margin-top: 2px;
+ margin-bottom: 2px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+.nav-pills > .active > a,
+.nav-pills > .active > a:hover {
+ color: #ffffff;
+ background-color: #0088cc;
+}
+.nav-stacked > li {
+ float: none;
+}
+.nav-stacked > li > a {
+ margin-right: 0;
+}
+.nav-tabs.nav-stacked {
+ border-bottom: 0;
+}
+.nav-tabs.nav-stacked > li > a {
+ border: 1px solid #ddd;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+.nav-tabs.nav-stacked > li:first-child > a {
+ -webkit-border-radius: 4px 4px 0 0;
+ -moz-border-radius: 4px 4px 0 0;
+ border-radius: 4px 4px 0 0;
+}
+.nav-tabs.nav-stacked > li:last-child > a {
+ -webkit-border-radius: 0 0 4px 4px;
+ -moz-border-radius: 0 0 4px 4px;
+ border-radius: 0 0 4px 4px;
+}
+.nav-tabs.nav-stacked > li > a:hover {
+ border-color: #ddd;
+ z-index: 2;
+}
+.nav-pills.nav-stacked > li > a {
+ margin-bottom: 3px;
+}
+.nav-pills.nav-stacked > li:last-child > a {
+ margin-bottom: 1px;
+}
+.nav-tabs .dropdown-menu,
+.nav-pills .dropdown-menu {
+ margin-top: 1px;
+ border-width: 1px;
+}
+.nav-pills .dropdown-menu {
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+.nav-tabs .dropdown-toggle .caret,
+.nav-pills .dropdown-toggle .caret {
+ border-top-color: #0088cc;
+ border-bottom-color: #0088cc;
+ margin-top: 6px;
+}
+.nav-tabs .dropdown-toggle:hover .caret,
+.nav-pills .dropdown-toggle:hover .caret {
+ border-top-color: #005580;
+ border-bottom-color: #005580;
+}
+.nav-tabs .active .dropdown-toggle .caret,
+.nav-pills .active .dropdown-toggle .caret {
+ border-top-color: #333333;
+ border-bottom-color: #333333;
+}
+.nav > .dropdown.active > a:hover {
+ color: #000000;
+ cursor: pointer;
+}
+.nav-tabs .open .dropdown-toggle,
+.nav-pills .open .dropdown-toggle,
+.nav > .open.active > a:hover {
+ color: #ffffff;
+ background-color: #999999;
+ border-color: #999999;
+}
+.nav .open .caret,
+.nav .open.active .caret,
+.nav .open a:hover .caret {
+ border-top-color: #ffffff;
+ border-bottom-color: #ffffff;
+ opacity: 1;
+ filter: alpha(opacity=100);
+}
+.tabs-stacked .open > a:hover {
+ border-color: #999999;
+}
+.tabbable {
+ *zoom: 1;
+}
+.tabbable:before,
+.tabbable:after {
+ display: table;
+ content: "";
+}
+.tabbable:after {
+ clear: both;
+}
+.tab-content {
+ display: table;
+ width: 100%;
+}
+.tabs-below .nav-tabs,
+.tabs-right .nav-tabs,
+.tabs-left .nav-tabs {
+ border-bottom: 0;
+}
+.tab-content > .tab-pane,
+.pill-content > .pill-pane {
+ display: none;
+}
+.tab-content > .active,
+.pill-content > .active {
+ display: block;
+}
+.tabs-below .nav-tabs {
+ border-top: 1px solid #ddd;
+}
+.tabs-below .nav-tabs > li {
+ margin-top: -1px;
+ margin-bottom: 0;
+}
+.tabs-below .nav-tabs > li > a {
+ -webkit-border-radius: 0 0 4px 4px;
+ -moz-border-radius: 0 0 4px 4px;
+ border-radius: 0 0 4px 4px;
+}
+.tabs-below .nav-tabs > li > a:hover {
+ border-bottom-color: transparent;
+ border-top-color: #ddd;
+}
+.tabs-below .nav-tabs .active > a,
+.tabs-below .nav-tabs .active > a:hover {
+ border-color: transparent #ddd #ddd #ddd;
+}
+.tabs-left .nav-tabs > li,
+.tabs-right .nav-tabs > li {
+ float: none;
+}
+.tabs-left .nav-tabs > li > a,
+.tabs-right .nav-tabs > li > a {
+ min-width: 74px;
+ margin-right: 0;
+ margin-bottom: 3px;
+}
+.tabs-left .nav-tabs {
+ float: left;
+ margin-right: 19px;
+ border-right: 1px solid #ddd;
+}
+.tabs-left .nav-tabs > li > a {
+ margin-right: -1px;
+ -webkit-border-radius: 4px 0 0 4px;
+ -moz-border-radius: 4px 0 0 4px;
+ border-radius: 4px 0 0 4px;
+}
+.tabs-left .nav-tabs > li > a:hover {
+ border-color: #eeeeee #dddddd #eeeeee #eeeeee;
+}
+.tabs-left .nav-tabs .active > a,
+.tabs-left .nav-tabs .active > a:hover {
+ border-color: #ddd transparent #ddd #ddd;
+ *border-right-color: #ffffff;
+}
+.tabs-right .nav-tabs {
+ float: right;
+ margin-left: 19px;
+ border-left: 1px solid #ddd;
+}
+.tabs-right .nav-tabs > li > a {
+ margin-left: -1px;
+ -webkit-border-radius: 0 4px 4px 0;
+ -moz-border-radius: 0 4px 4px 0;
+ border-radius: 0 4px 4px 0;
+}
+.tabs-right .nav-tabs > li > a:hover {
+ border-color: #eeeeee #eeeeee #eeeeee #dddddd;
+}
+.tabs-right .nav-tabs .active > a,
+.tabs-right .nav-tabs .active > a:hover {
+ border-color: #ddd #ddd #ddd transparent;
+ *border-left-color: #ffffff;
+}
+.navbar {
+ *position: relative;
+ *z-index: 2;
+ overflow: visible;
+ margin-bottom: 18px;
+}
+.navbar-inner {
+ padding-left: 20px;
+ padding-right: 20px;
+ background-color: #2c2c2c;
+ background-image: -moz-linear-gradient(top, #333333, #222222);
+ background-image: -ms-linear-gradient(top, #333333, #222222);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));
+ background-image: -webkit-linear-gradient(top, #333333, #222222);
+ background-image: -o-linear-gradient(top, #333333, #222222);
+ background-image: linear-gradient(top, #333333, #222222);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
+ -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
+}
+.navbar .container {
+ width: auto;
+}
+.btn-navbar {
+ display: none;
+ float: right;
+ padding: 7px 10px;
+ margin-left: 5px;
+ margin-right: 5px;
+ background-color: #2c2c2c;
+ background-image: -moz-linear-gradient(top, #333333, #222222);
+ background-image: -ms-linear-gradient(top, #333333, #222222);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));
+ background-image: -webkit-linear-gradient(top, #333333, #222222);
+ background-image: -o-linear-gradient(top, #333333, #222222);
+ background-image: linear-gradient(top, #333333, #222222);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);
+ border-color: #222222 #222222 #000000;
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+ filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
+}
+.btn-navbar:hover,
+.btn-navbar:active,
+.btn-navbar.active,
+.btn-navbar.disabled,
+.btn-navbar[disabled] {
+ background-color: #222222;
+}
+.btn-navbar:active,
+.btn-navbar.active {
+ background-color: #080808 \9;
+}
+.btn-navbar .icon-bar {
+ display: block;
+ width: 18px;
+ height: 2px;
+ background-color: #f5f5f5;
+ -webkit-border-radius: 1px;
+ -moz-border-radius: 1px;
+ border-radius: 1px;
+ -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
+ -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
+}
+.btn-navbar .icon-bar + .icon-bar {
+ margin-top: 3px;
+}
+.nav-collapse.collapse {
+ height: auto;
+}
+.navbar {
+ color: #999999;
+}
+.navbar .brand:hover {
+ text-decoration: none;
+}
+.navbar .brand {
+ float: left;
+ display: block;
+ padding: 8px 20px 12px;
+ margin-left: -20px;
+ font-size: 20px;
+ font-weight: 200;
+ line-height: 1;
+ color: #ffffff;
+}
+.navbar .navbar-text {
+ margin-bottom: 0;
+ line-height: 40px;
+}
+.navbar .btn,
+.navbar .btn-group {
+ margin-top: 5px;
+}
+.navbar .btn-group .btn {
+ margin-top: 0;
+}
+.navbar-form {
+ margin-bottom: 0;
+ *zoom: 1;
+}
+.navbar-form:before,
+.navbar-form:after {
+ display: table;
+ content: "";
+}
+.navbar-form:after {
+ clear: both;
+}
+.navbar-form input,
+.navbar-form select,
+.navbar-form .radio,
+.navbar-form .checkbox {
+ margin-top: 5px;
+}
+.navbar-form input,
+.navbar-form select {
+ display: inline-block;
+ margin-bottom: 0;
+}
+.navbar-form input[type="image"],
+.navbar-form input[type="checkbox"],
+.navbar-form input[type="radio"] {
+ margin-top: 3px;
+}
+.navbar-form .input-append,
+.navbar-form .input-prepend {
+ margin-top: 6px;
+ white-space: nowrap;
+}
+.navbar-form .input-append input,
+.navbar-form .input-prepend input {
+ margin-top: 0;
+}
+.navbar-search {
+ position: relative;
+ float: left;
+ margin-top: 6px;
+ margin-bottom: 0;
+}
+.navbar-search .search-query {
+ padding: 4px 9px;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 13px;
+ font-weight: normal;
+ line-height: 1;
+ color: #ffffff;
+ background-color: #626262;
+ border: 1px solid #151515;
+ -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15);
+ -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15);
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15);
+ -webkit-transition: none;
+ -moz-transition: none;
+ -ms-transition: none;
+ -o-transition: none;
+ transition: none;
+}
+.navbar-search .search-query:-moz-placeholder {
+ color: #cccccc;
+}
+.navbar-search .search-query::-webkit-input-placeholder {
+ color: #cccccc;
+}
+.navbar-search .search-query:focus,
+.navbar-search .search-query.focused {
+ padding: 5px 10px;
+ color: #333333;
+ text-shadow: 0 1px 0 #ffffff;
+ background-color: #ffffff;
+ border: 0;
+ -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
+ -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
+ box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
+ outline: 0;
+}
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+ position: fixed;
+ right: 0;
+ left: 0;
+ z-index: 1030;
+ margin-bottom: 0;
+}
+.navbar-fixed-top .navbar-inner,
+.navbar-fixed-bottom .navbar-inner {
+ padding-left: 0;
+ padding-right: 0;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+}
+.navbar-fixed-top .container,
+.navbar-fixed-bottom .container {
+ width: 940px;
+}
+.navbar-fixed-top {
+ top: 0;
+}
+.navbar-fixed-bottom {
+ bottom: 0;
+}
+.navbar .nav {
+ position: relative;
+ left: 0;
+ display: block;
+ float: left;
+ margin: 0 10px 0 0;
+}
+.navbar .nav.pull-right {
+ float: right;
+}
+.navbar .nav > li {
+ display: block;
+ float: left;
+}
+.navbar .nav > li > a {
+ float: none;
+ padding: 10px 10px 11px;
+ line-height: 19px;
+ color: #999999;
+ text-decoration: none;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+}
+.navbar .nav > li > a:hover {
+ background-color: transparent;
+ color: #ffffff;
+ text-decoration: none;
+}
+.navbar .nav .active > a,
+.navbar .nav .active > a:hover {
+ color: #ffffff;
+ text-decoration: none;
+ background-color: #222222;
+}
+.navbar .divider-vertical {
+ height: 40px;
+ width: 1px;
+ margin: 0 9px;
+ overflow: hidden;
+ background-color: #222222;
+ border-right: 1px solid #333333;
+}
+.navbar .nav.pull-right {
+ margin-left: 10px;
+ margin-right: 0;
+}
+.navbar .dropdown-menu {
+ margin-top: 1px;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+.navbar .dropdown-menu:before {
+ content: '';
+ display: inline-block;
+ border-left: 7px solid transparent;
+ border-right: 7px solid transparent;
+ border-bottom: 7px solid #ccc;
+ border-bottom-color: rgba(0, 0, 0, 0.2);
+ position: absolute;
+ top: -7px;
+ left: 9px;
+}
+.navbar .dropdown-menu:after {
+ content: '';
+ display: inline-block;
+ border-left: 6px solid transparent;
+ border-right: 6px solid transparent;
+ border-bottom: 6px solid #ffffff;
+ position: absolute;
+ top: -6px;
+ left: 10px;
+}
+.navbar-fixed-bottom .dropdown-menu:before {
+ border-top: 7px solid #ccc;
+ border-top-color: rgba(0, 0, 0, 0.2);
+ border-bottom: 0;
+ bottom: -7px;
+ top: auto;
+}
+.navbar-fixed-bottom .dropdown-menu:after {
+ border-top: 6px solid #ffffff;
+ border-bottom: 0;
+ bottom: -6px;
+ top: auto;
+}
+.navbar .nav .dropdown-toggle .caret,
+.navbar .nav .open.dropdown .caret {
+ border-top-color: #ffffff;
+ border-bottom-color: #ffffff;
+}
+.navbar .nav .active .caret {
+ opacity: 1;
+ filter: alpha(opacity=100);
+}
+.navbar .nav .open > .dropdown-toggle,
+.navbar .nav .active > .dropdown-toggle,
+.navbar .nav .open.active > .dropdown-toggle {
+ background-color: transparent;
+}
+.navbar .nav .active > .dropdown-toggle:hover {
+ color: #ffffff;
+}
+.navbar .nav.pull-right .dropdown-menu,
+.navbar .nav .dropdown-menu.pull-right {
+ left: auto;
+ right: 0;
+}
+.navbar .nav.pull-right .dropdown-menu:before,
+.navbar .nav .dropdown-menu.pull-right:before {
+ left: auto;
+ right: 12px;
+}
+.navbar .nav.pull-right .dropdown-menu:after,
+.navbar .nav .dropdown-menu.pull-right:after {
+ left: auto;
+ right: 13px;
+}
+.breadcrumb {
+ padding: 7px 14px;
+ margin: 0 0 18px;
+ list-style: none;
+ background-color: #fbfbfb;
+ background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5);
+ background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));
+ background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5);
+ background-image: -o-linear-gradient(top, #ffffff, #f5f5f5);
+ background-image: linear-gradient(top, #ffffff, #f5f5f5);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);
+ border: 1px solid #ddd;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-box-shadow: inset 0 1px 0 #ffffff;
+ -moz-box-shadow: inset 0 1px 0 #ffffff;
+ box-shadow: inset 0 1px 0 #ffffff;
+}
+.breadcrumb li {
+ display: inline-block;
+ *display: inline;
+ /* IE7 inline-block hack */
+
+ *zoom: 1;
+ text-shadow: 0 1px 0 #ffffff;
+}
+.breadcrumb .divider {
+ padding: 0 5px;
+ color: #999999;
+}
+.breadcrumb .active a {
+ color: #333333;
+}
+.pagination {
+ height: 36px;
+ margin: 18px 0;
+}
+.pagination ul {
+ display: inline-block;
+ *display: inline;
+ /* IE7 inline-block hack */
+
+ *zoom: 1;
+ margin-left: 0;
+ margin-bottom: 0;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+.pagination li {
+ display: inline;
+}
+.pagination a {
+ float: left;
+ padding: 0 14px;
+ line-height: 34px;
+ text-decoration: none;
+ border: 1px solid #ddd;
+ border-left-width: 0;
+}
+.pagination a:hover,
+.pagination .active a {
+ background-color: #f5f5f5;
+}
+.pagination .active a {
+ color: #999999;
+ cursor: default;
+}
+.pagination .disabled span,
+.pagination .disabled a,
+.pagination .disabled a:hover {
+ color: #999999;
+ background-color: transparent;
+ cursor: default;
+}
+.pagination li:first-child a {
+ border-left-width: 1px;
+ -webkit-border-radius: 3px 0 0 3px;
+ -moz-border-radius: 3px 0 0 3px;
+ border-radius: 3px 0 0 3px;
+}
+.pagination li:last-child a {
+ -webkit-border-radius: 0 3px 3px 0;
+ -moz-border-radius: 0 3px 3px 0;
+ border-radius: 0 3px 3px 0;
+}
+.pagination-centered {
+ text-align: center;
+}
+.pagination-right {
+ text-align: right;
+}
+.pager {
+ margin-left: 0;
+ margin-bottom: 18px;
+ list-style: none;
+ text-align: center;
+ *zoom: 1;
+}
+.pager:before,
+.pager:after {
+ display: table;
+ content: "";
+}
+.pager:after {
+ clear: both;
+}
+.pager li {
+ display: inline;
+}
+.pager a {
+ display: inline-block;
+ padding: 5px 14px;
+ background-color: #fff;
+ /*border: 1px solid #ddd;
+ -webkit-border-radius: 15px;
+ -moz-border-radius: 15px;
+ border-radius: 15px;*/
+}
+.pager a:hover {
+ text-decoration: none;
+ background-color: #f5f5f5;
+}
+.pager .next a {
+ float: right;
+}
+.pager .previous a {
+ float: left;
+}
+.pager .disabled a,
+.pager .disabled a:hover {
+ color: #999999;
+ background-color: #fff;
+ cursor: default;
+}
+.thumbnails {
+ margin-left: -20px;
+ list-style: none;
+ *zoom: 1;
+}
+.thumbnails:before,
+.thumbnails:after {
+ display: table;
+ content: "";
+}
+.thumbnails:after {
+ clear: both;
+}
+.thumbnails > li {
+ float: left;
+ margin: 0 0 18px 20px;
+}
+.thumbnail {
+ display: block;
+ padding: 4px;
+ line-height: 1;
+ border: 1px solid #ddd;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);
+ -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);
+}
+a.thumbnail:hover {
+ border-color: #0088cc;
+ -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
+ -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
+ box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
+}
+.thumbnail > img {
+ display: block;
+ max-width: 100%;
+ margin-left: auto;
+ margin-right: auto;
+}
+.thumbnail .caption {
+ padding: 9px;
+}
+.alert {
+ padding: 8px 35px 8px 14px;
+ margin-bottom: 18px;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+ background-color: #fcf8e3;
+ border: 1px solid #fbeed5;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ color: #c09853;
+}
+.alert-heading {
+ color: inherit;
+}
+.alert .close {
+ position: relative;
+ top: -2px;
+ right: -21px;
+ line-height: 18px;
+}
+.alert-success {
+ background-color: #dff0d8;
+ border-color: #d6e9c6;
+ color: #468847;
+}
+.alert-danger,
+.alert-error {
+ background-color: #f2dede;
+ border-color: #eed3d7;
+ color: #b94a48;
+}
+.alert-info {
+ background-color: #d9edf7;
+ border-color: #bce8f1;
+ color: #3a87ad;
+}
+.alert-block {
+ padding-top: 14px;
+ padding-bottom: 14px;
+}
+.alert-block > p,
+.alert-block > ul {
+ margin-bottom: 0;
+}
+.alert-block p + p {
+ margin-top: 5px;
+}
+@-webkit-keyframes progress-bar-stripes {
+ from {
+ background-position: 0 0;
+ }
+ to {
+ background-position: 40px 0;
+ }
+}
+@-moz-keyframes progress-bar-stripes {
+ from {
+ background-position: 0 0;
+ }
+ to {
+ background-position: 40px 0;
+ }
+}
+@-ms-keyframes progress-bar-stripes {
+ from {
+ background-position: 0 0;
+ }
+ to {
+ background-position: 40px 0;
+ }
+}
+@keyframes progress-bar-stripes {
+ from {
+ background-position: 0 0;
+ }
+ to {
+ background-position: 40px 0;
+ }
+}
+.progress {
+ overflow: hidden;
+ height: 18px;
+ margin-bottom: 18px;
+ background-color: #f7f7f7;
+ background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);
+ background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));
+ background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9);
+ background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);
+ background-image: linear-gradient(top, #f5f5f5, #f9f9f9);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);
+ -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+ -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+ box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+.progress .bar {
+ width: 0%;
+ height: 18px;
+ color: #ffffff;
+ font-size: 12px;
+ text-align: center;
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+ background-color: #0e90d2;
+ background-image: -moz-linear-gradient(top, #149bdf, #0480be);
+ background-image: -ms-linear-gradient(top, #149bdf, #0480be);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));
+ background-image: -webkit-linear-gradient(top, #149bdf, #0480be);
+ background-image: -o-linear-gradient(top, #149bdf, #0480be);
+ background-image: linear-gradient(top, #149bdf, #0480be);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);
+ -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+ -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+ box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+ -webkit-transition: width 0.6s ease;
+ -moz-transition: width 0.6s ease;
+ -ms-transition: width 0.6s ease;
+ -o-transition: width 0.6s ease;
+ transition: width 0.6s ease;
+}
+.progress-striped .bar {
+ background-color: #149bdf;
+ background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
+ background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ -webkit-background-size: 40px 40px;
+ -moz-background-size: 40px 40px;
+ -o-background-size: 40px 40px;
+ background-size: 40px 40px;
+}
+.progress.active .bar {
+ -webkit-animation: progress-bar-stripes 2s linear infinite;
+ -moz-animation: progress-bar-stripes 2s linear infinite;
+ animation: progress-bar-stripes 2s linear infinite;
+}
+.progress-danger .bar {
+ background-color: #dd514c;
+ background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
+ background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));
+ background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
+ background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
+ background-image: linear-gradient(top, #ee5f5b, #c43c35);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);
+}
+.progress-danger.progress-striped .bar {
+ background-color: #ee5f5b;
+ background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
+ background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-success .bar {
+ background-color: #5eb95e;
+ background-image: -moz-linear-gradient(top, #62c462, #57a957);
+ background-image: -ms-linear-gradient(top, #62c462, #57a957);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));
+ background-image: -webkit-linear-gradient(top, #62c462, #57a957);
+ background-image: -o-linear-gradient(top, #62c462, #57a957);
+ background-image: linear-gradient(top, #62c462, #57a957);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);
+}
+.progress-success.progress-striped .bar {
+ background-color: #62c462;
+ background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
+ background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-info .bar {
+ background-color: #4bb1cf;
+ background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
+ background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));
+ background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
+ background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
+ background-image: linear-gradient(top, #5bc0de, #339bb9);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);
+}
+.progress-info.progress-striped .bar {
+ background-color: #5bc0de;
+ background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
+ background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.progress-warning .bar {
+ background-color: #faa732;
+ background-image: -moz-linear-gradient(top, #fbb450, #f89406);
+ background-image: -ms-linear-gradient(top, #fbb450, #f89406);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
+ background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
+ background-image: -o-linear-gradient(top, #fbb450, #f89406);
+ background-image: linear-gradient(top, #fbb450, #f89406);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);
+}
+.progress-warning.progress-striped .bar {
+ background-color: #fbb450;
+ background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
+ background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+ background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+}
+.hero-unit {
+ padding: 60px;
+ margin-bottom: 30px;
+ background-color: #eeeeee;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+}
+.hero-unit h1 {
+ margin-bottom: 0;
+ font-size: 60px;
+ line-height: 1;
+ color: inherit;
+ letter-spacing: -1px;
+}
+.hero-unit p {
+ font-size: 18px;
+ font-weight: 200;
+ line-height: 27px;
+ color: inherit;
+}
+.tooltip {
+ position: absolute;
+ z-index: 1020;
+ display: block;
+ visibility: visible;
+ padding: 5px;
+ font-size: 11px;
+ opacity: 0;
+ filter: alpha(opacity=0);
+}
+.tooltip.in {
+ opacity: 0.8;
+ filter: alpha(opacity=80);
+}
+.tooltip.top {
+ margin-top: -2px;
+}
+.tooltip.right {
+ margin-left: 2px;
+}
+.tooltip.bottom {
+ margin-top: 2px;
+}
+.tooltip.left {
+ margin-left: -2px;
+}
+.tooltip.top .tooltip-arrow {
+ bottom: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-left: 5px solid transparent;
+ border-right: 5px solid transparent;
+ border-top: 5px solid #000000;
+}
+.tooltip.left .tooltip-arrow {
+ top: 50%;
+ right: 0;
+ margin-top: -5px;
+ border-top: 5px solid transparent;
+ border-bottom: 5px solid transparent;
+ border-left: 5px solid #000000;
+}
+.tooltip.bottom .tooltip-arrow {
+ top: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-left: 5px solid transparent;
+ border-right: 5px solid transparent;
+ border-bottom: 5px solid #000000;
+}
+.tooltip.right .tooltip-arrow {
+ top: 50%;
+ left: 0;
+ margin-top: -5px;
+ border-top: 5px solid transparent;
+ border-bottom: 5px solid transparent;
+ border-right: 5px solid #000000;
+}
+.tooltip-inner {
+ max-width: 200px;
+ padding: 3px 8px;
+ color: #ffffff;
+ text-align: center;
+ text-decoration: none;
+ background-color: #000000;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+.tooltip-arrow {
+ position: absolute;
+ width: 0;
+ height: 0;
+}
+.popover {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 1010;
+ display: none;
+ padding: 5px;
+}
+.popover.top {
+ margin-top: -5px;
+}
+.popover.right {
+ margin-left: 5px;
+}
+.popover.bottom {
+ margin-top: 5px;
+}
+.popover.left {
+ margin-left: -5px;
+}
+.popover.top .arrow {
+ bottom: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-left: 5px solid transparent;
+ border-right: 5px solid transparent;
+ border-top: 5px solid #000000;
+}
+.popover.right .arrow {
+ top: 50%;
+ left: 0;
+ margin-top: -5px;
+ border-top: 5px solid transparent;
+ border-bottom: 5px solid transparent;
+ border-right: 5px solid #000000;
+}
+.popover.bottom .arrow {
+ top: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-left: 5px solid transparent;
+ border-right: 5px solid transparent;
+ border-bottom: 5px solid #000000;
+}
+.popover.left .arrow {
+ top: 50%;
+ right: 0;
+ margin-top: -5px;
+ border-top: 5px solid transparent;
+ border-bottom: 5px solid transparent;
+ border-left: 5px solid #000000;
+}
+.popover .arrow {
+ position: absolute;
+ width: 0;
+ height: 0;
+}
+.popover-inner {
+ padding: 3px;
+ width: 280px;
+ overflow: hidden;
+ background: #000000;
+ background: rgba(0, 0, 0, 0.8);
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+}
+.popover-title {
+ padding: 9px 15px;
+ line-height: 1;
+ background-color: #f5f5f5;
+ border-bottom: 1px solid #eee;
+ -webkit-border-radius: 3px 3px 0 0;
+ -moz-border-radius: 3px 3px 0 0;
+ border-radius: 3px 3px 0 0;
+}
+.popover-content {
+ padding: 14px;
+ background-color: #ffffff;
+ -webkit-border-radius: 0 0 3px 3px;
+ -moz-border-radius: 0 0 3px 3px;
+ border-radius: 0 0 3px 3px;
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding-box;
+ background-clip: padding-box;
+}
+.popover-content p,
+.popover-content ul,
+.popover-content ol {
+ margin-bottom: 0;
+}
+.modal-open .dropdown-menu {
+ z-index: 2050;
+}
+.modal-open .dropdown.open {
+ *z-index: 2050;
+}
+.modal-open .popover {
+ z-index: 2060;
+}
+.modal-open .tooltip {
+ z-index: 2070;
+}
+.modal-backdrop {
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: 1040;
+ background-color: #000000;
+}
+.modal-backdrop.fade {
+ opacity: 0;
+}
+.modal-backdrop,
+.modal-backdrop.fade.in {
+ opacity: 0.8;
+ filter: alpha(opacity=80);
+}
+.modal {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ z-index: 1050;
+ overflow: auto;
+ width: 560px;
+ margin: -250px 0 0 -280px;
+ background-color: #ffffff;
+ border: 1px solid #999;
+ border: 1px solid rgba(0, 0, 0, 0.3);
+ *border: 1px solid #999;
+ /* IE6-7 */
+
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding-box;
+ background-clip: padding-box;
+}
+.modal.fade {
+ -webkit-transition: opacity .3s linear, top .3s ease-out;
+ -moz-transition: opacity .3s linear, top .3s ease-out;
+ -ms-transition: opacity .3s linear, top .3s ease-out;
+ -o-transition: opacity .3s linear, top .3s ease-out;
+ transition: opacity .3s linear, top .3s ease-out;
+ top: -25%;
+}
+.modal.fade.in {
+ top: 50%;
+}
+.modal-header {
+ padding: 9px 15px;
+ border-bottom: 1px solid #eee;
+}
+.modal-header .close {
+ margin-top: 2px;
+}
+.modal-body {
+ overflow-y: auto;
+ max-height: 400px;
+ padding: 15px;
+}
+.modal-form {
+ margin-bottom: 0;
+}
+.modal-footer {
+ padding: 14px 15px 15px;
+ margin-bottom: 0;
+ text-align: right;
+ background-color: #f5f5f5;
+ border-top: 1px solid #ddd;
+ -webkit-border-radius: 0 0 6px 6px;
+ -moz-border-radius: 0 0 6px 6px;
+ border-radius: 0 0 6px 6px;
+ -webkit-box-shadow: inset 0 1px 0 #ffffff;
+ -moz-box-shadow: inset 0 1px 0 #ffffff;
+ box-shadow: inset 0 1px 0 #ffffff;
+ *zoom: 1;
+}
+.modal-footer:before,
+.modal-footer:after {
+ display: table;
+ content: "";
+}
+.modal-footer:after {
+ clear: both;
+}
+.modal-footer .btn + .btn {
+ margin-left: 5px;
+ margin-bottom: 0;
+}
+.modal-footer .btn-group .btn + .btn {
+ margin-left: -1px;
+}
+.dropdown {
+ position: relative;
+}
+.dropdown-toggle {
+ *margin-bottom: -3px;
+}
+.dropdown-toggle:active,
+.open .dropdown-toggle {
+ outline: 0;
+}
+.caret {
+ display: inline-block;
+ width: 0;
+ height: 0;
+ vertical-align: top;
+ border-left: 4px solid transparent;
+ border-right: 4px solid transparent;
+ border-top: 4px solid #000000;
+ opacity: 0.3;
+ filter: alpha(opacity=30);
+ content: "";
+}
+.dropdown .caret {
+ margin-top: 8px;
+ margin-left: 2px;
+}
+.dropdown:hover .caret,
+.open.dropdown .caret {
+ opacity: 1;
+ filter: alpha(opacity=100);
+}
+.dropdown-menu {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ z-index: 1000;
+ float: left;
+ display: none;
+ min-width: 160px;
+ padding: 4px 0;
+ margin: 0;
+ list-style: none;
+ background-color: #ffffff;
+ border-color: #ccc;
+ border-color: rgba(0, 0, 0, 0.2);
+ border-style: solid;
+ border-width: 1px;
+ -webkit-border-radius: 0 0 5px 5px;
+ -moz-border-radius: 0 0 5px 5px;
+ border-radius: 0 0 5px 5px;
+ -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+ -webkit-background-clip: padding-box;
+ -moz-background-clip: padding;
+ background-clip: padding-box;
+ *border-right-width: 2px;
+ *border-bottom-width: 2px;
+}
+.dropdown-menu.pull-right {
+ right: 0;
+ left: auto;
+}
+.dropdown-menu .divider {
+ height: 1px;
+ margin: 8px 1px;
+ overflow: hidden;
+ background-color: #e5e5e5;
+ border-bottom: 1px solid #ffffff;
+ *width: 100%;
+ *margin: -5px 0 5px;
+}
+.dropdown-menu a {
+ display: block;
+ padding: 3px 15px;
+ clear: both;
+ font-weight: normal;
+ line-height: 18px;
+ color: #333333;
+ white-space: nowrap;
+}
+.dropdown-menu li > a:hover,
+.dropdown-menu .active > a,
+.dropdown-menu .active > a:hover {
+ color: #ffffff;
+ text-decoration: none;
+ background-color: #0088cc;
+}
+.dropdown.open {
+ *z-index: 1000;
+}
+.dropdown.open .dropdown-toggle {
+ color: #ffffff;
+ background: #ccc;
+ background: rgba(0, 0, 0, 0.3);
+}
+.dropdown.open .dropdown-menu {
+ display: block;
+}
+.pull-right .dropdown-menu {
+ left: auto;
+ right: 0;
+}
+.dropup .caret,
+.navbar-fixed-bottom .dropdown .caret {
+ border-top: 0;
+ border-bottom: 4px solid #000000;
+ content: "\2191";
+}
+.dropup .dropdown-menu,
+.navbar-fixed-bottom .dropdown .dropdown-menu {
+ top: auto;
+ bottom: 100%;
+ margin-bottom: 1px;
+}
+.typeahead {
+ margin-top: 2px;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+.accordion {
+ margin-bottom: 18px;
+}
+.accordion-group {
+ margin-bottom: 2px;
+ border: 1px solid #e5e5e5;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+.accordion-heading {
+ border-bottom: 0;
+}
+.accordion-heading .accordion-toggle {
+ display: block;
+ padding: 8px 15px;
+}
+.accordion-inner {
+ padding: 9px 15px;
+ border-top: 1px solid #e5e5e5;
+}
+.carousel {
+ position: relative;
+ margin-bottom: 18px;
+ line-height: 1;
+}
+.carousel-inner {
+ overflow: hidden;
+ width: 100%;
+ position: relative;
+}
+.carousel .item {
+ display: none;
+ position: relative;
+ -webkit-transition: 0.6s ease-in-out left;
+ -moz-transition: 0.6s ease-in-out left;
+ -ms-transition: 0.6s ease-in-out left;
+ -o-transition: 0.6s ease-in-out left;
+ transition: 0.6s ease-in-out left;
+}
+.carousel .item > img {
+ display: block;
+ line-height: 1;
+}
+.carousel .active,
+.carousel .next,
+.carousel .prev {
+ display: block;
+}
+.carousel .active {
+ left: 0;
+}
+.carousel .next,
+.carousel .prev {
+ position: absolute;
+ top: 0;
+ width: 100%;
+}
+.carousel .next {
+ left: 100%;
+}
+.carousel .prev {
+ left: -100%;
+}
+.carousel .next.left,
+.carousel .prev.right {
+ left: 0;
+}
+.carousel .active.left {
+ left: -100%;
+}
+.carousel .active.right {
+ left: 100%;
+}
+.carousel-control {
+ position: absolute;
+ top: 40%;
+ left: 15px;
+ width: 40px;
+ height: 40px;
+ margin-top: -20px;
+ font-size: 60px;
+ font-weight: 100;
+ line-height: 30px;
+ color: #ffffff;
+ text-align: center;
+ background: #222222;
+ border: 3px solid #ffffff;
+ -webkit-border-radius: 23px;
+ -moz-border-radius: 23px;
+ border-radius: 23px;
+ opacity: 0.5;
+ filter: alpha(opacity=50);
+}
+.carousel-control.right {
+ left: auto;
+ right: 15px;
+}
+.carousel-control:hover {
+ color: #ffffff;
+ text-decoration: none;
+ opacity: 0.9;
+ filter: alpha(opacity=90);
+}
+.carousel-caption {
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ padding: 10px 15px 5px;
+ background: #333333;
+ background: rgba(0, 0, 0, 0.75);
+}
+.carousel-caption h4,
+.carousel-caption p {
+ color: #ffffff;
+}
+.well {
+ min-height: 20px;
+ padding: 19px;
+ margin-bottom: 20px;
+ background-color: #f5f5f5;
+ border: 1px solid #eee;
+ border: 1px solid rgba(0, 0, 0, 0.05);
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
+}
+.well blockquote {
+ border-color: #ddd;
+ border-color: rgba(0, 0, 0, 0.15);
+}
+.well-large {
+ padding: 24px;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+}
+.well-small {
+ padding: 9px;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+.close {
+ float: right;
+ font-size: 20px;
+ font-weight: bold;
+ line-height: 18px;
+ color: #000000;
+ text-shadow: 0 1px 0 #ffffff;
+ opacity: 0.2;
+ filter: alpha(opacity=20);
+}
+.close:hover {
+ color: #000000;
+ text-decoration: none;
+ opacity: 0.4;
+ filter: alpha(opacity=40);
+ cursor: pointer;
+}
+.pull-right {
+ float: right;
+}
+.pull-left {
+ float: left;
+}
+.hide {
+ display: none;
+}
+.show {
+ display: block;
+}
+.invisible {
+ visibility: hidden;
+}
+.fade {
+ -webkit-transition: opacity 0.15s linear;
+ -moz-transition: opacity 0.15s linear;
+ -ms-transition: opacity 0.15s linear;
+ -o-transition: opacity 0.15s linear;
+ transition: opacity 0.15s linear;
+ opacity: 0;
+}
+.fade.in {
+ opacity: 1;
+}
+.collapse {
+ -webkit-transition: height 0.35s ease;
+ -moz-transition: height 0.35s ease;
+ -ms-transition: height 0.35s ease;
+ -o-transition: height 0.35s ease;
+ transition: height 0.35s ease;
+ position: relative;
+ overflow: hidden;
+ height: 0;
+}
+.collapse.in {
+ height: auto;
+}
+/*!
+ * Bootstrap Responsive v2.0.2
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */
+.hidden {
+ display: none;
+ visibility: hidden;
+}
+.visible-phone {
+ display: none;
+}
+.visible-tablet {
+ display: none;
+}
+.visible-desktop {
+ display: block;
+}
+.hidden-phone {
+ display: block;
+}
+.hidden-tablet {
+ display: block;
+}
+.hidden-desktop {
+ display: none;
+}
+@media (max-width: 767px) {
+ .visible-phone {
+ display: block;
+ }
+ .hidden-phone {
+ display: none;
+ }
+ .hidden-desktop {
+ display: block;
+ }
+ .visible-desktop {
+ display: none;
+ }
+}
+@media (min-width: 768px) and (max-width: 979px) {
+ .visible-tablet {
+ display: block;
+ }
+ .hidden-tablet {
+ display: none;
+ }
+ .hidden-desktop {
+ display: block;
+ }
+ .visible-desktop {
+ display: none;
+ }
+}
+@media (max-width: 480px) {
+ .nav-collapse {
+ -webkit-transform: translate3d(0, 0, 0);
+ }
+ .page-header h1 small {
+ display: block;
+ line-height: 18px;
+ }
+ input[type="checkbox"],
+ input[type="radio"] {
+ border: 1px solid #ccc;
+ }
+ .form-horizontal .control-group > label {
+ float: none;
+ width: auto;
+ padding-top: 0;
+ text-align: left;
+ }
+ .form-horizontal .controls {
+ margin-left: 0;
+ }
+ .form-horizontal .control-list {
+ padding-top: 0;
+ }
+ .form-horizontal .form-actions {
+ padding-left: 10px;
+ padding-right: 10px;
+ }
+ .modal {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ right: 10px;
+ width: auto;
+ margin: 0;
+ }
+ .modal.fade.in {
+ top: auto;
+ }
+ .modal-header .close {
+ padding: 10px;
+ margin: -10px;
+ }
+ .carousel-caption {
+ position: static;
+ }
+}
+@media (max-width: 767px) {
+ body {
+ padding-left: 20px;
+ padding-right: 20px;
+ }
+ .navbar-fixed-top {
+ margin-left: -20px;
+ margin-right: -20px;
+ }
+ .container {
+ width: auto;
+ }
+ .row-fluid {
+ width: 100%;
+ }
+ .row {
+ margin-left: 0;
+ }
+ .row > [class*="span"],
+ .row-fluid > [class*="span"] {
+ float: none;
+ display: block;
+ width: auto;
+ margin: 0;
+ }
+ .thumbnails [class*="span"] {
+ width: auto;
+ }
+ input[class*="span"],
+ select[class*="span"],
+ textarea[class*="span"],
+ .uneditable-input {
+ display: block;
+ width: 100%;
+ min-height: 28px;
+ /* Make inputs at least the height of their button counterpart */
+
+ /* Makes inputs behave like true block-level elements */
+
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ box-sizing: border-box;
+ }
+ .input-prepend input[class*="span"],
+ .input-append input[class*="span"] {
+ width: auto;
+ }
+}
+@media (min-width: 768px) and (max-width: 979px) {
+ .row {
+ margin-left: -20px;
+ *zoom: 1;
+ }
+ .row:before,
+ .row:after {
+ display: table;
+ content: "";
+ }
+ .row:after {
+ clear: both;
+ }
+ [class*="span"] {
+ float: left;
+ margin-left: 20px;
+ }
+ .container,
+ .navbar-fixed-top .container,
+ .navbar-fixed-bottom .container {
+ width: 724px;
+ }
+ .span12 {
+ width: 724px;
+ }
+ .span11 {
+ width: 662px;
+ }
+ .span10 {
+ width: 600px;
+ }
+ .span9 {
+ width: 538px;
+ }
+ .span8 {
+ width: 476px;
+ }
+ .span7 {
+ width: 414px;
+ }
+ .span6 {
+ width: 352px;
+ }
+ .span5 {
+ width: 290px;
+ }
+ .span4 {
+ width: 228px;
+ }
+ .span3 {
+ width: 166px;
+ }
+ .span2 {
+ width: 104px;
+ }
+ .span1 {
+ width: 42px;
+ }
+ .offset12 {
+ margin-left: 764px;
+ }
+ .offset11 {
+ margin-left: 702px;
+ }
+ .offset10 {
+ margin-left: 640px;
+ }
+ .offset9 {
+ margin-left: 578px;
+ }
+ .offset8 {
+ margin-left: 516px;
+ }
+ .offset7 {
+ margin-left: 454px;
+ }
+ .offset6 {
+ margin-left: 392px;
+ }
+ .offset5 {
+ margin-left: 330px;
+ }
+ .offset4 {
+ margin-left: 268px;
+ }
+ .offset3 {
+ margin-left: 206px;
+ }
+ .offset2 {
+ margin-left: 144px;
+ }
+ .offset1 {
+ margin-left: 82px;
+ }
+ .row-fluid {
+ width: 100%;
+ *zoom: 1;
+ }
+ .row-fluid:before,
+ .row-fluid:after {
+ display: table;
+ content: "";
+ }
+ .row-fluid:after {
+ clear: both;
+ }
+ .row-fluid > [class*="span"] {
+ float: left;
+ margin-left: 2.762430939%;
+ }
+ .row-fluid > [class*="span"]:first-child {
+ margin-left: 0;
+ }
+ .row-fluid > .span12 {
+ width: 99.999999993%;
+ }
+ .row-fluid > .span11 {
+ width: 91.436464082%;
+ }
+ .row-fluid > .span10 {
+ width: 82.87292817100001%;
+ }
+ .row-fluid > .span9 {
+ width: 74.30939226%;
+ }
+ .row-fluid > .span8 {
+ width: 65.74585634900001%;
+ }
+ .row-fluid > .span7 {
+ width: 57.182320438000005%;
+ }
+ .row-fluid > .span6 {
+ width: 48.618784527%;
+ }
+ .row-fluid > .span5 {
+ width: 40.055248616%;
+ }
+ .row-fluid > .span4 {
+ width: 31.491712705%;
+ }
+ .row-fluid > .span3 {
+ width: 22.928176794%;
+ }
+ .row-fluid > .span2 {
+ width: 14.364640883%;
+ }
+ .row-fluid > .span1 {
+ width: 5.801104972%;
+ }
+ input.span12, textarea.span12, .uneditable-input.span12 {
+ width: 714px;
+ }
+ input.span11, textarea.span11, .uneditable-input.span11 {
+ width: 652px;
+ }
+ input.span10, textarea.span10, .uneditable-input.span10 {
+ width: 590px;
+ }
+ input.span9, textarea.span9, .uneditable-input.span9 {
+ width: 528px;
+ }
+ input.span8, textarea.span8, .uneditable-input.span8 {
+ width: 466px;
+ }
+ input.span7, textarea.span7, .uneditable-input.span7 {
+ width: 404px;
+ }
+ input.span6, textarea.span6, .uneditable-input.span6 {
+ width: 342px;
+ }
+ input.span5, textarea.span5, .uneditable-input.span5 {
+ width: 280px;
+ }
+ input.span4, textarea.span4, .uneditable-input.span4 {
+ width: 218px;
+ }
+ input.span3, textarea.span3, .uneditable-input.span3 {
+ width: 156px;
+ }
+ input.span2, textarea.span2, .uneditable-input.span2 {
+ width: 94px;
+ }
+ input.span1, textarea.span1, .uneditable-input.span1 {
+ width: 32px;
+ }
+}
+@media (max-width: 979px) {
+ body {
+ padding-top: 0;
+ }
+ .navbar-fixed-top {
+ position: static;
+ margin-bottom: 18px;
+ }
+ .navbar-fixed-top .navbar-inner {
+ padding: 5px;
+ }
+ .navbar .container {
+ width: auto;
+ padding: 0;
+ }
+ .navbar .brand {
+ padding-left: 10px;
+ padding-right: 10px;
+ margin: 0 0 0 -5px;
+ }
+ .navbar .nav-collapse {
+ clear: left;
+ }
+ .navbar .nav {
+ float: none;
+ margin: 0 0 9px;
+ }
+ .navbar .nav > li {
+ float: none;
+ }
+ .navbar .nav > li > a {
+ margin-bottom: 2px;
+ }
+ .navbar .nav > .divider-vertical {
+ display: none;
+ }
+ .navbar .nav .nav-header {
+ color: #999999;
+ text-shadow: none;
+ }
+ .navbar .nav > li > a,
+ .navbar .dropdown-menu a {
+ padding: 6px 15px;
+ font-weight: bold;
+ color: #999999;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ }
+ .navbar .dropdown-menu li + li a {
+ margin-bottom: 2px;
+ }
+ .navbar .nav > li > a:hover,
+ .navbar .dropdown-menu a:hover {
+ background-color: #222222;
+ }
+ .navbar .dropdown-menu {
+ position: static;
+ top: auto;
+ left: auto;
+ float: none;
+ display: block;
+ max-width: none;
+ margin: 0 15px;
+ padding: 0;
+ background-color: transparent;
+ border: none;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+ -webkit-box-shadow: none;
+ -moz-box-shadow: none;
+ box-shadow: none;
+ }
+ .navbar .dropdown-menu:before,
+ .navbar .dropdown-menu:after {
+ display: none;
+ }
+ .navbar .dropdown-menu .divider {
+ display: none;
+ }
+ .navbar-form,
+ .navbar-search {
+ float: none;
+ padding: 9px 15px;
+ margin: 9px 0;
+ border-top: 1px solid #222222;
+ border-bottom: 1px solid #222222;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+ }
+ .navbar .nav.pull-right {
+ float: none;
+ margin-left: 0;
+ }
+ .navbar-static .navbar-inner {
+ padding-left: 10px;
+ padding-right: 10px;
+ }
+ .btn-navbar {
+ display: block;
+ }
+ .nav-collapse {
+ overflow: hidden;
+ height: 0;
+ }
+}
+@media (min-width: 980px) {
+ .nav-collapse.collapse {
+ height: auto !important;
+ overflow: visible !important;
+ }
+}
+@media (min-width: 1200px) {
+ .row {
+ margin-left: -30px;
+ *zoom: 1;
+ }
+ .row:before,
+ .row:after {
+ display: table;
+ content: "";
+ }
+ .row:after {
+ clear: both;
+ }
+ [class*="span"] {
+ float: left;
+ margin-left: 30px;
+ }
+ .container,
+ .navbar-fixed-top .container,
+ .navbar-fixed-bottom .container {
+ width: 1170px;
+ }
+ .span12 {
+ width: 1170px;
+ }
+ .span11 {
+ width: 1070px;
+ }
+ .span10 {
+ width: 970px;
+ }
+ .span9 {
+ width: 870px;
+ }
+ .span8 {
+ width: 770px;
+ }
+ .span7 {
+ width: 670px;
+ }
+ .span6 {
+ width: 570px;
+ }
+ .span5 {
+ width: 470px;
+ }
+ .span4 {
+ width: 370px;
+ }
+ .span3 {
+ width: 270px;
+ }
+ .span2 {
+ width: 170px;
+ }
+ .span1 {
+ width: 70px;
+ }
+ .offset12 {
+ margin-left: 1230px;
+ }
+ .offset11 {
+ margin-left: 1130px;
+ }
+ .offset10 {
+ margin-left: 1030px;
+ }
+ .offset9 {
+ margin-left: 930px;
+ }
+ .offset8 {
+ margin-left: 830px;
+ }
+ .offset7 {
+ margin-left: 730px;
+ }
+ .offset6 {
+ margin-left: 630px;
+ }
+ .offset5 {
+ margin-left: 530px;
+ }
+ .offset4 {
+ margin-left: 430px;
+ }
+ .offset3 {
+ margin-left: 330px;
+ }
+ .offset2 {
+ margin-left: 230px;
+ }
+ .offset1 {
+ margin-left: 130px;
+ }
+ .row-fluid {
+ width: 100%;
+ *zoom: 1;
+ }
+ .row-fluid:before,
+ .row-fluid:after {
+ display: table;
+ content: "";
+ }
+ .row-fluid:after {
+ clear: both;
+ }
+ .row-fluid > [class*="span"] {
+ float: left;
+ margin-left: 2.564102564%;
+ }
+ .row-fluid > [class*="span"]:first-child {
+ margin-left: 0;
+ }
+ .row-fluid > .span12 {
+ width: 100%;
+ }
+ .row-fluid > .span11 {
+ width: 91.45299145300001%;
+ }
+ .row-fluid > .span10 {
+ width: 82.905982906%;
+ }
+ .row-fluid > .span9 {
+ width: 74.358974359%;
+ }
+ .row-fluid > .span8 {
+ width: 65.81196581200001%;
+ }
+ .row-fluid > .span7 {
+ width: 57.264957265%;
+ }
+ .row-fluid > .span6 {
+ width: 48.717948718%;
+ }
+ .row-fluid > .span5 {
+ width: 40.170940171000005%;
+ }
+ .row-fluid > .span4 {
+ width: 31.623931624%;
+ }
+ .row-fluid > .span3 {
+ width: 23.076923077%;
+ }
+ .row-fluid > .span2 {
+ width: 14.529914530000001%;
+ }
+ .row-fluid > .span1 {
+ width: 5.982905983%;
+ }
+ input,
+ textarea,
+ .uneditable-input {
+ margin-left: 0;
+ }
+ input.span12, textarea.span12, .uneditable-input.span12 {
+ width: 1160px;
+ }
+ input.span11, textarea.span11, .uneditable-input.span11 {
+ width: 1060px;
+ }
+ input.span10, textarea.span10, .uneditable-input.span10 {
+ width: 960px;
+ }
+ input.span9, textarea.span9, .uneditable-input.span9 {
+ width: 860px;
+ }
+ input.span8, textarea.span8, .uneditable-input.span8 {
+ width: 760px;
+ }
+ input.span7, textarea.span7, .uneditable-input.span7 {
+ width: 660px;
+ }
+ input.span6, textarea.span6, .uneditable-input.span6 {
+ width: 560px;
+ }
+ input.span5, textarea.span5, .uneditable-input.span5 {
+ width: 460px;
+ }
+ input.span4, textarea.span4, .uneditable-input.span4 {
+ width: 360px;
+ }
+ input.span3, textarea.span3, .uneditable-input.span3 {
+ width: 260px;
+ }
+ input.span2, textarea.span2, .uneditable-input.span2 {
+ width: 160px;
+ }
+ input.span1, textarea.span1, .uneditable-input.span1 {
+ width: 60px;
+ }
+ .thumbnails {
+ margin-left: -30px;
+ }
+ .thumbnails > li {
+ margin-left: 30px;
+ }
+}
+
+/* Modifications for askbot */
+.caret {
+ margin-bottom: 7px;
+}
+.btn-group {
+ text-align: left;
+}
+.btn-toolbar {
+ margin: 0;
+}
+.modal-footer {
+ text-align: left;
+}
+.modal p {
+ font-size: 14px;
+}
+.modal-body > textarea {
+ width: 515px;
+ margin-bottom: 0px;
+}
+.modal-backdrop {
+ z-index: 200000;
+}
+.modal {
+ z-index: 200001;
+}
diff --git a/askbot/skins/default/media/bootstrap/css/bootstrap.min.css b/askbot/media/bootstrap/css/bootstrap.min.css
index 17b18fb6..17b18fb6 100644
--- a/askbot/skins/default/media/bootstrap/css/bootstrap.min.css
+++ b/askbot/media/bootstrap/css/bootstrap.min.css
diff --git a/askbot/skins/default/media/bootstrap/img/glyphicons-halflings-white.png b/askbot/media/bootstrap/img/glyphicons-halflings-white.png
index a20760bf..a20760bf 100644
--- a/askbot/skins/default/media/bootstrap/img/glyphicons-halflings-white.png
+++ b/askbot/media/bootstrap/img/glyphicons-halflings-white.png
Binary files differ
diff --git a/askbot/skins/default/media/bootstrap/img/glyphicons-halflings.png b/askbot/media/bootstrap/img/glyphicons-halflings.png
index 92d4445d..92d4445d 100644
--- a/askbot/skins/default/media/bootstrap/img/glyphicons-halflings.png
+++ b/askbot/media/bootstrap/img/glyphicons-halflings.png
Binary files differ
diff --git a/askbot/skins/default/media/bootstrap/js/bootstrap.js b/askbot/media/bootstrap/js/bootstrap.js
index d2d9200d..d2d9200d 100644
--- a/askbot/skins/default/media/bootstrap/js/bootstrap.js
+++ b/askbot/media/bootstrap/js/bootstrap.js
diff --git a/askbot/skins/default/media/bootstrap/js/bootstrap.min.js b/askbot/media/bootstrap/js/bootstrap.min.js
index edfee401..edfee401 100644
--- a/askbot/skins/default/media/bootstrap/js/bootstrap.min.js
+++ b/askbot/media/bootstrap/js/bootstrap.min.js
diff --git a/askbot/skins/default/media/images/OFL.txt b/askbot/media/images/OFL.txt
index 3bc11311..3bc11311 100644
--- a/askbot/skins/default/media/images/OFL.txt
+++ b/askbot/media/images/OFL.txt
diff --git a/askbot/media/images/OpenSans-CondBold.ttf b/askbot/media/images/OpenSans-CondBold.ttf
new file mode 100644
index 00000000..83966f21
--- /dev/null
+++ b/askbot/media/images/OpenSans-CondBold.ttf
Binary files differ
diff --git a/askbot/media/images/OpenSans-CondLight.ttf b/askbot/media/images/OpenSans-CondLight.ttf
new file mode 100644
index 00000000..97c355b9
--- /dev/null
+++ b/askbot/media/images/OpenSans-CondLight.ttf
Binary files differ
diff --git a/askbot/media/images/OpenSans-CondLightItalic.ttf b/askbot/media/images/OpenSans-CondLightItalic.ttf
new file mode 100644
index 00000000..0b45898d
--- /dev/null
+++ b/askbot/media/images/OpenSans-CondLightItalic.ttf
Binary files differ
diff --git a/askbot/skins/default/media/images/YanoneKaffeesatz-Bold.ttf b/askbot/media/images/YanoneKaffeesatz-Bold.ttf
index c693c4b3..c693c4b3 100644
--- a/askbot/skins/default/media/images/YanoneKaffeesatz-Bold.ttf
+++ b/askbot/media/images/YanoneKaffeesatz-Bold.ttf
Binary files differ
diff --git a/askbot/skins/default/media/images/YanoneKaffeesatz-ExtraLight.ttf b/askbot/media/images/YanoneKaffeesatz-ExtraLight.ttf
index b59e4894..b59e4894 100644
--- a/askbot/skins/default/media/images/YanoneKaffeesatz-ExtraLight.ttf
+++ b/askbot/media/images/YanoneKaffeesatz-ExtraLight.ttf
Binary files differ
diff --git a/askbot/skins/default/media/images/YanoneKaffeesatz-Light.ttf b/askbot/media/images/YanoneKaffeesatz-Light.ttf
index 5026d3bd..5026d3bd 100644
--- a/askbot/skins/default/media/images/YanoneKaffeesatz-Light.ttf
+++ b/askbot/media/images/YanoneKaffeesatz-Light.ttf
Binary files differ
diff --git a/askbot/skins/default/media/images/YanoneKaffeesatz-Regular.ttf b/askbot/media/images/YanoneKaffeesatz-Regular.ttf
index 808ce0d0..808ce0d0 100644
--- a/askbot/skins/default/media/images/YanoneKaffeesatz-Regular.ttf
+++ b/askbot/media/images/YanoneKaffeesatz-Regular.ttf
Binary files differ
diff --git a/askbot/skins/default/media/images/Yanone_Kaffeesatz.zip b/askbot/media/images/Yanone_Kaffeesatz.zip
index 55e9731a..55e9731a 100644
--- a/askbot/skins/default/media/images/Yanone_Kaffeesatz.zip
+++ b/askbot/media/images/Yanone_Kaffeesatz.zip
Binary files differ
diff --git a/askbot/skins/default/media/images/accept.png b/askbot/media/images/accept.png
index 16262c7a..16262c7a 100644
--- a/askbot/skins/default/media/images/accept.png
+++ b/askbot/media/images/accept.png
Binary files differ
diff --git a/askbot/skins/common/media/images/anon.png b/askbot/media/images/anon.png
index a2041590..a2041590 100644
--- a/askbot/skins/common/media/images/anon.png
+++ b/askbot/media/images/anon.png
Binary files differ
diff --git a/askbot/skins/default/media/images/answers-background.png b/askbot/media/images/answers-background.png
index 0e9b4788..0e9b4788 100644
--- a/askbot/skins/default/media/images/answers-background.png
+++ b/askbot/media/images/answers-background.png
Binary files differ
diff --git a/askbot/media/images/attachment.png b/askbot/media/images/attachment.png
new file mode 100644
index 00000000..1cb253dc
--- /dev/null
+++ b/askbot/media/images/attachment.png
Binary files differ
diff --git a/askbot/skins/default/media/images/background-user-info.png b/askbot/media/images/background-user-info.png
index b681cb37..b681cb37 100644
--- a/askbot/skins/default/media/images/background-user-info.png
+++ b/askbot/media/images/background-user-info.png
Binary files differ
diff --git a/askbot/skins/common/media/images/bigbutton.png b/askbot/media/images/bigbutton.png
index 2a7c0f05..2a7c0f05 100644
--- a/askbot/skins/common/media/images/bigbutton.png
+++ b/askbot/media/images/bigbutton.png
Binary files differ
diff --git a/askbot/skins/common/media/images/bigbuttonhover.png b/askbot/media/images/bigbuttonhover.png
index cf4bacca..cf4bacca 100644
--- a/askbot/skins/common/media/images/bigbuttonhover.png
+++ b/askbot/media/images/bigbuttonhover.png
Binary files differ
diff --git a/askbot/skins/common/media/images/blue-up-arrow-h18px.png b/askbot/media/images/blue-up-arrow-h18px.png
index e1f29e86..e1f29e86 100755
--- a/askbot/skins/common/media/images/blue-up-arrow-h18px.png
+++ b/askbot/media/images/blue-up-arrow-h18px.png
Binary files differ
diff --git a/askbot/skins/common/media/images/box-arrow.gif b/askbot/media/images/box-arrow.gif
index 89dcf5b3..89dcf5b3 100755
--- a/askbot/skins/common/media/images/box-arrow.gif
+++ b/askbot/media/images/box-arrow.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/bullet_green.gif b/askbot/media/images/bullet_green.gif
index fa530910..fa530910 100755
--- a/askbot/skins/common/media/images/bullet_green.gif
+++ b/askbot/media/images/bullet_green.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/cc-88x31.png b/askbot/media/images/cc-88x31.png
index 0f2a0f10..0f2a0f10 100755
--- a/askbot/skins/common/media/images/cc-88x31.png
+++ b/askbot/media/images/cc-88x31.png
Binary files differ
diff --git a/askbot/skins/common/media/images/cc-by-sa.png b/askbot/media/images/cc-by-sa.png
index f0a944e0..f0a944e0 100644
--- a/askbot/skins/common/media/images/cc-by-sa.png
+++ b/askbot/media/images/cc-by-sa.png
Binary files differ
diff --git a/askbot/skins/default/media/images/close-small-dark.png b/askbot/media/images/close-small-dark.png
index 72ada35b..72ada35b 100644
--- a/askbot/skins/default/media/images/close-small-dark.png
+++ b/askbot/media/images/close-small-dark.png
Binary files differ
diff --git a/askbot/skins/common/media/images/close-small-hover.png b/askbot/media/images/close-small-hover.png
index 7899aec7..7899aec7 100755
--- a/askbot/skins/common/media/images/close-small-hover.png
+++ b/askbot/media/images/close-small-hover.png
Binary files differ
diff --git a/askbot/skins/common/media/images/close-small.png b/askbot/media/images/close-small.png
index 5a99d31f..5a99d31f 100755
--- a/askbot/skins/common/media/images/close-small.png
+++ b/askbot/media/images/close-small.png
Binary files differ
diff --git a/askbot/skins/default/media/images/close.png b/askbot/media/images/close.png
index cfe209ff..cfe209ff 100644
--- a/askbot/skins/default/media/images/close.png
+++ b/askbot/media/images/close.png
Binary files differ
diff --git a/askbot/skins/default/media/images/comment-background.png b/askbot/media/images/comment-background.png
index 4299b847..4299b847 100644
--- a/askbot/skins/default/media/images/comment-background.png
+++ b/askbot/media/images/comment-background.png
Binary files differ
diff --git a/askbot/skins/default/media/images/comment.png b/askbot/media/images/comment.png
index 9dcc4c66..9dcc4c66 100644
--- a/askbot/skins/default/media/images/comment.png
+++ b/askbot/media/images/comment.png
Binary files differ
diff --git a/askbot/skins/common/media/images/contributorsback.png b/askbot/media/images/contributorsback.png
index dd728383..dd728383 100644
--- a/askbot/skins/common/media/images/contributorsback.png
+++ b/askbot/media/images/contributorsback.png
Binary files differ
diff --git a/askbot/skins/common/media/images/dash.gif b/askbot/media/images/dash.gif
index d1ddc507..d1ddc507 100755
--- a/askbot/skins/common/media/images/dash.gif
+++ b/askbot/media/images/dash.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/delete.png b/askbot/media/images/delete.png
index 9263eae3..9263eae3 100644
--- a/askbot/skins/default/media/images/delete.png
+++ b/askbot/media/images/delete.png
Binary files differ
diff --git a/askbot/skins/common/media/images/dialog-warning-off.png b/askbot/media/images/dialog-warning-off.png
index 258e4d86..258e4d86 100644
--- a/askbot/skins/common/media/images/dialog-warning-off.png
+++ b/askbot/media/images/dialog-warning-off.png
Binary files differ
diff --git a/askbot/skins/common/media/images/dialog-warning.png b/askbot/media/images/dialog-warning.png
index a9e4ff39..a9e4ff39 100644
--- a/askbot/skins/common/media/images/dialog-warning.png
+++ b/askbot/media/images/dialog-warning.png
Binary files differ
diff --git a/askbot/skins/common/media/images/djangomade124x25_grey.gif b/askbot/media/images/djangomade124x25_grey.gif
index d34bb311..d34bb311 100755
--- a/askbot/skins/common/media/images/djangomade124x25_grey.gif
+++ b/askbot/media/images/djangomade124x25_grey.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/dot-g.gif b/askbot/media/images/dot-g.gif
index 5d6bb28e..5d6bb28e 100755
--- a/askbot/skins/common/media/images/dot-g.gif
+++ b/askbot/media/images/dot-g.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/dot-list.gif b/askbot/media/images/dot-list.gif
index f6a6b865..f6a6b865 100755
--- a/askbot/skins/common/media/images/dot-list.gif
+++ b/askbot/media/images/dot-list.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/edit.png b/askbot/media/images/edit.png
index dcb09be0..dcb09be0 100755
--- a/askbot/skins/common/media/images/edit.png
+++ b/askbot/media/images/edit.png
Binary files differ
diff --git a/askbot/skins/default/media/images/edit2.png b/askbot/media/images/edit2.png
index f142a68c..f142a68c 100644
--- a/askbot/skins/default/media/images/edit2.png
+++ b/askbot/media/images/edit2.png
Binary files differ
diff --git a/askbot/skins/common/media/images/expander-arrow-hide.gif b/askbot/media/images/expander-arrow-hide.gif
index feb6a618..feb6a618 100755
--- a/askbot/skins/common/media/images/expander-arrow-hide.gif
+++ b/askbot/media/images/expander-arrow-hide.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/expander-arrow-show.gif b/askbot/media/images/expander-arrow-show.gif
index 6825c56e..6825c56e 100755
--- a/askbot/skins/common/media/images/expander-arrow-show.gif
+++ b/askbot/media/images/expander-arrow-show.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/favicon.gif b/askbot/media/images/favicon.gif
index f7f9061b..f7f9061b 100644
--- a/askbot/skins/common/media/images/favicon.gif
+++ b/askbot/media/images/favicon.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/favicon.ico b/askbot/media/images/favicon.ico
index 51a57bed..51a57bed 100644
--- a/askbot/skins/common/media/images/favicon.ico
+++ b/askbot/media/images/favicon.ico
Binary files differ
diff --git a/askbot/skins/common/media/images/feed-icon-small.png b/askbot/media/images/feed-icon-small.png
index 2794b0f5..2794b0f5 100644
--- a/askbot/skins/common/media/images/feed-icon-small.png
+++ b/askbot/media/images/feed-icon-small.png
Binary files differ
diff --git a/askbot/skins/default/media/images/flag.png b/askbot/media/images/flag.png
index fc302335..fc302335 100644
--- a/askbot/skins/default/media/images/flag.png
+++ b/askbot/media/images/flag.png
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ad.gif b/askbot/media/images/flags/ad.gif
index 57b49973..57b49973 100755
--- a/askbot/skins/common/media/images/flags/ad.gif
+++ b/askbot/media/images/flags/ad.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ae.gif b/askbot/media/images/flags/ae.gif
index 78d15b67..78d15b67 100755
--- a/askbot/skins/common/media/images/flags/ae.gif
+++ b/askbot/media/images/flags/ae.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/af.gif b/askbot/media/images/flags/af.gif
index 98894082..98894082 100755
--- a/askbot/skins/common/media/images/flags/af.gif
+++ b/askbot/media/images/flags/af.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ag.gif b/askbot/media/images/flags/ag.gif
index 48f8e7bc..48f8e7bc 100755
--- a/askbot/skins/common/media/images/flags/ag.gif
+++ b/askbot/media/images/flags/ag.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ai.gif b/askbot/media/images/flags/ai.gif
index 1cbc5795..1cbc5795 100755
--- a/askbot/skins/common/media/images/flags/ai.gif
+++ b/askbot/media/images/flags/ai.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/al.gif b/askbot/media/images/flags/al.gif
index c44fe0a0..c44fe0a0 100755
--- a/askbot/skins/common/media/images/flags/al.gif
+++ b/askbot/media/images/flags/al.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/am.gif b/askbot/media/images/flags/am.gif
index 2915e30c..2915e30c 100755
--- a/askbot/skins/common/media/images/flags/am.gif
+++ b/askbot/media/images/flags/am.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/an.gif b/askbot/media/images/flags/an.gif
index cb570c67..cb570c67 100755
--- a/askbot/skins/common/media/images/flags/an.gif
+++ b/askbot/media/images/flags/an.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ao.gif b/askbot/media/images/flags/ao.gif
index 8c854fa1..8c854fa1 100644
--- a/askbot/skins/common/media/images/flags/ao.gif
+++ b/askbot/media/images/flags/ao.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ar.gif b/askbot/media/images/flags/ar.gif
index a9f71f7d..a9f71f7d 100755
--- a/askbot/skins/common/media/images/flags/ar.gif
+++ b/askbot/media/images/flags/ar.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/as.gif b/askbot/media/images/flags/as.gif
index d776ec27..d776ec27 100755
--- a/askbot/skins/common/media/images/flags/as.gif
+++ b/askbot/media/images/flags/as.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/at.gif b/askbot/media/images/flags/at.gif
index 87e12173..87e12173 100755
--- a/askbot/skins/common/media/images/flags/at.gif
+++ b/askbot/media/images/flags/at.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/au.gif b/askbot/media/images/flags/au.gif
index 5269c6a0..5269c6a0 100755
--- a/askbot/skins/common/media/images/flags/au.gif
+++ b/askbot/media/images/flags/au.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/aw.gif b/askbot/media/images/flags/aw.gif
index 27fdb4d1..27fdb4d1 100755
--- a/askbot/skins/common/media/images/flags/aw.gif
+++ b/askbot/media/images/flags/aw.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ax.gif b/askbot/media/images/flags/ax.gif
index 0ceb6849..0ceb6849 100755
--- a/askbot/skins/common/media/images/flags/ax.gif
+++ b/askbot/media/images/flags/ax.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/az.gif b/askbot/media/images/flags/az.gif
index d7716184..d7716184 100755
--- a/askbot/skins/common/media/images/flags/az.gif
+++ b/askbot/media/images/flags/az.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ba.gif b/askbot/media/images/flags/ba.gif
index 9bf5f0ac..9bf5f0ac 100755
--- a/askbot/skins/common/media/images/flags/ba.gif
+++ b/askbot/media/images/flags/ba.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/bb.gif b/askbot/media/images/flags/bb.gif
index b7d08e57..b7d08e57 100755
--- a/askbot/skins/common/media/images/flags/bb.gif
+++ b/askbot/media/images/flags/bb.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/bd.gif b/askbot/media/images/flags/bd.gif
index 0fd27eca..0fd27eca 100755
--- a/askbot/skins/common/media/images/flags/bd.gif
+++ b/askbot/media/images/flags/bd.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/be.gif b/askbot/media/images/flags/be.gif
index ae09bfbe..ae09bfbe 100755
--- a/askbot/skins/common/media/images/flags/be.gif
+++ b/askbot/media/images/flags/be.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/bf.gif b/askbot/media/images/flags/bf.gif
index 9d6772cd..9d6772cd 100755
--- a/askbot/skins/common/media/images/flags/bf.gif
+++ b/askbot/media/images/flags/bf.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/bg.gif b/askbot/media/images/flags/bg.gif
index 11cf8ff3..11cf8ff3 100755
--- a/askbot/skins/common/media/images/flags/bg.gif
+++ b/askbot/media/images/flags/bg.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/bh.gif b/askbot/media/images/flags/bh.gif
index 56aa72b2..56aa72b2 100755
--- a/askbot/skins/common/media/images/flags/bh.gif
+++ b/askbot/media/images/flags/bh.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/bi.gif b/askbot/media/images/flags/bi.gif
index 6e2cbe12..6e2cbe12 100755
--- a/askbot/skins/common/media/images/flags/bi.gif
+++ b/askbot/media/images/flags/bi.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/bj.gif b/askbot/media/images/flags/bj.gif
index e676116f..e676116f 100755
--- a/askbot/skins/common/media/images/flags/bj.gif
+++ b/askbot/media/images/flags/bj.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/bm.gif b/askbot/media/images/flags/bm.gif
index 9feb87bc..9feb87bc 100755
--- a/askbot/skins/common/media/images/flags/bm.gif
+++ b/askbot/media/images/flags/bm.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/bn.gif b/askbot/media/images/flags/bn.gif
index b7b6b0f9..b7b6b0f9 100755
--- a/askbot/skins/common/media/images/flags/bn.gif
+++ b/askbot/media/images/flags/bn.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/bo.gif b/askbot/media/images/flags/bo.gif
index 4844f856..4844f856 100755
--- a/askbot/skins/common/media/images/flags/bo.gif
+++ b/askbot/media/images/flags/bo.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/br.gif b/askbot/media/images/flags/br.gif
index 8c866162..8c866162 100755
--- a/askbot/skins/common/media/images/flags/br.gif
+++ b/askbot/media/images/flags/br.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/bs.gif b/askbot/media/images/flags/bs.gif
index c0a741e5..c0a741e5 100755
--- a/askbot/skins/common/media/images/flags/bs.gif
+++ b/askbot/media/images/flags/bs.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/bt.gif b/askbot/media/images/flags/bt.gif
index abe2f3cc..abe2f3cc 100755
--- a/askbot/skins/common/media/images/flags/bt.gif
+++ b/askbot/media/images/flags/bt.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/bv.gif b/askbot/media/images/flags/bv.gif
index 6202d1f3..6202d1f3 100755
--- a/askbot/skins/common/media/images/flags/bv.gif
+++ b/askbot/media/images/flags/bv.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/bw.gif b/askbot/media/images/flags/bw.gif
index 986ab63c..986ab63c 100755
--- a/askbot/skins/common/media/images/flags/bw.gif
+++ b/askbot/media/images/flags/bw.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/by.gif b/askbot/media/images/flags/by.gif
index 43ffcd4c..43ffcd4c 100755
--- a/askbot/skins/common/media/images/flags/by.gif
+++ b/askbot/media/images/flags/by.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/bz.gif b/askbot/media/images/flags/bz.gif
index 791737f0..791737f0 100755
--- a/askbot/skins/common/media/images/flags/bz.gif
+++ b/askbot/media/images/flags/bz.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ca.gif b/askbot/media/images/flags/ca.gif
index 457d9662..457d9662 100755
--- a/askbot/skins/common/media/images/flags/ca.gif
+++ b/askbot/media/images/flags/ca.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/catalonia.gif b/askbot/media/images/flags/catalonia.gif
index 73df9a04..73df9a04 100644
--- a/askbot/skins/common/media/images/flags/catalonia.gif
+++ b/askbot/media/images/flags/catalonia.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/cc.gif b/askbot/media/images/flags/cc.gif
index 3f783270..3f783270 100755
--- a/askbot/skins/common/media/images/flags/cc.gif
+++ b/askbot/media/images/flags/cc.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/cd.gif b/askbot/media/images/flags/cd.gif
index 1df717ae..1df717ae 100644
--- a/askbot/skins/common/media/images/flags/cd.gif
+++ b/askbot/media/images/flags/cd.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/cf.gif b/askbot/media/images/flags/cf.gif
index 35787ca4..35787ca4 100755
--- a/askbot/skins/common/media/images/flags/cf.gif
+++ b/askbot/media/images/flags/cf.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/cg.gif b/askbot/media/images/flags/cg.gif
index e0a62a51..e0a62a51 100755
--- a/askbot/skins/common/media/images/flags/cg.gif
+++ b/askbot/media/images/flags/cg.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ch.gif b/askbot/media/images/flags/ch.gif
index d5c0e5b7..d5c0e5b7 100755
--- a/askbot/skins/common/media/images/flags/ch.gif
+++ b/askbot/media/images/flags/ch.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ci.gif b/askbot/media/images/flags/ci.gif
index 844120a5..844120a5 100755
--- a/askbot/skins/common/media/images/flags/ci.gif
+++ b/askbot/media/images/flags/ci.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ck.gif b/askbot/media/images/flags/ck.gif
index 2edb7399..2edb7399 100755
--- a/askbot/skins/common/media/images/flags/ck.gif
+++ b/askbot/media/images/flags/ck.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/cl.gif b/askbot/media/images/flags/cl.gif
index cbc370e6..cbc370e6 100755
--- a/askbot/skins/common/media/images/flags/cl.gif
+++ b/askbot/media/images/flags/cl.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/cm.gif b/askbot/media/images/flags/cm.gif
index 1fb102b2..1fb102b2 100755
--- a/askbot/skins/common/media/images/flags/cm.gif
+++ b/askbot/media/images/flags/cm.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/cn.gif b/askbot/media/images/flags/cn.gif
index b0525309..b0525309 100755
--- a/askbot/skins/common/media/images/flags/cn.gif
+++ b/askbot/media/images/flags/cn.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/co.gif b/askbot/media/images/flags/co.gif
index d0e15caf..d0e15caf 100755
--- a/askbot/skins/common/media/images/flags/co.gif
+++ b/askbot/media/images/flags/co.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/cr.gif b/askbot/media/images/flags/cr.gif
index 0728dd6a..0728dd6a 100755
--- a/askbot/skins/common/media/images/flags/cr.gif
+++ b/askbot/media/images/flags/cr.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/cs.gif b/askbot/media/images/flags/cs.gif
index 101db649..101db649 100755
--- a/askbot/skins/common/media/images/flags/cs.gif
+++ b/askbot/media/images/flags/cs.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/cu.gif b/askbot/media/images/flags/cu.gif
index 291255ca..291255ca 100755
--- a/askbot/skins/common/media/images/flags/cu.gif
+++ b/askbot/media/images/flags/cu.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/cv.gif b/askbot/media/images/flags/cv.gif
index 43c6c6cb..43c6c6cb 100755
--- a/askbot/skins/common/media/images/flags/cv.gif
+++ b/askbot/media/images/flags/cv.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/cx.gif b/askbot/media/images/flags/cx.gif
index a5b43089..a5b43089 100755
--- a/askbot/skins/common/media/images/flags/cx.gif
+++ b/askbot/media/images/flags/cx.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/cy.gif b/askbot/media/images/flags/cy.gif
index 35c661e1..35c661e1 100755
--- a/askbot/skins/common/media/images/flags/cy.gif
+++ b/askbot/media/images/flags/cy.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/cz.gif b/askbot/media/images/flags/cz.gif
index 0a605e58..0a605e58 100755
--- a/askbot/skins/common/media/images/flags/cz.gif
+++ b/askbot/media/images/flags/cz.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/de.gif b/askbot/media/images/flags/de.gif
index 75728ddf..75728ddf 100755
--- a/askbot/skins/common/media/images/flags/de.gif
+++ b/askbot/media/images/flags/de.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/dj.gif b/askbot/media/images/flags/dj.gif
index 212406d9..212406d9 100755
--- a/askbot/skins/common/media/images/flags/dj.gif
+++ b/askbot/media/images/flags/dj.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/dk.gif b/askbot/media/images/flags/dk.gif
index 03e75bd2..03e75bd2 100755
--- a/askbot/skins/common/media/images/flags/dk.gif
+++ b/askbot/media/images/flags/dk.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/dm.gif b/askbot/media/images/flags/dm.gif
index 2f87f3ca..2f87f3ca 100755
--- a/askbot/skins/common/media/images/flags/dm.gif
+++ b/askbot/media/images/flags/dm.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/do.gif b/askbot/media/images/flags/do.gif
index f7d0bad3..f7d0bad3 100755
--- a/askbot/skins/common/media/images/flags/do.gif
+++ b/askbot/media/images/flags/do.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/dz.gif b/askbot/media/images/flags/dz.gif
index ed580a7c..ed580a7c 100755
--- a/askbot/skins/common/media/images/flags/dz.gif
+++ b/askbot/media/images/flags/dz.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ec.gif b/askbot/media/images/flags/ec.gif
index 9e41e0ec..9e41e0ec 100755
--- a/askbot/skins/common/media/images/flags/ec.gif
+++ b/askbot/media/images/flags/ec.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ee.gif b/askbot/media/images/flags/ee.gif
index 9397a2d0..9397a2d0 100755
--- a/askbot/skins/common/media/images/flags/ee.gif
+++ b/askbot/media/images/flags/ee.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/eg.gif b/askbot/media/images/flags/eg.gif
index 6857c7dd..6857c7dd 100755
--- a/askbot/skins/common/media/images/flags/eg.gif
+++ b/askbot/media/images/flags/eg.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/eh.gif b/askbot/media/images/flags/eh.gif
index dd0391c2..dd0391c2 100755
--- a/askbot/skins/common/media/images/flags/eh.gif
+++ b/askbot/media/images/flags/eh.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/england.gif b/askbot/media/images/flags/england.gif
index 933a4f0b..933a4f0b 100755
--- a/askbot/skins/common/media/images/flags/england.gif
+++ b/askbot/media/images/flags/england.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/er.gif b/askbot/media/images/flags/er.gif
index 3d4d612c..3d4d612c 100755
--- a/askbot/skins/common/media/images/flags/er.gif
+++ b/askbot/media/images/flags/er.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/es.gif b/askbot/media/images/flags/es.gif
index c27d65e5..c27d65e5 100755
--- a/askbot/skins/common/media/images/flags/es.gif
+++ b/askbot/media/images/flags/es.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/et.gif b/askbot/media/images/flags/et.gif
index f77995d0..f77995d0 100755
--- a/askbot/skins/common/media/images/flags/et.gif
+++ b/askbot/media/images/flags/et.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/europeanunion.gif b/askbot/media/images/flags/europeanunion.gif
index 28a762a5..28a762a5 100644
--- a/askbot/skins/common/media/images/flags/europeanunion.gif
+++ b/askbot/media/images/flags/europeanunion.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/fam.gif b/askbot/media/images/flags/fam.gif
index 7d528852..7d528852 100755
--- a/askbot/skins/common/media/images/flags/fam.gif
+++ b/askbot/media/images/flags/fam.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/fi.gif b/askbot/media/images/flags/fi.gif
index 8d3a1918..8d3a1918 100755
--- a/askbot/skins/common/media/images/flags/fi.gif
+++ b/askbot/media/images/flags/fi.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/fj.gif b/askbot/media/images/flags/fj.gif
index 486151cb..486151cb 100755
--- a/askbot/skins/common/media/images/flags/fj.gif
+++ b/askbot/media/images/flags/fj.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/fk.gif b/askbot/media/images/flags/fk.gif
index 37b5ecf3..37b5ecf3 100755
--- a/askbot/skins/common/media/images/flags/fk.gif
+++ b/askbot/media/images/flags/fk.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/fm.gif b/askbot/media/images/flags/fm.gif
index 7f8723b7..7f8723b7 100755
--- a/askbot/skins/common/media/images/flags/fm.gif
+++ b/askbot/media/images/flags/fm.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/fo.gif b/askbot/media/images/flags/fo.gif
index 4a90fc04..4a90fc04 100755
--- a/askbot/skins/common/media/images/flags/fo.gif
+++ b/askbot/media/images/flags/fo.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/fr.gif b/askbot/media/images/flags/fr.gif
index 43d0b801..43d0b801 100755
--- a/askbot/skins/common/media/images/flags/fr.gif
+++ b/askbot/media/images/flags/fr.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ga.gif b/askbot/media/images/flags/ga.gif
index 23fd5f0d..23fd5f0d 100755
--- a/askbot/skins/common/media/images/flags/ga.gif
+++ b/askbot/media/images/flags/ga.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/gb.gif b/askbot/media/images/flags/gb.gif
index 3c6bce15..3c6bce15 100644
--- a/askbot/skins/common/media/images/flags/gb.gif
+++ b/askbot/media/images/flags/gb.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/gd.gif b/askbot/media/images/flags/gd.gif
index 25ea3123..25ea3123 100755
--- a/askbot/skins/common/media/images/flags/gd.gif
+++ b/askbot/media/images/flags/gd.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ge.gif b/askbot/media/images/flags/ge.gif
index faa7f126..faa7f126 100755
--- a/askbot/skins/common/media/images/flags/ge.gif
+++ b/askbot/media/images/flags/ge.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/gf.gif b/askbot/media/images/flags/gf.gif
index 43d0b801..43d0b801 100755
--- a/askbot/skins/common/media/images/flags/gf.gif
+++ b/askbot/media/images/flags/gf.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/gh.gif b/askbot/media/images/flags/gh.gif
index 273fb7d1..273fb7d1 100755
--- a/askbot/skins/common/media/images/flags/gh.gif
+++ b/askbot/media/images/flags/gh.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/gi.gif b/askbot/media/images/flags/gi.gif
index 7b1984bc..7b1984bc 100755
--- a/askbot/skins/common/media/images/flags/gi.gif
+++ b/askbot/media/images/flags/gi.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/gl.gif b/askbot/media/images/flags/gl.gif
index ef445be0..ef445be0 100755
--- a/askbot/skins/common/media/images/flags/gl.gif
+++ b/askbot/media/images/flags/gl.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/gm.gif b/askbot/media/images/flags/gm.gif
index 6847c5a8..6847c5a8 100755
--- a/askbot/skins/common/media/images/flags/gm.gif
+++ b/askbot/media/images/flags/gm.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/gn.gif b/askbot/media/images/flags/gn.gif
index a982ac6f..a982ac6f 100755
--- a/askbot/skins/common/media/images/flags/gn.gif
+++ b/askbot/media/images/flags/gn.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/gp.gif b/askbot/media/images/flags/gp.gif
index 31166db6..31166db6 100755
--- a/askbot/skins/common/media/images/flags/gp.gif
+++ b/askbot/media/images/flags/gp.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/gq.gif b/askbot/media/images/flags/gq.gif
index 8b4e0cc4..8b4e0cc4 100755
--- a/askbot/skins/common/media/images/flags/gq.gif
+++ b/askbot/media/images/flags/gq.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/gr.gif b/askbot/media/images/flags/gr.gif
index b4c8c04e..b4c8c04e 100755
--- a/askbot/skins/common/media/images/flags/gr.gif
+++ b/askbot/media/images/flags/gr.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/gs.gif b/askbot/media/images/flags/gs.gif
index ccc96ec0..ccc96ec0 100755
--- a/askbot/skins/common/media/images/flags/gs.gif
+++ b/askbot/media/images/flags/gs.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/gt.gif b/askbot/media/images/flags/gt.gif
index 7e94d1dd..7e94d1dd 100755
--- a/askbot/skins/common/media/images/flags/gt.gif
+++ b/askbot/media/images/flags/gt.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/gu.gif b/askbot/media/images/flags/gu.gif
index eafef683..eafef683 100755
--- a/askbot/skins/common/media/images/flags/gu.gif
+++ b/askbot/media/images/flags/gu.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/gw.gif b/askbot/media/images/flags/gw.gif
index 55f75711..55f75711 100755
--- a/askbot/skins/common/media/images/flags/gw.gif
+++ b/askbot/media/images/flags/gw.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/gy.gif b/askbot/media/images/flags/gy.gif
index 1cb4cd71..1cb4cd71 100755
--- a/askbot/skins/common/media/images/flags/gy.gif
+++ b/askbot/media/images/flags/gy.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/hk.gif b/askbot/media/images/flags/hk.gif
index 798af96d..798af96d 100755
--- a/askbot/skins/common/media/images/flags/hk.gif
+++ b/askbot/media/images/flags/hk.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/hm.gif b/askbot/media/images/flags/hm.gif
index 5269c6a0..5269c6a0 100755
--- a/askbot/skins/common/media/images/flags/hm.gif
+++ b/askbot/media/images/flags/hm.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/hn.gif b/askbot/media/images/flags/hn.gif
index 6c4ffe8e..6c4ffe8e 100755
--- a/askbot/skins/common/media/images/flags/hn.gif
+++ b/askbot/media/images/flags/hn.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/hr.gif b/askbot/media/images/flags/hr.gif
index 557c6602..557c6602 100755
--- a/askbot/skins/common/media/images/flags/hr.gif
+++ b/askbot/media/images/flags/hr.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ht.gif b/askbot/media/images/flags/ht.gif
index 059604ab..059604ab 100755
--- a/askbot/skins/common/media/images/flags/ht.gif
+++ b/askbot/media/images/flags/ht.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/hu.gif b/askbot/media/images/flags/hu.gif
index 6142d868..6142d868 100755
--- a/askbot/skins/common/media/images/flags/hu.gif
+++ b/askbot/media/images/flags/hu.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/id.gif b/askbot/media/images/flags/id.gif
index 865161b0..865161b0 100755
--- a/askbot/skins/common/media/images/flags/id.gif
+++ b/askbot/media/images/flags/id.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ie.gif b/askbot/media/images/flags/ie.gif
index 506ad285..506ad285 100755
--- a/askbot/skins/common/media/images/flags/ie.gif
+++ b/askbot/media/images/flags/ie.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/il.gif b/askbot/media/images/flags/il.gif
index c8483ae5..c8483ae5 100755
--- a/askbot/skins/common/media/images/flags/il.gif
+++ b/askbot/media/images/flags/il.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/in.gif b/askbot/media/images/flags/in.gif
index 1cd80272..1cd80272 100755
--- a/askbot/skins/common/media/images/flags/in.gif
+++ b/askbot/media/images/flags/in.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/io.gif b/askbot/media/images/flags/io.gif
index de7e7ab3..de7e7ab3 100755
--- a/askbot/skins/common/media/images/flags/io.gif
+++ b/askbot/media/images/flags/io.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/iq.gif b/askbot/media/images/flags/iq.gif
index c34fe3c4..c34fe3c4 100755
--- a/askbot/skins/common/media/images/flags/iq.gif
+++ b/askbot/media/images/flags/iq.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ir.gif b/askbot/media/images/flags/ir.gif
index 156040fc..156040fc 100755
--- a/askbot/skins/common/media/images/flags/ir.gif
+++ b/askbot/media/images/flags/ir.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/is.gif b/askbot/media/images/flags/is.gif
index b42502de..b42502de 100755
--- a/askbot/skins/common/media/images/flags/is.gif
+++ b/askbot/media/images/flags/is.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/it.gif b/askbot/media/images/flags/it.gif
index d79e90e9..d79e90e9 100755
--- a/askbot/skins/common/media/images/flags/it.gif
+++ b/askbot/media/images/flags/it.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/jm.gif b/askbot/media/images/flags/jm.gif
index 0bed67c2..0bed67c2 100755
--- a/askbot/skins/common/media/images/flags/jm.gif
+++ b/askbot/media/images/flags/jm.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/jo.gif b/askbot/media/images/flags/jo.gif
index 03daf8af..03daf8af 100755
--- a/askbot/skins/common/media/images/flags/jo.gif
+++ b/askbot/media/images/flags/jo.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/jp.gif b/askbot/media/images/flags/jp.gif
index 444c1d05..444c1d05 100755
--- a/askbot/skins/common/media/images/flags/jp.gif
+++ b/askbot/media/images/flags/jp.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ke.gif b/askbot/media/images/flags/ke.gif
index c2b5d45c..c2b5d45c 100755
--- a/askbot/skins/common/media/images/flags/ke.gif
+++ b/askbot/media/images/flags/ke.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/kg.gif b/askbot/media/images/flags/kg.gif
index 72a4d412..72a4d412 100755
--- a/askbot/skins/common/media/images/flags/kg.gif
+++ b/askbot/media/images/flags/kg.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/kh.gif b/askbot/media/images/flags/kh.gif
index 30a18315..30a18315 100755
--- a/askbot/skins/common/media/images/flags/kh.gif
+++ b/askbot/media/images/flags/kh.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ki.gif b/askbot/media/images/flags/ki.gif
index 4a0751a2..4a0751a2 100755
--- a/askbot/skins/common/media/images/flags/ki.gif
+++ b/askbot/media/images/flags/ki.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/km.gif b/askbot/media/images/flags/km.gif
index 5859595e..5859595e 100755
--- a/askbot/skins/common/media/images/flags/km.gif
+++ b/askbot/media/images/flags/km.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/kn.gif b/askbot/media/images/flags/kn.gif
index bb9cc34a..bb9cc34a 100755
--- a/askbot/skins/common/media/images/flags/kn.gif
+++ b/askbot/media/images/flags/kn.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/kp.gif b/askbot/media/images/flags/kp.gif
index 6e0ca09e..6e0ca09e 100755
--- a/askbot/skins/common/media/images/flags/kp.gif
+++ b/askbot/media/images/flags/kp.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/kr.gif b/askbot/media/images/flags/kr.gif
index 1cddbe75..1cddbe75 100755
--- a/askbot/skins/common/media/images/flags/kr.gif
+++ b/askbot/media/images/flags/kr.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/kw.gif b/askbot/media/images/flags/kw.gif
index 1efc7347..1efc7347 100755
--- a/askbot/skins/common/media/images/flags/kw.gif
+++ b/askbot/media/images/flags/kw.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ky.gif b/askbot/media/images/flags/ky.gif
index d3d02ee4..d3d02ee4 100755
--- a/askbot/skins/common/media/images/flags/ky.gif
+++ b/askbot/media/images/flags/ky.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/kz.gif b/askbot/media/images/flags/kz.gif
index 24baebe0..24baebe0 100755
--- a/askbot/skins/common/media/images/flags/kz.gif
+++ b/askbot/media/images/flags/kz.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/la.gif b/askbot/media/images/flags/la.gif
index d14cf4d8..d14cf4d8 100755
--- a/askbot/skins/common/media/images/flags/la.gif
+++ b/askbot/media/images/flags/la.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/lb.gif b/askbot/media/images/flags/lb.gif
index 003d83af..003d83af 100755
--- a/askbot/skins/common/media/images/flags/lb.gif
+++ b/askbot/media/images/flags/lb.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/lc.gif b/askbot/media/images/flags/lc.gif
index f5fe5bff..f5fe5bff 100644
--- a/askbot/skins/common/media/images/flags/lc.gif
+++ b/askbot/media/images/flags/lc.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/li.gif b/askbot/media/images/flags/li.gif
index 713c58e1..713c58e1 100755
--- a/askbot/skins/common/media/images/flags/li.gif
+++ b/askbot/media/images/flags/li.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/lk.gif b/askbot/media/images/flags/lk.gif
index 1b3ee7f5..1b3ee7f5 100755
--- a/askbot/skins/common/media/images/flags/lk.gif
+++ b/askbot/media/images/flags/lk.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/lr.gif b/askbot/media/images/flags/lr.gif
index 435af9e5..435af9e5 100755
--- a/askbot/skins/common/media/images/flags/lr.gif
+++ b/askbot/media/images/flags/lr.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ls.gif b/askbot/media/images/flags/ls.gif
index 427ae957..427ae957 100755
--- a/askbot/skins/common/media/images/flags/ls.gif
+++ b/askbot/media/images/flags/ls.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/lt.gif b/askbot/media/images/flags/lt.gif
index dee9c601..dee9c601 100755
--- a/askbot/skins/common/media/images/flags/lt.gif
+++ b/askbot/media/images/flags/lt.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/lu.gif b/askbot/media/images/flags/lu.gif
index 7d7293ed..7d7293ed 100755
--- a/askbot/skins/common/media/images/flags/lu.gif
+++ b/askbot/media/images/flags/lu.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/lv.gif b/askbot/media/images/flags/lv.gif
index 17e71b7e..17e71b7e 100755
--- a/askbot/skins/common/media/images/flags/lv.gif
+++ b/askbot/media/images/flags/lv.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ly.gif b/askbot/media/images/flags/ly.gif
index a654c30a..a654c30a 100755
--- a/askbot/skins/common/media/images/flags/ly.gif
+++ b/askbot/media/images/flags/ly.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ma.gif b/askbot/media/images/flags/ma.gif
index fc784119..fc784119 100755
--- a/askbot/skins/common/media/images/flags/ma.gif
+++ b/askbot/media/images/flags/ma.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/mc.gif b/askbot/media/images/flags/mc.gif
index 02a7c8e1..02a7c8e1 100755
--- a/askbot/skins/common/media/images/flags/mc.gif
+++ b/askbot/media/images/flags/mc.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/md.gif b/askbot/media/images/flags/md.gif
index e4b8a7e3..e4b8a7e3 100755
--- a/askbot/skins/common/media/images/flags/md.gif
+++ b/askbot/media/images/flags/md.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/me.gif b/askbot/media/images/flags/me.gif
index a260453c..a260453c 100644
--- a/askbot/skins/common/media/images/flags/me.gif
+++ b/askbot/media/images/flags/me.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/mg.gif b/askbot/media/images/flags/mg.gif
index a91b577d..a91b577d 100755
--- a/askbot/skins/common/media/images/flags/mg.gif
+++ b/askbot/media/images/flags/mg.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/mh.gif b/askbot/media/images/flags/mh.gif
index 92f5f485..92f5f485 100755
--- a/askbot/skins/common/media/images/flags/mh.gif
+++ b/askbot/media/images/flags/mh.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/mk.gif b/askbot/media/images/flags/mk.gif
index 7aeb8311..7aeb8311 100755
--- a/askbot/skins/common/media/images/flags/mk.gif
+++ b/askbot/media/images/flags/mk.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ml.gif b/askbot/media/images/flags/ml.gif
index 53d6f490..53d6f490 100755
--- a/askbot/skins/common/media/images/flags/ml.gif
+++ b/askbot/media/images/flags/ml.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/mm.gif b/askbot/media/images/flags/mm.gif
index 9e0a2756..9e0a2756 100755
--- a/askbot/skins/common/media/images/flags/mm.gif
+++ b/askbot/media/images/flags/mm.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/mn.gif b/askbot/media/images/flags/mn.gif
index dff8ea5a..dff8ea5a 100755
--- a/askbot/skins/common/media/images/flags/mn.gif
+++ b/askbot/media/images/flags/mn.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/mo.gif b/askbot/media/images/flags/mo.gif
index 66cf5b4f..66cf5b4f 100755
--- a/askbot/skins/common/media/images/flags/mo.gif
+++ b/askbot/media/images/flags/mo.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/mp.gif b/askbot/media/images/flags/mp.gif
index 73b7147e..73b7147e 100755
--- a/askbot/skins/common/media/images/flags/mp.gif
+++ b/askbot/media/images/flags/mp.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/mq.gif b/askbot/media/images/flags/mq.gif
index 570bc5dd..570bc5dd 100755
--- a/askbot/skins/common/media/images/flags/mq.gif
+++ b/askbot/media/images/flags/mq.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/mr.gif b/askbot/media/images/flags/mr.gif
index f52fcf09..f52fcf09 100755
--- a/askbot/skins/common/media/images/flags/mr.gif
+++ b/askbot/media/images/flags/mr.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ms.gif b/askbot/media/images/flags/ms.gif
index 5e5a67aa..5e5a67aa 100755
--- a/askbot/skins/common/media/images/flags/ms.gif
+++ b/askbot/media/images/flags/ms.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/mt.gif b/askbot/media/images/flags/mt.gif
index 45c709f2..45c709f2 100755
--- a/askbot/skins/common/media/images/flags/mt.gif
+++ b/askbot/media/images/flags/mt.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/mu.gif b/askbot/media/images/flags/mu.gif
index 081ab453..081ab453 100755
--- a/askbot/skins/common/media/images/flags/mu.gif
+++ b/askbot/media/images/flags/mu.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/mv.gif b/askbot/media/images/flags/mv.gif
index 46b63875..46b63875 100755
--- a/askbot/skins/common/media/images/flags/mv.gif
+++ b/askbot/media/images/flags/mv.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/mw.gif b/askbot/media/images/flags/mw.gif
index ad045a09..ad045a09 100755
--- a/askbot/skins/common/media/images/flags/mw.gif
+++ b/askbot/media/images/flags/mw.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/mx.gif b/askbot/media/images/flags/mx.gif
index ddc75d04..ddc75d04 100755
--- a/askbot/skins/common/media/images/flags/mx.gif
+++ b/askbot/media/images/flags/mx.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/my.gif b/askbot/media/images/flags/my.gif
index fc7d5236..fc7d5236 100755
--- a/askbot/skins/common/media/images/flags/my.gif
+++ b/askbot/media/images/flags/my.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/mz.gif b/askbot/media/images/flags/mz.gif
index 7d635082..7d635082 100755
--- a/askbot/skins/common/media/images/flags/mz.gif
+++ b/askbot/media/images/flags/mz.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/na.gif b/askbot/media/images/flags/na.gif
index c0babe72..c0babe72 100755
--- a/askbot/skins/common/media/images/flags/na.gif
+++ b/askbot/media/images/flags/na.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/nc.gif b/askbot/media/images/flags/nc.gif
index b1e91b9a..b1e91b9a 100755
--- a/askbot/skins/common/media/images/flags/nc.gif
+++ b/askbot/media/images/flags/nc.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ne.gif b/askbot/media/images/flags/ne.gif
index ff4eaf07..ff4eaf07 100755
--- a/askbot/skins/common/media/images/flags/ne.gif
+++ b/askbot/media/images/flags/ne.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/nf.gif b/askbot/media/images/flags/nf.gif
index c83424c2..c83424c2 100755
--- a/askbot/skins/common/media/images/flags/nf.gif
+++ b/askbot/media/images/flags/nf.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ng.gif b/askbot/media/images/flags/ng.gif
index bdde7cb3..bdde7cb3 100755
--- a/askbot/skins/common/media/images/flags/ng.gif
+++ b/askbot/media/images/flags/ng.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ni.gif b/askbot/media/images/flags/ni.gif
index d05894d0..d05894d0 100755
--- a/askbot/skins/common/media/images/flags/ni.gif
+++ b/askbot/media/images/flags/ni.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/nl.gif b/askbot/media/images/flags/nl.gif
index c1c8f46d..c1c8f46d 100755
--- a/askbot/skins/common/media/images/flags/nl.gif
+++ b/askbot/media/images/flags/nl.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/no.gif b/askbot/media/images/flags/no.gif
index 6202d1f3..6202d1f3 100755
--- a/askbot/skins/common/media/images/flags/no.gif
+++ b/askbot/media/images/flags/no.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/np.gif b/askbot/media/images/flags/np.gif
index 1096893a..1096893a 100755
--- a/askbot/skins/common/media/images/flags/np.gif
+++ b/askbot/media/images/flags/np.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/nr.gif b/askbot/media/images/flags/nr.gif
index 2e4c0c5c..2e4c0c5c 100755
--- a/askbot/skins/common/media/images/flags/nr.gif
+++ b/askbot/media/images/flags/nr.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/nu.gif b/askbot/media/images/flags/nu.gif
index 618210a7..618210a7 100755
--- a/askbot/skins/common/media/images/flags/nu.gif
+++ b/askbot/media/images/flags/nu.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/nz.gif b/askbot/media/images/flags/nz.gif
index 028a5dc6..028a5dc6 100755
--- a/askbot/skins/common/media/images/flags/nz.gif
+++ b/askbot/media/images/flags/nz.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/om.gif b/askbot/media/images/flags/om.gif
index 2b8c7750..2b8c7750 100755
--- a/askbot/skins/common/media/images/flags/om.gif
+++ b/askbot/media/images/flags/om.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/pa.gif b/askbot/media/images/flags/pa.gif
index d518b2f9..d518b2f9 100755
--- a/askbot/skins/common/media/images/flags/pa.gif
+++ b/askbot/media/images/flags/pa.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/pe.gif b/askbot/media/images/flags/pe.gif
index 3bc76390..3bc76390 100755
--- a/askbot/skins/common/media/images/flags/pe.gif
+++ b/askbot/media/images/flags/pe.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/pf.gif b/askbot/media/images/flags/pf.gif
index 849297a5..849297a5 100755
--- a/askbot/skins/common/media/images/flags/pf.gif
+++ b/askbot/media/images/flags/pf.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/pg.gif b/askbot/media/images/flags/pg.gif
index 2d20b078..2d20b078 100755
--- a/askbot/skins/common/media/images/flags/pg.gif
+++ b/askbot/media/images/flags/pg.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ph.gif b/askbot/media/images/flags/ph.gif
index 12b380ac..12b380ac 100755
--- a/askbot/skins/common/media/images/flags/ph.gif
+++ b/askbot/media/images/flags/ph.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/pk.gif b/askbot/media/images/flags/pk.gif
index f3f62c2e..f3f62c2e 100755
--- a/askbot/skins/common/media/images/flags/pk.gif
+++ b/askbot/media/images/flags/pk.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/pl.gif b/askbot/media/images/flags/pl.gif
index bf106463..bf106463 100755
--- a/askbot/skins/common/media/images/flags/pl.gif
+++ b/askbot/media/images/flags/pl.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/pm.gif b/askbot/media/images/flags/pm.gif
index 99bf6fdb..99bf6fdb 100755
--- a/askbot/skins/common/media/images/flags/pm.gif
+++ b/askbot/media/images/flags/pm.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/pn.gif b/askbot/media/images/flags/pn.gif
index 4bc86a1d..4bc86a1d 100755
--- a/askbot/skins/common/media/images/flags/pn.gif
+++ b/askbot/media/images/flags/pn.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/pr.gif b/askbot/media/images/flags/pr.gif
index 6d5d5896..6d5d5896 100755
--- a/askbot/skins/common/media/images/flags/pr.gif
+++ b/askbot/media/images/flags/pr.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ps.gif b/askbot/media/images/flags/ps.gif
index 6afa3b71..6afa3b71 100755
--- a/askbot/skins/common/media/images/flags/ps.gif
+++ b/askbot/media/images/flags/ps.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/pt.gif b/askbot/media/images/flags/pt.gif
index e735f740..e735f740 100755
--- a/askbot/skins/common/media/images/flags/pt.gif
+++ b/askbot/media/images/flags/pt.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/pw.gif b/askbot/media/images/flags/pw.gif
index 5854510f..5854510f 100755
--- a/askbot/skins/common/media/images/flags/pw.gif
+++ b/askbot/media/images/flags/pw.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/py.gif b/askbot/media/images/flags/py.gif
index f2e66af7..f2e66af7 100755
--- a/askbot/skins/common/media/images/flags/py.gif
+++ b/askbot/media/images/flags/py.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/qa.gif b/askbot/media/images/flags/qa.gif
index 2e843ff9..2e843ff9 100755
--- a/askbot/skins/common/media/images/flags/qa.gif
+++ b/askbot/media/images/flags/qa.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/re.gif b/askbot/media/images/flags/re.gif
index 43d0b801..43d0b801 100755
--- a/askbot/skins/common/media/images/flags/re.gif
+++ b/askbot/media/images/flags/re.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ro.gif b/askbot/media/images/flags/ro.gif
index f5d5f125..f5d5f125 100755
--- a/askbot/skins/common/media/images/flags/ro.gif
+++ b/askbot/media/images/flags/ro.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/rs.gif b/askbot/media/images/flags/rs.gif
index 3bd1fb2f..3bd1fb2f 100644
--- a/askbot/skins/common/media/images/flags/rs.gif
+++ b/askbot/media/images/flags/rs.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ru.gif b/askbot/media/images/flags/ru.gif
index b525c462..b525c462 100755
--- a/askbot/skins/common/media/images/flags/ru.gif
+++ b/askbot/media/images/flags/ru.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/rw.gif b/askbot/media/images/flags/rw.gif
index 0d095f7a..0d095f7a 100755
--- a/askbot/skins/common/media/images/flags/rw.gif
+++ b/askbot/media/images/flags/rw.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/sa.gif b/askbot/media/images/flags/sa.gif
index 179961b6..179961b6 100755
--- a/askbot/skins/common/media/images/flags/sa.gif
+++ b/askbot/media/images/flags/sa.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/sb.gif b/askbot/media/images/flags/sb.gif
index 8f5ff837..8f5ff837 100755
--- a/askbot/skins/common/media/images/flags/sb.gif
+++ b/askbot/media/images/flags/sb.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/sc.gif b/askbot/media/images/flags/sc.gif
index 31b47677..31b47677 100755
--- a/askbot/skins/common/media/images/flags/sc.gif
+++ b/askbot/media/images/flags/sc.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/scotland.gif b/askbot/media/images/flags/scotland.gif
index 03f3f1de..03f3f1de 100755
--- a/askbot/skins/common/media/images/flags/scotland.gif
+++ b/askbot/media/images/flags/scotland.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/sd.gif b/askbot/media/images/flags/sd.gif
index 53ae214f..53ae214f 100755
--- a/askbot/skins/common/media/images/flags/sd.gif
+++ b/askbot/media/images/flags/sd.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/se.gif b/askbot/media/images/flags/se.gif
index 80f62852..80f62852 100755
--- a/askbot/skins/common/media/images/flags/se.gif
+++ b/askbot/media/images/flags/se.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/sg.gif b/askbot/media/images/flags/sg.gif
index 5663d39f..5663d39f 100755
--- a/askbot/skins/common/media/images/flags/sg.gif
+++ b/askbot/media/images/flags/sg.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/sh.gif b/askbot/media/images/flags/sh.gif
index dcc7f3bc..dcc7f3bc 100755
--- a/askbot/skins/common/media/images/flags/sh.gif
+++ b/askbot/media/images/flags/sh.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/si.gif b/askbot/media/images/flags/si.gif
index 23852b50..23852b50 100755
--- a/askbot/skins/common/media/images/flags/si.gif
+++ b/askbot/media/images/flags/si.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/sj.gif b/askbot/media/images/flags/sj.gif
index 6202d1f3..6202d1f3 100755
--- a/askbot/skins/common/media/images/flags/sj.gif
+++ b/askbot/media/images/flags/sj.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/sk.gif b/askbot/media/images/flags/sk.gif
index 1b3f22ba..1b3f22ba 100755
--- a/askbot/skins/common/media/images/flags/sk.gif
+++ b/askbot/media/images/flags/sk.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/sl.gif b/askbot/media/images/flags/sl.gif
index f0f34923..f0f34923 100755
--- a/askbot/skins/common/media/images/flags/sl.gif
+++ b/askbot/media/images/flags/sl.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/sm.gif b/askbot/media/images/flags/sm.gif
index 04d98de5..04d98de5 100755
--- a/askbot/skins/common/media/images/flags/sm.gif
+++ b/askbot/media/images/flags/sm.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/sn.gif b/askbot/media/images/flags/sn.gif
index 6dac8709..6dac8709 100755
--- a/askbot/skins/common/media/images/flags/sn.gif
+++ b/askbot/media/images/flags/sn.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/so.gif b/askbot/media/images/flags/so.gif
index f1961694..f1961694 100755
--- a/askbot/skins/common/media/images/flags/so.gif
+++ b/askbot/media/images/flags/so.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/sr.gif b/askbot/media/images/flags/sr.gif
index 0f7499ad..0f7499ad 100755
--- a/askbot/skins/common/media/images/flags/sr.gif
+++ b/askbot/media/images/flags/sr.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/st.gif b/askbot/media/images/flags/st.gif
index 4f1e6e09..4f1e6e09 100755
--- a/askbot/skins/common/media/images/flags/st.gif
+++ b/askbot/media/images/flags/st.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/sv.gif b/askbot/media/images/flags/sv.gif
index 2d7b159a..2d7b159a 100755
--- a/askbot/skins/common/media/images/flags/sv.gif
+++ b/askbot/media/images/flags/sv.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/sy.gif b/askbot/media/images/flags/sy.gif
index dc8bd509..dc8bd509 100755
--- a/askbot/skins/common/media/images/flags/sy.gif
+++ b/askbot/media/images/flags/sy.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/sz.gif b/askbot/media/images/flags/sz.gif
index f37aaf80..f37aaf80 100755
--- a/askbot/skins/common/media/images/flags/sz.gif
+++ b/askbot/media/images/flags/sz.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/tc.gif b/askbot/media/images/flags/tc.gif
index 11a8c232..11a8c232 100755
--- a/askbot/skins/common/media/images/flags/tc.gif
+++ b/askbot/media/images/flags/tc.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/td.gif b/askbot/media/images/flags/td.gif
index 7aa8a10d..7aa8a10d 100755
--- a/askbot/skins/common/media/images/flags/td.gif
+++ b/askbot/media/images/flags/td.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/tf.gif b/askbot/media/images/flags/tf.gif
index 51a43250..51a43250 100755
--- a/askbot/skins/common/media/images/flags/tf.gif
+++ b/askbot/media/images/flags/tf.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/tg.gif b/askbot/media/images/flags/tg.gif
index ca6b4e77..ca6b4e77 100755
--- a/askbot/skins/common/media/images/flags/tg.gif
+++ b/askbot/media/images/flags/tg.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/th.gif b/askbot/media/images/flags/th.gif
index 01307924..01307924 100755
--- a/askbot/skins/common/media/images/flags/th.gif
+++ b/askbot/media/images/flags/th.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/tj.gif b/askbot/media/images/flags/tj.gif
index 2fe38d4a..2fe38d4a 100755
--- a/askbot/skins/common/media/images/flags/tj.gif
+++ b/askbot/media/images/flags/tj.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/tk.gif b/askbot/media/images/flags/tk.gif
index 3d3a727f..3d3a727f 100755
--- a/askbot/skins/common/media/images/flags/tk.gif
+++ b/askbot/media/images/flags/tk.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/tl.gif b/askbot/media/images/flags/tl.gif
index df22d582..df22d582 100755
--- a/askbot/skins/common/media/images/flags/tl.gif
+++ b/askbot/media/images/flags/tl.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/tm.gif b/askbot/media/images/flags/tm.gif
index 36d0994f..36d0994f 100755
--- a/askbot/skins/common/media/images/flags/tm.gif
+++ b/askbot/media/images/flags/tm.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/tn.gif b/askbot/media/images/flags/tn.gif
index 917d4288..917d4288 100755
--- a/askbot/skins/common/media/images/flags/tn.gif
+++ b/askbot/media/images/flags/tn.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/to.gif b/askbot/media/images/flags/to.gif
index d7ed4d11..d7ed4d11 100755
--- a/askbot/skins/common/media/images/flags/to.gif
+++ b/askbot/media/images/flags/to.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/tr.gif b/askbot/media/images/flags/tr.gif
index e407d553..e407d553 100755
--- a/askbot/skins/common/media/images/flags/tr.gif
+++ b/askbot/media/images/flags/tr.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/tt.gif b/askbot/media/images/flags/tt.gif
index 47d3b806..47d3b806 100755
--- a/askbot/skins/common/media/images/flags/tt.gif
+++ b/askbot/media/images/flags/tt.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/tv.gif b/askbot/media/images/flags/tv.gif
index 3c338277..3c338277 100755
--- a/askbot/skins/common/media/images/flags/tv.gif
+++ b/askbot/media/images/flags/tv.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/tw.gif b/askbot/media/images/flags/tw.gif
index cacfd9b7..cacfd9b7 100755
--- a/askbot/skins/common/media/images/flags/tw.gif
+++ b/askbot/media/images/flags/tw.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/tz.gif b/askbot/media/images/flags/tz.gif
index 82b52ca2..82b52ca2 100755
--- a/askbot/skins/common/media/images/flags/tz.gif
+++ b/askbot/media/images/flags/tz.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ua.gif b/askbot/media/images/flags/ua.gif
index 5d6cd83f..5d6cd83f 100755
--- a/askbot/skins/common/media/images/flags/ua.gif
+++ b/askbot/media/images/flags/ua.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ug.gif b/askbot/media/images/flags/ug.gif
index 58b731ad..58b731ad 100755
--- a/askbot/skins/common/media/images/flags/ug.gif
+++ b/askbot/media/images/flags/ug.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/um.gif b/askbot/media/images/flags/um.gif
index 3b4c8483..3b4c8483 100755
--- a/askbot/skins/common/media/images/flags/um.gif
+++ b/askbot/media/images/flags/um.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/us.gif b/askbot/media/images/flags/us.gif
index 8f198f73..8f198f73 100755
--- a/askbot/skins/common/media/images/flags/us.gif
+++ b/askbot/media/images/flags/us.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/uy.gif b/askbot/media/images/flags/uy.gif
index 12848c74..12848c74 100755
--- a/askbot/skins/common/media/images/flags/uy.gif
+++ b/askbot/media/images/flags/uy.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/uz.gif b/askbot/media/images/flags/uz.gif
index dc9daeca..dc9daeca 100755
--- a/askbot/skins/common/media/images/flags/uz.gif
+++ b/askbot/media/images/flags/uz.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/va.gif b/askbot/media/images/flags/va.gif
index 2bd74468..2bd74468 100755
--- a/askbot/skins/common/media/images/flags/va.gif
+++ b/askbot/media/images/flags/va.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/vc.gif b/askbot/media/images/flags/vc.gif
index 48213816..48213816 100755
--- a/askbot/skins/common/media/images/flags/vc.gif
+++ b/askbot/media/images/flags/vc.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ve.gif b/askbot/media/images/flags/ve.gif
index 19ce6c14..19ce6c14 100755
--- a/askbot/skins/common/media/images/flags/ve.gif
+++ b/askbot/media/images/flags/ve.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/vg.gif b/askbot/media/images/flags/vg.gif
index 1fc0f96e..1fc0f96e 100755
--- a/askbot/skins/common/media/images/flags/vg.gif
+++ b/askbot/media/images/flags/vg.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/vi.gif b/askbot/media/images/flags/vi.gif
index 66f9e746..66f9e746 100755
--- a/askbot/skins/common/media/images/flags/vi.gif
+++ b/askbot/media/images/flags/vi.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/vn.gif b/askbot/media/images/flags/vn.gif
index f1e20c94..f1e20c94 100755
--- a/askbot/skins/common/media/images/flags/vn.gif
+++ b/askbot/media/images/flags/vn.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/vu.gif b/askbot/media/images/flags/vu.gif
index 8a8b2b06..8a8b2b06 100755
--- a/askbot/skins/common/media/images/flags/vu.gif
+++ b/askbot/media/images/flags/vu.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/wales.gif b/askbot/media/images/flags/wales.gif
index 901d1750..901d1750 100755
--- a/askbot/skins/common/media/images/flags/wales.gif
+++ b/askbot/media/images/flags/wales.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/wf.gif b/askbot/media/images/flags/wf.gif
index eaa954b1..eaa954b1 100755
--- a/askbot/skins/common/media/images/flags/wf.gif
+++ b/askbot/media/images/flags/wf.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ws.gif b/askbot/media/images/flags/ws.gif
index a51f939e..a51f939e 100755
--- a/askbot/skins/common/media/images/flags/ws.gif
+++ b/askbot/media/images/flags/ws.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/ye.gif b/askbot/media/images/flags/ye.gif
index 7b0183d0..7b0183d0 100755
--- a/askbot/skins/common/media/images/flags/ye.gif
+++ b/askbot/media/images/flags/ye.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/yt.gif b/askbot/media/images/flags/yt.gif
index a2267c05..a2267c05 100755
--- a/askbot/skins/common/media/images/flags/yt.gif
+++ b/askbot/media/images/flags/yt.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/za.gif b/askbot/media/images/flags/za.gif
index ede52589..ede52589 100755
--- a/askbot/skins/common/media/images/flags/za.gif
+++ b/askbot/media/images/flags/za.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/zm.gif b/askbot/media/images/flags/zm.gif
index b2851d2b..b2851d2b 100755
--- a/askbot/skins/common/media/images/flags/zm.gif
+++ b/askbot/media/images/flags/zm.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/flags/zw.gif b/askbot/media/images/flags/zw.gif
index 02901f62..02901f62 100755
--- a/askbot/skins/common/media/images/flags/zw.gif
+++ b/askbot/media/images/flags/zw.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/go-up-grey.png b/askbot/media/images/go-up-grey.png
index 763bb799..763bb799 100644
--- a/askbot/skins/common/media/images/go-up-grey.png
+++ b/askbot/media/images/go-up-grey.png
Binary files differ
diff --git a/askbot/skins/common/media/images/go-up-orange.png b/askbot/media/images/go-up-orange.png
index eca3579d..eca3579d 100644
--- a/askbot/skins/common/media/images/go-up-orange.png
+++ b/askbot/media/images/go-up-orange.png
Binary files differ
diff --git a/askbot/skins/common/media/images/gray-up-arrow-h18px.png b/askbot/media/images/gray-up-arrow-h18px.png
index 78767445..78767445 100755
--- a/askbot/skins/common/media/images/gray-up-arrow-h18px.png
+++ b/askbot/media/images/gray-up-arrow-h18px.png
Binary files differ
diff --git a/askbot/skins/common/media/images/grippie.png b/askbot/media/images/grippie.png
index 6524d416..6524d416 100755
--- a/askbot/skins/common/media/images/grippie.png
+++ b/askbot/media/images/grippie.png
Binary files differ
diff --git a/askbot/skins/common/media/images/indicator.gif b/askbot/media/images/indicator.gif
index 1c72ebb5..1c72ebb5 100755
--- a/askbot/skins/common/media/images/indicator.gif
+++ b/askbot/media/images/indicator.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/link.png b/askbot/media/images/link.png
index 6ad60f5e..6ad60f5e 100644
--- a/askbot/skins/default/media/images/link.png
+++ b/askbot/media/images/link.png
Binary files differ
diff --git a/askbot/skins/default/media/images/logo.gif b/askbot/media/images/logo.gif
index 810b0bcf..810b0bcf 100644
--- a/askbot/skins/default/media/images/logo.gif
+++ b/askbot/media/images/logo.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/logo.png b/askbot/media/images/logo.png
index 10559161..10559161 100644
--- a/askbot/skins/common/media/images/logo.png
+++ b/askbot/media/images/logo.png
Binary files differ
diff --git a/askbot/skins/common/media/images/logo1.png b/askbot/media/images/logo1.png
index d79a6271..d79a6271 100755
--- a/askbot/skins/common/media/images/logo1.png
+++ b/askbot/media/images/logo1.png
Binary files differ
diff --git a/askbot/skins/common/media/images/logo2.png b/askbot/media/images/logo2.png
index bd3cccd9..bd3cccd9 100755
--- a/askbot/skins/common/media/images/logo2.png
+++ b/askbot/media/images/logo2.png
Binary files differ
diff --git a/askbot/skins/common/media/images/mail-envelope-empty.png b/askbot/media/images/mail-envelope-empty.png
index 0fde87dc..0fde87dc 100644
--- a/askbot/skins/common/media/images/mail-envelope-empty.png
+++ b/askbot/media/images/mail-envelope-empty.png
Binary files differ
diff --git a/askbot/skins/common/media/images/mail-envelope-full.png b/askbot/media/images/mail-envelope-full.png
index 2277e919..2277e919 100644
--- a/askbot/skins/common/media/images/mail-envelope-full.png
+++ b/askbot/media/images/mail-envelope-full.png
Binary files differ
diff --git a/askbot/skins/common/media/images/medala.gif b/askbot/media/images/medala.gif
index 93dd1a39..93dd1a39 100755
--- a/askbot/skins/common/media/images/medala.gif
+++ b/askbot/media/images/medala.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/medala_on.gif b/askbot/media/images/medala_on.gif
index a18f9e85..a18f9e85 100755
--- a/askbot/skins/common/media/images/medala_on.gif
+++ b/askbot/media/images/medala_on.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/medium-button.png b/askbot/media/images/medium-button.png
index f384be91..f384be91 100644
--- a/askbot/skins/default/media/images/medium-button.png
+++ b/askbot/media/images/medium-button.png
Binary files differ
diff --git a/askbot/skins/common/media/images/new.gif b/askbot/media/images/new.gif
index 8a220b53..8a220b53 100755
--- a/askbot/skins/common/media/images/new.gif
+++ b/askbot/media/images/new.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/nophoto.png b/askbot/media/images/nophoto.png
index 2daf0ffd..2daf0ffd 100755
--- a/askbot/skins/common/media/images/nophoto.png
+++ b/askbot/media/images/nophoto.png
Binary files differ
diff --git a/askbot/skins/default/media/images/notification.png b/askbot/media/images/notification.png
index c33ba699..c33ba699 100644
--- a/askbot/skins/default/media/images/notification.png
+++ b/askbot/media/images/notification.png
Binary files differ
diff --git a/askbot/skins/common/media/images/openid.gif b/askbot/media/images/openid.gif
index 8540e12b..8540e12b 100755
--- a/askbot/skins/common/media/images/openid.gif
+++ b/askbot/media/images/openid.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/openid/aol.gif b/askbot/media/images/openid/aol.gif
index decc4f12..decc4f12 100755
--- a/askbot/skins/common/media/images/openid/aol.gif
+++ b/askbot/media/images/openid/aol.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/openid/blogger.ico b/askbot/media/images/openid/blogger.ico
index 1b9730b0..1b9730b0 100755
--- a/askbot/skins/common/media/images/openid/blogger.ico
+++ b/askbot/media/images/openid/blogger.ico
Binary files differ
diff --git a/askbot/skins/common/media/images/openid/claimid.ico b/askbot/media/images/openid/claimid.ico
index 2b80f491..2b80f491 100755
--- a/askbot/skins/common/media/images/openid/claimid.ico
+++ b/askbot/media/images/openid/claimid.ico
Binary files differ
diff --git a/askbot/skins/common/media/images/openid/facebook.gif b/askbot/media/images/openid/facebook.gif
index b997b358..b997b358 100755
--- a/askbot/skins/common/media/images/openid/facebook.gif
+++ b/askbot/media/images/openid/facebook.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/openid/flickr.ico b/askbot/media/images/openid/flickr.ico
index 11f6e07f..11f6e07f 100755
--- a/askbot/skins/common/media/images/openid/flickr.ico
+++ b/askbot/media/images/openid/flickr.ico
Binary files differ
diff --git a/askbot/skins/common/media/images/openid/google.gif b/askbot/media/images/openid/google.gif
index 1b6cd07b..1b6cd07b 100755
--- a/askbot/skins/common/media/images/openid/google.gif
+++ b/askbot/media/images/openid/google.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/openid/livejournal.ico b/askbot/media/images/openid/livejournal.ico
index f3d21ec5..f3d21ec5 100755
--- a/askbot/skins/common/media/images/openid/livejournal.ico
+++ b/askbot/media/images/openid/livejournal.ico
Binary files differ
diff --git a/askbot/skins/common/media/images/openid/myopenid.ico b/askbot/media/images/openid/myopenid.ico
index ceb06e6a..ceb06e6a 100755
--- a/askbot/skins/common/media/images/openid/myopenid.ico
+++ b/askbot/media/images/openid/myopenid.ico
Binary files differ
diff --git a/askbot/skins/common/media/images/openid/openid-inputicon.gif b/askbot/media/images/openid/openid-inputicon.gif
index cde836c8..cde836c8 100755
--- a/askbot/skins/common/media/images/openid/openid-inputicon.gif
+++ b/askbot/media/images/openid/openid-inputicon.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/openid/openid.gif b/askbot/media/images/openid/openid.gif
index c718b0e6..c718b0e6 100755
--- a/askbot/skins/common/media/images/openid/openid.gif
+++ b/askbot/media/images/openid/openid.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/openid/technorati.ico b/askbot/media/images/openid/technorati.ico
index fa1083c1..fa1083c1 100755
--- a/askbot/skins/common/media/images/openid/technorati.ico
+++ b/askbot/media/images/openid/technorati.ico
Binary files differ
diff --git a/askbot/skins/common/media/images/openid/twitter.png b/askbot/media/images/openid/twitter.png
index 9a6552d1..9a6552d1 100755
--- a/askbot/skins/common/media/images/openid/twitter.png
+++ b/askbot/media/images/openid/twitter.png
Binary files differ
diff --git a/askbot/skins/common/media/images/openid/verisign.ico b/askbot/media/images/openid/verisign.ico
index 3953af93..3953af93 100755
--- a/askbot/skins/common/media/images/openid/verisign.ico
+++ b/askbot/media/images/openid/verisign.ico
Binary files differ
diff --git a/askbot/skins/common/media/images/openid/vidoop.ico b/askbot/media/images/openid/vidoop.ico
index bbd9a0d5..bbd9a0d5 100755
--- a/askbot/skins/common/media/images/openid/vidoop.ico
+++ b/askbot/media/images/openid/vidoop.ico
Binary files differ
diff --git a/askbot/skins/common/media/images/openid/wordpress.ico b/askbot/media/images/openid/wordpress.ico
index 31b7d2c2..31b7d2c2 100755
--- a/askbot/skins/common/media/images/openid/wordpress.ico
+++ b/askbot/media/images/openid/wordpress.ico
Binary files differ
diff --git a/askbot/skins/common/media/images/openid/yahoo.gif b/askbot/media/images/openid/yahoo.gif
index 0f0eb8ef..0f0eb8ef 100755
--- a/askbot/skins/common/media/images/openid/yahoo.gif
+++ b/askbot/media/images/openid/yahoo.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/print.png b/askbot/media/images/print.png
index 37bf88af..37bf88af 100644
--- a/askbot/skins/common/media/images/print.png
+++ b/askbot/media/images/print.png
Binary files differ
diff --git a/askbot/media/images/publish.png b/askbot/media/images/publish.png
new file mode 100644
index 00000000..038a87d2
--- /dev/null
+++ b/askbot/media/images/publish.png
Binary files differ
diff --git a/askbot/skins/common/media/images/pw-login.gif b/askbot/media/images/pw-login.gif
index f88b1bcf..f88b1bcf 100644
--- a/askbot/skins/common/media/images/pw-login.gif
+++ b/askbot/media/images/pw-login.gif
Binary files differ
diff --git a/askbot/skins/common/media/images/quest-bg.gif b/askbot/media/images/quest-bg.gif
index b7540238..b7540238 100755
--- a/askbot/skins/common/media/images/quest-bg.gif
+++ b/askbot/media/images/quest-bg.gif
Binary files differ
diff --git a/askbot/skins/default/media/images/retag.png b/askbot/media/images/retag.png
index 836c043c..836c043c 100644
--- a/askbot/skins/default/media/images/retag.png
+++ b/askbot/media/images/retag.png
Binary files differ
diff --git a/askbot/skins/common/media/images/scopearrow.png b/askbot/media/images/scopearrow.png
index 73dc6744..73dc6744 100644
--- a/askbot/skins/common/media/images/scopearrow.png
+++ b/askbot/media/images/scopearrow.png
Binary files differ
diff --git a/askbot/skins/default/media/images/small-button-blue.png b/askbot/media/images/small-button-blue.png
index 54082818..54082818 100644
--- a/askbot/skins/default/media/images/small-button-blue.png
+++ b/askbot/media/images/small-button-blue.png
Binary files differ
diff --git a/askbot/skins/default/media/images/small-button-cancel.png b/askbot/media/images/small-button-cancel.png
index 79a87497..79a87497 100644
--- a/askbot/skins/default/media/images/small-button-cancel.png
+++ b/askbot/media/images/small-button-cancel.png
Binary files differ
diff --git a/askbot/skins/default/media/images/socialsprite.png b/askbot/media/images/socialsprite.png
index 8d01ed77..8d01ed77 100644
--- a/askbot/skins/default/media/images/socialsprite.png
+++ b/askbot/media/images/socialsprite.png
Binary files differ
diff --git a/askbot/skins/common/media/images/sprite.png b/askbot/media/images/sprite.png
index 1a0fbc78..1a0fbc78 100644
--- a/askbot/skins/common/media/images/sprite.png
+++ b/askbot/media/images/sprite.png
Binary files differ
diff --git a/askbot/media/images/sprites.png b/askbot/media/images/sprites.png
new file mode 100644
index 00000000..c4e9029c
--- /dev/null
+++ b/askbot/media/images/sprites.png
Binary files differ
diff --git a/askbot/skins/default/media/images/sprites_source/graphics.svg b/askbot/media/images/sprites_source/graphics.svg
index 72e1d2aa..72e1d2aa 100644
--- a/askbot/skins/default/media/images/sprites_source/graphics.svg
+++ b/askbot/media/images/sprites_source/graphics.svg
diff --git a/askbot/skins/common/media/images/sprites_source/sprites.svg b/askbot/media/images/sprites_source/other.svg
index 34898e30..34898e30 100644
--- a/askbot/skins/common/media/images/sprites_source/sprites.svg
+++ b/askbot/media/images/sprites_source/other.svg
diff --git a/askbot/media/images/sprites_source/sprites.svg b/askbot/media/images/sprites_source/sprites.svg
new file mode 100644
index 00000000..1c16c89c
--- /dev/null
+++ b/askbot/media/images/sprites_source/sprites.svg
@@ -0,0 +1,519 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="600"
+ height="207"
+ id="svg3448"
+ version="1.1"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="sprites.svg"
+ inkscape:export-filename="/home/fitoria/code/askbot-devel/askbot/skins/default/media/images/sprites.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <defs
+ id="defs3450">
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3819">
+ <stop
+ style="stop-color:#000000;stop-opacity:1"
+ offset="0"
+ id="stop3821" />
+ <stop
+ style="stop-color:#deded0;stop-opacity:0;"
+ offset="1"
+ id="stop3823" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3029">
+ <stop
+ style="stop-color:#525252;stop-opacity:1"
+ offset="0"
+ id="stop3031" />
+ <stop
+ style="stop-color:#020202;stop-opacity:1"
+ offset="1"
+ id="stop3033" />
+ </linearGradient>
+ <radialGradient
+ r="11.136931"
+ fy="161.02299"
+ fx="222.6344"
+ cy="161.02299"
+ cx="222.6344"
+ gradientTransform="matrix(0.25937215,-1.0764281,1.4011863,0.30094439,-58.042568,347.29527)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient3838-8"
+ xlink:href="#linearGradient3865-1"
+ inkscape:collect="always" />
+ <linearGradient
+ id="linearGradient3865-1"
+ inkscape:collect="always">
+ <stop
+ id="stop3867-7"
+ offset="0"
+ style="stop-color:#0975cf;stop-opacity:1" />
+ <stop
+ id="stop3869-7"
+ offset="1"
+ style="stop-color:#14b3de;stop-opacity:0" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3824-7"
+ id="radialGradient3822-9"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.58002994,0.69397701,-0.72276743,0.59013931,3613.278,1050.6132)"
+ cx="-2600.8416"
+ cy="2819.7468"
+ fx="-2600.8416"
+ fy="2819.7468"
+ r="16.18819" />
+ <linearGradient
+ id="linearGradient3824-7"
+ inkscape:collect="always">
+ <stop
+ id="stop3826-9"
+ offset="0"
+ style="stop-color:#9f9f8d;stop-opacity:1" />
+ <stop
+ id="stop3828-8"
+ offset="1"
+ style="stop-color:#44443a;stop-opacity:1" />
+ </linearGradient>
+ <radialGradient
+ r="16.18819"
+ fy="2819.7468"
+ fx="-2600.8416"
+ cy="2819.7468"
+ cx="-2600.8416"
+ gradientTransform="matrix(0.58002994,0.69397701,-0.72276743,0.59013931,3568.2975,1050.6132)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient5712-8"
+ xlink:href="#linearGradient5675-9"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient5675-9">
+ <stop
+ style="stop-color:#9f9f8d;stop-opacity:1"
+ offset="0"
+ id="stop5677-8" />
+ <stop
+ style="stop-color:#757563;stop-opacity:1"
+ offset="1"
+ id="stop5679-0" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7944-2"
+ id="linearGradient6226-5"
+ gradientUnits="userSpaceOnUse"
+ x1="-1656.4215"
+ y1="3870.6523"
+ x2="-1656.4216"
+ y2="3887.7998" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient7944-2">
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="0"
+ id="stop7946-0" />
+ <stop
+ style="stop-color:#e4e4e4;stop-opacity:1"
+ offset="1"
+ id="stop7948-2" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7944-2"
+ id="linearGradient6228-4"
+ gradientUnits="userSpaceOnUse"
+ x1="-1656.4215"
+ y1="3870.6523"
+ x2="-1656.4216"
+ y2="3887.7998" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient7944-2"
+ id="linearGradient7950-3"
+ x1="-1656.4215"
+ y1="3870.6523"
+ x2="-1656.4216"
+ y2="3887.7998"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3029"
+ id="radialGradient3037"
+ cx="107.38955"
+ cy="37.76292"
+ fx="107.38955"
+ fy="37.76292"
+ r="10.875"
+ gradientTransform="matrix(1.8448978,1.1954022,-0.56343271,0.76622296,-66.658636,-116.22519)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3819"
+ id="linearGradient3825"
+ x1="112.05391"
+ y1="29.484962"
+ x2="113.33555"
+ y2="54.66436"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3819"
+ id="linearGradient3832"
+ gradientUnits="userSpaceOnUse"
+ x1="112.05391"
+ y1="29.484962"
+ x2="113.33555"
+ y2="54.66436" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3029"
+ id="radialGradient3834"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.8448978,1.1954022,-0.56343271,0.76622296,-66.658636,-116.22519)"
+ cx="107.38955"
+ cy="37.76292"
+ fx="107.38955"
+ fy="37.76292"
+ r="10.875" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3819"
+ id="linearGradient3846"
+ gradientUnits="userSpaceOnUse"
+ x1="112.05391"
+ y1="29.484962"
+ x2="113.33555"
+ y2="54.66436" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3029"
+ id="radialGradient3848"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.8448978,1.1954022,-0.56343271,0.76622296,-66.658636,-116.22519)"
+ cx="107.38955"
+ cy="37.76292"
+ fx="107.38955"
+ fy="37.76292"
+ r="10.875" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.8095563"
+ inkscape:cx="-20.257428"
+ inkscape:cy="137.9209"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1366"
+ inkscape:window-height="723"
+ inkscape:window-x="-3"
+ inkscape:window-y="-3"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata3453">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Capa 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-845.36218)">
+ <path
+ transform="matrix(1.0191083,0,0,0.98765432,1704.4089,-2965.0039)"
+ d="m -1647,3873.8623 c 0,5.2467 -4.2533,9.5 -9.5,9.5 -5.2467,0 -9.5,-4.2533 -9.5,-9.5 0,-5.2467 4.2533,-9.5 9.5,-9.5 5.2467,0 9.5,4.2533 9.5,9.5 z"
+ sodipodi:ry="9.5"
+ sodipodi:rx="9.5"
+ sodipodi:cy="3873.8623"
+ sodipodi:cx="-1656.5"
+ id="path7928"
+ style="fill:#c9a90d;fill-opacity:1;stroke:none"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient7950-3);fill-opacity:1;stroke:none"
+ id="path7922"
+ sodipodi:cx="-1656.5"
+ sodipodi:cy="3873.8623"
+ sodipodi:rx="9.5"
+ sodipodi:ry="9.5"
+ d="m -1647,3873.8623 c 0,5.2467 -4.2533,9.5 -9.5,9.5 -5.2467,0 -9.5,-4.2533 -9.5,-9.5 0,-5.2467 4.2533,-9.5 9.5,-9.5 5.2467,0 9.5,4.2533 9.5,9.5 z"
+ transform="matrix(1.0191083,0,0,0.98765432,1703.772,-2966.2384)" />
+ <text
+ transform="scale(1.1035306,0.9061824)"
+ xml:space="preserve"
+ style="font-size:19.10287285px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#b96161;fill-opacity:1;stroke:none;font-family:Arial Rounded MT Bold;-inkscape-font-specification:Arial Rounded MT Bold"
+ x="10.035251"
+ y="953.7583"
+ id="text7924"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan7926"
+ x="10.035251"
+ y="953.7583"
+ style="font-size:14.30124187px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#b96161;fill-opacity:1;font-family:Trebuchet MS;-inkscape-font-specification:Trebuchet MS">X</tspan></text>
+ <path
+ sodipodi:type="arc"
+ style="fill:#c9a90d;fill-opacity:1;stroke:none"
+ id="path6208"
+ sodipodi:cx="-1656.5"
+ sodipodi:cy="3873.8623"
+ sodipodi:rx="9.5"
+ sodipodi:ry="9.5"
+ d="m -1647,3873.8623 c 0,5.2467 -4.2533,9.5 -9.5,9.5 -5.2467,0 -9.5,-4.2533 -9.5,-9.5 0,-5.2467 4.2533,-9.5 9.5,-9.5 5.2467,0 9.5,4.2533 9.5,9.5 z"
+ transform="matrix(1.0191083,0,0,0.98765432,1704.4089,-2965.0039)" />
+ <path
+ transform="matrix(1.0191083,0,0,0.98765432,1703.772,-2966.2384)"
+ d="m -1647,3873.8623 c 0,5.2467 -4.2533,9.5 -9.5,9.5 -5.2467,0 -9.5,-4.2533 -9.5,-9.5 0,-5.2467 4.2533,-9.5 9.5,-9.5 5.2467,0 9.5,4.2533 9.5,9.5 z"
+ sodipodi:ry="9.5"
+ sodipodi:rx="9.5"
+ sodipodi:cy="3873.8623"
+ sodipodi:cx="-1656.5"
+ id="path6210"
+ style="fill:url(#linearGradient6228-4);fill-opacity:1;stroke:none"
+ sodipodi:type="arc" />
+ <text
+ sodipodi:linespacing="125%"
+ id="text6212"
+ y="953.7583"
+ x="10.035251"
+ style="font-size:19.10287285px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#b96161;fill-opacity:1;stroke:none;font-family:Arial Rounded MT Bold;-inkscape-font-specification:Arial Rounded MT Bold"
+ xml:space="preserve"
+ transform="scale(1.1035306,0.9061824)"><tspan
+ style="font-size:14.30124187px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#b96161;fill-opacity:1;font-family:Trebuchet MS;-inkscape-font-specification:Trebuchet MS"
+ y="953.7583"
+ x="10.035251"
+ id="tspan6214"
+ sodipodi:role="line">X</tspan></text>
+ <path
+ transform="matrix(1.0191083,0,0,0.98765432,1724.4089,-2965.0039)"
+ d="m -1647,3873.8623 c 0,5.2467 -4.2533,9.5 -9.5,9.5 -5.2467,0 -9.5,-4.2533 -9.5,-9.5 0,-5.2467 4.2533,-9.5 9.5,-9.5 5.2467,0 9.5,4.2533 9.5,9.5 z"
+ sodipodi:ry="9.5"
+ sodipodi:rx="9.5"
+ sodipodi:cy="3873.8623"
+ sodipodi:cx="-1656.5"
+ id="path6218"
+ style="fill:#c9a90d;fill-opacity:1;stroke:none"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#linearGradient6226-5);fill-opacity:1;stroke:none"
+ id="path6220"
+ sodipodi:cx="-1656.5"
+ sodipodi:cy="3873.8623"
+ sodipodi:rx="9.5"
+ sodipodi:ry="9.5"
+ d="m -1647,3873.8623 c 0,5.2467 -4.2533,9.5 -9.5,9.5 -5.2467,0 -9.5,-4.2533 -9.5,-9.5 0,-5.2467 4.2533,-9.5 9.5,-9.5 5.2467,0 9.5,4.2533 9.5,9.5 z"
+ transform="matrix(1.0191083,0,0,0.98765432,1723.772,-2966.2384)" />
+ <text
+ transform="scale(1.1035306,0.9061824)"
+ xml:space="preserve"
+ style="font-size:19.10287285px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#e90f0f;fill-opacity:1;stroke:none;font-family:Arial Rounded MT Bold;-inkscape-font-specification:Arial Rounded MT Bold"
+ x="28.158876"
+ y="953.7583"
+ id="text6222"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan6224"
+ x="28.158876"
+ y="953.7583"
+ style="font-size:14.30124187px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#e90f0f;fill-opacity:1;font-family:Trebuchet MS;-inkscape-font-specification:Trebuchet MS">X</tspan></text>
+ <g
+ id="g3045"
+ transform="translate(-46.460961,89.75573)">
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#e7e8a8;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ clip-rule="evenodd"
+ d="m 60.268935,856.20911 c -1.0424,-0.85947 -2.66478,-0.61037 -3.61221,0.54899 -0.95263,1.15795 -0.86987,2.79882 0.17873,3.65569 1.0444,0.86116 2.66667,0.61206 3.61631,-0.54959 0.94503,-1.16205 0.86746,-2.79822 -0.17854,-3.65559 z m 5.88263,18.6866 -12.99549,-10.63781 c -0.44703,-0.36346 -0.64755,-0.93014 -0.58638,-1.50242 -0.05,-0.11386 -0.087,-0.2505 -0.10985,-0.41064 l -1.33739,-8.83579 c -0.14424,-0.94964 0.5206,-1.76262 1.48163,-1.8085 l 8.91926,-0.44173 c 0.38495,-0.019 1.49952,0.35486 1.78501,0.58457 l 12.99449,10.6375 c 0.74232,0.60366 0.7989,1.77001 0.12665,2.5924 l -7.71322,9.43427 c -0.66824,0.82178 -1.8207,0.99492 -2.56061,0.38925 z"
+ id="path5443"
+ inkscape:export-filename="/home/bcorrales/personal/oxfam/arte/disenoindex.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90" />
+ <path
+ inkscape:transform-center-y="-0.28622416"
+ inkscape:transform-center-x="0.5180824"
+ inkscape:export-ydpi="90"
+ inkscape:export-xdpi="90"
+ inkscape:export-filename="/home/bcorrales/personal/oxfam/arte/disenoindex.png"
+ id="path5445"
+ d="m 60.685375,857.34507 c -0.92055,-0.75811 -2.28652,-0.61896 -3.04183,0.30448 -0.75951,0.92235 -0.62036,2.28942 0.30498,3.04553 0.92224,0.7595 2.28822,0.62046 3.04513,-0.30508 0.75321,-0.92595 0.61866,-2.28902 -0.30479,-3.04533 z m 5.77547,15.77522 -11.47288,-9.38529 c -0.39445,-0.32067 -0.58837,-0.79999 -0.56038,-1.27301 -0.047,-0.097 -0.084,-0.21191 -0.11056,-0.34586 l -1.50572,-7.39855 c -0.16224,-0.79519 0.36786,-1.44284 1.18105,-1.44084 l 7.54948,0.01 c 0.32578,4e-4 1.28701,0.35796 1.53911,0.56048 l 11.47158,9.38508 c 0.65525,0.53279 0.75211,1.50442 0.21612,2.15966 l -6.14833,7.51602 c -0.5325,0.65474 -1.50312,0.75031 -2.15627,0.21591 z"
+ clip-rule="evenodd"
+ style="fill:#16160f;fill-opacity:1;fill-rule:evenodd"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g3049"
+ transform="translate(-130.64701,127.66187)">
+ <path
+ style="fill:#e7e8a8;fill-opacity:1;stroke:none"
+ d="m 143.74707,850.88647 c -5.0386,0.15973 -7.45306,6.82507 -4.44845,10.23363 -5.35784,2.62945 -3.73419,8.64761 -3.90826,13.70497 6.23105,0 12.46221,0 18.69326,0 -0.0342,-5.17704 1.38659,-11.61813 -4.44823,-13.9621 3.5491,-4.27537 -0.52838,-10.73631 -5.88832,-9.9765 z"
+ id="path5457"
+ inkscape:connector-curvature="0" />
+ <path
+ transform="matrix(0.23246322,0,0,0.23246322,554.98367,575.74893)"
+ sodipodi:open="true"
+ sodipodi:end="6.6674319"
+ sodipodi:start="0.38694167"
+ d="m -1746.6683,1217.8622 c -4.3506,10.1651 -16.5325,15.0477 -27.209,10.9056 -10.6766,-4.1422 -15.8049,-15.7405 -11.4544,-25.9056 4.3506,-10.1651 16.5325,-15.0477 27.209,-10.9056 10.6563,4.1342 15.789,15.6991 11.4755,25.8559"
+ sodipodi:ry="19.875"
+ sodipodi:rx="20.875"
+ sodipodi:cy="1210.3622"
+ sodipodi:cx="-1766"
+ id="path5461"
+ style="fill:#16160f;fill-opacity:1;stroke:none"
+ sodipodi:type="arc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path5463"
+ d="m 142.46627,862.02883 c -2.77296,0 -5.03938,2.03973 -5.40307,4.70966 l -0.021,0 0,0.11384 c -0.0243,0.20805 -0.0408,0.42712 -0.0408,0.64178 0,0.21103 0.0177,0.41632 0.0408,0.62106 l 0,5.0718 15.40196,0 0,-5.0718 c 0.0232,-0.20474 0.0408,-0.41003 0.0408,-0.62106 0,-0.21466 -0.0177,-0.43373 -0.0408,-0.64178 l 0,-0.11384 -0.021,0 c -0.3638,-2.66993 -2.63021,-4.70966 -5.40306,-4.70966 l -1.03504,0 -1.35592,2.81554 -1.36629,-2.81554 -0.79699,0 z"
+ style="fill:#16160f;fill-opacity:1;stroke:none" />
+ </g>
+ <g
+ id="g3054"
+ transform="translate(-214.86075,163.94135)">
+ <path
+ inkscape:connector-curvature="0"
+ id="path5491"
+ d="m 230.09729,852.03013 c -1.6542,0.0555 -2.75231,2.08638 -1.97699,3.52883 -0.63135,1.02386 -1.18707,3.28768 -2.84533,2.51282 -1.58254,0.6738 -2.41713,-1.60371 -3.98172,-0.91457 -2.15656,0.50838 -2.50044,3.95528 -0.28646,4.60984 0.66658,0.11836 1.38854,0.19214 1.38577,1.01628 1.32012,1.04282 0.20536,3.35241 -1.27491,3.51052 -2.03524,0.99474 -1.52604,4.44609 0.79456,4.64674 1.48119,0.14147 2.53871,-1.5326 4.09258,-0.89608 1.17551,0.24938 1.76747,1.60242 2.05078,2.54048 -1.0087,1.8897 1.18605,4.16804 3.10405,3.20566 1.39067,-0.4601 1.85188,-2.07121 1.37652,-3.31653 0.41369,-0.83912 1.05271,-1.65965 1.6075,-2.34648 1.24643,-0.35941 2.55425,-0.14896 3.50119,0.71142 2.08378,0.88286 4.38154,-1.75378 2.95628,-3.63073 -0.53953,-1.15942 -2.19299,-0.66667 -2.50358,-1.94916 -0.82635,-1.06372 -0.34544,-2.40575 0.47111,-3.2519 0.51485,-0.51216 1.80066,-0.20231 2.15249,-1.1363 1.70737,-1.91245 -1.15266,-5.07734 -3.21491,-3.54741 -0.69552,1.09312 -1.98439,0.81045 -3.03932,0.8406 -0.98808,-0.56654 -1.66816,-1.89082 -1.84763,-2.90081 0.49774,-1.68564 -0.70875,-3.40169 -2.52198,-3.23322 z"
+ style="opacity:0.95734594;fill:#e7e8a8;fill-opacity:1;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ style="opacity:0.95734594;fill:#16160f;fill-opacity:1;stroke:none"
+ d="m 230.30968,853.20332 c -0.69043,0 -1.25641,0.56589 -1.25641,1.25632 0,0.41517 0.20601,0.77958 0.51734,1.00695 l -2.22628,3.81547 -4.22185,-0.009 c 0,0 0,-0.009 0,-0.009 -0.11993,-0.56552 -0.62747,-0.98854 -1.22877,-0.98854 -0.69034,0 -1.24707,0.55663 -1.24707,1.24716 0,0.69044 0.55673,1.24708 1.24707,1.24708 0.21813,0 0.4221,-0.0582 0.60056,-0.15692 l 2.01389,3.51967 -1.85688,3.19642 c -0.13232,-0.0472 -0.27629,-0.0841 -0.42497,-0.0841 -0.69044,0 -1.24717,0.55674 -1.24717,1.24727 0,0.69052 0.55673,1.25641 1.24717,1.25641 0.54915,0 1.01452,-0.35784 1.18244,-0.84994 l 3.88926,-0.0185 2.19872,3.72291 c -0.28692,0.22904 -0.48036,0.57421 -0.48036,0.96996 0,0.69053 0.55664,1.24726 1.24717,1.24726 0.69044,0 1.25641,-0.55673 1.25641,-1.24726 0,-0.37153 -0.16764,-0.70403 -0.42497,-0.93297 l 2.24487,-3.7599 4.02786,-0.009 c 0.13796,0.54037 0.62682,0.94231 1.21018,0.94231 0.69053,0 1.24717,-0.55673 1.24717,-1.24716 0,-0.69053 -0.55664,-1.25643 -1.24717,-1.25643 -0.18003,0 -0.3534,0.0425 -0.5081,0.11087 l -1.95849,-3.4089 2.05087,-3.53826 c 0.18262,0.10449 0.38447,0.16634 0.60971,0.16634 0.69053,0 1.25641,-0.55663 1.25641,-1.24707 0,-0.69062 -0.56588,-1.24726 -1.25641,-1.24726 -0.63921,0 -1.15415,0.48026 -1.22867,1.09941 l -4.13864,0.0185 -2.32808,-3.83387 c 0.28794,-0.22904 0.48045,-0.57347 0.48045,-0.96996 0,-0.69053 -0.55673,-1.25641 -1.24726,-1.25641 z"
+ id="path5404" />
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.95734594;fill:#e7e8a8;fill-opacity:1;stroke:none"
+ id="path5754"
+ sodipodi:cx="-2864"
+ sodipodi:cy="2735.8623"
+ sodipodi:rx="83.5"
+ sodipodi:ry="82.5"
+ d="m -2780.5,2735.8623 c 0,45.5635 -37.3842,82.5 -83.5,82.5 -46.1158,0 -83.5,-36.9365 -83.5,-82.5 0,-45.5635 37.3842,-82.5 83.5,-82.5 46.1158,0 83.5,36.9365 83.5,82.5 z"
+ transform="matrix(0.05048908,0,0,0.04995915,374.93399,727.37564)" />
+ </g>
+ <path
+ style="fill:url(#radialGradient5712-8);fill-opacity:1"
+ d="m 9.7549531,922.45495 c -0.094,-0.046 -0.2146,-0.1465 -0.2675,-0.2235 -0.092,-0.1328 -0.097,-0.507 -0.1104,-7.2852 l -0.014,-7.1451 5.5932999,-4.8985 c 3.0763,-2.6941 5.6262,-4.9108 5.6664,-4.9262 0.044,-0.017 2.291499,1.9154 5.694699,4.8961 l 5.6214,4.9239 -0.014,7.1474 c -0.013,6.7953 -0.019,7.1546 -0.1108,7.2883 -0.2172,0.3162 -0.1184,0.3086 -4.0168,0.3086 l -3.5623,0 -6e-4,-3.0266 c -6e-4,-1.6648 -0.016,-3.1187 -0.035,-3.2313 -0.022,-0.1319 -0.098,-0.2677 -0.2151,-0.3832 l -0.1811,-0.1789 -3.152299,0 -3.1523,0 -0.181,0.1789 c -0.1168,0.1155 -0.1931,0.2513 -0.2152,0.3832 -0.019,0.1126 -0.034,1.5665 -0.035,3.2313 l -5e-4,3.0266 -3.5704,0 c -3.1432,0 -3.5909999,-0.012 -3.7417999,-0.085 z m -4.3178,-15.0177 c -0.4595,-0.5139 -0.8170004,-0.9502 -0.7943004,-0.9695 0.023,-0.019 3.6131004,-3.1609 7.9784003,-6.9811 4.3654,-3.82019 7.9797,-6.94589 8.0317,-6.94589 0.052,0 3.651199,3.11599 7.998399,6.92429 4.3473,3.8085 7.9377,6.949 7.9789,6.9791 0.059,0.043 -0.096,0.24591 -0.764,0.9929 -0.7293,0.8159 -0.8498,0.9293 -0.9245,0.8704 -0.047,-0.038 -3.2709,-2.8571 -7.1641,-6.26639 -3.8931,-3.40961 -7.098499,-6.1989 -7.123099,-6.1989 -0.025,0 -3.2475,2.8051 -7.1619,6.23339 -3.9143999,3.4285 -7.1400999,6.2475 -7.1684999,6.2648 -0.028,0.018 -0.4273,-0.3892 -0.887,-0.9031 z m 3.9274,-9.9518 0,-2.96499 2.0325999,0 2.0326,0 0,0.9707 c 0,1.5539 0.2495,1.16 -2.0161,3.1826 -1.0729,0.95779 -1.9728999,1.74949 -1.9998999,1.75909 -0.03,0.011 -0.048,-1.1677 -0.048,-2.9474 z"
+ id="path5673"
+ inkscape:connector-curvature="0" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path3820"
+ d="m 54.735425,922.45495 c -0.094,-0.046 -0.2146,-0.1465 -0.2675,-0.2235 -0.092,-0.1328 -0.097,-0.507 -0.1104,-7.2852 l -0.014,-7.1451 5.5933,-4.8985 c 3.0763,-2.6941 5.6262,-4.9108 5.6664,-4.9262 0.044,-0.017 2.2915,1.9154 5.6947,4.8961 l 5.6214,4.9239 -0.014,7.1474 c -0.013,6.7953 -0.019,7.1546 -0.1108,7.2883 -0.2172,0.3162 -0.1184,0.3086 -4.0168,0.3086 l -3.5623,0 -6e-4,-3.0266 c -6e-4,-1.6648 -0.016,-3.1187 -0.035,-3.2313 -0.022,-0.1319 -0.098,-0.2677 -0.2151,-0.3832 l -0.1811,-0.1789 -3.1523,0 -3.1523,0 -0.181,0.1789 c -0.1168,0.1155 -0.1931,0.2513 -0.2152,0.3832 -0.019,0.1126 -0.034,1.5665 -0.035,3.2313 l -5e-4,3.0266 -3.5704,0 c -3.1432,0 -3.591,-0.012 -3.7418,-0.085 z m -4.3178,-15.0177 c -0.4595,-0.5139 -0.817,-0.9502 -0.7943,-0.9695 0.023,-0.019 3.6131,-3.1609 7.9784,-6.9811 4.3654,-3.82019 7.9797,-6.94589 8.0317,-6.94589 0.052,0 3.6512,3.11599 7.9984,6.92429 4.3473,3.8085 7.9377,6.949 7.9789,6.9791 0.059,0.043 -0.096,0.24591 -0.764,0.9929 -0.7293,0.8159 -0.8498,0.9293 -0.9245,0.8704 -0.047,-0.038 -3.2709,-2.8571 -7.1641,-6.26639 -3.8931,-3.40961 -7.0985,-6.1989 -7.1231,-6.1989 -0.025,0 -3.2475,2.8051 -7.1619,6.23339 -3.9144,3.4285 -7.1401,6.2475 -7.1685,6.2648 -0.028,0.018 -0.4273,-0.3892 -0.887,-0.9031 z m 3.9274,-9.9518 0,-2.96499 2.0326,0 2.0326,0 0,0.9707 c 0,1.5539 0.2495,1.16 -2.0161,3.1826 -1.0729,0.95779 -1.9729,1.74949 -1.9999,1.75909 -0.03,0.011 -0.048,-1.1677 -0.048,-2.9474 z"
+ style="fill:url(#radialGradient3822-9);fill-opacity:1" />
+ <rect
+ style="opacity:0.79620852;fill:#deded0;fill-opacity:1;stroke:none"
+ id="rect4547"
+ width="48"
+ height="40"
+ x="97.232117"
+ y="882.21423" />
+ <g
+ id="g3827"
+ transform="translate(-3.8890873,-41.012193)">
+ <path
+ sodipodi:type="arc"
+ style="opacity:0.6956522;fill:url(#linearGradient3832);fill-opacity:1;stroke:none"
+ id="path3815"
+ sodipodi:cx="113.25"
+ sodipodi:cy="45.375"
+ sodipodi:rx="10.875"
+ sodipodi:ry="10.125"
+ d="m 124.125,45.375 c 0,5.591883 -4.8689,10.125 -10.875,10.125 -6.0061,0 -10.875,-4.533117 -10.875,-10.125 0,-5.591883 4.8689,-10.125 10.875,-10.125 6.0061,0 10.875,4.533117 10.875,10.125 z"
+ transform="matrix(1.621439,0,0,1.7273288,-57.807891,865.70481)" />
+ <path
+ transform="matrix(1.408046,0,0,1.5,-33.48691,876.19302)"
+ d="m 124.125,45.375 c 0,5.591883 -4.8689,10.125 -10.875,10.125 -6.0061,0 -10.875,-4.533117 -10.875,-10.125 0,-5.591883 4.8689,-10.125 10.875,-10.125 6.0061,0 10.875,4.533117 10.875,10.125 z"
+ sodipodi:ry="10.125"
+ sodipodi:rx="10.875"
+ sodipodi:cy="45.375"
+ sodipodi:cx="113.25"
+ id="path3027"
+ style="fill:url(#radialGradient3834);fill-opacity:1;stroke:none"
+ sodipodi:type="arc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path3807"
+ d="m 123.65073,934.32167 c -4.50646,0 -8.15625,3.67292 -8.15625,8.1875 0,4.51459 3.64979,8.15625 8.15625,8.15625 1.78681,0 3.4379,-0.55881 4.78125,-1.53125 l 3.8125,3.53125 1.65625,-1.78125 -3.75,-3.5 c 1.02086,-1.36157 1.65625,-3.03756 1.65625,-4.875 0,-4.51458 -3.64979,-8.1875 -8.15625,-8.1875 z m 0.0312,2.21875 c 3.35929,0 6.09375,2.7284 6.09375,6.09375 0,3.36535 -2.73446,6.09375 -6.09375,6.09375 -3.35929,0 -6.0625,-2.7284 -6.0625,-6.09375 0,-3.36535 2.70321,-6.09375 6.0625,-6.09375 z"
+ style="fill:#ffffff;fill-opacity:1;stroke:none" />
+ </g>
+ <rect
+ y="882.21423"
+ x="145.23212"
+ height="40"
+ width="48"
+ id="rect3836"
+ style="opacity:0.79620852;fill:#deded0;fill-opacity:1;stroke:none" />
+ <g
+ transform="translate(44.110913,-41.012193)"
+ id="g3838">
+ <path
+ transform="matrix(1.621439,0,0,1.7273288,-57.807891,865.70481)"
+ d="m 124.125,45.375 c 0,5.591883 -4.8689,10.125 -10.875,10.125 -6.0061,0 -10.875,-4.533117 -10.875,-10.125 0,-5.591883 4.8689,-10.125 10.875,-10.125 6.0061,0 10.875,4.533117 10.875,10.125 z"
+ sodipodi:ry="10.125"
+ sodipodi:rx="10.875"
+ sodipodi:cy="45.375"
+ sodipodi:cx="113.25"
+ id="path3840"
+ style="opacity:0.6956522;fill:url(#linearGradient3846);fill-opacity:1;stroke:none"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#radialGradient3848);fill-opacity:1;stroke:none"
+ id="path3842"
+ sodipodi:cx="113.25"
+ sodipodi:cy="45.375"
+ sodipodi:rx="10.875"
+ sodipodi:ry="10.125"
+ d="m 124.125,45.375 c 0,5.591883 -4.8689,10.125 -10.875,10.125 -6.0061,0 -10.875,-4.533117 -10.875,-10.125 0,-5.591883 4.8689,-10.125 10.875,-10.125 6.0061,0 10.875,4.533117 10.875,10.125 z"
+ transform="matrix(1.408046,0,0,1.5,-33.48691,876.19302)" />
+ <path
+ style="fill:#ffffff;fill-opacity:1;stroke:none"
+ d="m 123.65073,934.32167 c -4.50646,0 -8.15625,3.67292 -8.15625,8.1875 0,4.51459 3.64979,8.15625 8.15625,8.15625 1.78681,0 3.4379,-0.55881 4.78125,-1.53125 l 3.8125,3.53125 1.65625,-1.78125 -3.75,-3.5 c 1.02086,-1.36157 1.65625,-3.03756 1.65625,-4.875 0,-4.51458 -3.64979,-8.1875 -8.15625,-8.1875 z m 0.0312,2.21875 c 3.35929,0 6.09375,2.7284 6.09375,6.09375 0,3.36535 -2.73446,6.09375 -6.09375,6.09375 -3.35929,0 -6.0625,-2.7284 -6.0625,-6.09375 0,-3.36535 2.70321,-6.09375 6.0625,-6.09375 z"
+ id="path3844"
+ inkscape:connector-curvature="0" />
+ </g>
+ <path
+ sodipodi:type="arc"
+ style="fill:url(#radialGradient3838-8);fill-opacity:1;stroke:none"
+ id="path3813"
+ sodipodi:cx="223.62251"
+ sodipodi:cy="147.08873"
+ sodipodi:rx="11.136931"
+ sodipodi:ry="9.0156116"
+ d="m 234.75944,147.08873 c 0,4.97918 -4.98617,9.01561 -11.13693,9.01561 -6.15075,0 -11.13693,-4.03643 -11.13693,-9.01561 0,-4.97918 4.98618,-9.01561 11.13693,-9.01561 6.15076,0 11.13693,4.03643 11.13693,9.01561 z"
+ transform="matrix(1.2054549,0,0,1.1341085,-99.371969,741.25595)" />
+ </g>
+</svg>
diff --git a/askbot/skins/default/media/images/summary-background.png b/askbot/media/images/summary-background.png
index 28a6a398..28a6a398 100644
--- a/askbot/skins/default/media/images/summary-background.png
+++ b/askbot/media/images/summary-background.png
Binary files differ
diff --git a/askbot/skins/default/media/images/tag-left.png b/askbot/media/images/tag-left.png
index 23369d98..23369d98 100644
--- a/askbot/skins/default/media/images/tag-left.png
+++ b/askbot/media/images/tag-left.png
Binary files differ
diff --git a/askbot/skins/default/media/images/tag-right.png b/askbot/media/images/tag-right.png
index 05a62aba..05a62aba 100644
--- a/askbot/skins/default/media/images/tag-right.png
+++ b/askbot/media/images/tag-right.png
Binary files differ
diff --git a/askbot/skins/default/media/images/tips.png b/askbot/media/images/tips.png
index 7e8aafdf..7e8aafdf 100644
--- a/askbot/skins/default/media/images/tips.png
+++ b/askbot/media/images/tips.png
Binary files differ
diff --git a/askbot/media/images/unpublish.png b/askbot/media/images/unpublish.png
new file mode 100644
index 00000000..bfac25b1
--- /dev/null
+++ b/askbot/media/images/unpublish.png
Binary files differ
diff --git a/askbot/skins/default/media/images/view-background.png b/askbot/media/images/view-background.png
index 5e951f40..5e951f40 100644
--- a/askbot/skins/default/media/images/view-background.png
+++ b/askbot/media/images/view-background.png
Binary files differ
diff --git a/askbot/skins/common/media/images/vote-accepted-on.png b/askbot/media/images/vote-accepted-on.png
index 2026f3bc..2026f3bc 100755
--- a/askbot/skins/common/media/images/vote-accepted-on.png
+++ b/askbot/media/images/vote-accepted-on.png
Binary files differ
diff --git a/askbot/skins/common/media/images/vote-accepted.png b/askbot/media/images/vote-accepted.png
index ecd18551..ecd18551 100755
--- a/askbot/skins/common/media/images/vote-accepted.png
+++ b/askbot/media/images/vote-accepted.png
Binary files differ
diff --git a/askbot/skins/default/media/images/vote-arrow-down-new.png b/askbot/media/images/vote-arrow-down-new.png
index f2a28aea..f2a28aea 100644
--- a/askbot/skins/default/media/images/vote-arrow-down-new.png
+++ b/askbot/media/images/vote-arrow-down-new.png
Binary files differ
diff --git a/askbot/skins/default/media/images/vote-arrow-down-on-new.png b/askbot/media/images/vote-arrow-down-on-new.png
index 2127bf7d..2127bf7d 100644
--- a/askbot/skins/default/media/images/vote-arrow-down-on-new.png
+++ b/askbot/media/images/vote-arrow-down-on-new.png
Binary files differ
diff --git a/askbot/skins/common/media/images/vote-arrow-down-on.png b/askbot/media/images/vote-arrow-down-on.png
index 048dbb44..048dbb44 100755
--- a/askbot/skins/common/media/images/vote-arrow-down-on.png
+++ b/askbot/media/images/vote-arrow-down-on.png
Binary files differ
diff --git a/askbot/skins/common/media/images/vote-arrow-down.png b/askbot/media/images/vote-arrow-down.png
index e4fdec0a..e4fdec0a 100755
--- a/askbot/skins/common/media/images/vote-arrow-down.png
+++ b/askbot/media/images/vote-arrow-down.png
Binary files differ
diff --git a/askbot/skins/default/media/images/vote-arrow-up-new.png b/askbot/media/images/vote-arrow-up-new.png
index cb9ea8b6..cb9ea8b6 100644
--- a/askbot/skins/default/media/images/vote-arrow-up-new.png
+++ b/askbot/media/images/vote-arrow-up-new.png
Binary files differ
diff --git a/askbot/skins/default/media/images/vote-arrow-up-on-new.png b/askbot/media/images/vote-arrow-up-on-new.png
index ef895206..ef895206 100644
--- a/askbot/skins/default/media/images/vote-arrow-up-on-new.png
+++ b/askbot/media/images/vote-arrow-up-on-new.png
Binary files differ
diff --git a/askbot/skins/common/media/images/vote-arrow-up-on.png b/askbot/media/images/vote-arrow-up-on.png
index 56ad0c25..56ad0c25 100755
--- a/askbot/skins/common/media/images/vote-arrow-up-on.png
+++ b/askbot/media/images/vote-arrow-up-on.png
Binary files differ
diff --git a/askbot/skins/common/media/images/vote-arrow-up.png b/askbot/media/images/vote-arrow-up.png
index 6e9a51c7..6e9a51c7 100755
--- a/askbot/skins/common/media/images/vote-arrow-up.png
+++ b/askbot/media/images/vote-arrow-up.png
Binary files differ
diff --git a/askbot/skins/default/media/images/vote-background.png b/askbot/media/images/vote-background.png
index 0e1ded6e..0e1ded6e 100644
--- a/askbot/skins/default/media/images/vote-background.png
+++ b/askbot/media/images/vote-background.png
Binary files differ
diff --git a/askbot/skins/common/media/images/vote-favorite-off.png b/askbot/media/images/vote-favorite-off.png
index c1bef074..c1bef074 100755
--- a/askbot/skins/common/media/images/vote-favorite-off.png
+++ b/askbot/media/images/vote-favorite-off.png
Binary files differ
diff --git a/askbot/skins/common/media/images/vote-favorite-on.png b/askbot/media/images/vote-favorite-on.png
index 1f9c14ab..1f9c14ab 100755
--- a/askbot/skins/common/media/images/vote-favorite-on.png
+++ b/askbot/media/images/vote-favorite-on.png
Binary files differ
diff --git a/askbot/skins/common/media/images/wiki.png b/askbot/media/images/wiki.png
index 06d487f3..06d487f3 100644
--- a/askbot/skins/common/media/images/wiki.png
+++ b/askbot/media/images/wiki.png
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/aol.gif b/askbot/media/jquery-openid/images/aol.gif
index 24d1e152..24d1e152 100755
--- a/askbot/skins/common/media/jquery-openid/images/aol.gif
+++ b/askbot/media/jquery-openid/images/aol.gif
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/blogger-1.png b/askbot/media/jquery-openid/images/blogger-1.png
index 8b360ea5..8b360ea5 100755
--- a/askbot/skins/common/media/jquery-openid/images/blogger-1.png
+++ b/askbot/media/jquery-openid/images/blogger-1.png
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/blogger.ico b/askbot/media/jquery-openid/images/blogger.ico
index 1b9730b0..1b9730b0 100755
--- a/askbot/skins/common/media/jquery-openid/images/blogger.ico
+++ b/askbot/media/jquery-openid/images/blogger.ico
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/claimid-0.png b/askbot/media/jquery-openid/images/claimid-0.png
index 4a0ea1b3..4a0ea1b3 100755
--- a/askbot/skins/common/media/jquery-openid/images/claimid-0.png
+++ b/askbot/media/jquery-openid/images/claimid-0.png
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/claimid.ico b/askbot/media/jquery-openid/images/claimid.ico
index 2b80f491..2b80f491 100755
--- a/askbot/skins/common/media/jquery-openid/images/claimid.ico
+++ b/askbot/media/jquery-openid/images/claimid.ico
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/facebook.gif b/askbot/media/jquery-openid/images/facebook.gif
index c5586455..c5586455 100755
--- a/askbot/skins/common/media/jquery-openid/images/facebook.gif
+++ b/askbot/media/jquery-openid/images/facebook.gif
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/flickr.ico b/askbot/media/jquery-openid/images/flickr.ico
index 11f6e07f..11f6e07f 100755
--- a/askbot/skins/common/media/jquery-openid/images/flickr.ico
+++ b/askbot/media/jquery-openid/images/flickr.ico
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/flickr.png b/askbot/media/jquery-openid/images/flickr.png
index 142405a6..142405a6 100755
--- a/askbot/skins/common/media/jquery-openid/images/flickr.png
+++ b/askbot/media/jquery-openid/images/flickr.png
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/google.gif b/askbot/media/jquery-openid/images/google.gif
index 65395365..65395365 100755
--- a/askbot/skins/common/media/jquery-openid/images/google.gif
+++ b/askbot/media/jquery-openid/images/google.gif
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/identica.png b/askbot/media/jquery-openid/images/identica.png
index 2b607db1..2b607db1 100644
--- a/askbot/skins/common/media/jquery-openid/images/identica.png
+++ b/askbot/media/jquery-openid/images/identica.png
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/linkedin.gif b/askbot/media/jquery-openid/images/linkedin.gif
index 36e049ac..36e049ac 100644
--- a/askbot/skins/common/media/jquery-openid/images/linkedin.gif
+++ b/askbot/media/jquery-openid/images/linkedin.gif
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/livejournal-1.png b/askbot/media/jquery-openid/images/livejournal-1.png
index e6436081..e6436081 100755
--- a/askbot/skins/common/media/jquery-openid/images/livejournal-1.png
+++ b/askbot/media/jquery-openid/images/livejournal-1.png
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/livejournal.ico b/askbot/media/jquery-openid/images/livejournal.ico
index f3d21ec5..f3d21ec5 100755
--- a/askbot/skins/common/media/jquery-openid/images/livejournal.ico
+++ b/askbot/media/jquery-openid/images/livejournal.ico
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/myopenid-2.png b/askbot/media/jquery-openid/images/myopenid-2.png
index f64fb8e8..f64fb8e8 100755
--- a/askbot/skins/common/media/jquery-openid/images/myopenid-2.png
+++ b/askbot/media/jquery-openid/images/myopenid-2.png
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/myopenid.ico b/askbot/media/jquery-openid/images/myopenid.ico
index ceb06e6a..ceb06e6a 100755
--- a/askbot/skins/common/media/jquery-openid/images/myopenid.ico
+++ b/askbot/media/jquery-openid/images/myopenid.ico
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/openid-inputicon.gif b/askbot/media/jquery-openid/images/openid-inputicon.gif
index cde836c8..cde836c8 100755
--- a/askbot/skins/common/media/jquery-openid/images/openid-inputicon.gif
+++ b/askbot/media/jquery-openid/images/openid-inputicon.gif
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/openid.gif b/askbot/media/jquery-openid/images/openid.gif
index 19eb7c6f..19eb7c6f 100755
--- a/askbot/skins/common/media/jquery-openid/images/openid.gif
+++ b/askbot/media/jquery-openid/images/openid.gif
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/openidico.png b/askbot/media/jquery-openid/images/openidico.png
index ab622669..ab622669 100755
--- a/askbot/skins/common/media/jquery-openid/images/openidico.png
+++ b/askbot/media/jquery-openid/images/openidico.png
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/openidico16.png b/askbot/media/jquery-openid/images/openidico16.png
index ad718ac5..ad718ac5 100755
--- a/askbot/skins/common/media/jquery-openid/images/openidico16.png
+++ b/askbot/media/jquery-openid/images/openidico16.png
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/technorati-1.png b/askbot/media/jquery-openid/images/technorati-1.png
index f7195240..f7195240 100755
--- a/askbot/skins/common/media/jquery-openid/images/technorati-1.png
+++ b/askbot/media/jquery-openid/images/technorati-1.png
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/technorati.ico b/askbot/media/jquery-openid/images/technorati.ico
index fa1083c1..fa1083c1 100755
--- a/askbot/skins/common/media/jquery-openid/images/technorati.ico
+++ b/askbot/media/jquery-openid/images/technorati.ico
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/twitter.gif b/askbot/media/jquery-openid/images/twitter.gif
index 173cace1..173cace1 100644
--- a/askbot/skins/common/media/jquery-openid/images/twitter.gif
+++ b/askbot/media/jquery-openid/images/twitter.gif
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/verisign-2.png b/askbot/media/jquery-openid/images/verisign-2.png
index c1467008..c1467008 100755
--- a/askbot/skins/common/media/jquery-openid/images/verisign-2.png
+++ b/askbot/media/jquery-openid/images/verisign-2.png
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/verisign.ico b/askbot/media/jquery-openid/images/verisign.ico
index 3953af93..3953af93 100755
--- a/askbot/skins/common/media/jquery-openid/images/verisign.ico
+++ b/askbot/media/jquery-openid/images/verisign.ico
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/vidoop.ico b/askbot/media/jquery-openid/images/vidoop.ico
index bbd9a0d5..bbd9a0d5 100755
--- a/askbot/skins/common/media/jquery-openid/images/vidoop.ico
+++ b/askbot/media/jquery-openid/images/vidoop.ico
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/vidoop.png b/askbot/media/jquery-openid/images/vidoop.png
index 032c9e98..032c9e98 100755
--- a/askbot/skins/common/media/jquery-openid/images/vidoop.png
+++ b/askbot/media/jquery-openid/images/vidoop.png
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/wordpress.ico b/askbot/media/jquery-openid/images/wordpress.ico
index 31b7d2c2..31b7d2c2 100755
--- a/askbot/skins/common/media/jquery-openid/images/wordpress.ico
+++ b/askbot/media/jquery-openid/images/wordpress.ico
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/wordpress.png b/askbot/media/jquery-openid/images/wordpress.png
index ee29f0cf..ee29f0cf 100755
--- a/askbot/skins/common/media/jquery-openid/images/wordpress.png
+++ b/askbot/media/jquery-openid/images/wordpress.png
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/images/yahoo.gif b/askbot/media/jquery-openid/images/yahoo.gif
index 614910a9..614910a9 100755
--- a/askbot/skins/common/media/jquery-openid/images/yahoo.gif
+++ b/askbot/media/jquery-openid/images/yahoo.gif
Binary files differ
diff --git a/askbot/skins/common/media/jquery-openid/jquery.openid.js b/askbot/media/jquery-openid/jquery.openid.js
index 249413b9..249413b9 100644
--- a/askbot/skins/common/media/jquery-openid/jquery.openid.js
+++ b/askbot/media/jquery-openid/jquery.openid.js
diff --git a/askbot/skins/common/media/jquery-openid/openid.css b/askbot/media/jquery-openid/openid.css
index 9a1db85f..9a1db85f 100644
--- a/askbot/skins/common/media/jquery-openid/openid.css
+++ b/askbot/media/jquery-openid/openid.css
diff --git a/askbot/media/js/autocompleter.js b/askbot/media/js/autocompleter.js
new file mode 100644
index 00000000..8121d2ea
--- /dev/null
+++ b/askbot/media/js/autocompleter.js
@@ -0,0 +1,794 @@
+/**
+ * AutoCompleter Object, refactored closure style from
+ * jQuery autocomplete plugin
+ * @param {Object=} options Settings
+ * @constructor
+ */
+var AutoCompleter = function(options) {
+
+ /**
+ * Default options for autocomplete plugin
+ */
+ var defaults = {
+ promptText: '',
+ autocompleteMultiple: true,
+ multipleSeparator: ' ',//a single character
+ inputClass: 'acInput',
+ loadingClass: 'acLoading',
+ resultsClass: 'acResults',
+ selectClass: 'acSelect',
+ queryParamName: 'q',
+ limitParamName: 'limit',
+ extraParams: {},
+ lineSeparator: '\n',
+ cellSeparator: '|',
+ minChars: 2,
+ maxItemsToShow: 10,
+ delay: 400,
+ useCache: true,
+ maxCacheLength: 10,
+ matchSubset: true,
+ matchCase: false,
+ matchInside: true,
+ mustMatch: false,
+ preloadData: false,
+ selectFirst: false,
+ stopCharRegex: /\s+/,
+ selectOnly: false,
+ formatItem: null, // TBD
+ onItemSelect: false,
+ autoFill: false,
+ filterResults: true,
+ sortResults: true,
+ sortFunction: false,
+ onNoMatch: false
+ };
+
+ /**
+ * Options dictionary
+ * @type Object
+ * @private
+ */
+ this.options = $.extend({}, defaults, options);
+
+ /**
+ * Cached data
+ * @type Object
+ * @private
+ */
+ this.cacheData_ = {};
+
+ /**
+ * Number of cached data items
+ * @type number
+ * @private
+ */
+ this.cacheLength_ = 0;
+
+ /**
+ * Class name to mark selected item
+ * @type string
+ * @private
+ */
+ this.selectClass_ = 'jquery-autocomplete-selected-item';
+
+ /**
+ * Handler to activation timeout
+ * @type ?number
+ * @private
+ */
+ this.keyTimeout_ = null;
+
+ /**
+ * Last key pressed in the input field (store for behavior)
+ * @type ?number
+ * @private
+ */
+ this.lastKeyPressed_ = null;
+
+ /**
+ * Last value processed by the autocompleter
+ * @type ?string
+ * @private
+ */
+ this.lastProcessedValue_ = null;
+
+ /**
+ * Last value selected by the user
+ * @type ?string
+ * @private
+ */
+ this.lastSelectedValue_ = null;
+
+ /**
+ * Is this autocompleter active?
+ * @type boolean
+ * @private
+ */
+ this.active_ = false;
+
+ /**
+ * Is it OK to finish on blur?
+ * @type boolean
+ * @private
+ */
+ this.finishOnBlur_ = true;
+
+ this.options.minChars = parseInt(this.options.minChars, 10);
+ if (isNaN(this.options.minChars) || this.options.minChars < 1) {
+ this.options.minChars = 2;
+ }
+
+ this.options.maxItemsToShow = parseInt(this.options.maxItemsToShow, 10);
+ if (isNaN(this.options.maxItemsToShow) || this.options.maxItemsToShow < 1) {
+ this.options.maxItemsToShow = 10;
+ }
+
+ this.options.maxCacheLength = parseInt(this.options.maxCacheLength, 10);
+ if (isNaN(this.options.maxCacheLength) || this.options.maxCacheLength < 1) {
+ this.options.maxCacheLength = 10;
+ }
+
+ if (this.options['preloadData'] === true){
+ this.fetchRemoteData('', function(){});
+ }
+};
+inherits(AutoCompleter, WrappedElement);
+
+AutoCompleter.prototype.decorate = function(element){
+
+ /**
+ * Init DOM elements repository
+ */
+ this._element = element;
+
+ /**
+ * Switch off the native autocomplete
+ */
+ this._element.attr('autocomplete', 'off');
+
+ /**
+ * Set prompt text
+ */
+ this.setPrompt();
+
+ /**
+ * Create DOM element to hold results
+ */
+ this._results = $('<div></div>').hide();
+ if (this.options.resultsClass) {
+ this._results.addClass(this.options.resultsClass);
+ }
+ this._results.css({
+ position: 'absolute'
+ });
+ $('body').append(this._results);
+
+ this.setEventHandlers();
+};
+
+AutoCompleter.prototype.setPrompt = function() {
+ this._element.val(this.options['promptText']);
+ this._element.addClass('prompt');
+};
+
+AutoCompleter.prototype.removePrompt = function() {
+ if (this._element.hasClass('prompt')) {
+ this._element.removeClass('prompt');
+ var val = this._element.val();
+ if (val === this.options['promptText']) {
+ this._element.val('');
+ }
+ }
+};
+
+AutoCompleter.prototype.setEventHandlers = function(){
+ /**
+ * Shortcut to self
+ */
+ var self = this;
+
+ /**
+ * Attach keyboard monitoring to $elem
+ */
+ self._element.keydown(function(e) {
+
+ self.removePrompt();
+
+ self.lastKeyPressed_ = e.keyCode;
+ switch(self.lastKeyPressed_) {
+
+ case 38: // up
+ e.preventDefault();
+ if (self.active_) {
+ self.focusPrev();
+ } else {
+ self.activate();
+ }
+ return false;
+ break;
+
+ case 40: // down
+ e.preventDefault();
+ if (self.active_) {
+ self.focusNext();
+ } else {
+ self.activate();
+ }
+ return false;
+ break;
+
+ case 9: // tab
+ case 13: // return
+ if (self.active_) {
+ e.preventDefault();
+ self.selectCurrent();
+ return false;
+ }
+ break;
+
+ case 27: // escape
+ if ($.trim(self._element.val()) === '') {
+ self.setPrompt();
+ return false;
+ }
+ if (self.active_) {
+ e.preventDefault();
+ self.finish();
+ return false;
+ }
+ break;
+
+ default:
+ self.activate();
+
+ }
+ });
+ self._element.blur(function() {
+ if (self.finishOnBlur_) {
+ setTimeout(function() { self.finish(); }, 200);
+ }
+ });
+};
+
+AutoCompleter.prototype.position = function() {
+ var offset = this._element.offset();
+ this._results.css({
+ top: offset.top + this._element.outerHeight(),
+ left: offset.left
+ });
+};
+
+AutoCompleter.prototype.cacheRead = function(filter) {
+ var filterLength, searchLength, search, maxPos, pos;
+ if (this.options.useCache) {
+ filter = String(filter);
+ filterLength = filter.length;
+ if (this.options.matchSubset) {
+ searchLength = 1;
+ } else {
+ searchLength = filterLength;
+ }
+ while (searchLength <= filterLength) {
+ if (this.options.matchInside) {
+ maxPos = filterLength - searchLength;
+ } else {
+ maxPos = 0;
+ }
+ pos = 0;
+ while (pos <= maxPos) {
+ search = filter.substr(0, searchLength);
+ if (this.cacheData_[search] !== undefined) {
+ return this.cacheData_[search];
+ }
+ pos++;
+ }
+ searchLength++;
+ }
+ }
+ return false;
+};
+
+AutoCompleter.prototype.cacheWrite = function(filter, data) {
+ if (this.options.useCache) {
+ if (this.cacheLength_ >= this.options.maxCacheLength) {
+ this.cacheFlush();
+ }
+ filter = String(filter);
+ if (this.cacheData_[filter] !== undefined) {
+ this.cacheLength_++;
+ }
+ return this.cacheData_[filter] = data;
+ }
+ return false;
+};
+
+AutoCompleter.prototype.cacheFlush = function() {
+ this.cacheData_ = {};
+ this.cacheLength_ = 0;
+};
+
+AutoCompleter.prototype.callHook = function(hook, data) {
+ var f = this.options[hook];
+ if (f && $.isFunction(f)) {
+ return f(data, this);
+ }
+ return false;
+};
+
+AutoCompleter.prototype.activate = function() {
+ var self = this;
+ var activateNow = function() {
+ self.activateNow();
+ };
+ var delay = parseInt(this.options.delay, 10);
+ if (isNaN(delay) || delay <= 0) {
+ delay = 250;
+ }
+ if (this.keyTimeout_) {
+ clearTimeout(this.keyTimeout_);
+ }
+ this.keyTimeout_ = setTimeout(activateNow, delay);
+};
+
+AutoCompleter.prototype.activateNow = function() {
+ var value = this.getValue();
+ if (value !== this.lastProcessedValue_ && value !== this.lastSelectedValue_) {
+ if (value.length >= this.options.minChars) {
+ this.active_ = true;
+ this.lastProcessedValue_ = value;
+ this.fetchData(value);
+ }
+ }
+};
+
+AutoCompleter.prototype.fetchData = function(value) {
+ if (this.options.data) {
+ this.filterAndShowResults(this.options.data, value);
+ } else {
+ var self = this;
+ this.fetchRemoteData(value, function(remoteData) {
+ self.filterAndShowResults(remoteData, value);
+ });
+ }
+};
+
+AutoCompleter.prototype.fetchRemoteData = function(filter, callback) {
+ var data = this.cacheRead(filter);
+ if (data) {
+ callback(data);
+ } else {
+ var self = this;
+ if (this._element){
+ this._element.addClass(this.options.loadingClass);
+ }
+ var ajaxCallback = function(data) {
+ var parsed = false;
+ if (data !== false) {
+ parsed = self.parseRemoteData(data);
+ self.options.data = parsed;//cache data forever - E.F.
+ self.cacheWrite(filter, parsed);
+ }
+ if (self._element){
+ self._element.removeClass(self.options.loadingClass);
+ }
+ callback(parsed);
+ };
+ $.ajax({
+ url: this.makeUrl(filter),
+ success: ajaxCallback,
+ error: function() {
+ ajaxCallback(false);
+ }
+ });
+ }
+};
+
+AutoCompleter.prototype.setOption = function(name, value){
+ this.options[name] = value;
+};
+
+AutoCompleter.prototype.setExtraParam = function(name, value) {
+ var index = $.trim(String(name));
+ if (index) {
+ if (!this.options.extraParams) {
+ this.options.extraParams = {};
+ }
+ if (this.options.extraParams[index] !== value) {
+ this.options.extraParams[index] = value;
+ this.cacheFlush();
+ }
+ }
+};
+
+AutoCompleter.prototype.makeUrl = function(param) {
+ var self = this;
+ var url = this.options.url;
+ var params = $.extend({}, this.options.extraParams);
+ // If options.queryParamName === false, append query to url
+ // instead of using a GET parameter
+ if (this.options.queryParamName === false) {
+ url += encodeURIComponent(param);
+ } else {
+ params[this.options.queryParamName] = param;
+ }
+
+ if (this.options.limitParamName && this.options.maxItemsToShow) {
+ params[this.options.limitParamName] = this.options.maxItemsToShow;
+ }
+
+ var urlAppend = [];
+ $.each(params, function(index, value) {
+ urlAppend.push(self.makeUrlParam(index, value));
+ });
+ if (urlAppend.length) {
+ url += url.indexOf('?') == -1 ? '?' : '&';
+ url += urlAppend.join('&');
+ }
+ return url;
+};
+
+AutoCompleter.prototype.makeUrlParam = function(name, value) {
+ return String(name) + '=' + encodeURIComponent(value);
+};
+
+/**
+ * Sanitize CR and LF, then split into lines
+ */
+AutoCompleter.prototype.splitText = function(text) {
+ return String(text).replace(/(\r\n|\r|\n)/g, '\n').split(this.options.lineSeparator);
+};
+
+AutoCompleter.prototype.parseRemoteData = function(remoteData) {
+ var value, lines, i, j, data;
+ var results = [];
+ var lines = this.splitText(remoteData);
+ for (i = 0; i < lines.length; i++) {
+ var line = lines[i].split(this.options.cellSeparator);
+ data = [];
+ for (j = 0; j < line.length; j++) {
+ data.push(unescape(line[j]));
+ }
+ value = data.shift();
+ results.push({ value: unescape(value), data: data });
+ }
+ return results;
+};
+
+AutoCompleter.prototype.filterAndShowResults = function(results, filter) {
+ this.showResults(this.filterResults(results, filter), filter);
+};
+
+AutoCompleter.prototype.filterResults = function(results, filter) {
+
+ var filtered = [];
+ var value, data, i, result, type, include;
+ var regex, pattern, testValue;
+
+ for (i = 0; i < results.length; i++) {
+ result = results[i];
+ type = typeof result;
+ if (type === 'string') {
+ value = result;
+ data = {};
+ } else if ($.isArray(result)) {
+ value = result[0];
+ data = result.slice(1);
+ } else if (type === 'object') {
+ value = result.value;
+ data = result.data;
+ }
+ value = String(value);
+ if (value > '') {
+ if (typeof data !== 'object') {
+ data = {};
+ }
+ if (this.options.filterResults) {
+ pattern = String(filter);
+ testValue = String(value);
+ if (!this.options.matchCase) {
+ pattern = pattern.toLowerCase();
+ testValue = testValue.toLowerCase();
+ }
+ include = testValue.indexOf(pattern);
+ if (this.options.matchInside) {
+ include = include > -1;
+ } else {
+ include = include === 0;
+ }
+ } else {
+ include = true;
+ }
+ if (include) {
+ filtered.push({ value: value, data: data });
+ }
+ }
+ }
+
+ if (this.options.sortResults) {
+ filtered = this.sortResults(filtered, filter);
+ }
+
+ if (this.options.maxItemsToShow > 0 && this.options.maxItemsToShow < filtered.length) {
+ filtered.length = this.options.maxItemsToShow;
+ }
+
+ return filtered;
+
+};
+
+AutoCompleter.prototype.sortResults = function(results, filter) {
+ var self = this;
+ var sortFunction = this.options.sortFunction;
+ if (!$.isFunction(sortFunction)) {
+ sortFunction = function(a, b, f) {
+ return self.sortValueAlpha(a, b, f);
+ };
+ }
+ results.sort(function(a, b) {
+ return sortFunction(a, b, filter);
+ });
+ return results;
+};
+
+AutoCompleter.prototype.sortValueAlpha = function(a, b, filter) {
+ a = String(a.value);
+ b = String(b.value);
+ if (!this.options.matchCase) {
+ a = a.toLowerCase();
+ b = b.toLowerCase();
+ }
+ if (a > b) {
+ return 1;
+ }
+ if (a < b) {
+ return -1;
+ }
+ return 0;
+};
+
+AutoCompleter.prototype.showResults = function(results, filter) {
+ var self = this;
+ var $ul = $('<ul></ul>');
+ var i, result, $li, extraWidth, first = false, $first = false;
+ var numResults = results.length;
+ for (i = 0; i < numResults; i++) {
+ result = results[i];
+ $li = $('<li>' + this.showResult(result.value, result.data) + '</li>');
+ $li.data('value', result.value);
+ $li.data('data', result.data);
+ $li.click(function() {
+ var $this = $(this);
+ self.selectItem($this);
+ }).mousedown(function() {
+ self.finishOnBlur_ = false;
+ }).mouseup(function() {
+ self.finishOnBlur_ = true;
+ });
+ $ul.append($li);
+ if (first === false) {
+ first = String(result.value);
+ $first = $li;
+ $li.addClass(this.options.firstItemClass);
+ }
+ if (i == numResults - 1) {
+ $li.addClass(this.options.lastItemClass);
+ }
+ }
+
+ // Alway recalculate position before showing since window size or
+ // input element location may have changed. This fixes #14
+ this.position();
+
+ this._results.html($ul).show();
+ extraWidth = this._results.outerWidth() - this._results.width();
+ this._results.width(this._element.outerWidth() - extraWidth);
+ $('li', this._results).hover(
+ function() { self.focusItem(this); },
+ function() { /* void */ }
+ );
+ if (this.autoFill(first, filter)) {
+ this.focusItem($first);
+ }
+};
+
+AutoCompleter.prototype.showResult = function(value, data) {
+ if ($.isFunction(this.options.showResult)) {
+ return this.options.showResult(value, data);
+ } else {
+ return value;
+ }
+};
+
+AutoCompleter.prototype.autoFill = function(value, filter) {
+ var lcValue, lcFilter, valueLength, filterLength;
+ if (this.options.autoFill && this.lastKeyPressed_ != 8) {
+ lcValue = String(value).toLowerCase();
+ lcFilter = String(filter).toLowerCase();
+ valueLength = value.length;
+ filterLength = filter.length;
+ if (lcValue.substr(0, filterLength) === lcFilter) {
+ this._element.val(value);
+ this.selectRange(filterLength, valueLength);
+ return true;
+ }
+ }
+ return false;
+};
+
+AutoCompleter.prototype.focusNext = function() {
+ this.focusMove(+1);
+};
+
+AutoCompleter.prototype.focusPrev = function() {
+ this.focusMove(-1);
+};
+
+AutoCompleter.prototype.focusMove = function(modifier) {
+ var i, $items = $('li', this._results);
+ modifier = parseInt(modifier, 10);
+ for (var i = 0; i < $items.length; i++) {
+ if ($($items[i]).hasClass(this.selectClass_)) {
+ this.focusItem(i + modifier);
+ return;
+ }
+ }
+ this.focusItem(0);
+};
+
+AutoCompleter.prototype.focusItem = function(item) {
+ var $item, $items = $('li', this._results);
+ if ($items.length) {
+ $items.removeClass(this.selectClass_).removeClass(this.options.selectClass);
+ if (typeof item === 'number') {
+ item = parseInt(item, 10);
+ if (item < 0) {
+ item = 0;
+ } else if (item >= $items.length) {
+ item = $items.length - 1;
+ }
+ $item = $($items[item]);
+ } else {
+ $item = $(item);
+ }
+ if ($item) {
+ $item.addClass(this.selectClass_).addClass(this.options.selectClass);
+ }
+ }
+};
+
+AutoCompleter.prototype.selectCurrent = function() {
+ var $item = $('li.' + this.selectClass_, this._results);
+ if ($item.length == 1) {
+ this.selectItem($item);
+ } else {
+ this.finish();
+ }
+};
+
+AutoCompleter.prototype.selectItem = function($li) {
+ var value = $li.data('value');
+ var data = $li.data('data');
+ var displayValue = this.displayValue(value, data);
+ this.lastProcessedValue_ = displayValue;
+ this.lastSelectedValue_ = displayValue;
+
+ this.setValue(displayValue);
+
+ this.setCaret(displayValue.length);
+ this.callHook('onItemSelect', { value: value, data: data });
+ this.finish();
+};
+
+/**
+ * @return {boolean} true if the symbol matches something that is
+ * considered content and false otherwise
+ * @param {string} symbol - a single char string
+ */
+AutoCompleter.prototype.isContentChar = function(symbol){
+ if (symbol.match(this.options['stopCharRegex'])){
+ return false;
+ } else if (symbol === this.options['multipleSeparator']){
+ return false;
+ } else {
+ return true;
+ }
+};
+
+/**
+ * takes value from the input box
+ * and saves _selection_start and _selection_end coordinates
+ * respects settings autocompleteMultiple and
+ * multipleSeparator
+ * @return {string} the current word in the
+ * autocompletable word
+ */
+AutoCompleter.prototype.getValue = function(){
+ var sel = this._element.getSelection();
+ var text = this._element.val();
+ var pos = sel.start;//estimated start
+ //find real start
+ var start = pos;
+ for (cpos = pos; cpos >= 0; cpos = cpos - 1){
+ if (cpos === text.length){
+ continue;
+ }
+ var symbol = text.charAt(cpos);
+ if (!this.isContentChar(symbol)){
+ break;
+ }
+ start = cpos;
+ }
+ //find real end
+ var end = pos;
+ for (cpos = pos; cpos < text.length; cpos = cpos + 1){
+ if (cpos === 0){
+ continue;
+ }
+ var symbol = text.charAt(cpos);
+ if (!this.isContentChar(symbol)){
+ break;
+ }
+ end = cpos;
+ }
+ this._selection_start = start;
+ this._selection_end = end;
+ return text.substring(start, end);
+}
+
+/**
+ * sets value of the input box
+ * by replacing the previous selection
+ * with the value from the autocompleter
+ */
+AutoCompleter.prototype.setValue = function(val){
+ var prefix = this._element.val().substring(0, this._selection_start);
+ var postfix = this._element.val().substring(this._selection_end + 1);
+ this._element.val(prefix + val + postfix);
+};
+
+AutoCompleter.prototype.displayValue = function(value, data) {
+ if ($.isFunction(this.options.displayValue)) {
+ return this.options.displayValue(value, data);
+ } else {
+ return value;
+ }
+};
+
+AutoCompleter.prototype.finish = function() {
+ if (this.keyTimeout_) {
+ clearTimeout(this.keyTimeout_);
+ }
+ if (this._element.val() !== this.lastSelectedValue_) {
+ if (this.options.mustMatch) {
+ this._element.val('');
+ }
+ this.callHook('onNoMatch');
+ }
+ this._results.hide();
+ this.lastKeyPressed_ = null;
+ this.lastProcessedValue_ = null;
+ if (this.active_) {
+ this.callHook('onFinish');
+ }
+ this.active_ = false;
+};
+
+AutoCompleter.prototype.selectRange = function(start, end) {
+ var input = this._element.get(0);
+ if (input.setSelectionRange) {
+ input.focus();
+ input.setSelectionRange(start, end);
+ } else if (this.createTextRange) {
+ var range = this.createTextRange();
+ range.collapse(true);
+ range.moveEnd('character', end);
+ range.moveStart('character', start);
+ range.select();
+ }
+};
+
+AutoCompleter.prototype.setCaret = function(pos) {
+ this.selectRange(pos, pos);
+};
+
diff --git a/askbot/skins/common/media/js/compress.bat b/askbot/media/js/compress.bat
index 53d72588..53d72588 100644
--- a/askbot/skins/common/media/js/compress.bat
+++ b/askbot/media/js/compress.bat
diff --git a/askbot/media/js/editor.js b/askbot/media/js/editor.js
new file mode 100644
index 00000000..25fdaa7e
--- /dev/null
+++ b/askbot/media/js/editor.js
@@ -0,0 +1,80 @@
+/*
+ jQuery TextAreaResizer plugin
+ Created on 17th January 2008 by Ryan O'Dell
+ Version 1.0.4
+*/(function($){var textarea,staticOffset;var iLastMousePos=0;var iMin=32;var grip;$.fn.TextAreaResizer=function(){return this.each(function(){textarea=$(this).addClass('processed'),staticOffset=null;$(this).wrap('<div class="resizable-textarea"><span></span></div>').parent().append($('<div class="grippie"></div>').bind("mousedown",{el:this},startDrag));var grippie=$('div.grippie',$(this).parent())[0];grippie.style.marginRight=(grippie.offsetWidth-$(this)[0].offsetWidth)+'px'})};function startDrag(e){textarea=$(e.data.el);textarea.blur();iLastMousePos=mousePosition(e).y;staticOffset=textarea.height()-iLastMousePos;textarea.css('opacity',0.25);$(document).mousemove(performDrag).mouseup(endDrag);return false}function performDrag(e){var iThisMousePos=mousePosition(e).y;var iMousePos=staticOffset+iThisMousePos;if(iLastMousePos>=(iThisMousePos)){iMousePos-=5}iLastMousePos=iThisMousePos;iMousePos=Math.max(iMin,iMousePos);textarea.height(iMousePos+'px');if(iMousePos<iMin){endDrag(e)}return false}function endDrag(e){$(document).unbind('mousemove',performDrag).unbind('mouseup',endDrag);textarea.css('opacity',1);textarea.focus();textarea=null;staticOffset=null;iLastMousePos=0}function mousePosition(e){return{x:e.clientX+document.documentElement.scrollLeft,y:e.clientY+document.documentElement.scrollTop}}})(jQuery);
+/*
+ * TypeWatch 2.0 - Original by Denny Ferrassoli / Refactored by Charles Christolini
+ * Copyright(c) 2007 Denny Ferrassoli - DennyDotNet.com
+ * Coprright(c) 2008 Charles Christolini - BinaryPie.com
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+*/(function(jQuery){jQuery.fn.typeWatch=function(o){var options=jQuery.extend({wait:750,callback:function(){},highlight:true,captureLength:2},o);function checkElement(timer,override){var elTxt=jQuery(timer.el).val();if((elTxt.length>options.captureLength&&elTxt.toUpperCase()!=timer.text)||(override&&elTxt.length>options.captureLength)){timer.text=elTxt.toUpperCase();timer.cb(elTxt)}};function watchElement(elem){if(elem.type.toUpperCase()=="TEXT"||elem.nodeName.toUpperCase()=="TEXTAREA"){var timer={timer:null,text:jQuery(elem).val().toUpperCase(),cb:options.callback,el:elem,wait:options.wait};if(options.highlight){jQuery(elem).focus(function(){this.select()})}var startWatch=function(evt){var timerWait=timer.wait;var overrideBool=false;if(evt.keyCode==13&&this.type.toUpperCase()=="TEXT"){timerWait=1;overrideBool=true}var timerCallbackFx=function(){checkElement(timer,overrideBool)};clearTimeout(timer.timer);timer.timer=setTimeout(timerCallbackFx,timerWait)};jQuery(elem).keydown(startWatch)}};return this.each(function(index){watchElement(this)})}})(jQuery);
+/*
+Ajax upload
+*/jQuery.extend({createUploadIframe:function(d,b){var a="jUploadFrame"+d;if(window.ActiveXObject){var c=document.createElement('<iframe id="'+a+'" name="'+a+'" />');if(typeof b=="boolean"){c.src="javascript:false"}else{if(typeof b=="string"){c.src=b}}}else{var c=document.createElement("iframe");c.id=a;c.name=a}c.style.position="absolute";c.style.top="-1000px";c.style.left="-1000px";document.body.appendChild(c);return c},createUploadForm:function(g,b){var e="jUploadForm"+g;var a="jUploadFile"+g;var d=$('<form action="" method="POST" name="'+e+'" id="'+e+'" enctype="multipart/form-data"></form>');var c=$("#"+b);var f=$(c).clone();$(c).attr("id",a);$(c).before(f);$(c).appendTo(d);$(d).css("position","absolute");$(d).css("top","-1200px");$(d).css("left","-1200px");$(d).appendTo("body");return d},ajaxFileUpload:function(k){k=jQuery.extend({},jQuery.ajaxSettings,k);var a=new Date().getTime();var b=jQuery.createUploadForm(a,k.fileElementId);var i=jQuery.createUploadIframe(a,k.secureuri);var h="jUploadFrame"+a;var j="jUploadForm"+a;if(k.global&&!jQuery.active++){jQuery.event.trigger("ajaxStart")}var c=false;var f={};if(k.global){jQuery.event.trigger("ajaxSend",[f,k])}var d=function(l){var p=document.getElementById(h);try{if(p.contentWindow){f.responseText=p.contentWindow.document.body?p.contentWindow.document.body.innerText:null;f.responseXML=p.contentWindow.document.XMLDocument?p.contentWindow.document.XMLDocument:p.contentWindow.document}else{if(p.contentDocument){f.responseText=p.contentDocument.document.body?p.contentDocument.document.body.textContent||document.body.innerText:null;f.responseXML=p.contentDocument.document.XMLDocument?p.contentDocument.document.XMLDocument:p.contentDocument.document}}}catch(o){jQuery.handleError(k,f,null,o)}if(f||l=="timeout"){c=true;var m;try{m=l!="timeout"?"success":"error";if(m!="error"){var n=jQuery.uploadHttpData(f,k.dataType);if(k.success){k.success(n,m)}if(k.global){jQuery.event.trigger("ajaxSuccess",[f,k])}}else{jQuery.handleError(k,f,m)}}catch(o){m="error";jQuery.handleError(k,f,m,o)}if(k.global){jQuery.event.trigger("ajaxComplete",[f,k])}if(k.global&&!--jQuery.active){jQuery.event.trigger("ajaxStop")}if(k.complete){k.complete(f,m)}jQuery(p).unbind();setTimeout(function(){try{$(p).remove();$(b).remove()}catch(q){jQuery.handleError(k,f,null,q)}},100);f=null}};if(k.timeout>0){setTimeout(function(){if(!c){d("timeout")}},k.timeout)}try{var b=$("#"+j);$(b).attr("action",k.url);$(b).attr("method","POST");$(b).attr("target",h);if(b.encoding){b.encoding="multipart/form-data"}else{b.enctype="multipart/form-data"}$(b).submit()}catch(g){jQuery.handleError(k,f,null,g)}if(window.attachEvent){document.getElementById(h).attachEvent("onload",d)}else{document.getElementById(h).addEventListener("load",d,false)}return{abort:function(){}}},uploadHttpData:function(r,type){var data=!type;data=type=="xml"||data?r.responseXML:r.responseText;if(type=="script"){jQuery.globalEval(data)}if(type=="json"){eval("data = "+data)}if(type=="html"){jQuery("<div>").html(data).evalScripts()}return data}});
+/**
+ * Upload call. Used only once in the wmd file upload
+ * this is used in the wmd file uploader and the
+ * askbots image and attachment upload plugins
+ * @todo refactor this code to "new style"
+ */
+function ajaxFileUpload(options) {
+
+ var spinner = options['spinner'];
+ var uploadInputId = options['uploadInputId'];
+ var urlInput = $(options['urlInput']);
+ var startUploadHandler = options['startUploadHandler'];
+
+ spinner.ajaxStart(function(){
+ $(this).show();
+ }).ajaxComplete(function(){
+ $(this).hide();
+ });
+
+ /* important!!! upload input must be loaded by id
+ * because ajaxFileUpload monkey-patches the upload form */
+ $('#' + uploadInputId).ajaxStart(function(){
+ $(this).hide();
+ }).ajaxComplete(function(){
+ $(this).show();
+ });
+
+ //var localFilePath = upload_input.val();
+ $.ajaxFileUpload({
+ url: askbot['urls']['upload'],
+ secureuri: false,
+ fileElementId: uploadInputId,
+ dataType: 'xml',
+ success: function (data, status) {
+
+ var fileURL = $(data).find('file_url').text();
+ /*
+ * hopefully a fix for the "fakepath" issue
+ * https://www.mediawiki.org/wiki/Special:Code/MediaWiki/83225
+ */
+ fileURL = fileURL.replace(/\w:.*\\(.*)$/,'$1');
+ var error = $(data).find('error').text();
+ if(error != ''){
+ alert(error);
+ } else {
+ urlInput.attr('value', fileURL);
+ }
+
+ /* re-install this as the upload extension
+ * will remove the handler to prevent double uploading
+ * this hack is a manipulation around the
+ * ajaxFileUpload jQuery plugin. */
+ $('#' + uploadInputId).unbind('change').change(startUploadHandler);
+ },
+ error: function (data, status, e) {
+ if (startUploadHandler){
+ /* re-install this as the upload extension
+ * will remove the handler to prevent double uploading */
+ $('#' + uploadInputId).unbind('change').change(startUploadHandler);
+ }
+ }
+ });
+ return false;
+};
diff --git a/askbot/skins/common/media/js/excanvas.min.js b/askbot/media/js/excanvas.min.js
index 12c74f7b..12c74f7b 100644
--- a/askbot/skins/common/media/js/excanvas.min.js
+++ b/askbot/media/js/excanvas.min.js
diff --git a/askbot/skins/common/media/js/flot-build.bat b/askbot/media/js/flot-build.bat
index f9f32cb7..f9f32cb7 100644
--- a/askbot/skins/common/media/js/flot-build.bat
+++ b/askbot/media/js/flot-build.bat
diff --git a/askbot/media/js/group_messaging.js b/askbot/media/js/group_messaging.js
new file mode 100644
index 00000000..2522f72e
--- /dev/null
+++ b/askbot/media/js/group_messaging.js
@@ -0,0 +1,672 @@
+var HideableWidget = function() {
+ Widget.call(this);
+};
+inherits(HideableWidget, Widget);
+
+HideableWidget.prototype.setState = function(state) {
+ this._state = state;
+ if (this._element) {
+ if (state === 'shown') {
+ this._element.show();
+ } else if (state === 'hidden') {
+ this._element.hide();
+ }
+ }
+};
+
+HideableWidget.prototype.onAfterShow = function() {};
+
+HideableWidget.prototype.show = function() {
+ this.setState('shown');
+ this.onAfterShow();
+};
+
+HideableWidget.prototype.hide = function() {
+ this.setState('hidden');
+};
+
+HideableWidget.prototype.decorate = function(element) {
+ this._element = element;
+};
+
+/**
+ * @constructor
+ */
+var MessageComposer = function() {
+ HideableWidget.call(this);
+};
+inherits(MessageComposer, HideableWidget);
+
+MessageComposer.prototype.onAfterCancel = function(handler) {
+ if (handler) {
+ this._onAfterCancel = handler;
+ } else {
+ return this._onAfterCancel();
+ }
+};
+
+/** override these two
+ * @param {object} data - the response data
+ * these functions will run after .send() receives
+ * the response
+ */
+MessageComposer.prototype.onSendSuccessInternal = function(data) {};
+MessageComposer.prototype.onSendErrorInternal = function(data) {};
+
+MessageComposer.prototype.onSendSuccess = function(callback) {
+ if (callback) {
+ this._onSendSuccess = callback;
+ } else if (this._onSendSuccess) {
+ this._onSendSuccess();
+ }
+};
+
+MessageComposer.prototype.onSendError = function(callback) {
+ if (callback) {
+ this._onSendError = callback;
+ } else if (this._onSendError) {
+ this._onSendError();
+ }
+};
+
+MessageComposer.prototype.onAfterShow = function() {
+ this._textarea.focus();
+};
+
+MessageComposer.prototype.cancel = function() {
+ this._textarea.val('');
+ this._textareaError.html('');
+ this.hide();
+ this.onAfterCancel();
+};
+
+MessageComposer.prototype.setPostData = function(data) {
+ this._postData = data;
+};
+
+MessageComposer.prototype.getPostData = function() {
+ return this._postData;
+};
+
+MessageComposer.prototype.setSendUrl = function(url) {
+ this._sendUrl = url;
+};
+
+MessageComposer.prototype.getInputData = function() {
+ return {'text': this._textarea.val()};
+};
+
+MessageComposer.prototype.dataIsValid = function() {
+ var text = $.trim(this._textarea.val());
+ if (text === '') {
+ this._textareaError.html(gettext('required'));
+ return false;
+ }
+ return true;
+};
+
+MessageComposer.prototype.send = function() {
+ var url = this._sendUrl;
+ var data = this.getPostData() || {};
+ var inputData = this.getInputData();
+ $.extend(data, inputData);
+ var me = this;
+ data['text'] = this._textarea.val();
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ url: url,
+ data: data,
+ cache: false,
+ success: function(data) {
+ if (data['success']) {
+ me.onSendSuccessInternal(data);
+ me.onSendSuccess();
+ } else {
+ me.onSendErrorInternal(data);
+ me.onSendError();
+ }
+ }
+ });
+};
+
+MessageComposer.prototype.createDom = function() {
+ this._element = this.makeElement('div');
+ this.hide();
+ this._element.addClass('message-composer');
+ //create textarea
+ var label = this.makeElement('label');
+ label.html(gettext('Your message:'));
+ this._element.append(label);
+ var error = this.makeElement('label');
+ error.addClass('errors');
+ this._element.append(error);
+ this._element.append($('<br/>'));
+ this._textareaError = error;
+ var textarea = this.makeElement('textarea');
+ this._element.append(textarea);
+ this._textarea = textarea;
+ //send button
+ var me = this;
+ var sendBtn = this.makeButton(
+ gettext('send'),
+ function() {
+ if (me.dataIsValid()){
+ me.send();
+ }
+ }
+ );
+ sendBtn.addClass('submit');
+ this._element.append(sendBtn);
+
+ //cancel button
+ var cancelBtn = this.makeButton(
+ gettext('cancel'),
+ function() { me.cancel(); }
+ );
+ cancelBtn.addClass('submit');
+ this._element.append(cancelBtn);
+};
+
+
+var ReplyMessageComposer = function() {
+ MessageComposer.call(this);
+};
+inherits(ReplyMessageComposer, MessageComposer);
+
+ReplyMessageComposer.prototype.setParent = function(elem) {
+ this._parent = elem;
+};
+
+ReplyMessageComposer.prototype.onSendSuccessInternal = function(data) {
+ var message = new Message();
+ message.decorate($(data['html']));
+ this._parent.addMessage(message);
+};
+
+/**
+ * @constructor
+ * same as message composer, but initially
+ * hidden and presented by a "reply" link
+ */
+var ReplyComposer = function() {
+ HideableWidget.call(this);
+};
+inherits(ReplyComposer, HideableWidget);
+
+ReplyComposer.prototype.open = function() {
+ this._opener.hide();
+ this._editor.show();
+};
+
+ReplyComposer.prototype.close = function() {
+ this._opener.show();
+ this._editor.hide();
+}
+
+ReplyComposer.prototype.setSendUrl = function(url) {
+ this._sendUrl = url;
+};
+
+ReplyComposer.prototype.setPostData = function(data) {
+ this._editor.setPostData(data);
+};
+
+ReplyComposer.prototype.setThread = function(thread) {
+ this._thread = thread;
+};
+
+ReplyComposer.prototype.addMessage = function(message) {
+ this._thread.addMessage(message);
+};
+
+ReplyComposer.prototype.createDom = function() {
+ this._element = this.makeElement('div');
+ this._element.addClass('reply-composer');
+ var opener = this.makeElement('a');
+ opener.html(gettext('Reply'));
+ this._opener = opener;
+ this._element.append(opener);
+
+ var editor = new ReplyMessageComposer();
+ editor.setSendUrl(this._sendUrl);
+ editor.setParent(this);
+ editor.onSendSuccess(function() {
+ editor.cancel();
+ notify.show(gettext('message sent'), true);
+ });
+ this._editor = editor;
+ this._element.append(editor.getElement());
+
+ var me = this;
+ setupButtonEventHandlers(opener, function() { me.open() });
+ editor.onAfterCancel(function() { me.close() });
+ this.hide();
+};
+
+
+/**
+ * @constructor
+ */
+var NewThreadComposer = function() {
+ MessageComposer.call(this);
+};
+inherits(NewThreadComposer, MessageComposer);
+
+NewThreadComposer.prototype.cancel = function() {
+ this._toInput.val('');
+ this._toInputError.html('');
+ NewThreadComposer.superClass_.cancel.call(this);
+};
+
+NewThreadComposer.prototype.onAfterShow = function() {
+ this._toInput.focus();
+};
+
+NewThreadComposer.prototype.onSendErrorInternal = function(data) {
+ var missingUsers = data['missing_users']
+ if (missingUsers) {
+ var errorTpl = ngettext(
+ 'user {{str}} does not exist',
+ 'users {{str}} do not exist',
+ missingUsers.length
+ )
+ error = errorTpl.replace('{{str}}', joinAsPhrase(missingUsers));
+ this._toInputError.html(error);
+ }
+};
+
+NewThreadComposer.prototype.getInputData = function() {
+ var data = NewThreadComposer.superClass_.getInputData.call(this);
+ data['to_usernames'] = $.trim(this._toInput.val());
+ return data;
+};
+
+NewThreadComposer.prototype.dataIsValid = function() {
+ var superIsValid = NewThreadComposer.superClass_.dataIsValid.call(this);
+ var to = $.trim(this._toInput.val());
+ if (to === '') {
+ this._toInputError.html(gettext('required'));
+ return false;
+ }
+ return superIsValid;
+};
+
+NewThreadComposer.prototype.createDom = function() {
+ NewThreadComposer.superClass_.createDom.call(this);
+ var element = this.getElement();
+
+ var toInput = this.makeElement('input');
+ toInput.addClass('recipients');
+ element.prepend(toInput);
+ this._toInput = toInput;
+
+ var userSelectHandler = function() {};
+
+ var usersAc = new AutoCompleter({
+ url: '/get-users-info/',//askbot['urls']['get_users_info'],
+ preloadData: false,
+ minChars: 1,
+ useCache: true,
+ matchInside: true,
+ maxCacheLength: 100,
+ delay: 10,
+ onItemSelect: userSelectHandler
+ });
+
+ usersAc.decorate(toInput);
+
+ var label = this.makeElement('label');
+ label.html(gettext('Recipient:'));
+ element.prepend(label);
+ var error = this.makeElement('label');
+ this._element.append($('<br/>'));
+ error.addClass('errors');
+ this._toInputError = error;
+ label.after(error);
+};
+
+var ThreadHeading = function() {
+ SimpleControl.call(this);
+};
+inherits(ThreadHeading, SimpleControl);
+
+ThreadHeading.prototype.getId = function() {
+ return this._id;
+};
+
+ThreadHeading.prototype.decorate = function(element) {
+ this._element = element;
+ this._id = element.data('threadId');
+};
+
+/**
+ * @constructor
+ */
+var ThreadsList = function() {
+ HideableWidget.call(this);
+};
+inherits(ThreadsList, HideableWidget);
+
+ThreadsList.prototype.setMessageCenter = function(ctr) {
+ this._messageCenter = ctr;
+};
+
+ThreadsList.prototype.getOpenThreadHandler = function(threadId) {
+ var messageCenter = this._messageCenter;
+ return function() {
+ messageCenter.openThread(threadId);
+ };
+};
+
+ThreadsList.prototype.setHTML = function(html) {
+ $.each(this._threads, function(idx, thread) {
+ thread.dispose();
+ });
+ this._element.html(html);
+ this.decorate(this._element);
+};
+
+ThreadsList.prototype.decorate = function(element) {
+ this._element = element;
+ var headingElements = element.find('tr.thread-heading');
+ var me = this;
+ var threads = [];
+ $.each(headingElements, function(idx, headingElement) {
+ var heading = new ThreadHeading();
+ heading.decorate($(headingElement));
+ var threadId = heading.getId();
+ heading.setHandler(me.getOpenThreadHandler(threadId));
+ threads.push(heading);
+ });
+ this._threads = threads;
+}
+
+
+/**
+ * @constructor
+ */
+var Message = function() {
+ Widget.call(this);
+};
+inherits(Message, Widget);
+
+Message.prototype.getId = function() {
+ return this._id;
+};
+
+Message.prototype.decorate = function(element) {
+ this._element = element;
+ this._id = element.data('messageId');
+};
+
+
+/**
+ * @constructor
+ */
+var ThreadContainer = function() {
+ HideableWidget.call(this);
+};
+inherits(ThreadContainer, HideableWidget);
+
+ThreadContainer.prototype.show = function() {
+ ThreadContainer.superClass_.show.call(this);
+ this._editor.close();
+ this._editor.show();
+};
+
+ThreadContainer.prototype.hide = function() {
+ ThreadContainer.superClass_.hide.call(this);
+ this._editor.close();
+ this._editor.hide();
+};
+
+/**
+ * sets html content part of the thread
+ * and re-decorates it
+ */
+ThreadContainer.prototype.setContent = function(html) {
+ if (this._thread) {
+ this._thread.dispose();
+ }
+ var thread = new Thread();
+ thread.decorate($(html));
+ this._thread = thread;
+ this._contentElement.empty();
+ this._contentElement.append(thread.getElement());
+ var postData = {parent_id: thread.getLastMessageId()};
+ this._editor.setPostData(postData);
+ this._editor.setThread(thread);
+};
+
+ThreadContainer.prototype.setReplyUrl = function(url) {
+ this._replyUrl = url;
+};
+
+ThreadContainer.prototype.createDom = function() {
+ this._element = this.makeElement('div');
+ var content = this.makeElement('div');
+ this._contentElement = content;
+ this._element.append(content);
+
+ var editor = new ReplyComposer();
+ editor.setSendUrl(this._replyUrl);
+ this._element.append(editor.getElement());
+ this._editor = editor;
+};
+
+
+/**
+ * @constructor
+ */
+var Thread = function() {
+ WrappedElement.call(this);
+};
+inherits(Thread, WrappedElement);
+
+Thread.prototype.getLastMessageId = function() {
+ return this._messages.slice(-1)[0].getId();
+};
+
+Thread.prototype.dispose = function() {
+ $.each(this._messages, function(idx, message) {
+ message.dispose()
+ });
+ Thread.superClass_.dispose.call(this);
+};
+
+Thread.prototype.addMessage = function(message) {
+ var li = this.makeElement('li');
+ this._element.append(li);
+ li.append(message.getElement());
+};
+
+Thread.prototype.decorate = function(element) {
+ this._element = element;
+ var messages = [];
+ $.each(element.find('.message'), function(idx, item) {
+ var message = new Message();
+ message.decorate($(item));
+ messages.push(message);
+ });
+ this._messages = messages;
+};
+
+
+/**
+ * @constructor
+ */
+var Sender = function() {
+ SimpleControl.call(this);
+};
+inherits(Sender, SimpleControl);
+
+Sender.prototype.getId = function() {
+ return this._id;
+};
+
+Sender.prototype.select = function() {
+ this._element.addClass('selected');
+};
+
+Sender.prototype.unselect = function() {
+ this._element.removeClass('selected');
+};
+
+Sender.prototype.decorate = function(element) {
+ Sender.superClass_.decorate.call(this, element);
+ this._id = element.data('senderId');
+};
+
+
+/**
+ * @constructor
+ * list of senders in the first column of inbox
+ */
+var SendersList = function() {
+ WrappedElement.call(this);
+ this._messageCenter = undefined;
+};
+inherits(SendersList, WrappedElement);
+
+SendersList.prototype.setMessageCenter = function(ctr) {
+ this._messageCenter = ctr;
+};
+
+SendersList.prototype.getSenders = function() {
+ return this._senders;
+};
+
+SendersList.prototype.getSenderSelectHandler = function(sender) {
+ var messageCenter = this._messageCenter;
+ var me = this;
+ return function() {
+ $.map(me.getSenders(), function(s){ s.unselect() });
+ sender.select();
+ messageCenter.loadThreadsForSender(sender.getId());
+ };
+};
+
+SendersList.prototype.decorate = function(element) {
+ this._element = element;
+ var senders = [];
+ $.each(element.find('a'), function(idx, item) {
+ var sender = new Sender();
+ sender.decorate($(item));
+ senders.push(sender);
+ });
+
+ this._senders = senders;
+
+ var me = this;
+ $.each(senders, function(idx, sender) {
+ sender.setHandler(me.getSenderSelectHandler(sender));
+ });
+};
+
+
+/**
+ * @contsructor
+ */
+var MessageCenter = function() {
+ Widget.call(this);
+};
+inherits(MessageCenter, Widget);
+
+MessageCenter.prototype.setState = function(state) {
+ this._editor.hide();
+ this._threadsList.hide();
+ this._threadContainer.hide();
+ if (state === 'compose') {
+ this._editor.show();
+ } else if (state === 'show-list') {
+ this._threadsList.show();
+ } else if (state === 'show-thread') {
+ this._threadContainer.show();
+ }
+};
+
+MessageCenter.prototype.openThread = function(threadId) {
+ var url = this._urls['getThreads'] + threadId + '/';
+ var me = this;
+ var threadContainer = this._threadContainer;
+ $.ajax({
+ type: 'GET',
+ dataType: 'json',
+ url: url,
+ cache: false,
+ success: function(data) {
+ if (data['success']) {
+ threadContainer.setContent(data['html']);
+ me.setState('show-thread');
+ }
+ }
+ });
+};
+
+MessageCenter.prototype.loadThreadsForSender = function(senderId) {
+ var threadsList = this._threadsList;
+ var url = this._urls['getThreads'];
+ me = this;
+ $.ajax({
+ type: 'GET',
+ dataType: 'json',
+ url: url,
+ cache: false,
+ data: {sender_id: senderId},
+ success: function(data) {
+ if (data['success']) {
+ threadsList.setHTML(data['html']);
+ me.setState('show-list');
+ }
+ }
+ });
+};
+
+MessageCenter.prototype.decorate = function(element) {
+ this._element = element;
+ this._firstCol = element.find('.first-col');
+ this._secondCol = element.find('.second-col');
+
+ this._urls = {
+ getThreads: element.data('getThreadsUrl'),
+ getThreadDetails: element.data('getThreadDetailsUrl'),
+ reply: element.data('replyUrl')
+ };
+
+ //read sender list
+ var senders = new SendersList();
+ senders.setMessageCenter(this);
+ senders.decorate($('.senders-list'));
+ this._sendersList = senders;
+ //read message list
+ var threads = new ThreadsList();
+ threads.setMessageCenter(this);
+ threads.decorate($('.threads-list'));
+ this._threadsList = threads;
+ //add empty thread container
+ var threadContainer = new ThreadContainer();
+ this._threadContainer = threadContainer;
+ threadContainer.setReplyUrl(this._urls['reply']);
+ this._secondCol.append(threadContainer.getElement());
+
+ var me = this;
+ //create editor
+ var editor = new NewThreadComposer();
+ this._secondCol.append(editor.getElement());
+ editor.setSendUrl(element.data('createThreadUrl'));
+ editor.onAfterCancel(function() { me.setState('show-list') });
+ editor.onSendSuccess(function() {
+ editor.cancel();
+ notify.show(gettext('message sent'), true);
+ });
+ this._editor = editor;
+
+ //activate compose button
+ var btn = element.find('button.compose');
+ this._composeBtn = btn;
+ setupButtonEventHandlers(btn, function(){ me.setState('compose') });
+};
+
+var msgCtr = new MessageCenter();
+msgCtr.decorate($('.group-messaging'));
diff --git a/askbot/skins/common/media/js/jquery-1.4.3.js b/askbot/media/js/jquery-1.4.3.js
index ad9a79c4..ad9a79c4 100644
--- a/askbot/skins/common/media/js/jquery-1.4.3.js
+++ b/askbot/media/js/jquery-1.4.3.js
diff --git a/askbot/skins/common/media/js/jquery-1.7.2.min.js b/askbot/media/js/jquery-1.7.2.min.js
index 16ad06c5..16ad06c5 100644
--- a/askbot/skins/common/media/js/jquery-1.7.2.min.js
+++ b/askbot/media/js/jquery-1.7.2.min.js
diff --git a/askbot/skins/common/media/js/jquery-fieldselection.js b/askbot/media/js/jquery-fieldselection.js
index 47f25a98..47f25a98 100644
--- a/askbot/skins/common/media/js/jquery-fieldselection.js
+++ b/askbot/media/js/jquery-fieldselection.js
diff --git a/askbot/skins/common/media/js/jquery-fieldselection.min.js b/askbot/media/js/jquery-fieldselection.min.js
index c2abde0b..c2abde0b 100644
--- a/askbot/skins/common/media/js/jquery-fieldselection.min.js
+++ b/askbot/media/js/jquery-fieldselection.min.js
diff --git a/askbot/media/js/jquery.ajaxfileupload.js b/askbot/media/js/jquery.ajaxfileupload.js
new file mode 100644
index 00000000..23759c2e
--- /dev/null
+++ b/askbot/media/js/jquery.ajaxfileupload.js
@@ -0,0 +1,186 @@
+jQuery.extend({
+ createUploadIframe: function(id, uri){
+ //create frame
+ var frameId = 'jUploadFrame' + id;
+ if(window.ActiveXObject) {
+ var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
+ if(typeof uri== 'boolean'){
+ io.src = 'javascript:false';
+ }
+ else if(typeof uri== 'string'){
+ io.src = uri;
+ }
+ }
+ else {
+ var io = document.createElement('iframe');
+ io.id = frameId;
+ io.name = frameId;
+ }
+ io.style.position = 'absolute';
+ io.style.top = '-1000px';
+ io.style.left = '-1000px';
+
+ document.body.appendChild(io);
+ return io;
+ },
+ createUploadForm: function(id, fileElementId) {
+ //create form
+ var formId = 'jUploadForm' + id;
+ var fileId = 'jUploadFile' + id;
+ var form = $('<form action="" method="POST" name="' + formId + '" id="' + formId
+ + '" enctype="multipart/form-data"></form>');
+ var oldElement = $('#' + fileElementId);
+ var newElement = $(oldElement).clone();
+ $(oldElement).attr('id', fileId);
+ $(oldElement).before(newElement);
+ $(oldElement).appendTo(form);
+ //set attributes
+ $(form).css('position', 'absolute');
+ $(form).css('top', '-1200px');
+ $(form).css('left', '-1200px');
+ $(form).appendTo('body');
+ return form;
+ },
+
+ ajaxFileUpload: function(s) {
+ // TODO introduce global settings, allowing the client to modify them for all requests, not only timeout
+ s = jQuery.extend({}, jQuery.ajaxSettings, s);
+ var id = new Date().getTime()
+ var form = jQuery.createUploadForm(id, s.fileElementId);
+ var io = jQuery.createUploadIframe(id, s.secureuri);
+ var frameId = 'jUploadFrame' + id;
+ var formId = 'jUploadForm' + id;
+ // Watch for a new set of requests
+ if ( s.global && ! jQuery.active++ )
+ {
+ jQuery.event.trigger( "ajaxStart" );
+ }
+ var requestDone = false;
+ // Create the request object
+ var xml = {}
+ if ( s.global )
+ jQuery.event.trigger("ajaxSend", [xml, s]);
+ // Wait for a response to come back
+ var uploadCallback = function(isTimeout) {
+ var io = document.getElementById(frameId);
+ try {
+ if(io.contentWindow){
+ xml.responseText = io.contentWindow.document.body ?
+ io.contentWindow.document.body.innerText : null;
+ xml.responseXML = io.contentWindow.document.XMLDocument ?
+ io.contentWindow.document.XMLDocument : io.contentWindow.document;
+
+ }
+ else if(io.contentDocument)
+ {
+ xml.responseText = io.contentDocument.document.body ?
+ io.contentDocument.document.body.textContent || document.body.innerText : null;
+ xml.responseXML = io.contentDocument.document.XMLDocument ?
+ io.contentDocument.document.XMLDocument : io.contentDocument.document;
+ }
+ }
+ catch(e) {
+ jQuery.handleError(s, xml, null, e);
+ }
+ if ( xml || isTimeout == "timeout") {
+ requestDone = true;
+ var status;
+ try {
+ status = isTimeout != "timeout" ? "success" : "error";
+ // Make sure that the request was successful or notmodified
+ if ( status != "error" )
+ {
+ // process the data (runs the xml through httpData regardless of callback)
+ var data = jQuery.uploadHttpData( xml, s.dataType );
+ // If a local callback was specified, fire it and pass it the data
+ if ( s.success )
+ s.success( data, status );
+
+ // Fire the global callback
+ if( s.global )
+ jQuery.event.trigger( "ajaxSuccess", [xml, s] );
+ } else
+ jQuery.handleError(s, xml, status);
+ } catch(e)
+ {
+ status = "error";
+ jQuery.handleError(s, xml, status, e);
+ }
+
+ // The request was completed
+ if( s.global )
+ jQuery.event.trigger( "ajaxComplete", [xml, s] );
+
+ // Handle the global AJAX counter
+ if ( s.global && ! --jQuery.active )
+ jQuery.event.trigger( "ajaxStop" );
+
+ // Process result
+ if ( s.complete )
+ s.complete(xml, status);
+
+ jQuery(io).unbind();
+
+ setTimeout(function() {
+ try {
+ $(io).remove();
+ $(form).remove();
+
+ } catch(e) {
+ jQuery.handleError(s, xml, null, e);
+ }
+ }, 100);
+ xml = null;
+ }
+ }
+ // Timeout checker
+ if ( s.timeout > 0 ) {
+ setTimeout(function(){
+ // Check to see if the request is still happening
+ if( !requestDone ) uploadCallback( "timeout" );
+ }, s.timeout);
+ }
+ try {
+ // var io = $('#' + frameId);
+ var form = $('#' + formId);
+ $(form).attr('action', s.url);
+ $(form).attr('method', 'POST');
+ $(form).attr('target', frameId);
+ if(form.encoding) {
+ form.encoding = 'multipart/form-data';
+ }
+ else {
+ form.enctype = 'multipart/form-data';
+ }
+ $(form).submit();
+
+ } catch(e) {
+ jQuery.handleError(s, xml, null, e);
+ }
+ if(window.attachEvent){
+ document.getElementById(frameId).attachEvent('onload', uploadCallback);
+ }
+ else{
+ document.getElementById(frameId).addEventListener('load', uploadCallback, false);
+ }
+ return {abort: function () {}};
+
+ },
+
+ uploadHttpData: function( r, type ) {
+ var data = !type;
+ data = type == "xml" || data ? r.responseXML : r.responseText;
+ // If the type is "script", eval it in global context
+ if ( type == "script" )
+ jQuery.globalEval( data );
+ // Get the JavaScript object, if JSON is used.
+ if ( type == "json" )
+ eval( "data = " + data );
+ // evaluate scripts within html
+ if ( type == "html" )
+ jQuery("<div>").html(data).evalScripts();
+ //alert($('param', data).each(function(){alert($(this).attr('value'));}));
+ return data;
+ }
+})
+
diff --git a/askbot/skins/common/media/js/jquery.animate-colors.js b/askbot/media/js/jquery.animate-colors.js
index 07d8ac9c..07d8ac9c 100644
--- a/askbot/skins/common/media/js/jquery.animate-colors.js
+++ b/askbot/media/js/jquery.animate-colors.js
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/ajax.txt b/askbot/media/js/jquery.fancybox-1.3.4/ajax.txt
new file mode 100644
index 00000000..6e278935
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/ajax.txt
@@ -0,0 +1,6 @@
+<div style="width:400px;">
+ <h2>This comes from ajax request</h2>
+ <p>
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean non velit. Donec pharetra, felis ut tristique adipiscing, diam magna rhoncus neque, sit amet convallis nibh nibh vel libero. Nulla facilisi. In eleifend nisl quis lorem. Duis semper fringilla justo. Proin imperdiet sapien sed lectus. Integer quis nisl et est elementum tempor. Morbi quis tellus nec turpis suscipit molestie. Praesent sed pede. Pellentesque ac orci. Sed sit amet urna eget tellus hendrerit aliquet. Nulla consectetur, pede aliquam ornare placerat, nunc augue commodo leo, sit amet elementum dolor est eleifend magna.
+ </p>
+</div> \ No newline at end of file
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/10_b.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/10_b.jpg
new file mode 100644
index 00000000..9a070ddd
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/10_b.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/10_s.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/10_s.jpg
new file mode 100644
index 00000000..8a1c644f
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/10_s.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/11_b.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/11_b.jpg
new file mode 100644
index 00000000..ea3eb0dd
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/11_b.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/11_s.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/11_s.jpg
new file mode 100644
index 00000000..0d071eff
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/11_s.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/12_b.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/12_b.jpg
new file mode 100644
index 00000000..3e620e08
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/12_b.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/12_s.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/12_s.jpg
new file mode 100644
index 00000000..3d47f7c2
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/12_s.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/1_b.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/1_b.jpg
new file mode 100644
index 00000000..93ae2398
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/1_b.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/1_s.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/1_s.jpg
new file mode 100644
index 00000000..97fdad20
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/1_s.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/2_b.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/2_b.jpg
new file mode 100644
index 00000000..6975516c
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/2_b.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/2_s.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/2_s.jpg
new file mode 100644
index 00000000..b293db4f
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/2_s.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/3_b.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/3_b.jpg
new file mode 100644
index 00000000..5e168478
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/3_b.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/3_s.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/3_s.jpg
new file mode 100644
index 00000000..0459e355
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/3_s.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/4_b.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/4_b.jpg
new file mode 100644
index 00000000..5a26b6bb
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/4_b.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/4_s.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/4_s.jpg
new file mode 100644
index 00000000..e52d8035
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/4_s.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/5_b.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/5_b.jpg
new file mode 100644
index 00000000..82662e31
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/5_b.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/5_s.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/5_s.jpg
new file mode 100644
index 00000000..c4ae36a5
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/5_s.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/6_b.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/6_b.jpg
new file mode 100644
index 00000000..6fcc1e72
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/6_b.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/6_s.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/6_s.jpg
new file mode 100644
index 00000000..729dadd8
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/6_s.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/7_b.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/7_b.jpg
new file mode 100644
index 00000000..fab6b7fb
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/7_b.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/7_s.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/7_s.jpg
new file mode 100644
index 00000000..4fa27b11
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/7_s.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/8_b.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/8_b.jpg
new file mode 100644
index 00000000..6d832874
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/8_b.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/8_s.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/8_s.jpg
new file mode 100644
index 00000000..4014046f
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/8_s.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/9_b.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/9_b.jpg
new file mode 100644
index 00000000..84d42817
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/9_b.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/example/9_s.jpg b/askbot/media/js/jquery.fancybox-1.3.4/example/9_s.jpg
new file mode 100644
index 00000000..146e0df2
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/example/9_s.jpg
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/blank.gif b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/blank.gif
new file mode 100644
index 00000000..35d42e80
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/blank.gif
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_close.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_close.png
new file mode 100644
index 00000000..07035307
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_close.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_loading.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_loading.png
new file mode 100644
index 00000000..25030179
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_loading.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_nav_left.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_nav_left.png
new file mode 100644
index 00000000..ebaa6a4f
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_nav_left.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_nav_right.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_nav_right.png
new file mode 100644
index 00000000..873294e9
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_nav_right.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_e.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_e.png
new file mode 100644
index 00000000..2eda0893
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_e.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_n.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_n.png
new file mode 100644
index 00000000..69aa10e2
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_n.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_ne.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_ne.png
new file mode 100644
index 00000000..79f6980a
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_ne.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_nw.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_nw.png
new file mode 100644
index 00000000..7182cd93
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_nw.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_s.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_s.png
new file mode 100644
index 00000000..d8858bfb
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_s.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_se.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_se.png
new file mode 100644
index 00000000..541e3ffd
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_se.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_sw.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_sw.png
new file mode 100644
index 00000000..b451689f
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_sw.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_w.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_w.png
new file mode 100644
index 00000000..8a4e4a88
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_shadow_w.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_title_left.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_title_left.png
new file mode 100644
index 00000000..6049223d
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_title_left.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_title_main.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_title_main.png
new file mode 100644
index 00000000..8044271f
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_title_main.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_title_over.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_title_over.png
new file mode 100644
index 00000000..d9f458f4
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_title_over.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_title_right.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_title_right.png
new file mode 100644
index 00000000..e36d9db2
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancy_title_right.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancybox-x.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancybox-x.png
new file mode 100644
index 00000000..c2130f86
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancybox-x.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancybox-y.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancybox-y.png
new file mode 100644
index 00000000..7ef399b9
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancybox-y.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancybox.png b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancybox.png
new file mode 100644
index 00000000..65e14f68
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/fancybox.png
Binary files differ
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.easing-1.3.pack.js b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.easing-1.3.pack.js
new file mode 100644
index 00000000..9028179e
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.easing-1.3.pack.js
@@ -0,0 +1,72 @@
+/*
+ * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
+ *
+ * Uses the built in easing capabilities added In jQuery 1.1
+ * to offer multiple easing options
+ *
+ * TERMS OF USE - jQuery Easing
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright © 2008 George McGinley Smith
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+*/
+
+// t: current time, b: begInnIng value, c: change In value, d: duration
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('h.i[\'1a\']=h.i[\'z\'];h.O(h.i,{y:\'D\',z:9(x,t,b,c,d){6 h.i[h.i.y](x,t,b,c,d)},17:9(x,t,b,c,d){6 c*(t/=d)*t+b},D:9(x,t,b,c,d){6-c*(t/=d)*(t-2)+b},13:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t+b;6-c/2*((--t)*(t-2)-1)+b},X:9(x,t,b,c,d){6 c*(t/=d)*t*t+b},U:9(x,t,b,c,d){6 c*((t=t/d-1)*t*t+1)+b},R:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t+b;6 c/2*((t-=2)*t*t+2)+b},N:9(x,t,b,c,d){6 c*(t/=d)*t*t*t+b},M:9(x,t,b,c,d){6-c*((t=t/d-1)*t*t*t-1)+b},L:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t*t+b;6-c/2*((t-=2)*t*t*t-2)+b},K:9(x,t,b,c,d){6 c*(t/=d)*t*t*t*t+b},J:9(x,t,b,c,d){6 c*((t=t/d-1)*t*t*t*t+1)+b},I:9(x,t,b,c,d){e((t/=d/2)<1)6 c/2*t*t*t*t*t+b;6 c/2*((t-=2)*t*t*t*t+2)+b},G:9(x,t,b,c,d){6-c*8.C(t/d*(8.g/2))+c+b},15:9(x,t,b,c,d){6 c*8.n(t/d*(8.g/2))+b},12:9(x,t,b,c,d){6-c/2*(8.C(8.g*t/d)-1)+b},Z:9(x,t,b,c,d){6(t==0)?b:c*8.j(2,10*(t/d-1))+b},Y:9(x,t,b,c,d){6(t==d)?b+c:c*(-8.j(2,-10*t/d)+1)+b},W:9(x,t,b,c,d){e(t==0)6 b;e(t==d)6 b+c;e((t/=d/2)<1)6 c/2*8.j(2,10*(t-1))+b;6 c/2*(-8.j(2,-10*--t)+2)+b},V:9(x,t,b,c,d){6-c*(8.o(1-(t/=d)*t)-1)+b},S:9(x,t,b,c,d){6 c*8.o(1-(t=t/d-1)*t)+b},Q:9(x,t,b,c,d){e((t/=d/2)<1)6-c/2*(8.o(1-t*t)-1)+b;6 c/2*(8.o(1-(t-=2)*t)+1)+b},P:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d)==1)6 b+c;e(!p)p=d*.3;e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);6-(a*8.j(2,10*(t-=1))*8.n((t*d-s)*(2*8.g)/p))+b},H:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d)==1)6 b+c;e(!p)p=d*.3;e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);6 a*8.j(2,-10*t)*8.n((t*d-s)*(2*8.g)/p)+c+b},T:9(x,t,b,c,d){f s=1.l;f p=0;f a=c;e(t==0)6 b;e((t/=d/2)==2)6 b+c;e(!p)p=d*(.3*1.5);e(a<8.w(c)){a=c;f s=p/4}m f s=p/(2*8.g)*8.r(c/a);e(t<1)6-.5*(a*8.j(2,10*(t-=1))*8.n((t*d-s)*(2*8.g)/p))+b;6 a*8.j(2,-10*(t-=1))*8.n((t*d-s)*(2*8.g)/p)*.5+c+b},F:9(x,t,b,c,d,s){e(s==u)s=1.l;6 c*(t/=d)*t*((s+1)*t-s)+b},E:9(x,t,b,c,d,s){e(s==u)s=1.l;6 c*((t=t/d-1)*t*((s+1)*t+s)+1)+b},16:9(x,t,b,c,d,s){e(s==u)s=1.l;e((t/=d/2)<1)6 c/2*(t*t*(((s*=(1.B))+1)*t-s))+b;6 c/2*((t-=2)*t*(((s*=(1.B))+1)*t+s)+2)+b},A:9(x,t,b,c,d){6 c-h.i.v(x,d-t,0,c,d)+b},v:9(x,t,b,c,d){e((t/=d)<(1/2.k)){6 c*(7.q*t*t)+b}m e(t<(2/2.k)){6 c*(7.q*(t-=(1.5/2.k))*t+.k)+b}m e(t<(2.5/2.k)){6 c*(7.q*(t-=(2.14/2.k))*t+.11)+b}m{6 c*(7.q*(t-=(2.18/2.k))*t+.19)+b}},1b:9(x,t,b,c,d){e(t<d/2)6 h.i.A(x,t*2,0,c,d)*.5+b;6 h.i.v(x,t*2-d,0,c,d)*.5+c*.5+b}});',62,74,'||||||return||Math|function|||||if|var|PI|jQuery|easing|pow|75|70158|else|sin|sqrt||5625|asin|||undefined|easeOutBounce|abs||def|swing|easeInBounce|525|cos|easeOutQuad|easeOutBack|easeInBack|easeInSine|easeOutElastic|easeInOutQuint|easeOutQuint|easeInQuint|easeInOutQuart|easeOutQuart|easeInQuart|extend|easeInElastic|easeInOutCirc|easeInOutCubic|easeOutCirc|easeInOutElastic|easeOutCubic|easeInCirc|easeInOutExpo|easeInCubic|easeOutExpo|easeInExpo||9375|easeInOutSine|easeInOutQuad|25|easeOutSine|easeInOutBack|easeInQuad|625|984375|jswing|easeInOutBounce'.split('|'),0,{}))
+
+/*
+ *
+ * TERMS OF USE - EASING EQUATIONS
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright © 2001 Robert Penner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.fancybox-1.3.4.css b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.fancybox-1.3.4.css
new file mode 100644
index 00000000..6f53d8f4
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.fancybox-1.3.4.css
@@ -0,0 +1,359 @@
+/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ *
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
+ *
+ * Version: 1.3.4 (11/11/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+#fancybox-loading {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ width: 40px;
+ height: 40px;
+ margin-top: -20px;
+ margin-left: -20px;
+ cursor: pointer;
+ overflow: hidden;
+ z-index: 1104;
+ display: none;
+}
+
+#fancybox-loading div {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 40px;
+ height: 480px;
+ background-image: url('fancybox.png');
+}
+
+#fancybox-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ z-index: 1100;
+ display: none;
+}
+
+#fancybox-tmp {
+ padding: 0;
+ margin: 0;
+ border: 0;
+ overflow: auto;
+ display: none;
+}
+
+#fancybox-wrap {
+ position: absolute;
+ top: 0;
+ left: 0;
+ padding: 20px;
+ z-index: 1101;
+ outline: none;
+ display: none;
+}
+
+#fancybox-outer {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ background: #fff;
+}
+
+#fancybox-content {
+ width: 0;
+ height: 0;
+ padding: 0;
+ outline: none;
+ position: relative;
+ overflow: hidden;
+ z-index: 1102;
+ border: 0px solid #fff;
+}
+
+#fancybox-hide-sel-frame {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: transparent;
+ z-index: 1101;
+}
+
+#fancybox-close {
+ position: absolute;
+ top: -15px;
+ right: -15px;
+ width: 30px;
+ height: 30px;
+ background: transparent url('fancybox.png') -40px 0px;
+ cursor: pointer;
+ z-index: 1103;
+ display: none;
+}
+
+#fancybox-error {
+ color: #444;
+ font: normal 12px/20px Arial;
+ padding: 14px;
+ margin: 0;
+}
+
+#fancybox-img {
+ width: 100%;
+ height: 100%;
+ padding: 0;
+ margin: 0;
+ border: none;
+ outline: none;
+ line-height: 0;
+ vertical-align: top;
+}
+
+#fancybox-frame {
+ width: 100%;
+ height: 100%;
+ border: none;
+ display: block;
+}
+
+#fancybox-left, #fancybox-right {
+ position: absolute;
+ bottom: 0px;
+ height: 100%;
+ width: 35%;
+ cursor: pointer;
+ outline: none;
+ background: transparent url('blank.gif');
+ z-index: 1102;
+ display: none;
+}
+
+#fancybox-left {
+ left: 0px;
+}
+
+#fancybox-right {
+ right: 0px;
+}
+
+#fancybox-left-ico, #fancybox-right-ico {
+ position: absolute;
+ top: 50%;
+ left: -9999px;
+ width: 30px;
+ height: 30px;
+ margin-top: -15px;
+ cursor: pointer;
+ z-index: 1102;
+ display: block;
+}
+
+#fancybox-left-ico {
+ background-image: url('fancybox.png');
+ background-position: -40px -30px;
+}
+
+#fancybox-right-ico {
+ background-image: url('fancybox.png');
+ background-position: -40px -60px;
+}
+
+#fancybox-left:hover, #fancybox-right:hover {
+ visibility: visible; /* IE6 */
+}
+
+#fancybox-left:hover span {
+ left: 20px;
+}
+
+#fancybox-right:hover span {
+ left: auto;
+ right: 20px;
+}
+
+.fancybox-bg {
+ position: absolute;
+ padding: 0;
+ margin: 0;
+ border: 0;
+ width: 20px;
+ height: 20px;
+ z-index: 1001;
+}
+
+#fancybox-bg-n {
+ top: -20px;
+ left: 0;
+ width: 100%;
+ background-image: url('fancybox-x.png');
+}
+
+#fancybox-bg-ne {
+ top: -20px;
+ right: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -162px;
+}
+
+#fancybox-bg-e {
+ top: 0;
+ right: -20px;
+ height: 100%;
+ background-image: url('fancybox-y.png');
+ background-position: -20px 0px;
+}
+
+#fancybox-bg-se {
+ bottom: -20px;
+ right: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -182px;
+}
+
+#fancybox-bg-s {
+ bottom: -20px;
+ left: 0;
+ width: 100%;
+ background-image: url('fancybox-x.png');
+ background-position: 0px -20px;
+}
+
+#fancybox-bg-sw {
+ bottom: -20px;
+ left: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -142px;
+}
+
+#fancybox-bg-w {
+ top: 0;
+ left: -20px;
+ height: 100%;
+ background-image: url('fancybox-y.png');
+}
+
+#fancybox-bg-nw {
+ top: -20px;
+ left: -20px;
+ background-image: url('fancybox.png');
+ background-position: -40px -122px;
+}
+
+#fancybox-title {
+ font-family: Helvetica;
+ font-size: 12px;
+ z-index: 1102;
+}
+
+.fancybox-title-inside {
+ padding-bottom: 10px;
+ text-align: center;
+ color: #333;
+ background: #fff;
+ position: relative;
+}
+
+.fancybox-title-outside {
+ padding-top: 10px;
+ color: #fff;
+}
+
+.fancybox-title-over {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ color: #FFF;
+ text-align: left;
+}
+
+#fancybox-title-over {
+ padding: 10px;
+ background-image: url('fancy_title_over.png');
+ display: block;
+}
+
+.fancybox-title-float {
+ position: absolute;
+ left: 0;
+ bottom: -20px;
+ height: 32px;
+}
+
+#fancybox-title-float-wrap {
+ border: none;
+ border-collapse: collapse;
+ width: auto;
+}
+
+#fancybox-title-float-wrap td {
+ border: none;
+ white-space: nowrap;
+}
+
+#fancybox-title-float-left {
+ padding: 0 0 0 15px;
+ background: url('fancybox.png') -40px -90px no-repeat;
+}
+
+#fancybox-title-float-main {
+ color: #FFF;
+ line-height: 29px;
+ font-weight: bold;
+ padding: 0 0 3px 0;
+ background: url('fancybox-x.png') 0px -40px;
+}
+
+#fancybox-title-float-right {
+ padding: 0 0 0 15px;
+ background: url('fancybox.png') -55px -90px no-repeat;
+}
+
+/* IE6 */
+
+.fancybox-ie6 #fancybox-close { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_close.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-left-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_left.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-right-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_right.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-title-over { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_over.png', sizingMethod='scale'); zoom: 1; }
+.fancybox-ie6 #fancybox-title-float-left { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_left.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-title-float-main { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_main.png', sizingMethod='scale'); }
+.fancybox-ie6 #fancybox-title-float-right { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_right.png', sizingMethod='scale'); }
+
+.fancybox-ie6 #fancybox-bg-w, .fancybox-ie6 #fancybox-bg-e, .fancybox-ie6 #fancybox-left, .fancybox-ie6 #fancybox-right, #fancybox-hide-sel-frame {
+ height: expression(this.parentNode.clientHeight + "px");
+}
+
+#fancybox-loading.fancybox-ie6 {
+ position: absolute; margin-top: 0;
+ top: expression( (-20 + (document.documentElement.clientHeight ? document.documentElement.clientHeight/2 : document.body.clientHeight/2 ) + ( ignoreMe = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop )) + 'px');
+}
+
+#fancybox-loading.fancybox-ie6 div { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_loading.png', sizingMethod='scale'); }
+
+/* IE6, IE7, IE8 */
+
+.fancybox-ie .fancybox-bg { background: transparent !important; }
+
+.fancybox-ie #fancybox-bg-n { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_n.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-ne { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_ne.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-e { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_e.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-se { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_se.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-s { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_s.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-sw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_sw.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-w { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_w.png', sizingMethod='scale'); }
+.fancybox-ie #fancybox-bg-nw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_nw.png', sizingMethod='scale'); } \ No newline at end of file
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.fancybox-1.3.4.js b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.fancybox-1.3.4.js
new file mode 100644
index 00000000..be772753
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.fancybox-1.3.4.js
@@ -0,0 +1,1156 @@
+/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ *
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
+ *
+ * Version: 1.3.4 (11/11/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+;(function($) {
+ var tmp, loading, overlay, wrap, outer, content, close, title, nav_left, nav_right,
+
+ selectedIndex = 0, selectedOpts = {}, selectedArray = [], currentIndex = 0, currentOpts = {}, currentArray = [],
+
+ ajaxLoader = null, imgPreloader = new Image(), imgRegExp = /\.(jpg|gif|png|bmp|jpeg)(.*)?$/i, swfRegExp = /[^\.]\.(swf)\s*$/i,
+
+ loadingTimer, loadingFrame = 1,
+
+ titleHeight = 0, titleStr = '', start_pos, final_pos, busy = false, fx = $.extend($('<div/>')[0], { prop: 0 }),
+
+ isIE6 = $.browser.msie && $.browser.version < 7 && !window.XMLHttpRequest,
+
+ /*
+ * Private methods
+ */
+
+ _abort = function() {
+ loading.hide();
+
+ imgPreloader.onerror = imgPreloader.onload = null;
+
+ if (ajaxLoader) {
+ ajaxLoader.abort();
+ }
+
+ tmp.empty();
+ },
+
+ _error = function() {
+ if (false === selectedOpts.onError(selectedArray, selectedIndex, selectedOpts)) {
+ loading.hide();
+ busy = false;
+ return;
+ }
+
+ selectedOpts.titleShow = false;
+
+ selectedOpts.width = 'auto';
+ selectedOpts.height = 'auto';
+
+ tmp.html( '<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>' );
+
+ _process_inline();
+ },
+
+ _start = function() {
+ var obj = selectedArray[ selectedIndex ],
+ href,
+ type,
+ title,
+ str,
+ emb,
+ ret;
+
+ _abort();
+
+ selectedOpts = $.extend({}, $.fn.fancybox.defaults, (typeof $(obj).data('fancybox') == 'undefined' ? selectedOpts : $(obj).data('fancybox')));
+
+ ret = selectedOpts.onStart(selectedArray, selectedIndex, selectedOpts);
+
+ if (ret === false) {
+ busy = false;
+ return;
+ } else if (typeof ret == 'object') {
+ selectedOpts = $.extend(selectedOpts, ret);
+ }
+
+ title = selectedOpts.title || (obj.nodeName ? $(obj).attr('title') : obj.title) || '';
+
+ if (obj.nodeName && !selectedOpts.orig) {
+ selectedOpts.orig = $(obj).children("img:first").length ? $(obj).children("img:first") : $(obj);
+ }
+
+ if (title === '' && selectedOpts.orig && selectedOpts.titleFromAlt) {
+ title = selectedOpts.orig.attr('alt');
+ }
+
+ href = selectedOpts.href || (obj.nodeName ? $(obj).attr('href') : obj.href) || null;
+
+ if ((/^(?:javascript)/i).test(href) || href == '#') {
+ href = null;
+ }
+
+ if (selectedOpts.type) {
+ type = selectedOpts.type;
+
+ if (!href) {
+ href = selectedOpts.content;
+ }
+
+ } else if (selectedOpts.content) {
+ type = 'html';
+
+ } else if (href) {
+ if (href.match(imgRegExp)) {
+ type = 'image';
+
+ } else if (href.match(swfRegExp)) {
+ type = 'swf';
+
+ } else if ($(obj).hasClass("iframe")) {
+ type = 'iframe';
+
+ } else if (href.indexOf("#") === 0) {
+ type = 'inline';
+
+ } else {
+ type = 'ajax';
+ }
+ }
+
+ if (!type) {
+ _error();
+ return;
+ }
+
+ if (type == 'inline') {
+ obj = href.substr(href.indexOf("#"));
+ type = $(obj).length > 0 ? 'inline' : 'ajax';
+ }
+
+ selectedOpts.type = type;
+ selectedOpts.href = href;
+ selectedOpts.title = title;
+
+ if (selectedOpts.autoDimensions) {
+ if (selectedOpts.type == 'html' || selectedOpts.type == 'inline' || selectedOpts.type == 'ajax') {
+ selectedOpts.width = 'auto';
+ selectedOpts.height = 'auto';
+ } else {
+ selectedOpts.autoDimensions = false;
+ }
+ }
+
+ if (selectedOpts.modal) {
+ selectedOpts.overlayShow = true;
+ selectedOpts.hideOnOverlayClick = false;
+ selectedOpts.hideOnContentClick = false;
+ selectedOpts.enableEscapeButton = false;
+ selectedOpts.showCloseButton = false;
+ }
+
+ selectedOpts.padding = parseInt(selectedOpts.padding, 10);
+ selectedOpts.margin = parseInt(selectedOpts.margin, 10);
+
+ tmp.css('padding', (selectedOpts.padding + selectedOpts.margin));
+
+ $('.fancybox-inline-tmp').unbind('fancybox-cancel').bind('fancybox-change', function() {
+ $(this).replaceWith(content.children());
+ });
+
+ switch (type) {
+ case 'html' :
+ tmp.html( selectedOpts.content );
+ _process_inline();
+ break;
+
+ case 'inline' :
+ if ( $(obj).parent().is('#fancybox-content') === true) {
+ busy = false;
+ return;
+ }
+
+ $('<div class="fancybox-inline-tmp" />')
+ .hide()
+ .insertBefore( $(obj) )
+ .bind('fancybox-cleanup', function() {
+ $(this).replaceWith(content.children());
+ }).bind('fancybox-cancel', function() {
+ $(this).replaceWith(tmp.children());
+ });
+
+ $(obj).appendTo(tmp);
+
+ _process_inline();
+ break;
+
+ case 'image':
+ busy = false;
+
+ $.fancybox.showActivity();
+
+ imgPreloader = new Image();
+
+ imgPreloader.onerror = function() {
+ _error();
+ };
+
+ imgPreloader.onload = function() {
+ busy = true;
+
+ imgPreloader.onerror = imgPreloader.onload = null;
+
+ _process_image();
+ };
+
+ imgPreloader.src = href;
+ break;
+
+ case 'swf':
+ selectedOpts.scrolling = 'no';
+
+ str = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"><param name="movie" value="' + href + '"></param>';
+ emb = '';
+
+ $.each(selectedOpts.swf, function(name, val) {
+ str += '<param name="' + name + '" value="' + val + '"></param>';
+ emb += ' ' + name + '="' + val + '"';
+ });
+
+ str += '<embed src="' + href + '" type="application/x-shockwave-flash" width="' + selectedOpts.width + '" height="' + selectedOpts.height + '"' + emb + '></embed></object>';
+
+ tmp.html(str);
+
+ _process_inline();
+ break;
+
+ case 'ajax':
+ busy = false;
+
+ $.fancybox.showActivity();
+
+ selectedOpts.ajax.win = selectedOpts.ajax.success;
+
+ ajaxLoader = $.ajax($.extend({}, selectedOpts.ajax, {
+ url : href,
+ data : selectedOpts.ajax.data || {},
+ error : function(XMLHttpRequest, textStatus, errorThrown) {
+ if ( XMLHttpRequest.status > 0 ) {
+ _error();
+ }
+ },
+ success : function(data, textStatus, XMLHttpRequest) {
+ var o = typeof XMLHttpRequest == 'object' ? XMLHttpRequest : ajaxLoader;
+ if (o.status == 200) {
+ if ( typeof selectedOpts.ajax.win == 'function' ) {
+ ret = selectedOpts.ajax.win(href, data, textStatus, XMLHttpRequest);
+
+ if (ret === false) {
+ loading.hide();
+ return;
+ } else if (typeof ret == 'string' || typeof ret == 'object') {
+ data = ret;
+ }
+ }
+
+ tmp.html( data );
+ _process_inline();
+ }
+ }
+ }));
+
+ break;
+
+ case 'iframe':
+ _show();
+ break;
+ }
+ },
+
+ _process_inline = function() {
+ var
+ w = selectedOpts.width,
+ h = selectedOpts.height;
+
+ if (w.toString().indexOf('%') > -1) {
+ w = parseInt( ($(window).width() - (selectedOpts.margin * 2)) * parseFloat(w) / 100, 10) + 'px';
+
+ } else {
+ w = w == 'auto' ? 'auto' : w + 'px';
+ }
+
+ if (h.toString().indexOf('%') > -1) {
+ h = parseInt( ($(window).height() - (selectedOpts.margin * 2)) * parseFloat(h) / 100, 10) + 'px';
+
+ } else {
+ h = h == 'auto' ? 'auto' : h + 'px';
+ }
+
+ tmp.wrapInner('<div style="width:' + w + ';height:' + h + ';overflow: ' + (selectedOpts.scrolling == 'auto' ? 'auto' : (selectedOpts.scrolling == 'yes' ? 'scroll' : 'hidden')) + ';position:relative;"></div>');
+
+ selectedOpts.width = tmp.width();
+ selectedOpts.height = tmp.height();
+
+ _show();
+ },
+
+ _process_image = function() {
+ selectedOpts.width = imgPreloader.width;
+ selectedOpts.height = imgPreloader.height;
+
+ $("<img />").attr({
+ 'id' : 'fancybox-img',
+ 'src' : imgPreloader.src,
+ 'alt' : selectedOpts.title
+ }).appendTo( tmp );
+
+ _show();
+ },
+
+ _show = function() {
+ var pos, equal;
+
+ loading.hide();
+
+ if (wrap.is(":visible") && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) {
+ $.event.trigger('fancybox-cancel');
+
+ busy = false;
+ return;
+ }
+
+ busy = true;
+
+ $(content.add( overlay )).unbind();
+
+ $(window).unbind("resize.fb scroll.fb");
+ $(document).unbind('keydown.fb');
+
+ if (wrap.is(":visible") && currentOpts.titlePosition !== 'outside') {
+ wrap.css('height', wrap.height());
+ }
+
+ currentArray = selectedArray;
+ currentIndex = selectedIndex;
+ currentOpts = selectedOpts;
+
+ if (currentOpts.overlayShow) {
+ overlay.css({
+ 'background-color' : currentOpts.overlayColor,
+ 'opacity' : currentOpts.overlayOpacity,
+ 'cursor' : currentOpts.hideOnOverlayClick ? 'pointer' : 'auto',
+ 'height' : $(document).height()
+ });
+
+ if (!overlay.is(':visible')) {
+ if (isIE6) {
+ $('select:not(#fancybox-tmp select)').filter(function() {
+ return this.style.visibility !== 'hidden';
+ }).css({'visibility' : 'hidden'}).one('fancybox-cleanup', function() {
+ this.style.visibility = 'inherit';
+ });
+ }
+
+ overlay.show();
+ }
+ } else {
+ overlay.hide();
+ }
+
+ final_pos = _get_zoom_to();
+
+ _process_title();
+
+ if (wrap.is(":visible")) {
+ $( close.add( nav_left ).add( nav_right ) ).hide();
+
+ pos = wrap.position(),
+
+ start_pos = {
+ top : pos.top,
+ left : pos.left,
+ width : wrap.width(),
+ height : wrap.height()
+ };
+
+ equal = (start_pos.width == final_pos.width && start_pos.height == final_pos.height);
+
+ content.fadeTo(currentOpts.changeFade, 0.3, function() {
+ var finish_resizing = function() {
+ content.html( tmp.contents() ).fadeTo(currentOpts.changeFade, 1, _finish);
+ };
+
+ $.event.trigger('fancybox-change');
+
+ content
+ .empty()
+ .removeAttr('filter')
+ .css({
+ 'border-width' : currentOpts.padding,
+ 'width' : final_pos.width - currentOpts.padding * 2,
+ 'height' : selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2
+ });
+
+ if (equal) {
+ finish_resizing();
+
+ } else {
+ fx.prop = 0;
+
+ $(fx).animate({prop: 1}, {
+ duration : currentOpts.changeSpeed,
+ easing : currentOpts.easingChange,
+ step : _draw,
+ complete : finish_resizing
+ });
+ }
+ });
+
+ return;
+ }
+
+ wrap.removeAttr("style");
+
+ content.css('border-width', currentOpts.padding);
+
+ if (currentOpts.transitionIn == 'elastic') {
+ start_pos = _get_zoom_from();
+
+ content.html( tmp.contents() );
+
+ wrap.show();
+
+ if (currentOpts.opacity) {
+ final_pos.opacity = 0;
+ }
+
+ fx.prop = 0;
+
+ $(fx).animate({prop: 1}, {
+ duration : currentOpts.speedIn,
+ easing : currentOpts.easingIn,
+ step : _draw,
+ complete : _finish
+ });
+
+ return;
+ }
+
+ if (currentOpts.titlePosition == 'inside' && titleHeight > 0) {
+ title.show();
+ }
+
+ content
+ .css({
+ 'width' : final_pos.width - currentOpts.padding * 2,
+ 'height' : selectedOpts.autoDimensions ? 'auto' : final_pos.height - titleHeight - currentOpts.padding * 2
+ })
+ .html( tmp.contents() );
+
+ wrap
+ .css(final_pos)
+ .fadeIn( currentOpts.transitionIn == 'none' ? 0 : currentOpts.speedIn, _finish );
+ },
+
+ _format_title = function(title) {
+ if (title && title.length) {
+ if (currentOpts.titlePosition == 'float') {
+ return '<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">' + title + '</td><td id="fancybox-title-float-right"></td></tr></table>';
+ }
+
+ return '<div id="fancybox-title-' + currentOpts.titlePosition + '">' + title + '</div>';
+ }
+
+ return false;
+ },
+
+ _process_title = function() {
+ titleStr = currentOpts.title || '';
+ titleHeight = 0;
+
+ title
+ .empty()
+ .removeAttr('style')
+ .removeClass();
+
+ if (currentOpts.titleShow === false) {
+ title.hide();
+ return;
+ }
+
+ titleStr = $.isFunction(currentOpts.titleFormat) ? currentOpts.titleFormat(titleStr, currentArray, currentIndex, currentOpts) : _format_title(titleStr);
+
+ if (!titleStr || titleStr === '') {
+ title.hide();
+ return;
+ }
+
+ title
+ .addClass('fancybox-title-' + currentOpts.titlePosition)
+ .html( titleStr )
+ .appendTo( 'body' )
+ .show();
+
+ switch (currentOpts.titlePosition) {
+ case 'inside':
+ title
+ .css({
+ 'width' : final_pos.width - (currentOpts.padding * 2),
+ 'marginLeft' : currentOpts.padding,
+ 'marginRight' : currentOpts.padding
+ });
+
+ titleHeight = title.outerHeight(true);
+
+ title.appendTo( outer );
+
+ final_pos.height += titleHeight;
+ break;
+
+ case 'over':
+ title
+ .css({
+ 'marginLeft' : currentOpts.padding,
+ 'width' : final_pos.width - (currentOpts.padding * 2),
+ 'bottom' : currentOpts.padding
+ })
+ .appendTo( outer );
+ break;
+
+ case 'float':
+ title
+ .css('left', parseInt((title.width() - final_pos.width - 40)/ 2, 10) * -1)
+ .appendTo( wrap );
+ break;
+
+ default:
+ title
+ .css({
+ 'width' : final_pos.width - (currentOpts.padding * 2),
+ 'paddingLeft' : currentOpts.padding,
+ 'paddingRight' : currentOpts.padding
+ })
+ .appendTo( wrap );
+ break;
+ }
+
+ title.hide();
+ },
+
+ _set_navigation = function() {
+ if (currentOpts.enableEscapeButton || currentOpts.enableKeyboardNav) {
+ $(document).bind('keydown.fb', function(e) {
+ if (e.keyCode == 27 && currentOpts.enableEscapeButton) {
+ e.preventDefault();
+ $.fancybox.close();
+
+ } else if ((e.keyCode == 37 || e.keyCode == 39) && currentOpts.enableKeyboardNav && e.target.tagName !== 'INPUT' && e.target.tagName !== 'TEXTAREA' && e.target.tagName !== 'SELECT') {
+ e.preventDefault();
+ $.fancybox[ e.keyCode == 37 ? 'prev' : 'next']();
+ }
+ });
+ }
+
+ if (!currentOpts.showNavArrows) {
+ nav_left.hide();
+ nav_right.hide();
+ return;
+ }
+
+ if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex !== 0) {
+ nav_left.show();
+ }
+
+ if ((currentOpts.cyclic && currentArray.length > 1) || currentIndex != (currentArray.length -1)) {
+ nav_right.show();
+ }
+ },
+
+ _finish = function () {
+ if (!$.support.opacity) {
+ content.get(0).style.removeAttribute('filter');
+ wrap.get(0).style.removeAttribute('filter');
+ }
+
+ if (selectedOpts.autoDimensions) {
+ content.css('height', 'auto');
+ }
+
+ wrap.css('height', 'auto');
+
+ if (titleStr && titleStr.length) {
+ title.show();
+ }
+
+ if (currentOpts.showCloseButton) {
+ close.show();
+ }
+
+ _set_navigation();
+
+ if (currentOpts.hideOnContentClick) {
+ content.bind('click', $.fancybox.close);
+ }
+
+ if (currentOpts.hideOnOverlayClick) {
+ overlay.bind('click', $.fancybox.close);
+ }
+
+ $(window).bind("resize.fb", $.fancybox.resize);
+
+ if (currentOpts.centerOnScroll) {
+ $(window).bind("scroll.fb", $.fancybox.center);
+ }
+
+ if (currentOpts.type == 'iframe') {
+ $('<iframe id="fancybox-frame" name="fancybox-frame' + new Date().getTime() + '" frameborder="0" hspace="0" ' + ($.browser.msie ? 'allowtransparency="true""' : '') + ' scrolling="' + selectedOpts.scrolling + '" src="' + currentOpts.href + '"></iframe>').appendTo(content);
+ }
+
+ wrap.show();
+
+ busy = false;
+
+ $.fancybox.center();
+
+ currentOpts.onComplete(currentArray, currentIndex, currentOpts);
+
+ _preload_images();
+ },
+
+ _preload_images = function() {
+ var href,
+ objNext;
+
+ if ((currentArray.length -1) > currentIndex) {
+ href = currentArray[ currentIndex + 1 ].href;
+
+ if (typeof href !== 'undefined' && href.match(imgRegExp)) {
+ objNext = new Image();
+ objNext.src = href;
+ }
+ }
+
+ if (currentIndex > 0) {
+ href = currentArray[ currentIndex - 1 ].href;
+
+ if (typeof href !== 'undefined' && href.match(imgRegExp)) {
+ objNext = new Image();
+ objNext.src = href;
+ }
+ }
+ },
+
+ _draw = function(pos) {
+ var dim = {
+ width : parseInt(start_pos.width + (final_pos.width - start_pos.width) * pos, 10),
+ height : parseInt(start_pos.height + (final_pos.height - start_pos.height) * pos, 10),
+
+ top : parseInt(start_pos.top + (final_pos.top - start_pos.top) * pos, 10),
+ left : parseInt(start_pos.left + (final_pos.left - start_pos.left) * pos, 10)
+ };
+
+ if (typeof final_pos.opacity !== 'undefined') {
+ dim.opacity = pos < 0.5 ? 0.5 : pos;
+ }
+
+ wrap.css(dim);
+
+ content.css({
+ 'width' : dim.width - currentOpts.padding * 2,
+ 'height' : dim.height - (titleHeight * pos) - currentOpts.padding * 2
+ });
+ },
+
+ _get_viewport = function() {
+ return [
+ $(window).width() - (currentOpts.margin * 2),
+ $(window).height() - (currentOpts.margin * 2),
+ $(document).scrollLeft() + currentOpts.margin,
+ $(document).scrollTop() + currentOpts.margin
+ ];
+ },
+
+ _get_zoom_to = function () {
+ var view = _get_viewport(),
+ to = {},
+ resize = currentOpts.autoScale,
+ double_padding = currentOpts.padding * 2,
+ ratio;
+
+ if (currentOpts.width.toString().indexOf('%') > -1) {
+ to.width = parseInt((view[0] * parseFloat(currentOpts.width)) / 100, 10);
+ } else {
+ to.width = currentOpts.width + double_padding;
+ }
+
+ if (currentOpts.height.toString().indexOf('%') > -1) {
+ to.height = parseInt((view[1] * parseFloat(currentOpts.height)) / 100, 10);
+ } else {
+ to.height = currentOpts.height + double_padding;
+ }
+
+ if (resize && (to.width > view[0] || to.height > view[1])) {
+ if (selectedOpts.type == 'image' || selectedOpts.type == 'swf') {
+ ratio = (currentOpts.width ) / (currentOpts.height );
+
+ if ((to.width ) > view[0]) {
+ to.width = view[0];
+ to.height = parseInt(((to.width - double_padding) / ratio) + double_padding, 10);
+ }
+
+ if ((to.height) > view[1]) {
+ to.height = view[1];
+ to.width = parseInt(((to.height - double_padding) * ratio) + double_padding, 10);
+ }
+
+ } else {
+ to.width = Math.min(to.width, view[0]);
+ to.height = Math.min(to.height, view[1]);
+ }
+ }
+
+ to.top = parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - to.height - 40) * 0.5)), 10);
+ to.left = parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - to.width - 40) * 0.5)), 10);
+
+ return to;
+ },
+
+ _get_obj_pos = function(obj) {
+ var pos = obj.offset();
+
+ pos.top += parseInt( obj.css('paddingTop'), 10 ) || 0;
+ pos.left += parseInt( obj.css('paddingLeft'), 10 ) || 0;
+
+ pos.top += parseInt( obj.css('border-top-width'), 10 ) || 0;
+ pos.left += parseInt( obj.css('border-left-width'), 10 ) || 0;
+
+ pos.width = obj.width();
+ pos.height = obj.height();
+
+ return pos;
+ },
+
+ _get_zoom_from = function() {
+ var orig = selectedOpts.orig ? $(selectedOpts.orig) : false,
+ from = {},
+ pos,
+ view;
+
+ if (orig && orig.length) {
+ pos = _get_obj_pos(orig);
+
+ from = {
+ width : pos.width + (currentOpts.padding * 2),
+ height : pos.height + (currentOpts.padding * 2),
+ top : pos.top - currentOpts.padding - 20,
+ left : pos.left - currentOpts.padding - 20
+ };
+
+ } else {
+ view = _get_viewport();
+
+ from = {
+ width : currentOpts.padding * 2,
+ height : currentOpts.padding * 2,
+ top : parseInt(view[3] + view[1] * 0.5, 10),
+ left : parseInt(view[2] + view[0] * 0.5, 10)
+ };
+ }
+
+ return from;
+ },
+
+ _animate_loading = function() {
+ if (!loading.is(':visible')){
+ clearInterval(loadingTimer);
+ return;
+ }
+
+ $('div', loading).css('top', (loadingFrame * -40) + 'px');
+
+ loadingFrame = (loadingFrame + 1) % 12;
+ };
+
+ /*
+ * Public methods
+ */
+
+ $.fn.fancybox = function(options) {
+ if (!$(this).length) {
+ return this;
+ }
+
+ $(this)
+ .data('fancybox', $.extend({}, options, ($.metadata ? $(this).metadata() : {})))
+ .unbind('click.fb')
+ .bind('click.fb', function(e) {
+ e.preventDefault();
+
+ if (busy) {
+ return;
+ }
+
+ busy = true;
+
+ $(this).blur();
+
+ selectedArray = [];
+ selectedIndex = 0;
+
+ var rel = $(this).attr('rel') || '';
+
+ if (!rel || rel == '' || rel === 'nofollow') {
+ selectedArray.push(this);
+
+ } else {
+ selectedArray = $("a[rel=" + rel + "], area[rel=" + rel + "]");
+ selectedIndex = selectedArray.index( this );
+ }
+
+ _start();
+
+ return;
+ });
+
+ return this;
+ };
+
+ $.fancybox = function(obj) {
+ var opts;
+
+ if (busy) {
+ return;
+ }
+
+ busy = true;
+ opts = typeof arguments[1] !== 'undefined' ? arguments[1] : {};
+
+ selectedArray = [];
+ selectedIndex = parseInt(opts.index, 10) || 0;
+
+ if ($.isArray(obj)) {
+ for (var i = 0, j = obj.length; i < j; i++) {
+ if (typeof obj[i] == 'object') {
+ $(obj[i]).data('fancybox', $.extend({}, opts, obj[i]));
+ } else {
+ obj[i] = $({}).data('fancybox', $.extend({content : obj[i]}, opts));
+ }
+ }
+
+ selectedArray = jQuery.merge(selectedArray, obj);
+
+ } else {
+ if (typeof obj == 'object') {
+ $(obj).data('fancybox', $.extend({}, opts, obj));
+ } else {
+ obj = $({}).data('fancybox', $.extend({content : obj}, opts));
+ }
+
+ selectedArray.push(obj);
+ }
+
+ if (selectedIndex > selectedArray.length || selectedIndex < 0) {
+ selectedIndex = 0;
+ }
+
+ _start();
+ };
+
+ $.fancybox.showActivity = function() {
+ clearInterval(loadingTimer);
+
+ loading.show();
+ loadingTimer = setInterval(_animate_loading, 66);
+ };
+
+ $.fancybox.hideActivity = function() {
+ loading.hide();
+ };
+
+ $.fancybox.next = function() {
+ return $.fancybox.pos( currentIndex + 1);
+ };
+
+ $.fancybox.prev = function() {
+ return $.fancybox.pos( currentIndex - 1);
+ };
+
+ $.fancybox.pos = function(pos) {
+ if (busy) {
+ return;
+ }
+
+ pos = parseInt(pos);
+
+ selectedArray = currentArray;
+
+ if (pos > -1 && pos < currentArray.length) {
+ selectedIndex = pos;
+ _start();
+
+ } else if (currentOpts.cyclic && currentArray.length > 1) {
+ selectedIndex = pos >= currentArray.length ? 0 : currentArray.length - 1;
+ _start();
+ }
+
+ return;
+ };
+
+ $.fancybox.cancel = function() {
+ if (busy) {
+ return;
+ }
+
+ busy = true;
+
+ $.event.trigger('fancybox-cancel');
+
+ _abort();
+
+ selectedOpts.onCancel(selectedArray, selectedIndex, selectedOpts);
+
+ busy = false;
+ };
+
+ // Note: within an iframe use - parent.$.fancybox.close();
+ $.fancybox.close = function() {
+ if (busy || wrap.is(':hidden')) {
+ return;
+ }
+
+ busy = true;
+
+ if (currentOpts && false === currentOpts.onCleanup(currentArray, currentIndex, currentOpts)) {
+ busy = false;
+ return;
+ }
+
+ _abort();
+
+ $(close.add( nav_left ).add( nav_right )).hide();
+
+ $(content.add( overlay )).unbind();
+
+ $(window).unbind("resize.fb scroll.fb");
+ $(document).unbind('keydown.fb');
+
+ content.find('iframe').attr('src', isIE6 && /^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank');
+
+ if (currentOpts.titlePosition !== 'inside') {
+ title.empty();
+ }
+
+ wrap.stop();
+
+ function _cleanup() {
+ overlay.fadeOut('fast');
+
+ title.empty().hide();
+ wrap.hide();
+
+ $.event.trigger('fancybox-cleanup');
+
+ content.empty();
+
+ currentOpts.onClosed(currentArray, currentIndex, currentOpts);
+
+ currentArray = selectedOpts = [];
+ currentIndex = selectedIndex = 0;
+ currentOpts = selectedOpts = {};
+
+ busy = false;
+ }
+
+ if (currentOpts.transitionOut == 'elastic') {
+ start_pos = _get_zoom_from();
+
+ var pos = wrap.position();
+
+ final_pos = {
+ top : pos.top ,
+ left : pos.left,
+ width : wrap.width(),
+ height : wrap.height()
+ };
+
+ if (currentOpts.opacity) {
+ final_pos.opacity = 1;
+ }
+
+ title.empty().hide();
+
+ fx.prop = 1;
+
+ $(fx).animate({ prop: 0 }, {
+ duration : currentOpts.speedOut,
+ easing : currentOpts.easingOut,
+ step : _draw,
+ complete : _cleanup
+ });
+
+ } else {
+ wrap.fadeOut( currentOpts.transitionOut == 'none' ? 0 : currentOpts.speedOut, _cleanup);
+ }
+ };
+
+ $.fancybox.resize = function() {
+ if (overlay.is(':visible')) {
+ overlay.css('height', $(document).height());
+ }
+
+ $.fancybox.center(true);
+ };
+
+ $.fancybox.center = function() {
+ var view, align;
+
+ if (busy) {
+ return;
+ }
+
+ align = arguments[0] === true ? 1 : 0;
+ view = _get_viewport();
+
+ if (!align && (wrap.width() > view[0] || wrap.height() > view[1])) {
+ return;
+ }
+
+ wrap
+ .stop()
+ .animate({
+ 'top' : parseInt(Math.max(view[3] - 20, view[3] + ((view[1] - content.height() - 40) * 0.5) - currentOpts.padding)),
+ 'left' : parseInt(Math.max(view[2] - 20, view[2] + ((view[0] - content.width() - 40) * 0.5) - currentOpts.padding))
+ }, typeof arguments[0] == 'number' ? arguments[0] : 200);
+ };
+
+ $.fancybox.init = function() {
+ if ($("#fancybox-wrap").length) {
+ return;
+ }
+
+ $('body').append(
+ tmp = $('<div id="fancybox-tmp"></div>'),
+ loading = $('<div id="fancybox-loading"><div></div></div>'),
+ overlay = $('<div id="fancybox-overlay"></div>'),
+ wrap = $('<div id="fancybox-wrap"></div>')
+ );
+
+ outer = $('<div id="fancybox-outer"></div>')
+ .append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>')
+ .appendTo( wrap );
+
+ outer.append(
+ content = $('<div id="fancybox-content"></div>'),
+ close = $('<a id="fancybox-close"></a>'),
+ title = $('<div id="fancybox-title"></div>'),
+
+ nav_left = $('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),
+ nav_right = $('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>')
+ );
+
+ close.click($.fancybox.close);
+ loading.click($.fancybox.cancel);
+
+ nav_left.click(function(e) {
+ e.preventDefault();
+ $.fancybox.prev();
+ });
+
+ nav_right.click(function(e) {
+ e.preventDefault();
+ $.fancybox.next();
+ });
+
+ if ($.fn.mousewheel) {
+ wrap.bind('mousewheel.fb', function(e, delta) {
+ if (busy) {
+ e.preventDefault();
+
+ } else if ($(e.target).get(0).clientHeight == 0 || $(e.target).get(0).scrollHeight === $(e.target).get(0).clientHeight) {
+ e.preventDefault();
+ $.fancybox[ delta > 0 ? 'prev' : 'next']();
+ }
+ });
+ }
+
+ if (!$.support.opacity) {
+ wrap.addClass('fancybox-ie');
+ }
+
+ if (isIE6) {
+ loading.addClass('fancybox-ie6');
+ wrap.addClass('fancybox-ie6');
+
+ $('<iframe id="fancybox-hide-sel-frame" src="' + (/^https/i.test(window.location.href || '') ? 'javascript:void(false)' : 'about:blank' ) + '" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(outer);
+ }
+ };
+
+ $.fn.fancybox.defaults = {
+ padding : 10,
+ margin : 40,
+ opacity : false,
+ modal : false,
+ cyclic : false,
+ scrolling : 'auto', // 'auto', 'yes' or 'no'
+
+ width : 560,
+ height : 340,
+
+ autoScale : true,
+ autoDimensions : true,
+ centerOnScroll : false,
+
+ ajax : {},
+ swf : { wmode: 'transparent' },
+
+ hideOnOverlayClick : true,
+ hideOnContentClick : false,
+
+ overlayShow : true,
+ overlayOpacity : 0.7,
+ overlayColor : '#777',
+
+ titleShow : true,
+ titlePosition : 'float', // 'float', 'outside', 'inside' or 'over'
+ titleFormat : null,
+ titleFromAlt : false,
+
+ transitionIn : 'fade', // 'elastic', 'fade' or 'none'
+ transitionOut : 'fade', // 'elastic', 'fade' or 'none'
+
+ speedIn : 300,
+ speedOut : 300,
+
+ changeSpeed : 300,
+ changeFade : 'fast',
+
+ easingIn : 'swing',
+ easingOut : 'swing',
+
+ showCloseButton : true,
+ showNavArrows : true,
+ enableEscapeButton : true,
+ enableKeyboardNav : true,
+
+ onStart : function(){},
+ onCancel : function(){},
+ onComplete : function(){},
+ onCleanup : function(){},
+ onClosed : function(){},
+ onError : function(){}
+ };
+
+ $(document).ready(function() {
+ $.fancybox.init();
+ });
+
+})(jQuery); \ No newline at end of file
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.fancybox-1.3.4.pack.js b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.fancybox-1.3.4.pack.js
new file mode 100644
index 00000000..1373ed08
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.fancybox-1.3.4.pack.js
@@ -0,0 +1,46 @@
+/*
+ * FancyBox - jQuery Plugin
+ * Simple and fancy lightbox alternative
+ *
+ * Examples and documentation at: http://fancybox.net
+ *
+ * Copyright (c) 2008 - 2010 Janis Skarnelis
+ * That said, it is hardly a one-person project. Many people have submitted bugs, code, and offered their advice freely. Their support is greatly appreciated.
+ *
+ * Version: 1.3.4 (11/11/2010)
+ * Requires: jQuery v1.3+
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+;(function(b){var m,t,u,f,D,j,E,n,z,A,q=0,e={},o=[],p=0,d={},l=[],G=null,v=new Image,J=/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i,W=/[^\.]\.(swf)\s*$/i,K,L=1,y=0,s="",r,i,h=false,B=b.extend(b("<div/>")[0],{prop:0}),M=b.browser.msie&&b.browser.version<7&&!window.XMLHttpRequest,N=function(){t.hide();v.onerror=v.onload=null;G&&G.abort();m.empty()},O=function(){if(false===e.onError(o,q,e)){t.hide();h=false}else{e.titleShow=false;e.width="auto";e.height="auto";m.html('<p id="fancybox-error">The requested content cannot be loaded.<br />Please try again later.</p>');
+F()}},I=function(){var a=o[q],c,g,k,C,P,w;N();e=b.extend({},b.fn.fancybox.defaults,typeof b(a).data("fancybox")=="undefined"?e:b(a).data("fancybox"));w=e.onStart(o,q,e);if(w===false)h=false;else{if(typeof w=="object")e=b.extend(e,w);k=e.title||(a.nodeName?b(a).attr("title"):a.title)||"";if(a.nodeName&&!e.orig)e.orig=b(a).children("img:first").length?b(a).children("img:first"):b(a);if(k===""&&e.orig&&e.titleFromAlt)k=e.orig.attr("alt");c=e.href||(a.nodeName?b(a).attr("href"):a.href)||null;if(/^(?:javascript)/i.test(c)||
+c=="#")c=null;if(e.type){g=e.type;if(!c)c=e.content}else if(e.content)g="html";else if(c)g=c.match(J)?"image":c.match(W)?"swf":b(a).hasClass("iframe")?"iframe":c.indexOf("#")===0?"inline":"ajax";if(g){if(g=="inline"){a=c.substr(c.indexOf("#"));g=b(a).length>0?"inline":"ajax"}e.type=g;e.href=c;e.title=k;if(e.autoDimensions)if(e.type=="html"||e.type=="inline"||e.type=="ajax"){e.width="auto";e.height="auto"}else e.autoDimensions=false;if(e.modal){e.overlayShow=true;e.hideOnOverlayClick=false;e.hideOnContentClick=
+false;e.enableEscapeButton=false;e.showCloseButton=false}e.padding=parseInt(e.padding,10);e.margin=parseInt(e.margin,10);m.css("padding",e.padding+e.margin);b(".fancybox-inline-tmp").unbind("fancybox-cancel").bind("fancybox-change",function(){b(this).replaceWith(j.children())});switch(g){case "html":m.html(e.content);F();break;case "inline":if(b(a).parent().is("#fancybox-content")===true){h=false;break}b('<div class="fancybox-inline-tmp" />').hide().insertBefore(b(a)).bind("fancybox-cleanup",function(){b(this).replaceWith(j.children())}).bind("fancybox-cancel",
+function(){b(this).replaceWith(m.children())});b(a).appendTo(m);F();break;case "image":h=false;b.fancybox.showActivity();v=new Image;v.onerror=function(){O()};v.onload=function(){h=true;v.onerror=v.onload=null;e.width=v.width;e.height=v.height;b("<img />").attr({id:"fancybox-img",src:v.src,alt:e.title}).appendTo(m);Q()};v.src=c;break;case "swf":e.scrolling="no";C='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="'+e.width+'" height="'+e.height+'"><param name="movie" value="'+c+
+'"></param>';P="";b.each(e.swf,function(x,H){C+='<param name="'+x+'" value="'+H+'"></param>';P+=" "+x+'="'+H+'"'});C+='<embed src="'+c+'" type="application/x-shockwave-flash" width="'+e.width+'" height="'+e.height+'"'+P+"></embed></object>";m.html(C);F();break;case "ajax":h=false;b.fancybox.showActivity();e.ajax.win=e.ajax.success;G=b.ajax(b.extend({},e.ajax,{url:c,data:e.ajax.data||{},error:function(x){x.status>0&&O()},success:function(x,H,R){if((typeof R=="object"?R:G).status==200){if(typeof e.ajax.win==
+"function"){w=e.ajax.win(c,x,H,R);if(w===false){t.hide();return}else if(typeof w=="string"||typeof w=="object")x=w}m.html(x);F()}}}));break;case "iframe":Q()}}else O()}},F=function(){var a=e.width,c=e.height;a=a.toString().indexOf("%")>-1?parseInt((b(window).width()-e.margin*2)*parseFloat(a)/100,10)+"px":a=="auto"?"auto":a+"px";c=c.toString().indexOf("%")>-1?parseInt((b(window).height()-e.margin*2)*parseFloat(c)/100,10)+"px":c=="auto"?"auto":c+"px";m.wrapInner('<div style="width:'+a+";height:"+c+
+";overflow: "+(e.scrolling=="auto"?"auto":e.scrolling=="yes"?"scroll":"hidden")+';position:relative;"></div>');e.width=m.width();e.height=m.height();Q()},Q=function(){var a,c;t.hide();if(f.is(":visible")&&false===d.onCleanup(l,p,d)){b.event.trigger("fancybox-cancel");h=false}else{h=true;b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");f.is(":visible")&&d.titlePosition!=="outside"&&f.css("height",f.height());l=o;p=q;d=e;if(d.overlayShow){u.css({"background-color":d.overlayColor,
+opacity:d.overlayOpacity,cursor:d.hideOnOverlayClick?"pointer":"auto",height:b(document).height()});if(!u.is(":visible")){M&&b("select:not(#fancybox-tmp select)").filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one("fancybox-cleanup",function(){this.style.visibility="inherit"});u.show()}}else u.hide();i=X();s=d.title||"";y=0;n.empty().removeAttr("style").removeClass();if(d.titleShow!==false){if(b.isFunction(d.titleFormat))a=d.titleFormat(s,l,p,d);else a=s&&s.length?
+d.titlePosition=="float"?'<table id="fancybox-title-float-wrap" cellpadding="0" cellspacing="0"><tr><td id="fancybox-title-float-left"></td><td id="fancybox-title-float-main">'+s+'</td><td id="fancybox-title-float-right"></td></tr></table>':'<div id="fancybox-title-'+d.titlePosition+'">'+s+"</div>":false;s=a;if(!(!s||s==="")){n.addClass("fancybox-title-"+d.titlePosition).html(s).appendTo("body").show();switch(d.titlePosition){case "inside":n.css({width:i.width-d.padding*2,marginLeft:d.padding,marginRight:d.padding});
+y=n.outerHeight(true);n.appendTo(D);i.height+=y;break;case "over":n.css({marginLeft:d.padding,width:i.width-d.padding*2,bottom:d.padding}).appendTo(D);break;case "float":n.css("left",parseInt((n.width()-i.width-40)/2,10)*-1).appendTo(f);break;default:n.css({width:i.width-d.padding*2,paddingLeft:d.padding,paddingRight:d.padding}).appendTo(f)}}}n.hide();if(f.is(":visible")){b(E.add(z).add(A)).hide();a=f.position();r={top:a.top,left:a.left,width:f.width(),height:f.height()};c=r.width==i.width&&r.height==
+i.height;j.fadeTo(d.changeFade,0.3,function(){var g=function(){j.html(m.contents()).fadeTo(d.changeFade,1,S)};b.event.trigger("fancybox-change");j.empty().removeAttr("filter").css({"border-width":d.padding,width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2});if(c)g();else{B.prop=0;b(B).animate({prop:1},{duration:d.changeSpeed,easing:d.easingChange,step:T,complete:g})}})}else{f.removeAttr("style");j.css("border-width",d.padding);if(d.transitionIn=="elastic"){r=V();j.html(m.contents());
+f.show();if(d.opacity)i.opacity=0;B.prop=0;b(B).animate({prop:1},{duration:d.speedIn,easing:d.easingIn,step:T,complete:S})}else{d.titlePosition=="inside"&&y>0&&n.show();j.css({width:i.width-d.padding*2,height:e.autoDimensions?"auto":i.height-y-d.padding*2}).html(m.contents());f.css(i).fadeIn(d.transitionIn=="none"?0:d.speedIn,S)}}}},Y=function(){if(d.enableEscapeButton||d.enableKeyboardNav)b(document).bind("keydown.fb",function(a){if(a.keyCode==27&&d.enableEscapeButton){a.preventDefault();b.fancybox.close()}else if((a.keyCode==
+37||a.keyCode==39)&&d.enableKeyboardNav&&a.target.tagName!=="INPUT"&&a.target.tagName!=="TEXTAREA"&&a.target.tagName!=="SELECT"){a.preventDefault();b.fancybox[a.keyCode==37?"prev":"next"]()}});if(d.showNavArrows){if(d.cyclic&&l.length>1||p!==0)z.show();if(d.cyclic&&l.length>1||p!=l.length-1)A.show()}else{z.hide();A.hide()}},S=function(){if(!b.support.opacity){j.get(0).style.removeAttribute("filter");f.get(0).style.removeAttribute("filter")}e.autoDimensions&&j.css("height","auto");f.css("height","auto");
+s&&s.length&&n.show();d.showCloseButton&&E.show();Y();d.hideOnContentClick&&j.bind("click",b.fancybox.close);d.hideOnOverlayClick&&u.bind("click",b.fancybox.close);b(window).bind("resize.fb",b.fancybox.resize);d.centerOnScroll&&b(window).bind("scroll.fb",b.fancybox.center);if(d.type=="iframe")b('<iframe id="fancybox-frame" name="fancybox-frame'+(new Date).getTime()+'" frameborder="0" hspace="0" '+(b.browser.msie?'allowtransparency="true""':"")+' scrolling="'+e.scrolling+'" src="'+d.href+'"></iframe>').appendTo(j);
+f.show();h=false;b.fancybox.center();d.onComplete(l,p,d);var a,c;if(l.length-1>p){a=l[p+1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}if(p>0){a=l[p-1].href;if(typeof a!=="undefined"&&a.match(J)){c=new Image;c.src=a}}},T=function(a){var c={width:parseInt(r.width+(i.width-r.width)*a,10),height:parseInt(r.height+(i.height-r.height)*a,10),top:parseInt(r.top+(i.top-r.top)*a,10),left:parseInt(r.left+(i.left-r.left)*a,10)};if(typeof i.opacity!=="undefined")c.opacity=a<0.5?0.5:a;f.css(c);
+j.css({width:c.width-d.padding*2,height:c.height-y*a-d.padding*2})},U=function(){return[b(window).width()-d.margin*2,b(window).height()-d.margin*2,b(document).scrollLeft()+d.margin,b(document).scrollTop()+d.margin]},X=function(){var a=U(),c={},g=d.autoScale,k=d.padding*2;c.width=d.width.toString().indexOf("%")>-1?parseInt(a[0]*parseFloat(d.width)/100,10):d.width+k;c.height=d.height.toString().indexOf("%")>-1?parseInt(a[1]*parseFloat(d.height)/100,10):d.height+k;if(g&&(c.width>a[0]||c.height>a[1]))if(e.type==
+"image"||e.type=="swf"){g=d.width/d.height;if(c.width>a[0]){c.width=a[0];c.height=parseInt((c.width-k)/g+k,10)}if(c.height>a[1]){c.height=a[1];c.width=parseInt((c.height-k)*g+k,10)}}else{c.width=Math.min(c.width,a[0]);c.height=Math.min(c.height,a[1])}c.top=parseInt(Math.max(a[3]-20,a[3]+(a[1]-c.height-40)*0.5),10);c.left=parseInt(Math.max(a[2]-20,a[2]+(a[0]-c.width-40)*0.5),10);return c},V=function(){var a=e.orig?b(e.orig):false,c={};if(a&&a.length){c=a.offset();c.top+=parseInt(a.css("paddingTop"),
+10)||0;c.left+=parseInt(a.css("paddingLeft"),10)||0;c.top+=parseInt(a.css("border-top-width"),10)||0;c.left+=parseInt(a.css("border-left-width"),10)||0;c.width=a.width();c.height=a.height();c={width:c.width+d.padding*2,height:c.height+d.padding*2,top:c.top-d.padding-20,left:c.left-d.padding-20}}else{a=U();c={width:d.padding*2,height:d.padding*2,top:parseInt(a[3]+a[1]*0.5,10),left:parseInt(a[2]+a[0]*0.5,10)}}return c},Z=function(){if(t.is(":visible")){b("div",t).css("top",L*-40+"px");L=(L+1)%12}else clearInterval(K)};
+b.fn.fancybox=function(a){if(!b(this).length)return this;b(this).data("fancybox",b.extend({},a,b.metadata?b(this).metadata():{})).unbind("click.fb").bind("click.fb",function(c){c.preventDefault();if(!h){h=true;b(this).blur();o=[];q=0;c=b(this).attr("rel")||"";if(!c||c==""||c==="nofollow")o.push(this);else{o=b("a[rel="+c+"], area[rel="+c+"]");q=o.index(this)}I()}});return this};b.fancybox=function(a,c){var g;if(!h){h=true;g=typeof c!=="undefined"?c:{};o=[];q=parseInt(g.index,10)||0;if(b.isArray(a)){for(var k=
+0,C=a.length;k<C;k++)if(typeof a[k]=="object")b(a[k]).data("fancybox",b.extend({},g,a[k]));else a[k]=b({}).data("fancybox",b.extend({content:a[k]},g));o=jQuery.merge(o,a)}else{if(typeof a=="object")b(a).data("fancybox",b.extend({},g,a));else a=b({}).data("fancybox",b.extend({content:a},g));o.push(a)}if(q>o.length||q<0)q=0;I()}};b.fancybox.showActivity=function(){clearInterval(K);t.show();K=setInterval(Z,66)};b.fancybox.hideActivity=function(){t.hide()};b.fancybox.next=function(){return b.fancybox.pos(p+
+1)};b.fancybox.prev=function(){return b.fancybox.pos(p-1)};b.fancybox.pos=function(a){if(!h){a=parseInt(a);o=l;if(a>-1&&a<l.length){q=a;I()}else if(d.cyclic&&l.length>1){q=a>=l.length?0:l.length-1;I()}}};b.fancybox.cancel=function(){if(!h){h=true;b.event.trigger("fancybox-cancel");N();e.onCancel(o,q,e);h=false}};b.fancybox.close=function(){function a(){u.fadeOut("fast");n.empty().hide();f.hide();b.event.trigger("fancybox-cleanup");j.empty();d.onClosed(l,p,d);l=e=[];p=q=0;d=e={};h=false}if(!(h||f.is(":hidden"))){h=
+true;if(d&&false===d.onCleanup(l,p,d))h=false;else{N();b(E.add(z).add(A)).hide();b(j.add(u)).unbind();b(window).unbind("resize.fb scroll.fb");b(document).unbind("keydown.fb");j.find("iframe").attr("src",M&&/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank");d.titlePosition!=="inside"&&n.empty();f.stop();if(d.transitionOut=="elastic"){r=V();var c=f.position();i={top:c.top,left:c.left,width:f.width(),height:f.height()};if(d.opacity)i.opacity=1;n.empty().hide();B.prop=1;
+b(B).animate({prop:0},{duration:d.speedOut,easing:d.easingOut,step:T,complete:a})}else f.fadeOut(d.transitionOut=="none"?0:d.speedOut,a)}}};b.fancybox.resize=function(){u.is(":visible")&&u.css("height",b(document).height());b.fancybox.center(true)};b.fancybox.center=function(a){var c,g;if(!h){g=a===true?1:0;c=U();!g&&(f.width()>c[0]||f.height()>c[1])||f.stop().animate({top:parseInt(Math.max(c[3]-20,c[3]+(c[1]-j.height()-40)*0.5-d.padding)),left:parseInt(Math.max(c[2]-20,c[2]+(c[0]-j.width()-40)*0.5-
+d.padding))},typeof a=="number"?a:200)}};b.fancybox.init=function(){if(!b("#fancybox-wrap").length){b("body").append(m=b('<div id="fancybox-tmp"></div>'),t=b('<div id="fancybox-loading"><div></div></div>'),u=b('<div id="fancybox-overlay"></div>'),f=b('<div id="fancybox-wrap"></div>'));D=b('<div id="fancybox-outer"></div>').append('<div class="fancybox-bg" id="fancybox-bg-n"></div><div class="fancybox-bg" id="fancybox-bg-ne"></div><div class="fancybox-bg" id="fancybox-bg-e"></div><div class="fancybox-bg" id="fancybox-bg-se"></div><div class="fancybox-bg" id="fancybox-bg-s"></div><div class="fancybox-bg" id="fancybox-bg-sw"></div><div class="fancybox-bg" id="fancybox-bg-w"></div><div class="fancybox-bg" id="fancybox-bg-nw"></div>').appendTo(f);
+D.append(j=b('<div id="fancybox-content"></div>'),E=b('<a id="fancybox-close"></a>'),n=b('<div id="fancybox-title"></div>'),z=b('<a href="javascript:;" id="fancybox-left"><span class="fancy-ico" id="fancybox-left-ico"></span></a>'),A=b('<a href="javascript:;" id="fancybox-right"><span class="fancy-ico" id="fancybox-right-ico"></span></a>'));E.click(b.fancybox.close);t.click(b.fancybox.cancel);z.click(function(a){a.preventDefault();b.fancybox.prev()});A.click(function(a){a.preventDefault();b.fancybox.next()});
+b.fn.mousewheel&&f.bind("mousewheel.fb",function(a,c){if(h)a.preventDefault();else if(b(a.target).get(0).clientHeight==0||b(a.target).get(0).scrollHeight===b(a.target).get(0).clientHeight){a.preventDefault();b.fancybox[c>0?"prev":"next"]()}});b.support.opacity||f.addClass("fancybox-ie");if(M){t.addClass("fancybox-ie6");f.addClass("fancybox-ie6");b('<iframe id="fancybox-hide-sel-frame" src="'+(/^https/i.test(window.location.href||"")?"javascript:void(false)":"about:blank")+'" scrolling="no" border="0" frameborder="0" tabindex="-1"></iframe>').prependTo(D)}}};
+b.fn.fancybox.defaults={padding:10,margin:40,opacity:false,modal:false,cyclic:false,scrolling:"auto",width:560,height:340,autoScale:true,autoDimensions:true,centerOnScroll:false,ajax:{},swf:{wmode:"transparent"},hideOnOverlayClick:true,hideOnContentClick:false,overlayShow:true,overlayOpacity:0.7,overlayColor:"#777",titleShow:true,titlePosition:"float",titleFormat:null,titleFromAlt:false,transitionIn:"fade",transitionOut:"fade",speedIn:300,speedOut:300,changeSpeed:300,changeFade:"fast",easingIn:"swing",
+easingOut:"swing",showCloseButton:true,showNavArrows:true,enableEscapeButton:true,enableKeyboardNav:true,onStart:function(){},onCancel:function(){},onComplete:function(){},onCleanup:function(){},onClosed:function(){},onError:function(){}};b(document).ready(function(){b.fancybox.init()})})(jQuery); \ No newline at end of file
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.mousewheel-3.0.4.pack.js b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.mousewheel-3.0.4.pack.js
new file mode 100644
index 00000000..cb66588e
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/fancybox/jquery.mousewheel-3.0.4.pack.js
@@ -0,0 +1,14 @@
+/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
+* Licensed under the MIT License (LICENSE.txt).
+*
+* Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
+* Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
+* Thanks to: Seamus Leahy for adding deltaX and deltaY
+*
+* Version: 3.0.4
+*
+* Requires: 1.2.2+
+*/
+
+(function(d){function g(a){var b=a||window.event,i=[].slice.call(arguments,1),c=0,h=0,e=0;a=d.event.fix(b);a.type="mousewheel";if(a.wheelDelta)c=a.wheelDelta/120;if(a.detail)c=-a.detail/3;e=c;if(b.axis!==undefined&&b.axis===b.HORIZONTAL_AXIS){e=0;h=-1*c}if(b.wheelDeltaY!==undefined)e=b.wheelDeltaY/120;if(b.wheelDeltaX!==undefined)h=-1*b.wheelDeltaX/120;i.unshift(a,c,h,e);return d.event.handle.apply(this,i)}var f=["DOMMouseScroll","mousewheel"];d.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=
+f.length;a;)this.addEventListener(f[--a],g,false);else this.onmousewheel=g},teardown:function(){if(this.removeEventListener)for(var a=f.length;a;)this.removeEventListener(f[--a],g,false);else this.onmousewheel=null}};d.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery); \ No newline at end of file
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/index.html b/askbot/media/js/jquery.fancybox-1.3.4/index.html
new file mode 100644
index 00000000..6b10a21e
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/index.html
@@ -0,0 +1,165 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="imagetoolbar" content="no" />
+ <title>FancyBox 1.3.4 | Demonstration</title>
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
+ <script>
+ !window.jQuery && document.write('<script src="jquery-1.4.3.min.js"><\/script>');
+ </script>
+ <script type="text/javascript" src="./fancybox/jquery.mousewheel-3.0.4.pack.js"></script>
+ <script type="text/javascript" src="./fancybox/jquery.fancybox-1.3.4.pack.js"></script>
+ <link rel="stylesheet" type="text/css" href="./fancybox/jquery.fancybox-1.3.4.css" media="screen" />
+ <link rel="stylesheet" href="style.css" />
+ <script type="text/javascript">
+ $(document).ready(function() {
+ /*
+ * Examples - images
+ */
+
+ $("a#example1").fancybox();
+
+ $("a#example2").fancybox({
+ 'overlayShow' : false,
+ 'transitionIn' : 'elastic',
+ 'transitionOut' : 'elastic'
+ });
+
+ $("a#example3").fancybox({
+ 'transitionIn' : 'none',
+ 'transitionOut' : 'none'
+ });
+
+ $("a#example4").fancybox({
+ 'opacity' : true,
+ 'overlayShow' : false,
+ 'transitionIn' : 'elastic',
+ 'transitionOut' : 'none'
+ });
+
+ $("a#example5").fancybox();
+
+ $("a#example6").fancybox({
+ 'titlePosition' : 'outside',
+ 'overlayColor' : '#000',
+ 'overlayOpacity' : 0.9
+ });
+
+ $("a#example7").fancybox({
+ 'titlePosition' : 'inside'
+ });
+
+ $("a#example8").fancybox({
+ 'titlePosition' : 'over'
+ });
+
+ $("a[rel=example_group]").fancybox({
+ 'transitionIn' : 'none',
+ 'transitionOut' : 'none',
+ 'titlePosition' : 'over',
+ 'titleFormat' : function(title, currentArray, currentIndex, currentOpts) {
+ return '<span id="fancybox-title-over">Image ' + (currentIndex + 1) + ' / ' + currentArray.length + (title.length ? ' &nbsp; ' + title : '') + '</span>';
+ }
+ });
+
+ /*
+ * Examples - various
+ */
+
+ $("#various1").fancybox({
+ 'titlePosition' : 'inside',
+ 'transitionIn' : 'none',
+ 'transitionOut' : 'none'
+ });
+
+ $("#various2").fancybox();
+
+ $("#various3").fancybox({
+ 'width' : '75%',
+ 'height' : '75%',
+ 'autoScale' : false,
+ 'transitionIn' : 'none',
+ 'transitionOut' : 'none',
+ 'type' : 'iframe'
+ });
+
+ $("#various4").fancybox({
+ 'padding' : 0,
+ 'autoScale' : false,
+ 'transitionIn' : 'none',
+ 'transitionOut' : 'none'
+ });
+ });
+ </script>
+</head>
+<body>
+<div id="content">
+ <h1>fancybox <span>v1.3.4</span></h1>
+
+ <p>This is a demonstration. <a href="http://fancybox.net">Home page</a></p>
+
+ <hr />
+
+ <p>
+ Different animations<br />
+
+ <a id="example1" href="./example/1_b.jpg"><img alt="example1" src="./example/1_s.jpg" /></a>
+
+ <a id="example2" href="./example/2_b.jpg"><img alt="example2" src="./example/2_s.jpg" /></a>
+
+ <a id="example3" href="./example/3_b.jpg"><img alt="example3" src="./example/3_s.jpg" /></a>
+
+ <a id="example4" href="./example/4_b.jpg"><img class="last" alt="example4" src="./example/4_s.jpg" /></a>
+ </p>
+
+ <p>
+ Different title positions<br />
+
+ <a id="example5" href="./example/5_b.jpg" title="Lorem ipsum dolor sit amet, consectetur adipiscing elit."><img alt="example4" src="./example/5_s.jpg" /></a>
+
+ <a id="example6" href="./example/6_b.jpg" title="Etiam quis mi eu elit tempor facilisis id et neque. Nulla sit amet sem sapien. Vestibulum imperdiet porta ante ac ornare. Vivamus fringilla congue laoreet."><img alt="example5" src="./example/6_s.jpg" /></a>
+
+ <a id="example7" href="./example/7_b.jpg" title="Cras neque mi, semper at interdum id, dapibus in leo. Suspendisse nunc leo, eleifend sit amet iaculis et, cursus sed turpis."><img alt="example6" src="./example/7_s.jpg" /></a>
+
+ <a id="example8" href="./example/8_b.jpg" title="Sed vel sapien vel sem tempus placerat eu ut tortor. Nulla facilisi. Sed adipiscing, turpis ut cursus molestie, sem eros viverra mauris, quis sollicitudin sapien enim nec est. ras pulvinar placerat diam eu consectetur."><img class="last" alt="example7" src="./example/8_s.jpg" /></a>
+ </p>
+
+ <p>
+ Image gallery (ps, try using mouse scroll wheel)<br />
+
+ <a rel="example_group" href="./example/9_b.jpg" title="Lorem ipsum dolor sit amet"><img alt="" src="./example/9_s.jpg" /></a>
+
+ <a rel="example_group" href="./example/10_b.jpg" title=""><img alt="" src="./example/10_s.jpg" /></a>
+
+ <a rel="example_group" href="./example/11_b.jpg" title=""><img alt="" src="./example/11_s.jpg" /></a>
+
+ <a rel="example_group" href="./example/12_b.jpg" title=""><img class="last" alt="" src="./example/12_s.jpg" /></a>
+ </p>
+
+ <p>
+ Various examples
+ </p>
+
+ <ul>
+ <li><a id="various1" href="#inline1" title="Lorem ipsum dolor sit amet">Inline</a></li>
+ <li><a id="various2" href="ajax.txt">Ajax</a></li>
+ <li><a id="various3" href="http://google.ca">Iframe</a></li>
+ <li><a id="various4" href="http://www.adobe.com/jp/events/cs3_web_edition_tour/swfs/perform.swf">Swf</a></li>
+ </ul>
+
+ <div style="display: none;">
+ <div id="inline1" style="width:400px;height:100px;overflow:auto;">
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam quis mi eu elit tempor facilisis id et neque. Nulla sit amet sem sapien. Vestibulum imperdiet porta ante ac ornare. Nulla et lorem eu nibh adipiscing ultricies nec at lacus. Cras laoreet ultricies sem, at blandit mi eleifend aliquam. Nunc enim ipsum, vehicula non pretium varius, cursus ac tortor. Vivamus fringilla congue laoreet. Quisque ultrices sodales orci, quis rhoncus justo auctor in. Phasellus dui eros, bibendum eu feugiat ornare, faucibus eu mi. Nunc aliquet tempus sem, id aliquam diam varius ac. Maecenas nisl nunc, molestie vitae eleifend vel, iaculis sed magna. Aenean tempus lacus vitae orci posuere porttitor eget non felis. Donec lectus elit, aliquam nec eleifend sit amet, vestibulum sed nunc.
+ </div>
+ </div>
+
+ <p>
+ Ajax example will not run from your local computer and requires a server to run.
+ </p>
+ <p>
+ Photo Credit: <a href="http://www.flickr.com/people/kharied/">Katie Harris</a>
+ </p>
+</div>
+</body>
+</html> \ No newline at end of file
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/jquery-1.4.3.min.js b/askbot/media/js/jquery.fancybox-1.3.4/jquery-1.4.3.min.js
new file mode 100644
index 00000000..c941a5f7
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/jquery-1.4.3.min.js
@@ -0,0 +1,166 @@
+/*!
+ * jQuery JavaScript Library v1.4.3
+ * 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: Thu Oct 14 23:10:06 2010 -0400
+ */
+(function(E,A){function U(){return false}function ba(){return true}function ja(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ga(a){var b,d,e=[],f=[],h,k,l,n,s,v,B,D;k=c.data(this,this.nodeType?"events":"__events__");if(typeof k==="function")k=k.events;if(!(a.liveFired===this||!k||!k.live||a.button&&a.type==="click")){if(a.namespace)D=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var H=k.live.slice(0);for(n=0;n<H.length;n++){k=H[n];k.origType.replace(X,
+"")===a.type?f.push(k.selector):H.splice(n--,1)}f=c(a.target).closest(f,a.currentTarget);s=0;for(v=f.length;s<v;s++){B=f[s];for(n=0;n<H.length;n++){k=H[n];if(B.selector===k.selector&&(!D||D.test(k.namespace))){l=B.elem;h=null;if(k.preType==="mouseenter"||k.preType==="mouseleave"){a.type=k.preType;h=c(a.relatedTarget).closest(k.selector)[0]}if(!h||h!==l)e.push({elem:l,handleObj:k,level:B.level})}}}s=0;for(v=e.length;s<v;s++){f=e[s];if(d&&f.level>d)break;a.currentTarget=f.elem;a.data=f.handleObj.data;
+a.handleObj=f.handleObj;D=f.handleObj.origHandler.apply(f.elem,arguments);if(D===false||a.isPropagationStopped()){d=f.level;if(D===false)b=false}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(Ha,"`").replace(Ia,"&")}function ka(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Ja.test(b))return c.filter(b,
+e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function la(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this,e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var k in e[h])c.event.add(this,h,e[h][k],e[h][k].data)}}})}function Ka(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 ma(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?La:Ma,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a,"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function ca(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Na.test(a)?e(a,h):ca(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?
+e(a,""):c.each(b,function(f,h){ca(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(na.concat.apply([],na.slice(0,b)),function(){d[this]=a});return d}function oa(a){if(!da[a]){var b=c("<"+a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";da[a]=d}return da[a]}function ea(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var u=E.document,c=function(){function a(){if(!b.isReady){try{u.documentElement.doScroll("left")}catch(i){setTimeout(a,
+1);return}b.ready()}}var b=function(i,r){return new b.fn.init(i,r)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,k=/\S/,l=/^\s+/,n=/\s+$/,s=/\W/,v=/\d/,B=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,D=/^[\],:{}\s]*$/,H=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,G=/(?:^|:|,)(?:\s*\[)+/g,M=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,j=/(msie) ([\w.]+)/,o=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,
+q=[],t,x=Object.prototype.toString,C=Object.prototype.hasOwnProperty,P=Array.prototype.push,N=Array.prototype.slice,R=String.prototype.trim,Q=Array.prototype.indexOf,L={};b.fn=b.prototype={init:function(i,r){var y,z,F;if(!i)return this;if(i.nodeType){this.context=this[0]=i;this.length=1;return this}if(i==="body"&&!r&&u.body){this.context=u;this[0]=u.body;this.selector="body";this.length=1;return this}if(typeof i==="string")if((y=h.exec(i))&&(y[1]||!r))if(y[1]){F=r?r.ownerDocument||r:u;if(z=B.exec(i))if(b.isPlainObject(r)){i=
+[u.createElement(z[1])];b.fn.attr.call(i,r,true)}else i=[F.createElement(z[1])];else{z=b.buildFragment([y[1]],[F]);i=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this,i)}else{if((z=u.getElementById(y[2]))&&z.parentNode){if(z.id!==y[2])return f.find(i);this.length=1;this[0]=z}this.context=u;this.selector=i;return this}else if(!r&&!s.test(i)){this.selector=i;this.context=u;i=u.getElementsByTagName(i);return b.merge(this,i)}else return!r||r.jquery?(r||f).find(i):b(r).find(i);
+else if(b.isFunction(i))return f.ready(i);if(i.selector!==A){this.selector=i.selector;this.context=i.context}return b.makeArray(i,this)},selector:"",jquery:"1.4.3",length:0,size:function(){return this.length},toArray:function(){return N.call(this,0)},get:function(i){return i==null?this.toArray():i<0?this.slice(i)[0]:this[i]},pushStack:function(i,r,y){var z=b();b.isArray(i)?P.apply(z,i):b.merge(z,i);z.prevObject=this;z.context=this.context;if(r==="find")z.selector=this.selector+(this.selector?" ":
+"")+y;else if(r)z.selector=this.selector+"."+r+"("+y+")";return z},each:function(i,r){return b.each(this,i,r)},ready:function(i){b.bindReady();if(b.isReady)i.call(u,b);else q&&q.push(i);return this},eq:function(i){return i===-1?this.slice(i):this.slice(i,+i+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(i){return this.pushStack(b.map(this,function(r,y){return i.call(r,
+y,r)}))},end:function(){return this.prevObject||b(null)},push:P,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var i=arguments[0]||{},r=1,y=arguments.length,z=false,F,I,K,J,fa;if(typeof i==="boolean"){z=i;i=arguments[1]||{};r=2}if(typeof i!=="object"&&!b.isFunction(i))i={};if(y===r){i=this;--r}for(;r<y;r++)if((F=arguments[r])!=null)for(I in F){K=i[I];J=F[I];if(i!==J)if(z&&J&&(b.isPlainObject(J)||(fa=b.isArray(J)))){if(fa){fa=false;clone=K&&b.isArray(K)?K:[]}else clone=
+K&&b.isPlainObject(K)?K:{};i[I]=b.extend(z,clone,J)}else if(J!==A)i[I]=J}return i};b.extend({noConflict:function(i){E.$=e;if(i)E.jQuery=d;return b},isReady:false,readyWait:1,ready:function(i){i===true&&b.readyWait--;if(!b.readyWait||i!==true&&!b.isReady){if(!u.body)return setTimeout(b.ready,1);b.isReady=true;if(!(i!==true&&--b.readyWait>0)){if(q){for(var r=0;i=q[r++];)i.call(u,b);q=null}b.fn.triggerHandler&&b(u).triggerHandler("ready")}}},bindReady:function(){if(!p){p=true;if(u.readyState==="complete")return setTimeout(b.ready,
+1);if(u.addEventListener){u.addEventListener("DOMContentLoaded",t,false);E.addEventListener("load",b.ready,false)}else if(u.attachEvent){u.attachEvent("onreadystatechange",t);E.attachEvent("onload",b.ready);var i=false;try{i=E.frameElement==null}catch(r){}u.documentElement.doScroll&&i&&a()}}},isFunction:function(i){return b.type(i)==="function"},isArray:Array.isArray||function(i){return b.type(i)==="array"},isWindow:function(i){return i&&typeof i==="object"&&"setInterval"in i},isNaN:function(i){return i==
+null||!v.test(i)||isNaN(i)},type:function(i){return i==null?String(i):L[x.call(i)]||"object"},isPlainObject:function(i){if(!i||b.type(i)!=="object"||i.nodeType||b.isWindow(i))return false;if(i.constructor&&!C.call(i,"constructor")&&!C.call(i.constructor.prototype,"isPrototypeOf"))return false;for(var r in i);return r===A||C.call(i,r)},isEmptyObject:function(i){for(var r in i)return false;return true},error:function(i){throw i;},parseJSON:function(i){if(typeof i!=="string"||!i)return null;i=b.trim(i);
+if(D.test(i.replace(H,"@").replace(w,"]").replace(G,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(i):(new Function("return "+i))();else b.error("Invalid JSON: "+i)},noop:function(){},globalEval:function(i){if(i&&k.test(i)){var r=u.getElementsByTagName("head")[0]||u.documentElement,y=u.createElement("script");y.type="text/javascript";if(b.support.scriptEval)y.appendChild(u.createTextNode(i));else y.text=i;r.insertBefore(y,r.firstChild);r.removeChild(y)}},nodeName:function(i,r){return i.nodeName&&i.nodeName.toUpperCase()===
+r.toUpperCase()},each:function(i,r,y){var z,F=0,I=i.length,K=I===A||b.isFunction(i);if(y)if(K)for(z in i){if(r.apply(i[z],y)===false)break}else for(;F<I;){if(r.apply(i[F++],y)===false)break}else if(K)for(z in i){if(r.call(i[z],z,i[z])===false)break}else for(y=i[0];F<I&&r.call(y,F,y)!==false;y=i[++F]);return i},trim:R?function(i){return i==null?"":R.call(i)}:function(i){return i==null?"":i.toString().replace(l,"").replace(n,"")},makeArray:function(i,r){var y=r||[];if(i!=null){var z=b.type(i);i.length==
+null||z==="string"||z==="function"||z==="regexp"||b.isWindow(i)?P.call(y,i):b.merge(y,i)}return y},inArray:function(i,r){if(r.indexOf)return r.indexOf(i);for(var y=0,z=r.length;y<z;y++)if(r[y]===i)return y;return-1},merge:function(i,r){var y=i.length,z=0;if(typeof r.length==="number")for(var F=r.length;z<F;z++)i[y++]=r[z];else for(;r[z]!==A;)i[y++]=r[z++];i.length=y;return i},grep:function(i,r,y){var z=[],F;y=!!y;for(var I=0,K=i.length;I<K;I++){F=!!r(i[I],I);y!==F&&z.push(i[I])}return z},map:function(i,
+r,y){for(var z=[],F,I=0,K=i.length;I<K;I++){F=r(i[I],I,y);if(F!=null)z[z.length]=F}return z.concat.apply([],z)},guid:1,proxy:function(i,r,y){if(arguments.length===2)if(typeof r==="string"){y=i;i=y[r];r=A}else if(r&&!b.isFunction(r)){y=r;r=A}if(!r&&i)r=function(){return i.apply(y||this,arguments)};if(i)r.guid=i.guid=i.guid||r.guid||b.guid++;return r},access:function(i,r,y,z,F,I){var K=i.length;if(typeof r==="object"){for(var J in r)b.access(i,J,r[J],z,F,y);return i}if(y!==A){z=!I&&z&&b.isFunction(y);
+for(J=0;J<K;J++)F(i[J],r,z?y.call(i[J],J,F(i[J],r)):y,I);return i}return K?F(i[0],r):A},now:function(){return(new Date).getTime()},uaMatch:function(i){i=i.toLowerCase();i=M.exec(i)||g.exec(i)||j.exec(i)||i.indexOf("compatible")<0&&o.exec(i)||[];return{browser:i[1]||"",version:i[2]||"0"}},browser:{}});b.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(i,r){L["[object "+r+"]"]=r.toLowerCase()});m=b.uaMatch(m);if(m.browser){b.browser[m.browser]=true;b.browser.version=
+m.version}if(b.browser.webkit)b.browser.safari=true;if(Q)b.inArray=function(i,r){return Q.call(r,i)};if(!/\s/.test("\u00a0")){l=/^[\s\xA0]+/;n=/[\s\xA0]+$/}f=b(u);if(u.addEventListener)t=function(){u.removeEventListener("DOMContentLoaded",t,false);b.ready()};else if(u.attachEvent)t=function(){if(u.readyState==="complete"){u.detachEvent("onreadystatechange",t);b.ready()}};return E.jQuery=E.$=b}();(function(){c.support={};var a=u.documentElement,b=u.createElement("script"),d=u.createElement("div"),
+e="script"+c.now();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 f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],k=u.createElement("select"),l=k.appendChild(u.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),
+hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:l.selected,optDisabled:false,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};k.disabled=true;c.support.optDisabled=!l.disabled;b.type="text/javascript";try{b.appendChild(u.createTextNode("window."+e+"=1;"))}catch(n){}a.insertBefore(b,
+a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function s(){c.support.noCloneEvent=false;d.detachEvent("onclick",s)});d.cloneNode(true).fireEvent("onclick")}d=u.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=u.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var s=u.createElement("div");
+s.style.width=s.style.paddingLeft="1px";u.body.appendChild(s);c.boxModel=c.support.boxModel=s.offsetWidth===2;if("zoom"in s.style){s.style.display="inline";s.style.zoom=1;c.support.inlineBlockNeedsLayout=s.offsetWidth===2;s.style.display="";s.innerHTML="<div style='width:4px;'></div>";c.support.shrinkWrapBlocks=s.offsetWidth!==2}s.innerHTML="<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>";var v=s.getElementsByTagName("td");c.support.reliableHiddenOffsets=v[0].offsetHeight===
+0;v[0].style.display="";v[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&v[0].offsetHeight===0;s.innerHTML="";u.body.removeChild(s).style.display="none"});a=function(s){var v=u.createElement("div");s="on"+s;var B=s in v;if(!B){v.setAttribute(s,"return;");B=typeof v[s]==="function"}return B};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",
+cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var pa={},Oa=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?pa:a;var e=a.nodeType,f=e?a[c.expando]:null,h=c.cache;if(!(e&&!f&&typeof b==="string"&&d===A)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=
+c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==A)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?pa:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando);else if(d)delete f[e];else for(var k in a)delete a[k]}},acceptData:function(a){if(a.nodeName){var b=
+c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){if(typeof a==="undefined")return this.length?c.data(this[0]):null;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===A){var e=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(e===A&&this.length){e=c.data(this[0],a);if(e===A&&this[0].nodeType===1){e=this[0].getAttribute("data-"+a);if(typeof e===
+"string")try{e=e==="true"?true:e==="false"?false:e==="null"?null:!c.isNaN(e)?parseFloat(e):Oa.test(e)?c.parseJSON(e):e}catch(f){}else e=A}}return e===A&&d[1]?this.data(d[0]):e}else return this.each(function(){var h=c(this),k=[d[0],b];h.triggerHandler("setData"+d[1]+"!",k);c.data(this,a,b);h.triggerHandler("changeData"+d[1]+"!",k)})},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 e=c.data(a,b);if(!d)return e||
+[];if(!e||c.isArray(d))e=c.data(a,b,c.makeArray(d));else e.push(d);return e}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),e=d.shift();if(e==="inprogress")e=d.shift();if(e){b==="fx"&&d.unshift("inprogress");e.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===A)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 qa=/[\n\t]/g,ga=/\s+/,Pa=/\r/g,Qa=/^(?:href|src|style)$/,Ra=/^(?:button|input)$/i,Sa=/^(?:button|input|object|select|textarea)$/i,Ta=/^a(?:rea)?$/i,ra=/^(?:radio|checkbox)$/i;c.fn.extend({attr:function(a,b){return c.access(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(s){var v=c(this);v.addClass(a.call(this,s,v.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ga),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1)if(f.className){for(var h=" "+f.className+" ",k=f.className,l=0,n=b.length;l<n;l++)if(h.indexOf(" "+b[l]+" ")<0)k+=" "+b[l];f.className=c.trim(k)}else f.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(n){var s=
+c(this);s.removeClass(a.call(this,n,s.attr("class")))});if(a&&typeof a==="string"||a===A)for(var b=(a||"").split(ga),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1&&f.className)if(a){for(var h=(" "+f.className+" ").replace(qa," "),k=0,l=b.length;k<l;k++)h=h.replace(" "+b[k]+" "," ");f.className=c.trim(h)}else f.className=""}return this},toggleClass:function(a,b){var d=typeof a,e=typeof b==="boolean";if(c.isFunction(a))return this.each(function(f){var h=c(this);h.toggleClass(a.call(this,
+f,h.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var f,h=0,k=c(this),l=b,n=a.split(ga);f=n[h++];){l=e?l:!k.hasClass(f);k[l?"addClass":"removeClass"](f)}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(qa," ").indexOf(a)>-1)return true;return false},
+val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one";if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h<e;h++){var k=f[h];if(k.selected&&(c.support.optDisabled?!k.disabled:k.getAttribute("disabled")===null)&&(!k.parentNode.disabled||!c.nodeName(k.parentNode,"optgroup"))){a=c(k).val();if(b)return a;d.push(a)}}return d}if(ra.test(b.type)&&
+!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Pa,"")}return A}var l=c.isFunction(a);return this.each(function(n){var s=c(this),v=a;if(this.nodeType===1){if(l)v=a.call(this,n,s.val());if(v==null)v="";else if(typeof v==="number")v+="";else if(c.isArray(v))v=c.map(v,function(D){return D==null?"":D+""});if(c.isArray(v)&&ra.test(this.type))this.checked=c.inArray(s.val(),v)>=0;else if(c.nodeName(this,"select")){var B=c.makeArray(v);c("option",this).each(function(){this.selected=
+c.inArray(c(this).val(),B)>=0});if(!B.length)this.selectedIndex=-1}else this.value=v}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return A;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==A;b=e&&c.props[b]||b;if(a.nodeType===1){var h=Qa.test(b);if((b in a||a[b]!==A)&&e&&!h){if(f){b==="type"&&Ra.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");
+if(d===null)a.nodeType===1&&a.removeAttribute(b);else 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:Sa.test(a.nodeName)||Ta.test(a.nodeName)&&a.href?0:A;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return A;a=!c.support.hrefNormalized&&e&&
+h?a.getAttribute(b,2):a.getAttribute(b);return a===null?A:a}}});var X=/\.(.*)$/,ha=/^(?:textarea|input|select)$/i,Ha=/\./g,Ia=/ /g,Ua=/[^\w\s.|`]/g,Va=function(a){return a.replace(Ua,"\\$&")},sa={focusin:0,focusout:0};c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var k=a.nodeType?"events":"__events__",l=h[k],n=h.handle;if(typeof l===
+"function"){n=l.handle;l=l.events}else if(!l){a.nodeType||(h[k]=h=function(){});h.events=l={}}if(!n)h.handle=n=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(n.elem,arguments):A};n.elem=a;b=b.split(" ");for(var s=0,v;k=b[s++];){h=f?c.extend({},f):{handler:d,data:e};if(k.indexOf(".")>-1){v=k.split(".");k=v.shift();h.namespace=v.slice(0).sort().join(".")}else{v=[];h.namespace=""}h.type=k;if(!h.guid)h.guid=d.guid;var B=l[k],D=c.event.special[k]||{};if(!B){B=l[k]=[];
+if(!D.setup||D.setup.call(a,e,v,n)===false)if(a.addEventListener)a.addEventListener(k,n,false);else a.attachEvent&&a.attachEvent("on"+k,n)}if(D.add){D.add.call(a,h);if(!h.handler.guid)h.handler.guid=d.guid}B.push(h);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,k=0,l,n,s,v,B,D,H=a.nodeType?"events":"__events__",w=c.data(a),G=w&&w[H];if(w&&G){if(typeof G==="function"){w=G;G=G.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||
+typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in G)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[k++];){v=f;l=f.indexOf(".")<0;n=[];if(!l){n=f.split(".");f=n.shift();s=RegExp("(^|\\.)"+c.map(n.slice(0).sort(),Va).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(B=G[f])if(d){v=c.event.special[f]||{};for(h=e||0;h<B.length;h++){D=B[h];if(d.guid===D.guid){if(l||s.test(D.namespace)){e==null&&B.splice(h--,1);v.remove&&v.remove.call(a,D)}if(e!=null)break}}if(B.length===0||e!=null&&B.length===1){if(!v.teardown||
+v.teardown.call(a,n)===false)c.removeEvent(a,f,w.handle);delete G[f]}}else for(h=0;h<B.length;h++){D=B[h];if(l||s.test(D.namespace)){c.event.remove(a,v,D.handler,h);B.splice(h--,1)}}}if(c.isEmptyObject(G)){if(b=w.handle)b.elem=null;delete w.events;delete w.handle;if(typeof w==="function")c.removeData(a,H);else c.isEmptyObject(w)&&c.removeData(a)}}}}},trigger:function(a,b,d,e){var f=a.type||a;if(!e){a=typeof a==="object"?a[c.expando]?a:c.extend(c.Event(f),a):c.Event(f);if(f.indexOf("!")>=0){a.type=
+f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return A;a.result=A;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===
+false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){e=a.target;var k,l=f.replace(X,""),n=c.nodeName(e,"a")&&l==="click",s=c.event.special[l]||{};if((!s._default||s._default.call(d,a)===false)&&!n&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[l]){if(k=e["on"+l])e["on"+l]=null;c.event.triggered=true;e[l]()}}catch(v){}if(k)e["on"+l]=k;c.event.triggered=false}}},handle:function(a){var b,d,e;
+d=[];var f,h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var k=d.length;f<k;f++){var l=d[f];if(b||e.test(l.namespace)){a.handler=l.handler;a.data=
+l.data;a.handleObj=l;l=l.handler.apply(this,h);if(l!==A){a.result=l;if(l===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 pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
+fix:function(a){if(a[c.expando])return a;var b=a;a=c.Event(b);for(var d=this.props.length,e;d;){e=this.props[--d];a[e]=b[e]}if(!a.target)a.target=a.srcElement||u;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=u.documentElement;d=u.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==null&&(a.charCode!=null||a.keyCode!=null))a.which=a.charCode!=null?a.charCode:a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==A)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,Y(a.origType,a.selector),c.extend({},a,{handler:Ga,guid:a.handler.guid}))},remove:function(a){c.event.remove(this,
+Y(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,d){if(c.isWindow(this))this.onbeforeunload=d},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.removeEvent=u.removeEventListener?function(a,b,d){a.removeEventListener&&a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent&&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=
+c.now();this[c.expando]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ba;var a=this.originalEvent;if(a)if(a.preventDefault)a.preventDefault();else a.returnValue=false},stopPropagation:function(){this.isPropagationStopped=ba;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ba;this.stopPropagation()},isDefaultPrevented:U,isPropagationStopped:U,isImmediatePropagationStopped:U};
+var ta=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){}},ua=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?ua:ta,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?ua:ta)}}});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){a.liveFired=A;return ja("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){a.liveFired=A;return ja("submit",this,arguments)}})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};if(!c.support.changeBubbles){var V,
+va=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(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ha.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=va(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===A||f===e))if(e!=null||f){a.type="change";a.liveFired=
+A;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.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 Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",va(a))}},setup:function(){if(this.type===
+"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ha.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ha.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}u.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){sa[b]++===0&&u.addEventListener(a,d,true)},teardown:function(){--sa[b]===
+0&&u.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=A}var k=b==="one"?c.proxy(f,function(n){c(this).unbind(n,k);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var l=this.length;h<l;h++)c.event.add(this[h],d,k,e)}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 e=this.length;d<e;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,e){return this.live(b,d,e,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]){var d=c.Event(a);d.preventDefault();d.stopPropagation();c.event.trigger(d,b,this[0]);return d.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(e){var f=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,f+1);e.preventDefault();return b[f].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var wa={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,e,f,h){var k,l=0,n,s,v=h||this.selector;h=h?this:c(this.context);if(typeof d===
+"object"&&!d.preventDefault){for(k in d)h[b](k,e,d[k],v);return this}if(c.isFunction(e)){f=e;e=A}for(d=(d||"").split(" ");(k=d[l++])!=null;){n=X.exec(k);s="";if(n){s=n[0];k=k.replace(X,"")}if(k==="hover")d.push("mouseenter"+s,"mouseleave"+s);else{n=k;if(k==="focus"||k==="blur"){d.push(wa[k]+s);k+=s}else k=(wa[k]||k)+s;if(b==="live"){s=0;for(var B=h.length;s<B;s++)c.event.add(h[s],"live."+Y(k,v),{data:e,selector:v,handler:f,origType:k,origHandler:f,preType:n})}else h.unbind("live."+Y(k,v),f)}}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,e){if(e==null){e=d;d=null}return arguments.length>0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",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,j,o,m,p,q){p=0;for(var t=m.length;p<t;p++){var x=m[p];if(x){x=x[g];for(var C=false;x;){if(x.sizcache===o){C=m[x.sizset];break}if(x.nodeType===1&&!q){x.sizcache=o;x.sizset=p}if(x.nodeName.toLowerCase()===j){C=x;break}x=x[g]}m[p]=C}}}function b(g,j,o,m,p,q){p=0;for(var t=m.length;p<t;p++){var x=m[p];if(x){x=x[g];for(var C=false;x;){if(x.sizcache===o){C=m[x.sizset];break}if(x.nodeType===1){if(!q){x.sizcache=o;x.sizset=p}if(typeof j!=="string"){if(x===j){C=true;break}}else if(l.filter(j,
+[x]).length>0){C=x;break}}x=x[g]}m[p]=C}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,k=true;[0,0].sort(function(){k=false;return 0});var l=function(g,j,o,m){o=o||[];var p=j=j||u;if(j.nodeType!==1&&j.nodeType!==9)return[];if(!g||typeof g!=="string")return o;var q=[],t,x,C,P,N=true,R=l.isXML(j),Q=g,L;do{d.exec("");if(t=d.exec(Q)){Q=t[3];q.push(t[1]);if(t[2]){P=t[3];
+break}}}while(t);if(q.length>1&&s.exec(g))if(q.length===2&&n.relative[q[0]])x=M(q[0]+q[1],j);else for(x=n.relative[q[0]]?[j]:l(q.shift(),j);q.length;){g=q.shift();if(n.relative[g])g+=q.shift();x=M(g,x)}else{if(!m&&q.length>1&&j.nodeType===9&&!R&&n.match.ID.test(q[0])&&!n.match.ID.test(q[q.length-1])){t=l.find(q.shift(),j,R);j=t.expr?l.filter(t.expr,t.set)[0]:t.set[0]}if(j){t=m?{expr:q.pop(),set:D(m)}:l.find(q.pop(),q.length===1&&(q[0]==="~"||q[0]==="+")&&j.parentNode?j.parentNode:j,R);x=t.expr?l.filter(t.expr,
+t.set):t.set;if(q.length>0)C=D(x);else N=false;for(;q.length;){t=L=q.pop();if(n.relative[L])t=q.pop();else L="";if(t==null)t=j;n.relative[L](C,t,R)}}else C=[]}C||(C=x);C||l.error(L||g);if(f.call(C)==="[object Array]")if(N)if(j&&j.nodeType===1)for(g=0;C[g]!=null;g++){if(C[g]&&(C[g]===true||C[g].nodeType===1&&l.contains(j,C[g])))o.push(x[g])}else for(g=0;C[g]!=null;g++)C[g]&&C[g].nodeType===1&&o.push(x[g]);else o.push.apply(o,C);else D(C,o);if(P){l(P,p,o,m);l.uniqueSort(o)}return o};l.uniqueSort=function(g){if(w){h=
+k;g.sort(w);if(h)for(var j=1;j<g.length;j++)g[j]===g[j-1]&&g.splice(j--,1)}return g};l.matches=function(g,j){return l(g,null,null,j)};l.matchesSelector=function(g,j){return l(j,null,null,[g]).length>0};l.find=function(g,j,o){var m;if(!g)return[];for(var p=0,q=n.order.length;p<q;p++){var t=n.order[p],x;if(x=n.leftMatch[t].exec(g)){var C=x[1];x.splice(1,1);if(C.substr(C.length-1)!=="\\"){x[1]=(x[1]||"").replace(/\\/g,"");m=n.find[t](x,j,o);if(m!=null){g=g.replace(n.match[t],"");break}}}}m||(m=j.getElementsByTagName("*"));
+return{set:m,expr:g}};l.filter=function(g,j,o,m){for(var p=g,q=[],t=j,x,C,P=j&&j[0]&&l.isXML(j[0]);g&&j.length;){for(var N in n.filter)if((x=n.leftMatch[N].exec(g))!=null&&x[2]){var R=n.filter[N],Q,L;L=x[1];C=false;x.splice(1,1);if(L.substr(L.length-1)!=="\\"){if(t===q)q=[];if(n.preFilter[N])if(x=n.preFilter[N](x,t,o,q,m,P)){if(x===true)continue}else C=Q=true;if(x)for(var i=0;(L=t[i])!=null;i++)if(L){Q=R(L,x,i,t);var r=m^!!Q;if(o&&Q!=null)if(r)C=true;else t[i]=false;else if(r){q.push(L);C=true}}if(Q!==
+A){o||(t=q);g=g.replace(n.match[N],"");if(!C)return[];break}}}if(g===p)if(C==null)l.error(g);else break;p=g}return t};l.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var n=l.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,j){var o=typeof j==="string",m=o&&!/\W/.test(j);o=o&&!m;if(m)j=j.toLowerCase();m=0;for(var p=g.length,q;m<p;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=o||q&&q.nodeName.toLowerCase()===
+j?q||false:q===j}o&&l.filter(j,g,true)},">":function(g,j){var o=typeof j==="string",m,p=0,q=g.length;if(o&&!/\W/.test(j))for(j=j.toLowerCase();p<q;p++){if(m=g[p]){o=m.parentNode;g[p]=o.nodeName.toLowerCase()===j?o:false}}else{for(;p<q;p++)if(m=g[p])g[p]=o?m.parentNode:m.parentNode===j;o&&l.filter(j,g,true)}},"":function(g,j,o){var m=e++,p=b,q;if(typeof j==="string"&&!/\W/.test(j)){q=j=j.toLowerCase();p=a}p("parentNode",j,m,g,q,o)},"~":function(g,j,o){var m=e++,p=b,q;if(typeof j==="string"&&!/\W/.test(j)){q=
+j=j.toLowerCase();p=a}p("previousSibling",j,m,g,q,o)}},find:{ID:function(g,j,o){if(typeof j.getElementById!=="undefined"&&!o)return(g=j.getElementById(g[1]))&&g.parentNode?[g]:[]},NAME:function(g,j){if(typeof j.getElementsByName!=="undefined"){for(var o=[],m=j.getElementsByName(g[1]),p=0,q=m.length;p<q;p++)m[p].getAttribute("name")===g[1]&&o.push(m[p]);return o.length===0?null:o}},TAG:function(g,j){return j.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,j,o,m,p,q){g=" "+g[1].replace(/\\/g,
+"")+" ";if(q)return g;q=0;for(var t;(t=j[q])!=null;q++)if(t)if(p^(t.className&&(" "+t.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))o||m.push(t);else if(o)j[q]=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 j=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=j[1]+(j[2]||1)-0;g[3]=j[3]-0}g[0]=e++;return g},ATTR:function(g,j,o,
+m,p,q){j=g[1].replace(/\\/g,"");if(!q&&n.attrMap[j])g[1]=n.attrMap[j];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,j,o,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=l(g[3],null,null,j);else{g=l.filter(g[3],j,o,true^p);o||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,j,o){return!!l(o[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,j){return j===0},last:function(g,j,o,m){return j===m.length-1},even:function(g,j){return j%2===0},odd:function(g,j){return j%2===1},lt:function(g,j,o){return j<o[3]-0},gt:function(g,j,o){return j>o[3]-0},nth:function(g,j,o){return o[3]-
+0===j},eq:function(g,j,o){return o[3]-0===j}},filter:{PSEUDO:function(g,j,o,m){var p=j[1],q=n.filters[p];if(q)return q(g,o,j,m);else if(p==="contains")return(g.textContent||g.innerText||l.getText([g])||"").indexOf(j[3])>=0;else if(p==="not"){j=j[3];o=0;for(m=j.length;o<m;o++)if(j[o]===g)return false;return true}else l.error("Syntax error, unrecognized expression: "+p)},CHILD:function(g,j){var o=j[1],m=g;switch(o){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(o===
+"first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":o=j[2];var p=j[3];if(o===1&&p===0)return true;var q=j[0],t=g.parentNode;if(t&&(t.sizcache!==q||!g.nodeIndex)){var x=0;for(m=t.firstChild;m;m=m.nextSibling)if(m.nodeType===1)m.nodeIndex=++x;t.sizcache=q}m=g.nodeIndex-p;return o===0?m===0:m%o===0&&m/o>=0}},ID:function(g,j){return g.nodeType===1&&g.getAttribute("id")===j},TAG:function(g,j){return j==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===
+j},CLASS:function(g,j){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(j)>-1},ATTR:function(g,j){var o=j[1];o=n.attrHandle[o]?n.attrHandle[o](g):g[o]!=null?g[o]:g.getAttribute(o);var m=o+"",p=j[2],q=j[4];return o==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&o!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,j,o,m){var p=n.setFilters[j[2]];
+if(p)return p(g,o,j,m)}}},s=n.match.POS,v=function(g,j){return"\\"+(j-0+1)},B;for(B in n.match){n.match[B]=RegExp(n.match[B].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[B]=RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[B].source.replace(/\\(\d+)/g,v))}var D=function(g,j){g=Array.prototype.slice.call(g,0);if(j){j.push.apply(j,g);return j}return g};try{Array.prototype.slice.call(u.documentElement.childNodes,0)}catch(H){D=function(g,j){var o=j||[],m=0;if(f.call(g)==="[object Array]")Array.prototype.push.apply(o,
+g);else if(typeof g.length==="number")for(var p=g.length;m<p;m++)o.push(g[m]);else for(;g[m];m++)o.push(g[m]);return o}}var w,G;if(u.documentElement.compareDocumentPosition)w=function(g,j){if(g===j){h=true;return 0}if(!g.compareDocumentPosition||!j.compareDocumentPosition)return g.compareDocumentPosition?-1:1;return g.compareDocumentPosition(j)&4?-1:1};else{w=function(g,j){var o=[],m=[],p=g.parentNode,q=j.parentNode,t=p;if(g===j){h=true;return 0}else if(p===q)return G(g,j);else if(p){if(!q)return 1}else return-1;
+for(;t;){o.unshift(t);t=t.parentNode}for(t=q;t;){m.unshift(t);t=t.parentNode}p=o.length;q=m.length;for(t=0;t<p&&t<q;t++)if(o[t]!==m[t])return G(o[t],m[t]);return t===p?G(g,m[t],-1):G(o[t],j,1)};G=function(g,j,o){if(g===j)return o;for(g=g.nextSibling;g;){if(g===j)return-1;g=g.nextSibling}return 1}}l.getText=function(g){for(var j="",o,m=0;g[m];m++){o=g[m];if(o.nodeType===3||o.nodeType===4)j+=o.nodeValue;else if(o.nodeType!==8)j+=l.getText(o.childNodes)}return j};(function(){var g=u.createElement("div"),
+j="script"+(new Date).getTime();g.innerHTML="<a name='"+j+"'/>";var o=u.documentElement;o.insertBefore(g,o.firstChild);if(u.getElementById(j)){n.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:A:[]};n.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}o.removeChild(g);
+o=g=null})();(function(){var g=u.createElement("div");g.appendChild(u.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(j,o){var m=o.getElementsByTagName(j[1]);if(j[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(j){return j.getAttribute("href",2)};g=null})();u.querySelectorAll&&
+function(){var g=l,j=u.createElement("div");j.innerHTML="<p class='TEST'></p>";if(!(j.querySelectorAll&&j.querySelectorAll(".TEST").length===0)){l=function(m,p,q,t){p=p||u;if(!t&&!l.isXML(p))if(p.nodeType===9)try{return D(p.querySelectorAll(m),q)}catch(x){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var C=p.id,P=p.id="__sizzle__";try{return D(p.querySelectorAll("#"+P+" "+m),q)}catch(N){}finally{if(C)p.id=C;else p.removeAttribute("id")}}return g(m,p,q,t)};for(var o in g)l[o]=g[o];
+j=null}}();(function(){var g=u.documentElement,j=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,o=false;try{j.call(u.documentElement,":sizzle")}catch(m){o=true}if(j)l.matchesSelector=function(p,q){try{if(o||!n.match.PSEUDO.test(q))return j.call(p,q)}catch(t){}return l(q,null,null,[p]).length>0}})();(function(){var g=u.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(j,o,m){if(typeof o.getElementsByClassName!=="undefined"&&!m)return o.getElementsByClassName(j[1])};g=null}}})();l.contains=u.documentElement.contains?function(g,j){return g!==j&&(g.contains?g.contains(j):true)}:function(g,j){return!!(g.compareDocumentPosition(j)&16)};l.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var M=function(g,
+j){for(var o=[],m="",p,q=j.nodeType?[j]:j;p=n.match.PSEUDO.exec(g);){m+=p[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;p=0;for(var t=q.length;p<t;p++)l(g,q[p],o);return l.filter(m,o)};c.find=l;c.expr=l.selectors;c.expr[":"]=c.expr.filters;c.unique=l.uniqueSort;c.text=l.getText;c.isXMLDoc=l.isXML;c.contains=l.contains})();var Wa=/Until$/,Xa=/^(?:parents|prevUntil|prevAll)/,Ya=/,/,Ja=/^.[^:#\[\.,]*$/,Za=Array.prototype.slice,$a=c.expr.match.POS;c.fn.extend({find:function(a){for(var b=this.pushStack("",
+"find",a),d=0,e=0,f=this.length;e<f;e++){d=b.length;c.find(a,this[e],b);if(e>0)for(var h=d;h<b.length;h++)for(var k=0;k<d;k++)if(b[k]===b[h]){b.splice(h--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,e=b.length;d<e;d++)if(c.contains(this,b[d]))return true})},not:function(a){return this.pushStack(ka(this,a,false),"not",a)},filter:function(a){return this.pushStack(ka(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,
+b){var d=[],e,f,h=this[0];if(c.isArray(a)){var k={},l,n=1;if(h&&a.length){e=0;for(f=a.length;e<f;e++){l=a[e];k[l]||(k[l]=c.expr.match.POS.test(l)?c(l,b||this.context):l)}for(;h&&h.ownerDocument&&h!==b;){for(l in k){e=k[l];if(e.jquery?e.index(h)>-1:c(h).is(e))d.push({selector:l,elem:h,level:n})}h=h.parentNode;n++}}return d}k=$a.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e<f;e++)for(h=this[e];h;)if(k?k.index(h)>-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||
+!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},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){var d=typeof a==="string"?c(a,b||this.context):c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},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,e){var f=c.map(this,b,d);Wa.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||Ya.test(e))&&Xa.test(a))f=f.reverse();return this.pushStack(f,a,Za.call(arguments).join(","))}});
+c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===A||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===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 xa=/ jQuery\d+="(?:\d+|null)"/g,
+$=/^\s+/,ya=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,za=/<([\w:]+)/,ab=/<tbody/i,bb=/<|&#?\w+;/,Aa=/<(?:script|object|embed|option|style)/i,Ba=/checked\s*(?:[^=]|=\s*.checked.)/i,cb=/\=([^="'>\s]+\/)>/g,O={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,"",""]};O.optgroup=O.option;O.tbody=O.tfoot=O.colgroup=O.caption=O.thead;O.th=O.td;if(!c.support.htmlSerialize)O._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!==A)return this.empty().append((this[0]&&this[0].ownerDocument||u).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,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));
+c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}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,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(xa,"").replace(cb,'="$1">').replace($,
+"")],e)[0]}else return this.cloneNode(true)});if(a===true){la(this,b);la(this.find("*"),b.find("*"))}return b},html:function(a){if(a===A)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(xa,""):null;else if(typeof a==="string"&&!Aa.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!O[(za.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ya,"<$1></$2>");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(e){this.empty().append(a)}}else c.isFunction(a)?
+this.each(function(f){var h=c(this);h.html(a.call(this,f,h.html()))}):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),e=d.html();d.replaceWith(a.call(this,b,e))});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){var e,f,h=a[0],k=[],l;if(!c.support.checkClone&&arguments.length===3&&typeof h==="string"&&Ba.test(h))return this.each(function(){c(this).domManip(a,b,d,true)});if(c.isFunction(h))return this.each(function(s){var v=c(this);a[0]=h.call(this,s,b?v.html():A);v.domManip(a,b,d)});if(this[0]){e=h&&h.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:c.buildFragment(a,this,k);l=e.fragment;if(f=l.childNodes.length===1?l=l.firstChild:
+l.firstChild){b=b&&c.nodeName(f,"tr");f=0;for(var n=this.length;f<n;f++)d.call(b?c.nodeName(this[f],"table")?this[f].getElementsByTagName("tbody")[0]||this[f].appendChild(this[f].ownerDocument.createElement("tbody")):this[f]:this[f],f>0||e.cacheable||this.length>1?l.cloneNode(true):l)}k.length&&c.each(k,Ka)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:u;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===u&&!Aa.test(a[0])&&(c.support.checkClone||
+!Ba.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=
+d.length;f<h;f++){var k=(f>0?this.clone(true):this).get();c(d[f])[b](k);e=e.concat(k)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||u;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||u;for(var f=[],h=0,k;(k=a[h])!=null;h++){if(typeof k==="number")k+="";if(k){if(typeof k==="string"&&!bb.test(k))k=b.createTextNode(k);else if(typeof k==="string"){k=k.replace(ya,"<$1></$2>");var l=(za.exec(k)||["",""])[1].toLowerCase(),n=O[l]||O._default,
+s=n[0],v=b.createElement("div");for(v.innerHTML=n[1]+k+n[2];s--;)v=v.lastChild;if(!c.support.tbody){s=ab.test(k);l=l==="table"&&!s?v.firstChild&&v.firstChild.childNodes:n[1]==="<table>"&&!s?v.childNodes:[];for(n=l.length-1;n>=0;--n)c.nodeName(l[n],"tbody")&&!l[n].childNodes.length&&l[n].parentNode.removeChild(l[n])}!c.support.leadingWhitespace&&$.test(k)&&v.insertBefore(b.createTextNode($.exec(k)[0]),v.firstChild);k=v.childNodes}if(k.nodeType)f.push(k);else f=c.merge(f,k)}}if(d)for(h=0;f[h];h++)if(e&&
+c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script"))));d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,k=0,l;(l=a[k])!=null;k++)if(!(l.nodeName&&c.noData[l.nodeName.toLowerCase()]))if(d=l[c.expando]){if((b=e[d])&&b.events)for(var n in b.events)f[n]?
+c.event.remove(l,n):c.removeEvent(l,n,b.handle);if(h)delete l[c.expando];else l.removeAttribute&&l.removeAttribute(c.expando);delete e[d]}}});var Ca=/alpha\([^)]*\)/i,db=/opacity=([^)]*)/,eb=/-([a-z])/ig,fb=/([A-Z])/g,Da=/^-?\d+(?:px)?$/i,gb=/^-?\d/,hb={position:"absolute",visibility:"hidden",display:"block"},La=["Left","Right"],Ma=["Top","Bottom"],W,ib=u.defaultView&&u.defaultView.getComputedStyle,jb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===A)return this;
+return c.access(this,a,b,true,function(d,e,f){return f!==A?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true,zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),k=a.style,l=c.cssHooks[h];b=c.cssProps[h]||
+h;if(d!==A){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!l||!("set"in l)||(d=l.set(a,d))!==A)try{k[b]=d}catch(n){}}}else{if(l&&"get"in l&&(f=l.get(a,false,e))!==A)return f;return k[b]}}},css:function(a,b,d){var e,f=c.camelCase(b),h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==A)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=
+e[f]},camelCase:function(a){return a.replace(eb,jb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=ma(d,b,f);else c.swap(d,hb,function(){h=ma(d,b,f)});return h+"px"}},set:function(d,e){if(Da.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return db.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":
+b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f=d.filter||"";d.filter=Ca.test(f)?f.replace(Ca,e):d.filter+" "+e}};if(ib)W=function(a,b,d){var e;d=d.replace(fb,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return A;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};else if(u.documentElement.currentStyle)W=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],
+h=a.style;if(!Da.test(f)&&gb.test(f)){d=h.left;e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f};if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var kb=c.now(),lb=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+mb=/^(?:select|textarea)/i,nb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,ob=/^(?:GET|HEAD|DELETE)$/,Na=/\[\]$/,T=/\=\?(&|$)/,ia=/\?/,pb=/([?&])_=[^&]*/,qb=/^(\w+:)?\/\/([^\/?#]+)/,rb=/%20/g,sb=/#.*$/,Ea=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ea)return Ea.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=
+b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(k,l){if(l==="success"||l==="notmodified")h.html(f?c("<div>").append(k.responseText.replace(lb,"")).find(f):k.responseText);d&&h.each(d,[k.responseText,l,k])}});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||mb.test(this.nodeName)||nb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).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,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})},
+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,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},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:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html",
+script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),k=ob.test(h);b.url=b.url.replace(sb,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ia.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data||
+!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+kb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var l=E[d];E[d]=function(m){f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);if(c.isFunction(l))l(m);else{E[d]=A;try{delete E[d]}catch(p){}}v&&v.removeChild(B)}}if(b.dataType==="script"&&b.cache===null)b.cache=
+false;if(b.cache===false&&h==="GET"){var n=c.now(),s=b.url.replace(pb,"$1_="+n);b.url=s+(s===b.url?(ia.test(b.url)?"&":"?")+"_="+n:"")}if(b.data&&h==="GET")b.url+=(ia.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");n=(n=qb.exec(b.url))&&(n[1]&&n[1]!==location.protocol||n[2]!==location.host);if(b.dataType==="script"&&h==="GET"&&n){var v=u.getElementsByTagName("head")[0]||u.documentElement,B=u.createElement("script");if(b.scriptCharset)B.charset=b.scriptCharset;B.src=
+b.url;if(!d){var D=false;B.onload=B.onreadystatechange=function(){if(!D&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){D=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);B.onload=B.onreadystatechange=null;v&&B.parentNode&&v.removeChild(B)}}}v.insertBefore(B,v.firstChild);return A}var H=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!k||a&&a.contentType)w.setRequestHeader("Content-Type",
+b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}n||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(G){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&&
+c.triggerGlobal(b,"ajaxSend",[w,b]);var M=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){H||c.handleComplete(b,w,e,f);H=true;if(w)w.onreadystatechange=c.noop}else if(!H&&w&&(w.readyState===4||m==="timeout")){H=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d||
+c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&g.call&&g.call(w);M("abort")}}catch(j){}b.async&&b.timeout>0&&setTimeout(function(){w&&!H&&M("timeout")},b.timeout);try{w.send(k||b.data==null?null:b.data)}catch(o){c.handleError(b,w,null,o);c.handleComplete(b,w,e,f)}b.async||M();return w}},param:function(a,b){var d=[],e=function(h,k){k=c.isFunction(k)?k():k;d[d.length]=encodeURIComponent(h)+
+"="+encodeURIComponent(k)};if(b===A)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)ca(f,a[f],b,e);return d.join("&").replace(rb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess",[b,a])},handleComplete:function(a,
+b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),e=a.getResponseHeader("Etag");
+if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}});if(E.ActiveXObject)c.ajaxSettings.xhr=
+function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var da={},tb=/^(?:toggle|show|hide)$/,ub=/^([+\-]=)?([\d+.\-]+)(.*)$/,aa,na=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show",3),a,b,d);else{a=
+0;for(b=this.length;a<b;a++){if(!c.data(this[a],"olddisplay")&&this[a].style.display==="none")this[a].style.display="";this[a].style.display===""&&c.css(this[a],"display")==="none"&&c.data(this[a],"olddisplay",oa(this[a].nodeName))}for(a=0;a<b;a++)this[a].style.display=c.data(this[a],"olddisplay")||"";return this}},hide:function(a,b,d){if(a||a===0)return this.animate(S("hide",3),a,b,d);else{a=0;for(b=this.length;a<b;a++){d=c.css(this[a],"display");d!=="none"&&c.data(this[a],"olddisplay",d)}for(a=
+0;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b,d){var e=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||e?this.each(function(){var f=e?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(S("toggle",3),a,b,d);return this},fadeTo:function(a,b,d,e){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d,e)},animate:function(a,b,d,e){var f=c.speed(b,d,e);if(c.isEmptyObject(a))return this.each(f.complete);
+return this[f.queue===false?"each":"queue"](function(){var h=c.extend({},f),k,l=this.nodeType===1,n=l&&c(this).is(":hidden"),s=this;for(k in a){var v=c.camelCase(k);if(k!==v){a[v]=a[k];delete a[k];k=v}if(a[k]==="hide"&&n||a[k]==="show"&&!n)return h.complete.call(this);if(l&&(k==="height"||k==="width")){h.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(c.css(this,"display")==="inline"&&c.css(this,"float")==="none")if(c.support.inlineBlockNeedsLayout)if(oa(this.nodeName)===
+"inline")this.style.display="inline-block";else{this.style.display="inline";this.style.zoom=1}else this.style.display="inline-block"}if(c.isArray(a[k])){(h.specialEasing=h.specialEasing||{})[k]=a[k][1];a[k]=a[k][0]}}if(h.overflow!=null)this.style.overflow="hidden";h.curAnim=c.extend({},a);c.each(a,function(B,D){var H=new c.fx(s,h,B);if(tb.test(D))H[D==="toggle"?n?"show":"hide":D](a);else{var w=ub.exec(D),G=H.cur(true)||0;if(w){var M=parseFloat(w[2]),g=w[3]||"px";if(g!=="px"){c.style(s,B,(M||1)+g);
+G=(M||1)/H.cur(true)*G;c.style(s,B,G+g)}if(w[1])M=(w[1]==="-="?-1:1)*M+G;H.custom(G,M,g)}else H.custom(G,D,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var e=d.length-1;e>=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b,
+d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a*
+Math.PI)/2+0.5)*e+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)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(h){return f.step(h)}
+this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;var f=this;a=c.fx;e.elem=this.elem;if(e()&&c.timers.push(e)&&!aa)aa=setInterval(a.tick,a.interval)},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=c.now(),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 e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(l,n){f.style["overflow"+n]=h.overflow[l]})}this.options.hide&&c(this.elem).hide();if(this.options.hide||
+this.options.show)for(var k in this.options.curAnim)c.style(this.elem,k,this.options.orig[k]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,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()},interval:13,stop:function(){clearInterval(aa);aa=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};var vb=/^t(?:able|d|h)$/i,Fa=/^(?:body|html)$/i;c.fn.offset="getBoundingClientRect"in u.documentElement?function(a){var b=this[0],d;if(a)return this.each(function(k){c.offset.setOffset(this,a,k)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);try{d=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,h=f.documentElement;if(!d||!c.contains(h,b))return d||{top:0,left:0};b=f.body;f=ea(f);return{top:d.top+(f.pageYOffset||c.support.boxModel&&
+h.scrollTop||b.scrollTop)-(h.clientTop||b.clientTop||0),left:d.left+(f.pageXOffset||c.support.boxModel&&h.scrollLeft||b.scrollLeft)-(h.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(s){c.offset.setOffset(this,a,s)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d=b.offsetParent,e=b.ownerDocument,f,h=e.documentElement,k=e.body;f=(e=e.defaultView)?e.getComputedStyle(b,null):b.currentStyle;
+for(var l=b.offsetTop,n=b.offsetLeft;(b=b.parentNode)&&b!==k&&b!==h;){if(c.offset.supportsFixedPosition&&f.position==="fixed")break;f=e?e.getComputedStyle(b,null):b.currentStyle;l-=b.scrollTop;n-=b.scrollLeft;if(b===d){l+=b.offsetTop;n+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&vb.test(b.nodeName))){l+=parseFloat(f.borderTopWidth)||0;n+=parseFloat(f.borderLeftWidth)||0}d=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&f.overflow!=="visible"){l+=
+parseFloat(f.borderTopWidth)||0;n+=parseFloat(f.borderLeftWidth)||0}f=f}if(f.position==="relative"||f.position==="static"){l+=k.offsetTop;n+=k.offsetLeft}if(c.offset.supportsFixedPosition&&f.position==="fixed"){l+=Math.max(h.scrollTop,k.scrollTop);n+=Math.max(h.scrollLeft,k.scrollLeft)}return{top:l,left:n}};c.offset={initialize:function(){var a=u.body,b=u.createElement("div"),d,e,f,h=parseFloat(c.css(a,"marginTop"))||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;e=d.firstChild;f=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=e.offsetTop!==5;this.doesAddBorderForTableAndCells=
+f.offsetTop===5;e.style.position="fixed";e.style.top="20px";this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15;e.style.position=e.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==h;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.css(a,
+"marginTop"))||0;d+=parseFloat(c.css(a,"marginLeft"))||0}return{top:b,left:d}},setOffset:function(a,b,d){var e=c.css(a,"position");if(e==="static")a.style.position="relative";var f=c(a),h=f.offset(),k=c.css(a,"top"),l=c.css(a,"left"),n=e==="absolute"&&c.inArray("auto",[k,l])>-1;e={};var s={};if(n)s=f.position();k=n?s.top:parseInt(k,10)||0;l=n?s.left:parseInt(l,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+k;if(b.left!=null)e.left=b.left-h.left+l;"using"in b?b.using.call(a,
+e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Fa.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||u.body;a&&!Fa.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(e){var f=this[0],h;if(!f)return null;if(e!==A)return this.each(function(){if(h=ea(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=ea(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();
+c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(h){var k=c(this);k[d](e.call(this,h,k[d]()))});return c.isWindow(f)?f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b]:f.nodeType===9?Math.max(f.documentElement["client"+
+b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]):e===A?parseFloat(c.css(f,d)):this.css(d,typeof e==="string"?e:e+"px")}})})(window);
diff --git a/askbot/media/js/jquery.fancybox-1.3.4/style.css b/askbot/media/js/jquery.fancybox-1.3.4/style.css
new file mode 100644
index 00000000..e11a5122
--- /dev/null
+++ b/askbot/media/js/jquery.fancybox-1.3.4/style.css
@@ -0,0 +1,65 @@
+html, body, div, ul {
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ color: #262626;
+ background: #f4f4f4;
+ font: normal 12px/18px Verdana, sans-serif;
+}
+
+#content {
+ width: 400px;
+ margin: 40px auto 0 auto;
+ padding: 0 60px 30px 60px;
+ border: solid 1px #cbcbcb;
+ background: #fafafa;
+ -moz-box-shadow: 0px 0px 10px #cbcbcb;
+ -webkit-box-shadow: 0px 0px 10px #cbcbcb;
+}
+
+h1 {
+ margin: 30px 0 15px 0;
+ font-size: 30px;
+ font-weight: bold;
+ font-family: Arial;
+}
+
+h1 span {
+ font-size: 50%;
+ letter-spacing: -0.05em;
+}
+
+hr {
+ border: none;
+ height: 1px; line-height: 1px;
+ background: #E5E5E5;
+ margin-bottom: 20px;
+ padding: 0;
+}
+
+p {
+ margin: 0;
+ padding: 7px 0;
+}
+
+a {
+ outline: none;
+}
+
+a img {
+ border: 1px solid #BBB;
+ padding: 2px;
+ margin: 10px 20px 10px 0;
+ vertical-align: top;
+}
+
+a img.last {
+ margin-right: 0;
+}
+
+ul {
+ margin-bottom: 24px;
+ padding-left: 30px;
+}
diff --git a/askbot/skins/common/media/js/jquery.flot.js b/askbot/media/js/jquery.flot.js
index 6534a468..6534a468 100644
--- a/askbot/skins/common/media/js/jquery.flot.js
+++ b/askbot/media/js/jquery.flot.js
diff --git a/askbot/skins/common/media/js/jquery.flot.min.js b/askbot/media/js/jquery.flot.min.js
index 31f465b8..31f465b8 100644
--- a/askbot/skins/common/media/js/jquery.flot.min.js
+++ b/askbot/media/js/jquery.flot.min.js
diff --git a/askbot/skins/common/media/js/jquery.form.js b/askbot/media/js/jquery.form.js
index 443114fd..443114fd 100644
--- a/askbot/skins/common/media/js/jquery.form.js
+++ b/askbot/media/js/jquery.form.js
diff --git a/askbot/skins/common/media/js/jquery.history.js b/askbot/media/js/jquery.history.js
index 8d4edcd2..8d4edcd2 100644
--- a/askbot/skins/common/media/js/jquery.history.js
+++ b/askbot/media/js/jquery.history.js
diff --git a/askbot/skins/common/media/js/jquery.i18n.js b/askbot/media/js/jquery.i18n.js
index 0a155a31..0a155a31 100644
--- a/askbot/skins/common/media/js/jquery.i18n.js
+++ b/askbot/media/js/jquery.i18n.js
diff --git a/askbot/skins/common/media/js/jquery.openid.js b/askbot/media/js/jquery.openid.js
index af7d8cb9..af7d8cb9 100644
--- a/askbot/skins/common/media/js/jquery.openid.js
+++ b/askbot/media/js/jquery.openid.js
diff --git a/askbot/skins/common/media/js/jquery.validate.js b/askbot/media/js/jquery.validate.js
index e402ea8c..e402ea8c 100644
--- a/askbot/skins/common/media/js/jquery.validate.js
+++ b/askbot/media/js/jquery.validate.js
diff --git a/askbot/skins/common/media/js/jquery.validate.min.js b/askbot/media/js/jquery.validate.min.js
index 6264866f..6264866f 100644
--- a/askbot/skins/common/media/js/jquery.validate.min.js
+++ b/askbot/media/js/jquery.validate.min.js
diff --git a/askbot/skins/common/media/js/jquery.validate.pack.js b/askbot/media/js/jquery.validate.pack.js
index 49134500..49134500 100644
--- a/askbot/skins/common/media/js/jquery.validate.pack.js
+++ b/askbot/media/js/jquery.validate.pack.js
diff --git a/askbot/skins/common/media/js/less.min.js b/askbot/media/js/less.min.js
index 6e4d5cff..6e4d5cff 100644
--- a/askbot/skins/common/media/js/less.min.js
+++ b/askbot/media/js/less.min.js
diff --git a/askbot/skins/common/media/js/live_search.js b/askbot/media/js/live_search.js
index f7d89c2a..f7d89c2a 100644
--- a/askbot/skins/common/media/js/live_search.js
+++ b/askbot/media/js/live_search.js
diff --git a/askbot/media/js/live_search_new_thread.js b/askbot/media/js/live_search_new_thread.js
new file mode 100644
index 00000000..eedd5fe8
--- /dev/null
+++ b/askbot/media/js/live_search_new_thread.js
@@ -0,0 +1,93 @@
+
+var liveSearchNewThreadInit = function(auto_focus_out) {
+ var query = $('input#id_title.questionTitleInput');
+ var prev_text = $.trim(query.val());
+ var search_url = askbot['urls']['api_get_questions'];
+ var running = false;
+ var q_list_sel = 'question-list'; //id of question listing div
+
+ running = false;
+ var ask_page_eval_handle;
+ query.keyup(function(e){
+ if (running === false){
+ clearTimeout(ask_page_eval_handle);
+ ask_page_eval_handle = setTimeout(eval_query, 400);
+ }
+ });
+
+ query.focusout(function(){
+ if (auto_focus_out){
+ var restart_query_handle = setTimeout(restart_query, 500);
+ restart_query_handle();
+ }
+ });
+
+ var restart_query = function(){
+ /* restart query */
+ $('#' + q_list_sel).css('height',0).children().remove();
+ running = false;
+ prev_text = '';
+ }
+
+ var eval_query = function(){
+ cur_text = $.trim(query.val());
+ if (cur_text !== prev_text && running === false){
+ if (cur_text.length >= minSearchWordLength){
+ send_query(cur_text);
+ } else if (cur_text.length === 0){
+ restart_query();
+ }
+ }
+ };
+
+ var render_result = function(data, text_status, xhr){
+ var container = $('#' + q_list_sel);
+ container.fadeOut(200, function() {
+ container.children().remove();
+ $.each(data, function(idx, question){
+ var url = question['url'];
+ var title = question['title'];
+ var answer_count = question['answer_count'];
+ var list_item = $('<h2></h2>');
+ var count_element = $('<span class="item-count"></span>');
+ count_element.html(answer_count);
+ list_item.append(count_element);
+ var link = $('<a></a>');
+ link.attr('href', url);
+ link.attr('target', '_blank');
+ list_item.append(link);
+ title_element = $('<span class="title"></span>');
+ title_element.html(title);
+ link.append(title)
+ container.append(list_item);
+ });
+ container.show();//show just to measure
+ var unit_height = container.children(':first').outerHeight();
+ container.hide();//now hide
+ if (data.length > 5){
+ container.css('overflow-y', 'scroll');
+ container.css('height', unit_height*5 + 'px');
+ } else {
+ container.css('height', data.length*unit_height + 'px');
+ container.css('overflow-y', 'hidden');
+ }
+ container.fadeIn();
+ });
+ };
+
+ var send_query = function(query_text){
+ prev_text = query_text;
+ running = true;
+ $.ajax({
+ url: search_url,
+ dataType: 'json',
+ success: render_result,
+ complete: function() {
+ running = false;
+ eval_query();
+ },
+ data: {query: query_text},
+ cache: false
+ });
+ }
+};
diff --git a/askbot/skins/common/media/js/modernizr.custom.js b/askbot/media/js/modernizr.custom.js
index cf1d0196..cf1d0196 100644
--- a/askbot/skins/common/media/js/modernizr.custom.js
+++ b/askbot/media/js/modernizr.custom.js
diff --git a/askbot/skins/common/media/js/output-words.html b/askbot/media/js/output-words.html
index 8ea5f314..8ea5f314 100644
--- a/askbot/skins/common/media/js/output-words.html
+++ b/askbot/media/js/output-words.html
diff --git a/askbot/skins/common/media/js/output-words.js b/askbot/media/js/output-words.js
index 41e25651..41e25651 100644
--- a/askbot/skins/common/media/js/output-words.js
+++ b/askbot/media/js/output-words.js
diff --git a/askbot/media/js/post.js b/askbot/media/js/post.js
new file mode 100644
index 00000000..483973ec
--- /dev/null
+++ b/askbot/media/js/post.js
@@ -0,0 +1,4081 @@
+/*
+Scripts for cnprog.com
+Project Name: Lanai
+All Rights Resevred 2008. CNPROG.COM
+*/
+var lanai = {
+ /**
+ * Finds any <pre><code></code></pre> tags which aren't registered for
+ * pretty printing, adds the appropriate class name and invokes prettify.
+ */
+ highlightSyntax: function(){
+ var styled = false;
+ $("pre code").parent().each(function(){
+ if (!$(this).hasClass('prettyprint')){
+ $(this).addClass('prettyprint');
+ styled = true;
+ }
+ });
+
+ if (styled){
+ prettyPrint();
+ }
+ }
+};
+
+function appendLoader(element) {
+ loading = gettext('loading...')
+ element.append('<img class="ajax-loader" ' +
+ 'src="' + mediaUrl("media/images/indicator.gif") + '" title="' +
+ loading +
+ '" alt="' +
+ loading +
+ '" />');
+}
+
+function removeLoader() {
+ $("img.ajax-loader").remove();
+}
+
+function setSubmitButtonDisabled(form, isDisabled) {
+ form.find('input[type="submit"]').attr("disabled", isDisabled);
+}
+
+function enableSubmitButton(form) {
+ setSubmitButtonDisabled(form, false);
+}
+
+function disableSubmitButton(form) {
+ setSubmitButtonDisabled(form, true);
+}
+
+function setupFormValidation(form, validationRules, validationMessages, onSubmitCallback) {
+ enableSubmitButton(form);
+ form.validate({
+ debug: true,
+ rules: (validationRules ? validationRules : {}),
+ messages: (validationMessages ? validationMessages : {}),
+ errorElement: "span",
+ errorClass: "form-error",
+ errorPlacement: function(error, element) {
+ var span = element.next().find("span.form-error");
+ if (span.length === 0) {
+ span = element.parent().find("span.form-error");
+ if (span.length === 0){
+ //for resizable textarea
+ var element_id = element.attr('id');
+ span = $('label[for="' + element_id + '"]');
+ }
+ }
+ span.replaceWith(error);
+ },
+ submitHandler: function(form_dom) {
+ disableSubmitButton($(form_dom));
+
+ if (onSubmitCallback){
+ onSubmitCallback();
+ }
+ else{
+ form_dom.submit();
+ }
+ }
+ });
+}
+
+/**
+ * generic tag cleaning function, settings
+ * are from askbot live settings and askbot.const
+ */
+var cleanTag = function(tag_name, settings) {
+ var tag_regex = new RegExp(settings['tag_regex']);
+ if (tag_regex.test(tag_name) === false) {
+ throw settings['messages']['wrong_chars']
+ }
+
+ var max_length = settings['max_tag_length'];
+ if (tag_name.length > max_length) {
+ throw interpolate(
+ ngettext(
+ 'must be shorter than %(max_chars)s character',
+ 'must be shorter than %(max_chars)s characters',
+ max_length
+ ),
+ {'max_chars': max_length },
+ true
+ );
+ }
+ if (settings['force_lowercase_tags']) {
+ return tag_name.toLowerCase();
+ } else {
+ return tag_name;
+ }
+};
+
+var validateTagLength = function(value){
+ var tags = getUniqueWords(value);
+ var are_tags_ok = true;
+ $.each(tags, function(index, value){
+ if (value.length > askbot['settings']['maxTagLength']){
+ are_tags_ok = false;
+ }
+ });
+ return are_tags_ok;
+};
+var validateTagCount = function(value){
+ var tags = getUniqueWords(value);
+ return (tags.length <= askbot['settings']['maxTagsPerPost']);
+};
+
+$.validator.addMethod('limit_tag_count', validateTagCount);
+$.validator.addMethod('limit_tag_length', validateTagLength);
+
+var CPValidator = function(){
+ return {
+ getQuestionFormRules : function(){
+ return {
+ tags: {
+ required: askbot['settings']['tagsAreRequired'],
+ maxlength: 105,
+ limit_tag_count: true,
+ limit_tag_length: true
+ },
+ text: {
+ minlength: askbot['settings']['minQuestionBodyLength']
+ },
+ title: {
+ minlength: askbot['settings']['minTitleLength']
+ }
+ };
+ },
+ getQuestionFormMessages: function(){
+ return {
+ tags: {
+ required: " " + gettext('tags cannot be empty'),
+ maxlength: askbot['messages']['tagLimits'],
+ limit_tag_count: askbot['messages']['maxTagsPerPost'],
+ limit_tag_length: askbot['messages']['maxTagLength']
+ },
+ text: {
+ required: " " + gettext('content cannot be empty'),
+ minlength: interpolate(
+ ngettext(
+ 'question body must be > %s character',
+ 'question body must be > %s characters',
+ askbot['settings']['minQuestionBodyLength']
+ ),
+ [askbot['settings']['minQuestionBodyLength'], ]
+ )
+ },
+ title: {
+ required: " " + gettext('please enter title'),
+ minlength: interpolate(
+ ngettext(
+ 'title must be > %s character',
+ 'title must be > %s characters',
+ askbot['settings']['minTitleLength']
+ ),
+ [askbot['settings']['minTitleLength'], ]
+ )
+ }
+ };
+ },
+ getAnswerFormRules : function(){
+ return {
+ text: {
+ minlength: askbot['settings']['minAnswerBodyLength']
+ },
+ };
+ },
+ getAnswerFormMessages: function(){
+ return {
+ text: {
+ required: " " + gettext('content cannot be empty'),
+ minlength: interpolate(
+ ngettext(
+ 'answer must be > %s character',
+ 'answer must be > %s characters',
+ askbot['settings']['minAnswerBodyLength']
+ ),
+ [askbot['settings']['minAnswerBodyLength'], ]
+ )
+ },
+ }
+ }
+ };
+}();
+
+/**
+ * @constructor
+ */
+var ThreadUsersDialog = function() {
+ SimpleControl.call(this);
+ this._heading_text = 'Add heading with the setHeadingText()';
+};
+inherits(ThreadUsersDialog, SimpleControl);
+
+ThreadUsersDialog.prototype.setHeadingText = function(text) {
+ this._heading_text = text;
+};
+
+ThreadUsersDialog.prototype.showUsers = function(html) {
+ this._dialog.setContent(html);
+ this._dialog.show();
+};
+
+ThreadUsersDialog.prototype.startShowingUsers = function() {
+ var me = this;
+ var threadId = this._threadId;
+ var url = this._url;
+ $.ajax({
+ type: 'GET',
+ data: {'thread_id': threadId},
+ dataType: 'json',
+ url: url,
+ cache: false,
+ success: function(data){
+ if (data['success'] == true){
+ me.showUsers(data['html']);
+ } else {
+ showMessage(me.getElement(), data['message'], 'after');
+ }
+ }
+ });
+};
+
+ThreadUsersDialog.prototype.decorate = function(element) {
+ this._element = element;
+ ThreadUsersDialog.superClass_.decorate.call(this, element);
+ this._threadId = element.data('threadId');
+ this._url = element.data('url');
+ var dialog = new ModalDialog();
+ dialog.setRejectButtonText('');
+ dialog.setAcceptButtonText(gettext('Back to the question'));
+ dialog.setHeadingText(this._heading_text);
+ dialog.setAcceptHandler(function(){ dialog.hide(); });
+ var dialog_element = dialog.getElement();
+ $(dialog_element).find('.modal-footer').css('text-align', 'center');
+ $(document).append(dialog_element);
+ this._dialog = dialog;
+ var me = this;
+ this.setHandler(function(){
+ me.startShowingUsers();
+ });
+};
+
+
+/**
+ * @constructor
+ */
+var DraftPost = function() {
+ WrappedElement.call(this);
+};
+inherits(DraftPost, WrappedElement);
+
+/**
+ * @return {string}
+ */
+DraftPost.prototype.getUrl = function() {
+ throw 'Not Implemented';
+};
+
+/**
+ * @return {boolean}
+ */
+DraftPost.prototype.shouldSave = function() {
+ throw 'Not Implemented';
+};
+
+/**
+ * @return {object} data dict
+ */
+DraftPost.prototype.getData = function() {
+ throw 'Not Implemented';
+};
+
+DraftPost.prototype.backupData = function() {
+ this._old_data = this.getData();
+};
+
+DraftPost.prototype.showNotification = function() {
+ var note = $('.editor-status span');
+ note.hide();
+ note.html(gettext('draft saved...'));
+ note.fadeIn().delay(3000).fadeOut();
+};
+
+DraftPost.prototype.getSaveHandler = function() {
+ var me = this;
+ return function(save_synchronously) {
+ if (me.shouldSave()) {
+ $.ajax({
+ type: 'POST',
+ cache: false,
+ dataType: 'json',
+ async: save_synchronously ? false : true,
+ url: me.getUrl(),
+ data: me.getData(),
+ success: function(data) {
+ if (data['success'] && !save_synchronously) {
+ me.showNotification();
+ }
+ me.backupData();
+ }
+ });
+ }
+ };
+};
+
+DraftPost.prototype.decorate = function(element) {
+ this._element = element;
+ this.assignContentElements();
+ this.backupData();
+ setInterval(this.getSaveHandler(), 30000);//auto-save twice a minute
+ var me = this;
+ window.onbeforeunload = function() {
+ var saveHandler = me.getSaveHandler();
+ saveHandler(true);
+ //var msg = gettext("%s, we've saved your draft, but...");
+ //return interpolate(msg, [askbot['data']['userName']]);
+ };
+};
+
+
+/**
+ * @contstructor
+ */
+var DraftQuestion = function() {
+ DraftPost.call(this);
+};
+inherits(DraftQuestion, DraftPost);
+
+DraftQuestion.prototype.getUrl = function() {
+ return askbot['urls']['saveDraftQuestion'];
+};
+
+DraftQuestion.prototype.shouldSave = function() {
+ var newd = this.getData();
+ var oldd = this._old_data;
+ return (
+ newd['title'] !== oldd['title'] ||
+ newd['text'] !== oldd['text'] ||
+ newd['tagnames'] !== oldd['tagnames']
+ );
+};
+
+DraftQuestion.prototype.getData = function() {
+ return {
+ 'title': this._title_element.val(),
+ 'text': this._text_element.val(),
+ 'tagnames': this._tagnames_element.val()
+ };
+};
+
+DraftQuestion.prototype.assignContentElements = function() {
+ this._title_element = $('#id_title');
+ this._text_element = $('#editor');
+ this._tagnames_element = $('#id_tags');
+};
+
+var DraftAnswer = function() {
+ DraftPost.call(this);
+};
+inherits(DraftAnswer, DraftPost);
+
+DraftAnswer.prototype.setThreadId = function(id) {
+ this._threadId = id;
+};
+
+DraftAnswer.prototype.getUrl = function() {
+ return askbot['urls']['saveDraftAnswer'];
+};
+
+DraftAnswer.prototype.shouldSave = function() {
+ return this.getData()['text'] !== this._old_data['text'];
+};
+
+DraftAnswer.prototype.getData = function() {
+ return {
+ 'text': this._textElement.val(),
+ 'thread_id': this._threadId
+ };
+};
+
+DraftAnswer.prototype.assignContentElements = function() {
+ this._textElement = $('#editor');
+};
+
+
+/**
+ * @constructor
+ * @extends {SimpleControl}
+ * @param {Comment} comment to upvote
+ */
+var CommentVoteButton = function(comment){
+ SimpleControl.call(this);
+ /**
+ * @param {Comment}
+ */
+ this._comment = comment;
+ /**
+ * @type {boolean}
+ */
+ this._voted = false;
+ /**
+ * @type {number}
+ */
+ this._score = 0;
+};
+inherits(CommentVoteButton, SimpleControl);
+/**
+ * @param {number} score
+ */
+CommentVoteButton.prototype.setScore = function(score){
+ this._score = score;
+ if (this._element){
+ this._element.html(score);
+ }
+};
+/**
+ * @param {boolean} voted
+ */
+CommentVoteButton.prototype.setVoted = function(voted){
+ this._voted = voted;
+ if (this._element){
+ this._element.addClass('upvoted');
+ }
+};
+
+CommentVoteButton.prototype.getVoteHandler = function(){
+ var me = this;
+ var comment = this._comment;
+ return function(){
+ var voted = me._voted;
+ var post_id = me._comment.getId();
+ var data = {
+ cancel_vote: voted ? true:false,
+ post_id: post_id
+ };
+ $.ajax({
+ type: 'POST',
+ data: data,
+ dataType: 'json',
+ url: askbot['urls']['upvote_comment'],
+ cache: false,
+ success: function(data){
+ if (data['success'] == true){
+ me.setScore(data['score']);
+ me.setVoted(true);
+ } else {
+ showMessage(comment.getElement(), data['message'], 'after');
+ }
+ }
+ });
+ };
+};
+
+CommentVoteButton.prototype.decorate = function(element){
+ this._element = element;
+ this.setHandler(this.getVoteHandler());
+
+ var element = this._element;
+ var comment = this._comment;
+ /* can't call comment.getElement() here due
+ * an issue in the getElement() of comment
+ * so use an "illegal" access to comment._element here
+ */
+ comment._element.mouseenter(function(){
+ //outside height may not be known
+ //var height = comment.getElement().height();
+ //element.height(height);
+ element.addClass('hover');
+ });
+ comment._element.mouseleave(function(){
+ element.removeClass('hover');
+ });
+
+};
+
+CommentVoteButton.prototype.createDom = function(){
+ this._element = this.makeElement('div');
+ if (this._score > 0){
+ this._element.html(this._score);
+ }
+ this._element.addClass('upvote');
+ if (this._voted){
+ this._element.addClass('upvoted');
+ }
+ this.decorate(this._element);
+};
+
+/**
+ * legacy Vote class
+ * handles all sorts of vote-like operations
+ */
+var Vote = function(){
+ // All actions are related to a question
+ var questionId;
+ //question slug to build redirect urls
+ var questionSlug;
+ // The object we operate on actually. It can be a question or an answer.
+ var postId;
+ var questionAuthorId;
+ var currentUserId;
+ var answerContainerIdPrefix = 'post-id-';
+ var voteContainerId = 'vote-buttons';
+ var imgIdPrefixAccept = 'answer-img-accept-';
+ var classPrefixFollow= 'button follow';
+ var classPrefixFollowed= 'button followed';
+ var imgIdPrefixQuestionVoteup = 'question-img-upvote-';
+ var imgIdPrefixQuestionVotedown = 'question-img-downvote-';
+ var imgIdPrefixAnswerVoteup = 'answer-img-upvote-';
+ var imgIdPrefixAnswerVotedown = 'answer-img-downvote-';
+ var divIdFavorite = 'favorite-number';
+ var commentLinkIdPrefix = 'comment-';
+ var voteNumberClass = "vote-number";
+ var offensiveIdPrefixQuestionFlag = 'question-offensive-flag-';
+ var removeOffensiveIdPrefixQuestionFlag = 'question-offensive-remove-flag-';
+ var removeAllOffensiveIdPrefixQuestionFlag = 'question-offensive-remove-all-flag-';
+ var offensiveIdPrefixAnswerFlag = 'answer-offensive-flag-';
+ var removeOffensiveIdPrefixAnswerFlag = 'answer-offensive-remove-flag-';
+ var removeAllOffensiveIdPrefixAnswerFlag = 'answer-offensive-remove-all-flag-';
+ var offensiveClassFlag = 'offensive-flag';
+ var questionControlsId = 'question-controls';
+ var removeAnswerLinkIdPrefix = 'answer-delete-link-';
+ var questionSubscribeUpdates = 'question-subscribe-updates';
+ var questionSubscribeSidebar= 'question-subscribe-sidebar';
+
+ var acceptAnonymousMessage = gettext('insufficient privilege');
+ var acceptOwnAnswerMessage = gettext('cannot pick own answer as best');
+
+ var pleaseLogin = " <a href='" + askbot['urls']['user_signin']
+ + "?next=" + askbot['urls']['question_url_template']
+ + "'>"
+ + gettext('please login') + "</a>";
+
+ var favoriteAnonymousMessage = gettext('anonymous users cannot follow questions') + pleaseLogin;
+ var subscribeAnonymousMessage = gettext('anonymous users cannot subscribe to questions') + pleaseLogin;
+ var voteAnonymousMessage = gettext('anonymous users cannot vote') + pleaseLogin;
+ //there were a couple of more messages...
+ var offensiveConfirmation = gettext('please confirm offensive');
+ var removeOffensiveConfirmation = gettext('please confirm removal of offensive flag');
+ var offensiveAnonymousMessage = gettext('anonymous users cannot flag offensive posts') + pleaseLogin;
+ var removeConfirmation = gettext('confirm delete');
+ var removeAnonymousMessage = gettext('anonymous users cannot delete/undelete') + pleaseLogin;
+ var recoveredMessage = gettext('post recovered');
+ var deletedMessage = gettext('post deleted');
+
+ var VoteType = {
+ acceptAnswer : 0,
+ questionUpVote : 1,
+ questionDownVote : 2,
+ favorite : 4,
+ answerUpVote: 5,
+ answerDownVote:6,
+ offensiveQuestion : 7,
+ removeOffensiveQuestion : 7.5,
+ removeAllOffensiveQuestion : 7.6,
+ offensiveAnswer:8,
+ removeOffensiveAnswer:8.5,
+ removeAllOffensiveAnswer:8.6,
+ removeQuestion: 9,//deprecate
+ removeAnswer:10,//deprecate
+ questionSubscribeUpdates:11,
+ questionUnsubscribeUpdates:12
+ };
+
+ var getFavoriteButton = function(){
+ var favoriteButton = 'div.'+ voteContainerId +' a[class="'+ classPrefixFollow +'"]';
+ favoriteButton += ', div.'+ voteContainerId +' a[class="'+ classPrefixFollowed +'"]';
+ return $(favoriteButton);
+ };
+ var getFavoriteNumber = function(){
+ var favoriteNumber = '#'+ divIdFavorite ;
+ return $(favoriteNumber);
+ };
+ var getQuestionVoteUpButton = function(){
+ var questionVoteUpButton = 'div.'+ voteContainerId +' div[id^="'+ imgIdPrefixQuestionVoteup +'"]';
+ return $(questionVoteUpButton);
+ };
+ var getQuestionVoteDownButton = function(){
+ var questionVoteDownButton = 'div.'+ voteContainerId +' div[id^="'+ imgIdPrefixQuestionVotedown +'"]';
+ return $(questionVoteDownButton);
+ };
+ var getAnswerVoteUpButtons = function(){
+ var answerVoteUpButton = 'div.'+ voteContainerId +' div[id^="'+ imgIdPrefixAnswerVoteup +'"]';
+ return $(answerVoteUpButton);
+ };
+ var getAnswerVoteDownButtons = function(){
+ var answerVoteDownButton = 'div.'+ voteContainerId +' div[id^="'+ imgIdPrefixAnswerVotedown +'"]';
+ return $(answerVoteDownButton);
+ };
+ var getAnswerVoteUpButton = function(id){
+ var answerVoteUpButton = 'div.'+ voteContainerId +' div[id="'+ imgIdPrefixAnswerVoteup + id + '"]';
+ return $(answerVoteUpButton);
+ };
+ var getAnswerVoteDownButton = function(id){
+ var answerVoteDownButton = 'div.'+ voteContainerId +' div[id="'+ imgIdPrefixAnswerVotedown + id + '"]';
+ return $(answerVoteDownButton);
+ };
+
+ var getOffensiveQuestionFlag = function(){
+ var offensiveQuestionFlag = '#question-table span[id^="'+ offensiveIdPrefixQuestionFlag +'"]';
+ return $(offensiveQuestionFlag);
+ };
+
+ var getRemoveOffensiveQuestionFlag = function(){
+ var removeOffensiveQuestionFlag = '#question-table span[id^="'+ removeOffensiveIdPrefixQuestionFlag +'"]';
+ return $(removeOffensiveQuestionFlag);
+ };
+
+ var getRemoveAllOffensiveQuestionFlag = function(){
+ var removeAllOffensiveQuestionFlag = '#question-table span[id^="'+ removeAllOffensiveIdPrefixQuestionFlag +'"]';
+ return $(removeAllOffensiveQuestionFlag);
+ };
+
+ var getOffensiveAnswerFlags = function(){
+ var offensiveQuestionFlag = 'div.answer span[id^="'+ offensiveIdPrefixAnswerFlag +'"]';
+ return $(offensiveQuestionFlag);
+ };
+
+ var getRemoveOffensiveAnswerFlag = function(){
+ var removeOffensiveAnswerFlag = 'div.answer span[id^="'+ removeOffensiveIdPrefixAnswerFlag +'"]';
+ return $(removeOffensiveAnswerFlag);
+ };
+
+ var getRemoveAllOffensiveAnswerFlag = function(){
+ var removeAllOffensiveAnswerFlag = 'div.answer span[id^="'+ removeAllOffensiveIdPrefixAnswerFlag +'"]';
+ return $(removeAllOffensiveAnswerFlag);
+ };
+
+ var getquestionSubscribeUpdatesCheckbox = function(){
+ return $('#' + questionSubscribeUpdates);
+ };
+
+ var getquestionSubscribeSidebarCheckbox= function(){
+ return $('#' + questionSubscribeSidebar);
+ };
+
+ var getremoveAnswersLinks = function(){
+ var removeAnswerLinks = 'div.answer-controls a[id^="'+ removeAnswerLinkIdPrefix +'"]';
+ return $(removeAnswerLinks);
+ };
+
+ var setVoteImage = function(voteType, undo, object){
+ var flag = undo ? false : true;
+ if (object.hasClass("on")) {
+ object.removeClass("on");
+ }else{
+ object.addClass("on");
+ }
+
+ if(undo){
+ if(voteType == VoteType.questionUpVote || voteType == VoteType.questionDownVote){
+ $(getQuestionVoteUpButton()).removeClass("on");
+ $(getQuestionVoteDownButton()).removeClass("on");
+ }
+ else{
+ $(getAnswerVoteUpButton(postId)).removeClass("on");
+ $(getAnswerVoteDownButton(postId)).removeClass("on");
+ }
+ }
+ };
+
+ var setVoteNumber = function(object, number){
+ var voteNumber = object.parent('div.'+ voteContainerId).find('div.'+ voteNumberClass);
+ $(voteNumber).text(number);
+ };
+
+ var bindEvents = function(){
+ // accept answers
+ var acceptedButtons = 'div.'+ voteContainerId +' div[id^="'+ imgIdPrefixAccept +'"]';
+ $(acceptedButtons).unbind('click').click(function(event){
+ Vote.accept($(event.target));
+ });
+ // set favorite question
+ var favoriteButton = getFavoriteButton();
+ favoriteButton.unbind('click').click(function(event){
+ //Vote.favorite($(event.target));
+ Vote.favorite(favoriteButton);
+ });
+
+ // question vote up
+ var questionVoteUpButton = getQuestionVoteUpButton();
+ questionVoteUpButton.unbind('click').click(function(event){
+ Vote.vote($(event.target), VoteType.questionUpVote);
+ });
+
+ var questionVoteDownButton = getQuestionVoteDownButton();
+ questionVoteDownButton.unbind('click').click(function(event){
+ Vote.vote($(event.target), VoteType.questionDownVote);
+ });
+
+ var answerVoteUpButton = getAnswerVoteUpButtons();
+ answerVoteUpButton.unbind('click').click(function(event){
+ Vote.vote($(event.target), VoteType.answerUpVote);
+ });
+
+ var answerVoteDownButton = getAnswerVoteDownButtons();
+ answerVoteDownButton.unbind('click').click(function(event){
+ Vote.vote($(event.target), VoteType.answerDownVote);
+ });
+
+ getOffensiveQuestionFlag().unbind('click').click(function(event){
+ Vote.offensive(this, VoteType.offensiveQuestion);
+ });
+
+ getRemoveOffensiveQuestionFlag().unbind('click').click(function(event){
+ Vote.remove_offensive(this, VoteType.removeOffensiveQuestion);
+ });
+
+ getRemoveAllOffensiveQuestionFlag().unbind('click').click(function(event){
+ Vote.remove_all_offensive(this, VoteType.removeAllOffensiveQuestion);
+ });
+
+ getOffensiveAnswerFlags().unbind('click').click(function(event){
+ Vote.offensive(this, VoteType.offensiveAnswer);
+ });
+
+ getRemoveOffensiveAnswerFlag().unbind('click').click(function(event){
+ Vote.remove_offensive(this, VoteType.removeOffensiveAnswer);
+ });
+
+ getRemoveAllOffensiveAnswerFlag().unbind('click').click(function(event){
+ Vote.remove_all_offensive(this, VoteType.removeAllOffensiveAnswer);
+ });
+
+ getquestionSubscribeUpdatesCheckbox().unbind('click').click(function(event){
+ //despeluchar esto
+ if (this.checked){
+ getquestionSubscribeSidebarCheckbox().attr({'checked': true});
+ Vote.vote($(event.target), VoteType.questionSubscribeUpdates);
+ }
+ else {
+ getquestionSubscribeSidebarCheckbox().attr({'checked': false});
+ Vote.vote($(event.target), VoteType.questionUnsubscribeUpdates);
+ }
+ });
+
+ getquestionSubscribeSidebarCheckbox().unbind('click').click(function(event){
+ if (this.checked){
+ getquestionSubscribeUpdatesCheckbox().attr({'checked': true});
+ Vote.vote($(event.target), VoteType.questionSubscribeUpdates);
+ }
+ else {
+ getquestionSubscribeUpdatesCheckbox().attr({'checked': false});
+ Vote.vote($(event.target), VoteType.questionUnsubscribeUpdates);
+ }
+ });
+
+ getremoveAnswersLinks().unbind('click').click(function(event){
+ Vote.remove(this, VoteType.removeAnswer);
+ });
+ };
+
+ var submit = function(object, voteType, callback) {
+ //this function submits votes
+ $.ajax({
+ type: "POST",
+ cache: false,
+ dataType: "json",
+ url: askbot['urls']['vote_url_template'].replace('{{QuestionID}}', questionId),
+ data: { "type": voteType, "postId": postId },
+ error: handleFail,
+ success: function(data) {
+ callback(object, voteType, data);
+ }
+ });
+ };
+
+ var handleFail = function(xhr, msg){
+ alert("Callback invoke error: " + msg);
+ };
+
+ // callback function for Accept Answer action
+ var callback_accept = function(object, voteType, data){
+ if(data.allowed == "0" && data.success == "0"){
+ showMessage(object, acceptAnonymousMessage);
+ }
+ else if(data.allowed == "-1"){
+ showMessage(object, acceptOwnAnswerMessage);
+ }
+ else if(data.status == "1"){
+ $("#"+answerContainerIdPrefix+postId).removeClass("accepted-answer");
+ $("#"+commentLinkIdPrefix+postId).removeClass("comment-link-accepted");
+ }
+ else if(data.success == "1"){
+ var answers = ('div[id^="'+answerContainerIdPrefix +'"]');
+ $(answers).removeClass('accepted-answer');
+ var commentLinks = ('div[id^="'+answerContainerIdPrefix +'"] div[id^="'+ commentLinkIdPrefix +'"]');
+ $(commentLinks).removeClass("comment-link-accepted");
+
+ $("#"+answerContainerIdPrefix+postId).addClass("accepted-answer");
+ $("#"+commentLinkIdPrefix+postId).addClass("comment-link-accepted");
+ }
+ else{
+ showMessage(object, data.message);
+ }
+ };
+
+ var callback_favorite = function(object, voteType, data){
+ if(data.allowed == "0" && data.success == "0"){
+ showMessage(
+ object,
+ favoriteAnonymousMessage.replace(
+ '{{QuestionID}}',
+ questionId).replace(
+ '{{questionSlug}}',
+ ''
+ )
+ );
+ }
+ else if(data.status == "1"){
+ var follow_html = gettext('Follow');
+ object.attr("class", 'button follow');
+ object.html(follow_html);
+ var fav = getFavoriteNumber();
+ fav.removeClass("my-favorite-number");
+ if(data.count === 0){
+ data.count = '';
+ fav.text('');
+ }else{
+ var fmts = ngettext('%s follower', '%s followers', data.count);
+ fav.text(interpolate(fmts, [data.count]));
+ }
+ }
+ else if(data.success == "1"){
+ var followed_html = gettext('<div>Following</div><div class="unfollow">Unfollow</div>');
+ object.html(followed_html);
+ object.attr("class", 'button followed');
+ var fav = getFavoriteNumber();
+ var fmts = ngettext('%s follower', '%s followers', data.count);
+ fav.text(interpolate(fmts, [data.count]));
+ fav.addClass("my-favorite-number");
+ }
+ else{
+ showMessage(object, data.message);
+ }
+ };
+
+ var callback_vote = function(object, voteType, data){
+ if (data.success == '0'){
+ showMessage(object, data.message);
+ return;
+ }
+ else {
+ if (data.status == '1'){
+ setVoteImage(voteType, true, object);
+ }
+ else {
+ setVoteImage(voteType, false, object);
+ }
+ setVoteNumber(object, data.count);
+ if (data.message && data.message.length > 0){
+ showMessage(object, data.message);
+ }
+ return;
+ }
+ //may need to take a look at this again
+ if (data.status == "1"){
+ setVoteImage(voteType, true, object);
+ setVoteNumber(object, data.count);
+ }
+ else if (data.success == "1"){
+ setVoteImage(voteType, false, object);
+ setVoteNumber(object, data.count);
+ if (data.message.length > 0){
+ showMessage(object, data.message);
+ }
+ }
+ };
+
+ var callback_offensive = function(object, voteType, data){
+ //todo: transfer proper translations of these from i18n.js
+ //to django.po files
+ //_('anonymous users cannot flag offensive posts') + pleaseLogin;
+ if (data.success == "1"){
+ if(data.count > 0)
+ $(object).children('span[class="darkred"]').text("("+ data.count +")");
+ else
+ $(object).children('span[class="darkred"]').text("");
+
+ // Change the link text and rebind events
+ $(object).find("a.question-flag").html(gettext("remove flag"));
+ var obj_id = $(object).attr("id");
+ $(object).attr("id", obj_id.replace("flag-", "remove-flag-"));
+
+ getRemoveOffensiveQuestionFlag().unbind('click').click(function(event){
+ Vote.remove_offensive(this, VoteType.removeOffensiveQuestion);
+ });
+
+ getRemoveOffensiveAnswerFlag().unbind('click').click(function(event){
+ Vote.remove_offensive(this, VoteType.removeOffensiveAnswer);
+ });
+ }
+ else {
+ object = $(object);
+ showMessage(object, data.message)
+ }
+ };
+
+ var callback_remove_offensive = function(object, voteType, data){
+ //todo: transfer proper translations of these from i18n.js
+ //to django.po files
+ //_('anonymous users cannot flag offensive posts') + pleaseLogin;
+ if (data.success == "1"){
+ if(data.count > 0){
+ $(object).children('span[class="darkred"]').text("("+ data.count +")");
+ }
+ else{
+ $(object).children('span[class="darkred"]').text("");
+ // Remove "remove all flags link" since there are no more flags to remove
+ var remove_all = $(object).siblings('span.offensive-flag[id*="-offensive-remove-all-flag-"]');
+ $(remove_all).next("span.sep").remove();
+ $(remove_all).remove();
+ }
+ // Change the link text and rebind events
+ $(object).find("a.question-flag").html(gettext("flag offensive"));
+ var obj_id = $(object).attr("id");
+ $(object).attr("id", obj_id.replace("remove-flag-", "flag-"));
+
+ getOffensiveQuestionFlag().unbind('click').click(function(event){
+ Vote.offensive(this, VoteType.offensiveQuestion);
+ });
+
+ getOffensiveAnswerFlags().unbind('click').click(function(event){
+ Vote.offensive(this, VoteType.offensiveAnswer);
+ });
+ }
+ else {
+ object = $(object);
+ showMessage(object, data.message)
+ }
+ };
+
+ var callback_remove_all_offensive = function(object, voteType, data){
+ //todo: transfer proper translations of these from i18n.js
+ //to django.po files
+ //_('anonymous users cannot flag offensive posts') + pleaseLogin;
+ if (data.success == "1"){
+ if(data.count > 0)
+ $(object).children('span[class="darkred"]').text("("+ data.count +")");
+ else
+ $(object).children('span[class="darkred"]').text("");
+ // remove the link. All flags are gone
+ var remove_own = $(object).siblings('span.offensive-flag[id*="-offensive-remove-flag-"]');
+ $(remove_own).find("a.question-flag").html(gettext("flag offensive"));
+ $(remove_own).attr("id", $(remove_own).attr("id").replace("remove-flag-", "flag-"));
+
+ $(object).next("span.sep").remove();
+ $(object).remove();
+
+
+
+ getOffensiveQuestionFlag().unbind('click').click(function(event){
+ Vote.offensive(this, VoteType.offensiveQuestion);
+ });
+
+ getOffensiveAnswerFlags().unbind('click').click(function(event){
+ Vote.offensive(this, VoteType.offensiveAnswer);
+ });
+ }
+ else {
+ object = $(object);
+ showMessage(object, data.message)
+ }
+ };
+
+ var callback_remove = function(object, voteType, data){
+ if (data.success == "1"){
+ if (removeActionType == 'delete'){
+ postNode.addClass('deleted');
+ postRemoveLink.innerHTML = gettext('undelete');
+ showMessage(object, deletedMessage);
+ }
+ else if (removeActionType == 'undelete') {
+ postNode.removeClass('deleted');
+ postRemoveLink.innerHTML = gettext('delete');
+ showMessage(object, recoveredMessage);
+ }
+ }
+ else {
+ showMessage(object, data.message)
+ }
+ };
+
+ return {
+ init : function(qId, qSlug, questionAuthor, userId){
+ questionId = qId;
+ questionSlug = qSlug;
+ questionAuthorId = questionAuthor;
+ currentUserId = userId;
+ bindEvents();
+ },
+
+ //accept answer
+ accept: function(object){
+ postId = object.attr("id").substring(imgIdPrefixAccept.length);
+ submit(object, VoteType.acceptAnswer, callback_accept);
+ },
+ //mark question as favorite
+ favorite: function(object){
+ if (!currentUserId || currentUserId.toUpperCase() == "NONE"){
+ showMessage(
+ object,
+ favoriteAnonymousMessage.replace(
+ "{{QuestionID}}",
+ questionId
+ ).replace(
+ '{{questionSlug}}',
+ questionSlug
+ )
+ );
+ return false;
+ }
+ submit(object, VoteType.favorite, callback_favorite);
+ },
+
+ vote: function(object, voteType){
+ if (!currentUserId || currentUserId.toUpperCase() == "NONE"){
+ if (voteType == VoteType.questionSubscribeUpdates || voteType == VoteType.questionUnsubscribeUpdates){
+ getquestionSubscribeSidebarCheckbox().removeAttr('checked');
+ getquestionSubscribeUpdatesCheckbox().removeAttr('checked');
+ showMessage(object, subscribeAnonymousMessage);
+ }else {
+ showMessage(
+ $(object),
+ voteAnonymousMessage.replace(
+ "{{QuestionID}}",
+ questionId
+ ).replace(
+ '{{questionSlug}}',
+ questionSlug
+ )
+ );
+ }
+ return false;
+ }
+ // up and downvote processor
+ if (voteType == VoteType.answerUpVote){
+ postId = object.attr("id").substring(imgIdPrefixAnswerVoteup.length);
+ }
+ else if (voteType == VoteType.answerDownVote){
+ postId = object.attr("id").substring(imgIdPrefixAnswerVotedown.length);
+ }
+
+ submit(object, voteType, callback_vote);
+ },
+ //flag offensive
+ offensive: function(object, voteType){
+ if (!currentUserId || currentUserId.toUpperCase() == "NONE"){
+ showMessage(
+ $(object),
+ offensiveAnonymousMessage.replace(
+ "{{QuestionID}}",
+ questionId
+ ).replace(
+ '{{questionSlug}}',
+ questionSlug
+ )
+ );
+ return false;
+ }
+ if (confirm(offensiveConfirmation)){
+ postId = object.id.substr(object.id.lastIndexOf('-') + 1);
+ submit(object, voteType, callback_offensive);
+ }
+ },
+ //remove flag offensive
+ remove_offensive: function(object, voteType){
+ if (!currentUserId || currentUserId.toUpperCase() == "NONE"){
+ showMessage(
+ $(object),
+ offensiveAnonymousMessage.replace(
+ "{{QuestionID}}",
+ questionId
+ ).replace(
+ '{{questionSlug}}',
+ questionSlug
+ )
+ );
+ return false;
+ }
+ if (confirm(removeOffensiveConfirmation)){
+ postId = object.id.substr(object.id.lastIndexOf('-') + 1);
+ submit(object, voteType, callback_remove_offensive);
+ }
+ },
+ remove_all_offensive: function(object, voteType){
+ if (!currentUserId || currentUserId.toUpperCase() == "NONE"){
+ showMessage(
+ $(object),
+ offensiveAnonymousMessage.replace(
+ "{{QuestionID}}",
+ questionId
+ ).replace(
+ '{{questionSlug}}',
+ questionSlug
+ )
+ );
+ return false;
+ }
+ if (confirm(removeOffensiveConfirmation)){
+ postId = object.id.substr(object.id.lastIndexOf('-') + 1);
+ submit(object, voteType, callback_remove_all_offensive);
+ }
+ },
+ //delete question or answer (comments are deleted separately)
+ remove: function(object, voteType){
+ if (!currentUserId || currentUserId.toUpperCase() == "NONE"){
+ showMessage(
+ $(object),
+ removeAnonymousMessage.replace(
+ '{{QuestionID}}',
+ questionId
+ ).replace(
+ '{{questionSlug}}',
+ questionSlug
+ )
+ );
+ return false;
+ }
+ bits = object.id.split('-');
+ postId = bits.pop();/* this seems to be used within submit! */
+ postType = bits.shift();
+
+ var do_proceed = false;
+ if (postType == 'answer'){
+ postNode = $('#post-id-' + postId);
+ }
+ else if (postType == 'question'){
+ postNode = $('#question-table');
+ }
+ postRemoveLink = object;
+ if (postNode.hasClass('deleted')){
+ removeActionType = 'undelete';
+ do_proceed = true;
+ }
+ else {
+ removeActionType = 'delete';
+ do_proceed = confirm(removeConfirmation);
+ }
+ if (do_proceed) {
+ submit($(object), voteType, callback_remove);
+ }
+ }
+ };
+} ();
+
+var questionRetagger = function(){
+
+ var oldTagsHTML = '';
+ var tagInput = null;
+ var tagsDiv = null;
+ var retagLink = null;
+
+ var restoreEventHandlers = function(){
+ $(document).unbind('click');
+ };
+
+ var cancelRetag = function(){
+ tagsDiv.html(oldTagsHTML);
+ tagsDiv.removeClass('post-retag');
+ tagsDiv.addClass('post-tags');
+ restoreEventHandlers();
+ initRetagger();
+ };
+
+ var drawNewTags = function(new_tags){
+ tagsDiv.empty();
+ if (new_tags === ''){
+ return;
+ }
+ new_tags = new_tags.split(/\s+/);
+ var tags_html = ''
+ $.each(new_tags, function(index, name){
+ var tag = new Tag();
+ tag.setName(name);
+ tagsDiv.append(tag.getElement());
+ });
+ };
+
+ var doRetag = function(){
+ $.ajax({
+ type: "POST",
+ url: retagUrl,//todo add this url to askbot['urls']
+ dataType: "json",
+ data: { tags: getUniqueWords(tagInput.val()).join(' ') },
+ success: function(json) {
+ if (json['success'] === true){
+ new_tags = getUniqueWords(json['new_tags']);
+ oldTagsHtml = '';
+ cancelRetag();
+ drawNewTags(new_tags.join(' '));
+ if (json['message']) {
+ notify.show(json['message']);
+ }
+ }
+ else {
+ cancelRetag();
+ showMessage(tagsDiv, json['message']);
+ }
+ },
+ error: function(xhr, textStatus, errorThrown) {
+ showMessage(tagsDiv, 'sorry, something is not right here');
+ cancelRetag();
+ }
+ });
+ return false;
+ }
+
+ var setupInputEventHandlers = function(input){
+ input.keydown(function(e){
+ if ((e.which && e.which == 27) || (e.keyCode && e.keyCode == 27)){
+ cancelRetag();
+ }
+ });
+ $(document).unbind('click').click(cancelRetag, false);
+ input.click(function(){return false});
+ };
+
+ var createRetagForm = function(old_tags_string){
+ var div = $('<form method="post"></form>');
+ tagInput = $('<input id="retag_tags" type="text" autocomplete="off" name="tags" size="30"/>');
+ //var tagLabel = $('<label for="retag_tags" class="error"></label>');
+ //populate input
+ var tagAc = new AutoCompleter({
+ url: askbot['urls']['get_tag_list'],
+ preloadData: true,
+ minChars: 1,
+ useCache: true,
+ matchInside: true,
+ maxCacheLength: 100,
+ delay: 10
+ });
+ tagAc.decorate(tagInput);
+ tagInput.val(old_tags_string);
+ div.append(tagInput);
+ //div.append(tagLabel);
+ setupInputEventHandlers(tagInput);
+
+ //button = $('<input type="submit" />');
+ //button.val(gettext('save tags'));
+ //div.append(button);
+ //setupButtonEventHandlers(button);
+ div.validate({//copy-paste from utils.js
+ rules: {
+ tags: {
+ required: askbot['settings']['tagsAreRequired'],
+ maxlength: askbot['settings']['maxTagsPerPost'] * askbot['settings']['maxTagLength'],
+ limit_tag_count: true,
+ limit_tag_length: true
+ }
+ },
+ messages: {
+ tags: {
+ required: gettext('tags cannot be empty'),
+ maxlength: askbot['messages']['tagLimits'],
+ limit_tag_count: askbot['messages']['maxTagsPerPost'],
+ limit_tag_length: askbot['messages']['maxTagLength']
+ }
+ },
+ submitHandler: doRetag,
+ errorClass: "retag-error"
+ });
+
+ return div;
+ };
+
+ var getTagsAsString = function(tags_div){
+ var links = tags_div.find('a');
+ var tags_str = '';
+ links.each(function(index, element){
+ if (index === 0){
+ //this is pretty bad - we should use Tag.getName()
+ tags_str = $(element).data('tagName');
+ }
+ else {
+ tags_str += ' ' + $(element).data('tagName');
+ }
+ });
+ return tags_str;
+ };
+
+ var noopHandler = function(){
+ tagInput.focus();
+ return false;
+ };
+
+ var deactivateRetagLink = function(){
+ retagLink.unbind('click').click(noopHandler);
+ retagLink.unbind('keypress').keypress(noopHandler);
+ };
+
+ var startRetag = function(){
+ tagsDiv = $('#question-tags');
+ oldTagsHTML = tagsDiv.html();//save to restore on cancel
+ var old_tags_string = getTagsAsString(tagsDiv);
+ var retag_form = createRetagForm(old_tags_string);
+ tagsDiv.html('');
+ tagsDiv.append(retag_form);
+ tagsDiv.removeClass('post-tags');
+ tagsDiv.addClass('post-retag');
+ tagInput.focus();
+ deactivateRetagLink();
+ return false;
+ };
+
+ var setupClickAndEnterHandler = function(element, callback){
+ element.unbind('click').click(callback);
+ element.unbind('keypress').keypress(function(e){
+ if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)){
+ callback();
+ }
+ });
+ }
+
+ var initRetagger = function(){
+ setupClickAndEnterHandler(retagLink, startRetag);
+ };
+
+ return {
+ init: function(){
+ retagLink = $('#retag');
+ initRetagger();
+ }
+ };
+}();
+
+var DeletePostLink = function(){
+ SimpleControl.call(this);
+ this._post_id = null;
+};
+inherits(DeletePostLink, SimpleControl);
+
+DeletePostLink.prototype.setPostId = function(id){
+ this._post_id = id;
+};
+
+DeletePostLink.prototype.getPostId = function(){
+ return this._post_id;
+};
+
+DeletePostLink.prototype.getPostElement = function(){
+ return $('#post-id-' + this.getPostId());
+};
+
+DeletePostLink.prototype.isPostDeleted = function(){
+ return this._post_deleted;
+};
+
+DeletePostLink.prototype.setPostDeleted = function(is_deleted){
+ var post = this.getPostElement();
+ if (is_deleted === true){
+ post.addClass('deleted');
+ this._post_deleted = true;
+ this.getElement().html(gettext('undelete'));
+ } else if (is_deleted === false){
+ post.removeClass('deleted');
+ this._post_deleted = false;
+ this.getElement().html(gettext('delete'));
+ }
+};
+
+DeletePostLink.prototype.getDeleteHandler = function(){
+ var me = this;
+ var post_id = this.getPostId();
+ return function(){
+ var data = {
+ 'post_id': me.getPostId(),
+ //todo rename cancel_vote -> undo
+ 'cancel_vote': me.isPostDeleted() ? true: false
+ };
+ $.ajax({
+ type: 'POST',
+ data: data,
+ dataType: 'json',
+ url: askbot['urls']['delete_post'],
+ cache: false,
+ success: function(data){
+ if (data['success'] == true){
+ me.setPostDeleted(data['is_deleted']);
+ } else {
+ showMessage(me.getElement(), data['message']);
+ }
+ }
+ });
+ };
+};
+
+DeletePostLink.prototype.decorate = function(element){
+ this._element = element;
+ this._post_deleted = this.getPostElement().hasClass('deleted');
+ this.setHandler(this.getDeleteHandler());
+}
+
+//constructor for the form
+var EditCommentForm = function(){
+ WrappedElement.call(this);
+ this._comment = null;
+ this._comment_widget = null;
+ this._element = null;
+ this._text = '';
+ this._id = 'edit-comment-form';
+};
+inherits(EditCommentForm, WrappedElement);
+
+EditCommentForm.prototype.getElement = function(){
+ EditCommentForm.superClass_.getElement.call(this);
+ this._textarea.val(this._text);
+ return this._element;
+};
+
+EditCommentForm.prototype.attachTo = function(comment, mode){
+ this._comment = comment;
+ this._type = mode;
+ this._comment_widget = comment.getContainerWidget();
+ this._text = comment.getText();
+ comment.getElement().after(this.getElement());
+ comment.getElement().hide();
+ this._comment_widget.hideButton();
+ if (this._type == 'add'){
+ this._submit_btn.html(gettext('add comment'));
+ }
+ else {
+ this._submit_btn.html(gettext('save comment'));
+ }
+ this.getElement().show();
+ this.enableButtons();
+ this.focus();
+ putCursorAtEnd(this._textarea);
+};
+
+EditCommentForm.prototype.getCounterUpdater = function(){
+ //returns event handler
+ var counter = this._text_counter;
+ var handler = function(){
+ var textarea = $(this);
+ var length = textarea.val() ? textarea.val().length : 0;
+ var length1 = maxCommentLength - 100;
+ if (length1 < 0){
+ length1 = Math.round(0.7*maxCommentLength);
+ }
+ var length2 = maxCommentLength - 30;
+ if (length2 < 0){
+ length2 = Math.round(0.9*maxCommentLength);
+ }
+
+ //todo:
+ //1) use class instead of color - move color def to css
+ var color = 'maroon';
+ var chars = 10;
+ if (length === 0){
+ var feedback = interpolate(gettext('%s title minchars'), [chars]);
+ }
+ else if (length < 10){
+ var feedback = interpolate(gettext('enter %s more characters'), [chars - length]);
+ }
+ else {
+ color = length > length2 ? "#f00" : length > length1 ? "#f60" : "#999"
+ chars = maxCommentLength - length
+ var feedback = interpolate(gettext('%s characters left'), [chars])
+ }
+ counter.html(feedback).css('color', color)
+ };
+ return handler;
+};
+
+EditCommentForm.prototype.canCancel = function(){
+ if (this._element === null){
+ return true;
+ }
+ var ctext = $.trim(this._textarea.val());
+ if ($.trim(ctext) == $.trim(this._text)){
+ return true;
+ }
+ else if (this.confirmAbandon()){
+ return true;
+ }
+ this.focus();
+ return false;
+};
+
+EditCommentForm.prototype.getCancelHandler = function(){
+ var form = this;
+ return function(){
+ if (form.canCancel()){
+ form.detach();
+ }
+ return false;
+ };
+};
+
+EditCommentForm.prototype.detach = function(){
+ if (this._comment === null){
+ return;
+ }
+ this._comment.getContainerWidget().showButton();
+ if (this._comment.isBlank()){
+ this._comment.dispose();
+ }
+ else {
+ this._comment.getElement().show();
+ }
+ this.reset();
+ this._element = this._element.detach();
+};
+
+EditCommentForm.prototype.createDom = function(){
+ this._element = $('<form></form>');
+ this._element.attr('class', 'post-comments');
+
+ var div = $('<div></div>');
+ this._textarea = $('<textarea></textarea>');
+ this._textarea.attr('id', this._id);
+
+ /*
+ this._help_text = $('<span></span>').attr('class', 'help-text');
+ this._help_text.html(gettext('Markdown is allowed in the comments'));
+ div.append(this._help_text);
+
+ this._help_text = $('<div></div>').attr('class', 'clearfix');
+ div.append(this._help_text);
+ */
+
+ this._element.append(div);
+ div.append(this._textarea);
+ this._text_counter = $('<span></span>').attr('class', 'counter');
+ div.append(this._text_counter);
+ this._submit_btn = $('<button class="submit small"></button>');
+ div.append(this._submit_btn);
+ this._cancel_btn = $('<button class="submit small"></button>');
+ this._cancel_btn.html(gettext('cancel'));
+ div.append(this._cancel_btn);
+
+ setupButtonEventHandlers(this._submit_btn, this.getSaveHandler());
+ setupButtonEventHandlers(this._cancel_btn, this.getCancelHandler());
+
+ var update_counter = this.getCounterUpdater();
+ var escape_handler = makeKeyHandler(27, this.getCancelHandler());
+ this._textarea.attr('name', 'comment')
+ .attr('cols', 60)
+ .attr('rows', 5)
+ .attr('maxlength', maxCommentLength)
+ .blur(update_counter)
+ .focus(update_counter)
+ .keyup(update_counter)
+ .keyup(escape_handler);
+ if (askbot['settings']['saveCommentOnEnter']){
+ var save_handler = makeKeyHandler(13, this.getSaveHandler());
+ this._textarea.keydown(save_handler);
+ }
+ this._textarea.val(this._text);
+};
+
+EditCommentForm.prototype.enableButtons = function(){
+ this._submit_btn.attr('disabled', false);
+ this._cancel_btn.attr('disabled', false);
+};
+
+EditCommentForm.prototype.disableButtons = function(){
+ this._submit_btn.attr('disabled', true);
+ this._cancel_btn.attr('disabled', true);
+};
+
+EditCommentForm.prototype.reset = function(){
+ this._comment = null;
+ this._text = '';
+ this._textarea.val('');
+ this.enableButtons();
+};
+
+EditCommentForm.prototype.confirmAbandon = function(){
+ this.focus(true);
+ this._textarea.addClass('highlight');
+ var answer = confirm(gettext('confirm abandon comment'));
+ this._textarea.removeClass('highlight');
+ return answer;
+};
+
+EditCommentForm.prototype.focus = function(hard){
+ this._textarea.focus();
+ if (hard === true){
+ $(this._textarea).scrollTop();
+ }
+};
+
+EditCommentForm.prototype.getSaveHandler = function(){
+
+ var me = this;
+ return function(){
+ var text = me._textarea.val();
+ if (text.length < 10){
+ me.focus();
+ return false;
+ }
+
+ var post_data = {
+ comment: text
+ };
+
+ if (me._type == 'edit'){
+ post_data['comment_id'] = me._comment.getId();
+ post_url = askbot['urls']['editComment'];
+ }
+ else {
+ post_data['post_type'] = me._comment.getParentType();
+ post_data['post_id'] = me._comment.getParentId();
+ post_url = askbot['urls']['postComments'];
+ }
+
+ me.disableButtons();
+
+ $.ajax({
+ type: "POST",
+ url: post_url,
+ dataType: "json",
+ data: post_data,
+ success: function(json) {
+ if (me._type == 'add'){
+ me._comment.dispose();
+ me._comment.getContainerWidget().reRenderComments(json);
+ }
+ else {
+ me._comment.setContent(json);
+ me._comment.getElement().show();
+ }
+ me.detach();
+ },
+ error: function(xhr, textStatus, errorThrown) {
+ me._comment.getElement().show();
+ showMessage(me._comment.getElement(), xhr.responseText, 'after');
+ me.detach();
+ me.enableButtons();
+ }
+ });
+ return false;
+ };
+};
+
+//a single instance to reuse
+var editCommentForm = new EditCommentForm();
+
+var Comment = function(widget, data){
+ WrappedElement.call(this);
+ this._container_widget = widget;
+ this._data = data || {};
+ this._blank = true;//set to false by setContent
+ this._element = null;
+ this._is_convertible = askbot['data']['userIsAdminOrMod'];
+ this.convert_link = null;
+ this._delete_prompt = gettext('delete this comment');
+ if (data && data['is_deletable']){
+ this._deletable = data['is_deletable'];
+ }
+ else {
+ this._deletable = false;
+ }
+ if (data && data['is_editable']){
+ this._editable = data['is_deletable'];
+ }
+ else {
+ this._editable = false;
+ }
+};
+inherits(Comment, WrappedElement);
+
+Comment.prototype.decorate = function(element){
+ this._element = $(element);
+ var parent_type = this._element.parent().parent().attr('id').split('-')[2];
+ var comment_id = this._element.attr('id').replace('comment-','');
+ this._data = {id: comment_id};
+ var delete_img = this._element.find('span.delete-icon');
+ if (delete_img.length > 0){
+ this._deletable = true;
+ this._delete_icon = new DeleteIcon(this.deletePrompt);
+ this._delete_icon.setHandler(this.getDeleteHandler());
+ this._delete_icon.decorate(delete_img);
+ }
+ var edit_link = this._element.find('a.edit');
+ if (edit_link.length > 0){
+ this._editable = true;
+ this._edit_link = new EditLink();
+ this._edit_link.setHandler(this.getEditHandler());
+ this._edit_link.decorate(edit_link);
+ }
+
+ var convert_link = this._element.find('form.convert-comment');
+ if (this._is_convertible){
+ this._convert_link = new CommentConvertLink(comment_id);
+ this._convert_link.decorate(convert_link);
+ }
+
+ var vote = new CommentVoteButton(this);
+ vote.decorate(this._element.find('.comment-votes .upvote'));
+
+ this._blank = false;
+};
+
+Comment.prototype.isBlank = function(){
+ return this._blank;
+};
+
+Comment.prototype.getId = function(){
+ return this._data['id'];
+};
+
+Comment.prototype.hasContent = function(){
+ return ('id' in this._data);
+ //shortcut for 'user_url' 'html' 'user_display_name' 'comment_age'
+};
+
+Comment.prototype.hasText = function(){
+ return ('text' in this._data);
+}
+
+Comment.prototype.getContainerWidget = function(){
+ return this._container_widget;
+};
+
+Comment.prototype.getParentType = function(){
+ return this._container_widget.getPostType();
+};
+
+Comment.prototype.getParentId = function(){
+ return this._container_widget.getPostId();
+};
+
+Comment.prototype.setContent = function(data){
+ this._data = data || this._data;
+ this._element.html('');
+ this._element.attr('class', 'comment');
+ this._element.attr('id', 'comment-' + this._data['id']);
+
+ var votes = this.makeElement('div');
+ votes.addClass('comment-votes');
+
+ var vote = new CommentVoteButton(this);
+ if (this._data['upvoted_by_user']){
+ vote.setVoted(true);
+ }
+ vote.setScore(this._data['score']);
+ votes.append(vote.getElement());
+
+ this._element.append(votes);
+
+ this._comment_delete = $('<div class="comment-delete"></div>');
+ if (this._deletable){
+ this._delete_icon = new DeleteIcon(this._delete_prompt);
+ this._delete_icon.setHandler(this.getDeleteHandler());
+ this._comment_delete.append(this._delete_icon.getElement());
+ }
+ this._element.append(this._comment_delete);
+
+ this._comment_body = $('<div class="comment-body"></div>');
+ this._comment_body.html(this._data['html']);
+ //this._comment_body.append(' &ndash; ');
+
+ this._user_link = $('<a></a>').attr('class', 'author');
+ this._user_link.attr('href', this._data['user_url']);
+ this._user_link.html(this._data['user_display_name']);
+ this._comment_body.append(this._user_link);
+
+ this._comment_body.append(' (');
+ this._comment_added_at = $('<abbr class="timeago"></abbr>');
+ this._comment_added_at.html(this._data['comment_added_at']);
+ this._comment_added_at.attr('title', this._data['comment_added_at']);
+ this._comment_added_at.timeago();
+ this._comment_body.append(this._comment_added_at);
+ this._comment_body.append(')');
+
+ if (this._editable){
+ this._edit_link = new EditLink();
+ this._edit_link.setHandler(this.getEditHandler())
+ this._comment_body.append(this._edit_link.getElement());
+ }
+
+ if (this._is_convertible){
+ this._convert_link = new CommentConvertLink(this._data['id']);
+ this._comment_body.append(this._convert_link.getElement());
+ }
+ this._element.append(this._comment_body);
+
+ this._blank = false;
+};
+
+Comment.prototype.dispose = function(){
+ if (this._comment_body){
+ this._comment_body.remove();
+ }
+ if (this._comment_delete){
+ this._comment_delete.remove();
+ }
+ if (this._user_link){
+ this._user_link.remove();
+ }
+ if (this._comment_added_at){
+ this._comment_added_at.remove();
+ }
+ if (this._delete_icon){
+ this._delete_icon.dispose();
+ }
+ if (this._edit_link){
+ this._edit_link.dispose();
+ }
+ if (this._convert_link){
+ this._convert_link.dispose();
+ }
+ this._data = null;
+ Comment.superClass_.dispose.call(this);
+};
+
+Comment.prototype.getElement = function(){
+ Comment.superClass_.getElement.call(this);
+ if (this.isBlank() && this.hasContent()){
+ this.setContent();
+ if (enableMathJax === true){
+ MathJax.Hub.Queue(['Typeset', MathJax.Hub]);
+ }
+ }
+ return this._element;
+};
+
+Comment.prototype.loadText = function(on_load_handler){
+ var me = this;
+ $.ajax({
+ type: "GET",
+ url: askbot['urls']['getComment'],
+ data: {id: this._data['id']},
+ success: function(json){
+ me._data['text'] = json['text'];
+ on_load_handler()
+ },
+ error: function(xhr, textStatus, exception) {
+ showMessage(me.getElement(), xhr.responseText, 'after');
+ }
+ });
+};
+
+Comment.prototype.getText = function(){
+ if (!this.isBlank()){
+ if ('text' in this._data){
+ return this._data['text'];
+ }
+ }
+ return '';
+}
+
+Comment.prototype.getEditHandler = function(){
+ var comment = this;
+ return function(){
+ if (editCommentForm.canCancel()){
+ editCommentForm.detach();
+ if (comment.hasText()){
+ editCommentForm.attachTo(comment, 'edit');
+ }
+ else {
+ comment.loadText(
+ function(){
+ editCommentForm.attachTo(comment, 'edit');
+ }
+ );
+ }
+ }
+ };
+};
+
+Comment.prototype.getDeleteHandler = function(){
+ var comment = this;
+ var del_icon = this._delete_icon;
+ return function(){
+ if (confirm(gettext('confirm delete comment'))){
+ comment.getElement().hide();
+ $.ajax({
+ type: 'POST',
+ url: askbot['urls']['deleteComment'],
+ data: { comment_id: comment.getId() },
+ success: function(json, textStatus, xhr) {
+ comment.dispose();
+ },
+ error: function(xhr, textStatus, exception) {
+ comment.getElement().show()
+ showMessage(del_icon.getElement(), xhr.responseText);
+ },
+ dataType: "json"
+ });
+ }
+ };
+};
+
+var PostCommentsWidget = function(){
+ WrappedElement.call(this);
+ this._denied = false;
+};
+inherits(PostCommentsWidget, WrappedElement);
+
+PostCommentsWidget.prototype.decorate = function(element){
+ var element = $(element);
+ this._element = element;
+
+ var widget_id = element.attr('id');
+ var id_bits = widget_id.split('-');
+ this._post_id = id_bits[3];
+ this._post_type = id_bits[2];
+ this._is_truncated = askbot['data'][widget_id]['truncated'];
+ this._user_can_post = askbot['data'][widget_id]['can_post'];
+
+ //see if user can comment here
+ var controls = element.find('.controls');
+ this._activate_button = controls.find('.button');
+
+ if (this._user_can_post == false){
+ setupButtonEventHandlers(
+ this._activate_button,
+ this.getReadOnlyLoadHandler()
+ );
+ }
+ else {
+ setupButtonEventHandlers(
+ this._activate_button,
+ this.getActivateHandler()
+ );
+ }
+
+ this._cbox = element.find('.content');
+ var comments = new Array();
+ var me = this;
+ this._cbox.children('.comment').each(function(index, element){
+ var comment = new Comment(me);
+ comments.push(comment)
+ comment.decorate(element);
+ });
+ this._comments = comments;
+};
+
+PostCommentsWidget.prototype.getPostType = function(){
+ return this._post_type;
+};
+
+PostCommentsWidget.prototype.getPostId = function(){
+ return this._post_id;
+};
+
+PostCommentsWidget.prototype.hideButton = function(){
+ this._activate_button.hide();
+};
+
+PostCommentsWidget.prototype.showButton = function(){
+ if (this._is_truncated === false){
+ this._activate_button.html(askbot['messages']['addComment']);
+ }
+ this._activate_button.show();
+}
+
+PostCommentsWidget.prototype.startNewComment = function(){
+ var comment = new Comment(this);
+ this._cbox.append(comment.getElement());
+ editCommentForm.attachTo(comment, 'add');
+};
+
+PostCommentsWidget.prototype.needToReload = function(){
+ return this._is_truncated;
+};
+
+PostCommentsWidget.prototype.getActivateHandler = function(){
+ var me = this;
+ return function() {
+ if (editCommentForm.canCancel()){
+ editCommentForm.detach();
+ if (me.needToReload()){
+ me.reloadAllComments(function(json){
+ me.reRenderComments(json);
+ me.startNewComment();
+ });
+ }
+ else {
+ me.startNewComment();
+ }
+ }
+ };
+};
+
+PostCommentsWidget.prototype.getReadOnlyLoadHandler = function(){
+ var me = this;
+ return function(){
+ me.reloadAllComments(function(json){
+ me.reRenderComments(json);
+ me._activate_button.remove();
+ });
+ };
+};
+
+
+PostCommentsWidget.prototype.reloadAllComments = function(callback){
+ var post_data = {post_id: this._post_id, post_type: this._post_type};
+ var me = this;
+ $.ajax({
+ type: "GET",
+ url: askbot['urls']['postComments'],
+ data: post_data,
+ success: function(json){
+ callback(json);
+ me._is_truncated = false;
+ },
+ dataType: "json"
+ });
+};
+
+PostCommentsWidget.prototype.reRenderComments = function(json){
+ $.each(this._comments, function(i, item){
+ item.dispose();
+ });
+ this._comments = new Array();
+ var me = this;
+ $.each(json, function(i, item){
+ var comment = new Comment(me, item);
+ me._cbox.append(comment.getElement());
+ me._comments.push(comment);
+ });
+};
+
+
+var socialSharing = function(){
+
+ var SERVICE_DATA = {
+ //url - template for the sharing service url, params are for the popup
+ identica: {
+ url: "http://identi.ca/notice/new?status_textarea={TEXT}%20{URL}",
+ params: "width=820, height=526,toolbar=1,status=1,resizable=1,scrollbars=1"
+ },
+ twitter: {
+ url: "http://twitter.com/share?url={URL}&ref=twitbtn&text={TEXT}",
+ params: "width=820,height=526,toolbar=1,status=1,resizable=1,scrollbars=1"
+ },
+ facebook: {
+ url: "http://www.facebook.com/sharer.php?u={URL}&ref=fbshare&t={TEXT}",
+ params: "width=630,height=436,toolbar=1,status=1,resizable=1,scrollbars=1"
+ },
+ linkedin: {
+ url: "http://www.linkedin.com/shareArticle?mini=true&url={URL}&title={TEXT}",
+ params: "width=630,height=436,toolbar=1,status=1,resizable=1,scrollbars=1"
+ }
+ };
+ var URL = "";
+ var TEXT = "";
+
+ var share_page = function(service_name){
+ if (SERVICE_DATA[service_name]){
+ var url = SERVICE_DATA[service_name]['url'];
+ $.ajax({
+ async: false,
+ url: "http://json-tinyurl.appspot.com/?&callback=?",
+ dataType: "json",
+ data: {'url':URL},
+ success: function(data){
+ url = url.replace('{URL}', data.tinyurl);
+ },
+ error: function(data){
+ url = url.replace('{URL}', URL);
+ },
+ complete: function(data){
+ url = url.replace('{TEXT}', TEXT);
+ var params = SERVICE_DATA[service_name]['params'];
+ if(!window.open(url, "sharing", params)){
+ window.location.href=url;
+ }
+ }
+ });
+ }
+ }
+
+ return {
+ init: function(){
+ URL = window.location.href;
+ TEXT = escape($('h1 > a').html());
+ var fb = $('a.facebook-share')
+ var tw = $('a.twitter-share');
+ var ln = $('a.linkedin-share');
+ var ica = $('a.identica-share');
+ copyAltToTitle(fb);
+ copyAltToTitle(tw);
+ copyAltToTitle(ln);
+ copyAltToTitle(ica);
+ setupButtonEventHandlers(fb, function(){share_page("facebook")});
+ setupButtonEventHandlers(tw, function(){share_page("twitter")});
+ setupButtonEventHandlers(ln, function(){share_page("linkedin")});
+ setupButtonEventHandlers(ica, function(){share_page("identica")});
+ }
+ }
+}();
+
+/**
+ * @constructor
+ * @extends {SimpleControl}
+ */
+var QASwapper = function(){
+ SimpleControl.call(this);
+ this._ans_id = null;
+};
+inherits(QASwapper, SimpleControl);
+
+QASwapper.prototype.decorate = function(element){
+ this._element = element;
+ this._ans_id = parseInt(element.attr('id').split('-').pop());
+ var me = this;
+ this.setHandler(function(){
+ me.startSwapping();
+ });
+};
+
+QASwapper.prototype.startSwapping = function(){
+ while (true){
+ var title = prompt(gettext('Please enter question title (>10 characters)'));
+ if (title.length >= 10){
+ var data = {new_title: title, answer_id: this._ans_id};
+ $.ajax({
+ type: "POST",
+ cache: false,
+ dataType: "json",
+ url: askbot['urls']['swap_question_with_answer'],
+ data: data,
+ success: function(data){
+ var url_template = askbot['urls']['question_url_template'];
+ new_question_url = url_template.replace(
+ '{{QuestionID}}',
+ data['id']
+ ).replace(
+ '{{questionSlug}}',
+ data['slug']
+ );
+ window.location.href = new_question_url;
+ }
+ });
+ break;
+ }
+ }
+};
+
+/**
+ * @constructor
+ */
+var WMD = function(){
+ WrappedElement.call(this);
+ this._text = undefined;
+ this._enabled_buttons = 'bold italic link blockquote code ' +
+ 'image attachment ol ul heading hr';
+ this._is_previewer_enabled = true;
+};
+inherits(WMD, WrappedElement);
+
+WMD.prototype.setEnabledButtons = function(buttons){
+ this._enabled_buttons = buttons;
+};
+
+WMD.prototype.setPreviewerEnabled = function(state){
+ this._is_previewer_enabled = state;
+ if (this._previewer){
+ this._previewer.hide();
+ }
+};
+
+WMD.prototype.createDom = function(){
+ this._element = this.makeElement('div');
+ var clearfix = this.makeElement('div').addClass('clearfix');
+ this._element.append(clearfix);
+
+ var wmd_container = this.makeElement('div');
+ wmd_container.addClass('wmd-container');
+ this._element.append(wmd_container);
+
+ var wmd_buttons = this.makeElement('div')
+ .attr('id', 'wmd-button-bar')
+ .addClass('wmd-panel');
+ wmd_container.append(wmd_buttons);
+
+ var editor = this.makeElement('textarea')
+ .attr('id', 'editor');
+ wmd_container.append(editor);
+ this._textarea = editor;
+
+ if (this._markdown){
+ editor.val(this._markdown);
+ }
+
+ var previewer = this.makeElement('div')
+ .attr('id', 'previewer')
+ .addClass('wmd-preview');
+ wmd_container.append(previewer);
+ this._previewer = previewer;
+ if (this._is_previewer_enabled === false) {
+ previewer.hide();
+ }
+};
+
+WMD.prototype.setText = function(text){
+ this._markdown = text;
+ if (this._textarea){
+ this._textarea.val(text);
+ }
+};
+
+WMD.prototype.getText = function(){
+ return this._textarea.val();
+};
+
+WMD.prototype.start = function(){
+ Attacklab.Util.startEditor(true, this._enabled_buttons);
+};
+
+/**
+ * @constructor
+ */
+var TinyMCE = function(config) {
+ WrappedElement.call(this);
+ this._config = config || {};
+};
+inherits(TinyMCE, WrappedElement);
+
+/* 3 dummy functions to match WMD api */
+TinyMCE.prototype.setEnabledButtons = function() {};
+TinyMCE.prototype.start = function() {
+ this.loadEditor();
+};
+TinyMCE.prototype.setPreviewerEnabled = function() {};
+
+TinyMCE.prototype.setText = function(text) {
+ this._text = text;
+};
+
+TinyMCE.prototype.getText = function() {
+ return tinyMCE.activeEditor.getContent();
+};
+
+TinyMCE.prototype.loadEditor = function() {
+ var config = JSON.stringify(this._config);
+ var data = {config: config};
+ var editorBox = this._element;
+ var me = this;
+ $.ajax({
+ async: false,
+ type: 'GET',
+ dataType: 'json',
+ cache: false,
+ url: askbot['urls']['getEditor'],
+ data: data,
+ success: function(data) {
+ if (data['success']) {
+ editorBox.html(data['html']);
+ editorBox.find('textarea').val(me._text);//@todo: fixme
+ $.each(data['scripts'], function(idx, scriptData) {
+ var scriptElement = me.makeElement('script');
+ scriptElement.attr('type', 'text/javascript');
+ if (scriptData['src']) {
+ scriptElement.attr('src', scriptData['src']);
+ }
+ if (scriptData['contents']) {
+ scriptElement.html(scriptData['contents']);
+ }
+ $('head').append(scriptElement);
+ });
+ }
+ }
+ });
+};
+
+TinyMCE.prototype.createDom = function() {
+ var editorBox = this.makeElement('div');
+ editorBox.addClass('wmd-container');
+ this._element = editorBox;
+};
+
+/**
+ * @constructor
+ * @todo: change this to generic object description editor
+ */
+var TagWikiEditor = function(){
+ WrappedElement.call(this);
+ this._state = 'display';//'edit' or 'display'
+ this._content_backup = '';
+ this._is_editor_loaded = false;
+ this._enabled_editor_buttons = null;
+ this._is_previewer_enabled = false;
+};
+inherits(TagWikiEditor, WrappedElement);
+
+TagWikiEditor.prototype.backupContent = function(){
+ this._content_backup = this._content_box.contents();
+};
+
+TagWikiEditor.prototype.setEnabledEditorButtons = function(buttons){
+ this._enabled_editor_buttons = buttons;
+};
+
+TagWikiEditor.prototype.setPreviewerEnabled = function(state){
+ this._is_previewer_enabled = state;
+ if (this.isEditorLoaded()){
+ this._editor.setPreviewerEnabled(this._is_previewer_enabled);
+ }
+};
+
+TagWikiEditor.prototype.setContent = function(content){
+ this._content_box.empty();
+ this._content_box.append(content);
+};
+
+TagWikiEditor.prototype.setState = function(state){
+ if (state === 'edit'){
+ this._state = state;
+ this._edit_btn.hide();
+ this._cancel_btn.show();
+ this._save_btn.show();
+ this._cancel_sep.show();
+ } else if (state === 'display'){
+ this._state = state;
+ this._edit_btn.show();
+ this._cancel_btn.hide();
+ this._cancel_sep.hide();
+ this._save_btn.hide();
+ }
+};
+
+TagWikiEditor.prototype.restoreContent = function(){
+ var content_box = this._content_box;
+ content_box.empty();
+ $.each(this._content_backup, function(idx, element){
+ content_box.append(element);
+ });
+};
+
+TagWikiEditor.prototype.getTagId = function(){
+ return this._tag_id;
+};
+
+TagWikiEditor.prototype.isEditorLoaded = function(){
+ return this._is_editor_loaded;
+};
+
+TagWikiEditor.prototype.setEditorLoaded = function(){
+ return this._is_editor_loaded = true;
+};
+
+/**
+ * loads initial data for the editor input and activates
+ * the editor
+ */
+TagWikiEditor.prototype.startActivatingEditor = function(){
+ var editor = this._editor;
+ var me = this;
+ var data = {
+ object_id: me.getTagId(),
+ model_name: 'Group'
+ };
+ $.ajax({
+ type: 'GET',
+ url: askbot['urls']['load_object_description'],
+ data: data,
+ cache: false,
+ success: function(data){
+ me.backupContent();
+ editor.setText(data);
+ me.setContent(editor.getElement());
+ me.setState('edit');
+ if (me.isEditorLoaded() === false){
+ editor.start();
+ me.setEditorLoaded();
+ }
+ }
+ });
+};
+
+TagWikiEditor.prototype.saveData = function(){
+ var me = this;
+ var text = this._editor.getText();
+ var data = {
+ object_id: me.getTagId(),
+ model_name: 'Group',//todo: fixme
+ text: text
+ };
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ url: askbot['urls']['save_object_description'],
+ data: data,
+ cache: false,
+ success: function(data){
+ if (data['success']){
+ me.setState('display');
+ me.setContent(data['html']);
+ } else {
+ showMessage(me.getElement(), data['message']);
+ }
+ }
+ });
+};
+
+TagWikiEditor.prototype.cancelEdit = function(){
+ this.restoreContent();
+ this.setState('display');
+};
+
+TagWikiEditor.prototype.decorate = function(element){
+ //expect <div id='group-wiki-{{id}}'><div class="content"/><a class="edit"/></div>
+ this._element = element;
+ var edit_btn = element.find('.edit-description');
+ this._edit_btn = edit_btn;
+
+ //adding two buttons...
+ var save_btn = this.makeElement('a');
+ save_btn.html(gettext('save'));
+ edit_btn.after(save_btn);
+ save_btn.hide();
+ this._save_btn = save_btn;
+
+ var cancel_btn = this.makeElement('a');
+ cancel_btn.html(gettext('cancel'));
+ save_btn.after(cancel_btn);
+ cancel_btn.hide();
+ this._cancel_btn = cancel_btn;
+
+ this._cancel_sep = $('<span> | </span>');
+ cancel_btn.before(this._cancel_sep);
+ this._cancel_sep.hide();
+
+ this._content_box = element.find('.content');
+ this._tag_id = element.attr('id').split('-').pop();
+
+ var me = this;
+ if (askbot['settings']['editorType'] === 'markdown') {
+ var editor = new WMD();
+ } else {
+ var editor = new TinyMCE({//override defaults
+ mode: 'exact',
+ elements: 'editor',
+ theme_advanced_buttons1: 'bold, italic, |, link, |, numlist, bullist',
+ theme_advanced_buttons2: '',
+ plugins: '',
+ width: '200'
+ });
+ }
+ if (this._enabled_editor_buttons){
+ editor.setEnabledButtons(this._enabled_editor_buttons);
+ }
+ editor.setPreviewerEnabled(this._is_previewer_enabled);
+ this._editor = editor;
+ setupButtonEventHandlers(edit_btn, function(){ me.startActivatingEditor() });
+ setupButtonEventHandlers(cancel_btn, function(){me.cancelEdit()});
+ setupButtonEventHandlers(save_btn, function(){me.saveData()});
+};
+
+var ImageChanger = function(){
+ WrappedElement.call(this);
+ this._image_element = undefined;
+ this._delete_button = undefined;
+ this._save_url = undefined;
+ this._delete_url = undefined;
+ this._messages = undefined;
+};
+inherits(ImageChanger, WrappedElement);
+
+ImageChanger.prototype.setImageElement = function(image_element){
+ this._image_element = image_element;
+};
+
+ImageChanger.prototype.setMessages = function(messages){
+ this._messages = messages;
+};
+
+ImageChanger.prototype.setDeleteButton = function(delete_button){
+ this._delete_button = delete_button;
+};
+
+ImageChanger.prototype.setSaveUrl = function(url){
+ this._save_url = url;
+};
+
+ImageChanger.prototype.setDeleteUrl = function(url){
+ this._delete_url = url;
+};
+
+ImageChanger.prototype.setAjaxData = function(data){
+ this._ajax_data = data;
+};
+
+ImageChanger.prototype.showImage = function(image_url){
+ this._image_element.attr('src', image_url);
+ this._image_element.show();
+};
+
+ImageChanger.prototype.deleteImage = function(){
+ this._image_element.attr('src', '');
+ this._image_element.css('display', 'none');
+
+ var me = this;
+ var delete_url = this._delete_url;
+ var data = this._ajax_data;
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ url: delete_url,
+ data: data,
+ cache: false,
+ success: function(data){
+ if (data['success'] === true){
+ showMessage(me.getElement(), data['message'], 'after');
+ }
+ }
+ });
+};
+
+ImageChanger.prototype.saveImageUrl = function(image_url){
+ var me = this;
+ var data = this._ajax_data;
+ data['image_url'] = image_url;
+ var save_url = this._save_url;
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ url: save_url,
+ data: data,
+ cache: false,
+ success: function(data){
+ if (!data['success']){
+ showMessage(me.getElement(), data['message'], 'after');
+ }
+ }
+ });
+};
+
+ImageChanger.prototype.startDialog = function(){
+ //reusing the wmd's file uploader
+ var me = this;
+ var change_image_text = this._messages['change_image'];
+ var change_image_button = this._element;
+ Attacklab.Util.prompt(
+ "<h3>" + gettext('Enter the logo url or upload an image') + '</h3>',
+ 'http://',
+ function(image_url){
+ if (image_url){
+ me.saveImageUrl(image_url);
+ me.showImage(image_url);
+ change_image_button.html(change_image_text);
+ me.showDeleteButton();
+ }
+ },
+ 'image'
+ );
+};
+
+ImageChanger.prototype.showDeleteButton = function(){
+ this._delete_button.show();
+ this._delete_button.prev().show();
+};
+
+ImageChanger.prototype.hideDeleteButton = function(){
+ this._delete_button.hide();
+ this._delete_button.prev().hide();
+};
+
+
+ImageChanger.prototype.startDeleting = function(){
+ if (confirm(gettext('Do you really want to remove the image?'))){
+ this.deleteImage();
+ this._element.html(this._messages['add_image']);
+ this.hideDeleteButton();
+ this._delete_button.hide();
+ var sep = this._delete_button.prev();
+ sep.hide();
+ };
+};
+
+/**
+ * decorates an element that will serve as the image changer button
+ */
+ImageChanger.prototype.decorate = function(element){
+ this._element = element;
+ var me = this;
+ setupButtonEventHandlers(
+ element,
+ function(){
+ me.startDialog();
+ }
+ );
+ setupButtonEventHandlers(
+ this._delete_button,
+ function(){
+ me.startDeleting();
+ }
+ )
+};
+
+var UserGroupProfileEditor = function(){
+ TagWikiEditor.call(this);
+};
+inherits(UserGroupProfileEditor, TagWikiEditor);
+
+UserGroupProfileEditor.prototype.toggleEmailModeration = function(){
+ var btn = this._moderate_email_btn;
+ var group_id = this.getTagId();
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ cache: false,
+ data: {group_id: group_id},
+ url: askbot['urls']['toggle_group_email_moderation'],
+ success: function(data){
+ if (data['success']){
+ btn.html(data['new_button_text']);
+ } else {
+ showMessage(btn, data['message']);
+ }
+ }
+ });
+};
+
+UserGroupProfileEditor.prototype.decorate = function(element){
+ this.setEnabledEditorButtons('bold italic link ol ul');
+ this.setPreviewerEnabled(false);
+ UserGroupProfileEditor.superClass_.decorate.call(this, element);
+ var change_logo_btn = element.find('.change-logo');
+ this._change_logo_btn = change_logo_btn;
+
+ var moderate_email_toggle = new TwoStateToggle();
+ moderate_email_toggle.setPostData({
+ group_id: this.getTagId(),
+ property_name: 'moderate_email'
+ });
+ var moderate_email_btn = element.find('#moderate-email');
+ this._moderate_email_btn = moderate_email_btn;
+ moderate_email_toggle.decorate(moderate_email_btn);
+
+ var moderate_publishing_replies_toggle = new TwoStateToggle();
+ moderate_publishing_replies_toggle.setPostData({
+ group_id: this.getTagId(),
+ property_name: 'moderate_answers_to_enquirers'
+ });
+ var btn = element.find('#moderate-answers-to-enquirers');
+ moderate_publishing_replies_toggle.decorate(btn);
+
+ var opennessSelector = new DropdownSelect();
+ var selectorElement = element.find('#group-openness-selector');
+ opennessSelector.setPostData({
+ group_id: this.getTagId(),
+ property_name: 'openness'
+ });
+ opennessSelector.decorate(selectorElement);
+
+ var email_editor = new TextPropertyEditor();
+ email_editor.decorate(element.find('#preapproved-emails'));
+
+ var domain_editor = new TextPropertyEditor();
+ domain_editor.decorate(element.find('#preapproved-email-domains'));
+
+ var logo_changer = new ImageChanger();
+ logo_changer.setImageElement(element.find('.group-logo'));
+ logo_changer.setAjaxData({
+ group_id: this.getTagId()
+ });
+ logo_changer.setSaveUrl(askbot['urls']['save_group_logo_url']);
+ logo_changer.setDeleteUrl(askbot['urls']['delete_group_logo_url']);
+ logo_changer.setMessages({
+ change_image: gettext('change logo'),
+ add_image: gettext('add logo')
+ });
+ var delete_logo_btn = element.find('.delete-logo');
+ logo_changer.setDeleteButton(delete_logo_btn);
+ logo_changer.decorate(change_logo_btn);
+};
+
+var GroupJoinButton = function(){
+ TwoStateToggle.call(this);
+};
+inherits(GroupJoinButton, TwoStateToggle);
+
+GroupJoinButton.prototype.getPostData = function(){
+ return { group_id: this._group_id };
+};
+
+GroupJoinButton.prototype.getHandler = function(){
+ var me = this;
+ return function(){
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ cache: false,
+ data: me.getPostData(),
+ url: askbot['urls']['join_or_leave_group'],
+ success: function(data){
+ if (data['success']){
+ var level = data['membership_level'];
+ var new_state = 'off-state';
+ if (level == 'full' || level == 'pending') {
+ new_state = 'on-state';
+ }
+ me.setState(new_state);
+ } else {
+ showMessage(me.getElement(), data['message']);
+ }
+ }
+ });
+ };
+};
+GroupJoinButton.prototype.decorate = function(elem) {
+ GroupJoinButton.superClass_.decorate.call(this, elem);
+ this._group_id = this._element.data('groupId');
+};
+
+var TagEditor = function() {
+ WrappedElement.call(this);
+ this._has_hot_backspace = false;
+ this._settings = JSON.parse(askbot['settings']['tag_editor']);
+};
+inherits(TagEditor, WrappedElement);
+
+TagEditor.prototype.getSelectedTags = function() {
+ return $.trim(this._hidden_tags_input.val()).split(/\s+/);
+};
+
+TagEditor.prototype.setSelectedTags = function(tag_names) {
+ this._hidden_tags_input.val($.trim(tag_names.join(' ')));
+};
+
+TagEditor.prototype.addSelectedTag = function(tag_name) {
+ var tag_names = this._hidden_tags_input.val();
+ this._hidden_tags_input.val(tag_names + ' ' + tag_name);
+ $('.acResults').hide();//a hack to hide the autocompleter
+};
+
+TagEditor.prototype.isSelectedTagName = function(tag_name) {
+ var tag_names = this.getSelectedTags();
+ return $.inArray(tag_name, tag_names) != -1;
+};
+
+TagEditor.prototype.removeSelectedTag = function(tag_name) {
+ var tag_names = this.getSelectedTags();
+ var idx = $.inArray(tag_name, tag_names);
+ if (idx !== -1) {
+ tag_names.splice(idx, 1)
+ }
+ this.setSelectedTags(tag_names);
+};
+
+TagEditor.prototype.getTagDeleteHandler = function(tag){
+ var me = this;
+ return function(){
+ me.removeSelectedTag(tag.getName());
+ me.clearErrorMessage();
+ tag.dispose();
+ $('.acResults').hide();//a hack to hide the autocompleter
+ me.fixHeight();
+ };
+};
+
+TagEditor.prototype.cleanTag = function(tag_name, reject_dupe) {
+ tag_name = $.trim(tag_name);
+ tag_name = tag_name.replace(/\s+/, ' ');
+
+ var force_lowercase = this._settings['force_lowercase_tags'];
+ if (force_lowercase) {
+ tag_name = tag_name.toLowerCase();
+ }
+
+ if (reject_dupe && this.isSelectedTagName(tag_name)) {
+ throw interpolate(
+ gettext('tag "%s" was already added, no need to repeat (press "escape" to delete)'),
+ [tag_name]
+ );
+ }
+
+ var max_tags = this._settings['max_tags_per_post'];
+ if (this.getSelectedTags().length + 1 > max_tags) {//count current
+ throw interpolate(
+ ngettext(
+ 'a maximum of %s tag is allowed',
+ 'a maximum of %s tags are allowed',
+ max_tags
+ ),
+ [max_tags]
+ );
+ }
+
+ //generic cleaning
+ return cleanTag(tag_name, this._settings);
+};
+
+TagEditor.prototype.addTag = function(tag_name) {
+ var tag = new Tag();
+ tag.setName(tag_name);
+ tag.setDeletable(true);
+ tag.setLinkable(true);
+ tag.setDeleteHandler(this.getTagDeleteHandler(tag));
+ this._tags_container.append(tag.getElement());
+ this.addSelectedTag(tag_name);
+};
+
+TagEditor.prototype.immediateClearErrorMessage = function() {
+ this._error_alert.html('');
+ this._error_alert.show();
+ //this._element.css('margin-top', '18px');//todo: the margin thing is a hack
+}
+
+TagEditor.prototype.clearErrorMessage = function(fade) {
+ if (fade) {
+ var me = this;
+ this._error_alert.fadeOut(function(){
+ me.immediateClearErrorMessage();
+ });
+ } else {
+ this.immediateClearErrorMessage();
+ }
+};
+
+TagEditor.prototype.setErrorMessage = function(text) {
+ var old_text = this._error_alert.html();
+ this._error_alert.html(text);
+ if (old_text == '') {
+ this._error_alert.hide();
+ this._error_alert.fadeIn(100);
+ }
+ //this._element.css('margin-top', '0');//todo: remove this hack
+};
+
+TagEditor.prototype.getAddTagHandler = function() {
+ var me = this;
+ return function(tag_name) {
+ if (me.isSelectedTagName(tag_name)) {
+ return;
+ }
+ try {
+ var clean_tag_name = me.cleanTag($.trim(tag_name));
+ me.addTag(clean_tag_name);
+ me.clearNewTagInput();
+ me.fixHeight();
+ } catch (error) {
+ me.setErrorMessage(error);
+ setTimeout(function(){
+ me.clearErrorMessage(true);
+ }, 1000);
+ }
+ };
+};
+
+TagEditor.prototype.getRawNewTagValue = function() {
+ return this._visible_tags_input.val();//without trimming
+};
+
+TagEditor.prototype.clearNewTagInput = function() {
+ return this._visible_tags_input.val('');
+};
+
+TagEditor.prototype.editLastTag = function() {
+ //delete rendered tag
+ var tc = this._tags_container;
+ tc.find('li:last').remove();
+ //remove from hidden tags input
+ var tags = this.getSelectedTags();
+ var last_tag = tags.pop();
+ this.setSelectedTags(tags);
+ //populate the tag editor
+ this._visible_tags_input.val(last_tag);
+ putCursorAtEnd(this._visible_tags_input);
+};
+
+TagEditor.prototype.setHotBackspace = function(is_hot) {
+ this._has_hot_backspace = is_hot;
+};
+
+TagEditor.prototype.hasHotBackspace = function() {
+ return this._has_hot_backspace;
+};
+
+TagEditor.prototype.completeTagInput = function(reject_dupe) {
+ var tag_name = $.trim(this._visible_tags_input.val());
+ try {
+ tag_name = this.cleanTag(tag_name, reject_dupe);
+ this.addTag(tag_name);
+ this.clearNewTagInput();
+ } catch (error) {
+ this.setErrorMessage(error);
+ }
+};
+
+TagEditor.prototype.saveHeight = function() {
+ return;
+ var elem = this._visible_tags_input;
+ this._height = elem.offset().top;
+};
+
+TagEditor.prototype.fixHeight = function() {
+ return;
+ var new_height = this._visible_tags_input.offset().top;
+ //@todo: replace this by real measurement
+ var element_height = parseInt(
+ this._element.css('height').replace('px', '')
+ );
+ if (new_height > this._height) {
+ this._element.css('height', element_height + 28);//magic number!!!
+ } else if (new_height < this._height) {
+ this._element.css('height', element_height - 28);//magic number!!!
+ }
+ this.saveHeight();
+};
+
+TagEditor.prototype.closeAutoCompleter = function() {
+ this._autocompleter.finish();
+};
+
+TagEditor.prototype.getTagInputKeyHandler = function() {
+ var new_tags = this._visible_tags_input;
+ var me = this;
+ return function(e) {
+ if (e.shiftKey) {
+ return;
+ }
+ me.saveHeight();
+ var key = e.which || e.keyCode;
+ var text = me.getRawNewTagValue();
+
+ //space 32, enter 13
+ if (key == 32 || key == 13) {
+ var tag_name = $.trim(text);
+ if (tag_name.length > 0) {
+ me.completeTagInput(true);//true for reject dupes
+ }
+ me.fixHeight();
+ return false;
+ }
+
+ if (text == '') {
+ me.clearErrorMessage();
+ me.closeAutoCompleter();
+ } else {
+ try {
+ /* do-nothing validation here
+ * just to report any errors while
+ * the user is typing */
+ me.cleanTag(text);
+ me.clearErrorMessage();
+ } catch (error) {
+ me.setErrorMessage(error);
+ }
+ }
+
+ //8 is backspace
+ if (key == 8 && text.length == 0) {
+ if (me.hasHotBackspace() === true) {
+ me.editLastTag();
+ me.setHotBackspace(false);
+ } else {
+ me.setHotBackspace(true);
+ }
+ }
+
+ //27 is escape
+ if (key == 27) {
+ me.clearNewTagInput();
+ me.clearErrorMessage();
+ }
+
+ if (key !== 8) {
+ me.setHotBackspace(false);
+ }
+ me.fixHeight();
+ return false;
+ };
+}
+
+TagEditor.prototype.decorate = function(element) {
+ this._element = element;
+ this._hidden_tags_input = element.find('input[name="tags"]');//this one is hidden
+ this._tags_container = element.find('ul.tags');
+ this._error_alert = $('.tag-editor-error-alert > span');
+
+ var me = this;
+ this._tags_container.children().each(function(idx, elem){
+ var tag = new Tag();
+ tag.setDeletable(true);
+ tag.setLinkable(false);
+ tag.decorate($(elem));
+ tag.setDeleteHandler(me.getTagDeleteHandler(tag));
+ });
+
+ var visible_tags_input = element.find('.new-tags-input');
+ this._visible_tags_input = visible_tags_input;
+ this.saveHeight();
+
+ var me = this;
+ var tagsAc = new AutoCompleter({
+ url: askbot['urls']['get_tag_list'],
+ onItemSelect: function(item){
+ if (me.isSelectedTagName(item['value']) === false) {
+ me.completeTagInput();
+ } else {
+ me.clearNewTagInput();
+ }
+ },
+ preloadData: true,
+ minChars: 1,
+ useCache: true,
+ matchInside: true,
+ maxCacheLength: 100,
+ delay: 10
+ });
+ tagsAc.decorate(visible_tags_input);
+ this._autocompleter = tagsAc;
+ visible_tags_input.keyup(this.getTagInputKeyHandler());
+
+ element.click(function(e) {
+ visible_tags_input.focus();
+ return false;
+ });
+};
+
+/**
+ * @constructor
+ * Category is a select box item
+ * that has CategoryEditControls
+ */
+var Category = function() {
+ SelectBoxItem.call(this);
+ this._state = 'display';
+ this._settings = JSON.parse(askbot['settings']['tag_editor']);
+};
+inherits(Category, SelectBoxItem);
+
+Category.prototype.setCategoryTree = function(tree) {
+ this._tree = tree;
+};
+
+Category.prototype.getCategoryTree = function() {
+ return this._tree;
+};
+
+Category.prototype.getName = function() {
+ return this.getContent().getContent();
+};
+
+Category.prototype.getPath = function() {
+ return this._tree.getPathToItem(this);
+};
+
+Category.prototype.setState = function(state) {
+ this._state = state;
+ if ( !this._element ) {
+ return;
+ }
+ this._input_box.val('');
+ if (state === 'display') {
+ this.showContent();
+ this.hideEditor();
+ this.hideEditControls();
+ } else if (state === 'editable') {
+ this._tree._state = 'editable';//a hack
+ this.showContent();
+ this.hideEditor();
+ this.showEditControls();
+ } else if (state === 'editing') {
+ this._prev_tree_state = this._tree.getState();
+ this._tree._state = 'editing';//a hack
+ this._input_box.val(this.getName());
+ this.hideContent();
+ this.showEditor();
+ this.hideEditControls();
+ }
+};
+
+Category.prototype.hideEditControls = function() {
+ this._delete_button.hide();
+ this._edit_button.hide();
+ this._element.unbind('mouseenter mouseleave');
+};
+
+Category.prototype.showEditControls = function() {
+ var del = this._delete_button;
+ var edit = this._edit_button;
+ this._element.hover(
+ function(){
+ del.show();
+ edit.show();
+ },
+ function(){
+ del.hide();
+ edit.hide();
+ }
+ );
+};
+
+Category.prototype.showEditControlsNow = function() {
+ this._delete_button.show();
+ this._edit_button.show();
+};
+
+Category.prototype.hideContent = function() {
+ this.getContent().getElement().hide();
+};
+
+Category.prototype.showContent = function() {
+ this.getContent().getElement().show();
+};
+
+Category.prototype.showEditor = function() {
+ this._input_box.show();
+ this._input_box.focus();
+ this._save_button.show();
+ this._cancel_button.show();
+};
+
+Category.prototype.hideEditor = function() {
+ this._input_box.hide();
+ this._save_button.hide();
+ this._cancel_button.hide();
+};
+
+Category.prototype.getInput = function() {
+ return this._input_box.val();
+};
+
+Category.prototype.getDeleteHandler = function() {
+ var me = this;
+ return function() {
+ if (confirm(gettext('Delete category?'))) {
+ var tree = me.getCategoryTree();
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ data: JSON.stringify({
+ tag_name: me.getName(),
+ path: me.getPath()
+ }),
+ cache: false,
+ url: askbot['urls']['delete_tag'],
+ success: function(data) {
+ if (data['success']) {
+ //rebuild category tree based on data
+ tree.setData(data['tree_data']);
+ //re-open current branch
+ tree.selectPath(tree.getCurrentPath());
+ tree.setState('editable');
+ } else {
+ alert(data['message']);
+ }
+ }
+ });
+ }
+ return false;
+ };
+};
+
+Category.prototype.getSaveHandler = function() {
+ var me = this;
+ var settings = this._settings;
+ //here we need old value and new value
+ return function(){
+ var to_name = me.getInput();
+ try {
+ to_name = cleanTag(to_name, settings);
+ var data = {
+ from_name: me.getOriginalName(),
+ to_name: to_name,
+ path: me.getPath()
+ };
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ data: JSON.stringify(data),
+ cache: false,
+ url: askbot['urls']['rename_tag'],
+ success: function(data) {
+ if (data['success']) {
+ me.setName(to_name);
+ me.setState('editable');
+ me.showEditControlsNow();
+ } else {
+ alert(data['message']);
+ }
+ }
+ });
+ } catch (error) {
+ alert(error);
+ }
+ return false;
+ };
+};
+
+Category.prototype.addControls = function() {
+ var input_box = this.makeElement('input');
+ this._input_box = input_box;
+ this._element.append(input_box);
+
+ var save_button = this.makeButton(
+ gettext('save'),
+ this.getSaveHandler()
+ );
+ this._save_button = save_button;
+ this._element.append(save_button);
+
+ var me = this;
+ var cancel_button = this.makeButton(
+ 'x',
+ function(){
+ me.setState('editable');
+ me.showEditControlsNow();
+ return false;
+ }
+ );
+ this._cancel_button = cancel_button;
+ this._element.append(cancel_button);
+
+ var edit_button = this.makeButton(
+ gettext('edit'),
+ function(){
+ //todo: I would like to make only one at a time editable
+ //var tree = me.getCategoryTree();
+ //tree.closeAllEditors();
+ //tree.setState('editable');
+ //calc path, then select it
+ var tree = me.getCategoryTree();
+ tree.selectPath(me.getPath());
+ me.setState('editing');
+ return false;
+ }
+ );
+ this._edit_button = edit_button;
+ this._element.append(edit_button);
+
+ var delete_button = this.makeButton(
+ 'x', this.getDeleteHandler()
+ );
+ this._delete_button = delete_button;
+ this._element.append(delete_button);
+};
+
+Category.prototype.getOriginalName = function() {
+ return this._original_name;
+};
+
+Category.prototype.createDom = function() {
+ Category.superClass_.createDom.call(this);
+ this.addControls();
+ this.setState('display');
+ this._original_name = this.getName();
+};
+
+Category.prototype.decorate = function(element) {
+ Category.superClass_.decorate.call(this, element);
+ this.addControls();
+ this.setState('display');
+ this._original_name = this.getName();
+};
+
+var CategoryAdder = function() {
+ WrappedElement.call(this);
+ this._state = 'disabled';//waitedit
+ this._tree = undefined;//category tree
+ this._settings = JSON.parse(askbot['settings']['tag_editor']);
+};
+inherits(CategoryAdder, WrappedElement);
+
+CategoryAdder.prototype.setCategoryTree = function(tree) {
+ this._tree = tree;
+};
+
+CategoryAdder.prototype.setLevel = function(level) {
+ this._level = level;
+};
+
+CategoryAdder.prototype.setState = function(state) {
+ this._state = state;
+ if (!this._element) {
+ return;
+ }
+ if (state === 'waiting') {
+ this._element.show();
+ this._input.val('');
+ this._input.hide();
+ this._save_button.hide();
+ this._cancel_button.hide();
+ this._trigger.show();
+ } else if (state === 'editable') {
+ this._element.show();
+ this._input.show();
+ this._input.val('');
+ this._input.focus();
+ this._save_button.show();
+ this._cancel_button.show();
+ this._trigger.hide();
+ } else if (state === 'disabled') {
+ this.setState('waiting');//a little hack
+ this._state = 'disabled';
+ this._element.hide();
+ }
+};
+
+CategoryAdder.prototype.cleanCategoryName = function(name) {
+ name = $.trim(name);
+ if (name === '') {
+ throw gettext('category name cannot be empty');
+ }
+ //if ( this._tree.hasCategory(name) ) {
+ //throw interpolate(
+ //throw gettext('this category already exists');
+ // [this._tree.getDisplayPathByName(name)]
+ //)
+ //}
+ return cleanTag(name, this._settings);
+};
+
+CategoryAdder.prototype.getPath = function() {
+ var path = this._tree.getCurrentPath();
+ if (path.length > this._level + 1) {
+ return path.slice(0, this._level + 1);
+ } else {
+ return path;
+ }
+};
+
+CategoryAdder.prototype.getSelectBox = function() {
+ return this._tree.getSelectBox(this._level);
+};
+
+CategoryAdder.prototype.startAdding = function() {
+ try {
+ var name = this._input.val();
+ name = this.cleanCategoryName(name);
+ } catch (error) {
+ alert(error);
+ return;
+ }
+
+ //don't add dupes to the same level
+ var existing_names = this.getSelectBox().getNames();
+ if ($.inArray(name, existing_names) != -1) {
+ alert(gettext('already exists at the current level!'));
+ return;
+ }
+
+ var me = this;
+ var tree = this._tree;
+ var adder_path = this.getPath();
+
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ data: JSON.stringify({
+ path: adder_path,
+ new_category_name: name
+ }),
+ url: askbot['urls']['add_tag_category'],
+ cache: false,
+ success: function(data) {
+ if (data['success']) {
+ //rebuild category tree based on data
+ tree.setData(data['tree_data']);
+ tree.selectPath(data['new_path']);
+ tree.setState('editable');
+ me.setState('waiting');
+ } else {
+ alert(data['message']);
+ }
+ }
+ });
+};
+
+CategoryAdder.prototype.createDom = function() {
+ this._element = this.makeElement('li');
+ //add open adder link
+ var trigger = this.makeElement('a');
+ this._trigger = trigger;
+ trigger.html(gettext('add category'));
+ this._element.append(trigger);
+ //add input box and the add button
+ var input = this.makeElement('input');
+ this._input = input;
+ input.addClass('add-category');
+ input.attr('name', 'add_category');
+ this._element.append(input);
+ //add save category button
+ var save_button = this.makeElement('button');
+ this._save_button = save_button;
+ save_button.html(gettext('save'));
+ this._element.append(save_button);
+
+ var cancel_button = this.makeElement('button');
+ this._cancel_button = cancel_button;
+ cancel_button.html('x');
+ this._element.append(cancel_button);
+
+ this.setState(this._state);
+
+ var me = this;
+ setupButtonEventHandlers(
+ trigger,
+ function(){ me.setState('editable'); }
+ )
+ setupButtonEventHandlers(
+ save_button,
+ function() {
+ me.startAdding();
+ return false;//prevent form submit
+ }
+ );
+ setupButtonEventHandlers(
+ cancel_button,
+ function() {
+ me.setState('waiting');
+ return false;//prevent submit
+ }
+ );
+ //create input box, button and the "activate" link
+};
+
+/**
+ * @constructor
+ * SelectBox subclass to create/edit/delete
+ * categories
+ */
+var CategorySelectBox = function() {
+ SelectBox.call(this);
+ this._item_class = Category;
+ this._category_adder = undefined;
+ this._tree = undefined;//cat tree
+ this._level = undefined;
+};
+inherits(CategorySelectBox, SelectBox);
+
+CategorySelectBox.prototype.setState = function(state) {
+ this._state = state;
+ if (state === 'select') {
+ if (this._category_adder) {
+ this._category_adder.setState('disabled');
+ }
+ $.each(this._items, function(idx, item){
+ item.setState('display');
+ });
+ } else if (state === 'editable') {
+ this._category_adder.setState('waiting');
+ $.each(this._items, function(idx, item){
+ item.setState('editable');
+ });
+ }
+};
+
+CategorySelectBox.prototype.setCategoryTree = function(tree) {
+ this._tree = tree;
+};
+
+CategorySelectBox.prototype.getCategoryTree = function() {
+};
+
+CategorySelectBox.prototype.setLevel = function(level) {
+ this._level = level;
+};
+
+CategorySelectBox.prototype.getNames = function() {
+ var names = [];
+ $.each(this._items, function(idx, item) {
+ names.push(item.getName());
+ });
+ return names;
+};
+
+CategorySelectBox.prototype.appendCategoryAdder = function() {
+ var adder = new CategoryAdder();
+ adder.setLevel(this._level);
+ adder.setCategoryTree(this._tree);
+ this._category_adder = adder;
+ this._element.append(adder.getElement());
+};
+
+CategorySelectBox.prototype.createDom = function() {
+ CategorySelectBox.superClass_.createDom();
+ if (askbot['data']['userIsAdmin']) {
+ this.appendCategoryAdder();
+ }
+};
+
+CategorySelectBox.prototype.decorate = function(element) {
+ CategorySelectBox.superClass_.decorate.call(this, element);
+ this.setState(this._state);
+ if (askbot['data']['userIsAdmin']) {
+ this.appendCategoryAdder();
+ }
+};
+
+/**
+ * @constructor
+ * turns on/off the category editor
+ */
+var CategoryEditorToggle = function() {
+ TwoStateToggle.call(this);
+};
+inherits(CategoryEditorToggle, TwoStateToggle);
+
+CategoryEditorToggle.prototype.setCategorySelector = function(sel) {
+ this._category_selector = sel;
+};
+
+CategoryEditorToggle.prototype.getCategorySelector = function() {
+ return this._category_selector;
+};
+
+CategoryEditorToggle.prototype.decorate = function(element) {
+ CategoryEditorToggle.superClass_.decorate.call(this, element);
+};
+
+CategoryEditorToggle.prototype.getDefaultHandler = function() {
+ var me = this;
+ return function() {
+ var editor = me.getCategorySelector();
+ if (me.isOn()) {
+ me.setState('off-state');
+ editor.setState('select');
+ } else {
+ me.setState('on-state');
+ editor.setState('editable');
+ }
+ };
+};
+
+var CategorySelector = function() {
+ Widget.call(this);
+ this._data = null;
+ this._select_handler = function(){};//dummy default
+ this._current_path = [0];//path points to selected item in tree
+};
+inherits(CategorySelector, Widget);
+
+/**
+ * propagates state to the individual selectors
+ */
+CategorySelector.prototype.setState = function(state) {
+ this._state = state;
+ if (state === 'editing') {
+ return;//do not propagate this state
+ }
+ $.each(this._selectors, function(idx, selector){
+ selector.setState(state);
+ });
+};
+
+CategorySelector.prototype.getPathToItem = function(item) {
+ function findPathToItemInTree(tree, item) {
+ for (var i = 0; i < tree.length; i++) {
+ var node = tree[i];
+ if (node[2] === item) {
+ return [i];
+ }
+ var path = findPathToItemInTree(node[1], item);
+ if (path.length > 0) {
+ path.unshift(i);
+ return path;
+ }
+ }
+ return [];
+ };
+ return findPathToItemInTree(this._data, item);
+};
+
+CategorySelector.prototype.applyToDataItems = function(func) {
+ function applyToDataItems(tree) {
+ $.each(tree, function(idx, item) {
+ func(item);
+ applyToDataItems(item[1]);
+ });
+ };
+ if (this._data) {
+ applyToDataItems(this._data);
+ }
+};
+
+CategorySelector.prototype.setData = function(data) {
+ this._clearData
+ this._data = data;
+ var tree = this;
+ function attachCategory(item) {
+ var cat = new Category();
+ cat.setName(item[0]);
+ cat.setCategoryTree(tree);
+ item[2] = cat;
+ };
+ this.applyToDataItems(attachCategory);
+};
+
+/**
+ * clears contents of selector boxes starting from
+ * the given level, in range 0..2
+ */
+CategorySelector.prototype.clearCategoryLevels = function(level) {
+ for (var i = level; i < 3; i++) {
+ this._selectors[i].detachAllItems();
+ }
+};
+
+CategorySelector.prototype.getLeafItems = function(selection_path) {
+ //traverse the tree down to items pointed to by the path
+ var data = this._data[0];
+ for (var i = 1; i < selection_path.length; i++) {
+ data = data[1][selection_path[i]];
+ }
+ return data[1];
+}
+
+/**
+ * called when a sub-level needs to open
+ */
+CategorySelector.prototype.populateCategoryLevel = function(source_path) {
+ var level = source_path.length - 1;
+ if (level >= 3) {
+ return;
+ }
+ //clear all items downstream
+ this.clearCategoryLevels(level);
+
+ //populate current selector
+ var selector = this._selectors[level];
+ var items = this.getLeafItems(source_path);
+
+ $.each(items, function(idx, item) {
+ var category_name = item[0];
+ var category_subtree = item[1];
+ var category_object = item[2];
+ selector.addItemObject(category_object);
+ if (category_subtree.length > 0) {
+ category_object.addCssClass('tree');
+ }
+ });
+
+ this.setState(this._state);//update state
+
+ selector.clearSelection();
+};
+
+CategorySelector.prototype.selectPath = function(path) {
+ for (var i = 1; i <= path.length; i++) {
+ this.populateCategoryLevel(path.slice(0, i));
+ }
+ for (var i = 1; i < path.length; i++) {
+ var sel_box = this._selectors[i-1];
+ var category = sel_box.getItemByIndex(path[i]);
+ sel_box.selectItem(category);
+ }
+};
+
+CategorySelector.prototype.getSelectBox = function(level) {
+ return this._selectors[level];
+};
+
+CategorySelector.prototype.getSelectedPath = function(selected_level) {
+ var path = [0];//root, todo: better use names for path???
+ /*
+ * upper limit capped by current clicked level
+ * we ignore all selection above the current level
+ */
+ for (var i = 0; i < selected_level + 1; i++) {
+ var selector = this._selectors[i];
+ var item = selector.getSelectedItem();
+ if (item) {
+ path.push(selector.getItemIndex(item));
+ } else {
+ return path;
+ }
+ }
+ return path;
+};
+
+/** getter and setter are not symmetric */
+CategorySelector.prototype.setSelectHandler = function(handler) {
+ this._select_handler = handler;
+};
+
+CategorySelector.prototype.getSelectHandlerInternal = function() {
+ return this._select_handler;
+};
+
+CategorySelector.prototype.setCurrentPath = function(path) {
+ return this._current_path = path;
+};
+
+CategorySelector.prototype.getCurrentPath = function() {
+ return this._current_path;
+};
+
+CategorySelector.prototype.getEditorToggle = function() {
+ return this._editor_toggle;
+};
+
+/*CategorySelector.prototype.closeAllEditors = function() {
+ $.each(this._selectors, function(idx, sel) {
+ sel._category_adder.setState('wait');
+ $.each(sel._items, function(idx2, item) {
+ item.setState('editable');
+ });
+ });
+};*/
+
+CategorySelector.prototype.getSelectHandler = function(level) {
+ var me = this;
+ return function(item_data) {
+ if (me.getState() === 'editing') {
+ return;//don't navigate when editing
+ }
+ //1) run the assigned select handler
+ var tag_name = item_data['title']
+ if (me.getState() === 'select') {
+ /* this one will actually select the tag
+ * maybe a bit too implicit
+ */
+ me.getSelectHandlerInternal()(tag_name);
+ }
+ //2) if appropriate, populate the higher level
+ if (level < 2) {
+ var current_path = me.getSelectedPath(level);
+ me.setCurrentPath(current_path);
+ me.populateCategoryLevel(current_path);
+ }
+ }
+};
+
+CategorySelector.prototype.decorate = function(element) {
+ this._element = element;
+ this._selectors = [];
+
+ var selector0 = new CategorySelectBox();
+ selector0.setLevel(0);
+ selector0.setCategoryTree(this);
+ selector0.decorate(element.find('.cat-col-0'));
+ selector0.setSelectHandler(this.getSelectHandler(0));
+ this._selectors.push(selector0);
+
+ var selector1 = new CategorySelectBox();
+ selector1.setLevel(1);
+ selector1.setCategoryTree(this);
+ selector1.decorate(element.find('.cat-col-1'));
+ selector1.setSelectHandler(this.getSelectHandler(1));
+ this._selectors.push(selector1)
+
+ var selector2 = new CategorySelectBox();
+ selector2.setLevel(2);
+ selector2.setCategoryTree(this);
+ selector2.decorate(element.find('.cat-col-2'));
+ selector2.setSelectHandler(this.getSelectHandler(2));
+ this._selectors.push(selector2);
+
+ if (askbot['data']['userIsAdminOrMod']) {
+ var editor_toggle = new CategoryEditorToggle();
+ editor_toggle.setCategorySelector(this);
+ var toggle_element = $('.category-editor-toggle');
+ toggle_element.show();
+ editor_toggle.decorate(toggle_element);
+ this._editor_toggle = editor_toggle;
+ }
+
+ this.populateCategoryLevel([0]);
+};
+
+/**
+ * @constructor
+ * loads html for the category selector from
+ * the server via ajax and activates the
+ * CategorySelector on the loaded HTML
+ */
+var CategorySelectorLoader = function() {
+ WrappedElement.call(this);
+ this._is_loaded = false;
+};
+inherits(CategorySelectorLoader, WrappedElement);
+
+CategorySelectorLoader.prototype.setCategorySelector = function(sel) {
+ this._category_selector = sel;
+};
+
+CategorySelectorLoader.prototype.setLoaded = function(is_loaded) {
+ this._is_loaded = is_loaded;
+};
+
+CategorySelectorLoader.prototype.isLoaded = function() {
+ return this._is_loaded;
+};
+
+CategorySelectorLoader.prototype.setEditor = function(editor) {
+ this._editor = editor;
+};
+
+CategorySelectorLoader.prototype.closeEditor = function() {
+ this._editor.hide();
+ this._editor_buttons.hide();
+ this._display_tags_container.show();
+ this._question_body.show();
+ this._question_controls.show();
+};
+
+CategorySelectorLoader.prototype.openEditor = function() {
+ this._editor.show();
+ this._editor_buttons.show();
+ this._display_tags_container.hide();
+ this._question_body.hide();
+ this._question_controls.hide();
+ var sel = this._category_selector;
+ sel.setState('select');
+ sel.getEditorToggle().setState('off-state');
+};
+
+CategorySelectorLoader.prototype.addEditorButtons = function() {
+ this._editor.after(this._editor_buttons);
+};
+
+CategorySelectorLoader.prototype.getOnLoadHandler = function() {
+ var me = this;
+ return function(html){
+ me.setLoaded(true);
+
+ //append loaded html to dom
+ var editor = $('<div>' + html + '</div>');
+ me.setEditor(editor);
+ $('#question-tags').after(editor);
+
+ var selector = askbot['functions']['initCategoryTree']();
+ me.setCategorySelector(selector);
+
+ me.addEditorButtons();
+ me.openEditor();
+ //add the save button
+ };
+};
+
+CategorySelectorLoader.prototype.startLoadingHTML = function(on_load) {
+ var me = this;
+ $.ajax({
+ type: 'GET',
+ dataType: 'json',
+ data: { template_name: 'widgets/tag_category_selector.html' },
+ url: askbot['urls']['get_html_template'],
+ cache: true,
+ success: function(data) {
+ if (data['success']) {
+ on_load(data['html']);
+ } else {
+ showMessage(me.getElement(), data['message']);
+ }
+ }
+ });
+};
+
+CategorySelectorLoader.prototype.getRetagHandler = function() {
+ var me = this;
+ return function() {
+ if (me.isLoaded() === false) {
+ me.startLoadingHTML(me.getOnLoadHandler());
+ } else {
+ me.openEditor();
+ }
+ return false;
+ }
+};
+
+CategorySelectorLoader.prototype.drawNewTags = function(new_tags) {
+ if (new_tags === ''){
+ this._display_tags_container.html('');
+ return;
+ }
+ new_tags = new_tags.split(/\s+/);
+ var tags_html = ''
+ $.each(new_tags, function(index, name){
+ var tag = new Tag();
+ tag.setName(name);
+ tags_html += tag.getElement().outerHTML();
+ });
+ this._display_tags_container.html(tags_html);
+};
+
+CategorySelectorLoader.prototype.getSaveHandler = function() {
+ var me = this;
+ return function() {
+ var tagInput = $('input[name="tags"]');
+ $.ajax({
+ type: "POST",
+ url: retagUrl,//add to askbot['urls']
+ dataType: "json",
+ data: { tags: getUniqueWords(tagInput.val()).join(' ') },
+ success: function(json) {
+ if (json['success'] === true){
+ var new_tags = getUniqueWords(json['new_tags']);
+ oldTagsHtml = '';
+ me.closeEditor();
+ me.drawNewTags(new_tags.join(' '));
+ }
+ else {
+ me.closeEditor();
+ showMessage(me.getElement(), json['message']);
+ }
+ },
+ error: function(xhr, textStatus, errorThrown) {
+ showMessage(tagsDiv, 'sorry, something is not right here');
+ cancelRetag();
+ }
+ });
+ return false;
+ };
+};
+
+CategorySelectorLoader.prototype.getCancelHandler = function() {
+ var me = this;
+ return function() {
+ me.closeEditor();
+ };
+};
+
+CategorySelectorLoader.prototype.decorate = function(element) {
+ this._element = element;
+ this._display_tags_container = $('#question-tags');
+ this._question_body = $('.question-body');
+ this._question_controls = $('#question-controls');
+
+ this._editor_buttons = this.makeElement('div');
+ this._done_button = this.makeElement('button');
+ this._done_button.html(gettext('save tags'));
+ this._editor_buttons.append(this._done_button);
+
+ this._cancel_button = this.makeElement('button');
+ this._cancel_button.html(gettext('cancel'));
+ this._editor_buttons.append(this._cancel_button);
+ this._editor_buttons.find('button').addClass('submit');
+ this._editor_buttons.addClass('retagger-buttons');
+
+ //done button
+ setupButtonEventHandlers(
+ this._done_button,
+ this.getSaveHandler()
+ );
+ //cancel button
+ setupButtonEventHandlers(
+ this._cancel_button,
+ this.getCancelHandler()
+ );
+
+ //retag button
+ setupButtonEventHandlers(
+ element,
+ this.getRetagHandler()
+ );
+};
+
+$(document).ready(function() {
+ $('[id^="comments-for-"]').each(function(index, element){
+ var comments = new PostCommentsWidget();
+ comments.decorate(element);
+ });
+ $('[id^="swap-question-with-answer-"]').each(function(idx, element){
+ var swapper = new QASwapper();
+ swapper.decorate($(element));
+ });
+ $('[id^="post-id-"]').each(function(idx, element){
+ var deleter = new DeletePostLink();
+ //confusingly .question-delete matches the answers too need rename
+ var post_id = element.id.split('-').pop();
+ deleter.setPostId(post_id);
+ deleter.decorate($(element).find('.question-delete'));
+ });
+ //todo: convert to "control" class
+ var publishBtns = $('.answer-publish, .answer-unpublish');
+ publishBtns.each(function(idx, btn) {
+ setupButtonEventHandlers($(btn), function() {
+ var answerId = $(btn).data('answerId');
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ data: {'answer_id': answerId},
+ url: askbot['urls']['publishAnswer'],
+ success: function(data) {
+ if (data['success']) {
+ window.location.reload(true);
+ } else {
+ showMessage($(btn), data['message']);
+ }
+ }
+ });
+ });
+ });
+
+ if (askbot['settings']['tagSource'] == 'category-tree') {
+ var catSelectorLoader = new CategorySelectorLoader();
+ catSelectorLoader.decorate($('#retag'));
+ } else {
+ questionRetagger.init();
+ }
+ socialSharing.init();
+
+ var proxyUserNameInput = $('#id_post_author_username');
+ var proxyUserEmailInput = $('#id_post_author_email');
+ if (proxyUserNameInput.length === 1) {
+
+ var userSelectHandler = function(data) {
+ proxyUserEmailInput.val(data['data'][0]);
+ };
+
+ var fakeUserAc = new AutoCompleter({
+ url: '/get-users-info/',//askbot['urls']['get_users_info'],
+ preloadData: true,
+ promptText: gettext('User name:'),
+ minChars: 1,
+ useCache: true,
+ matchInside: true,
+ maxCacheLength: 100,
+ delay: 10,
+ onItemSelect: userSelectHandler
+ });
+
+ fakeUserAc.decorate(proxyUserNameInput);
+ if (proxyUserEmailInput.length === 1) {
+ var tip = new TippedInput();
+ tip.decorate(proxyUserEmailInput);
+ }
+
+ }
+ //if groups are enabled - activate share functions
+ var groupsInput = $('#share_group_name');
+ if (groupsInput.length === 1) {
+ var groupsAc = new AutoCompleter({
+ url: askbot['urls']['getGroupsList'],
+ preloadData: true,
+ promptText: gettext('Group name:'),
+ minChars: 1,
+ useCache: false,
+ matchInside: true,
+ maxCacheLength: 100,
+ delay: 10
+ });
+ groupsAc.decorate(groupsInput);
+ }
+ var usersInput = $('#share_user_name');
+ if (usersInput.length === 1) {
+ var usersAc = new AutoCompleter({
+ url: '/get-users-info/',
+ preloadData: true,
+ promptText: gettext('User name:'),
+ minChars: 1,
+ useCache: false,
+ matchInside: true,
+ maxCacheLength: 100,
+ delay: 10
+ });
+ usersAc.decorate(usersInput);
+ }
+
+ var showSharedUsers = $('.see-related-users');
+ if (showSharedUsers.length) {
+ var usersPopup = new ThreadUsersDialog();
+ usersPopup.setHeadingText(gettext('Shared with the following users:'));
+ usersPopup.decorate(showSharedUsers);
+ }
+ var showSharedGroups = $('.see-related-groups');
+ if (showSharedGroups.length) {
+ var groupsPopup = new ThreadUsersDialog();
+ groupsPopup.setHeadingText(gettext('Shared with the following groups:'));
+ groupsPopup.decorate(showSharedGroups);
+ }
+});
+
+
+/*
+Prettify
+http://www.apache.org/licenses/LICENSE-2.0
+*/
+var PR_SHOULD_USE_CONTINUATION = true; var PR_TAB_WIDTH = 8; var PR_normalizedHtml; var PR; var prettyPrintOne; var prettyPrint; function _pr_isIE6() { var isIE6 = navigator && navigator.userAgent && /\bMSIE 6\./.test(navigator.userAgent); _pr_isIE6 = function() { return isIE6; }; return isIE6; } (function() { function wordSet(words) { words = words.split(/ /g); var set = {}; for (var i = words.length; --i >= 0; ) { var w = words[i]; if (w) { set[w] = null; } } return set; } var FLOW_CONTROL_KEYWORDS = "break continue do else for if return while "; var C_KEYWORDS = FLOW_CONTROL_KEYWORDS + "auto case char const default " + "double enum extern float goto int long register short signed sizeof " + "static struct switch typedef union unsigned void volatile "; var COMMON_KEYWORDS = C_KEYWORDS + "catch class delete false import " + "new operator private protected public this throw true try "; var CPP_KEYWORDS = COMMON_KEYWORDS + "alignof align_union asm axiom bool " + "concept concept_map const_cast constexpr decltype " + "dynamic_cast explicit export friend inline late_check " + "mutable namespace nullptr reinterpret_cast static_assert static_cast " + "template typeid typename typeof using virtual wchar_t where "; var JAVA_KEYWORDS = COMMON_KEYWORDS + "boolean byte extends final finally implements import instanceof null " + "native package strictfp super synchronized throws transient "; var CSHARP_KEYWORDS = JAVA_KEYWORDS + "as base by checked decimal delegate descending event " + "fixed foreach from group implicit in interface internal into is lock " + "object out override orderby params readonly ref sbyte sealed " + "stackalloc string select uint ulong unchecked unsafe ushort var "; var JSCRIPT_KEYWORDS = COMMON_KEYWORDS + "debugger eval export function get null set undefined var with " + "Infinity NaN "; var PERL_KEYWORDS = "caller delete die do dump elsif eval exit foreach for " + "goto if import last local my next no our print package redo require " + "sub undef unless until use wantarray while BEGIN END "; var PYTHON_KEYWORDS = FLOW_CONTROL_KEYWORDS + "and as assert class def del " + "elif except exec finally from global import in is lambda " + "nonlocal not or pass print raise try with yield " + "False True None "; var RUBY_KEYWORDS = FLOW_CONTROL_KEYWORDS + "alias and begin case class def" + " defined elsif end ensure false in module next nil not or redo rescue " + "retry self super then true undef unless until when yield BEGIN END "; var SH_KEYWORDS = FLOW_CONTROL_KEYWORDS + "case done elif esac eval fi " + "function in local set then until "; var ALL_KEYWORDS = (CPP_KEYWORDS + CSHARP_KEYWORDS + JSCRIPT_KEYWORDS + PERL_KEYWORDS + PYTHON_KEYWORDS + RUBY_KEYWORDS + SH_KEYWORDS); var PR_STRING = 'str'; var PR_KEYWORD = 'kwd'; var PR_COMMENT = 'com'; var PR_TYPE = 'typ'; var PR_LITERAL = 'lit'; var PR_PUNCTUATION = 'pun'; var PR_PLAIN = 'pln'; var PR_TAG = 'tag'; var PR_DECLARATION = 'dec'; var PR_SOURCE = 'src'; var PR_ATTRIB_NAME = 'atn'; var PR_ATTRIB_VALUE = 'atv'; var PR_NOCODE = 'nocode'; function isWordChar(ch) { return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); } function spliceArrayInto(inserted, container, containerPosition, countReplaced) { inserted.unshift(containerPosition, countReplaced || 0); try { container.splice.apply(container, inserted); } finally { inserted.splice(0, 2); } } var REGEXP_PRECEDER_PATTERN = function() { var preceders = ["!", "!=", "!==", "#", "%", "%=", "&", "&&", "&&=", "&=", "(", "*", "*=", "+=", ",", "-=", "->", "/", "/=", ":", "::", ";", "<", "<<", "<<=", "<=", "=", "==", "===", ">", ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[", "^", "^=", "^^", "^^=", "{", "|", "|=", "||", "||=", "~", "break", "case", "continue", "delete", "do", "else", "finally", "instanceof", "return", "throw", "try", "typeof"]; var pattern = '(?:' + '(?:(?:^|[^0-9.])\\.{1,3})|' + '(?:(?:^|[^\\+])\\+)|' + '(?:(?:^|[^\\-])-)'; for (var i = 0; i < preceders.length; ++i) { var preceder = preceders[i]; if (isWordChar(preceder.charAt(0))) { pattern += '|\\b' + preceder; } else { pattern += '|' + preceder.replace(/([^=<>:&])/g, '\\$1'); } } pattern += '|^)\\s*$'; return new RegExp(pattern); } (); var pr_amp = /&/g; var pr_lt = /</g; var pr_gt = />/g; var pr_quot = /\"/g; function attribToHtml(str) { return str.replace(pr_amp, '&amp;').replace(pr_lt, '&lt;').replace(pr_gt, '&gt;').replace(pr_quot, '&quot;'); } function textToHtml(str) { return str.replace(pr_amp, '&amp;').replace(pr_lt, '&lt;').replace(pr_gt, '&gt;'); } var pr_ltEnt = /&lt;/g; var pr_gtEnt = /&gt;/g; var pr_aposEnt = /&apos;/g; var pr_quotEnt = /&quot;/g; var pr_ampEnt = /&amp;/g; var pr_nbspEnt = /&nbsp;/g; function htmlToText(html) { var pos = html.indexOf('&'); if (pos < 0) { return html; } for (--pos; (pos = html.indexOf('&#', pos + 1)) >= 0; ) { var end = html.indexOf(';', pos); if (end >= 0) { var num = html.substring(pos + 3, end); var radix = 10; if (num && num.charAt(0) === 'x') { num = num.substring(1); radix = 16; } var codePoint = parseInt(num, radix); if (!isNaN(codePoint)) { html = (html.substring(0, pos) + String.fromCharCode(codePoint) + html.substring(end + 1)); } } } return html.replace(pr_ltEnt, '<').replace(pr_gtEnt, '>').replace(pr_aposEnt, "'").replace(pr_quotEnt, '"').replace(pr_ampEnt, '&').replace(pr_nbspEnt, ' '); } function isRawContent(node) { return 'XMP' === node.tagName; } function normalizedHtml(node, out) { switch (node.nodeType) { case 1: var name = node.tagName.toLowerCase(); out.push('<', name); for (var i = 0; i < node.attributes.length; ++i) { var attr = node.attributes[i]; if (!attr.specified) { continue; } out.push(' '); normalizedHtml(attr, out); } out.push('>'); for (var child = node.firstChild; child; child = child.nextSibling) { normalizedHtml(child, out); } if (node.firstChild || !/^(?:br|link|img)$/.test(name)) { out.push('<\/', name, '>'); } break; case 2: out.push(node.name.toLowerCase(), '="', attribToHtml(node.value), '"'); break; case 3: case 4: out.push(textToHtml(node.nodeValue)); break; } } var PR_innerHtmlWorks = null; function getInnerHtml(node) { if (null === PR_innerHtmlWorks) { var testNode = document.createElement('PRE'); testNode.appendChild(document.createTextNode('<!DOCTYPE foo PUBLIC "foo bar">\n<foo />')); PR_innerHtmlWorks = !/</.test(testNode.innerHTML); } if (PR_innerHtmlWorks) { var content = node.innerHTML; if (isRawContent(node)) { content = textToHtml(content); } return content; } var out = []; for (var child = node.firstChild; child; child = child.nextSibling) { normalizedHtml(child, out); } return out.join(''); } function makeTabExpander(tabWidth) { var SPACES = ' '; var charInLine = 0; return function(plainText) { var out = null; var pos = 0; for (var i = 0, n = plainText.length; i < n; ++i) { var ch = plainText.charAt(i); switch (ch) { case '\t': if (!out) { out = []; } out.push(plainText.substring(pos, i)); var nSpaces = tabWidth - (charInLine % tabWidth); charInLine += nSpaces; for (; nSpaces >= 0; nSpaces -= SPACES.length) { out.push(SPACES.substring(0, nSpaces)); } pos = i + 1; break; case '\n': charInLine = 0; break; default: ++charInLine; } } if (!out) { return plainText; } out.push(plainText.substring(pos)); return out.join(''); }; } var pr_chunkPattern = /(?:[^<]+|<!--[\s\S]*?-->|<!\[CDATA\[([\s\S]*?)\]\]>|<\/?[a-zA-Z][^>]*>|<)/g; var pr_commentPrefix = /^<!--/; var pr_cdataPrefix = /^<\[CDATA\[/; var pr_brPrefix = /^<br\b/i; var pr_tagNameRe = /^<(\/?)([a-zA-Z]+)/; function extractTags(s) { var matches = s.match(pr_chunkPattern); var sourceBuf = []; var sourceBufLen = 0; var extractedTags = []; if (matches) { for (var i = 0, n = matches.length; i < n; ++i) { var match = matches[i]; if (match.length > 1 && match.charAt(0) === '<') { if (pr_commentPrefix.test(match)) { continue; } if (pr_cdataPrefix.test(match)) { sourceBuf.push(match.substring(9, match.length - 3)); sourceBufLen += match.length - 12; } else if (pr_brPrefix.test(match)) { sourceBuf.push('\n'); ++sourceBufLen; } else { if (match.indexOf(PR_NOCODE) >= 0 && isNoCodeTag(match)) { var name = match.match(pr_tagNameRe)[2]; var depth = 1; end_tag_loop: for (var j = i + 1; j < n; ++j) { var name2 = matches[j].match(pr_tagNameRe); if (name2 && name2[2] === name) { if (name2[1] === '/') { if (--depth === 0) { break end_tag_loop; } } else { ++depth; } } } if (j < n) { extractedTags.push(sourceBufLen, matches.slice(i, j + 1).join('')); i = j; } else { extractedTags.push(sourceBufLen, match); } } else { extractedTags.push(sourceBufLen, match); } } } else { var literalText = htmlToText(match); sourceBuf.push(literalText); sourceBufLen += literalText.length; } } } return { source: sourceBuf.join(''), tags: extractedTags }; } function isNoCodeTag(tag) { return !!tag.replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g, ' $1="$2$3$4"').match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/); } function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) { var shortcuts = {}; (function() { var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns); for (var i = allPatterns.length; --i >= 0; ) { var patternParts = allPatterns[i]; var shortcutChars = patternParts[3]; if (shortcutChars) { for (var c = shortcutChars.length; --c >= 0; ) { shortcuts[shortcutChars.charAt(c)] = patternParts; } } } })(); var nPatterns = fallthroughStylePatterns.length; var notWs = /\S/; return function(sourceCode, opt_basePos) { opt_basePos = opt_basePos || 0; var decorations = [opt_basePos, PR_PLAIN]; var lastToken = ''; var pos = 0; var tail = sourceCode; while (tail.length) { var style; var token = null; var match; var patternParts = shortcuts[tail.charAt(0)]; if (patternParts) { match = tail.match(patternParts[1]); token = match[0]; style = patternParts[0]; } else { for (var i = 0; i < nPatterns; ++i) { patternParts = fallthroughStylePatterns[i]; var contextPattern = patternParts[2]; if (contextPattern && !contextPattern.test(lastToken)) { continue; } match = tail.match(patternParts[1]); if (match) { token = match[0]; style = patternParts[0]; break; } } if (!token) { style = PR_PLAIN; token = tail.substring(0, 1); } } decorations.push(opt_basePos + pos, style); pos += token.length; tail = tail.substring(token.length); if (style !== PR_COMMENT && notWs.test(token)) { lastToken = token; } } return decorations; }; } var PR_MARKUP_LEXER = createSimpleLexer([], [[PR_PLAIN, /^[^<]+/, null], [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/, null], [PR_COMMENT, /^<!--[\s\S]*?(?:-->|$)/, null], [PR_SOURCE, /^<\?[\s\S]*?(?:\?>|$)/, null], [PR_SOURCE, /^<%[\s\S]*?(?:%>|$)/, null], [PR_SOURCE, /^<(script|style|xmp)\b[^>]*>[\s\S]*?<\/\1\b[^>]*>/i, null], [PR_TAG, /^<\/?\w[^<>]*>/, null]]); var PR_SOURCE_CHUNK_PARTS = /^(<[^>]*>)([\s\S]*)(<\/[^>]*>)$/; function tokenizeMarkup(source) { var decorations = PR_MARKUP_LEXER(source); for (var i = 0; i < decorations.length; i += 2) { if (decorations[i + 1] === PR_SOURCE) { var start, end; start = decorations[i]; end = i + 2 < decorations.length ? decorations[i + 2] : source.length; var sourceChunk = source.substring(start, end); var match = sourceChunk.match(PR_SOURCE_CHUNK_PARTS); if (match) { decorations.splice(i, 2, start, PR_TAG, start + match[1].length, PR_SOURCE, start + match[1].length + (match[2] || '').length, PR_TAG); } } } return decorations; } var PR_TAG_LEXER = createSimpleLexer([[PR_ATTRIB_VALUE, /^\'[^\']*(?:\'|$)/, null, "'"], [PR_ATTRIB_VALUE, /^\"[^\"]*(?:\"|$)/, null, '"'], [PR_PUNCTUATION, /^[<>\/=]+/, null, '<>/=']], [[PR_TAG, /^[\w:\-]+/, /^</], [PR_ATTRIB_VALUE, /^[\w\-]+/, /^=/], [PR_ATTRIB_NAME, /^[\w:\-]+/, null], [PR_PLAIN, /^\s+/, null, ' \t\r\n']]); function splitTagAttributes(source, decorations) { for (var i = 0; i < decorations.length; i += 2) { var style = decorations[i + 1]; if (style === PR_TAG) { var start, end; start = decorations[i]; end = i + 2 < decorations.length ? decorations[i + 2] : source.length; var chunk = source.substring(start, end); var subDecorations = PR_TAG_LEXER(chunk, start); spliceArrayInto(subDecorations, decorations, i, 2); i += subDecorations.length - 2; } } return decorations; } function sourceDecorator(options) { var shortcutStylePatterns = [], fallthroughStylePatterns = []; if (options.tripleQuotedStrings) { shortcutStylePatterns.push([PR_STRING, /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/, null, '\'"']); } else if (options.multiLineStrings) { shortcutStylePatterns.push([PR_STRING, /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/, null, '\'"`']); } else { shortcutStylePatterns.push([PR_STRING, /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/, null, '"\'']); } fallthroughStylePatterns.push([PR_PLAIN, /^(?:[^\'\"\`\/\#]+)/, null, ' \r\n']); if (options.hashComments) { shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']); } if (options.cStyleComments) { fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]); fallthroughStylePatterns.push([PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]); } if (options.regexLiterals) { var REGEX_LITERAL = ('^/(?=[^/*])' + '(?:[^/\\x5B\\x5C]' + '|\\x5C[\\s\\S]' + '|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+' + '(?:/|$)'); fallthroughStylePatterns.push([PR_STRING, new RegExp(REGEX_LITERAL), REGEXP_PRECEDER_PATTERN]); } var keywords = wordSet(options.keywords); options = null; var splitStringAndCommentTokens = createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns); var styleLiteralIdentifierPuncRecognizer = createSimpleLexer([], [[PR_PLAIN, /^\s+/, null, ' \r\n'], [PR_PLAIN, /^[a-z_$@][a-z_$@0-9]*/i, null], [PR_LITERAL, /^0x[a-f0-9]+[a-z]/i, null], [PR_LITERAL, /^(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d+)(?:e[+\-]?\d+)?[a-z]*/i, null, '123456789'], [PR_PUNCTUATION, /^[^\s\w\.$@]+/, null]]); function splitNonStringNonCommentTokens(source, decorations) { for (var i = 0; i < decorations.length; i += 2) { var style = decorations[i + 1]; if (style === PR_PLAIN) { var start, end, chunk, subDecs; start = decorations[i]; end = i + 2 < decorations.length ? decorations[i + 2] : source.length; chunk = source.substring(start, end); subDecs = styleLiteralIdentifierPuncRecognizer(chunk, start); for (var j = 0, m = subDecs.length; j < m; j += 2) { var subStyle = subDecs[j + 1]; if (subStyle === PR_PLAIN) { var subStart = subDecs[j]; var subEnd = j + 2 < m ? subDecs[j + 2] : chunk.length; var token = source.substring(subStart, subEnd); if (token === '.') { subDecs[j + 1] = PR_PUNCTUATION; } else if (token in keywords) { subDecs[j + 1] = PR_KEYWORD; } else if (/^@?[A-Z][A-Z$]*[a-z][A-Za-z$]*$/.test(token)) { subDecs[j + 1] = token.charAt(0) === '@' ? PR_LITERAL : PR_TYPE; } } } spliceArrayInto(subDecs, decorations, i, 2); i += subDecs.length - 2; } } return decorations; } return function(sourceCode) { var decorations = splitStringAndCommentTokens(sourceCode); decorations = splitNonStringNonCommentTokens(sourceCode, decorations); return decorations; }; } var decorateSource = sourceDecorator({ keywords: ALL_KEYWORDS, hashComments: true, cStyleComments: true, multiLineStrings: true, regexLiterals: true }); function splitSourceNodes(source, decorations) { for (var i = 0; i < decorations.length; i += 2) { var style = decorations[i + 1]; if (style === PR_SOURCE) { var start, end; start = decorations[i]; end = i + 2 < decorations.length ? decorations[i + 2] : source.length; var subDecorations = decorateSource(source.substring(start, end)); for (var j = 0, m = subDecorations.length; j < m; j += 2) { subDecorations[j] += start; } spliceArrayInto(subDecorations, decorations, i, 2); i += subDecorations.length - 2; } } return decorations; } function splitSourceAttributes(source, decorations) { var nextValueIsSource = false; for (var i = 0; i < decorations.length; i += 2) { var style = decorations[i + 1]; var start, end; if (style === PR_ATTRIB_NAME) { start = decorations[i]; end = i + 2 < decorations.length ? decorations[i + 2] : source.length; nextValueIsSource = /^on|^style$/i.test(source.substring(start, end)); } else if (style === PR_ATTRIB_VALUE) { if (nextValueIsSource) { start = decorations[i]; end = i + 2 < decorations.length ? decorations[i + 2] : source.length; var attribValue = source.substring(start, end); var attribLen = attribValue.length; var quoted = (attribLen >= 2 && /^[\"\']/.test(attribValue) && attribValue.charAt(0) === attribValue.charAt(attribLen - 1)); var attribSource; var attribSourceStart; var attribSourceEnd; if (quoted) { attribSourceStart = start + 1; attribSourceEnd = end - 1; attribSource = attribValue; } else { attribSourceStart = start + 1; attribSourceEnd = end - 1; attribSource = attribValue.substring(1, attribValue.length - 1); } var attribSourceDecorations = decorateSource(attribSource); for (var j = 0, m = attribSourceDecorations.length; j < m; j += 2) { attribSourceDecorations[j] += attribSourceStart; } if (quoted) { attribSourceDecorations.push(attribSourceEnd, PR_ATTRIB_VALUE); spliceArrayInto(attribSourceDecorations, decorations, i + 2, 0); } else { spliceArrayInto(attribSourceDecorations, decorations, i, 2); } } nextValueIsSource = false; } } return decorations; } function decorateMarkup(sourceCode) { var decorations = tokenizeMarkup(sourceCode); decorations = splitTagAttributes(sourceCode, decorations); decorations = splitSourceNodes(sourceCode, decorations); decorations = splitSourceAttributes(sourceCode, decorations); return decorations; } function recombineTagsAndDecorations(sourceText, extractedTags, decorations) { var html = []; var outputIdx = 0; var openDecoration = null; var currentDecoration = null; var tagPos = 0; var decPos = 0; var tabExpander = makeTabExpander(PR_TAB_WIDTH); var adjacentSpaceRe = /([\r\n ]) /g; var startOrSpaceRe = /(^| ) /gm; var newlineRe = /\r\n?|\n/g; var trailingSpaceRe = /[ \r\n]$/; var lastWasSpace = true; function emitTextUpTo(sourceIdx) { if (sourceIdx > outputIdx) { if (openDecoration && openDecoration !== currentDecoration) { html.push('</span>'); openDecoration = null; } if (!openDecoration && currentDecoration) { openDecoration = currentDecoration; html.push('<span class="', openDecoration, '">'); } var htmlChunk = textToHtml(tabExpander(sourceText.substring(outputIdx, sourceIdx))).replace(lastWasSpace ? startOrSpaceRe : adjacentSpaceRe, '$1&nbsp;'); lastWasSpace = trailingSpaceRe.test(htmlChunk); html.push(htmlChunk.replace(newlineRe, '<br />')); outputIdx = sourceIdx; } } while (true) { var outputTag; if (tagPos < extractedTags.length) { if (decPos < decorations.length) { outputTag = extractedTags[tagPos] <= decorations[decPos]; } else { outputTag = true; } } else { outputTag = false; } if (outputTag) { emitTextUpTo(extractedTags[tagPos]); if (openDecoration) { html.push('</span>'); openDecoration = null; } html.push(extractedTags[tagPos + 1]); tagPos += 2; } else if (decPos < decorations.length) { emitTextUpTo(decorations[decPos]); currentDecoration = decorations[decPos + 1]; decPos += 2; } else { break; } } emitTextUpTo(sourceText.length); if (openDecoration) { html.push('</span>'); } return html.join(''); } var langHandlerRegistry = {}; function registerLangHandler(handler, fileExtensions) { for (var i = fileExtensions.length; --i >= 0; ) { var ext = fileExtensions[i]; if (!langHandlerRegistry.hasOwnProperty(ext)) { langHandlerRegistry[ext] = handler; } else if ('console' in window) { console.log('cannot override language handler %s', ext); } } } registerLangHandler(decorateSource, ['default-code']); registerLangHandler(decorateMarkup, ['default-markup', 'html', 'htm', 'xhtml', 'xml', 'xsl']); registerLangHandler(sourceDecorator({ keywords: CPP_KEYWORDS, hashComments: true, cStyleComments: true }), ['c', 'cc', 'cpp', 'cs', 'cxx', 'cyc']); registerLangHandler(sourceDecorator({ keywords: JAVA_KEYWORDS, cStyleComments: true }), ['java']); registerLangHandler(sourceDecorator({ keywords: SH_KEYWORDS, hashComments: true, multiLineStrings: true }), ['bsh', 'csh', 'sh']); registerLangHandler(sourceDecorator({ keywords: PYTHON_KEYWORDS, hashComments: true, multiLineStrings: true, tripleQuotedStrings: true }), ['cv', 'py']); registerLangHandler(sourceDecorator({ keywords: PERL_KEYWORDS, hashComments: true, multiLineStrings: true, regexLiterals: true }), ['perl', 'pl', 'pm']); registerLangHandler(sourceDecorator({ keywords: RUBY_KEYWORDS, hashComments: true, multiLineStrings: true, regexLiterals: true }), ['rb']); registerLangHandler(sourceDecorator({ keywords: JSCRIPT_KEYWORDS, cStyleComments: true, regexLiterals: true }), ['js']); function prettyPrintOne(sourceCodeHtml, opt_langExtension) { try { var sourceAndExtractedTags = extractTags(sourceCodeHtml); var source = sourceAndExtractedTags.source; var extractedTags = sourceAndExtractedTags.tags; if (!langHandlerRegistry.hasOwnProperty(opt_langExtension)) { opt_langExtension = /^\s*</.test(source) ? 'default-markup' : 'default-code'; } var decorations = langHandlerRegistry[opt_langExtension].call({}, source); return recombineTagsAndDecorations(source, extractedTags, decorations); } catch (e) { if ('console' in window) { console.log(e); console.trace(); } return sourceCodeHtml; } } function prettyPrint(opt_whenDone) { var isIE6 = _pr_isIE6(); var codeSegments = [document.getElementsByTagName('pre'), document.getElementsByTagName('code'), document.getElementsByTagName('xmp')]; var elements = []; for (var i = 0; i < codeSegments.length; ++i) { for (var j = 0; j < codeSegments[i].length; ++j) { elements.push(codeSegments[i][j]); } } codeSegments = null; var k = 0; function doWork() { var endTime = (PR_SHOULD_USE_CONTINUATION ? new Date().getTime() + 250 : Infinity); for (; k < elements.length && new Date().getTime() < endTime; k++) { var cs = elements[k]; if (cs.className && cs.className.indexOf('prettyprint') >= 0) { var langExtension = cs.className.match(/\blang-(\w+)\b/); if (langExtension) { langExtension = langExtension[1]; } var nested = false; for (var p = cs.parentNode; p; p = p.parentNode) { if ((p.tagName === 'pre' || p.tagName === 'code' || p.tagName === 'xmp') && p.className && p.className.indexOf('prettyprint') >= 0) { nested = true; break; } } if (!nested) { var content = getInnerHtml(cs); content = content.replace(/(?:\r\n?|\n)$/, ''); var newContent = prettyPrintOne(content, langExtension); if (!isRawContent(cs)) { cs.innerHTML = newContent; } else { var pre = document.createElement('PRE'); for (var i = 0; i < cs.attributes.length; ++i) { var a = cs.attributes[i]; if (a.specified) { var aname = a.name.toLowerCase(); if (aname === 'class') { pre.className = a.value; } else { pre.setAttribute(a.name, a.value); } } } pre.innerHTML = newContent; cs.parentNode.replaceChild(pre, cs); cs = pre; } if (isIE6 && cs.tagName === 'PRE') { var lineBreaks = cs.getElementsByTagName('br'); for (var j = lineBreaks.length; --j >= 0; ) { var lineBreak = lineBreaks[j]; lineBreak.parentNode.replaceChild(document.createTextNode('\r\n'), lineBreak); } } } } } if (k < elements.length) { setTimeout(doWork, 250); } else if (opt_whenDone) { opt_whenDone(); } } doWork(); } window['PR_normalizedHtml'] = normalizedHtml; window['prettyPrintOne'] = prettyPrintOne; window['prettyPrint'] = prettyPrint; window['PR'] = { 'createSimpleLexer': createSimpleLexer, 'registerLangHandler': registerLangHandler, 'sourceDecorator': sourceDecorator, 'PR_ATTRIB_NAME': PR_ATTRIB_NAME, 'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE, 'PR_COMMENT': PR_COMMENT, 'PR_DECLARATION': PR_DECLARATION, 'PR_KEYWORD': PR_KEYWORD, 'PR_LITERAL': PR_LITERAL, 'PR_NOCODE': PR_NOCODE, 'PR_PLAIN': PR_PLAIN, 'PR_PUNCTUATION': PR_PUNCTUATION, 'PR_SOURCE': PR_SOURCE, 'PR_STRING': PR_STRING, 'PR_TAG': PR_TAG, 'PR_TYPE': PR_TYPE }; })();
diff --git a/askbot/skins/common/media/js/se_hilite.js b/askbot/media/js/se_hilite.js
index 42e99c8e..42e99c8e 100644
--- a/askbot/skins/common/media/js/se_hilite.js
+++ b/askbot/media/js/se_hilite.js
diff --git a/askbot/skins/common/media/js/se_hilite_src.js b/askbot/media/js/se_hilite_src.js
index b604f156..b604f156 100644
--- a/askbot/skins/common/media/js/se_hilite_src.js
+++ b/askbot/media/js/se_hilite_src.js
diff --git a/askbot/media/js/tag_moderation.js b/askbot/media/js/tag_moderation.js
new file mode 100644
index 00000000..31e05e37
--- /dev/null
+++ b/askbot/media/js/tag_moderation.js
@@ -0,0 +1,217 @@
+/**
+ * @constructor
+ * base class for two tag moderators - per thread
+ * and per tag
+ */
+var TagModerator = function() {
+ WrappedElement.call(this);
+ this._tagId = undefined;
+ this._threadId = undefined;
+};
+inherits(TagModerator, WrappedElement);
+
+TagModerator.prototype.setTagId = function(id) {
+ this._tagId = id;
+};
+
+TagModerator.prototype.getTagId = function() {
+ return this._tagId;
+};
+
+TagModerator.prototype.setThreadId = function(id) {
+ this._threadId = id;
+};
+
+TagModerator.prototype.getThreadId = function() {
+ return this._threadId;
+};
+
+TagModerator.prototype.afterActionHandler = function() {
+ throw "Implement me";
+};
+
+/**
+ * @return {function}
+ * the returned function makes an ajax post
+ * to the moderate tag url. thread id is added
+ * as parameter to data, if defined.
+ */
+TagModerator.prototype.getHandler = function(action) {
+ var me = this;
+ return function() {
+ var data = {
+ action: action,
+ tag_id: me.getTagId()
+ };
+ if (me.getThreadId() !== undefined) {
+ data['thread_id'] = me.getThreadId();
+ }
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ url: askbot['urls']['moderateSuggestedTag'],
+ cache: false,
+ data: data,
+ success: function(data) {
+ if (data['success']) {
+ $(me.getElement()).fadeOut();
+ me.afterActionHandler();
+ } else {
+ showMessage($(me.getElement()), data['error']);
+ }
+ }
+ });
+ };
+};
+/**
+ * @constructor
+ */
+var PerThreadTagModerator = function() {
+ TagModerator.call(this);
+ this._tagId = undefined;
+ this._threadId = undefined;
+ this._parent = undefined;
+};
+inherits(PerThreadTagModerator, TagModerator);
+
+PerThreadTagModerator.prototype.setParent = function(thing) {
+ this._parent = thing;
+};
+
+PerThreadTagModerator.prototype.afterActionHandler = function() {
+ var ancestor = this._parent;
+ ancestor.removeChild(this);
+ var childCount = ancestor.getChildCount();
+ if (childCount == 1) {
+ ancestor.hideButtons();
+ this.dispose();
+ } else if (childCount == 0) {
+ var table = $('.suggested-tags-table');
+ table.before($('<p>' + gettext('No suggested tags left') + '</p>'));
+ table.remove();
+ ancestor.dispose();
+ } else {
+ this.dispose();
+ }
+};
+
+PerThreadTagModerator.prototype.decorate = function(element) {
+ this._element = element;
+ this._threadId = element.data('threadId');
+
+ var acceptBtn = element.find('button.accept');
+ var rejectBtn = element.find('button.reject');
+
+ var mouseEnterHandler = function() {
+ acceptBtn.fadeIn('fast');
+ rejectBtn.fadeIn('fast');
+ return false;
+ };
+ var mouseLeaveHandler = function() {
+ acceptBtn.stop().hide();
+ rejectBtn.stop().hide();
+ return false;
+ };
+
+ element.mouseenter(mouseEnterHandler);
+ element.mouseleave(mouseLeaveHandler);
+
+ setupButtonEventHandlers(acceptBtn, this.getHandler('accept'));
+ setupButtonEventHandlers(rejectBtn, this.getHandler('reject'));
+ //threadInfo.hover(mouseEnterHandler, mouseLeaveHandler);
+ //element.hover(mouseEnterHandler, mouseLeaveHandler);
+};
+
+/**
+ * @constructor
+ */
+var AllThreadsTagModerator = function() {
+ TagModerator.call(this);
+ this._tag_entry_element = undefined;
+ this._children = [];
+};
+inherits(AllThreadsTagModerator, TagModerator);
+
+AllThreadsTagModerator.prototype.addChild = function(child) {
+ this._children.push(child);
+};
+
+AllThreadsTagModerator.prototype.getChildCount = function() {
+ return this._children.length;
+};
+
+AllThreadsTagModerator.prototype.removeChild = function(child) {
+ var idx = $.inArray(child, this._children);
+ if (idx == -1) {
+ return;
+ }
+ this._children.splice(idx, 1);
+};
+
+AllThreadsTagModerator.prototype.hideButtons = function() {
+ this._acceptBtn.hide();
+ this._rejectBtn.hide();
+};
+
+AllThreadsTagModerator.prototype.setTagEntryElement = function(element) {
+ this._tag_entry_element = element;
+};
+
+AllThreadsTagModerator.prototype.afterActionHandler = function() {
+ var me = this;
+ this._tag_entry_element.fadeOut('fast');
+ this._element.fadeOut('fast', function() { me.dispose() });
+};
+
+AllThreadsTagModerator.prototype.dispose = function() {
+ this._tag_entry_element.fadeOut('fast', function() {
+ $.each(this._children, function(idx, child) {
+ child.dispose();
+ });
+ });
+ AllThreadsTagModerator.superClass_.dispose.call(this);
+};
+
+AllThreadsTagModerator.prototype.decorate = function(element) {
+ this._element = element;
+
+ //var controls = new TagModerationControls();
+ //controls.setParent(this);
+
+ //var tagId = $(element).data('tagId');
+ //controls.setTagId(tagId);
+
+ var threads_data = [];
+ $(element).find('.thread-info').each(function(idx, element) {
+ var id = $(element).data('threadId');
+ var title = $(element).data('threadTitle');
+ threads_data.push([id, title]);
+ });
+ var acceptBtn = element.find('button.accept');
+ var rejectBtn = element.find('button.reject');
+ setupButtonEventHandlers(acceptBtn, this.getHandler('accept'));
+ setupButtonEventHandlers(rejectBtn, this.getHandler('reject'));
+ this._acceptBtn = acceptBtn;
+ this._rejectBtn = rejectBtn;
+};
+
+(function() {
+ $('.suggested-tag-row').each(function(idx, element) {
+ var tagEntry = $(element);
+ var tagId = tagEntry.data('tagId');
+
+ var tagMod = new AllThreadsTagModerator();
+ tagMod.decorate(tagEntry.next());
+ tagMod.setTagId(tagId);
+ tagMod.setTagEntryElement(tagEntry);
+
+ tagEntry.find('.thread-info').each(function(idx, element) {
+ var threadMod = new PerThreadTagModerator();
+ threadMod.setTagId(tagId);
+ threadMod.setParent(tagMod);
+ tagMod.addChild(threadMod);
+ threadMod.decorate($(element));
+ });
+
+ });
+})();
diff --git a/askbot/media/js/tag_selector.js b/askbot/media/js/tag_selector.js
new file mode 100644
index 00000000..790acce2
--- /dev/null
+++ b/askbot/media/js/tag_selector.js
@@ -0,0 +1,402 @@
+var TagDetailBox = function(box_type){
+ WrappedElement.call(this);
+ this.box_type = box_type;
+ this._is_blank = true;
+ this._tags = new Array();
+ this.wildcard = undefined;
+};
+inherits(TagDetailBox, WrappedElement);
+
+TagDetailBox.prototype.createDom = function(){
+ this._element = this.makeElement('div');
+ this._element.addClass('wildcard-tags');
+ this._headline = this.makeElement('p');
+ this._headline.html(gettext('Tag "<span></span>" matches:'));
+ this._element.append(this._headline);
+ this._tag_list_element = this.makeElement('ul');
+ this._tag_list_element.addClass('tags');
+ this._element.append(this._tag_list_element);
+ this._footer = this.makeElement('p');
+ this._footer.css('clear', 'left');
+ this._element.append(this._footer);
+ this._element.hide();
+};
+
+TagDetailBox.prototype.belongsTo = function(wildcard){
+ return (this.wildcard === wildcard);
+};
+
+TagDetailBox.prototype.isBlank = function(){
+ return this._is_blank;
+};
+
+TagDetailBox.prototype.clear = function(){
+ if (this.isBlank()){
+ return;
+ }
+ this._is_blank = true;
+ this.getElement().hide();
+ this.wildcard = null;
+ $.each(this._tags, function(idx, item){
+ item.dispose();
+ });
+ this._tags = new Array();
+};
+
+TagDetailBox.prototype.loadTags = function(wildcard, callback){
+ var me = this;
+ $.ajax({
+ type: 'GET',
+ dataType: 'json',
+ cache: false,
+ url: askbot['urls']['get_tags_by_wildcard'],
+ data: { wildcard: wildcard },
+ success: callback,
+ failure: function(){ me._loading = false; }
+ });
+};
+
+TagDetailBox.prototype.renderFor = function(wildcard){
+ var me = this;
+ if (this._loading === true){
+ return;
+ }
+ this._loading = true;
+ this.loadTags(
+ wildcard,
+ function(data, text_status, xhr){
+ me._tag_names = data['tag_names'];
+ if (data['tag_count'] > 0){
+ var wildcard_display = wildcard.replace(/\*$/, '&#10045;');
+ me._headline.find('span').html(wildcard_display);
+ $.each(me._tag_names, function(idx, name){
+ var tag = new Tag();
+ tag.setName(name);
+ tag.setUrlParams(name)
+ //tag.setLinkable(false);
+ me._tags.push(tag);
+ me._tag_list_element.append(tag.getElement());
+ });
+ me._is_blank = false;
+ me.wildcard = wildcard;
+ var tag_count = data['tag_count'];
+ if (tag_count > 20){
+ var fmts = gettext('and %s more, not shown...');
+ var footer_text = interpolate(fmts, [tag_count - 20]);
+ me._footer.html(footer_text);
+ me._footer.show();
+ } else {
+ me._footer.hide();
+ }
+ me._element.show();
+ } else {
+ me.clear();
+ }
+ me._loading = false;
+ }
+ );
+}
+
+function pickedTags(){
+
+ var interestingTags = {};
+ var ignoredTags = {};
+ var subscribedTags = {};
+ var interestingTagDetailBox = new TagDetailBox('interesting');
+ var ignoredTagDetailBox = new TagDetailBox('ignored');
+ var subscribedTagDetailBox = new TagDetailBox('subscribed');
+
+ var sendAjax = function(tagnames, reason, action, callback){
+ var url = '';
+ if (action == 'add') {
+ if (reason == 'good') {
+ url = askbot['urls']['mark_interesting_tag'];
+ } else if (reason == 'bad') {
+ url = askbot['urls']['mark_ignored_tag'];
+ } else {
+ url = askbot['urls']['mark_subscribed_tag'];
+ }
+ }
+ else {
+ url = askbot['urls']['unmark_tag'];
+ }
+
+ var data = JSON.stringify({
+ tagnames: tagnames,
+ reason: reason
+ });
+ var call_settings = {
+ type:'POST',
+ url:url,
+ data: data,
+ dataType: 'json'
+ };
+ if (callback !== false){
+ call_settings.success = callback;
+ }
+ $.ajax(call_settings);
+ };
+
+ var unpickTag = function(from_target, tagname, reason, send_ajax){
+ //send ajax request to delete tag
+ var deleteTagLocally = function(){
+ from_target[tagname].remove();
+ delete from_target[tagname];
+ };
+ if (send_ajax){
+ sendAjax(
+ [tagname],
+ reason,
+ 'remove',
+ function(){
+ deleteTagLocally();
+ liveSearch.refresh();
+ }
+ );
+ }
+ else {
+ deleteTagLocally();
+ }
+ };
+
+ var getTagList = function(reason){
+ var base_selector = '.marked-tags';
+ if (reason === 'good') {
+ var extra_selector = '.interesting';
+ } else if (reason === 'bad') {
+ var extra_selector = '.ignored';
+ } else if (reason === 'subscribed') {
+ var extra_selector = '.subscribed';
+ }
+ return $(base_selector + extra_selector);
+ };
+
+ var getWildcardTagDetailBox = function(reason){
+ if (reason === 'good') {
+ return interestingTagDetailBox;
+ } else if (reason === 'bad') {
+ return ignoredTagDetailBox;
+ } else if (reason === 'subscribed') {
+ return subscribedTagDetailBox;
+ }
+ };
+
+ var handleWildcardTagClick = function(tag_name, reason){
+ var detail_box = getWildcardTagDetailBox(reason);
+ var tag_box = getTagList(reason);
+ if (detail_box.isBlank()){
+ detail_box.renderFor(tag_name);
+ } else if (detail_box.belongsTo(tag_name)){
+ detail_box.clear();//toggle off
+ } else {
+ detail_box.clear();//redraw with new data
+ detail_box.renderFor(tag_name);
+ }
+ if (!detail_box.inDocument()){
+ tag_box.after(detail_box.getElement());
+ detail_box.enterDocument();
+ }
+ };
+
+ var renderNewTags = function(
+ clean_tag_names,
+ reason,
+ to_target,
+ to_tag_container
+ ){
+ $.each(clean_tag_names, function(idx, tag_name){
+ var tag = new Tag();
+ tag.setName(tag_name);
+ tag.setDeletable(true);
+
+ if (/\*$/.test(tag_name)){
+ tag.setLinkable(false);
+ var detail_box = getWildcardTagDetailBox(reason);
+ tag.setHandler(function(){
+ handleWildcardTagClick(tag_name, reason);
+ if (detail_box.belongsTo(tag_name)){
+ detail_box.clear();
+ }
+ });
+ var delete_handler = function(){
+ unpickTag(to_target, tag_name, reason, true);
+ if (detail_box.belongsTo(tag_name)){
+ detail_box.clear();
+ }
+ }
+ } else {
+ var delete_handler = function(){
+ unpickTag(to_target, tag_name, reason, true);
+ }
+ }
+
+ tag.setDeleteHandler(delete_handler);
+ var tag_element = tag.getElement();
+ to_tag_container.append(tag_element);
+ to_target[tag_name] = tag_element;
+ });
+ };
+
+ var handlePickedTag = function(reason){
+ var to_target = interestingTags;
+ var from_target = ignoredTags;
+ var to_tag_container;
+ if (reason === 'bad') {
+ var input_sel = '#ignoredTagInput';
+ to_target = ignoredTags;
+ from_target = interestingTags;
+ to_tag_container = $('div .tags.ignored');
+ } else if (reason === 'good') {
+ var input_sel = '#interestingTagInput';
+ to_tag_container = $('div .tags.interesting');
+ } else if (reason === 'subscribed') {
+ var input_sel = '#subscribedTagInput';
+ to_target = subscribedTags;
+ to_tag_container = $('div .tags.subscribed');
+ } else {
+ return;
+ }
+
+ var tags_input =$.trim($(input_sel).attr('value'));
+ if (tags_input === '') {
+ return;
+ }
+ var tagnames = getUniqueWords(tags_input);
+
+ if (reason !== 'subscribed') {//for "subscribed" we do not remove
+ $.each(tagnames, function(idx, tagname) {
+ if (tagname in from_target) {
+ unpickTag(from_target, tagname, reason, false);
+ }
+ });
+ }
+
+ var clean_tagnames = [];
+ $.each(tagnames, function(idx, tagname){
+ if (!(tagname in to_target)){
+ clean_tagnames.push(tagname);
+ }
+ });
+
+ if (clean_tagnames.length > 0){
+ //send ajax request to pick this tag
+
+ sendAjax(
+ clean_tagnames,
+ reason,
+ 'add',
+ function(){
+ renderNewTags(
+ clean_tagnames,
+ reason,
+ to_target,
+ to_tag_container
+ );
+ $(input_sel).val('');
+ liveSearch.refresh();
+ }
+ );
+ }
+ };
+
+ var collectPickedTags = function(section){
+ if (section === 'interesting') {
+ var reason = 'good';
+ var tag_store = interestingTags;
+ } else if (section === 'ignored') {
+ var reason = 'bad';
+ var tag_store = ignoredTags;
+ } else if (section === 'subscribed') {
+ var reason = 'subscribed';
+ var tag_store = subscribedTags;
+ } else {
+ return;
+ }
+ $('.' + section + '.tags.marked-tags .tag-left').each(
+ function(i,item){
+ var tag = new Tag();
+ tag.decorate($(item));
+ tag.setDeleteHandler(function(){
+ unpickTag(
+ tag_store,
+ tag.getName(),
+ reason,
+ true
+ )
+ });
+ if (tag.isWildcard()){
+ tag.setHandler(function(){
+ handleWildcardTagClick(tag.getName(), reason)
+ });
+ }
+ tag_store[tag.getName()] = $(item);
+ }
+ );
+ };
+
+ var setupTagFilterControl = function(control_type){
+ $('#' + control_type + 'TagFilterControl input')
+ .unbind('click')
+ .click(function(){
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ cache: false,
+ url: askbot['urls']['set_tag_filter_strategy'],
+ data: {
+ filter_type: control_type,
+ filter_value: $(this).val()
+ },
+ success: function(){
+ liveSearch.refresh();
+ }
+ });
+ });
+ };
+
+ var getResultCallback = function(reason){
+ return function(){
+ handlePickedTag(reason);
+ };
+ };
+
+ return {
+ init: function(){
+ collectPickedTags('interesting');
+ collectPickedTags('ignored');
+ collectPickedTags('subscribed');
+ setupTagFilterControl('display');
+ setupTagFilterControl('email');
+ var ac = new AutoCompleter({
+ url: askbot['urls']['get_tag_list'],
+ preloadData: true,
+ minChars: 1,
+ useCache: true,
+ matchInside: true,
+ maxCacheLength: 100,
+ delay: 10
+ });
+
+
+ var interestingTagAc = $.extend(true, {}, ac);
+ interestingTagAc.decorate($('#interestingTagInput'));
+ interestingTagAc.setOption('onItemSelect', getResultCallback('good'));
+
+ var ignoredTagAc = $.extend(true, {}, ac);
+ ignoredTagAc.decorate($('#ignoredTagInput'));
+ ignoredTagAc.setOption('onItemSelect', getResultCallback('bad'));
+
+ var subscribedTagAc = $.extend(true, {}, ac);
+ subscribedTagAc.decorate($('#subscribedTagInput'));
+ subscribedTagAc.setOption('onItemSelect', getResultCallback('subscribed'));
+
+ $("#interestingTagAdd").click(getResultCallback('good'));
+ $("#ignoredTagAdd").click(getResultCallback('bad'));
+ $("#subscribedTagAdd").click(getResultCallback('subscribed'));
+ }
+ };
+}
+
+$(document).ready( function(){
+ pickedTags().init();
+});
diff --git a/askbot/media/js/tinymce/langs/en.js b/askbot/media/js/tinymce/langs/en.js
new file mode 100644
index 00000000..19324f74
--- /dev/null
+++ b/askbot/media/js/tinymce/langs/en.js
@@ -0,0 +1 @@
+tinyMCE.addI18n({en:{common:{"more_colors":"More Colors...","invalid_data":"Error: Invalid values entered, these are marked in red.","popup_blocked":"Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.","clipboard_no_support":"Currently not supported by your browser, use keyboard shortcuts instead.","clipboard_msg":"Copy/Cut/Paste is not available in Mozilla and Firefox.\nDo you want more information about this issue?","not_set":"-- Not Set --","class_name":"Class",browse:"Browse",close:"Close",cancel:"Cancel",update:"Update",insert:"Insert",apply:"Apply","edit_confirm":"Do you want to use the WYSIWYG mode for this textarea?","invalid_data_number":"{#field} must be a number","invalid_data_min":"{#field} must be a number greater than {#min}","invalid_data_size":"{#field} must be a number or percentage",value:"(value)"},contextmenu:{full:"Full",right:"Right",center:"Center",left:"Left",align:"Alignment"},insertdatetime:{"day_short":"Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun","day_long":"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday","months_short":"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec","months_long":"January,February,March,April,May,June,July,August,September,October,November,December","inserttime_desc":"Insert Time","insertdate_desc":"Insert Date","time_fmt":"%H:%M:%S","date_fmt":"%Y-%m-%d"},print:{"print_desc":"Print"},preview:{"preview_desc":"Preview"},directionality:{"rtl_desc":"Direction Right to Left","ltr_desc":"Direction Left to Right"},layer:{content:"New layer...","absolute_desc":"Toggle Absolute Positioning","backward_desc":"Move Backward","forward_desc":"Move Forward","insertlayer_desc":"Insert New Layer"},save:{"save_desc":"Save","cancel_desc":"Cancel All Changes"},nonbreaking:{"nonbreaking_desc":"Insert Non-Breaking Space Character"},iespell:{download:"ieSpell not detected. Do you want to install it now?","iespell_desc":"Check Spelling"},advhr:{"delta_height":"","delta_width":"","advhr_desc":"Insert Horizontal Line"},emotions:{"delta_height":"","delta_width":"","emotions_desc":"Emotions"},searchreplace:{"replace_desc":"Find/Replace","delta_width":"","delta_height":"","search_desc":"Find"},advimage:{"delta_width":"","image_desc":"Insert/Edit Image","delta_height":""},advlink:{"delta_height":"","delta_width":"","link_desc":"Insert/Edit Link"},xhtmlxtras:{"attribs_delta_height":"","attribs_delta_width":"","ins_delta_height":"","ins_delta_width":"","del_delta_height":"","del_delta_width":"","acronym_delta_height":"","acronym_delta_width":"","abbr_delta_height":"","abbr_delta_width":"","cite_delta_height":"","cite_delta_width":"","attribs_desc":"Insert/Edit Attributes","ins_desc":"Insertion","del_desc":"Deletion","acronym_desc":"Acronym","abbr_desc":"Abbreviation","cite_desc":"Citation"},style:{"delta_height":"","delta_width":"",desc:"Edit CSS Style"},paste:{"plaintext_mode_stick":"Paste is now in plain text mode. Click again to toggle back to regular paste mode.","plaintext_mode":"Paste is now in plain text mode. Click again to toggle back to regular paste mode. After you paste something you will be returned to regular paste mode.","selectall_desc":"Select All","paste_word_desc":"Paste from Word","paste_text_desc":"Paste as Plain Text"},"paste_dlg":{"word_title":"Use Ctrl+V on your keyboard to paste the text into the window.","text_linebreaks":"Keep Linebreaks","text_title":"Use Ctrl+V on your keyboard to paste the text into the window."},table:{"merge_cells_delta_height":"","merge_cells_delta_width":"","table_delta_height":"","table_delta_width":"","cellprops_delta_height":"","cellprops_delta_width":"","rowprops_delta_height":"","rowprops_delta_width":"",cell:"Cell",col:"Column",row:"Row",del:"Delete Table","copy_row_desc":"Copy Table Row","cut_row_desc":"Cut Table Row","paste_row_after_desc":"Paste Table Row After","paste_row_before_desc":"Paste Table Row Before","props_desc":"Table Properties","cell_desc":"Table Cell Properties","row_desc":"Table Row Properties","merge_cells_desc":"Merge Table Cells","split_cells_desc":"Split Merged Table Cells","delete_col_desc":"Delete Column","col_after_desc":"Insert Column After","col_before_desc":"Insert Column Before","delete_row_desc":"Delete Row","row_after_desc":"Insert Row After","row_before_desc":"Insert Row Before",desc:"Insert/Edit Table"},autosave:{"warning_message":"If you restore the saved content, you will lose all the content that is currently in the editor.\n\nAre you sure you want to restore the saved content?","restore_content":"Restore auto-saved content.","unload_msg":"The changes you made will be lost if you navigate away from this page."},fullscreen:{desc:"Toggle Full Screen Mode"},media:{"delta_height":"","delta_width":"",edit:"Edit Embedded Media",desc:"Insert/Edit Embedded Media"},fullpage:{desc:"Document Properties","delta_width":"","delta_height":""},template:{desc:"Insert Predefined Template Content"},visualchars:{desc:"Show/Hide Visual Control Characters"},spellchecker:{desc:"Toggle Spell Checker",menu:"Spell Checker Settings","ignore_word":"Ignore Word","ignore_words":"Ignore All",langs:"Languages",wait:"Please wait...",sug:"Suggestions","no_sug":"No Suggestions","no_mpell":"No misspellings found.","learn_word":"Learn word"},pagebreak:{desc:"Insert Page Break for Printing"},advlist:{types:"Types",def:"Default","lower_alpha":"Lower Alpha","lower_greek":"Lower Greek","lower_roman":"Lower Roman","upper_alpha":"Upper Alpha","upper_roman":"Upper Roman",circle:"Circle",disc:"Disc",square:"Square"},colors:{"333300":"Dark olive","993300":"Burnt orange","000000":"Black","003300":"Dark green","003366":"Dark azure","000080":"Navy Blue","333399":"Indigo","333333":"Very dark gray","800000":"Maroon",FF6600:"Orange","808000":"Olive","008000":"Green","008080":"Teal","0000FF":"Blue","666699":"Grayish blue","808080":"Gray",FF0000:"Red",FF9900:"Amber","99CC00":"Yellow green","339966":"Sea green","33CCCC":"Turquoise","3366FF":"Royal blue","800080":"Purple","999999":"Medium gray",FF00FF:"Magenta",FFCC00:"Gold",FFFF00:"Yellow","00FF00":"Lime","00FFFF":"Aqua","00CCFF":"Sky blue","993366":"Brown",C0C0C0:"Silver",FF99CC:"Pink",FFCC99:"Peach",FFFF99:"Light yellow",CCFFCC:"Pale green",CCFFFF:"Pale cyan","99CCFF":"Light sky blue",CC99FF:"Plum",FFFFFF:"White"},aria:{"rich_text_area":"Rich Text Area"},wordcount:{words:"Words:"},visualblocks:{desc:'Show/hide block elements'}}}); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/license.txt b/askbot/media/js/tinymce/license.txt
new file mode 100644
index 00000000..60d6d4c8
--- /dev/null
+++ b/askbot/media/js/tinymce/license.txt
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/askbot/media/js/tinymce/plugins/advhr/css/advhr.css b/askbot/media/js/tinymce/plugins/advhr/css/advhr.css
new file mode 100644
index 00000000..0e228349
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advhr/css/advhr.css
@@ -0,0 +1,5 @@
+input.radio {border:1px none #000; background:transparent; vertical-align:middle;}
+.panel_wrapper div.current {height:80px;}
+#width {width:50px; vertical-align:middle;}
+#width2 {width:50px; vertical-align:middle;}
+#size {width:100px;}
diff --git a/askbot/media/js/tinymce/plugins/advhr/editor_plugin.js b/askbot/media/js/tinymce/plugins/advhr/editor_plugin.js
new file mode 100644
index 00000000..4d3b062d
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advhr/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.AdvancedHRPlugin",{init:function(a,b){a.addCommand("mceAdvancedHr",function(){a.windowManager.open({file:b+"/rule.htm",width:250+parseInt(a.getLang("advhr.delta_width",0)),height:160+parseInt(a.getLang("advhr.delta_height",0)),inline:1},{plugin_url:b})});a.addButton("advhr",{title:"advhr.advhr_desc",cmd:"mceAdvancedHr"});a.onNodeChange.add(function(d,c,e){c.setActive("advhr",e.nodeName=="HR")});a.onClick.add(function(c,d){d=d.target;if(d.nodeName==="HR"){c.selection.select(d)}})},getInfo:function(){return{longname:"Advanced HR",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advhr",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("advhr",tinymce.plugins.AdvancedHRPlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/advhr/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/advhr/editor_plugin_src.js
new file mode 100644
index 00000000..0c652d33
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advhr/editor_plugin_src.js
@@ -0,0 +1,57 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.AdvancedHRPlugin', {
+ init : function(ed, url) {
+ // Register commands
+ ed.addCommand('mceAdvancedHr', function() {
+ ed.windowManager.open({
+ file : url + '/rule.htm',
+ width : 250 + parseInt(ed.getLang('advhr.delta_width', 0)),
+ height : 160 + parseInt(ed.getLang('advhr.delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url
+ });
+ });
+
+ // Register buttons
+ ed.addButton('advhr', {
+ title : 'advhr.advhr_desc',
+ cmd : 'mceAdvancedHr'
+ });
+
+ ed.onNodeChange.add(function(ed, cm, n) {
+ cm.setActive('advhr', n.nodeName == 'HR');
+ });
+
+ ed.onClick.add(function(ed, e) {
+ e = e.target;
+
+ if (e.nodeName === 'HR')
+ ed.selection.select(e);
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Advanced HR',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advhr',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('advhr', tinymce.plugins.AdvancedHRPlugin);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/advhr/js/rule.js b/askbot/media/js/tinymce/plugins/advhr/js/rule.js
new file mode 100644
index 00000000..b6cbd66c
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advhr/js/rule.js
@@ -0,0 +1,43 @@
+var AdvHRDialog = {
+ init : function(ed) {
+ var dom = ed.dom, f = document.forms[0], n = ed.selection.getNode(), w;
+
+ w = dom.getAttrib(n, 'width');
+ f.width.value = w ? parseInt(w) : (dom.getStyle('width') || '');
+ f.size.value = dom.getAttrib(n, 'size') || parseInt(dom.getStyle('height')) || '';
+ f.noshade.checked = !!dom.getAttrib(n, 'noshade') || !!dom.getStyle('border-width');
+ selectByValue(f, 'width2', w.indexOf('%') != -1 ? '%' : 'px');
+ },
+
+ update : function() {
+ var ed = tinyMCEPopup.editor, h, f = document.forms[0], st = '';
+
+ h = '<hr';
+
+ if (f.size.value) {
+ h += ' size="' + f.size.value + '"';
+ st += ' height:' + f.size.value + 'px;';
+ }
+
+ if (f.width.value) {
+ h += ' width="' + f.width.value + (f.width2.value == '%' ? '%' : '') + '"';
+ st += ' width:' + f.width.value + (f.width2.value == '%' ? '%' : 'px') + ';';
+ }
+
+ if (f.noshade.checked) {
+ h += ' noshade="noshade"';
+ st += ' border-width: 1px; border-style: solid; border-color: #CCCCCC; color: #ffffff;';
+ }
+
+ if (ed.settings.inline_styles)
+ h += ' style="' + tinymce.trim(st) + '"';
+
+ h += ' />';
+
+ ed.execCommand("mceInsertContent", false, h);
+ tinyMCEPopup.close();
+ }
+};
+
+tinyMCEPopup.requireLangPack();
+tinyMCEPopup.onInit.add(AdvHRDialog.init, AdvHRDialog);
diff --git a/askbot/media/js/tinymce/plugins/advhr/langs/en_dlg.js b/askbot/media/js/tinymce/plugins/advhr/langs/en_dlg.js
new file mode 100644
index 00000000..0c3bf15e
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advhr/langs/en_dlg.js
@@ -0,0 +1 @@
+tinyMCE.addI18n('en.advhr_dlg',{size:"Height",noshade:"No Shadow",width:"Width",normal:"Normal",widthunits:"Units"}); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/advhr/rule.htm b/askbot/media/js/tinymce/plugins/advhr/rule.htm
new file mode 100644
index 00000000..843e1f8f
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advhr/rule.htm
@@ -0,0 +1,58 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#advhr.advhr_desc}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="js/rule.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <link href="css/advhr.css" rel="stylesheet" type="text/css" />
+</head>
+<body role="application">
+<form onsubmit="AdvHRDialog.update();return false;" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" class="current" aria-controls="general_panel"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#advhr.advhr_desc}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr role="group" aria-labelledby="width_label">
+ <td><label id="width_label" for="width">{#advhr_dlg.width}</label></td>
+ <td class="nowrap">
+ <input id="width" name="width" type="text" value="" class="mceFocus" />
+ <span style="display:none;" id="width_unit_label">{#advhr_dlg.widthunits}</span>
+ <select name="width2" id="width2" aria-labelledby="width_unit_label">
+ <option value="">px</option>
+ <option value="%">%</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="size">{#advhr_dlg.size}</label></td>
+ <td><select id="size" name="size">
+ <option value="">{#advhr_dlg.normal}</option>
+ <option value="1">1</option>
+ <option value="2">2</option>
+ <option value="3">3</option>
+ <option value="4">4</option>
+ <option value="5">5</option>
+ </select></td>
+ </tr>
+ <tr>
+ <td><label for="noshade">{#advhr_dlg.noshade}</label></td>
+ <td><input type="checkbox" name="noshade" id="noshade" class="radio" /></td>
+ </tr>
+ </table>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#insert}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/advimage/css/advimage.css b/askbot/media/js/tinymce/plugins/advimage/css/advimage.css
new file mode 100644
index 00000000..0a6251a6
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advimage/css/advimage.css
@@ -0,0 +1,13 @@
+#src_list, #over_list, #out_list {width:280px;}
+.mceActionPanel {margin-top:7px;}
+.alignPreview {border:1px solid #000; width:140px; height:140px; overflow:hidden; padding:5px;}
+.checkbox {border:0;}
+.panel_wrapper div.current {height:305px;}
+#prev {margin:0; border:1px solid #000; width:428px; height:150px; overflow:auto;}
+#align, #classlist {width:150px;}
+#width, #height {vertical-align:middle; width:50px; text-align:center;}
+#vspace, #hspace, #border {vertical-align:middle; width:30px; text-align:center;}
+#class_list {width:180px;}
+input {width: 280px;}
+#constrain, #onmousemovecheck {width:auto;}
+#id, #dir, #lang, #usemap, #longdesc {width:200px;}
diff --git a/askbot/media/js/tinymce/plugins/advimage/editor_plugin.js b/askbot/media/js/tinymce/plugins/advimage/editor_plugin.js
new file mode 100644
index 00000000..d613a613
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advimage/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.AdvancedImagePlugin",{init:function(a,b){a.addCommand("mceAdvImage",function(){if(a.dom.getAttrib(a.selection.getNode(),"class","").indexOf("mceItem")!=-1){return}a.windowManager.open({file:b+"/image.htm",width:480+parseInt(a.getLang("advimage.delta_width",0)),height:385+parseInt(a.getLang("advimage.delta_height",0)),inline:1},{plugin_url:b})});a.addButton("image",{title:"advimage.image_desc",cmd:"mceAdvImage"})},getInfo:function(){return{longname:"Advanced image",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advimage",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("advimage",tinymce.plugins.AdvancedImagePlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/advimage/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/advimage/editor_plugin_src.js
new file mode 100644
index 00000000..d2678cbc
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advimage/editor_plugin_src.js
@@ -0,0 +1,50 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.AdvancedImagePlugin', {
+ init : function(ed, url) {
+ // Register commands
+ ed.addCommand('mceAdvImage', function() {
+ // Internal image object like a flash placeholder
+ if (ed.dom.getAttrib(ed.selection.getNode(), 'class', '').indexOf('mceItem') != -1)
+ return;
+
+ ed.windowManager.open({
+ file : url + '/image.htm',
+ width : 480 + parseInt(ed.getLang('advimage.delta_width', 0)),
+ height : 385 + parseInt(ed.getLang('advimage.delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url
+ });
+ });
+
+ // Register buttons
+ ed.addButton('image', {
+ title : 'advimage.image_desc',
+ cmd : 'mceAdvImage'
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Advanced image',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advimage',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('advimage', tinymce.plugins.AdvancedImagePlugin);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/advimage/image.htm b/askbot/media/js/tinymce/plugins/advimage/image.htm
new file mode 100644
index 00000000..ed16b3d4
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advimage/image.htm
@@ -0,0 +1,235 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#advimage_dlg.dialog_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="../../utils/validate.js"></script>
+ <script type="text/javascript" src="../../utils/editable_selects.js"></script>
+ <script type="text/javascript" src="js/image.js"></script>
+ <link href="css/advimage.css" rel="stylesheet" type="text/css" />
+</head>
+<body id="advimage" style="display: none" role="application" aria-labelledby="app_title">
+ <span id="app_title" style="display:none">{#advimage_dlg.dialog_title}</span>
+ <form onsubmit="ImageDialog.insert();return false;" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" class="current" aria-controls="general_panel"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#advimage_dlg.tab_general}</a></span></li>
+ <li id="appearance_tab" aria-controls="appearance_panel"><span><a href="javascript:mcTabs.displayTab('appearance_tab','appearance_panel');" onmousedown="return false;">{#advimage_dlg.tab_appearance}</a></span></li>
+ <li id="advanced_tab" aria-controls="advanced_panel"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');" onmousedown="return false;">{#advimage_dlg.tab_advanced}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <fieldset>
+ <legend>{#advimage_dlg.general}</legend>
+
+ <table role="presentation" class="properties">
+ <tr>
+ <td class="column1"><label id="srclabel" for="src">{#advimage_dlg.src}</label></td>
+ <td colspan="2"><table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input name="src" type="text" id="src" value="" class="mceFocus" onchange="ImageDialog.showPreviewImage(this.value);" aria-required="true" /></td>
+ <td id="srcbrowsercontainer">&nbsp;</td>
+ </tr>
+ </table></td>
+ </tr>
+ <tr>
+ <td><label for="src_list">{#advimage_dlg.image_list}</label></td>
+ <td><select id="src_list" name="src_list" onchange="document.getElementById('src').value=this.options[this.selectedIndex].value;document.getElementById('alt').value=this.options[this.selectedIndex].text;document.getElementById('title').value=this.options[this.selectedIndex].text;ImageDialog.showPreviewImage(this.options[this.selectedIndex].value);"><option value=""></option></select></td>
+ </tr>
+ <tr>
+ <td class="column1"><label id="altlabel" for="alt">{#advimage_dlg.alt}</label></td>
+ <td colspan="2"><input id="alt" name="alt" type="text" value="" /></td>
+ </tr>
+ <tr>
+ <td class="column1"><label id="titlelabel" for="title">{#advimage_dlg.title}</label></td>
+ <td colspan="2"><input id="title" name="title" type="text" value="" /></td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset>
+ <legend>{#advimage_dlg.preview}</legend>
+ <div id="prev"></div>
+ </fieldset>
+ </div>
+
+ <div id="appearance_panel" class="panel">
+ <fieldset>
+ <legend>{#advimage_dlg.tab_appearance}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td class="column1"><label id="alignlabel" for="align">{#advimage_dlg.align}</label></td>
+ <td><select id="align" name="align" onchange="ImageDialog.updateStyle('align');ImageDialog.changeAppearance();">
+ <option value="">{#not_set}</option>
+ <option value="baseline">{#advimage_dlg.align_baseline}</option>
+ <option value="top">{#advimage_dlg.align_top}</option>
+ <option value="middle">{#advimage_dlg.align_middle}</option>
+ <option value="bottom">{#advimage_dlg.align_bottom}</option>
+ <option value="text-top">{#advimage_dlg.align_texttop}</option>
+ <option value="text-bottom">{#advimage_dlg.align_textbottom}</option>
+ <option value="left">{#advimage_dlg.align_left}</option>
+ <option value="right">{#advimage_dlg.align_right}</option>
+ </select>
+ </td>
+ <td rowspan="6" valign="top">
+ <div class="alignPreview">
+ <img id="alignSampleImg" src="img/sample.gif" alt="{#advimage_dlg.example_img}" />
+ Lorem ipsum, Dolor sit amet, consectetuer adipiscing loreum ipsum edipiscing elit, sed diam
+ nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.Loreum ipsum
+ edipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam
+ erat volutpat.
+ </div>
+ </td>
+ </tr>
+
+ <tr role="group" aria-labelledby="widthlabel">
+ <td class="column1"><label id="widthlabel" for="width">{#advimage_dlg.dimensions}</label></td>
+ <td class="nowrap">
+ <span style="display:none" id="width_voiceLabel">{#advimage_dlg.width}</span>
+ <input name="width" type="text" id="width" value="" size="5" maxlength="5" class="size" onchange="ImageDialog.changeHeight();" aria-labelledby="width_voiceLabel" /> x
+ <span style="display:none" id="height_voiceLabel">{#advimage_dlg.height}</span>
+ <input name="height" type="text" id="height" value="" size="5" maxlength="5" class="size" onchange="ImageDialog.changeWidth();" aria-labelledby="height_voiceLabel" /> px
+ </td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ <td><table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="constrain" type="checkbox" name="constrain" class="checkbox" /></td>
+ <td><label id="constrainlabel" for="constrain">{#advimage_dlg.constrain_proportions}</label></td>
+ </tr>
+ </table></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label id="vspacelabel" for="vspace">{#advimage_dlg.vspace}</label></td>
+ <td><input name="vspace" type="text" id="vspace" value="" size="3" maxlength="3" class="number" onchange="ImageDialog.updateStyle('vspace');ImageDialog.changeAppearance();" onblur="ImageDialog.updateStyle('vspace');ImageDialog.changeAppearance();" />
+ </td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label id="hspacelabel" for="hspace">{#advimage_dlg.hspace}</label></td>
+ <td><input name="hspace" type="text" id="hspace" value="" size="3" maxlength="3" class="number" onchange="ImageDialog.updateStyle('hspace');ImageDialog.changeAppearance();" onblur="ImageDialog.updateStyle('hspace');ImageDialog.changeAppearance();" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label id="borderlabel" for="border">{#advimage_dlg.border}</label></td>
+ <td><input id="border" name="border" type="text" value="" size="3" maxlength="3" class="number" onchange="ImageDialog.updateStyle('border');ImageDialog.changeAppearance();" onblur="ImageDialog.updateStyle('border');ImageDialog.changeAppearance();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="class_list">{#class_name}</label></td>
+ <td colspan="2"><select id="class_list" name="class_list" class="mceEditableSelect"><option value=""></option></select></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label id="stylelabel" for="style">{#advimage_dlg.style}</label></td>
+ <td colspan="2"><input id="style" name="style" type="text" value="" onchange="ImageDialog.changeAppearance();" /></td>
+ </tr>
+
+ <!-- <tr>
+ <td class="column1"><label id="classeslabel" for="classes">{#advimage_dlg.classes}</label></td>
+ <td colspan="2"><input id="classes" name="classes" type="text" value="" onchange="selectByValue(this.form,'classlist',this.value,true);" /></td>
+ </tr> -->
+ </table>
+ </fieldset>
+ </div>
+
+ <div id="advanced_panel" class="panel">
+ <fieldset>
+ <legend>{#advimage_dlg.swap_image}</legend>
+
+ <input type="checkbox" id="onmousemovecheck" name="onmousemovecheck" class="checkbox" onclick="ImageDialog.setSwapImage(this.checked);" aria-controls="onmouseoversrc onmouseoutsrc" />
+ <label id="onmousemovechecklabel" for="onmousemovecheck">{#advimage_dlg.alt_image}</label>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0" width="100%">
+ <tr>
+ <td class="column1"><label id="onmouseoversrclabel" for="onmouseoversrc">{#advimage_dlg.mouseover}</label></td>
+ <td><table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input id="onmouseoversrc" name="onmouseoversrc" type="text" value="" /></td>
+ <td id="onmouseoversrccontainer">&nbsp;</td>
+ </tr>
+ </table></td>
+ </tr>
+ <tr>
+ <td><label for="over_list">{#advimage_dlg.image_list}</label></td>
+ <td><select id="over_list" name="over_list" onchange="document.getElementById('onmouseoversrc').value=this.options[this.selectedIndex].value;"><option value=""></option></select></td>
+ </tr>
+ <tr>
+ <td class="column1"><label id="onmouseoutsrclabel" for="onmouseoutsrc">{#advimage_dlg.mouseout}</label></td>
+ <td class="column2"><table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input id="onmouseoutsrc" name="onmouseoutsrc" type="text" value="" /></td>
+ <td id="onmouseoutsrccontainer">&nbsp;</td>
+ </tr>
+ </table></td>
+ </tr>
+ <tr>
+ <td><label for="out_list">{#advimage_dlg.image_list}</label></td>
+ <td><select id="out_list" name="out_list" onchange="document.getElementById('onmouseoutsrc').value=this.options[this.selectedIndex].value;"><option value=""></option></select></td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset>
+ <legend>{#advimage_dlg.misc}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td class="column1"><label id="idlabel" for="id">{#advimage_dlg.id}</label></td>
+ <td><input id="id" name="id" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label id="dirlabel" for="dir">{#advimage_dlg.langdir}</label></td>
+ <td>
+ <select id="dir" name="dir" onchange="ImageDialog.changeAppearance();">
+ <option value="">{#not_set}</option>
+ <option value="ltr">{#advimage_dlg.ltr}</option>
+ <option value="rtl">{#advimage_dlg.rtl}</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label id="langlabel" for="lang">{#advimage_dlg.langcode}</label></td>
+ <td>
+ <input id="lang" name="lang" type="text" value="" />
+ </td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label id="usemaplabel" for="usemap">{#advimage_dlg.map}</label></td>
+ <td>
+ <input id="usemap" name="usemap" type="text" value="" />
+ </td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label id="longdesclabel" for="longdesc">{#advimage_dlg.long_desc}</label></td>
+ <td><table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input id="longdesc" name="longdesc" type="text" value="" /></td>
+ <td id="longdesccontainer">&nbsp;</td>
+ </tr>
+ </table></td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#insert}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+ </form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/advimage/img/sample.gif b/askbot/media/js/tinymce/plugins/advimage/img/sample.gif
new file mode 100644
index 00000000..53bf6890
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advimage/img/sample.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/advimage/js/image.js b/askbot/media/js/tinymce/plugins/advimage/js/image.js
new file mode 100644
index 00000000..546b69c0
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advimage/js/image.js
@@ -0,0 +1,462 @@
+var ImageDialog = {
+ preInit : function() {
+ var url;
+
+ tinyMCEPopup.requireLangPack();
+
+ if (url = tinyMCEPopup.getParam("external_image_list_url"))
+ document.write('<script language="javascript" type="text/javascript" src="' + tinyMCEPopup.editor.documentBaseURI.toAbsolute(url) + '"></script>');
+ },
+
+ init : function(ed) {
+ var f = document.forms[0], nl = f.elements, ed = tinyMCEPopup.editor, dom = ed.dom, n = ed.selection.getNode(), fl = tinyMCEPopup.getParam('external_image_list', 'tinyMCEImageList');
+
+ tinyMCEPopup.resizeToInnerSize();
+ this.fillClassList('class_list');
+ this.fillFileList('src_list', fl);
+ this.fillFileList('over_list', fl);
+ this.fillFileList('out_list', fl);
+ TinyMCE_EditableSelects.init();
+
+ if (n.nodeName == 'IMG') {
+ nl.src.value = dom.getAttrib(n, 'src');
+ nl.width.value = dom.getAttrib(n, 'width');
+ nl.height.value = dom.getAttrib(n, 'height');
+ nl.alt.value = dom.getAttrib(n, 'alt');
+ nl.title.value = dom.getAttrib(n, 'title');
+ nl.vspace.value = this.getAttrib(n, 'vspace');
+ nl.hspace.value = this.getAttrib(n, 'hspace');
+ nl.border.value = this.getAttrib(n, 'border');
+ selectByValue(f, 'align', this.getAttrib(n, 'align'));
+ selectByValue(f, 'class_list', dom.getAttrib(n, 'class'), true, true);
+ nl.style.value = dom.getAttrib(n, 'style');
+ nl.id.value = dom.getAttrib(n, 'id');
+ nl.dir.value = dom.getAttrib(n, 'dir');
+ nl.lang.value = dom.getAttrib(n, 'lang');
+ nl.usemap.value = dom.getAttrib(n, 'usemap');
+ nl.longdesc.value = dom.getAttrib(n, 'longdesc');
+ nl.insert.value = ed.getLang('update');
+
+ if (/^\s*this.src\s*=\s*\'([^\']+)\';?\s*$/.test(dom.getAttrib(n, 'onmouseover')))
+ nl.onmouseoversrc.value = dom.getAttrib(n, 'onmouseover').replace(/^\s*this.src\s*=\s*\'([^\']+)\';?\s*$/, '$1');
+
+ if (/^\s*this.src\s*=\s*\'([^\']+)\';?\s*$/.test(dom.getAttrib(n, 'onmouseout')))
+ nl.onmouseoutsrc.value = dom.getAttrib(n, 'onmouseout').replace(/^\s*this.src\s*=\s*\'([^\']+)\';?\s*$/, '$1');
+
+ if (ed.settings.inline_styles) {
+ // Move attribs to styles
+ if (dom.getAttrib(n, 'align'))
+ this.updateStyle('align');
+
+ if (dom.getAttrib(n, 'hspace'))
+ this.updateStyle('hspace');
+
+ if (dom.getAttrib(n, 'border'))
+ this.updateStyle('border');
+
+ if (dom.getAttrib(n, 'vspace'))
+ this.updateStyle('vspace');
+ }
+ }
+
+ // Setup browse button
+ document.getElementById('srcbrowsercontainer').innerHTML = getBrowserHTML('srcbrowser','src','image','theme_advanced_image');
+ if (isVisible('srcbrowser'))
+ document.getElementById('src').style.width = '260px';
+
+ // Setup browse button
+ document.getElementById('onmouseoversrccontainer').innerHTML = getBrowserHTML('overbrowser','onmouseoversrc','image','theme_advanced_image');
+ if (isVisible('overbrowser'))
+ document.getElementById('onmouseoversrc').style.width = '260px';
+
+ // Setup browse button
+ document.getElementById('onmouseoutsrccontainer').innerHTML = getBrowserHTML('outbrowser','onmouseoutsrc','image','theme_advanced_image');
+ if (isVisible('outbrowser'))
+ document.getElementById('onmouseoutsrc').style.width = '260px';
+
+ // If option enabled default contrain proportions to checked
+ if (ed.getParam("advimage_constrain_proportions", true))
+ f.constrain.checked = true;
+
+ // Check swap image if valid data
+ if (nl.onmouseoversrc.value || nl.onmouseoutsrc.value)
+ this.setSwapImage(true);
+ else
+ this.setSwapImage(false);
+
+ this.changeAppearance();
+ this.showPreviewImage(nl.src.value, 1);
+ },
+
+ insert : function(file, title) {
+ var ed = tinyMCEPopup.editor, t = this, f = document.forms[0];
+
+ if (f.src.value === '') {
+ if (ed.selection.getNode().nodeName == 'IMG') {
+ ed.dom.remove(ed.selection.getNode());
+ ed.execCommand('mceRepaint');
+ }
+
+ tinyMCEPopup.close();
+ return;
+ }
+
+ if (tinyMCEPopup.getParam("accessibility_warnings", 1)) {
+ if (!f.alt.value) {
+ tinyMCEPopup.confirm(tinyMCEPopup.getLang('advimage_dlg.missing_alt'), function(s) {
+ if (s)
+ t.insertAndClose();
+ });
+
+ return;
+ }
+ }
+
+ t.insertAndClose();
+ },
+
+ insertAndClose : function() {
+ var ed = tinyMCEPopup.editor, f = document.forms[0], nl = f.elements, v, args = {}, el;
+
+ tinyMCEPopup.restoreSelection();
+
+ // Fixes crash in Safari
+ if (tinymce.isWebKit)
+ ed.getWin().focus();
+
+ if (!ed.settings.inline_styles) {
+ args = {
+ vspace : nl.vspace.value,
+ hspace : nl.hspace.value,
+ border : nl.border.value,
+ align : getSelectValue(f, 'align')
+ };
+ } else {
+ // Remove deprecated values
+ args = {
+ vspace : '',
+ hspace : '',
+ border : '',
+ align : ''
+ };
+ }
+
+ tinymce.extend(args, {
+ src : nl.src.value.replace(/ /g, '%20'),
+ width : nl.width.value,
+ height : nl.height.value,
+ alt : nl.alt.value,
+ title : nl.title.value,
+ 'class' : getSelectValue(f, 'class_list'),
+ style : nl.style.value,
+ id : nl.id.value,
+ dir : nl.dir.value,
+ lang : nl.lang.value,
+ usemap : nl.usemap.value,
+ longdesc : nl.longdesc.value
+ });
+
+ args.onmouseover = args.onmouseout = '';
+
+ if (f.onmousemovecheck.checked) {
+ if (nl.onmouseoversrc.value)
+ args.onmouseover = "this.src='" + nl.onmouseoversrc.value + "';";
+
+ if (nl.onmouseoutsrc.value)
+ args.onmouseout = "this.src='" + nl.onmouseoutsrc.value + "';";
+ }
+
+ el = ed.selection.getNode();
+
+ if (el && el.nodeName == 'IMG') {
+ ed.dom.setAttribs(el, args);
+ } else {
+ tinymce.each(args, function(value, name) {
+ if (value === "") {
+ delete args[name];
+ }
+ });
+
+ ed.execCommand('mceInsertContent', false, tinyMCEPopup.editor.dom.createHTML('img', args), {skip_undo : 1});
+ ed.undoManager.add();
+ }
+
+ tinyMCEPopup.editor.execCommand('mceRepaint');
+ tinyMCEPopup.editor.focus();
+ tinyMCEPopup.close();
+ },
+
+ getAttrib : function(e, at) {
+ var ed = tinyMCEPopup.editor, dom = ed.dom, v, v2;
+
+ if (ed.settings.inline_styles) {
+ switch (at) {
+ case 'align':
+ if (v = dom.getStyle(e, 'float'))
+ return v;
+
+ if (v = dom.getStyle(e, 'vertical-align'))
+ return v;
+
+ break;
+
+ case 'hspace':
+ v = dom.getStyle(e, 'margin-left')
+ v2 = dom.getStyle(e, 'margin-right');
+
+ if (v && v == v2)
+ return parseInt(v.replace(/[^0-9]/g, ''));
+
+ break;
+
+ case 'vspace':
+ v = dom.getStyle(e, 'margin-top')
+ v2 = dom.getStyle(e, 'margin-bottom');
+ if (v && v == v2)
+ return parseInt(v.replace(/[^0-9]/g, ''));
+
+ break;
+
+ case 'border':
+ v = 0;
+
+ tinymce.each(['top', 'right', 'bottom', 'left'], function(sv) {
+ sv = dom.getStyle(e, 'border-' + sv + '-width');
+
+ // False or not the same as prev
+ if (!sv || (sv != v && v !== 0)) {
+ v = 0;
+ return false;
+ }
+
+ if (sv)
+ v = sv;
+ });
+
+ if (v)
+ return parseInt(v.replace(/[^0-9]/g, ''));
+
+ break;
+ }
+ }
+
+ if (v = dom.getAttrib(e, at))
+ return v;
+
+ return '';
+ },
+
+ setSwapImage : function(st) {
+ var f = document.forms[0];
+
+ f.onmousemovecheck.checked = st;
+ setBrowserDisabled('overbrowser', !st);
+ setBrowserDisabled('outbrowser', !st);
+
+ if (f.over_list)
+ f.over_list.disabled = !st;
+
+ if (f.out_list)
+ f.out_list.disabled = !st;
+
+ f.onmouseoversrc.disabled = !st;
+ f.onmouseoutsrc.disabled = !st;
+ },
+
+ fillClassList : function(id) {
+ var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl;
+
+ if (v = tinyMCEPopup.getParam('theme_advanced_styles')) {
+ cl = [];
+
+ tinymce.each(v.split(';'), function(v) {
+ var p = v.split('=');
+
+ cl.push({'title' : p[0], 'class' : p[1]});
+ });
+ } else
+ cl = tinyMCEPopup.editor.dom.getClasses();
+
+ if (cl.length > 0) {
+ lst.options.length = 0;
+ lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('not_set'), '');
+
+ tinymce.each(cl, function(o) {
+ lst.options[lst.options.length] = new Option(o.title || o['class'], o['class']);
+ });
+ } else
+ dom.remove(dom.getParent(id, 'tr'));
+ },
+
+ fillFileList : function(id, l) {
+ var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl;
+
+ l = typeof(l) === 'function' ? l() : window[l];
+ lst.options.length = 0;
+
+ if (l && l.length > 0) {
+ lst.options[lst.options.length] = new Option('', '');
+
+ tinymce.each(l, function(o) {
+ lst.options[lst.options.length] = new Option(o[0], o[1]);
+ });
+ } else
+ dom.remove(dom.getParent(id, 'tr'));
+ },
+
+ resetImageData : function() {
+ var f = document.forms[0];
+
+ f.elements.width.value = f.elements.height.value = '';
+ },
+
+ updateImageData : function(img, st) {
+ var f = document.forms[0];
+
+ if (!st) {
+ f.elements.width.value = img.width;
+ f.elements.height.value = img.height;
+ }
+
+ this.preloadImg = img;
+ },
+
+ changeAppearance : function() {
+ var ed = tinyMCEPopup.editor, f = document.forms[0], img = document.getElementById('alignSampleImg');
+
+ if (img) {
+ if (ed.getParam('inline_styles')) {
+ ed.dom.setAttrib(img, 'style', f.style.value);
+ } else {
+ img.align = f.align.value;
+ img.border = f.border.value;
+ img.hspace = f.hspace.value;
+ img.vspace = f.vspace.value;
+ }
+ }
+ },
+
+ changeHeight : function() {
+ var f = document.forms[0], tp, t = this;
+
+ if (!f.constrain.checked || !t.preloadImg) {
+ return;
+ }
+
+ if (f.width.value == "" || f.height.value == "")
+ return;
+
+ tp = (parseInt(f.width.value) / parseInt(t.preloadImg.width)) * t.preloadImg.height;
+ f.height.value = tp.toFixed(0);
+ },
+
+ changeWidth : function() {
+ var f = document.forms[0], tp, t = this;
+
+ if (!f.constrain.checked || !t.preloadImg) {
+ return;
+ }
+
+ if (f.width.value == "" || f.height.value == "")
+ return;
+
+ tp = (parseInt(f.height.value) / parseInt(t.preloadImg.height)) * t.preloadImg.width;
+ f.width.value = tp.toFixed(0);
+ },
+
+ updateStyle : function(ty) {
+ var dom = tinyMCEPopup.dom, b, bStyle, bColor, v, isIE = tinymce.isIE, f = document.forms[0], img = dom.create('img', {style : dom.get('style').value});
+
+ if (tinyMCEPopup.editor.settings.inline_styles) {
+ // Handle align
+ if (ty == 'align') {
+ dom.setStyle(img, 'float', '');
+ dom.setStyle(img, 'vertical-align', '');
+
+ v = getSelectValue(f, 'align');
+ if (v) {
+ if (v == 'left' || v == 'right')
+ dom.setStyle(img, 'float', v);
+ else
+ img.style.verticalAlign = v;
+ }
+ }
+
+ // Handle border
+ if (ty == 'border') {
+ b = img.style.border ? img.style.border.split(' ') : [];
+ bStyle = dom.getStyle(img, 'border-style');
+ bColor = dom.getStyle(img, 'border-color');
+
+ dom.setStyle(img, 'border', '');
+
+ v = f.border.value;
+ if (v || v == '0') {
+ if (v == '0')
+ img.style.border = isIE ? '0' : '0 none none';
+ else {
+ if (b.length == 3 && b[isIE ? 2 : 1])
+ bStyle = b[isIE ? 2 : 1];
+ else if (!bStyle || bStyle == 'none')
+ bStyle = 'solid';
+ if (b.length == 3 && b[isIE ? 0 : 2])
+ bColor = b[isIE ? 0 : 2];
+ else if (!bColor || bColor == 'none')
+ bColor = 'black';
+ img.style.border = v + 'px ' + bStyle + ' ' + bColor;
+ }
+ }
+ }
+
+ // Handle hspace
+ if (ty == 'hspace') {
+ dom.setStyle(img, 'marginLeft', '');
+ dom.setStyle(img, 'marginRight', '');
+
+ v = f.hspace.value;
+ if (v) {
+ img.style.marginLeft = v + 'px';
+ img.style.marginRight = v + 'px';
+ }
+ }
+
+ // Handle vspace
+ if (ty == 'vspace') {
+ dom.setStyle(img, 'marginTop', '');
+ dom.setStyle(img, 'marginBottom', '');
+
+ v = f.vspace.value;
+ if (v) {
+ img.style.marginTop = v + 'px';
+ img.style.marginBottom = v + 'px';
+ }
+ }
+
+ // Merge
+ dom.get('style').value = dom.serializeStyle(dom.parseStyle(img.style.cssText), 'img');
+ }
+ },
+
+ changeMouseMove : function() {
+ },
+
+ showPreviewImage : function(u, st) {
+ if (!u) {
+ tinyMCEPopup.dom.setHTML('prev', '');
+ return;
+ }
+
+ if (!st && tinyMCEPopup.getParam("advimage_update_dimensions_onchange", true))
+ this.resetImageData();
+
+ u = tinyMCEPopup.editor.documentBaseURI.toAbsolute(u);
+
+ if (!st)
+ tinyMCEPopup.dom.setHTML('prev', '<img id="previewImg" src="' + u + '" border="0" onload="ImageDialog.updateImageData(this);" onerror="ImageDialog.resetImageData();" />');
+ else
+ tinyMCEPopup.dom.setHTML('prev', '<img id="previewImg" src="' + u + '" border="0" onload="ImageDialog.updateImageData(this, 1);" />');
+ }
+};
+
+ImageDialog.preInit();
+tinyMCEPopup.onInit.add(ImageDialog.init, ImageDialog);
diff --git a/askbot/media/js/tinymce/plugins/advimage/langs/en_dlg.js b/askbot/media/js/tinymce/plugins/advimage/langs/en_dlg.js
new file mode 100644
index 00000000..5f122e2c
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advimage/langs/en_dlg.js
@@ -0,0 +1 @@
+tinyMCE.addI18n('en.advimage_dlg',{"image_list":"Image List","align_right":"Right","align_left":"Left","align_textbottom":"Text Bottom","align_texttop":"Text Top","align_bottom":"Bottom","align_middle":"Middle","align_top":"Top","align_baseline":"Baseline",align:"Alignment",hspace:"Horizontal Space",vspace:"Vertical Space",dimensions:"Dimensions",border:"Border",list:"Image List",alt:"Image Description",src:"Image URL","dialog_title":"Insert/Edit Image","missing_alt":"Are you sure you want to continue without including an Image Description? Without it the image may not be accessible to some users with disabilities, or to those using a text browser, or browsing the Web with images turned off.","example_img":"Appearance Preview Image",misc:"Miscellaneous",mouseout:"For Mouse Out",mouseover:"For Mouse Over","alt_image":"Alternative Image","swap_image":"Swap Image",map:"Image Map",id:"ID",rtl:"Right to Left",ltr:"Left to Right",classes:"Classes",style:"Style","long_desc":"Long Description Link",langcode:"Language Code",langdir:"Language Direction","constrain_proportions":"Constrain Proportions",preview:"Preview",title:"Title",general:"General","tab_advanced":"Advanced","tab_appearance":"Appearance","tab_general":"General",width:"Width",height:"Height"}); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/advlink/css/advlink.css b/askbot/media/js/tinymce/plugins/advlink/css/advlink.css
new file mode 100644
index 00000000..14364316
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advlink/css/advlink.css
@@ -0,0 +1,8 @@
+.mceLinkList, .mceAnchorList, #targetlist {width:280px;}
+.mceActionPanel {margin-top:7px;}
+.panel_wrapper div.current {height:320px;}
+#classlist, #title, #href {width:280px;}
+#popupurl, #popupname {width:200px;}
+#popupwidth, #popupheight, #popupleft, #popuptop {width:30px;vertical-align:middle;text-align:center;}
+#id, #style, #classes, #target, #dir, #hreflang, #lang, #charset, #type, #rel, #rev, #tabindex, #accesskey {width:200px;}
+#events_panel input {width:200px;}
diff --git a/askbot/media/js/tinymce/plugins/advlink/editor_plugin.js b/askbot/media/js/tinymce/plugins/advlink/editor_plugin.js
new file mode 100644
index 00000000..983fe5a9
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advlink/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.AdvancedLinkPlugin",{init:function(a,b){this.editor=a;a.addCommand("mceAdvLink",function(){var c=a.selection;if(c.isCollapsed()&&!a.dom.getParent(c.getNode(),"A")){return}a.windowManager.open({file:b+"/link.htm",width:480+parseInt(a.getLang("advlink.delta_width",0)),height:400+parseInt(a.getLang("advlink.delta_height",0)),inline:1},{plugin_url:b})});a.addButton("link",{title:"advlink.link_desc",cmd:"mceAdvLink"});a.addShortcut("ctrl+k","advlink.advlink_desc","mceAdvLink");a.onNodeChange.add(function(d,c,f,e){c.setDisabled("link",e&&f.nodeName!="A");c.setActive("link",f.nodeName=="A"&&!f.name)})},getInfo:function(){return{longname:"Advanced link",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advlink",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("advlink",tinymce.plugins.AdvancedLinkPlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/advlink/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/advlink/editor_plugin_src.js
new file mode 100644
index 00000000..14e46a76
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advlink/editor_plugin_src.js
@@ -0,0 +1,61 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.AdvancedLinkPlugin', {
+ init : function(ed, url) {
+ this.editor = ed;
+
+ // Register commands
+ ed.addCommand('mceAdvLink', function() {
+ var se = ed.selection;
+
+ // No selection and not in link
+ if (se.isCollapsed() && !ed.dom.getParent(se.getNode(), 'A'))
+ return;
+
+ ed.windowManager.open({
+ file : url + '/link.htm',
+ width : 480 + parseInt(ed.getLang('advlink.delta_width', 0)),
+ height : 400 + parseInt(ed.getLang('advlink.delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url
+ });
+ });
+
+ // Register buttons
+ ed.addButton('link', {
+ title : 'advlink.link_desc',
+ cmd : 'mceAdvLink'
+ });
+
+ ed.addShortcut('ctrl+k', 'advlink.advlink_desc', 'mceAdvLink');
+
+ ed.onNodeChange.add(function(ed, cm, n, co) {
+ cm.setDisabled('link', co && n.nodeName != 'A');
+ cm.setActive('link', n.nodeName == 'A' && !n.name);
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Advanced link',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advlink',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('advlink', tinymce.plugins.AdvancedLinkPlugin);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/advlink/js/advlink.js b/askbot/media/js/tinymce/plugins/advlink/js/advlink.js
new file mode 100644
index 00000000..9ca955c9
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advlink/js/advlink.js
@@ -0,0 +1,539 @@
+/* Functions for the advlink plugin popup */
+
+tinyMCEPopup.requireLangPack();
+
+var templates = {
+ "window.open" : "window.open('${url}','${target}','${options}')"
+};
+
+function preinit() {
+ var url;
+
+ if (url = tinyMCEPopup.getParam("external_link_list_url"))
+ document.write('<script language="javascript" type="text/javascript" src="' + tinyMCEPopup.editor.documentBaseURI.toAbsolute(url) + '"></script>');
+}
+
+function changeClass() {
+ var f = document.forms[0];
+
+ f.classes.value = getSelectValue(f, 'classlist');
+}
+
+function init() {
+ tinyMCEPopup.resizeToInnerSize();
+
+ var formObj = document.forms[0];
+ var inst = tinyMCEPopup.editor;
+ var elm = inst.selection.getNode();
+ var action = "insert";
+ var html;
+
+ document.getElementById('hrefbrowsercontainer').innerHTML = getBrowserHTML('hrefbrowser','href','file','advlink');
+ document.getElementById('popupurlbrowsercontainer').innerHTML = getBrowserHTML('popupurlbrowser','popupurl','file','advlink');
+ document.getElementById('targetlistcontainer').innerHTML = getTargetListHTML('targetlist','target');
+
+ // Link list
+ html = getLinkListHTML('linklisthref','href');
+ if (html == "")
+ document.getElementById("linklisthrefrow").style.display = 'none';
+ else
+ document.getElementById("linklisthrefcontainer").innerHTML = html;
+
+ // Anchor list
+ html = getAnchorListHTML('anchorlist','href');
+ if (html == "")
+ document.getElementById("anchorlistrow").style.display = 'none';
+ else
+ document.getElementById("anchorlistcontainer").innerHTML = html;
+
+ // Resize some elements
+ if (isVisible('hrefbrowser'))
+ document.getElementById('href').style.width = '260px';
+
+ if (isVisible('popupurlbrowser'))
+ document.getElementById('popupurl').style.width = '180px';
+
+ elm = inst.dom.getParent(elm, "A");
+ if (elm == null) {
+ var prospect = inst.dom.create("p", null, inst.selection.getContent());
+ if (prospect.childNodes.length === 1) {
+ elm = prospect.firstChild;
+ }
+ }
+
+ if (elm != null && elm.nodeName == "A")
+ action = "update";
+
+ formObj.insert.value = tinyMCEPopup.getLang(action, 'Insert', true);
+
+ setPopupControlsDisabled(true);
+
+ if (action == "update") {
+ var href = inst.dom.getAttrib(elm, 'href');
+ var onclick = inst.dom.getAttrib(elm, 'onclick');
+
+ // Setup form data
+ setFormValue('href', href);
+ setFormValue('title', inst.dom.getAttrib(elm, 'title'));
+ setFormValue('id', inst.dom.getAttrib(elm, 'id'));
+ setFormValue('style', inst.dom.getAttrib(elm, "style"));
+ setFormValue('rel', inst.dom.getAttrib(elm, 'rel'));
+ setFormValue('rev', inst.dom.getAttrib(elm, 'rev'));
+ setFormValue('charset', inst.dom.getAttrib(elm, 'charset'));
+ setFormValue('hreflang', inst.dom.getAttrib(elm, 'hreflang'));
+ setFormValue('dir', inst.dom.getAttrib(elm, 'dir'));
+ setFormValue('lang', inst.dom.getAttrib(elm, 'lang'));
+ setFormValue('tabindex', inst.dom.getAttrib(elm, 'tabindex', typeof(elm.tabindex) != "undefined" ? elm.tabindex : ""));
+ setFormValue('accesskey', inst.dom.getAttrib(elm, 'accesskey', typeof(elm.accesskey) != "undefined" ? elm.accesskey : ""));
+ setFormValue('type', inst.dom.getAttrib(elm, 'type'));
+ setFormValue('onfocus', inst.dom.getAttrib(elm, 'onfocus'));
+ setFormValue('onblur', inst.dom.getAttrib(elm, 'onblur'));
+ setFormValue('onclick', onclick);
+ setFormValue('ondblclick', inst.dom.getAttrib(elm, 'ondblclick'));
+ setFormValue('onmousedown', inst.dom.getAttrib(elm, 'onmousedown'));
+ setFormValue('onmouseup', inst.dom.getAttrib(elm, 'onmouseup'));
+ setFormValue('onmouseover', inst.dom.getAttrib(elm, 'onmouseover'));
+ setFormValue('onmousemove', inst.dom.getAttrib(elm, 'onmousemove'));
+ setFormValue('onmouseout', inst.dom.getAttrib(elm, 'onmouseout'));
+ setFormValue('onkeypress', inst.dom.getAttrib(elm, 'onkeypress'));
+ setFormValue('onkeydown', inst.dom.getAttrib(elm, 'onkeydown'));
+ setFormValue('onkeyup', inst.dom.getAttrib(elm, 'onkeyup'));
+ setFormValue('target', inst.dom.getAttrib(elm, 'target'));
+ setFormValue('classes', inst.dom.getAttrib(elm, 'class'));
+
+ // Parse onclick data
+ if (onclick != null && onclick.indexOf('window.open') != -1)
+ parseWindowOpen(onclick);
+ else
+ parseFunction(onclick);
+
+ // Select by the values
+ selectByValue(formObj, 'dir', inst.dom.getAttrib(elm, 'dir'));
+ selectByValue(formObj, 'rel', inst.dom.getAttrib(elm, 'rel'));
+ selectByValue(formObj, 'rev', inst.dom.getAttrib(elm, 'rev'));
+ selectByValue(formObj, 'linklisthref', href);
+
+ if (href.charAt(0) == '#')
+ selectByValue(formObj, 'anchorlist', href);
+
+ addClassesToList('classlist', 'advlink_styles');
+
+ selectByValue(formObj, 'classlist', inst.dom.getAttrib(elm, 'class'), true);
+ selectByValue(formObj, 'targetlist', inst.dom.getAttrib(elm, 'target'), true);
+ } else
+ addClassesToList('classlist', 'advlink_styles');
+}
+
+function checkPrefix(n) {
+ if (n.value && Validator.isEmail(n) && !/^\s*mailto:/i.test(n.value) && confirm(tinyMCEPopup.getLang('advlink_dlg.is_email')))
+ n.value = 'mailto:' + n.value;
+
+ if (/^\s*www\./i.test(n.value) && confirm(tinyMCEPopup.getLang('advlink_dlg.is_external')))
+ n.value = 'http://' + n.value;
+}
+
+function setFormValue(name, value) {
+ document.forms[0].elements[name].value = value;
+}
+
+function parseWindowOpen(onclick) {
+ var formObj = document.forms[0];
+
+ // Preprocess center code
+ if (onclick.indexOf('return false;') != -1) {
+ formObj.popupreturn.checked = true;
+ onclick = onclick.replace('return false;', '');
+ } else
+ formObj.popupreturn.checked = false;
+
+ var onClickData = parseLink(onclick);
+
+ if (onClickData != null) {
+ formObj.ispopup.checked = true;
+ setPopupControlsDisabled(false);
+
+ var onClickWindowOptions = parseOptions(onClickData['options']);
+ var url = onClickData['url'];
+
+ formObj.popupname.value = onClickData['target'];
+ formObj.popupurl.value = url;
+ formObj.popupwidth.value = getOption(onClickWindowOptions, 'width');
+ formObj.popupheight.value = getOption(onClickWindowOptions, 'height');
+
+ formObj.popupleft.value = getOption(onClickWindowOptions, 'left');
+ formObj.popuptop.value = getOption(onClickWindowOptions, 'top');
+
+ if (formObj.popupleft.value.indexOf('screen') != -1)
+ formObj.popupleft.value = "c";
+
+ if (formObj.popuptop.value.indexOf('screen') != -1)
+ formObj.popuptop.value = "c";
+
+ formObj.popuplocation.checked = getOption(onClickWindowOptions, 'location') == "yes";
+ formObj.popupscrollbars.checked = getOption(onClickWindowOptions, 'scrollbars') == "yes";
+ formObj.popupmenubar.checked = getOption(onClickWindowOptions, 'menubar') == "yes";
+ formObj.popupresizable.checked = getOption(onClickWindowOptions, 'resizable') == "yes";
+ formObj.popuptoolbar.checked = getOption(onClickWindowOptions, 'toolbar') == "yes";
+ formObj.popupstatus.checked = getOption(onClickWindowOptions, 'status') == "yes";
+ formObj.popupdependent.checked = getOption(onClickWindowOptions, 'dependent') == "yes";
+
+ buildOnClick();
+ }
+}
+
+function parseFunction(onclick) {
+ var formObj = document.forms[0];
+ var onClickData = parseLink(onclick);
+
+ // TODO: Add stuff here
+}
+
+function getOption(opts, name) {
+ return typeof(opts[name]) == "undefined" ? "" : opts[name];
+}
+
+function setPopupControlsDisabled(state) {
+ var formObj = document.forms[0];
+
+ formObj.popupname.disabled = state;
+ formObj.popupurl.disabled = state;
+ formObj.popupwidth.disabled = state;
+ formObj.popupheight.disabled = state;
+ formObj.popupleft.disabled = state;
+ formObj.popuptop.disabled = state;
+ formObj.popuplocation.disabled = state;
+ formObj.popupscrollbars.disabled = state;
+ formObj.popupmenubar.disabled = state;
+ formObj.popupresizable.disabled = state;
+ formObj.popuptoolbar.disabled = state;
+ formObj.popupstatus.disabled = state;
+ formObj.popupreturn.disabled = state;
+ formObj.popupdependent.disabled = state;
+
+ setBrowserDisabled('popupurlbrowser', state);
+}
+
+function parseLink(link) {
+ link = link.replace(new RegExp('&#39;', 'g'), "'");
+
+ var fnName = link.replace(new RegExp("\\s*([A-Za-z0-9\.]*)\\s*\\(.*", "gi"), "$1");
+
+ // Is function name a template function
+ var template = templates[fnName];
+ if (template) {
+ // Build regexp
+ var variableNames = template.match(new RegExp("'?\\$\\{[A-Za-z0-9\.]*\\}'?", "gi"));
+ var regExp = "\\s*[A-Za-z0-9\.]*\\s*\\(";
+ var replaceStr = "";
+ for (var i=0; i<variableNames.length; i++) {
+ // Is string value
+ if (variableNames[i].indexOf("'${") != -1)
+ regExp += "'(.*)'";
+ else // Number value
+ regExp += "([0-9]*)";
+
+ replaceStr += "$" + (i+1);
+
+ // Cleanup variable name
+ variableNames[i] = variableNames[i].replace(new RegExp("[^A-Za-z0-9]", "gi"), "");
+
+ if (i != variableNames.length-1) {
+ regExp += "\\s*,\\s*";
+ replaceStr += "<delim>";
+ } else
+ regExp += ".*";
+ }
+
+ regExp += "\\);?";
+
+ // Build variable array
+ var variables = [];
+ variables["_function"] = fnName;
+ var variableValues = link.replace(new RegExp(regExp, "gi"), replaceStr).split('<delim>');
+ for (var i=0; i<variableNames.length; i++)
+ variables[variableNames[i]] = variableValues[i];
+
+ return variables;
+ }
+
+ return null;
+}
+
+function parseOptions(opts) {
+ if (opts == null || opts == "")
+ return [];
+
+ // Cleanup the options
+ opts = opts.toLowerCase();
+ opts = opts.replace(/;/g, ",");
+ opts = opts.replace(/[^0-9a-z=,]/g, "");
+
+ var optionChunks = opts.split(',');
+ var options = [];
+
+ for (var i=0; i<optionChunks.length; i++) {
+ var parts = optionChunks[i].split('=');
+
+ if (parts.length == 2)
+ options[parts[0]] = parts[1];
+ }
+
+ return options;
+}
+
+function buildOnClick() {
+ var formObj = document.forms[0];
+
+ if (!formObj.ispopup.checked) {
+ formObj.onclick.value = "";
+ return;
+ }
+
+ var onclick = "window.open('";
+ var url = formObj.popupurl.value;
+
+ onclick += url + "','";
+ onclick += formObj.popupname.value + "','";
+
+ if (formObj.popuplocation.checked)
+ onclick += "location=yes,";
+
+ if (formObj.popupscrollbars.checked)
+ onclick += "scrollbars=yes,";
+
+ if (formObj.popupmenubar.checked)
+ onclick += "menubar=yes,";
+
+ if (formObj.popupresizable.checked)
+ onclick += "resizable=yes,";
+
+ if (formObj.popuptoolbar.checked)
+ onclick += "toolbar=yes,";
+
+ if (formObj.popupstatus.checked)
+ onclick += "status=yes,";
+
+ if (formObj.popupdependent.checked)
+ onclick += "dependent=yes,";
+
+ if (formObj.popupwidth.value != "")
+ onclick += "width=" + formObj.popupwidth.value + ",";
+
+ if (formObj.popupheight.value != "")
+ onclick += "height=" + formObj.popupheight.value + ",";
+
+ if (formObj.popupleft.value != "") {
+ if (formObj.popupleft.value != "c")
+ onclick += "left=" + formObj.popupleft.value + ",";
+ else
+ onclick += "left='+(screen.availWidth/2-" + (formObj.popupwidth.value/2) + ")+',";
+ }
+
+ if (formObj.popuptop.value != "") {
+ if (formObj.popuptop.value != "c")
+ onclick += "top=" + formObj.popuptop.value + ",";
+ else
+ onclick += "top='+(screen.availHeight/2-" + (formObj.popupheight.value/2) + ")+',";
+ }
+
+ if (onclick.charAt(onclick.length-1) == ',')
+ onclick = onclick.substring(0, onclick.length-1);
+
+ onclick += "');";
+
+ if (formObj.popupreturn.checked)
+ onclick += "return false;";
+
+ // tinyMCE.debug(onclick);
+
+ formObj.onclick.value = onclick;
+
+ if (formObj.href.value == "")
+ formObj.href.value = url;
+}
+
+function setAttrib(elm, attrib, value) {
+ var formObj = document.forms[0];
+ var valueElm = formObj.elements[attrib.toLowerCase()];
+ var dom = tinyMCEPopup.editor.dom;
+
+ if (typeof(value) == "undefined" || value == null) {
+ value = "";
+
+ if (valueElm)
+ value = valueElm.value;
+ }
+
+ // Clean up the style
+ if (attrib == 'style')
+ value = dom.serializeStyle(dom.parseStyle(value), 'a');
+
+ dom.setAttrib(elm, attrib, value);
+}
+
+function getAnchorListHTML(id, target) {
+ var ed = tinyMCEPopup.editor, nodes = ed.dom.select('a'), name, i, len, html = "";
+
+ for (i=0, len=nodes.length; i<len; i++) {
+ if ((name = ed.dom.getAttrib(nodes[i], "name")) != "")
+ html += '<option value="#' + name + '">' + name + '</option>';
+ }
+
+ if (html == "")
+ return "";
+
+ html = '<select id="' + id + '" name="' + id + '" class="mceAnchorList"'
+ + ' onchange="this.form.' + target + '.value=this.options[this.selectedIndex].value"'
+ + '>'
+ + '<option value="">---</option>'
+ + html
+ + '</select>';
+
+ return html;
+}
+
+function insertAction() {
+ var inst = tinyMCEPopup.editor;
+ var elm, elementArray, i;
+
+ elm = inst.selection.getNode();
+ checkPrefix(document.forms[0].href);
+
+ elm = inst.dom.getParent(elm, "A");
+
+ // Remove element if there is no href
+ if (!document.forms[0].href.value) {
+ i = inst.selection.getBookmark();
+ inst.dom.remove(elm, 1);
+ inst.selection.moveToBookmark(i);
+ tinyMCEPopup.execCommand("mceEndUndoLevel");
+ tinyMCEPopup.close();
+ return;
+ }
+
+ // Create new anchor elements
+ if (elm == null) {
+ inst.getDoc().execCommand("unlink", false, null);
+ tinyMCEPopup.execCommand("mceInsertLink", false, "#mce_temp_url#", {skip_undo : 1});
+
+ elementArray = tinymce.grep(inst.dom.select("a"), function(n) {return inst.dom.getAttrib(n, 'href') == '#mce_temp_url#';});
+ for (i=0; i<elementArray.length; i++)
+ setAllAttribs(elm = elementArray[i]);
+ } else
+ setAllAttribs(elm);
+
+ // Don't move caret if selection was image
+ if (elm.childNodes.length != 1 || elm.firstChild.nodeName != 'IMG') {
+ inst.focus();
+ inst.selection.select(elm);
+ inst.selection.collapse(0);
+ tinyMCEPopup.storeSelection();
+ }
+
+ tinyMCEPopup.execCommand("mceEndUndoLevel");
+ tinyMCEPopup.close();
+}
+
+function setAllAttribs(elm) {
+ var formObj = document.forms[0];
+ var href = formObj.href.value.replace(/ /g, '%20');
+ var target = getSelectValue(formObj, 'targetlist');
+
+ setAttrib(elm, 'href', href);
+ setAttrib(elm, 'title');
+ setAttrib(elm, 'target', target == '_self' ? '' : target);
+ setAttrib(elm, 'id');
+ setAttrib(elm, 'style');
+ setAttrib(elm, 'class', getSelectValue(formObj, 'classlist'));
+ setAttrib(elm, 'rel');
+ setAttrib(elm, 'rev');
+ setAttrib(elm, 'charset');
+ setAttrib(elm, 'hreflang');
+ setAttrib(elm, 'dir');
+ setAttrib(elm, 'lang');
+ setAttrib(elm, 'tabindex');
+ setAttrib(elm, 'accesskey');
+ setAttrib(elm, 'type');
+ setAttrib(elm, 'onfocus');
+ setAttrib(elm, 'onblur');
+ setAttrib(elm, 'onclick');
+ setAttrib(elm, 'ondblclick');
+ setAttrib(elm, 'onmousedown');
+ setAttrib(elm, 'onmouseup');
+ setAttrib(elm, 'onmouseover');
+ setAttrib(elm, 'onmousemove');
+ setAttrib(elm, 'onmouseout');
+ setAttrib(elm, 'onkeypress');
+ setAttrib(elm, 'onkeydown');
+ setAttrib(elm, 'onkeyup');
+
+ // Refresh in old MSIE
+ if (tinyMCE.isMSIE5)
+ elm.outerHTML = elm.outerHTML;
+}
+
+function getSelectValue(form_obj, field_name) {
+ var elm = form_obj.elements[field_name];
+
+ if (!elm || elm.options == null || elm.selectedIndex == -1)
+ return "";
+
+ return elm.options[elm.selectedIndex].value;
+}
+
+function getLinkListHTML(elm_id, target_form_element, onchange_func) {
+ if (typeof(tinyMCELinkList) == "undefined" || tinyMCELinkList.length == 0)
+ return "";
+
+ var html = "";
+
+ html += '<select id="' + elm_id + '" name="' + elm_id + '"';
+ html += ' class="mceLinkList" onchange="this.form.' + target_form_element + '.value=';
+ html += 'this.options[this.selectedIndex].value;';
+
+ if (typeof(onchange_func) != "undefined")
+ html += onchange_func + '(\'' + target_form_element + '\',this.options[this.selectedIndex].text,this.options[this.selectedIndex].value);';
+
+ html += '"><option value="">---</option>';
+
+ for (var i=0; i<tinyMCELinkList.length; i++)
+ html += '<option value="' + tinyMCELinkList[i][1] + '">' + tinyMCELinkList[i][0] + '</option>';
+
+ html += '</select>';
+
+ return html;
+
+ // tinyMCE.debug('-- image list start --', html, '-- image list end --');
+}
+
+function getTargetListHTML(elm_id, target_form_element) {
+ var targets = tinyMCEPopup.getParam('theme_advanced_link_targets', '').split(';');
+ var html = '';
+
+ html += '<select id="' + elm_id + '" name="' + elm_id + '" onchange="this.form.' + target_form_element + '.value=';
+ html += 'this.options[this.selectedIndex].value;">';
+ html += '<option value="_self">' + tinyMCEPopup.getLang('advlink_dlg.target_same') + '</option>';
+ html += '<option value="_blank">' + tinyMCEPopup.getLang('advlink_dlg.target_blank') + ' (_blank)</option>';
+ html += '<option value="_parent">' + tinyMCEPopup.getLang('advlink_dlg.target_parent') + ' (_parent)</option>';
+ html += '<option value="_top">' + tinyMCEPopup.getLang('advlink_dlg.target_top') + ' (_top)</option>';
+
+ for (var i=0; i<targets.length; i++) {
+ var key, value;
+
+ if (targets[i] == "")
+ continue;
+
+ key = targets[i].split('=')[0];
+ value = targets[i].split('=')[1];
+
+ html += '<option value="' + key + '">' + value + ' (' + key + ')</option>';
+ }
+
+ html += '</select>';
+
+ return html;
+}
+
+// While loading
+preinit();
+tinyMCEPopup.onInit.add(init);
diff --git a/askbot/media/js/tinymce/plugins/advlink/langs/en_dlg.js b/askbot/media/js/tinymce/plugins/advlink/langs/en_dlg.js
new file mode 100644
index 00000000..3169a565
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advlink/langs/en_dlg.js
@@ -0,0 +1 @@
+tinyMCE.addI18n('en.advlink_dlg',{"target_name":"Target Name",classes:"Classes",style:"Style",id:"ID","popup_position":"Position (X/Y)",langdir:"Language Direction","popup_size":"Size","popup_dependent":"Dependent (Mozilla/Firefox Only)","popup_resizable":"Make Window Resizable","popup_location":"Show Location Bar","popup_menubar":"Show Menu Bar","popup_toolbar":"Show Toolbars","popup_statusbar":"Show Status Bar","popup_scrollbars":"Show Scrollbars","popup_return":"Insert \'return false\'","popup_name":"Window Name","popup_url":"Popup URL",popup:"JavaScript Popup","target_blank":"Open in New Window","target_top":"Open in Top Frame (Replaces All Frames)","target_parent":"Open in Parent Window/Frame","target_same":"Open in This Window/Frame","anchor_names":"Anchors","popup_opts":"Options","advanced_props":"Advanced Properties","event_props":"Events","popup_props":"Popup Properties","general_props":"General Properties","advanced_tab":"Advanced","events_tab":"Events","popup_tab":"Popup","general_tab":"General",list:"Link List","is_external":"The URL you entered seems to be an external link. Do you want to add the required http:// prefix?","is_email":"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",titlefield:"Title",target:"Target",url:"Link URL",title:"Insert/Edit Link","link_list":"Link List",rtl:"Right to Left",ltr:"Left to Right",accesskey:"AccessKey",tabindex:"TabIndex",rev:"Relationship Target to Page",rel:"Relationship Page to Target",mime:"Target MIME Type",encoding:"Target Character Encoding",langcode:"Language Code","target_langcode":"Target Language",width:"Width",height:"Height"}); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/advlink/link.htm b/askbot/media/js/tinymce/plugins/advlink/link.htm
new file mode 100644
index 00000000..8ab7c2a9
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advlink/link.htm
@@ -0,0 +1,338 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#advlink_dlg.title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="../../utils/validate.js"></script>
+ <script type="text/javascript" src="js/advlink.js"></script>
+ <link href="css/advlink.css" rel="stylesheet" type="text/css" />
+</head>
+<body id="advlink" style="display: none" role="application" onload="javascript:mcTabs.displayTab('general_tab','general_panel', true);" aria-labelledby="app_label">
+ <span class="mceVoiceLabel" id="app_label" style="display:none;">{#advlink_dlg.title}</span>
+ <form onsubmit="insertAction();return false;" action="#">
+ <div class="tabs" role="presentation">
+ <ul>
+ <li id="general_tab" class="current" aria-controls="general_panel" ><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#advlink_dlg.general_tab}</a></span></li>
+ <li id="popup_tab" aria-controls="popup_panel" ><span><a href="javascript:mcTabs.displayTab('popup_tab','popup_panel');" onmousedown="return false;">{#advlink_dlg.popup_tab}</a></span></li>
+ <li id="events_tab" aria-controls="events_panel"><span><a href="javascript:mcTabs.displayTab('events_tab','events_panel');" onmousedown="return false;">{#advlink_dlg.events_tab}</a></span></li>
+ <li id="advanced_tab" aria-controls="advanced_panel"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');" onmousedown="return false;">{#advlink_dlg.advanced_tab}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper" role="presentation">
+ <div id="general_panel" class="panel current">
+ <fieldset>
+ <legend>{#advlink_dlg.general_props}</legend>
+
+ <table border="0" cellpadding="4" cellspacing="0" role="presentation">
+ <tr>
+ <td class="nowrap"><label id="hreflabel" for="href">{#advlink_dlg.url}</label></td>
+ <td><table border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input id="href" name="href" type="text" class="mceFocus" value="" onchange="selectByValue(this.form,'linklisthref',this.value);" aria-required="true" /></td>
+ <td id="hrefbrowsercontainer">&nbsp;</td>
+ </tr>
+ </table></td>
+ </tr>
+ <tr id="linklisthrefrow">
+ <td class="column1"><label for="linklisthref">{#advlink_dlg.list}</label></td>
+ <td colspan="2" id="linklisthrefcontainer"><select id="linklisthref"><option value=""></option></select></td>
+ </tr>
+ <tr id="anchorlistrow">
+ <td class="column1"><label for="anchorlist">{#advlink_dlg.anchor_names}</label></td>
+ <td colspan="2" id="anchorlistcontainer"><select id="anchorlist"><option value=""></option></select></td>
+ </tr>
+ <tr>
+ <td><label id="targetlistlabel" for="targetlist">{#advlink_dlg.target}</label></td>
+ <td id="targetlistcontainer"><select id="targetlist"><option value=""></option></select></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label id="titlelabel" for="title">{#advlink_dlg.titlefield}</label></td>
+ <td><input id="title" name="title" type="text" value="" /></td>
+ </tr>
+ <tr>
+ <td><label id="classlabel" for="classlist">{#class_name}</label></td>
+ <td>
+ <select id="classlist" name="classlist" onchange="changeClass();">
+ <option value="" selected="selected">{#not_set}</option>
+ </select>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+
+ <div id="popup_panel" class="panel">
+ <fieldset>
+ <legend>{#advlink_dlg.popup_props}</legend>
+
+ <input type="checkbox" id="ispopup" name="ispopup" class="radio" onclick="setPopupControlsDisabled(!this.checked);buildOnClick();" />
+ <label id="ispopuplabel" for="ispopup">{#advlink_dlg.popup}</label>
+
+ <table border="0" cellpadding="0" cellspacing="4" role="presentation" >
+ <tr>
+ <td class="nowrap"><label for="popupurl">{#advlink_dlg.popup_url}</label>&nbsp;</td>
+ <td>
+ <table border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" name="popupurl" id="popupurl" value="" onchange="buildOnClick();" /></td>
+ <td id="popupurlbrowsercontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="popupname">{#advlink_dlg.popup_name}</label>&nbsp;</td>
+ <td><input type="text" name="popupname" id="popupname" value="" onchange="buildOnClick();" /></td>
+ </tr>
+ <tr role="group" aria-labelledby="popup_size_label">
+ <td class="nowrap"><label id="popup_size_label">{#advlink_dlg.popup_size}</label>&nbsp;</td>
+ <td class="nowrap">
+ <span style="display:none" id="width_voiceLabel">{#advlink_dlg.width}</span>
+ <input type="text" id="popupwidth" name="popupwidth" value="" onchange="buildOnClick();" aria-labelledby="width_voiceLabel" /> x
+ <span style="display:none" id="height_voiceLabel">{#advlink_dlg.height}</span>
+ <input type="text" id="popupheight" name="popupheight" value="" onchange="buildOnClick();" aria-labelledby="height_voiceLabel" /> px
+ </td>
+ </tr>
+ <tr role="group" aria-labelledby="popup_position_label center_hint">
+ <td class="nowrap" id="labelleft"><label id="popup_position_label">{#advlink_dlg.popup_position}</label>&nbsp;</td>
+ <td class="nowrap">
+ <span style="display:none" id="x_voiceLabel">X</span>
+ <input type="text" id="popupleft" name="popupleft" value="" onchange="buildOnClick();" aria-labelledby="x_voiceLabel" /> /
+ <span style="display:none" id="y_voiceLabel">Y</span>
+ <input type="text" id="popuptop" name="popuptop" value="" onchange="buildOnClick();" aria-labelledby="y_voiceLabel" /> <span id="center_hint">(c /c = center)</span>
+ </td>
+ </tr>
+ </table>
+
+ <fieldset>
+ <legend>{#advlink_dlg.popup_opts}</legend>
+
+ <table border="0" cellpadding="0" cellspacing="4" role="presentation" >
+ <tr>
+ <td><input type="checkbox" id="popuplocation" name="popuplocation" class="checkbox" onchange="buildOnClick();" /></td>
+ <td class="nowrap"><label id="popuplocationlabel" for="popuplocation">{#advlink_dlg.popup_location}</label></td>
+ <td><input type="checkbox" id="popupscrollbars" name="popupscrollbars" class="checkbox" onchange="buildOnClick();" /></td>
+ <td class="nowrap"><label id="popupscrollbarslabel" for="popupscrollbars">{#advlink_dlg.popup_scrollbars}</label></td>
+ </tr>
+ <tr>
+ <td><input type="checkbox" id="popupmenubar" name="popupmenubar" class="checkbox" onchange="buildOnClick();" /></td>
+ <td class="nowrap"><label id="popupmenubarlabel" for="popupmenubar">{#advlink_dlg.popup_menubar}</label></td>
+ <td><input type="checkbox" id="popupresizable" name="popupresizable" class="checkbox" onchange="buildOnClick();" /></td>
+ <td class="nowrap"><label id="popupresizablelabel" for="popupresizable">{#advlink_dlg.popup_resizable}</label></td>
+ </tr>
+ <tr>
+ <td><input type="checkbox" id="popuptoolbar" name="popuptoolbar" class="checkbox" onchange="buildOnClick();" /></td>
+ <td class="nowrap"><label id="popuptoolbarlabel" for="popuptoolbar">{#advlink_dlg.popup_toolbar}</label></td>
+ <td><input type="checkbox" id="popupdependent" name="popupdependent" class="checkbox" onchange="buildOnClick();" /></td>
+ <td class="nowrap"><label id="popupdependentlabel" for="popupdependent">{#advlink_dlg.popup_dependent}</label></td>
+ </tr>
+ <tr>
+ <td><input type="checkbox" id="popupstatus" name="popupstatus" class="checkbox" onchange="buildOnClick();" /></td>
+ <td class="nowrap"><label id="popupstatuslabel" for="popupstatus">{#advlink_dlg.popup_statusbar}</label></td>
+ <td><input type="checkbox" id="popupreturn" name="popupreturn" class="checkbox" onchange="buildOnClick();" checked="checked" /></td>
+ <td class="nowrap"><label id="popupreturnlabel" for="popupreturn">{#advlink_dlg.popup_return}</label></td>
+ </tr>
+ </table>
+ </fieldset>
+ </fieldset>
+ </div>
+
+ <div id="advanced_panel" class="panel">
+ <fieldset>
+ <legend>{#advlink_dlg.advanced_props}</legend>
+
+ <table border="0" cellpadding="0" cellspacing="4" role="presentation" >
+ <tr>
+ <td class="column1"><label id="idlabel" for="id">{#advlink_dlg.id}</label></td>
+ <td><input id="id" name="id" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td><label id="stylelabel" for="style">{#advlink_dlg.style}</label></td>
+ <td><input type="text" id="style" name="style" value="" /></td>
+ </tr>
+
+ <tr>
+ <td><label id="classeslabel" for="classes">{#advlink_dlg.classes}</label></td>
+ <td><input type="text" id="classes" name="classes" value="" onchange="selectByValue(this.form,'classlist',this.value,true);" /></td>
+ </tr>
+
+ <tr>
+ <td><label id="targetlabel" for="target">{#advlink_dlg.target_name}</label></td>
+ <td><input type="text" id="target" name="target" value="" onchange="selectByValue(this.form,'targetlist',this.value,true);" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label id="dirlabel" for="dir">{#advlink_dlg.langdir}</label></td>
+ <td>
+ <select id="dir" name="dir">
+ <option value="">{#not_set}</option>
+ <option value="ltr">{#advlink_dlg.ltr}</option>
+ <option value="rtl">{#advlink_dlg.rtl}</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label id="hreflanglabel" for="hreflang">{#advlink_dlg.target_langcode}</label></td>
+ <td><input type="text" id="hreflang" name="hreflang" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label id="langlabel" for="lang">{#advlink_dlg.langcode}</label></td>
+ <td>
+ <input id="lang" name="lang" type="text" value="" />
+ </td>
+ </tr>
+
+ <tr>
+ <td><label id="charsetlabel" for="charset">{#advlink_dlg.encoding}</label></td>
+ <td><input type="text" id="charset" name="charset" value="" /></td>
+ </tr>
+
+ <tr>
+ <td><label id="typelabel" for="type">{#advlink_dlg.mime}</label></td>
+ <td><input type="text" id="type" name="type" value="" /></td>
+ </tr>
+
+ <tr>
+ <td><label id="rellabel" for="rel">{#advlink_dlg.rel}</label></td>
+ <td><select id="rel" name="rel">
+ <option value="">{#not_set}</option>
+ <option value="lightbox">Lightbox</option>
+ <option value="alternate">Alternate</option>
+ <option value="designates">Designates</option>
+ <option value="stylesheet">Stylesheet</option>
+ <option value="start">Start</option>
+ <option value="next">Next</option>
+ <option value="prev">Prev</option>
+ <option value="contents">Contents</option>
+ <option value="index">Index</option>
+ <option value="glossary">Glossary</option>
+ <option value="copyright">Copyright</option>
+ <option value="chapter">Chapter</option>
+ <option value="subsection">Subsection</option>
+ <option value="appendix">Appendix</option>
+ <option value="help">Help</option>
+ <option value="bookmark">Bookmark</option>
+ <option value="nofollow">No Follow</option>
+ <option value="tag">Tag</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label id="revlabel" for="rev">{#advlink_dlg.rev}</label></td>
+ <td><select id="rev" name="rev">
+ <option value="">{#not_set}</option>
+ <option value="alternate">Alternate</option>
+ <option value="designates">Designates</option>
+ <option value="stylesheet">Stylesheet</option>
+ <option value="start">Start</option>
+ <option value="next">Next</option>
+ <option value="prev">Prev</option>
+ <option value="contents">Contents</option>
+ <option value="index">Index</option>
+ <option value="glossary">Glossary</option>
+ <option value="copyright">Copyright</option>
+ <option value="chapter">Chapter</option>
+ <option value="subsection">Subsection</option>
+ <option value="appendix">Appendix</option>
+ <option value="help">Help</option>
+ <option value="bookmark">Bookmark</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label id="tabindexlabel" for="tabindex">{#advlink_dlg.tabindex}</label></td>
+ <td><input type="text" id="tabindex" name="tabindex" value="" /></td>
+ </tr>
+
+ <tr>
+ <td><label id="accesskeylabel" for="accesskey">{#advlink_dlg.accesskey}</label></td>
+ <td><input type="text" id="accesskey" name="accesskey" value="" /></td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+
+ <div id="events_panel" class="panel">
+ <fieldset>
+ <legend>{#advlink_dlg.event_props}</legend>
+
+ <table border="0" cellpadding="0" cellspacing="4" role="presentation" >
+ <tr>
+ <td class="column1"><label for="onfocus">onfocus</label></td>
+ <td><input id="onfocus" name="onfocus" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="onblur">onblur</label></td>
+ <td><input id="onblur" name="onblur" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="onclick">onclick</label></td>
+ <td><input id="onclick" name="onclick" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="ondblclick">ondblclick</label></td>
+ <td><input id="ondblclick" name="ondblclick" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="onmousedown">onmousedown</label></td>
+ <td><input id="onmousedown" name="onmousedown" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="onmouseup">onmouseup</label></td>
+ <td><input id="onmouseup" name="onmouseup" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="onmouseover">onmouseover</label></td>
+ <td><input id="onmouseover" name="onmouseover" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="onmousemove">onmousemove</label></td>
+ <td><input id="onmousemove" name="onmousemove" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="onmouseout">onmouseout</label></td>
+ <td><input id="onmouseout" name="onmouseout" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="onkeypress">onkeypress</label></td>
+ <td><input id="onkeypress" name="onkeypress" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="onkeydown">onkeydown</label></td>
+ <td><input id="onkeydown" name="onkeydown" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="onkeyup">onkeyup</label></td>
+ <td><input id="onkeyup" name="onkeyup" type="text" value="" /></td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#insert}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+ </form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/advlist/editor_plugin.js b/askbot/media/js/tinymce/plugins/advlist/editor_plugin.js
new file mode 100644
index 00000000..57ecce6e
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advlist/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var a=tinymce.each;tinymce.create("tinymce.plugins.AdvListPlugin",{init:function(b,c){var d=this;d.editor=b;function e(g){var f=[];a(g.split(/,/),function(h){f.push({title:"advlist."+(h=="default"?"def":h.replace(/-/g,"_")),styles:{listStyleType:h=="default"?"":h}})});return f}d.numlist=b.getParam("advlist_number_styles")||e("default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman");d.bullist=b.getParam("advlist_bullet_styles")||e("default,circle,disc,square");if(tinymce.isIE&&/MSIE [2-7]/.test(navigator.userAgent)){d.isIE7=true}},createControl:function(d,b){var f=this,e,i,g=f.editor;if(d=="numlist"||d=="bullist"){if(f[d][0].title=="advlist.def"){i=f[d][0]}function c(j,l){var k=true;a(l.styles,function(n,m){if(g.dom.getStyle(j,m)!=n){k=false;return false}});return k}function h(){var k,l=g.dom,j=g.selection;k=l.getParent(j.getNode(),"ol,ul");if(!k||k.nodeName==(d=="bullist"?"OL":"UL")||c(k,i)){g.execCommand(d=="bullist"?"InsertUnorderedList":"InsertOrderedList")}if(i){k=l.getParent(j.getNode(),"ol,ul");if(k){l.setStyles(k,i.styles);k.removeAttribute("data-mce-style")}}g.focus()}e=b.createSplitButton(d,{title:"advanced."+d+"_desc","class":"mce_"+d,onclick:function(){h()}});e.onRenderMenu.add(function(j,k){k.onHideMenu.add(function(){if(f.bookmark){g.selection.moveToBookmark(f.bookmark);f.bookmark=0}});k.onShowMenu.add(function(){var n=g.dom,m=n.getParent(g.selection.getNode(),"ol,ul"),l;if(m||i){l=f[d];a(k.items,function(o){var p=true;o.setSelected(0);if(m&&!o.isDisabled()){a(l,function(q){if(q.id==o.id){if(!c(m,q)){p=false;return false}}});if(p){o.setSelected(1)}}});if(!m){k.items[i.id].setSelected(1)}}g.focus();if(tinymce.isIE){f.bookmark=g.selection.getBookmark(1)}});k.add({id:g.dom.uniqueId(),title:"advlist.types","class":"mceMenuItemTitle",titleItem:true}).setDisabled(1);a(f[d],function(l){if(f.isIE7&&l.styles.listStyleType=="lower-greek"){return}l.id=g.dom.uniqueId();k.add({id:l.id,title:l.title,onclick:function(){i=l;h()}})})});return e}},getInfo:function(){return{longname:"Advanced lists",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advlist",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("advlist",tinymce.plugins.AdvListPlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/advlist/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/advlist/editor_plugin_src.js
new file mode 100644
index 00000000..a8f046b4
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/advlist/editor_plugin_src.js
@@ -0,0 +1,176 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var each = tinymce.each;
+
+ tinymce.create('tinymce.plugins.AdvListPlugin', {
+ init : function(ed, url) {
+ var t = this;
+
+ t.editor = ed;
+
+ function buildFormats(str) {
+ var formats = [];
+
+ each(str.split(/,/), function(type) {
+ formats.push({
+ title : 'advlist.' + (type == 'default' ? 'def' : type.replace(/-/g, '_')),
+ styles : {
+ listStyleType : type == 'default' ? '' : type
+ }
+ });
+ });
+
+ return formats;
+ };
+
+ // Setup number formats from config or default
+ t.numlist = ed.getParam("advlist_number_styles") || buildFormats("default,lower-alpha,lower-greek,lower-roman,upper-alpha,upper-roman");
+ t.bullist = ed.getParam("advlist_bullet_styles") || buildFormats("default,circle,disc,square");
+
+ if (tinymce.isIE && /MSIE [2-7]/.test(navigator.userAgent))
+ t.isIE7 = true;
+ },
+
+ createControl: function(name, cm) {
+ var t = this, btn, format, editor = t.editor;
+
+ if (name == 'numlist' || name == 'bullist') {
+ // Default to first item if it's a default item
+ if (t[name][0].title == 'advlist.def')
+ format = t[name][0];
+
+ function hasFormat(node, format) {
+ var state = true;
+
+ each(format.styles, function(value, name) {
+ // Format doesn't match
+ if (editor.dom.getStyle(node, name) != value) {
+ state = false;
+ return false;
+ }
+ });
+
+ return state;
+ };
+
+ function applyListFormat() {
+ var list, dom = editor.dom, sel = editor.selection;
+
+ // Check for existing list element
+ list = dom.getParent(sel.getNode(), 'ol,ul');
+
+ // Switch/add list type if needed
+ if (!list || list.nodeName == (name == 'bullist' ? 'OL' : 'UL') || hasFormat(list, format))
+ editor.execCommand(name == 'bullist' ? 'InsertUnorderedList' : 'InsertOrderedList');
+
+ // Append styles to new list element
+ if (format) {
+ list = dom.getParent(sel.getNode(), 'ol,ul');
+ if (list) {
+ dom.setStyles(list, format.styles);
+ list.removeAttribute('data-mce-style');
+ }
+ }
+
+ editor.focus();
+ };
+
+ btn = cm.createSplitButton(name, {
+ title : 'advanced.' + name + '_desc',
+ 'class' : 'mce_' + name,
+ onclick : function() {
+ applyListFormat();
+ }
+ });
+
+ btn.onRenderMenu.add(function(btn, menu) {
+ menu.onHideMenu.add(function() {
+ if (t.bookmark) {
+ editor.selection.moveToBookmark(t.bookmark);
+ t.bookmark = 0;
+ }
+ });
+
+ menu.onShowMenu.add(function() {
+ var dom = editor.dom, list = dom.getParent(editor.selection.getNode(), 'ol,ul'), fmtList;
+
+ if (list || format) {
+ fmtList = t[name];
+
+ // Unselect existing items
+ each(menu.items, function(item) {
+ var state = true;
+
+ item.setSelected(0);
+
+ if (list && !item.isDisabled()) {
+ each(fmtList, function(fmt) {
+ if (fmt.id == item.id) {
+ if (!hasFormat(list, fmt)) {
+ state = false;
+ return false;
+ }
+ }
+ });
+
+ if (state)
+ item.setSelected(1);
+ }
+ });
+
+ // Select the current format
+ if (!list)
+ menu.items[format.id].setSelected(1);
+ }
+
+ editor.focus();
+
+ // IE looses it's selection so store it away and restore it later
+ if (tinymce.isIE) {
+ t.bookmark = editor.selection.getBookmark(1);
+ }
+ });
+
+ menu.add({id : editor.dom.uniqueId(), title : 'advlist.types', 'class' : 'mceMenuItemTitle', titleItem: true}).setDisabled(1);
+
+ each(t[name], function(item) {
+ // IE<8 doesn't support lower-greek, skip it
+ if (t.isIE7 && item.styles.listStyleType == 'lower-greek')
+ return;
+
+ item.id = editor.dom.uniqueId();
+
+ menu.add({id : item.id, title : item.title, onclick : function() {
+ format = item;
+ applyListFormat();
+ }});
+ });
+ });
+
+ return btn;
+ }
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Advanced lists',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advlist',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('advlist', tinymce.plugins.AdvListPlugin);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/askbot_attachment/editor_plugin.js b/askbot/media/js/tinymce/plugins/askbot_attachment/editor_plugin.js
new file mode 100644
index 00000000..d1ef13b4
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/askbot_attachment/editor_plugin.js
@@ -0,0 +1,117 @@
+/**
+ * askbot_attachment.js
+ *
+ * Copyright 2012, Askbot SpA
+ * Released under License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var insertIntoDom = function(url, description) {
+ var content = '<a href="' + url;
+ if (description) {
+ content = content + '" title="' + description;
+ }
+ content = content + '">file attached</a>';
+
+ tinyMCE.activeEditor.focus();
+ if (document.selection) {
+ //this branch is a work around the IE's "this" quirk
+ var sel = document.selection.createRange();
+ sel.pasteHTML(content);
+ } else {
+ var sel = tinyMCE.activeEditor.selection;
+ sel.setContent(content);
+ }
+ };
+
+ var modalMenuHeadline = gettext('Insert a file');
+
+ var createDialog = function() {
+ var dialog = new FileUploadDialog();
+ dialog.setHeadingText(modalMenuHeadline);
+ dialog.setPostUploadHandler(insertIntoDom);
+ dialog.setInputId('askbot_attachment_input');
+ dialog.setUrlInputTooltip(gettext('Or paste file url here'));
+ $(document).append(dialog.getElement());
+ return dialog;
+ };
+
+ var dialog = undefined;
+
+ var getDialog = function() {
+ if (dialog === undefined) {
+ dialog = createDialog();
+ }
+ return dialog;
+ };
+
+ // Load plugin specific language pack
+ tinymce.PluginManager.requireLangPack('askbot_attachment');
+
+ tinymce.create('tinymce.plugins.AskbotAttachmentPlugin', {
+ /**
+ * Initializes the plugin, this will be executed after the plugin has been created.
+ * This call is done before the editor instance has finished it's initialization so use the onInit event
+ * of the editor instance to intercept that event.
+ *
+ * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in.
+ * @param {string} url Absolute URL to where the plugin is located.
+ */
+ init : function(ed, url) {
+ // Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('mceAskbotAttachment');
+ ed.addCommand('mceAskbotAttachment', function() {
+ //start file uploader modal menu
+ var dialog = getDialog();
+ dialog.show();
+ });
+
+ // Register askbot_attachment button
+ ed.addButton('askbot_attachment', {
+ title : gettext('Insert a file'),
+ cmd : 'mceAskbotAttachment'
+ //image : url + '/img/askbot_leuploader.gif'
+ });
+
+ // Add a node change handler, selects the button in the UI when a image is selected
+ ed.onNodeChange.add(function(ed, cm, n) {
+ cm.setActive('askbot_attachment', n.nodeName == 'IMG');
+ });
+ },
+
+ /**
+ * Creates control instances based in the incomming name. This method is normally not
+ * needed since the addButton method of the tinymce.Editor class is a more easy way of adding buttons
+ * but you sometimes need to create more complex controls like listboxes, split buttons etc then this
+ * method can be used to create those.
+ *
+ * @param {String} n Name of the control to create.
+ * @param {tinymce.ControlManager} cm Control manager to use inorder to create new control.
+ * @return {tinymce.ui.Control} New control instance or null if no control was created.
+ */
+ createControl : function(n, cm) {
+ return null;
+ },
+
+ /**
+ * Returns information about the plugin as a name/value array.
+ * The current keys are longname, author, authorurl, infourl and version.
+ *
+ * @return {Object} Name/value array containing information about the plugin.
+ */
+ getInfo : function() {
+ return {
+ longname : 'AskbotAttachment plugin',
+ author : 'Askbot SpA, Chile',
+ authorurl : 'http://askbot.com',
+ infourl : 'http://github.com/ASKBOT/askbot-devel/',
+ version : '0.1'
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('askbot_attachment', tinymce.plugins.AskbotAttachmentPlugin);
+})();
diff --git a/askbot/media/js/tinymce/plugins/askbot_attachment/langs/en.js b/askbot/media/js/tinymce/plugins/askbot_attachment/langs/en.js
new file mode 100644
index 00000000..d38ad8ea
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/askbot_attachment/langs/en.js
@@ -0,0 +1,3 @@
+tinyMCE.addI18n('en.askbot_imageupload',{
+ desc : 'Upload an image'
+});
diff --git a/askbot/media/js/tinymce/plugins/askbot_attachment/langs/en_dlg.js b/askbot/media/js/tinymce/plugins/askbot_attachment/langs/en_dlg.js
new file mode 100644
index 00000000..5cd400c1
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/askbot_attachment/langs/en_dlg.js
@@ -0,0 +1,3 @@
+tinyMCE.addI18n('en.askbot_imageupload_dlg',{
+ title : 'Upload an image'
+});
diff --git a/askbot/media/js/tinymce/plugins/askbot_imageuploader/editor_plugin.js b/askbot/media/js/tinymce/plugins/askbot_imageuploader/editor_plugin.js
new file mode 100644
index 00000000..7fa6b6be
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/askbot_imageuploader/editor_plugin.js
@@ -0,0 +1,117 @@
+/**
+ * askbot_imageuploader.js
+ *
+ * Copyright 2012, Askbot SpA
+ * Released under License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var insertIntoDom = function(url, description) {
+ var content = '<img src="' + url;
+ if (description) {
+ content = content + '" alt="' + description;
+ }
+ content = content + '"/>';
+
+ tinyMCE.activeEditor.focus();
+ if (document.selection) {
+ //this branch is a work around the IE "this" quirk
+ var sel = document.selection.createRange();
+ sel.pasteHTML(content);
+ } else {
+ var sel = tinyMCE.activeEditor.selection;
+ sel.setContent(content);
+ }
+ };
+
+ var modalMenuHeadline = gettext('Upload an image');
+
+ var createDialog = function() {
+ var dialog = new FileUploadDialog();
+ dialog.setHeadingText(modalMenuHeadline);
+ dialog.setPostUploadHandler(insertIntoDom);
+ dialog.setUrlInputTooltip('Or paste image url here');
+ dialog.setInputId('askbot_imageuploader_input');
+ $(document).append(dialog.getElement());
+ return dialog;
+ };
+
+ var dialog = undefined;
+
+ var getDialog = function() {
+ if (dialog === undefined) {
+ dialog = createDialog();
+ }
+ return dialog;
+ };
+
+ // Load plugin specific language pack
+ tinymce.PluginManager.requireLangPack('askbot_imageuploader');
+
+ tinymce.create('tinymce.plugins.AskbotImageUploaderPlugin', {
+ /**
+ * Initializes the plugin, this will be executed after the plugin has been created.
+ * This call is done before the editor instance has finished it's initialization so use the onInit event
+ * of the editor instance to intercept that event.
+ *
+ * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in.
+ * @param {string} url Absolute URL to where the plugin is located.
+ */
+ init : function(ed, url) {
+ // Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('mceAskbotImageUploader');
+ ed.addCommand('mceAskbotImageUploader', function() {
+ //start file uploader modal menu
+ var dialog = getDialog();
+ dialog.show();
+ });
+
+ // Register askbot_imageuploader button
+ ed.addButton('askbot_imageuploader', {
+ title : gettext('Insert image'),
+ cmd : 'mceAskbotImageUploader'
+ //image : url + '/img/askbot_leuploader.gif'
+ });
+
+ // Add a node change handler, selects the button in the UI when a image is selected
+ ed.onNodeChange.add(function(ed, cm, n) {
+ cm.setActive('askbot_imageuploader', n.nodeName == 'IMG');
+ });
+ },
+
+ /**
+ * Creates control instances based in the incomming name. This method is normally not
+ * needed since the addButton method of the tinymce.Editor class is a more easy way of adding buttons
+ * but you sometimes need to create more complex controls like listboxes, split buttons etc then this
+ * method can be used to create those.
+ *
+ * @param {String} n Name of the control to create.
+ * @param {tinymce.ControlManager} cm Control manager to use inorder to create new control.
+ * @return {tinymce.ui.Control} New control instance or null if no control was created.
+ */
+ createControl : function(n, cm) {
+ return null;
+ },
+
+ /**
+ * Returns information about the plugin as a name/value array.
+ * The current keys are longname, author, authorurl, infourl and version.
+ *
+ * @return {Object} Name/value array containing information about the plugin.
+ */
+ getInfo : function() {
+ return {
+ longname : 'AskbotImageUploader plugin',
+ author : 'Askbot SpA, Chile',
+ authorurl : 'http://askbot.com',
+ infourl : 'http://github.com/ASKBOT/askbot-devel/',
+ version : '0.1'
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('askbot_imageuploader', tinymce.plugins.AskbotImageUploaderPlugin);
+})();
diff --git a/askbot/media/js/tinymce/plugins/askbot_imageuploader/langs/en.js b/askbot/media/js/tinymce/plugins/askbot_imageuploader/langs/en.js
new file mode 100644
index 00000000..d38ad8ea
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/askbot_imageuploader/langs/en.js
@@ -0,0 +1,3 @@
+tinyMCE.addI18n('en.askbot_imageupload',{
+ desc : 'Upload an image'
+});
diff --git a/askbot/media/js/tinymce/plugins/askbot_imageuploader/langs/en_dlg.js b/askbot/media/js/tinymce/plugins/askbot_imageuploader/langs/en_dlg.js
new file mode 100644
index 00000000..5cd400c1
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/askbot_imageuploader/langs/en_dlg.js
@@ -0,0 +1,3 @@
+tinyMCE.addI18n('en.askbot_imageupload_dlg',{
+ title : 'Upload an image'
+});
diff --git a/askbot/media/js/tinymce/plugins/autolink/editor_plugin.js b/askbot/media/js/tinymce/plugins/autolink/editor_plugin.js
new file mode 100644
index 00000000..9662b50b
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/autolink/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.AutolinkPlugin",{init:function(a,b){var c=this;a.onKeyDown.addToTop(function(d,f){if(f.keyCode==13){return c.handleEnter(d)}});if(tinyMCE.isIE){return}a.onKeyPress.add(function(d,f){if(f.which==41){return c.handleEclipse(d)}});a.onKeyUp.add(function(d,f){if(f.keyCode==32){return c.handleSpacebar(d)}})},handleEclipse:function(a){this.parseCurrentLine(a,-1,"(",true)},handleSpacebar:function(a){this.parseCurrentLine(a,0,"",true)},handleEnter:function(a){this.parseCurrentLine(a,-1,"",false)},parseCurrentLine:function(i,d,b,g){var a,f,c,n,k,m,h,e,j;a=i.selection.getRng(true).cloneRange();if(a.startOffset<5){e=a.endContainer.previousSibling;if(e==null){if(a.endContainer.firstChild==null||a.endContainer.firstChild.nextSibling==null){return}e=a.endContainer.firstChild.nextSibling}j=e.length;a.setStart(e,j);a.setEnd(e,j);if(a.endOffset<5){return}f=a.endOffset;n=e}else{n=a.endContainer;if(n.nodeType!=3&&n.firstChild){while(n.nodeType!=3&&n.firstChild){n=n.firstChild}a.setStart(n,0);a.setEnd(n,n.nodeValue.length)}if(a.endOffset==1){f=2}else{f=a.endOffset-1-d}}c=f;do{a.setStart(n,f-2);a.setEnd(n,f-1);f-=1}while(a.toString()!=" "&&a.toString()!=""&&a.toString().charCodeAt(0)!=160&&(f-2)>=0&&a.toString()!=b);if(a.toString()==b||a.toString().charCodeAt(0)==160){a.setStart(n,f);a.setEnd(n,c);f+=1}else{if(a.startOffset==0){a.setStart(n,0);a.setEnd(n,c)}else{a.setStart(n,f);a.setEnd(n,c)}}var m=a.toString();if(m.charAt(m.length-1)=="."){a.setEnd(n,c-1)}m=a.toString();h=m.match(/^(https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.|(?:mailto:)?[A-Z0-9._%+-]+@)(.+)$/i);if(h){if(h[1]=="www."){h[1]="http://www."}else{if(/@$/.test(h[1])&&!/^mailto:/.test(h[1])){h[1]="mailto:"+h[1]}}k=i.selection.getBookmark();i.selection.setRng(a);tinyMCE.execCommand("createlink",false,h[1]+h[2]);i.selection.moveToBookmark(k);i.nodeChanged();if(tinyMCE.isWebKit){i.selection.collapse(false);var l=Math.min(n.length,c+1);a.setStart(n,l);a.setEnd(n,l);i.selection.setRng(a)}}},getInfo:function(){return{longname:"Autolink",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/autolink",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("autolink",tinymce.plugins.AutolinkPlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/autolink/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/autolink/editor_plugin_src.js
new file mode 100644
index 00000000..8c1cd688
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/autolink/editor_plugin_src.js
@@ -0,0 +1,181 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2011, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.AutolinkPlugin', {
+ /**
+ * Initializes the plugin, this will be executed after the plugin has been created.
+ * This call is done before the editor instance has finished it's initialization so use the onInit event
+ * of the editor instance to intercept that event.
+ *
+ * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in.
+ * @param {string} url Absolute URL to where the plugin is located.
+ */
+
+ init : function(ed, url) {
+ var t = this;
+
+ // Add a key down handler
+ ed.onKeyDown.addToTop(function(ed, e) {
+ if (e.keyCode == 13)
+ return t.handleEnter(ed);
+ });
+
+ // Internet Explorer has built-in automatic linking for most cases
+ if (tinyMCE.isIE)
+ return;
+
+ ed.onKeyPress.add(function(ed, e) {
+ if (e.which == 41)
+ return t.handleEclipse(ed);
+ });
+
+ // Add a key up handler
+ ed.onKeyUp.add(function(ed, e) {
+ if (e.keyCode == 32)
+ return t.handleSpacebar(ed);
+ });
+ },
+
+ handleEclipse : function(ed) {
+ this.parseCurrentLine(ed, -1, '(', true);
+ },
+
+ handleSpacebar : function(ed) {
+ this.parseCurrentLine(ed, 0, '', true);
+ },
+
+ handleEnter : function(ed) {
+ this.parseCurrentLine(ed, -1, '', false);
+ },
+
+ parseCurrentLine : function(ed, end_offset, delimiter, goback) {
+ var r, end, start, endContainer, bookmark, text, matches, prev, len;
+
+ // We need at least five characters to form a URL,
+ // hence, at minimum, five characters from the beginning of the line.
+ r = ed.selection.getRng(true).cloneRange();
+ if (r.startOffset < 5) {
+ // During testing, the caret is placed inbetween two text nodes.
+ // The previous text node contains the URL.
+ prev = r.endContainer.previousSibling;
+ if (prev == null) {
+ if (r.endContainer.firstChild == null || r.endContainer.firstChild.nextSibling == null)
+ return;
+
+ prev = r.endContainer.firstChild.nextSibling;
+ }
+ len = prev.length;
+ r.setStart(prev, len);
+ r.setEnd(prev, len);
+
+ if (r.endOffset < 5)
+ return;
+
+ end = r.endOffset;
+ endContainer = prev;
+ } else {
+ endContainer = r.endContainer;
+
+ // Get a text node
+ if (endContainer.nodeType != 3 && endContainer.firstChild) {
+ while (endContainer.nodeType != 3 && endContainer.firstChild)
+ endContainer = endContainer.firstChild;
+
+ r.setStart(endContainer, 0);
+ r.setEnd(endContainer, endContainer.nodeValue.length);
+ }
+
+ if (r.endOffset == 1)
+ end = 2;
+ else
+ end = r.endOffset - 1 - end_offset;
+ }
+
+ start = end;
+
+ do
+ {
+ // Move the selection one character backwards.
+ r.setStart(endContainer, end - 2);
+ r.setEnd(endContainer, end - 1);
+ end -= 1;
+
+ // Loop until one of the following is found: a blank space, &nbsp;, delimeter, (end-2) >= 0
+ } while (r.toString() != ' ' && r.toString() != '' && r.toString().charCodeAt(0) != 160 && (end -2) >= 0 && r.toString() != delimiter);
+
+ if (r.toString() == delimiter || r.toString().charCodeAt(0) == 160) {
+ r.setStart(endContainer, end);
+ r.setEnd(endContainer, start);
+ end += 1;
+ } else if (r.startOffset == 0) {
+ r.setStart(endContainer, 0);
+ r.setEnd(endContainer, start);
+ }
+ else {
+ r.setStart(endContainer, end);
+ r.setEnd(endContainer, start);
+ }
+
+ // Exclude last . from word like "www.site.com."
+ var text = r.toString();
+ if (text.charAt(text.length - 1) == '.') {
+ r.setEnd(endContainer, start - 1);
+ }
+
+ text = r.toString();
+ matches = text.match(/^(https?:\/\/|ssh:\/\/|ftp:\/\/|file:\/|www\.|(?:mailto:)?[A-Z0-9._%+-]+@)(.+)$/i);
+
+ if (matches) {
+ if (matches[1] == 'www.') {
+ matches[1] = 'http://www.';
+ } else if (/@$/.test(matches[1]) && !/^mailto:/.test(matches[1])) {
+ matches[1] = 'mailto:' + matches[1];
+ }
+
+ bookmark = ed.selection.getBookmark();
+
+ ed.selection.setRng(r);
+ tinyMCE.execCommand('createlink',false, matches[1] + matches[2]);
+ ed.selection.moveToBookmark(bookmark);
+ ed.nodeChanged();
+
+ // TODO: Determine if this is still needed.
+ if (tinyMCE.isWebKit) {
+ // move the caret to its original position
+ ed.selection.collapse(false);
+ var max = Math.min(endContainer.length, start + 1);
+ r.setStart(endContainer, max);
+ r.setEnd(endContainer, max);
+ ed.selection.setRng(r);
+ }
+ }
+ },
+
+ /**
+ * Returns information about the plugin as a name/value array.
+ * The current keys are longname, author, authorurl, infourl and version.
+ *
+ * @return {Object} Name/value array containing information about the plugin.
+ */
+ getInfo : function() {
+ return {
+ longname : 'Autolink',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/autolink',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('autolink', tinymce.plugins.AutolinkPlugin);
+})();
diff --git a/askbot/media/js/tinymce/plugins/autoresize/editor_plugin.js b/askbot/media/js/tinymce/plugins/autoresize/editor_plugin.js
new file mode 100644
index 00000000..46d9dc3d
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/autoresize/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.AutoResizePlugin",{init:function(a,c){var d=this,e=0;if(a.getParam("fullscreen_is_enabled")){return}function b(){var j,i=a.getDoc(),f=i.body,l=i.documentElement,h=tinymce.DOM,k=d.autoresize_min_height,g;g=tinymce.isIE?f.scrollHeight:(tinymce.isWebKit&&f.clientHeight==0?0:f.offsetHeight);if(g>d.autoresize_min_height){k=g}if(d.autoresize_max_height&&g>d.autoresize_max_height){k=d.autoresize_max_height;f.style.overflowY="auto";l.style.overflowY="auto"}else{f.style.overflowY="hidden";l.style.overflowY="hidden";f.scrollTop=0}if(k!==e){j=k-e;h.setStyle(h.get(a.id+"_ifr"),"height",k+"px");e=k;if(tinymce.isWebKit&&j<0){b()}}}d.editor=a;d.autoresize_min_height=parseInt(a.getParam("autoresize_min_height",a.getElement().offsetHeight));d.autoresize_max_height=parseInt(a.getParam("autoresize_max_height",0));a.onInit.add(function(f){f.dom.setStyle(f.getBody(),"paddingBottom",f.getParam("autoresize_bottom_margin",50)+"px")});a.onChange.add(b);a.onSetContent.add(b);a.onPaste.add(b);a.onKeyUp.add(b);a.onPostRender.add(b);if(a.getParam("autoresize_on_init",true)){a.onLoad.add(b);a.onLoadContent.add(b)}a.addCommand("mceAutoResize",b)},getInfo:function(){return{longname:"Auto Resize",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/autoresize",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("autoresize",tinymce.plugins.AutoResizePlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/autoresize/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/autoresize/editor_plugin_src.js
new file mode 100644
index 00000000..7673bcff
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/autoresize/editor_plugin_src.js
@@ -0,0 +1,119 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ /**
+ * Auto Resize
+ *
+ * This plugin automatically resizes the content area to fit its content height.
+ * It will retain a minimum height, which is the height of the content area when
+ * it's initialized.
+ */
+ tinymce.create('tinymce.plugins.AutoResizePlugin', {
+ /**
+ * Initializes the plugin, this will be executed after the plugin has been created.
+ * This call is done before the editor instance has finished it's initialization so use the onInit event
+ * of the editor instance to intercept that event.
+ *
+ * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in.
+ * @param {string} url Absolute URL to where the plugin is located.
+ */
+ init : function(ed, url) {
+ var t = this, oldSize = 0;
+
+ if (ed.getParam('fullscreen_is_enabled'))
+ return;
+
+ /**
+ * This method gets executed each time the editor needs to resize.
+ */
+ function resize() {
+ var deltaSize, d = ed.getDoc(), body = d.body, de = d.documentElement, DOM = tinymce.DOM, resizeHeight = t.autoresize_min_height, myHeight;
+
+ // Get height differently depending on the browser used
+ myHeight = tinymce.isIE ? body.scrollHeight : (tinymce.isWebKit && body.clientHeight == 0 ? 0 : body.offsetHeight);
+
+ // Don't make it smaller than the minimum height
+ if (myHeight > t.autoresize_min_height)
+ resizeHeight = myHeight;
+
+ // If a maximum height has been defined don't exceed this height
+ if (t.autoresize_max_height && myHeight > t.autoresize_max_height) {
+ resizeHeight = t.autoresize_max_height;
+ body.style.overflowY = "auto";
+ de.style.overflowY = "auto"; // Old IE
+ } else {
+ body.style.overflowY = "hidden";
+ de.style.overflowY = "hidden"; // Old IE
+ body.scrollTop = 0;
+ }
+
+ // Resize content element
+ if (resizeHeight !== oldSize) {
+ deltaSize = resizeHeight - oldSize;
+ DOM.setStyle(DOM.get(ed.id + '_ifr'), 'height', resizeHeight + 'px');
+ oldSize = resizeHeight;
+
+ // WebKit doesn't decrease the size of the body element until the iframe gets resized
+ // So we need to continue to resize the iframe down until the size gets fixed
+ if (tinymce.isWebKit && deltaSize < 0)
+ resize();
+ }
+ };
+
+ t.editor = ed;
+
+ // Define minimum height
+ t.autoresize_min_height = parseInt(ed.getParam('autoresize_min_height', ed.getElement().offsetHeight));
+
+ // Define maximum height
+ t.autoresize_max_height = parseInt(ed.getParam('autoresize_max_height', 0));
+
+ // Add padding at the bottom for better UX
+ ed.onInit.add(function(ed){
+ ed.dom.setStyle(ed.getBody(), 'paddingBottom', ed.getParam('autoresize_bottom_margin', 50) + 'px');
+ });
+
+ // Add appropriate listeners for resizing content area
+ ed.onChange.add(resize);
+ ed.onSetContent.add(resize);
+ ed.onPaste.add(resize);
+ ed.onKeyUp.add(resize);
+ ed.onPostRender.add(resize);
+
+ if (ed.getParam('autoresize_on_init', true)) {
+ ed.onLoad.add(resize);
+ ed.onLoadContent.add(resize);
+ }
+
+ // Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('mceExample');
+ ed.addCommand('mceAutoResize', resize);
+ },
+
+ /**
+ * Returns information about the plugin as a name/value array.
+ * The current keys are longname, author, authorurl, infourl and version.
+ *
+ * @return {Object} Name/value array containing information about the plugin.
+ */
+ getInfo : function() {
+ return {
+ longname : 'Auto Resize',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/autoresize',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('autoresize', tinymce.plugins.AutoResizePlugin);
+})();
diff --git a/askbot/media/js/tinymce/plugins/autosave/editor_plugin.js b/askbot/media/js/tinymce/plugins/autosave/editor_plugin.js
new file mode 100644
index 00000000..6da98ff3
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/autosave/editor_plugin.js
@@ -0,0 +1 @@
+(function(e){var c="autosave",g="restoredraft",b=true,f,d,a=e.util.Dispatcher;e.create("tinymce.plugins.AutoSave",{init:function(i,j){var h=this,l=i.settings;h.editor=i;function k(n){var m={s:1000,m:60000};n=/^(\d+)([ms]?)$/.exec(""+n);return(n[2]?m[n[2]]:1)*parseInt(n)}e.each({ask_before_unload:b,interval:"30s",retention:"20m",minlength:50},function(n,m){m=c+"_"+m;if(l[m]===f){l[m]=n}});l.autosave_interval=k(l.autosave_interval);l.autosave_retention=k(l.autosave_retention);i.addButton(g,{title:c+".restore_content",onclick:function(){if(i.getContent({draft:true}).replace(/\s|&nbsp;|<\/?p[^>]*>|<br[^>]*>/gi,"").length>0){i.windowManager.confirm(c+".warning_message",function(m){if(m){h.restoreDraft()}})}else{h.restoreDraft()}}});i.onNodeChange.add(function(){var m=i.controlManager;if(m.get(g)){m.setDisabled(g,!h.hasDraft())}});i.onInit.add(function(){if(i.controlManager.get(g)){h.setupStorage(i);setInterval(function(){if(!i.removed){h.storeDraft();i.nodeChanged()}},l.autosave_interval)}});h.onStoreDraft=new a(h);h.onRestoreDraft=new a(h);h.onRemoveDraft=new a(h);if(!d){window.onbeforeunload=e.plugins.AutoSave._beforeUnloadHandler;d=b}},getInfo:function(){return{longname:"Auto save",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/autosave",version:e.majorVersion+"."+e.minorVersion}},getExpDate:function(){return new Date(new Date().getTime()+this.editor.settings.autosave_retention).toUTCString()},setupStorage:function(i){var h=this,k=c+"_test",j="OK";h.key=c+i.id;e.each([function(){if(localStorage){localStorage.setItem(k,j);if(localStorage.getItem(k)===j){localStorage.removeItem(k);return localStorage}}},function(){if(sessionStorage){sessionStorage.setItem(k,j);if(sessionStorage.getItem(k)===j){sessionStorage.removeItem(k);return sessionStorage}}},function(){if(e.isIE){i.getElement().style.behavior="url('#default#userData')";return{autoExpires:b,setItem:function(l,n){var m=i.getElement();m.setAttribute(l,n);m.expires=h.getExpDate();try{m.save("TinyMCE")}catch(o){}},getItem:function(l){var m=i.getElement();try{m.load("TinyMCE");return m.getAttribute(l)}catch(n){return null}},removeItem:function(l){i.getElement().removeAttribute(l)}}}},],function(l){try{h.storage=l();if(h.storage){return false}}catch(m){}})},storeDraft:function(){var i=this,l=i.storage,j=i.editor,h,k;if(l){if(!l.getItem(i.key)&&!j.isDirty()){return}k=j.getContent({draft:true});if(k.length>j.settings.autosave_minlength){h=i.getExpDate();if(!i.storage.autoExpires){i.storage.setItem(i.key+"_expires",h)}i.storage.setItem(i.key,k);i.onStoreDraft.dispatch(i,{expires:h,content:k})}}},restoreDraft:function(){var h=this,j=h.storage,i;if(j){i=j.getItem(h.key);if(i){h.editor.setContent(i);h.onRestoreDraft.dispatch(h,{content:i})}}},hasDraft:function(){var h=this,k=h.storage,i,j;if(k){j=!!k.getItem(h.key);if(j){if(!h.storage.autoExpires){i=new Date(k.getItem(h.key+"_expires"));if(new Date().getTime()<i.getTime()){return b}h.removeDraft()}else{return b}}}return false},removeDraft:function(){var h=this,k=h.storage,i=h.key,j;if(k){j=k.getItem(i);k.removeItem(i);k.removeItem(i+"_expires");if(j){h.onRemoveDraft.dispatch(h,{content:j})}}},"static":{_beforeUnloadHandler:function(h){var i;e.each(tinyMCE.editors,function(j){if(j.plugins.autosave){j.plugins.autosave.storeDraft()}if(j.getParam("fullscreen_is_enabled")){return}if(!i&&j.isDirty()&&j.getParam("autosave_ask_before_unload")){i=j.getLang("autosave.unload_msg")}});return i}}});e.PluginManager.add("autosave",e.plugins.AutoSave)})(tinymce); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/autosave/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/autosave/editor_plugin_src.js
new file mode 100644
index 00000000..8b308f5a
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/autosave/editor_plugin_src.js
@@ -0,0 +1,433 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ *
+ * Adds auto-save capability to the TinyMCE text editor to rescue content
+ * inadvertently lost. This plugin was originally developed by Speednet
+ * and that project can be found here: http://code.google.com/p/tinyautosave/
+ *
+ * TECHNOLOGY DISCUSSION:
+ *
+ * The plugin attempts to use the most advanced features available in the current browser to save
+ * as much content as possible. There are a total of four different methods used to autosave the
+ * content. In order of preference, they are:
+ *
+ * 1. localStorage - A new feature of HTML 5, localStorage can store megabytes of data per domain
+ * on the client computer. Data stored in the localStorage area has no expiration date, so we must
+ * manage expiring the data ourselves. localStorage is fully supported by IE8, and it is supposed
+ * to be working in Firefox 3 and Safari 3.2, but in reality is is flaky in those browsers. As
+ * HTML 5 gets wider support, the AutoSave plugin will use it automatically. In Windows Vista/7,
+ * localStorage is stored in the following folder:
+ * C:\Users\[username]\AppData\Local\Microsoft\Internet Explorer\DOMStore\[tempFolder]
+ *
+ * 2. sessionStorage - A new feature of HTML 5, sessionStorage works similarly to localStorage,
+ * except it is designed to expire after a certain amount of time. Because the specification
+ * around expiration date/time is very loosely-described, it is preferrable to use locaStorage and
+ * manage the expiration ourselves. sessionStorage has similar storage characteristics to
+ * localStorage, although it seems to have better support by Firefox 3 at the moment. (That will
+ * certainly change as Firefox continues getting better at HTML 5 adoption.)
+ *
+ * 3. UserData - A very under-exploited feature of Microsoft Internet Explorer, UserData is a
+ * way to store up to 128K of data per "document", or up to 1MB of data per domain, on the client
+ * computer. The feature is available for IE 5+, which makes it available for every version of IE
+ * supported by TinyMCE. The content is persistent across browser restarts and expires on the
+ * date/time specified, just like a cookie. However, the data is not cleared when the user clears
+ * cookies on the browser, which makes it well-suited for rescuing autosaved content. UserData,
+ * like other Microsoft IE browser technologies, is implemented as a behavior attached to a
+ * specific DOM object, so in this case we attach the behavior to the same DOM element that the
+ * TinyMCE editor instance is attached to.
+ */
+
+(function(tinymce) {
+ // Setup constants to help the compressor to reduce script size
+ var PLUGIN_NAME = 'autosave',
+ RESTORE_DRAFT = 'restoredraft',
+ TRUE = true,
+ undefined,
+ unloadHandlerAdded,
+ Dispatcher = tinymce.util.Dispatcher;
+
+ /**
+ * This plugin adds auto-save capability to the TinyMCE text editor to rescue content
+ * inadvertently lost. By using localStorage.
+ *
+ * @class tinymce.plugins.AutoSave
+ */
+ tinymce.create('tinymce.plugins.AutoSave', {
+ /**
+ * Initializes the plugin, this will be executed after the plugin has been created.
+ * This call is done before the editor instance has finished it's initialization so use the onInit event
+ * of the editor instance to intercept that event.
+ *
+ * @method init
+ * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in.
+ * @param {string} url Absolute URL to where the plugin is located.
+ */
+ init : function(ed, url) {
+ var self = this, settings = ed.settings;
+
+ self.editor = ed;
+
+ // Parses the specified time string into a milisecond number 10m, 10s etc.
+ function parseTime(time) {
+ var multipels = {
+ s : 1000,
+ m : 60000
+ };
+
+ time = /^(\d+)([ms]?)$/.exec('' + time);
+
+ return (time[2] ? multipels[time[2]] : 1) * parseInt(time);
+ };
+
+ // Default config
+ tinymce.each({
+ ask_before_unload : TRUE,
+ interval : '30s',
+ retention : '20m',
+ minlength : 50
+ }, function(value, key) {
+ key = PLUGIN_NAME + '_' + key;
+
+ if (settings[key] === undefined)
+ settings[key] = value;
+ });
+
+ // Parse times
+ settings.autosave_interval = parseTime(settings.autosave_interval);
+ settings.autosave_retention = parseTime(settings.autosave_retention);
+
+ // Register restore button
+ ed.addButton(RESTORE_DRAFT, {
+ title : PLUGIN_NAME + ".restore_content",
+ onclick : function() {
+ if (ed.getContent({draft: true}).replace(/\s|&nbsp;|<\/?p[^>]*>|<br[^>]*>/gi, "").length > 0) {
+ // Show confirm dialog if the editor isn't empty
+ ed.windowManager.confirm(
+ PLUGIN_NAME + ".warning_message",
+ function(ok) {
+ if (ok)
+ self.restoreDraft();
+ }
+ );
+ } else
+ self.restoreDraft();
+ }
+ });
+
+ // Enable/disable restoredraft button depending on if there is a draft stored or not
+ ed.onNodeChange.add(function() {
+ var controlManager = ed.controlManager;
+
+ if (controlManager.get(RESTORE_DRAFT))
+ controlManager.setDisabled(RESTORE_DRAFT, !self.hasDraft());
+ });
+
+ ed.onInit.add(function() {
+ // Check if the user added the restore button, then setup auto storage logic
+ if (ed.controlManager.get(RESTORE_DRAFT)) {
+ // Setup storage engine
+ self.setupStorage(ed);
+
+ // Auto save contents each interval time
+ setInterval(function() {
+ if (!ed.removed) {
+ self.storeDraft();
+ ed.nodeChanged();
+ }
+ }, settings.autosave_interval);
+ }
+ });
+
+ /**
+ * This event gets fired when a draft is stored to local storage.
+ *
+ * @event onStoreDraft
+ * @param {tinymce.plugins.AutoSave} sender Plugin instance sending the event.
+ * @param {Object} draft Draft object containing the HTML contents of the editor.
+ */
+ self.onStoreDraft = new Dispatcher(self);
+
+ /**
+ * This event gets fired when a draft is restored from local storage.
+ *
+ * @event onStoreDraft
+ * @param {tinymce.plugins.AutoSave} sender Plugin instance sending the event.
+ * @param {Object} draft Draft object containing the HTML contents of the editor.
+ */
+ self.onRestoreDraft = new Dispatcher(self);
+
+ /**
+ * This event gets fired when a draft removed/expired.
+ *
+ * @event onRemoveDraft
+ * @param {tinymce.plugins.AutoSave} sender Plugin instance sending the event.
+ * @param {Object} draft Draft object containing the HTML contents of the editor.
+ */
+ self.onRemoveDraft = new Dispatcher(self);
+
+ // Add ask before unload dialog only add one unload handler
+ if (!unloadHandlerAdded) {
+ window.onbeforeunload = tinymce.plugins.AutoSave._beforeUnloadHandler;
+ unloadHandlerAdded = TRUE;
+ }
+ },
+
+ /**
+ * Returns information about the plugin as a name/value array.
+ * The current keys are longname, author, authorurl, infourl and version.
+ *
+ * @method getInfo
+ * @return {Object} Name/value array containing information about the plugin.
+ */
+ getInfo : function() {
+ return {
+ longname : 'Auto save',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/autosave',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ /**
+ * Returns an expiration date UTC string.
+ *
+ * @method getExpDate
+ * @return {String} Expiration date UTC string.
+ */
+ getExpDate : function() {
+ return new Date(
+ new Date().getTime() + this.editor.settings.autosave_retention
+ ).toUTCString();
+ },
+
+ /**
+ * This method will setup the storage engine. If the browser has support for it.
+ *
+ * @method setupStorage
+ */
+ setupStorage : function(ed) {
+ var self = this, testKey = PLUGIN_NAME + '_test', testVal = "OK";
+
+ self.key = PLUGIN_NAME + ed.id;
+
+ // Loop though each storage engine type until we find one that works
+ tinymce.each([
+ function() {
+ // Try HTML5 Local Storage
+ if (localStorage) {
+ localStorage.setItem(testKey, testVal);
+
+ if (localStorage.getItem(testKey) === testVal) {
+ localStorage.removeItem(testKey);
+
+ return localStorage;
+ }
+ }
+ },
+
+ function() {
+ // Try HTML5 Session Storage
+ if (sessionStorage) {
+ sessionStorage.setItem(testKey, testVal);
+
+ if (sessionStorage.getItem(testKey) === testVal) {
+ sessionStorage.removeItem(testKey);
+
+ return sessionStorage;
+ }
+ }
+ },
+
+ function() {
+ // Try IE userData
+ if (tinymce.isIE) {
+ ed.getElement().style.behavior = "url('#default#userData')";
+
+ // Fake localStorage on old IE
+ return {
+ autoExpires : TRUE,
+
+ setItem : function(key, value) {
+ var userDataElement = ed.getElement();
+
+ userDataElement.setAttribute(key, value);
+ userDataElement.expires = self.getExpDate();
+
+ try {
+ userDataElement.save("TinyMCE");
+ } catch (e) {
+ // Ignore, saving might fail if "Userdata Persistence" is disabled in IE
+ }
+ },
+
+ getItem : function(key) {
+ var userDataElement = ed.getElement();
+
+ try {
+ userDataElement.load("TinyMCE");
+ return userDataElement.getAttribute(key);
+ } catch (e) {
+ // Ignore, loading might fail if "Userdata Persistence" is disabled in IE
+ return null;
+ }
+ },
+
+ removeItem : function(key) {
+ ed.getElement().removeAttribute(key);
+ }
+ };
+ }
+ },
+ ], function(setup) {
+ // Try executing each function to find a suitable storage engine
+ try {
+ self.storage = setup();
+
+ if (self.storage)
+ return false;
+ } catch (e) {
+ // Ignore
+ }
+ });
+ },
+
+ /**
+ * This method will store the current contents in the the storage engine.
+ *
+ * @method storeDraft
+ */
+ storeDraft : function() {
+ var self = this, storage = self.storage, editor = self.editor, expires, content;
+
+ // Is the contents dirty
+ if (storage) {
+ // If there is no existing key and the contents hasn't been changed since
+ // it's original value then there is no point in saving a draft
+ if (!storage.getItem(self.key) && !editor.isDirty())
+ return;
+
+ // Store contents if the contents if longer than the minlength of characters
+ content = editor.getContent({draft: true});
+ if (content.length > editor.settings.autosave_minlength) {
+ expires = self.getExpDate();
+
+ // Store expiration date if needed IE userData has auto expire built in
+ if (!self.storage.autoExpires)
+ self.storage.setItem(self.key + "_expires", expires);
+
+ self.storage.setItem(self.key, content);
+ self.onStoreDraft.dispatch(self, {
+ expires : expires,
+ content : content
+ });
+ }
+ }
+ },
+
+ /**
+ * This method will restore the contents from the storage engine back to the editor.
+ *
+ * @method restoreDraft
+ */
+ restoreDraft : function() {
+ var self = this, storage = self.storage, content;
+
+ if (storage) {
+ content = storage.getItem(self.key);
+
+ if (content) {
+ self.editor.setContent(content);
+ self.onRestoreDraft.dispatch(self, {
+ content : content
+ });
+ }
+ }
+ },
+
+ /**
+ * This method will return true/false if there is a local storage draft available.
+ *
+ * @method hasDraft
+ * @return {boolean} true/false state if there is a local draft.
+ */
+ hasDraft : function() {
+ var self = this, storage = self.storage, expDate, exists;
+
+ if (storage) {
+ // Does the item exist at all
+ exists = !!storage.getItem(self.key);
+ if (exists) {
+ // Storage needs autoexpire
+ if (!self.storage.autoExpires) {
+ expDate = new Date(storage.getItem(self.key + "_expires"));
+
+ // Contents hasn't expired
+ if (new Date().getTime() < expDate.getTime())
+ return TRUE;
+
+ // Remove it if it has
+ self.removeDraft();
+ } else
+ return TRUE;
+ }
+ }
+
+ return false;
+ },
+
+ /**
+ * Removes the currently stored draft.
+ *
+ * @method removeDraft
+ */
+ removeDraft : function() {
+ var self = this, storage = self.storage, key = self.key, content;
+
+ if (storage) {
+ // Get current contents and remove the existing draft
+ content = storage.getItem(key);
+ storage.removeItem(key);
+ storage.removeItem(key + "_expires");
+
+ // Dispatch remove event if we had any contents
+ if (content) {
+ self.onRemoveDraft.dispatch(self, {
+ content : content
+ });
+ }
+ }
+ },
+
+ "static" : {
+ // Internal unload handler will be called before the page is unloaded
+ _beforeUnloadHandler : function(e) {
+ var msg;
+
+ tinymce.each(tinyMCE.editors, function(ed) {
+ // Store a draft for each editor instance
+ if (ed.plugins.autosave)
+ ed.plugins.autosave.storeDraft();
+
+ // Never ask in fullscreen mode
+ if (ed.getParam("fullscreen_is_enabled"))
+ return;
+
+ // Setup a return message if the editor is dirty
+ if (!msg && ed.isDirty() && ed.getParam("autosave_ask_before_unload"))
+ msg = ed.getLang("autosave.unload_msg");
+ });
+
+ return msg;
+ }
+ }
+ });
+
+ tinymce.PluginManager.add('autosave', tinymce.plugins.AutoSave);
+})(tinymce);
diff --git a/askbot/media/js/tinymce/plugins/autosave/langs/en.js b/askbot/media/js/tinymce/plugins/autosave/langs/en.js
new file mode 100644
index 00000000..fce6bd3e
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/autosave/langs/en.js
@@ -0,0 +1,4 @@
+tinyMCE.addI18n('en.autosave',{
+restore_content: "Restore auto-saved content",
+warning_message: "If you restore the saved content, you will lose all the content that is currently in the editor.\n\nAre you sure you want to restore the saved content?"
+}); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/bbcode/editor_plugin.js b/askbot/media/js/tinymce/plugins/bbcode/editor_plugin.js
new file mode 100644
index 00000000..8f8821fd
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/bbcode/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.BBCodePlugin",{init:function(a,b){var d=this,c=a.getParam("bbcode_dialect","punbb").toLowerCase();a.onBeforeSetContent.add(function(e,f){f.content=d["_"+c+"_bbcode2html"](f.content)});a.onPostProcess.add(function(e,f){if(f.set){f.content=d["_"+c+"_bbcode2html"](f.content)}if(f.get){f.content=d["_"+c+"_html2bbcode"](f.content)}})},getInfo:function(){return{longname:"BBCode Plugin",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/bbcode",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_punbb_html2bbcode:function(a){a=tinymce.trim(a);function b(c,d){a=a.replace(c,d)}b(/<a.*?href=\"(.*?)\".*?>(.*?)<\/a>/gi,"[url=$1]$2[/url]");b(/<font.*?color=\"(.*?)\".*?class=\"codeStyle\".*?>(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]");b(/<font.*?color=\"(.*?)\".*?class=\"quoteStyle\".*?>(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]");b(/<font.*?class=\"codeStyle\".*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]");b(/<font.*?class=\"quoteStyle\".*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]");b(/<span style=\"color: ?(.*?);\">(.*?)<\/span>/gi,"[color=$1]$2[/color]");b(/<font.*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[color=$1]$2[/color]");b(/<span style=\"font-size:(.*?);\">(.*?)<\/span>/gi,"[size=$1]$2[/size]");b(/<font>(.*?)<\/font>/gi,"$1");b(/<img.*?src=\"(.*?)\".*?\/>/gi,"[img]$1[/img]");b(/<span class=\"codeStyle\">(.*?)<\/span>/gi,"[code]$1[/code]");b(/<span class=\"quoteStyle\">(.*?)<\/span>/gi,"[quote]$1[/quote]");b(/<strong class=\"codeStyle\">(.*?)<\/strong>/gi,"[code][b]$1[/b][/code]");b(/<strong class=\"quoteStyle\">(.*?)<\/strong>/gi,"[quote][b]$1[/b][/quote]");b(/<em class=\"codeStyle\">(.*?)<\/em>/gi,"[code][i]$1[/i][/code]");b(/<em class=\"quoteStyle\">(.*?)<\/em>/gi,"[quote][i]$1[/i][/quote]");b(/<u class=\"codeStyle\">(.*?)<\/u>/gi,"[code][u]$1[/u][/code]");b(/<u class=\"quoteStyle\">(.*?)<\/u>/gi,"[quote][u]$1[/u][/quote]");b(/<\/(strong|b)>/gi,"[/b]");b(/<(strong|b)>/gi,"[b]");b(/<\/(em|i)>/gi,"[/i]");b(/<(em|i)>/gi,"[i]");b(/<\/u>/gi,"[/u]");b(/<span style=\"text-decoration: ?underline;\">(.*?)<\/span>/gi,"[u]$1[/u]");b(/<u>/gi,"[u]");b(/<blockquote[^>]*>/gi,"[quote]");b(/<\/blockquote>/gi,"[/quote]");b(/<br \/>/gi,"\n");b(/<br\/>/gi,"\n");b(/<br>/gi,"\n");b(/<p>/gi,"");b(/<\/p>/gi,"\n");b(/&nbsp;|\u00a0/gi," ");b(/&quot;/gi,'"');b(/&lt;/gi,"<");b(/&gt;/gi,">");b(/&amp;/gi,"&");return a},_punbb_bbcode2html:function(a){a=tinymce.trim(a);function b(c,d){a=a.replace(c,d)}b(/\n/gi,"<br />");b(/\[b\]/gi,"<strong>");b(/\[\/b\]/gi,"</strong>");b(/\[i\]/gi,"<em>");b(/\[\/i\]/gi,"</em>");b(/\[u\]/gi,"<u>");b(/\[\/u\]/gi,"</u>");b(/\[url=([^\]]+)\](.*?)\[\/url\]/gi,'<a href="$1">$2</a>');b(/\[url\](.*?)\[\/url\]/gi,'<a href="$1">$1</a>');b(/\[img\](.*?)\[\/img\]/gi,'<img src="$1" />');b(/\[color=(.*?)\](.*?)\[\/color\]/gi,'<font color="$1">$2</font>');b(/\[code\](.*?)\[\/code\]/gi,'<span class="codeStyle">$1</span>&nbsp;');b(/\[quote.*?\](.*?)\[\/quote\]/gi,'<span class="quoteStyle">$1</span>&nbsp;');return a}});tinymce.PluginManager.add("bbcode",tinymce.plugins.BBCodePlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/bbcode/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/bbcode/editor_plugin_src.js
new file mode 100644
index 00000000..4e7eb337
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/bbcode/editor_plugin_src.js
@@ -0,0 +1,120 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.BBCodePlugin', {
+ init : function(ed, url) {
+ var t = this, dialect = ed.getParam('bbcode_dialect', 'punbb').toLowerCase();
+
+ ed.onBeforeSetContent.add(function(ed, o) {
+ o.content = t['_' + dialect + '_bbcode2html'](o.content);
+ });
+
+ ed.onPostProcess.add(function(ed, o) {
+ if (o.set)
+ o.content = t['_' + dialect + '_bbcode2html'](o.content);
+
+ if (o.get)
+ o.content = t['_' + dialect + '_html2bbcode'](o.content);
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'BBCode Plugin',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/bbcode',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ // Private methods
+
+ // HTML -> BBCode in PunBB dialect
+ _punbb_html2bbcode : function(s) {
+ s = tinymce.trim(s);
+
+ function rep(re, str) {
+ s = s.replace(re, str);
+ };
+
+ // example: <strong> to [b]
+ rep(/<a.*?href=\"(.*?)\".*?>(.*?)<\/a>/gi,"[url=$1]$2[/url]");
+ rep(/<font.*?color=\"(.*?)\".*?class=\"codeStyle\".*?>(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]");
+ rep(/<font.*?color=\"(.*?)\".*?class=\"quoteStyle\".*?>(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]");
+ rep(/<font.*?class=\"codeStyle\".*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]");
+ rep(/<font.*?class=\"quoteStyle\".*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]");
+ rep(/<span style=\"color: ?(.*?);\">(.*?)<\/span>/gi,"[color=$1]$2[/color]");
+ rep(/<font.*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[color=$1]$2[/color]");
+ rep(/<span style=\"font-size:(.*?);\">(.*?)<\/span>/gi,"[size=$1]$2[/size]");
+ rep(/<font>(.*?)<\/font>/gi,"$1");
+ rep(/<img.*?src=\"(.*?)\".*?\/>/gi,"[img]$1[/img]");
+ rep(/<span class=\"codeStyle\">(.*?)<\/span>/gi,"[code]$1[/code]");
+ rep(/<span class=\"quoteStyle\">(.*?)<\/span>/gi,"[quote]$1[/quote]");
+ rep(/<strong class=\"codeStyle\">(.*?)<\/strong>/gi,"[code][b]$1[/b][/code]");
+ rep(/<strong class=\"quoteStyle\">(.*?)<\/strong>/gi,"[quote][b]$1[/b][/quote]");
+ rep(/<em class=\"codeStyle\">(.*?)<\/em>/gi,"[code][i]$1[/i][/code]");
+ rep(/<em class=\"quoteStyle\">(.*?)<\/em>/gi,"[quote][i]$1[/i][/quote]");
+ rep(/<u class=\"codeStyle\">(.*?)<\/u>/gi,"[code][u]$1[/u][/code]");
+ rep(/<u class=\"quoteStyle\">(.*?)<\/u>/gi,"[quote][u]$1[/u][/quote]");
+ rep(/<\/(strong|b)>/gi,"[/b]");
+ rep(/<(strong|b)>/gi,"[b]");
+ rep(/<\/(em|i)>/gi,"[/i]");
+ rep(/<(em|i)>/gi,"[i]");
+ rep(/<\/u>/gi,"[/u]");
+ rep(/<span style=\"text-decoration: ?underline;\">(.*?)<\/span>/gi,"[u]$1[/u]");
+ rep(/<u>/gi,"[u]");
+ rep(/<blockquote[^>]*>/gi,"[quote]");
+ rep(/<\/blockquote>/gi,"[/quote]");
+ rep(/<br \/>/gi,"\n");
+ rep(/<br\/>/gi,"\n");
+ rep(/<br>/gi,"\n");
+ rep(/<p>/gi,"");
+ rep(/<\/p>/gi,"\n");
+ rep(/&nbsp;|\u00a0/gi," ");
+ rep(/&quot;/gi,"\"");
+ rep(/&lt;/gi,"<");
+ rep(/&gt;/gi,">");
+ rep(/&amp;/gi,"&");
+
+ return s;
+ },
+
+ // BBCode -> HTML from PunBB dialect
+ _punbb_bbcode2html : function(s) {
+ s = tinymce.trim(s);
+
+ function rep(re, str) {
+ s = s.replace(re, str);
+ };
+
+ // example: [b] to <strong>
+ rep(/\n/gi,"<br />");
+ rep(/\[b\]/gi,"<strong>");
+ rep(/\[\/b\]/gi,"</strong>");
+ rep(/\[i\]/gi,"<em>");
+ rep(/\[\/i\]/gi,"</em>");
+ rep(/\[u\]/gi,"<u>");
+ rep(/\[\/u\]/gi,"</u>");
+ rep(/\[url=([^\]]+)\](.*?)\[\/url\]/gi,"<a href=\"$1\">$2</a>");
+ rep(/\[url\](.*?)\[\/url\]/gi,"<a href=\"$1\">$1</a>");
+ rep(/\[img\](.*?)\[\/img\]/gi,"<img src=\"$1\" />");
+ rep(/\[color=(.*?)\](.*?)\[\/color\]/gi,"<font color=\"$1\">$2</font>");
+ rep(/\[code\](.*?)\[\/code\]/gi,"<span class=\"codeStyle\">$1</span>&nbsp;");
+ rep(/\[quote.*?\](.*?)\[\/quote\]/gi,"<span class=\"quoteStyle\">$1</span>&nbsp;");
+
+ return s;
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('bbcode', tinymce.plugins.BBCodePlugin);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/contextmenu/editor_plugin.js b/askbot/media/js/tinymce/plugins/contextmenu/editor_plugin.js
new file mode 100644
index 00000000..4f99010e
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/contextmenu/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var a=tinymce.dom.Event,c=tinymce.each,b=tinymce.DOM;tinymce.create("tinymce.plugins.ContextMenu",{init:function(e){var h=this,f,d,i;h.editor=e;d=e.settings.contextmenu_never_use_native;h.onContextMenu=new tinymce.util.Dispatcher(this);f=e.onContextMenu.add(function(j,k){if((i!==0?i:k.ctrlKey)&&!d){return}a.cancel(k);if(k.target.nodeName=="IMG"){j.selection.select(k.target)}h._getMenu(j).showMenu(k.clientX||k.pageX,k.clientY||k.pageY);a.add(j.getDoc(),"click",function(l){g(j,l)});j.nodeChanged()});e.onRemove.add(function(){if(h._menu){h._menu.removeAll()}});function g(j,k){i=0;if(k&&k.button==2){i=k.ctrlKey;return}if(h._menu){h._menu.removeAll();h._menu.destroy();a.remove(j.getDoc(),"click",g);h._menu=null}}e.onMouseDown.add(g);e.onKeyDown.add(g);e.onKeyDown.add(function(j,k){if(k.shiftKey&&!k.ctrlKey&&!k.altKey&&k.keyCode===121){a.cancel(k);f(j,k)}})},getInfo:function(){return{longname:"Contextmenu",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/contextmenu",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_getMenu:function(e){var g=this,d=g._menu,j=e.selection,f=j.isCollapsed(),h=j.getNode()||e.getBody(),i,k;if(d){d.removeAll();d.destroy()}k=b.getPos(e.getContentAreaContainer());d=e.controlManager.createDropMenu("contextmenu",{offset_x:k.x+e.getParam("contextmenu_offset_x",0),offset_y:k.y+e.getParam("contextmenu_offset_y",0),constrain:1,keyboard_focus:true});g._menu=d;d.add({title:"advanced.cut_desc",icon:"cut",cmd:"Cut"}).setDisabled(f);d.add({title:"advanced.copy_desc",icon:"copy",cmd:"Copy"}).setDisabled(f);d.add({title:"advanced.paste_desc",icon:"paste",cmd:"Paste"});if((h.nodeName=="A"&&!e.dom.getAttrib(h,"name"))||!f){d.addSeparator();d.add({title:"advanced.link_desc",icon:"link",cmd:e.plugins.advlink?"mceAdvLink":"mceLink",ui:true});d.add({title:"advanced.unlink_desc",icon:"unlink",cmd:"UnLink"})}d.addSeparator();d.add({title:"advanced.image_desc",icon:"image",cmd:e.plugins.advimage?"mceAdvImage":"mceImage",ui:true});d.addSeparator();i=d.addMenu({title:"contextmenu.align"});i.add({title:"contextmenu.left",icon:"justifyleft",cmd:"JustifyLeft"});i.add({title:"contextmenu.center",icon:"justifycenter",cmd:"JustifyCenter"});i.add({title:"contextmenu.right",icon:"justifyright",cmd:"JustifyRight"});i.add({title:"contextmenu.full",icon:"justifyfull",cmd:"JustifyFull"});g.onContextMenu.dispatch(g,d,h,f);return d}});tinymce.PluginManager.add("contextmenu",tinymce.plugins.ContextMenu)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/contextmenu/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/contextmenu/editor_plugin_src.js
new file mode 100644
index 00000000..004d011d
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/contextmenu/editor_plugin_src.js
@@ -0,0 +1,161 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var Event = tinymce.dom.Event, each = tinymce.each, DOM = tinymce.DOM;
+
+ /**
+ * This plugin a context menu to TinyMCE editor instances.
+ *
+ * @class tinymce.plugins.ContextMenu
+ */
+ tinymce.create('tinymce.plugins.ContextMenu', {
+ /**
+ * Initializes the plugin, this will be executed after the plugin has been created.
+ * This call is done before the editor instance has finished it's initialization so use the onInit event
+ * of the editor instance to intercept that event.
+ *
+ * @method init
+ * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in.
+ * @param {string} url Absolute URL to where the plugin is located.
+ */
+ init : function(ed) {
+ var t = this, showMenu, contextmenuNeverUseNative, realCtrlKey;
+
+ t.editor = ed;
+
+ contextmenuNeverUseNative = ed.settings.contextmenu_never_use_native;
+
+ /**
+ * This event gets fired when the context menu is shown.
+ *
+ * @event onContextMenu
+ * @param {tinymce.plugins.ContextMenu} sender Plugin instance sending the event.
+ * @param {tinymce.ui.DropMenu} menu Drop down menu to fill with more items if needed.
+ */
+ t.onContextMenu = new tinymce.util.Dispatcher(this);
+
+ showMenu = ed.onContextMenu.add(function(ed, e) {
+ // Block TinyMCE menu on ctrlKey and work around Safari issue
+ if ((realCtrlKey !== 0 ? realCtrlKey : e.ctrlKey) && !contextmenuNeverUseNative)
+ return;
+
+ Event.cancel(e);
+
+ // Select the image if it's clicked. WebKit would other wise expand the selection
+ if (e.target.nodeName == 'IMG')
+ ed.selection.select(e.target);
+
+ t._getMenu(ed).showMenu(e.clientX || e.pageX, e.clientY || e.pageY);
+ Event.add(ed.getDoc(), 'click', function(e) {
+ hide(ed, e);
+ });
+
+ ed.nodeChanged();
+ });
+
+ ed.onRemove.add(function() {
+ if (t._menu)
+ t._menu.removeAll();
+ });
+
+ function hide(ed, e) {
+ realCtrlKey = 0;
+
+ // Since the contextmenu event moves
+ // the selection we need to store it away
+ if (e && e.button == 2) {
+ realCtrlKey = e.ctrlKey;
+ return;
+ }
+
+ if (t._menu) {
+ t._menu.removeAll();
+ t._menu.destroy();
+ Event.remove(ed.getDoc(), 'click', hide);
+ t._menu = null;
+ }
+ };
+
+ ed.onMouseDown.add(hide);
+ ed.onKeyDown.add(hide);
+ ed.onKeyDown.add(function(ed, e) {
+ if (e.shiftKey && !e.ctrlKey && !e.altKey && e.keyCode === 121) {
+ Event.cancel(e);
+ showMenu(ed, e);
+ }
+ });
+ },
+
+ /**
+ * Returns information about the plugin as a name/value array.
+ * The current keys are longname, author, authorurl, infourl and version.
+ *
+ * @method getInfo
+ * @return {Object} Name/value array containing information about the plugin.
+ */
+ getInfo : function() {
+ return {
+ longname : 'Contextmenu',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/contextmenu',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ _getMenu : function(ed) {
+ var t = this, m = t._menu, se = ed.selection, col = se.isCollapsed(), el = se.getNode() || ed.getBody(), am, p;
+
+ if (m) {
+ m.removeAll();
+ m.destroy();
+ }
+
+ p = DOM.getPos(ed.getContentAreaContainer());
+
+ m = ed.controlManager.createDropMenu('contextmenu', {
+ offset_x : p.x + ed.getParam('contextmenu_offset_x', 0),
+ offset_y : p.y + ed.getParam('contextmenu_offset_y', 0),
+ constrain : 1,
+ keyboard_focus: true
+ });
+
+ t._menu = m;
+
+ m.add({title : 'advanced.cut_desc', icon : 'cut', cmd : 'Cut'}).setDisabled(col);
+ m.add({title : 'advanced.copy_desc', icon : 'copy', cmd : 'Copy'}).setDisabled(col);
+ m.add({title : 'advanced.paste_desc', icon : 'paste', cmd : 'Paste'});
+
+ if ((el.nodeName == 'A' && !ed.dom.getAttrib(el, 'name')) || !col) {
+ m.addSeparator();
+ m.add({title : 'advanced.link_desc', icon : 'link', cmd : ed.plugins.advlink ? 'mceAdvLink' : 'mceLink', ui : true});
+ m.add({title : 'advanced.unlink_desc', icon : 'unlink', cmd : 'UnLink'});
+ }
+
+ m.addSeparator();
+ m.add({title : 'advanced.image_desc', icon : 'image', cmd : ed.plugins.advimage ? 'mceAdvImage' : 'mceImage', ui : true});
+
+ m.addSeparator();
+ am = m.addMenu({title : 'contextmenu.align'});
+ am.add({title : 'contextmenu.left', icon : 'justifyleft', cmd : 'JustifyLeft'});
+ am.add({title : 'contextmenu.center', icon : 'justifycenter', cmd : 'JustifyCenter'});
+ am.add({title : 'contextmenu.right', icon : 'justifyright', cmd : 'JustifyRight'});
+ am.add({title : 'contextmenu.full', icon : 'justifyfull', cmd : 'JustifyFull'});
+
+ t.onContextMenu.dispatch(t, m, el, col);
+
+ return m;
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('contextmenu', tinymce.plugins.ContextMenu);
+})();
diff --git a/askbot/media/js/tinymce/plugins/directionality/editor_plugin.js b/askbot/media/js/tinymce/plugins/directionality/editor_plugin.js
new file mode 100644
index 00000000..bce8e739
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/directionality/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.Directionality",{init:function(a,b){var c=this;c.editor=a;a.addCommand("mceDirectionLTR",function(){var d=a.dom.getParent(a.selection.getNode(),a.dom.isBlock);if(d){if(a.dom.getAttrib(d,"dir")!="ltr"){a.dom.setAttrib(d,"dir","ltr")}else{a.dom.setAttrib(d,"dir","")}}a.nodeChanged()});a.addCommand("mceDirectionRTL",function(){var d=a.dom.getParent(a.selection.getNode(),a.dom.isBlock);if(d){if(a.dom.getAttrib(d,"dir")!="rtl"){a.dom.setAttrib(d,"dir","rtl")}else{a.dom.setAttrib(d,"dir","")}}a.nodeChanged()});a.addButton("ltr",{title:"directionality.ltr_desc",cmd:"mceDirectionLTR"});a.addButton("rtl",{title:"directionality.rtl_desc",cmd:"mceDirectionRTL"});a.onNodeChange.add(c._nodeChange,c)},getInfo:function(){return{longname:"Directionality",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/directionality",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_nodeChange:function(b,a,e){var d=b.dom,c;e=d.getParent(e,d.isBlock);if(!e){a.setDisabled("ltr",1);a.setDisabled("rtl",1);return}c=d.getAttrib(e,"dir");a.setActive("ltr",c=="ltr");a.setDisabled("ltr",0);a.setActive("rtl",c=="rtl");a.setDisabled("rtl",0)}});tinymce.PluginManager.add("directionality",tinymce.plugins.Directionality)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/directionality/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/directionality/editor_plugin_src.js
new file mode 100644
index 00000000..4444959b
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/directionality/editor_plugin_src.js
@@ -0,0 +1,82 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.Directionality', {
+ init : function(ed, url) {
+ var t = this;
+
+ t.editor = ed;
+
+ ed.addCommand('mceDirectionLTR', function() {
+ var e = ed.dom.getParent(ed.selection.getNode(), ed.dom.isBlock);
+
+ if (e) {
+ if (ed.dom.getAttrib(e, "dir") != "ltr")
+ ed.dom.setAttrib(e, "dir", "ltr");
+ else
+ ed.dom.setAttrib(e, "dir", "");
+ }
+
+ ed.nodeChanged();
+ });
+
+ ed.addCommand('mceDirectionRTL', function() {
+ var e = ed.dom.getParent(ed.selection.getNode(), ed.dom.isBlock);
+
+ if (e) {
+ if (ed.dom.getAttrib(e, "dir") != "rtl")
+ ed.dom.setAttrib(e, "dir", "rtl");
+ else
+ ed.dom.setAttrib(e, "dir", "");
+ }
+
+ ed.nodeChanged();
+ });
+
+ ed.addButton('ltr', {title : 'directionality.ltr_desc', cmd : 'mceDirectionLTR'});
+ ed.addButton('rtl', {title : 'directionality.rtl_desc', cmd : 'mceDirectionRTL'});
+
+ ed.onNodeChange.add(t._nodeChange, t);
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Directionality',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/directionality',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ // Private methods
+
+ _nodeChange : function(ed, cm, n) {
+ var dom = ed.dom, dir;
+
+ n = dom.getParent(n, dom.isBlock);
+ if (!n) {
+ cm.setDisabled('ltr', 1);
+ cm.setDisabled('rtl', 1);
+ return;
+ }
+
+ dir = dom.getAttrib(n, 'dir');
+ cm.setActive('ltr', dir == "ltr");
+ cm.setDisabled('ltr', 0);
+ cm.setActive('rtl', dir == "rtl");
+ cm.setDisabled('rtl', 0);
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('directionality', tinymce.plugins.Directionality);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/emotions/editor_plugin.js b/askbot/media/js/tinymce/plugins/emotions/editor_plugin.js
new file mode 100644
index 00000000..dbdd8ffb
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/editor_plugin.js
@@ -0,0 +1 @@
+(function(a){a.create("tinymce.plugins.EmotionsPlugin",{init:function(b,c){b.addCommand("mceEmotion",function(){b.windowManager.open({file:c+"/emotions.htm",width:250+parseInt(b.getLang("emotions.delta_width",0)),height:160+parseInt(b.getLang("emotions.delta_height",0)),inline:1},{plugin_url:c})});b.addButton("emotions",{title:"emotions.emotions_desc",cmd:"mceEmotion"})},getInfo:function(){return{longname:"Emotions",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/emotions",version:a.majorVersion+"."+a.minorVersion}}});a.PluginManager.add("emotions",a.plugins.EmotionsPlugin)})(tinymce); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/emotions/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/emotions/editor_plugin_src.js
new file mode 100644
index 00000000..71d54169
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/editor_plugin_src.js
@@ -0,0 +1,43 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function(tinymce) {
+ tinymce.create('tinymce.plugins.EmotionsPlugin', {
+ init : function(ed, url) {
+ // Register commands
+ ed.addCommand('mceEmotion', function() {
+ ed.windowManager.open({
+ file : url + '/emotions.htm',
+ width : 250 + parseInt(ed.getLang('emotions.delta_width', 0)),
+ height : 160 + parseInt(ed.getLang('emotions.delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url
+ });
+ });
+
+ // Register buttons
+ ed.addButton('emotions', {title : 'emotions.emotions_desc', cmd : 'mceEmotion'});
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Emotions',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/emotions',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('emotions', tinymce.plugins.EmotionsPlugin);
+})(tinymce); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/emotions/emotions.htm b/askbot/media/js/tinymce/plugins/emotions/emotions.htm
new file mode 100644
index 00000000..10135565
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/emotions.htm
@@ -0,0 +1,42 @@
+<!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">
+<head>
+ <title>{#emotions_dlg.title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="js/emotions.js"></script>
+</head>
+<body style="display: none" role="application" aria-labelledby="app_title">
+<span style="display:none;" id="app_title">{#emotions_dlg.title}</span>
+<div align="center">
+ <div class="title">{#emotions_dlg.title}:<br /><br /></div>
+
+ <table id="emoticon_table" role="presentation" border="0" cellspacing="0" cellpadding="4">
+ <tr>
+ <td><a class="emoticon_link" role="button" title="{#emotions_dlg.cool}. {#emotions_dlg.usage}" href="javascript:EmotionsDialog.insert('smiley-cool.gif','emotions_dlg.cool');"><img src="img/smiley-cool.gif" width="18" height="18" border="0" alt="{#emotions_dlg.cool}. {#emotions_dlg.usage}" /></a></td>
+ <td><a class="emoticon_link" role="button" title="{#emotions_dlg.cry}. {#emotions_dlg.usage}" href="javascript:EmotionsDialog.insert('smiley-cry.gif','emotions_dlg.cry');"><img src="img/smiley-cry.gif" width="18" height="18" border="0" alt="{#emotions_dlg.cry}. {#emotions_dlg.usage}" /></a></td>
+ <td><a class="emoticon_link" role="button" title="{#emotions_dlg.embarassed}. {#emotions_dlg.usage}" href="javascript:EmotionsDialog.insert('smiley-embarassed.gif','emotions_dlg.embarassed');"><img src="img/smiley-embarassed.gif" width="18" height="18" border="0" alt="{#emotions_dlg.embarassed}. {#emotions_dlg.usage}" /></a></td>
+ <td><a class="emoticon_link" role="button" title="{#emotions_dlg.foot_in_mouth}. {#emotions_dlg.usage}" href="javascript:EmotionsDialog.insert('smiley-foot-in-mouth.gif','emotions_dlg.foot_in_mouth');"><img src="img/smiley-foot-in-mouth.gif" width="18" height="18" border="0" alt="{#emotions_dlg.foot_in_mouth}. {#emotions_dlg.usage}" /></a></td>
+ </tr>
+ <tr>
+ <td><a class="emoticon_link" role="button" title="{#emotions_dlg.frown}. {#emotions_dlg.usage}" href="javascript:EmotionsDialog.insert('smiley-frown.gif','emotions_dlg.frown');"><img src="img/smiley-frown.gif" width="18" height="18" border="0" alt="{#emotions_dlg.frown}. {#emotions_dlg.usage}" /></a></td>
+ <td><a class="emoticon_link" role="button" title="{#emotions_dlg.innocent}. {#emotions_dlg.usage}" href="javascript:EmotionsDialog.insert('smiley-innocent.gif','emotions_dlg.innocent');"><img src="img/smiley-innocent.gif" width="18" height="18" border="0" alt="{#emotions_dlg.innocent}. {#emotions_dlg.usage}" /></a></td>
+ <td><a class="emoticon_link" role="button" title="{#emotions_dlg.kiss}. {#emotions_dlg.usage}" href="javascript:EmotionsDialog.insert('smiley-kiss.gif','emotions_dlg.kiss');"><img src="img/smiley-kiss.gif" width="18" height="18" border="0" alt="{#emotions_dlg.kiss}. {#emotions_dlg.usage}" /></a></td>
+ <td><a class="emoticon_link" role="button" title="{#emotions_dlg.laughing}. {#emotions_dlg.usage}" href="javascript:EmotionsDialog.insert('smiley-laughing.gif','emotions_dlg.laughing');"><img src="img/smiley-laughing.gif" width="18" height="18" border="0" alt="{#emotions_dlg.laughing}. {#emotions_dlg.usage}" /></a></td>
+ </tr>
+ <tr>
+ <td><a class="emoticon_link" role="button" title="{#emotions_dlg.money_mouth}. {#emotions_dlg.usage}" href="javascript:EmotionsDialog.insert('smiley-money-mouth.gif','emotions_dlg.money_mouth');"><img src="img/smiley-money-mouth.gif" width="18" height="18" border="0" alt="{#emotions_dlg.money_mouth}. {#emotions_dlg.usage}"/></a></td>
+ <td><a class="emoticon_link" role="button" title="{#emotions_dlg.sealed}. {#emotions_dlg.usage}" href="javascript:EmotionsDialog.insert('smiley-sealed.gif','emotions_dlg.sealed');"><img src="img/smiley-sealed.gif" width="18" height="18" border="0" alt="{#emotions_dlg.sealed}. {#emotions_dlg.usage}" /></a></td>
+ <td><a class="emoticon_link" role="button" title="{#emotions_dlg.smile}. {#emotions_dlg.usage}" href="javascript:EmotionsDialog.insert('smiley-smile.gif','emotions_dlg.smile');"><img src="img/smiley-smile.gif" width="18" height="18" border="0" alt="{#emotions_dlg.smile}. {#emotions_dlg.usage}" /></a></td>
+ <td><a class="emoticon_link" role="button" title="{#emotions_dlg.surprised}. {#emotions_dlg.usage}" href="javascript:EmotionsDialog.insert('smiley-surprised.gif','emotions_dlg.surprised');"><img src="img/smiley-surprised.gif" width="18" height="18" border="0" alt="{#emotions_dlg.surprised}. {#emotions_dlg.usage}" /></a></td>
+ </tr>
+ <tr>
+ <td><a class="emoticon_link" role="button" title="{#emotions_dlg.tongue_out}. {#emotions_dlg.usage}" href="javascript:EmotionsDialog.insert('smiley-tongue-out.gif','emotions_dlg.tongue_out');"><img src="img/smiley-tongue-out.gif" width="18" height="18" border="0" alt="{#emotions_dlg.tongue-out}. {#emotions_dlg.usage}" /></a></td>
+ <td><a class="emoticon_link" role="button" title="{#emotions_dlg.undecided}. {#emotions_dlg.usage}" href="javascript:EmotionsDialog.insert('smiley-undecided.gif','emotions_dlg.undecided');"><img src="img/smiley-undecided.gif" width="18" height="18" border="0" alt="{#emotions_dlg.undecided}. {#emotions_dlg.usage}" /></a></td>
+ <td><a class="emoticon_link" role="button" title="{#emotions_dlg.wink}. {#emotions_dlg.usage}" href="javascript:EmotionsDialog.insert('smiley-wink.gif','emotions_dlg.wink');"><img src="img/smiley-wink.gif" width="18" height="18" border="0" alt="{#emotions_dlg.wink}. {#emotions_dlg.usage}" /></a></td>
+ <td><a class="emoticon_link" role="button" title="{#emotions_dlg.yell}. {#emotions_dlg.usage}" href="javascript:EmotionsDialog.insert('smiley-yell.gif','emotions_dlg.yell');"><img src="img/smiley-yell.gif" width="18" height="18" border="0" alt="{#emotions_dlg.yell}. {#emotions_dlg.usage}" /></a></td>
+ </tr>
+ </table>
+ <div>{#emotions_dlg.usage}</div>
+</div>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/emotions/img/smiley-cool.gif b/askbot/media/js/tinymce/plugins/emotions/img/smiley-cool.gif
new file mode 100644
index 00000000..ba90cc36
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/img/smiley-cool.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/emotions/img/smiley-cry.gif b/askbot/media/js/tinymce/plugins/emotions/img/smiley-cry.gif
new file mode 100644
index 00000000..74d897a4
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/img/smiley-cry.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/emotions/img/smiley-embarassed.gif b/askbot/media/js/tinymce/plugins/emotions/img/smiley-embarassed.gif
new file mode 100644
index 00000000..963a96b8
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/img/smiley-embarassed.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/emotions/img/smiley-foot-in-mouth.gif b/askbot/media/js/tinymce/plugins/emotions/img/smiley-foot-in-mouth.gif
new file mode 100644
index 00000000..c7cf1011
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/img/smiley-foot-in-mouth.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/emotions/img/smiley-frown.gif b/askbot/media/js/tinymce/plugins/emotions/img/smiley-frown.gif
new file mode 100644
index 00000000..716f55e1
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/img/smiley-frown.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/emotions/img/smiley-innocent.gif b/askbot/media/js/tinymce/plugins/emotions/img/smiley-innocent.gif
new file mode 100644
index 00000000..334d49e0
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/img/smiley-innocent.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/emotions/img/smiley-kiss.gif b/askbot/media/js/tinymce/plugins/emotions/img/smiley-kiss.gif
new file mode 100644
index 00000000..4efd549e
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/img/smiley-kiss.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/emotions/img/smiley-laughing.gif b/askbot/media/js/tinymce/plugins/emotions/img/smiley-laughing.gif
new file mode 100644
index 00000000..82c5b182
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/img/smiley-laughing.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/emotions/img/smiley-money-mouth.gif b/askbot/media/js/tinymce/plugins/emotions/img/smiley-money-mouth.gif
new file mode 100644
index 00000000..ca2451e1
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/img/smiley-money-mouth.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/emotions/img/smiley-sealed.gif b/askbot/media/js/tinymce/plugins/emotions/img/smiley-sealed.gif
new file mode 100644
index 00000000..fe66220c
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/img/smiley-sealed.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/emotions/img/smiley-smile.gif b/askbot/media/js/tinymce/plugins/emotions/img/smiley-smile.gif
new file mode 100644
index 00000000..fd27edfa
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/img/smiley-smile.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/emotions/img/smiley-surprised.gif b/askbot/media/js/tinymce/plugins/emotions/img/smiley-surprised.gif
new file mode 100644
index 00000000..0cc9bb71
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/img/smiley-surprised.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/emotions/img/smiley-tongue-out.gif b/askbot/media/js/tinymce/plugins/emotions/img/smiley-tongue-out.gif
new file mode 100644
index 00000000..2075dc16
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/img/smiley-tongue-out.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/emotions/img/smiley-undecided.gif b/askbot/media/js/tinymce/plugins/emotions/img/smiley-undecided.gif
new file mode 100644
index 00000000..bef7e257
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/img/smiley-undecided.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/emotions/img/smiley-wink.gif b/askbot/media/js/tinymce/plugins/emotions/img/smiley-wink.gif
new file mode 100644
index 00000000..0631c761
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/img/smiley-wink.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/emotions/img/smiley-yell.gif b/askbot/media/js/tinymce/plugins/emotions/img/smiley-yell.gif
new file mode 100644
index 00000000..648e6e87
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/img/smiley-yell.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/emotions/js/emotions.js b/askbot/media/js/tinymce/plugins/emotions/js/emotions.js
new file mode 100644
index 00000000..b360f20b
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/js/emotions.js
@@ -0,0 +1,43 @@
+tinyMCEPopup.requireLangPack();
+
+var EmotionsDialog = {
+ addKeyboardNavigation: function(){
+ var tableElm, cells, settings;
+
+ cells = tinyMCEPopup.dom.select("a.emoticon_link", "emoticon_table");
+
+ settings ={
+ root: "emoticon_table",
+ items: cells
+ };
+ cells[0].tabindex=0;
+ tinyMCEPopup.dom.addClass(cells[0], "mceFocus");
+ if (tinymce.isGecko) {
+ cells[0].focus();
+ } else {
+ setTimeout(function(){
+ cells[0].focus();
+ }, 100);
+ }
+ tinyMCEPopup.editor.windowManager.createInstance('tinymce.ui.KeyboardNavigation', settings, tinyMCEPopup.dom);
+ },
+ init : function(ed) {
+ tinyMCEPopup.resizeToInnerSize();
+ this.addKeyboardNavigation();
+ },
+
+ insert : function(file, title) {
+ var ed = tinyMCEPopup.editor, dom = ed.dom;
+
+ tinyMCEPopup.execCommand('mceInsertContent', false, dom.createHTML('img', {
+ src : tinyMCEPopup.getWindowArg('plugin_url') + '/img/' + file,
+ alt : ed.getLang(title),
+ title : ed.getLang(title),
+ border : 0
+ }));
+
+ tinyMCEPopup.close();
+ }
+};
+
+tinyMCEPopup.onInit.add(EmotionsDialog.init, EmotionsDialog);
diff --git a/askbot/media/js/tinymce/plugins/emotions/langs/en_dlg.js b/askbot/media/js/tinymce/plugins/emotions/langs/en_dlg.js
new file mode 100644
index 00000000..037c4b58
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/emotions/langs/en_dlg.js
@@ -0,0 +1 @@
+tinyMCE.addI18n('en.emotions_dlg',{cry:"Cry",cool:"Cool",desc:"Emotions",title:"Insert Emotion",usage:"Use left and right arrows to navigate.",yell:"Yell",wink:"Wink",undecided:"Undecided","tongue_out":"Tongue Out",surprised:"Surprised",smile:"Smile",sealed:"Sealed","money_mouth":"Money Mouth",laughing:"Laughing",kiss:"Kiss",innocent:"Innocent",frown:"Frown","foot_in_mouth":"Foot in Mouth",embarassed:"Embarassed"});
diff --git a/askbot/media/js/tinymce/plugins/example/dialog.htm b/askbot/media/js/tinymce/plugins/example/dialog.htm
new file mode 100644
index 00000000..50b2b344
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/example/dialog.htm
@@ -0,0 +1,22 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#example_dlg.title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="js/dialog.js"></script>
+</head>
+<body>
+
+<form onsubmit="ExampleDialog.insert();return false;" action="#">
+ <p>Here is a example dialog.</p>
+ <p>Selected text: <input id="someval" name="someval" type="text" class="text" /></p>
+ <p>Custom arg: <input id="somearg" name="somearg" type="text" class="text" /></p>
+
+ <div class="mceActionPanel">
+ <input type="button" id="insert" name="insert" value="{#insert}" onclick="ExampleDialog.insert();" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/example/editor_plugin.js b/askbot/media/js/tinymce/plugins/example/editor_plugin.js
new file mode 100644
index 00000000..ec1f81ea
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/example/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.PluginManager.requireLangPack("example");tinymce.create("tinymce.plugins.ExamplePlugin",{init:function(a,b){a.addCommand("mceExample",function(){a.windowManager.open({file:b+"/dialog.htm",width:320+parseInt(a.getLang("example.delta_width",0)),height:120+parseInt(a.getLang("example.delta_height",0)),inline:1},{plugin_url:b,some_custom_arg:"custom arg"})});a.addButton("example",{title:"example.desc",cmd:"mceExample",image:b+"/img/example.gif"});a.onNodeChange.add(function(d,c,e){c.setActive("example",e.nodeName=="IMG")})},createControl:function(b,a){return null},getInfo:function(){return{longname:"Example plugin",author:"Some author",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/example",version:"1.0"}}});tinymce.PluginManager.add("example",tinymce.plugins.ExamplePlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/example/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/example/editor_plugin_src.js
new file mode 100644
index 00000000..9a0e7da1
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/example/editor_plugin_src.js
@@ -0,0 +1,84 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ // Load plugin specific language pack
+ tinymce.PluginManager.requireLangPack('example');
+
+ tinymce.create('tinymce.plugins.ExamplePlugin', {
+ /**
+ * Initializes the plugin, this will be executed after the plugin has been created.
+ * This call is done before the editor instance has finished it's initialization so use the onInit event
+ * of the editor instance to intercept that event.
+ *
+ * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in.
+ * @param {string} url Absolute URL to where the plugin is located.
+ */
+ init : function(ed, url) {
+ // Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('mceExample');
+ ed.addCommand('mceExample', function() {
+ ed.windowManager.open({
+ file : url + '/dialog.htm',
+ width : 320 + parseInt(ed.getLang('example.delta_width', 0)),
+ height : 120 + parseInt(ed.getLang('example.delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url, // Plugin absolute URL
+ some_custom_arg : 'custom arg' // Custom argument
+ });
+ });
+
+ // Register example button
+ ed.addButton('example', {
+ title : 'example.desc',
+ cmd : 'mceExample',
+ image : url + '/img/example.gif'
+ });
+
+ // Add a node change handler, selects the button in the UI when a image is selected
+ ed.onNodeChange.add(function(ed, cm, n) {
+ cm.setActive('example', n.nodeName == 'IMG');
+ });
+ },
+
+ /**
+ * Creates control instances based in the incomming name. This method is normally not
+ * needed since the addButton method of the tinymce.Editor class is a more easy way of adding buttons
+ * but you sometimes need to create more complex controls like listboxes, split buttons etc then this
+ * method can be used to create those.
+ *
+ * @param {String} n Name of the control to create.
+ * @param {tinymce.ControlManager} cm Control manager to use inorder to create new control.
+ * @return {tinymce.ui.Control} New control instance or null if no control was created.
+ */
+ createControl : function(n, cm) {
+ return null;
+ },
+
+ /**
+ * Returns information about the plugin as a name/value array.
+ * The current keys are longname, author, authorurl, infourl and version.
+ *
+ * @return {Object} Name/value array containing information about the plugin.
+ */
+ getInfo : function() {
+ return {
+ longname : 'Example plugin',
+ author : 'Some author',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/example',
+ version : "1.0"
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('example', tinymce.plugins.ExamplePlugin);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/example/img/example.gif b/askbot/media/js/tinymce/plugins/example/img/example.gif
new file mode 100644
index 00000000..1ab5da44
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/example/img/example.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/example/js/dialog.js b/askbot/media/js/tinymce/plugins/example/js/dialog.js
new file mode 100644
index 00000000..fa834113
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/example/js/dialog.js
@@ -0,0 +1,19 @@
+tinyMCEPopup.requireLangPack();
+
+var ExampleDialog = {
+ init : function() {
+ var f = document.forms[0];
+
+ // Get the selected contents as text and place it in the input
+ f.someval.value = tinyMCEPopup.editor.selection.getContent({format : 'text'});
+ f.somearg.value = tinyMCEPopup.getWindowArg('some_custom_arg');
+ },
+
+ insert : function() {
+ // Insert the contents from the input into the document
+ tinyMCEPopup.editor.execCommand('mceInsertContent', false, document.forms[0].someval.value);
+ tinyMCEPopup.close();
+ }
+};
+
+tinyMCEPopup.onInit.add(ExampleDialog.init, ExampleDialog);
diff --git a/askbot/media/js/tinymce/plugins/example/langs/en.js b/askbot/media/js/tinymce/plugins/example/langs/en.js
new file mode 100644
index 00000000..e0784f80
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/example/langs/en.js
@@ -0,0 +1,3 @@
+tinyMCE.addI18n('en.example',{
+ desc : 'This is just a template button'
+});
diff --git a/askbot/media/js/tinymce/plugins/example/langs/en_dlg.js b/askbot/media/js/tinymce/plugins/example/langs/en_dlg.js
new file mode 100644
index 00000000..ebcf948d
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/example/langs/en_dlg.js
@@ -0,0 +1,3 @@
+tinyMCE.addI18n('en.example_dlg',{
+ title : 'This is just a example title'
+});
diff --git a/askbot/media/js/tinymce/plugins/example_dependency/editor_plugin.js b/askbot/media/js/tinymce/plugins/example_dependency/editor_plugin.js
new file mode 100644
index 00000000..0a4551d3
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/example_dependency/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.ExampleDependencyPlugin",{init:function(a,b){},getInfo:function(){return{longname:"Example Dependency plugin",author:"Some author",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/example_dependency",version:"1.0"}}});tinymce.PluginManager.add("example_dependency",tinymce.plugins.ExampleDependencyPlugin,["example"])})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/example_dependency/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/example_dependency/editor_plugin_src.js
new file mode 100644
index 00000000..e1c55e41
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/example_dependency/editor_plugin_src.js
@@ -0,0 +1,50 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+
+ tinymce.create('tinymce.plugins.ExampleDependencyPlugin', {
+ /**
+ * Initializes the plugin, this will be executed after the plugin has been created.
+ * This call is done before the editor instance has finished it's initialization so use the onInit event
+ * of the editor instance to intercept that event.
+ *
+ * @param {tinymce.Editor} ed Editor instance that the plugin is initialized in.
+ * @param {string} url Absolute URL to where the plugin is located.
+ */
+ init : function(ed, url) {
+ },
+
+
+ /**
+ * Returns information about the plugin as a name/value array.
+ * The current keys are longname, author, authorurl, infourl and version.
+ *
+ * @return {Object} Name/value array containing information about the plugin.
+ */
+ getInfo : function() {
+ return {
+ longname : 'Example Dependency plugin',
+ author : 'Some author',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/example_dependency',
+ version : "1.0"
+ };
+ }
+ });
+
+ /**
+ * Register the plugin, specifying the list of the plugins that this plugin depends on. They are specified in a list, with the list loaded in order.
+ * plugins in this list will be initialised when this plugin is initialized. (before the init method is called).
+ * plugins in a depends list should typically be specified using the short name). If neccesary this can be done
+ * with an object which has the url to the plugin and the shortname.
+ */
+ tinymce.PluginManager.add('example_dependency', tinymce.plugins.ExampleDependencyPlugin, ['example']);
+})();
diff --git a/askbot/media/js/tinymce/plugins/fullpage/css/fullpage.css b/askbot/media/js/tinymce/plugins/fullpage/css/fullpage.css
new file mode 100644
index 00000000..2675cec1
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/fullpage/css/fullpage.css
@@ -0,0 +1,143 @@
+/* Hide the advanced tab */
+#advanced_tab {
+ display: none;
+}
+
+#metatitle, #metakeywords, #metadescription, #metaauthor, #metacopyright {
+ width: 280px;
+}
+
+#doctype, #docencoding {
+ width: 200px;
+}
+
+#langcode {
+ width: 30px;
+}
+
+#bgimage {
+ width: 220px;
+}
+
+#fontface {
+ width: 240px;
+}
+
+#leftmargin, #rightmargin, #topmargin, #bottommargin {
+ width: 50px;
+}
+
+.panel_wrapper div.current {
+ height: 400px;
+}
+
+#stylesheet, #style {
+ width: 240px;
+}
+
+#doctypes {
+ width: 200px;
+}
+
+/* Head list classes */
+
+.headlistwrapper {
+ width: 100%;
+}
+
+.selected {
+ border: 1px solid #0A246A;
+ background-color: #B6BDD2;
+}
+
+.toolbar {
+ width: 100%;
+}
+
+#headlist {
+ width: 100%;
+ margin-top: 3px;
+ font-size: 11px;
+}
+
+#info, #title_element, #meta_element, #script_element, #style_element, #base_element, #link_element, #comment_element, #unknown_element {
+ display: none;
+}
+
+#addmenu {
+ position: absolute;
+ border: 1px solid gray;
+ display: none;
+ z-index: 100;
+ background-color: white;
+}
+
+#addmenu a {
+ display: block;
+ width: 100%;
+ line-height: 20px;
+ text-decoration: none;
+ background-color: white;
+}
+
+#addmenu a:hover {
+ background-color: #B6BDD2;
+ color: black;
+}
+
+#addmenu span {
+ padding-left: 10px;
+ padding-right: 10px;
+}
+
+#updateElementPanel {
+ display: none;
+}
+
+#script_element .panel_wrapper div.current {
+ height: 108px;
+}
+
+#style_element .panel_wrapper div.current {
+ height: 108px;
+}
+
+#link_element .panel_wrapper div.current {
+ height: 140px;
+}
+
+#element_script_value {
+ width: 100%;
+ height: 100px;
+}
+
+#element_comment_value {
+ width: 100%;
+ height: 120px;
+}
+
+#element_style_value {
+ width: 100%;
+ height: 100px;
+}
+
+#element_title, #element_script_src, #element_meta_name, #element_meta_content, #element_base_href, #element_link_href, #element_link_title {
+ width: 250px;
+}
+
+.updateElementButton {
+ margin-top: 3px;
+}
+
+/* MSIE specific styles */
+
+* html .addbutton, * html .removebutton, * html .moveupbutton, * html .movedownbutton {
+ width: 22px;
+ height: 22px;
+}
+
+textarea {
+ height: 55px;
+}
+
+.panel_wrapper div.current {height:420px;} \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/fullpage/editor_plugin.js b/askbot/media/js/tinymce/plugins/fullpage/editor_plugin.js
new file mode 100644
index 00000000..dcf76024
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/fullpage/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var b=tinymce.each,a=tinymce.html.Node;tinymce.create("tinymce.plugins.FullPagePlugin",{init:function(c,d){var e=this;e.editor=c;c.addCommand("mceFullPageProperties",function(){c.windowManager.open({file:d+"/fullpage.htm",width:430+parseInt(c.getLang("fullpage.delta_width",0)),height:495+parseInt(c.getLang("fullpage.delta_height",0)),inline:1},{plugin_url:d,data:e._htmlToData()})});c.addButton("fullpage",{title:"fullpage.desc",cmd:"mceFullPageProperties"});c.onBeforeSetContent.add(e._setContent,e);c.onGetContent.add(e._getContent,e)},getInfo:function(){return{longname:"Fullpage",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullpage",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_htmlToData:function(){var f=this._parseHeader(),h={},c,i,g,e=this.editor;function d(l,j){var k=l.attr(j);return k||""}h.fontface=e.getParam("fullpage_default_fontface","");h.fontsize=e.getParam("fullpage_default_fontsize","");i=f.firstChild;if(i.type==7){h.xml_pi=true;g=/encoding="([^"]+)"/.exec(i.value);if(g){h.docencoding=g[1]}}i=f.getAll("#doctype")[0];if(i){h.doctype="<!DOCTYPE"+i.value+">"}i=f.getAll("title")[0];if(i&&i.firstChild){h.metatitle=i.firstChild.value}b(f.getAll("meta"),function(m){var k=m.attr("name"),j=m.attr("http-equiv"),l;if(k){h["meta"+k.toLowerCase()]=m.attr("content")}else{if(j=="Content-Type"){l=/charset\s*=\s*(.*)\s*/gi.exec(m.attr("content"));if(l){h.docencoding=l[1]}}}});i=f.getAll("html")[0];if(i){h.langcode=d(i,"lang")||d(i,"xml:lang")}i=f.getAll("link")[0];if(i&&i.attr("rel")=="stylesheet"){h.stylesheet=i.attr("href")}i=f.getAll("body")[0];if(i){h.langdir=d(i,"dir");h.style=d(i,"style");h.visited_color=d(i,"vlink");h.link_color=d(i,"link");h.active_color=d(i,"alink")}return h},_dataToHtml:function(g){var f,d,h,j,k,e=this.editor.dom;function c(n,l,m){n.attr(l,m?m:undefined)}function i(l){if(d.firstChild){d.insert(l,d.firstChild)}else{d.append(l)}}f=this._parseHeader();d=f.getAll("head")[0];if(!d){j=f.getAll("html")[0];d=new a("head",1);if(j.firstChild){j.insert(d,j.firstChild,true)}else{j.append(d)}}j=f.firstChild;if(g.xml_pi){k='version="1.0"';if(g.docencoding){k+=' encoding="'+g.docencoding+'"'}if(j.type!=7){j=new a("xml",7);f.insert(j,f.firstChild,true)}j.value=k}else{if(j&&j.type==7){j.remove()}}j=f.getAll("#doctype")[0];if(g.doctype){if(!j){j=new a("#doctype",10);if(g.xml_pi){f.insert(j,f.firstChild)}else{i(j)}}j.value=g.doctype.substring(9,g.doctype.length-1)}else{if(j){j.remove()}}j=f.getAll("title")[0];if(g.metatitle){if(!j){j=new a("title",1);j.append(new a("#text",3)).value=g.metatitle;i(j)}}if(g.docencoding){j=null;b(f.getAll("meta"),function(l){if(l.attr("http-equiv")=="Content-Type"){j=l}});if(!j){j=new a("meta",1);j.attr("http-equiv","Content-Type");j.shortEnded=true;i(j)}j.attr("content","text/html; charset="+g.docencoding)}b("keywords,description,author,copyright,robots".split(","),function(m){var l=f.getAll("meta"),n,p,o=g["meta"+m];for(n=0;n<l.length;n++){p=l[n];if(p.attr("name")==m){if(o){p.attr("content",o)}else{p.remove()}return}}if(o){j=new a("meta",1);j.attr("name",m);j.attr("content",o);j.shortEnded=true;i(j)}});j=f.getAll("link")[0];if(j&&j.attr("rel")=="stylesheet"){if(g.stylesheet){j.attr("href",g.stylesheet)}else{j.remove()}}else{if(g.stylesheet){j=new a("link",1);j.attr({rel:"stylesheet",text:"text/css",href:g.stylesheet});j.shortEnded=true;i(j)}}j=f.getAll("body")[0];if(j){c(j,"dir",g.langdir);c(j,"style",g.style);c(j,"vlink",g.visited_color);c(j,"link",g.link_color);c(j,"alink",g.active_color);e.setAttribs(this.editor.getBody(),{style:g.style,dir:g.dir,vLink:g.visited_color,link:g.link_color,aLink:g.active_color})}j=f.getAll("html")[0];if(j){c(j,"lang",g.langcode);c(j,"xml:lang",g.langcode)}h=new tinymce.html.Serializer({validate:false,indent:true,apply_source_formatting:true,indent_before:"head,html,body,meta,title,script,link,style",indent_after:"head,html,body,meta,title,script,link,style"}).serialize(f);this.head=h.substring(0,h.indexOf("</body>"))},_parseHeader:function(){return new tinymce.html.DomParser({validate:false,root_name:"#document"}).parse(this.head)},_setContent:function(g,d){var m=this,i,c,h=d.content,f,l="",e=m.editor.dom,j;function k(n){return n.replace(/<\/?[A-Z]+/g,function(o){return o.toLowerCase()})}if(d.format=="raw"&&m.head){return}if(d.source_view&&g.getParam("fullpage_hide_in_source_view")){return}h=h.replace(/<(\/?)BODY/gi,"<$1body");i=h.indexOf("<body");if(i!=-1){i=h.indexOf(">",i);m.head=k(h.substring(0,i+1));c=h.indexOf("</body",i);if(c==-1){c=h.length}d.content=h.substring(i+1,c);m.foot=k(h.substring(c))}else{m.head=this._getDefaultHeader();m.foot="\n</body>\n</html>"}f=m._parseHeader();b(f.getAll("style"),function(n){if(n.firstChild){l+=n.firstChild.value}});j=f.getAll("body")[0];if(j){e.setAttribs(m.editor.getBody(),{style:j.attr("style")||"",dir:j.attr("dir")||"",vLink:j.attr("vlink")||"",link:j.attr("link")||"",aLink:j.attr("alink")||""})}e.remove("fullpage_styles");if(l){e.add(m.editor.getDoc().getElementsByTagName("head")[0],"style",{id:"fullpage_styles"},l);j=e.get("fullpage_styles");if(j.styleSheet){j.styleSheet.cssText=l}}},_getDefaultHeader:function(){var f="",c=this.editor,e,d="";if(c.getParam("fullpage_default_xml_pi")){f+='<?xml version="1.0" encoding="'+c.getParam("fullpage_default_encoding","ISO-8859-1")+'" ?>\n'}f+=c.getParam("fullpage_default_doctype",'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');f+="\n<html>\n<head>\n";if(e=c.getParam("fullpage_default_title")){f+="<title>"+e+"</title>\n"}if(e=c.getParam("fullpage_default_encoding")){f+='<meta http-equiv="Content-Type" content="text/html; charset='+e+'" />\n'}if(e=c.getParam("fullpage_default_font_family")){d+="font-family: "+e+";"}if(e=c.getParam("fullpage_default_font_size")){d+="font-size: "+e+";"}if(e=c.getParam("fullpage_default_text_color")){d+="color: "+e+";"}f+="</head>\n<body"+(d?' style="'+d+'"':"")+">\n";return f},_getContent:function(d,e){var c=this;if(!e.source_view||!d.getParam("fullpage_hide_in_source_view")){e.content=tinymce.trim(c.head)+"\n"+tinymce.trim(e.content)+"\n"+tinymce.trim(c.foot)}}});tinymce.PluginManager.add("fullpage",tinymce.plugins.FullPagePlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/fullpage/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/fullpage/editor_plugin_src.js
new file mode 100644
index 00000000..23de7c5a
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/fullpage/editor_plugin_src.js
@@ -0,0 +1,405 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var each = tinymce.each, Node = tinymce.html.Node;
+
+ tinymce.create('tinymce.plugins.FullPagePlugin', {
+ init : function(ed, url) {
+ var t = this;
+
+ t.editor = ed;
+
+ // Register commands
+ ed.addCommand('mceFullPageProperties', function() {
+ ed.windowManager.open({
+ file : url + '/fullpage.htm',
+ width : 430 + parseInt(ed.getLang('fullpage.delta_width', 0)),
+ height : 495 + parseInt(ed.getLang('fullpage.delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url,
+ data : t._htmlToData()
+ });
+ });
+
+ // Register buttons
+ ed.addButton('fullpage', {title : 'fullpage.desc', cmd : 'mceFullPageProperties'});
+
+ ed.onBeforeSetContent.add(t._setContent, t);
+ ed.onGetContent.add(t._getContent, t);
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Fullpage',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullpage',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ // Private plugin internal methods
+
+ _htmlToData : function() {
+ var headerFragment = this._parseHeader(), data = {}, nodes, elm, matches, editor = this.editor;
+
+ function getAttr(elm, name) {
+ var value = elm.attr(name);
+
+ return value || '';
+ };
+
+ // Default some values
+ data.fontface = editor.getParam("fullpage_default_fontface", "");
+ data.fontsize = editor.getParam("fullpage_default_fontsize", "");
+
+ // Parse XML PI
+ elm = headerFragment.firstChild;
+ if (elm.type == 7) {
+ data.xml_pi = true;
+ matches = /encoding="([^"]+)"/.exec(elm.value);
+ if (matches)
+ data.docencoding = matches[1];
+ }
+
+ // Parse doctype
+ elm = headerFragment.getAll('#doctype')[0];
+ if (elm)
+ data.doctype = '<!DOCTYPE' + elm.value + ">";
+
+ // Parse title element
+ elm = headerFragment.getAll('title')[0];
+ if (elm && elm.firstChild) {
+ data.metatitle = elm.firstChild.value;
+ }
+
+ // Parse meta elements
+ each(headerFragment.getAll('meta'), function(meta) {
+ var name = meta.attr('name'), httpEquiv = meta.attr('http-equiv'), matches;
+
+ if (name)
+ data['meta' + name.toLowerCase()] = meta.attr('content');
+ else if (httpEquiv == "Content-Type") {
+ matches = /charset\s*=\s*(.*)\s*/gi.exec(meta.attr('content'));
+
+ if (matches)
+ data.docencoding = matches[1];
+ }
+ });
+
+ // Parse html attribs
+ elm = headerFragment.getAll('html')[0];
+ if (elm)
+ data.langcode = getAttr(elm, 'lang') || getAttr(elm, 'xml:lang');
+
+ // Parse stylesheet
+ elm = headerFragment.getAll('link')[0];
+ if (elm && elm.attr('rel') == 'stylesheet')
+ data.stylesheet = elm.attr('href');
+
+ // Parse body parts
+ elm = headerFragment.getAll('body')[0];
+ if (elm) {
+ data.langdir = getAttr(elm, 'dir');
+ data.style = getAttr(elm, 'style');
+ data.visited_color = getAttr(elm, 'vlink');
+ data.link_color = getAttr(elm, 'link');
+ data.active_color = getAttr(elm, 'alink');
+ }
+
+ return data;
+ },
+
+ _dataToHtml : function(data) {
+ var headerFragment, headElement, html, elm, value, dom = this.editor.dom;
+
+ function setAttr(elm, name, value) {
+ elm.attr(name, value ? value : undefined);
+ };
+
+ function addHeadNode(node) {
+ if (headElement.firstChild)
+ headElement.insert(node, headElement.firstChild);
+ else
+ headElement.append(node);
+ };
+
+ headerFragment = this._parseHeader();
+ headElement = headerFragment.getAll('head')[0];
+ if (!headElement) {
+ elm = headerFragment.getAll('html')[0];
+ headElement = new Node('head', 1);
+
+ if (elm.firstChild)
+ elm.insert(headElement, elm.firstChild, true);
+ else
+ elm.append(headElement);
+ }
+
+ // Add/update/remove XML-PI
+ elm = headerFragment.firstChild;
+ if (data.xml_pi) {
+ value = 'version="1.0"';
+
+ if (data.docencoding)
+ value += ' encoding="' + data.docencoding + '"';
+
+ if (elm.type != 7) {
+ elm = new Node('xml', 7);
+ headerFragment.insert(elm, headerFragment.firstChild, true);
+ }
+
+ elm.value = value;
+ } else if (elm && elm.type == 7)
+ elm.remove();
+
+ // Add/update/remove doctype
+ elm = headerFragment.getAll('#doctype')[0];
+ if (data.doctype) {
+ if (!elm) {
+ elm = new Node('#doctype', 10);
+
+ if (data.xml_pi)
+ headerFragment.insert(elm, headerFragment.firstChild);
+ else
+ addHeadNode(elm);
+ }
+
+ elm.value = data.doctype.substring(9, data.doctype.length - 1);
+ } else if (elm)
+ elm.remove();
+
+ // Add/update/remove title
+ elm = headerFragment.getAll('title')[0];
+ if (data.metatitle) {
+ if (!elm) {
+ elm = new Node('title', 1);
+ elm.append(new Node('#text', 3)).value = data.metatitle;
+ addHeadNode(elm);
+ }
+ }
+
+ // Add meta encoding
+ if (data.docencoding) {
+ elm = null;
+ each(headerFragment.getAll('meta'), function(meta) {
+ if (meta.attr('http-equiv') == 'Content-Type')
+ elm = meta;
+ });
+
+ if (!elm) {
+ elm = new Node('meta', 1);
+ elm.attr('http-equiv', 'Content-Type');
+ elm.shortEnded = true;
+ addHeadNode(elm);
+ }
+
+ elm.attr('content', 'text/html; charset=' + data.docencoding);
+ }
+
+ // Add/update/remove meta
+ each('keywords,description,author,copyright,robots'.split(','), function(name) {
+ var nodes = headerFragment.getAll('meta'), i, meta, value = data['meta' + name];
+
+ for (i = 0; i < nodes.length; i++) {
+ meta = nodes[i];
+
+ if (meta.attr('name') == name) {
+ if (value)
+ meta.attr('content', value);
+ else
+ meta.remove();
+
+ return;
+ }
+ }
+
+ if (value) {
+ elm = new Node('meta', 1);
+ elm.attr('name', name);
+ elm.attr('content', value);
+ elm.shortEnded = true;
+
+ addHeadNode(elm);
+ }
+ });
+
+ // Add/update/delete link
+ elm = headerFragment.getAll('link')[0];
+ if (elm && elm.attr('rel') == 'stylesheet') {
+ if (data.stylesheet)
+ elm.attr('href', data.stylesheet);
+ else
+ elm.remove();
+ } else if (data.stylesheet) {
+ elm = new Node('link', 1);
+ elm.attr({
+ rel : 'stylesheet',
+ text : 'text/css',
+ href : data.stylesheet
+ });
+ elm.shortEnded = true;
+
+ addHeadNode(elm);
+ }
+
+ // Update body attributes
+ elm = headerFragment.getAll('body')[0];
+ if (elm) {
+ setAttr(elm, 'dir', data.langdir);
+ setAttr(elm, 'style', data.style);
+ setAttr(elm, 'vlink', data.visited_color);
+ setAttr(elm, 'link', data.link_color);
+ setAttr(elm, 'alink', data.active_color);
+
+ // Update iframe body as well
+ dom.setAttribs(this.editor.getBody(), {
+ style : data.style,
+ dir : data.dir,
+ vLink : data.visited_color,
+ link : data.link_color,
+ aLink : data.active_color
+ });
+ }
+
+ // Set html attributes
+ elm = headerFragment.getAll('html')[0];
+ if (elm) {
+ setAttr(elm, 'lang', data.langcode);
+ setAttr(elm, 'xml:lang', data.langcode);
+ }
+
+ // Serialize header fragment and crop away body part
+ html = new tinymce.html.Serializer({
+ validate: false,
+ indent: true,
+ apply_source_formatting : true,
+ indent_before: 'head,html,body,meta,title,script,link,style',
+ indent_after: 'head,html,body,meta,title,script,link,style'
+ }).serialize(headerFragment);
+
+ this.head = html.substring(0, html.indexOf('</body>'));
+ },
+
+ _parseHeader : function() {
+ // Parse the contents with a DOM parser
+ return new tinymce.html.DomParser({
+ validate: false,
+ root_name: '#document'
+ }).parse(this.head);
+ },
+
+ _setContent : function(ed, o) {
+ var self = this, startPos, endPos, content = o.content, headerFragment, styles = '', dom = self.editor.dom, elm;
+
+ function low(s) {
+ return s.replace(/<\/?[A-Z]+/g, function(a) {
+ return a.toLowerCase();
+ })
+ };
+
+ // Ignore raw updated if we already have a head, this will fix issues with undo/redo keeping the head/foot separate
+ if (o.format == 'raw' && self.head)
+ return;
+
+ if (o.source_view && ed.getParam('fullpage_hide_in_source_view'))
+ return;
+
+ // Parse out head, body and footer
+ content = content.replace(/<(\/?)BODY/gi, '<$1body');
+ startPos = content.indexOf('<body');
+
+ if (startPos != -1) {
+ startPos = content.indexOf('>', startPos);
+ self.head = low(content.substring(0, startPos + 1));
+
+ endPos = content.indexOf('</body', startPos);
+ if (endPos == -1)
+ endPos = content.length;
+
+ o.content = content.substring(startPos + 1, endPos);
+ self.foot = low(content.substring(endPos));
+ } else {
+ self.head = this._getDefaultHeader();
+ self.foot = '\n</body>\n</html>';
+ }
+
+ // Parse header and update iframe
+ headerFragment = self._parseHeader();
+ each(headerFragment.getAll('style'), function(node) {
+ if (node.firstChild)
+ styles += node.firstChild.value;
+ });
+
+ elm = headerFragment.getAll('body')[0];
+ if (elm) {
+ dom.setAttribs(self.editor.getBody(), {
+ style : elm.attr('style') || '',
+ dir : elm.attr('dir') || '',
+ vLink : elm.attr('vlink') || '',
+ link : elm.attr('link') || '',
+ aLink : elm.attr('alink') || ''
+ });
+ }
+
+ dom.remove('fullpage_styles');
+
+ if (styles) {
+ dom.add(self.editor.getDoc().getElementsByTagName('head')[0], 'style', {id : 'fullpage_styles'}, styles);
+
+ // Needed for IE 6/7
+ elm = dom.get('fullpage_styles');
+ if (elm.styleSheet)
+ elm.styleSheet.cssText = styles;
+ }
+ },
+
+ _getDefaultHeader : function() {
+ var header = '', editor = this.editor, value, styles = '';
+
+ if (editor.getParam('fullpage_default_xml_pi'))
+ header += '<?xml version="1.0" encoding="' + editor.getParam('fullpage_default_encoding', 'ISO-8859-1') + '" ?>\n';
+
+ header += editor.getParam('fullpage_default_doctype', '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">');
+ header += '\n<html>\n<head>\n';
+
+ if (value = editor.getParam('fullpage_default_title'))
+ header += '<title>' + value + '</title>\n';
+
+ if (value = editor.getParam('fullpage_default_encoding'))
+ header += '<meta http-equiv="Content-Type" content="text/html; charset=' + value + '" />\n';
+
+ if (value = editor.getParam('fullpage_default_font_family'))
+ styles += 'font-family: ' + value + ';';
+
+ if (value = editor.getParam('fullpage_default_font_size'))
+ styles += 'font-size: ' + value + ';';
+
+ if (value = editor.getParam('fullpage_default_text_color'))
+ styles += 'color: ' + value + ';';
+
+ header += '</head>\n<body' + (styles ? ' style="' + styles + '"' : '') + '>\n';
+
+ return header;
+ },
+
+ _getContent : function(ed, o) {
+ var self = this;
+
+ if (!o.source_view || !ed.getParam('fullpage_hide_in_source_view'))
+ o.content = tinymce.trim(self.head) + '\n' + tinymce.trim(o.content) + '\n' + tinymce.trim(self.foot);
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('fullpage', tinymce.plugins.FullPagePlugin);
+})();
diff --git a/askbot/media/js/tinymce/plugins/fullpage/fullpage.htm b/askbot/media/js/tinymce/plugins/fullpage/fullpage.htm
new file mode 100644
index 00000000..14ab8652
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/fullpage/fullpage.htm
@@ -0,0 +1,259 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#fullpage_dlg.title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="js/fullpage.js"></script>
+ <link href="css/fullpage.css" rel="stylesheet" type="text/css" />
+</head>
+<body id="fullpage" style="display: none">
+<form onsubmit="FullPageDialog.update();return false;" name="fullpage" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="meta_tab" class="current"><span><a href="javascript:mcTabs.displayTab('meta_tab','meta_panel');" onmousedown="return false;">{#fullpage_dlg.meta_tab}</a></span></li>
+ <li id="appearance_tab"><span><a href="javascript:mcTabs.displayTab('appearance_tab','appearance_panel');" onmousedown="return false;">{#fullpage_dlg.appearance_tab}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="meta_panel" class="panel current">
+ <fieldset>
+ <legend>{#fullpage_dlg.meta_props}</legend>
+
+ <table border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td class="nowrap"><label for="metatitle">{#fullpage_dlg.meta_title}</label>&nbsp;</td>
+ <td><input type="text" id="metatitle" name="metatitle" value="" class="mceFocus" /></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="metakeywords">{#fullpage_dlg.meta_keywords}</label>&nbsp;</td>
+ <td><textarea id="metakeywords" name="metakeywords" rows="4"></textarea></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="metadescription">{#fullpage_dlg.meta_description}</label>&nbsp;</td>
+ <td><textarea id="metadescription" name="metadescription" rows="4"></textarea></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="metaauthor">{#fullpage_dlg.author}</label>&nbsp;</td>
+ <td><input type="text" id="metaauthor" name="metaauthor" value="" /></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="metacopyright">{#fullpage_dlg.copyright}</label>&nbsp;</td>
+ <td><input type="text" id="metacopyright" name="metacopyright" value="" /></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="metarobots">{#fullpage_dlg.meta_robots}</label>&nbsp;</td>
+ <td>
+ <select id="metarobots" name="metarobots">
+ <option value="">{#not_set}</option>
+ <option value="index,follow">{#fullpage_dlg.meta_index_follow}</option>
+ <option value="index,nofollow">{#fullpage_dlg.meta_index_nofollow}</option>
+ <option value="noindex,follow">{#fullpage_dlg.meta_noindex_follow}</option>
+ <option value="noindex,nofollow">{#fullpage_dlg.meta_noindex_nofollow}</option>
+ </select>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset>
+ <legend>{#fullpage_dlg.langprops}</legend>
+
+ <table border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td class="column1"><label for="docencoding">{#fullpage_dlg.encoding}</label></td>
+ <td>
+ <select id="docencoding" name="docencoding">
+ <option value="">{#not_set}</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="doctype">{#fullpage_dlg.doctypes}</label>&nbsp;</td>
+ <td>
+ <select id="doctype" name="doctype">
+ <option value="">{#not_set}</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="langcode">{#fullpage_dlg.langcode}</label>&nbsp;</td>
+ <td><input type="text" id="langcode" name="langcode" value="" /></td>
+ </tr>
+ <tr>
+ <td class="column1"><label for="langdir">{#fullpage_dlg.langdir}</label></td>
+ <td>
+ <select id="langdir" name="langdir">
+ <option value="">{#not_set}</option>
+ <option value="ltr">{#fullpage_dlg.ltr}</option>
+ <option value="rtl">{#fullpage_dlg.rtl}</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="xml_pi">{#fullpage_dlg.xml_pi}</label>&nbsp;</td>
+ <td><input type="checkbox" id="xml_pi" name="xml_pi" class="checkbox" /></td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+
+ <div id="appearance_panel" class="panel">
+ <fieldset>
+ <legend>{#fullpage_dlg.appearance_textprops}</legend>
+
+ <table border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td class="column1"><label for="fontface">{#fullpage_dlg.fontface}</label></td>
+ <td>
+ <select id="fontface" name="fontface" onchange="FullPageDialog.changedStyleProp();">
+ <option value="">{#not_set}</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="fontsize">{#fullpage_dlg.fontsize}</label></td>
+ <td>
+ <select id="fontsize" name="fontsize" onchange="FullPageDialog.changedStyleProp();">
+ <option value="">{#not_set}</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="textcolor">{#fullpage_dlg.textcolor}</label></td>
+ <td>
+ <table border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="textcolor" name="textcolor" type="text" value="" size="9" onchange="updateColor('textcolor_pick','textcolor');FullPageDialog.changedStyleProp();" /></td>
+ <td id="textcolor_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset>
+ <legend>{#fullpage_dlg.appearance_bgprops}</legend>
+
+ <table border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td class="column1"><label for="bgimage">{#fullpage_dlg.bgimage}</label></td>
+ <td>
+ <table border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="bgimage" name="bgimage" type="text" value="" onchange="FullPageDialog.changedStyleProp();" /></td>
+ <td id="bgimage_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td class="column1"><label for="bgcolor">{#fullpage_dlg.bgcolor}</label></td>
+ <td>
+ <table border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="bgcolor" name="bgcolor" type="text" value="" size="9" onchange="updateColor('bgcolor_pick','bgcolor');FullPageDialog.changedStyleProp();" /></td>
+ <td id="bgcolor_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset>
+ <legend>{#fullpage_dlg.appearance_marginprops}</legend>
+
+ <table border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td class="column1"><label for="leftmargin">{#fullpage_dlg.left_margin}</label></td>
+ <td><input id="leftmargin" name="leftmargin" type="text" value="" onchange="FullPageDialog.changedStyleProp();" /></td>
+ <td class="column1"><label for="rightmargin">{#fullpage_dlg.right_margin}</label></td>
+ <td><input id="rightmargin" name="rightmargin" type="text" value="" onchange="FullPageDialog.changedStyleProp();" /></td>
+ </tr>
+ <tr>
+ <td class="column1"><label for="topmargin">{#fullpage_dlg.top_margin}</label></td>
+ <td><input id="topmargin" name="topmargin" type="text" value="" onchange="FullPageDialog.changedStyleProp();" /></td>
+ <td class="column1"><label for="bottommargin">{#fullpage_dlg.bottom_margin}</label></td>
+ <td><input id="bottommargin" name="bottommargin" type="text" value="" onchange="FullPageDialog.changedStyleProp();" /></td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset>
+ <legend>{#fullpage_dlg.appearance_linkprops}</legend>
+
+ <table border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td class="column1"><label for="link_color">{#fullpage_dlg.link_color}</label></td>
+ <td>
+ <table border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="link_color" name="link_color" type="text" value="" size="9" onchange="updateColor('link_color_pick','link_color');FullPageDialog.changedStyleProp();" /></td>
+ <td id="link_color_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+
+ <td class="column1"><label for="visited_color">{#fullpage_dlg.visited_color}</label></td>
+ <td>
+ <table border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="visited_color" name="visited_color" type="text" value="" size="9" onchange="updateColor('visited_color_pick','visited_color');FullPageDialog.changedStyleProp();" /></td>
+ <td id="visited_color_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="active_color">{#fullpage_dlg.active_color}</label></td>
+ <td>
+ <table border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="active_color" name="active_color" type="text" value="" size="9" onchange="updateColor('active_color_pick','active_color');FullPageDialog.changedStyleProp();" /></td>
+ <td id="active_color_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+
+ <td>&nbsp;</td>
+ <td>&nbsp;</td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset>
+ <legend>{#fullpage_dlg.appearance_style}</legend>
+
+ <table border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td class="column1"><label for="stylesheet">{#fullpage_dlg.stylesheet}</label></td>
+ <td><table border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="stylesheet" name="stylesheet" type="text" value="" /></td>
+ <td id="stylesheet_browsercontainer">&nbsp;</td>
+ </tr>
+ </table></td>
+ </tr>
+ <tr>
+ <td class="column1"><label for="style">{#fullpage_dlg.style}</label></td>
+ <td><input id="style" name="style" type="text" value="" onchange="FullPageDialog.changedStyle();" /></td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="update" value="{#update}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/fullpage/js/fullpage.js b/askbot/media/js/tinymce/plugins/fullpage/js/fullpage.js
new file mode 100644
index 00000000..3f672ad3
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/fullpage/js/fullpage.js
@@ -0,0 +1,232 @@
+/**
+ * fullpage.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinyMCEPopup.requireLangPack();
+
+ var defaultDocTypes =
+ 'XHTML 1.0 Transitional=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">,' +
+ 'XHTML 1.0 Frameset=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">,' +
+ 'XHTML 1.0 Strict=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">,' +
+ 'XHTML 1.1=<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">,' +
+ 'HTML 4.01 Transitional=<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">,' +
+ 'HTML 4.01 Strict=<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">,' +
+ 'HTML 4.01 Frameset=<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">';
+
+ var defaultEncodings =
+ 'Western european (iso-8859-1)=iso-8859-1,' +
+ 'Central European (iso-8859-2)=iso-8859-2,' +
+ 'Unicode (UTF-8)=utf-8,' +
+ 'Chinese traditional (Big5)=big5,' +
+ 'Cyrillic (iso-8859-5)=iso-8859-5,' +
+ 'Japanese (iso-2022-jp)=iso-2022-jp,' +
+ 'Greek (iso-8859-7)=iso-8859-7,' +
+ 'Korean (iso-2022-kr)=iso-2022-kr,' +
+ 'ASCII (us-ascii)=us-ascii';
+
+ var defaultFontNames = 'Arial=arial,helvetica,sans-serif;Courier New=courier new,courier,monospace;Georgia=georgia,times new roman,times,serif;Tahoma=tahoma,arial,helvetica,sans-serif;Times New Roman=times new roman,times,serif;Verdana=verdana,arial,helvetica,sans-serif;Impact=impact;WingDings=wingdings';
+ var defaultFontSizes = '10px,11px,12px,13px,14px,15px,16px';
+
+ function setVal(id, value) {
+ var elm = document.getElementById(id);
+
+ if (elm) {
+ value = value || '';
+
+ if (elm.nodeName == "SELECT")
+ selectByValue(document.forms[0], id, value);
+ else if (elm.type == "checkbox")
+ elm.checked = !!value;
+ else
+ elm.value = value;
+ }
+ };
+
+ function getVal(id) {
+ var elm = document.getElementById(id);
+
+ if (elm.nodeName == "SELECT")
+ return elm.options[elm.selectedIndex].value;
+
+ if (elm.type == "checkbox")
+ return elm.checked;
+
+ return elm.value;
+ };
+
+ window.FullPageDialog = {
+ changedStyle : function() {
+ var val, styles = tinyMCEPopup.editor.dom.parseStyle(getVal('style'));
+
+ setVal('fontface', styles['font-face']);
+ setVal('fontsize', styles['font-size']);
+ setVal('textcolor', styles['color']);
+
+ if (val = styles['background-image'])
+ setVal('bgimage', val.replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1"));
+ else
+ setVal('bgimage', '');
+
+ setVal('bgcolor', styles['background-color']);
+
+ // Reset margin form elements
+ setVal('topmargin', '');
+ setVal('rightmargin', '');
+ setVal('bottommargin', '');
+ setVal('leftmargin', '');
+
+ // Expand margin
+ if (val = styles['margin']) {
+ val = val.split(' ');
+ styles['margin-top'] = val[0] || '';
+ styles['margin-right'] = val[1] || val[0] || '';
+ styles['margin-bottom'] = val[2] || val[0] || '';
+ styles['margin-left'] = val[3] || val[0] || '';
+ }
+
+ if (val = styles['margin-top'])
+ setVal('topmargin', val.replace(/px/, ''));
+
+ if (val = styles['margin-right'])
+ setVal('rightmargin', val.replace(/px/, ''));
+
+ if (val = styles['margin-bottom'])
+ setVal('bottommargin', val.replace(/px/, ''));
+
+ if (val = styles['margin-left'])
+ setVal('leftmargin', val.replace(/px/, ''));
+
+ updateColor('bgcolor_pick', 'bgcolor');
+ updateColor('textcolor_pick', 'textcolor');
+ },
+
+ changedStyleProp : function() {
+ var val, dom = tinyMCEPopup.editor.dom, styles = dom.parseStyle(getVal('style'));
+
+ styles['font-face'] = getVal('fontface');
+ styles['font-size'] = getVal('fontsize');
+ styles['color'] = getVal('textcolor');
+ styles['background-color'] = getVal('bgcolor');
+
+ if (val = getVal('bgimage'))
+ styles['background-image'] = "url('" + val + "')";
+ else
+ styles['background-image'] = '';
+
+ delete styles['margin'];
+
+ if (val = getVal('topmargin'))
+ styles['margin-top'] = val + "px";
+ else
+ styles['margin-top'] = '';
+
+ if (val = getVal('rightmargin'))
+ styles['margin-right'] = val + "px";
+ else
+ styles['margin-right'] = '';
+
+ if (val = getVal('bottommargin'))
+ styles['margin-bottom'] = val + "px";
+ else
+ styles['margin-bottom'] = '';
+
+ if (val = getVal('leftmargin'))
+ styles['margin-left'] = val + "px";
+ else
+ styles['margin-left'] = '';
+
+ // Serialize, parse and reserialize this will compress redundant styles
+ setVal('style', dom.serializeStyle(dom.parseStyle(dom.serializeStyle(styles))));
+ this.changedStyle();
+ },
+
+ update : function() {
+ var data = {};
+
+ tinymce.each(tinyMCEPopup.dom.select('select,input,textarea'), function(node) {
+ data[node.id] = getVal(node.id);
+ });
+
+ tinyMCEPopup.editor.plugins.fullpage._dataToHtml(data);
+ tinyMCEPopup.close();
+ }
+ };
+
+ function init() {
+ var form = document.forms[0], i, item, list, editor = tinyMCEPopup.editor;
+
+ // Setup doctype select box
+ list = editor.getParam("fullpage_doctypes", defaultDocTypes).split(',');
+ for (i = 0; i < list.length; i++) {
+ item = list[i].split('=');
+
+ if (item.length > 1)
+ addSelectValue(form, 'doctype', item[0], item[1]);
+ }
+
+ // Setup fonts select box
+ list = editor.getParam("fullpage_fonts", defaultFontNames).split(';');
+ for (i = 0; i < list.length; i++) {
+ item = list[i].split('=');
+
+ if (item.length > 1)
+ addSelectValue(form, 'fontface', item[0], item[1]);
+ }
+
+ // Setup fontsize select box
+ list = editor.getParam("fullpage_fontsizes", defaultFontSizes).split(',');
+ for (i = 0; i < list.length; i++)
+ addSelectValue(form, 'fontsize', list[i], list[i]);
+
+ // Setup encodings select box
+ list = editor.getParam("fullpage_encodings", defaultEncodings).split(',');
+ for (i = 0; i < list.length; i++) {
+ item = list[i].split('=');
+
+ if (item.length > 1)
+ addSelectValue(form, 'docencoding', item[0], item[1]);
+ }
+
+ // Setup color pickers
+ document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor');
+ document.getElementById('link_color_pickcontainer').innerHTML = getColorPickerHTML('link_color_pick','link_color');
+ document.getElementById('visited_color_pickcontainer').innerHTML = getColorPickerHTML('visited_color_pick','visited_color');
+ document.getElementById('active_color_pickcontainer').innerHTML = getColorPickerHTML('active_color_pick','active_color');
+ document.getElementById('textcolor_pickcontainer').innerHTML = getColorPickerHTML('textcolor_pick','textcolor');
+ document.getElementById('stylesheet_browsercontainer').innerHTML = getBrowserHTML('stylesheetbrowser','stylesheet','file','fullpage');
+ document.getElementById('bgimage_pickcontainer').innerHTML = getBrowserHTML('bgimage_browser','bgimage','image','fullpage');
+
+ // Resize some elements
+ if (isVisible('stylesheetbrowser'))
+ document.getElementById('stylesheet').style.width = '220px';
+
+ if (isVisible('link_href_browser'))
+ document.getElementById('element_link_href').style.width = '230px';
+
+ if (isVisible('bgimage_browser'))
+ document.getElementById('bgimage').style.width = '210px';
+
+ // Update form
+ tinymce.each(tinyMCEPopup.getWindowArg('data'), function(value, key) {
+ setVal(key, value);
+ });
+
+ FullPageDialog.changedStyle();
+
+ // Update colors
+ updateColor('textcolor_pick', 'textcolor');
+ updateColor('bgcolor_pick', 'bgcolor');
+ updateColor('visited_color_pick', 'visited_color');
+ updateColor('active_color_pick', 'active_color');
+ updateColor('link_color_pick', 'link_color');
+ };
+
+ tinyMCEPopup.onInit.add(init);
+})();
diff --git a/askbot/media/js/tinymce/plugins/fullpage/langs/en_dlg.js b/askbot/media/js/tinymce/plugins/fullpage/langs/en_dlg.js
new file mode 100644
index 00000000..516edc74
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/fullpage/langs/en_dlg.js
@@ -0,0 +1 @@
+tinyMCE.addI18n('en.fullpage_dlg',{title:"Document Properties","meta_tab":"General","appearance_tab":"Appearance","advanced_tab":"Advanced","meta_props":"Meta Information",langprops:"Language and Encoding","meta_title":"Title","meta_keywords":"Keywords","meta_description":"Description","meta_robots":"Robots",doctypes:"Doctype",langcode:"Language Code",langdir:"Language Direction",ltr:"Left to Right",rtl:"Right to Left","xml_pi":"XML Declaration",encoding:"Character Encoding","appearance_bgprops":"Background Properties","appearance_marginprops":"Body Margins","appearance_linkprops":"Link Colors","appearance_textprops":"Text Properties",bgcolor:"Background Color",bgimage:"Background Image","left_margin":"Left Margin","right_margin":"Right Margin","top_margin":"Top Margin","bottom_margin":"Bottom Margin","text_color":"Text Color","font_size":"Font Size","font_face":"Font Face","link_color":"Link Color","hover_color":"Hover Color","visited_color":"Visited Color","active_color":"Active Color",textcolor:"Color",fontsize:"Font Size",fontface:"Font Family","meta_index_follow":"Index and Follow the Links","meta_index_nofollow":"Index and Don\'t Follow the Links","meta_noindex_follow":"Do Not Index but Follow the Links","meta_noindex_nofollow":"Do Not Index and Don\'t Follow the Links","appearance_style":"Stylesheet and Style Properties",stylesheet:"Stylesheet",style:"Style",author:"Author",copyright:"Copyright",add:"Add New Element",remove:"Remove Selected Element",moveup:"Move Selected Element Up",movedown:"Move Selected Element Down","head_elements":"Head Elements",info:"Information","add_title":"Title Element","add_meta":"Meta Element","add_script":"Script Element","add_style":"Style Element","add_link":"Link Element","add_base":"Base Element","add_comment":"Comment Node","title_element":"Title Element","script_element":"Script Element","style_element":"Style Element","base_element":"Base Element","link_element":"Link Element","meta_element":"Meta Element","comment_element":"Comment",src:"Source",language:"Language",href:"HREF",target:"Target",type:"Type",charset:"Charset",defer:"Defer",media:"Media",properties:"Properties",name:"Name",value:"Value",content:"Content",rel:"Rel",rev:"Rev",hreflang:"HREF Lang","general_props":"General","advanced_props":"Advanced"}); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/fullscreen/editor_plugin.js b/askbot/media/js/tinymce/plugins/fullscreen/editor_plugin.js
new file mode 100644
index 00000000..7b65e733
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/fullscreen/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var a=tinymce.DOM;tinymce.create("tinymce.plugins.FullScreenPlugin",{init:function(d,e){var f=this,g={},c,b;f.editor=d;d.addCommand("mceFullScreen",function(){var i,j=a.doc.documentElement;if(d.getParam("fullscreen_is_enabled")){if(d.getParam("fullscreen_new_window")){closeFullscreen()}else{a.win.setTimeout(function(){tinymce.dom.Event.remove(a.win,"resize",f.resizeFunc);tinyMCE.get(d.getParam("fullscreen_editor_id")).setContent(d.getContent());tinyMCE.remove(d);a.remove("mce_fullscreen_container");j.style.overflow=d.getParam("fullscreen_html_overflow");a.setStyle(a.doc.body,"overflow",d.getParam("fullscreen_overflow"));a.win.scrollTo(d.getParam("fullscreen_scrollx"),d.getParam("fullscreen_scrolly"));tinyMCE.settings=tinyMCE.oldSettings},10)}return}if(d.getParam("fullscreen_new_window")){i=a.win.open(e+"/fullscreen.htm","mceFullScreenPopup","fullscreen=yes,menubar=no,toolbar=no,scrollbars=no,resizable=yes,left=0,top=0,width="+screen.availWidth+",height="+screen.availHeight);try{i.resizeTo(screen.availWidth,screen.availHeight)}catch(h){}}else{tinyMCE.oldSettings=tinyMCE.settings;g.fullscreen_overflow=a.getStyle(a.doc.body,"overflow",1)||"auto";g.fullscreen_html_overflow=a.getStyle(j,"overflow",1);c=a.getViewPort();g.fullscreen_scrollx=c.x;g.fullscreen_scrolly=c.y;if(tinymce.isOpera&&g.fullscreen_overflow=="visible"){g.fullscreen_overflow="auto"}if(tinymce.isIE&&g.fullscreen_overflow=="scroll"){g.fullscreen_overflow="auto"}if(tinymce.isIE&&(g.fullscreen_html_overflow=="visible"||g.fullscreen_html_overflow=="scroll")){g.fullscreen_html_overflow="auto"}if(g.fullscreen_overflow=="0px"){g.fullscreen_overflow=""}a.setStyle(a.doc.body,"overflow","hidden");j.style.overflow="hidden";c=a.getViewPort();a.win.scrollTo(0,0);if(tinymce.isIE){c.h-=1}if(tinymce.isIE6||document.compatMode=="BackCompat"){b="absolute;top:"+c.y}else{b="fixed;top:0"}n=a.add(a.doc.body,"div",{id:"mce_fullscreen_container",style:"position:"+b+";left:0;width:"+c.w+"px;height:"+c.h+"px;z-index:200000;"});a.add(n,"div",{id:"mce_fullscreen"});tinymce.each(d.settings,function(k,l){g[l]=k});g.id="mce_fullscreen";g.width=n.clientWidth;g.height=n.clientHeight-15;g.fullscreen_is_enabled=true;g.fullscreen_editor_id=d.id;g.theme_advanced_resizing=false;g.save_onsavecallback=function(){d.setContent(tinyMCE.get(g.id).getContent());d.execCommand("mceSave")};tinymce.each(d.getParam("fullscreen_settings"),function(m,l){g[l]=m});if(g.theme_advanced_toolbar_location==="external"){g.theme_advanced_toolbar_location="top"}f.fullscreenEditor=new tinymce.Editor("mce_fullscreen",g);f.fullscreenEditor.onInit.add(function(){f.fullscreenEditor.setContent(d.getContent());f.fullscreenEditor.focus()});f.fullscreenEditor.render();f.fullscreenElement=new tinymce.dom.Element("mce_fullscreen_container");f.fullscreenElement.update();f.resizeFunc=tinymce.dom.Event.add(a.win,"resize",function(){var o=tinymce.DOM.getViewPort(),l=f.fullscreenEditor,k,m;k=l.dom.getSize(l.getContainer().firstChild);m=l.dom.getSize(l.getContainer().getElementsByTagName("iframe")[0]);l.theme.resizeTo(o.w-k.w+m.w,o.h-k.h+m.h)})}});d.addButton("fullscreen",{title:"fullscreen.desc",cmd:"mceFullScreen"});d.onNodeChange.add(function(i,h){h.setActive("fullscreen",i.getParam("fullscreen_is_enabled"))})},getInfo:function(){return{longname:"Fullscreen",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullscreen",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("fullscreen",tinymce.plugins.FullScreenPlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/fullscreen/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/fullscreen/editor_plugin_src.js
new file mode 100644
index 00000000..6622f924
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/fullscreen/editor_plugin_src.js
@@ -0,0 +1,159 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var DOM = tinymce.DOM;
+
+ tinymce.create('tinymce.plugins.FullScreenPlugin', {
+ init : function(ed, url) {
+ var t = this, s = {}, vp, posCss;
+
+ t.editor = ed;
+
+ // Register commands
+ ed.addCommand('mceFullScreen', function() {
+ var win, de = DOM.doc.documentElement;
+
+ if (ed.getParam('fullscreen_is_enabled')) {
+ if (ed.getParam('fullscreen_new_window'))
+ closeFullscreen(); // Call to close in new window
+ else {
+ DOM.win.setTimeout(function() {
+ tinymce.dom.Event.remove(DOM.win, 'resize', t.resizeFunc);
+ tinyMCE.get(ed.getParam('fullscreen_editor_id')).setContent(ed.getContent());
+ tinyMCE.remove(ed);
+ DOM.remove('mce_fullscreen_container');
+ de.style.overflow = ed.getParam('fullscreen_html_overflow');
+ DOM.setStyle(DOM.doc.body, 'overflow', ed.getParam('fullscreen_overflow'));
+ DOM.win.scrollTo(ed.getParam('fullscreen_scrollx'), ed.getParam('fullscreen_scrolly'));
+ tinyMCE.settings = tinyMCE.oldSettings; // Restore old settings
+ }, 10);
+ }
+
+ return;
+ }
+
+ if (ed.getParam('fullscreen_new_window')) {
+ win = DOM.win.open(url + "/fullscreen.htm", "mceFullScreenPopup", "fullscreen=yes,menubar=no,toolbar=no,scrollbars=no,resizable=yes,left=0,top=0,width=" + screen.availWidth + ",height=" + screen.availHeight);
+ try {
+ win.resizeTo(screen.availWidth, screen.availHeight);
+ } catch (e) {
+ // Ignore
+ }
+ } else {
+ tinyMCE.oldSettings = tinyMCE.settings; // Store old settings
+ s.fullscreen_overflow = DOM.getStyle(DOM.doc.body, 'overflow', 1) || 'auto';
+ s.fullscreen_html_overflow = DOM.getStyle(de, 'overflow', 1);
+ vp = DOM.getViewPort();
+ s.fullscreen_scrollx = vp.x;
+ s.fullscreen_scrolly = vp.y;
+
+ // Fixes an Opera bug where the scrollbars doesn't reappear
+ if (tinymce.isOpera && s.fullscreen_overflow == 'visible')
+ s.fullscreen_overflow = 'auto';
+
+ // Fixes an IE bug where horizontal scrollbars would appear
+ if (tinymce.isIE && s.fullscreen_overflow == 'scroll')
+ s.fullscreen_overflow = 'auto';
+
+ // Fixes an IE bug where the scrollbars doesn't reappear
+ if (tinymce.isIE && (s.fullscreen_html_overflow == 'visible' || s.fullscreen_html_overflow == 'scroll'))
+ s.fullscreen_html_overflow = 'auto';
+
+ if (s.fullscreen_overflow == '0px')
+ s.fullscreen_overflow = '';
+
+ DOM.setStyle(DOM.doc.body, 'overflow', 'hidden');
+ de.style.overflow = 'hidden'; //Fix for IE6/7
+ vp = DOM.getViewPort();
+ DOM.win.scrollTo(0, 0);
+
+ if (tinymce.isIE)
+ vp.h -= 1;
+
+ // Use fixed position if it exists
+ if (tinymce.isIE6 || document.compatMode == 'BackCompat')
+ posCss = 'absolute;top:' + vp.y;
+ else
+ posCss = 'fixed;top:0';
+
+ n = DOM.add(DOM.doc.body, 'div', {
+ id : 'mce_fullscreen_container',
+ style : 'position:' + posCss + ';left:0;width:' + vp.w + 'px;height:' + vp.h + 'px;z-index:200000;'});
+ DOM.add(n, 'div', {id : 'mce_fullscreen'});
+
+ tinymce.each(ed.settings, function(v, n) {
+ s[n] = v;
+ });
+
+ s.id = 'mce_fullscreen';
+ s.width = n.clientWidth;
+ s.height = n.clientHeight - 15;
+ s.fullscreen_is_enabled = true;
+ s.fullscreen_editor_id = ed.id;
+ s.theme_advanced_resizing = false;
+ s.save_onsavecallback = function() {
+ ed.setContent(tinyMCE.get(s.id).getContent());
+ ed.execCommand('mceSave');
+ };
+
+ tinymce.each(ed.getParam('fullscreen_settings'), function(v, k) {
+ s[k] = v;
+ });
+
+ if (s.theme_advanced_toolbar_location === 'external')
+ s.theme_advanced_toolbar_location = 'top';
+
+ t.fullscreenEditor = new tinymce.Editor('mce_fullscreen', s);
+ t.fullscreenEditor.onInit.add(function() {
+ t.fullscreenEditor.setContent(ed.getContent());
+ t.fullscreenEditor.focus();
+ });
+
+ t.fullscreenEditor.render();
+
+ t.fullscreenElement = new tinymce.dom.Element('mce_fullscreen_container');
+ t.fullscreenElement.update();
+ //document.body.overflow = 'hidden';
+
+ t.resizeFunc = tinymce.dom.Event.add(DOM.win, 'resize', function() {
+ var vp = tinymce.DOM.getViewPort(), fed = t.fullscreenEditor, outerSize, innerSize;
+
+ // Get outer/inner size to get a delta size that can be used to calc the new iframe size
+ outerSize = fed.dom.getSize(fed.getContainer().firstChild);
+ innerSize = fed.dom.getSize(fed.getContainer().getElementsByTagName('iframe')[0]);
+
+ fed.theme.resizeTo(vp.w - outerSize.w + innerSize.w, vp.h - outerSize.h + innerSize.h);
+ });
+ }
+ });
+
+ // Register buttons
+ ed.addButton('fullscreen', {title : 'fullscreen.desc', cmd : 'mceFullScreen'});
+
+ ed.onNodeChange.add(function(ed, cm) {
+ cm.setActive('fullscreen', ed.getParam('fullscreen_is_enabled'));
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Fullscreen',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/fullscreen',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('fullscreen', tinymce.plugins.FullScreenPlugin);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/fullscreen/fullscreen.htm b/askbot/media/js/tinymce/plugins/fullscreen/fullscreen.htm
new file mode 100644
index 00000000..ffe528e4
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/fullscreen/fullscreen.htm
@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title></title>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+ <script type="text/javascript" src="../../tiny_mce.js"></script>
+ <script type="text/javascript">
+ function patchCallback(settings, key) {
+ if (settings[key])
+ settings[key] = "window.opener." + settings[key];
+ }
+
+ var settings = {}, paSe = window.opener.tinyMCE.activeEditor.settings, oeID = window.opener.tinyMCE.activeEditor.id;
+
+ // Clone array
+ for (var n in paSe)
+ settings[n] = paSe[n];
+
+ // Override options for fullscreen
+ for (var n in paSe.fullscreen_settings)
+ settings[n] = paSe.fullscreen_settings[n];
+
+ // Patch callbacks, make them point to window.opener
+ patchCallback(settings, 'urlconverter_callback');
+ patchCallback(settings, 'insertlink_callback');
+ patchCallback(settings, 'insertimage_callback');
+ patchCallback(settings, 'setupcontent_callback');
+ patchCallback(settings, 'save_callback');
+ patchCallback(settings, 'onchange_callback');
+ patchCallback(settings, 'init_instance_callback');
+ patchCallback(settings, 'file_browser_callback');
+ patchCallback(settings, 'cleanup_callback');
+ patchCallback(settings, 'execcommand_callback');
+ patchCallback(settings, 'oninit');
+
+ // Set options
+ delete settings.id;
+ settings['mode'] = 'exact';
+ settings['elements'] = 'fullscreenarea';
+ settings['add_unload_trigger'] = false;
+ settings['ask'] = false;
+ settings['document_base_url'] = window.opener.tinyMCE.activeEditor.documentBaseURI.getURI();
+ settings['fullscreen_is_enabled'] = true;
+ settings['fullscreen_editor_id'] = oeID;
+ settings['theme_advanced_resizing'] = false;
+ settings['strict_loading_mode'] = true;
+
+ settings.save_onsavecallback = function() {
+ window.opener.tinyMCE.get(oeID).setContent(tinyMCE.get('fullscreenarea').getContent({format : 'raw'}), {format : 'raw'});
+ window.opener.tinyMCE.get(oeID).execCommand('mceSave');
+ window.close();
+ };
+
+ function unloadHandler(e) {
+ moveContent();
+ }
+
+ function moveContent() {
+ window.opener.tinyMCE.get(oeID).setContent(tinyMCE.activeEditor.getContent());
+ }
+
+ function closeFullscreen() {
+ moveContent();
+ window.close();
+ }
+
+ function doParentSubmit() {
+ moveContent();
+
+ if (window.opener.tinyMCE.selectedInstance.formElement.form)
+ window.opener.tinyMCE.selectedInstance.formElement.form.submit();
+
+ window.close();
+
+ return false;
+ }
+
+ function render() {
+ var e = document.getElementById('fullscreenarea'), vp, ed, ow, oh, dom = tinymce.DOM;
+
+ e.value = window.opener.tinyMCE.get(oeID).getContent();
+
+ vp = dom.getViewPort();
+ settings.width = vp.w;
+ settings.height = vp.h - 15;
+
+ tinymce.dom.Event.add(window, 'resize', function() {
+ var vp = dom.getViewPort();
+
+ tinyMCE.activeEditor.theme.resizeTo(vp.w, vp.h);
+ });
+
+ tinyMCE.init(settings);
+ }
+
+ // Add onunload
+ tinymce.dom.Event.add(window, "beforeunload", unloadHandler);
+ </script>
+</head>
+<body style="margin:0;overflow:hidden;width:100%;height:100%" scrolling="no" scroll="no">
+<form onsubmit="doParentSubmit();">
+<textarea id="fullscreenarea" style="width:100%; height:100%"></textarea>
+</form>
+
+<script type="text/javascript">
+ render();
+</script>
+
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/iespell/editor_plugin.js b/askbot/media/js/tinymce/plugins/iespell/editor_plugin.js
new file mode 100644
index 00000000..e9cba106
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/iespell/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.IESpell",{init:function(a,b){var c=this,d;if(!tinymce.isIE){return}c.editor=a;a.addCommand("mceIESpell",function(){try{d=new ActiveXObject("ieSpell.ieSpellExtension");d.CheckDocumentNode(a.getDoc().documentElement)}catch(f){if(f.number==-2146827859){a.windowManager.confirm(a.getLang("iespell.download"),function(e){if(e){window.open("http://www.iespell.com/download.php","ieSpellDownload","")}})}else{a.windowManager.alert("Error Loading ieSpell: Exception "+f.number)}}});a.addButton("iespell",{title:"iespell.iespell_desc",cmd:"mceIESpell"})},getInfo:function(){return{longname:"IESpell (IE Only)",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/iespell",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("iespell",tinymce.plugins.IESpell)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/iespell/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/iespell/editor_plugin_src.js
new file mode 100644
index 00000000..1b2bb984
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/iespell/editor_plugin_src.js
@@ -0,0 +1,54 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.IESpell', {
+ init : function(ed, url) {
+ var t = this, sp;
+
+ if (!tinymce.isIE)
+ return;
+
+ t.editor = ed;
+
+ // Register commands
+ ed.addCommand('mceIESpell', function() {
+ try {
+ sp = new ActiveXObject("ieSpell.ieSpellExtension");
+ sp.CheckDocumentNode(ed.getDoc().documentElement);
+ } catch (e) {
+ if (e.number == -2146827859) {
+ ed.windowManager.confirm(ed.getLang("iespell.download"), function(s) {
+ if (s)
+ window.open('http://www.iespell.com/download.php', 'ieSpellDownload', '');
+ });
+ } else
+ ed.windowManager.alert("Error Loading ieSpell: Exception " + e.number);
+ }
+ });
+
+ // Register buttons
+ ed.addButton('iespell', {title : 'iespell.iespell_desc', cmd : 'mceIESpell'});
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'IESpell (IE Only)',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/iespell',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('iespell', tinymce.plugins.IESpell);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/inlinepopups/editor_plugin.js b/askbot/media/js/tinymce/plugins/inlinepopups/editor_plugin.js
new file mode 100644
index 00000000..8bb96f9c
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/inlinepopups/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var d=tinymce.DOM,b=tinymce.dom.Element,a=tinymce.dom.Event,e=tinymce.each,c=tinymce.is;tinymce.create("tinymce.plugins.InlinePopups",{init:function(f,g){f.onBeforeRenderUI.add(function(){f.windowManager=new tinymce.InlineWindowManager(f);d.loadCSS(g+"/skins/"+(f.settings.inlinepopups_skin||"clearlooks2")+"/window.css")})},getInfo:function(){return{longname:"InlinePopups",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/inlinepopups",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.create("tinymce.InlineWindowManager:tinymce.WindowManager",{InlineWindowManager:function(f){var g=this;g.parent(f);g.zIndex=300000;g.count=0;g.windows={}},open:function(s,j){var z=this,i,k="",r=z.editor,g=0,v=0,h,m,o,q,l,x,y,n;s=s||{};j=j||{};if(!s.inline){return z.parent(s,j)}n=z._frontWindow();if(n&&d.get(n.id+"_ifr")){n.focussedElement=d.get(n.id+"_ifr").contentWindow.document.activeElement}if(!s.type){z.bookmark=r.selection.getBookmark(1)}i=d.uniqueId();h=d.getViewPort();s.width=parseInt(s.width||320);s.height=parseInt(s.height||240)+(tinymce.isIE?8:0);s.min_width=parseInt(s.min_width||150);s.min_height=parseInt(s.min_height||100);s.max_width=parseInt(s.max_width||2000);s.max_height=parseInt(s.max_height||2000);s.left=s.left||Math.round(Math.max(h.x,h.x+(h.w/2)-(s.width/2)));s.top=s.top||Math.round(Math.max(h.y,h.y+(h.h/2)-(s.height/2)));s.movable=s.resizable=true;j.mce_width=s.width;j.mce_height=s.height;j.mce_inline=true;j.mce_window_id=i;j.mce_auto_focus=s.auto_focus;z.features=s;z.params=j;z.onOpen.dispatch(z,s,j);if(s.type){k+=" mceModal";if(s.type){k+=" mce"+s.type.substring(0,1).toUpperCase()+s.type.substring(1)}s.resizable=false}if(s.statusbar){k+=" mceStatusbar"}if(s.resizable){k+=" mceResizable"}if(s.minimizable){k+=" mceMinimizable"}if(s.maximizable){k+=" mceMaximizable"}if(s.movable){k+=" mceMovable"}z._addAll(d.doc.body,["div",{id:i,role:"dialog","aria-labelledby":s.type?i+"_content":i+"_title","class":(r.settings.inlinepopups_skin||"clearlooks2")+(tinymce.isIE&&window.getSelection?" ie9":""),style:"width:100px;height:100px"},["div",{id:i+"_wrapper","class":"mceWrapper"+k},["div",{id:i+"_top","class":"mceTop"},["div",{"class":"mceLeft"}],["div",{"class":"mceCenter"}],["div",{"class":"mceRight"}],["span",{id:i+"_title"},s.title||""]],["div",{id:i+"_middle","class":"mceMiddle"},["div",{id:i+"_left","class":"mceLeft",tabindex:"0"}],["span",{id:i+"_content"}],["div",{id:i+"_right","class":"mceRight",tabindex:"0"}]],["div",{id:i+"_bottom","class":"mceBottom"},["div",{"class":"mceLeft"}],["div",{"class":"mceCenter"}],["div",{"class":"mceRight"}],["span",{id:i+"_status"},"Content"]],["a",{"class":"mceMove",tabindex:"-1",href:"javascript:;"}],["a",{"class":"mceMin",tabindex:"-1",href:"javascript:;",onmousedown:"return false;"}],["a",{"class":"mceMax",tabindex:"-1",href:"javascript:;",onmousedown:"return false;"}],["a",{"class":"mceMed",tabindex:"-1",href:"javascript:;",onmousedown:"return false;"}],["a",{"class":"mceClose",tabindex:"-1",href:"javascript:;",onmousedown:"return false;"}],["a",{id:i+"_resize_n","class":"mceResize mceResizeN",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_s","class":"mceResize mceResizeS",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_w","class":"mceResize mceResizeW",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_e","class":"mceResize mceResizeE",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_nw","class":"mceResize mceResizeNW",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_ne","class":"mceResize mceResizeNE",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_sw","class":"mceResize mceResizeSW",tabindex:"-1",href:"javascript:;"}],["a",{id:i+"_resize_se","class":"mceResize mceResizeSE",tabindex:"-1",href:"javascript:;"}]]]);d.setStyles(i,{top:-10000,left:-10000});if(tinymce.isGecko){d.setStyle(i,"overflow","auto")}if(!s.type){g+=d.get(i+"_left").clientWidth;g+=d.get(i+"_right").clientWidth;v+=d.get(i+"_top").clientHeight;v+=d.get(i+"_bottom").clientHeight}d.setStyles(i,{top:s.top,left:s.left,width:s.width+g,height:s.height+v});y=s.url||s.file;if(y){if(tinymce.relaxedDomain){y+=(y.indexOf("?")==-1?"?":"&")+"mce_rdomain="+tinymce.relaxedDomain}y=tinymce._addVer(y)}if(!s.type){d.add(i+"_content","iframe",{id:i+"_ifr",src:'javascript:""',frameBorder:0,style:"border:0;width:10px;height:10px"});d.setStyles(i+"_ifr",{width:s.width,height:s.height});d.setAttrib(i+"_ifr","src",y)}else{d.add(i+"_wrapper","a",{id:i+"_ok","class":"mceButton mceOk",href:"javascript:;",onmousedown:"return false;"},"Ok");if(s.type=="confirm"){d.add(i+"_wrapper","a",{"class":"mceButton mceCancel",href:"javascript:;",onmousedown:"return false;"},"Cancel")}d.add(i+"_middle","div",{"class":"mceIcon"});d.setHTML(i+"_content",s.content.replace("\n","<br />"));a.add(i,"keyup",function(f){var p=27;if(f.keyCode===p){s.button_func(false);return a.cancel(f)}});a.add(i,"keydown",function(f){var t,p=9;if(f.keyCode===p){t=d.select("a.mceCancel",i+"_wrapper")[0];if(t&&t!==f.target){t.focus()}else{d.get(i+"_ok").focus()}return a.cancel(f)}})}o=a.add(i,"mousedown",function(t){var u=t.target,f,p;f=z.windows[i];z.focus(i);if(u.nodeName=="A"||u.nodeName=="a"){if(u.className=="mceClose"){z.close(null,i);return a.cancel(t)}else{if(u.className=="mceMax"){f.oldPos=f.element.getXY();f.oldSize=f.element.getSize();p=d.getViewPort();p.w-=2;p.h-=2;f.element.moveTo(p.x,p.y);f.element.resizeTo(p.w,p.h);d.setStyles(i+"_ifr",{width:p.w-f.deltaWidth,height:p.h-f.deltaHeight});d.addClass(i+"_wrapper","mceMaximized")}else{if(u.className=="mceMed"){f.element.moveTo(f.oldPos.x,f.oldPos.y);f.element.resizeTo(f.oldSize.w,f.oldSize.h);f.iframeElement.resizeTo(f.oldSize.w-f.deltaWidth,f.oldSize.h-f.deltaHeight);d.removeClass(i+"_wrapper","mceMaximized")}else{if(u.className=="mceMove"){return z._startDrag(i,t,u.className)}else{if(d.hasClass(u,"mceResize")){return z._startDrag(i,t,u.className.substring(13))}}}}}}});q=a.add(i,"click",function(f){var p=f.target;z.focus(i);if(p.nodeName=="A"||p.nodeName=="a"){switch(p.className){case"mceClose":z.close(null,i);return a.cancel(f);case"mceButton mceOk":case"mceButton mceCancel":s.button_func(p.className=="mceButton mceOk");return a.cancel(f)}}});a.add([i+"_left",i+"_right"],"focus",function(p){var t=d.get(i+"_ifr");if(t){var f=t.contentWindow.document.body;var u=d.select(":input:enabled,*[tabindex=0]",f);if(p.target.id===(i+"_left")){u[u.length-1].focus()}else{u[0].focus()}}else{d.get(i+"_ok").focus()}});x=z.windows[i]={id:i,mousedown_func:o,click_func:q,element:new b(i,{blocker:1,container:r.getContainer()}),iframeElement:new b(i+"_ifr"),features:s,deltaWidth:g,deltaHeight:v};x.iframeElement.on("focus",function(){z.focus(i)});if(z.count==0&&z.editor.getParam("dialog_type","modal")=="modal"){d.add(d.doc.body,"div",{id:"mceModalBlocker","class":(z.editor.settings.inlinepopups_skin||"clearlooks2")+"_modalBlocker",style:{zIndex:z.zIndex-1}});d.show("mceModalBlocker");d.setAttrib(d.doc.body,"aria-hidden","true")}else{d.setStyle("mceModalBlocker","z-index",z.zIndex-1)}if(tinymce.isIE6||/Firefox\/2\./.test(navigator.userAgent)||(tinymce.isIE&&!d.boxModel)){d.setStyles("mceModalBlocker",{position:"absolute",left:h.x,top:h.y,width:h.w-2,height:h.h-2})}d.setAttrib(i,"aria-hidden","false");z.focus(i);z._fixIELayout(i,1);if(d.get(i+"_ok")){d.get(i+"_ok").focus()}z.count++;return x},focus:function(h){var g=this,f;if(f=g.windows[h]){f.zIndex=this.zIndex++;f.element.setStyle("zIndex",f.zIndex);f.element.update();h=h+"_wrapper";d.removeClass(g.lastId,"mceFocus");d.addClass(h,"mceFocus");g.lastId=h;if(f.focussedElement){f.focussedElement.focus()}else{if(d.get(h+"_ok")){d.get(f.id+"_ok").focus()}else{if(d.get(f.id+"_ifr")){d.get(f.id+"_ifr").focus()}}}}},_addAll:function(k,h){var g,l,f=this,j=tinymce.DOM;if(c(h,"string")){k.appendChild(j.doc.createTextNode(h))}else{if(h.length){k=k.appendChild(j.create(h[0],h[1]));for(g=2;g<h.length;g++){f._addAll(k,h[g])}}}},_startDrag:function(v,G,E){var o=this,u,z,C=d.doc,f,l=o.windows[v],h=l.element,y=h.getXY(),x,q,F,g,A,s,r,j,i,m,k,n,B;g={x:0,y:0};A=d.getViewPort();A.w-=2;A.h-=2;j=G.screenX;i=G.screenY;m=k=n=B=0;u=a.add(C,"mouseup",function(p){a.remove(C,"mouseup",u);a.remove(C,"mousemove",z);if(f){f.remove()}h.moveBy(m,k);h.resizeBy(n,B);q=h.getSize();d.setStyles(v+"_ifr",{width:q.w-l.deltaWidth,height:q.h-l.deltaHeight});o._fixIELayout(v,1);return a.cancel(p)});if(E!="Move"){D()}function D(){if(f){return}o._fixIELayout(v,0);d.add(C.body,"div",{id:"mceEventBlocker","class":"mceEventBlocker "+(o.editor.settings.inlinepopups_skin||"clearlooks2"),style:{zIndex:o.zIndex+1}});if(tinymce.isIE6||(tinymce.isIE&&!d.boxModel)){d.setStyles("mceEventBlocker",{position:"absolute",left:A.x,top:A.y,width:A.w-2,height:A.h-2})}f=new b("mceEventBlocker");f.update();x=h.getXY();q=h.getSize();s=g.x+x.x-A.x;r=g.y+x.y-A.y;d.add(f.get(),"div",{id:"mcePlaceHolder","class":"mcePlaceHolder",style:{left:s,top:r,width:q.w,height:q.h}});F=new b("mcePlaceHolder")}z=a.add(C,"mousemove",function(w){var p,H,t;D();p=w.screenX-j;H=w.screenY-i;switch(E){case"ResizeW":m=p;n=0-p;break;case"ResizeE":n=p;break;case"ResizeN":case"ResizeNW":case"ResizeNE":if(E=="ResizeNW"){m=p;n=0-p}else{if(E=="ResizeNE"){n=p}}k=H;B=0-H;break;case"ResizeS":case"ResizeSW":case"ResizeSE":if(E=="ResizeSW"){m=p;n=0-p}else{if(E=="ResizeSE"){n=p}}B=H;break;case"mceMove":m=p;k=H;break}if(n<(t=l.features.min_width-q.w)){if(m!==0){m+=n-t}n=t}if(B<(t=l.features.min_height-q.h)){if(k!==0){k+=B-t}B=t}n=Math.min(n,l.features.max_width-q.w);B=Math.min(B,l.features.max_height-q.h);m=Math.max(m,A.x-(s+A.x));k=Math.max(k,A.y-(r+A.y));m=Math.min(m,(A.w+A.x)-(s+q.w+A.x));k=Math.min(k,(A.h+A.y)-(r+q.h+A.y));if(m+k!==0){if(s+m<0){m=0}if(r+k<0){k=0}F.moveTo(s+m,r+k)}if(n+B!==0){F.resizeTo(q.w+n,q.h+B)}return a.cancel(w)});return a.cancel(G)},resizeBy:function(g,h,i){var f=this.windows[i];if(f){f.element.resizeBy(g,h);f.iframeElement.resizeBy(g,h)}},close:function(i,k){var g=this,f,j=d.doc,h,k;k=g._findId(k||i);if(!g.windows[k]){g.parent(i);return}g.count--;if(g.count==0){d.remove("mceModalBlocker");d.setAttrib(d.doc.body,"aria-hidden","false");g.editor.focus()}if(f=g.windows[k]){g.onClose.dispatch(g);a.remove(j,"mousedown",f.mousedownFunc);a.remove(j,"click",f.clickFunc);a.clear(k);a.clear(k+"_ifr");d.setAttrib(k+"_ifr","src",'javascript:""');f.element.remove();delete g.windows[k];h=g._frontWindow();if(h){g.focus(h.id)}}},_frontWindow:function(){var g,f=0;e(this.windows,function(h){if(h.zIndex>f){g=h;f=h.zIndex}});return g},setTitle:function(f,g){var h;f=this._findId(f);if(h=d.get(f+"_title")){h.innerHTML=d.encode(g)}},alert:function(g,f,j){var i=this,h;h=i.open({title:i,type:"alert",button_func:function(k){if(f){f.call(k||i,k)}i.close(null,h.id)},content:d.encode(i.editor.getLang(g,g)),inline:1,width:400,height:130})},confirm:function(g,f,j){var i=this,h;h=i.open({title:i,type:"confirm",button_func:function(k){if(f){f.call(k||i,k)}i.close(null,h.id)},content:d.encode(i.editor.getLang(g,g)),inline:1,width:400,height:130})},_findId:function(f){var g=this;if(typeof(f)=="string"){return f}e(g.windows,function(h){var i=d.get(h.id+"_ifr");if(i&&f==i.contentWindow){f=h.id;return false}});return f},_fixIELayout:function(i,h){var f,g;if(!tinymce.isIE6){return}e(["n","s","w","e","nw","ne","sw","se"],function(j){var k=d.get(i+"_resize_"+j);d.setStyles(k,{width:h?k.clientWidth:"",height:h?k.clientHeight:"",cursor:d.getStyle(k,"cursor",1)});d.setStyle(i+"_bottom","bottom","-1px");k=0});if(f=this.windows[i]){f.element.hide();f.element.show();e(d.select("div,a",i),function(k,j){if(k.currentStyle.backgroundImage!="none"){g=new Image();g.src=k.currentStyle.backgroundImage.replace(/url\(\"(.+)\"\)/,"$1")}});d.get(i).style.filter=""}}});tinymce.PluginManager.add("inlinepopups",tinymce.plugins.InlinePopups)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/inlinepopups/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/inlinepopups/editor_plugin_src.js
new file mode 100644
index 00000000..67123ca3
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/inlinepopups/editor_plugin_src.js
@@ -0,0 +1,699 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var DOM = tinymce.DOM, Element = tinymce.dom.Element, Event = tinymce.dom.Event, each = tinymce.each, is = tinymce.is;
+
+ tinymce.create('tinymce.plugins.InlinePopups', {
+ init : function(ed, url) {
+ // Replace window manager
+ ed.onBeforeRenderUI.add(function() {
+ ed.windowManager = new tinymce.InlineWindowManager(ed);
+ DOM.loadCSS(url + '/skins/' + (ed.settings.inlinepopups_skin || 'clearlooks2') + "/window.css");
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'InlinePopups',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/inlinepopups',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ tinymce.create('tinymce.InlineWindowManager:tinymce.WindowManager', {
+ InlineWindowManager : function(ed) {
+ var t = this;
+
+ t.parent(ed);
+ t.zIndex = 300000;
+ t.count = 0;
+ t.windows = {};
+ },
+
+ open : function(f, p) {
+ var t = this, id, opt = '', ed = t.editor, dw = 0, dh = 0, vp, po, mdf, clf, we, w, u, parentWindow;
+
+ f = f || {};
+ p = p || {};
+
+ // Run native windows
+ if (!f.inline)
+ return t.parent(f, p);
+
+ parentWindow = t._frontWindow();
+ if (parentWindow && DOM.get(parentWindow.id + '_ifr')) {
+ parentWindow.focussedElement = DOM.get(parentWindow.id + '_ifr').contentWindow.document.activeElement;
+ }
+
+ // Only store selection if the type is a normal window
+ if (!f.type)
+ t.bookmark = ed.selection.getBookmark(1);
+
+ id = DOM.uniqueId();
+ vp = DOM.getViewPort();
+ f.width = parseInt(f.width || 320);
+ f.height = parseInt(f.height || 240) + (tinymce.isIE ? 8 : 0);
+ f.min_width = parseInt(f.min_width || 150);
+ f.min_height = parseInt(f.min_height || 100);
+ f.max_width = parseInt(f.max_width || 2000);
+ f.max_height = parseInt(f.max_height || 2000);
+ f.left = f.left || Math.round(Math.max(vp.x, vp.x + (vp.w / 2.0) - (f.width / 2.0)));
+ f.top = f.top || Math.round(Math.max(vp.y, vp.y + (vp.h / 2.0) - (f.height / 2.0)));
+ f.movable = f.resizable = true;
+ p.mce_width = f.width;
+ p.mce_height = f.height;
+ p.mce_inline = true;
+ p.mce_window_id = id;
+ p.mce_auto_focus = f.auto_focus;
+
+ // Transpose
+// po = DOM.getPos(ed.getContainer());
+// f.left -= po.x;
+// f.top -= po.y;
+
+ t.features = f;
+ t.params = p;
+ t.onOpen.dispatch(t, f, p);
+
+ if (f.type) {
+ opt += ' mceModal';
+
+ if (f.type)
+ opt += ' mce' + f.type.substring(0, 1).toUpperCase() + f.type.substring(1);
+
+ f.resizable = false;
+ }
+
+ if (f.statusbar)
+ opt += ' mceStatusbar';
+
+ if (f.resizable)
+ opt += ' mceResizable';
+
+ if (f.minimizable)
+ opt += ' mceMinimizable';
+
+ if (f.maximizable)
+ opt += ' mceMaximizable';
+
+ if (f.movable)
+ opt += ' mceMovable';
+
+ // Create DOM objects
+ t._addAll(DOM.doc.body,
+ ['div', {id : id, role : 'dialog', 'aria-labelledby': f.type ? id + '_content' : id + '_title', 'class' : (ed.settings.inlinepopups_skin || 'clearlooks2') + (tinymce.isIE && window.getSelection ? ' ie9' : ''), style : 'width:100px;height:100px'},
+ ['div', {id : id + '_wrapper', 'class' : 'mceWrapper' + opt},
+ ['div', {id : id + '_top', 'class' : 'mceTop'},
+ ['div', {'class' : 'mceLeft'}],
+ ['div', {'class' : 'mceCenter'}],
+ ['div', {'class' : 'mceRight'}],
+ ['span', {id : id + '_title'}, f.title || '']
+ ],
+
+ ['div', {id : id + '_middle', 'class' : 'mceMiddle'},
+ ['div', {id : id + '_left', 'class' : 'mceLeft', tabindex : '0'}],
+ ['span', {id : id + '_content'}],
+ ['div', {id : id + '_right', 'class' : 'mceRight', tabindex : '0'}]
+ ],
+
+ ['div', {id : id + '_bottom', 'class' : 'mceBottom'},
+ ['div', {'class' : 'mceLeft'}],
+ ['div', {'class' : 'mceCenter'}],
+ ['div', {'class' : 'mceRight'}],
+ ['span', {id : id + '_status'}, 'Content']
+ ],
+
+ ['a', {'class' : 'mceMove', tabindex : '-1', href : 'javascript:;'}],
+ ['a', {'class' : 'mceMin', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}],
+ ['a', {'class' : 'mceMax', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}],
+ ['a', {'class' : 'mceMed', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}],
+ ['a', {'class' : 'mceClose', tabindex : '-1', href : 'javascript:;', onmousedown : 'return false;'}],
+ ['a', {id : id + '_resize_n', 'class' : 'mceResize mceResizeN', tabindex : '-1', href : 'javascript:;'}],
+ ['a', {id : id + '_resize_s', 'class' : 'mceResize mceResizeS', tabindex : '-1', href : 'javascript:;'}],
+ ['a', {id : id + '_resize_w', 'class' : 'mceResize mceResizeW', tabindex : '-1', href : 'javascript:;'}],
+ ['a', {id : id + '_resize_e', 'class' : 'mceResize mceResizeE', tabindex : '-1', href : 'javascript:;'}],
+ ['a', {id : id + '_resize_nw', 'class' : 'mceResize mceResizeNW', tabindex : '-1', href : 'javascript:;'}],
+ ['a', {id : id + '_resize_ne', 'class' : 'mceResize mceResizeNE', tabindex : '-1', href : 'javascript:;'}],
+ ['a', {id : id + '_resize_sw', 'class' : 'mceResize mceResizeSW', tabindex : '-1', href : 'javascript:;'}],
+ ['a', {id : id + '_resize_se', 'class' : 'mceResize mceResizeSE', tabindex : '-1', href : 'javascript:;'}]
+ ]
+ ]
+ );
+
+ DOM.setStyles(id, {top : -10000, left : -10000});
+
+ // Fix gecko rendering bug, where the editors iframe messed with window contents
+ if (tinymce.isGecko)
+ DOM.setStyle(id, 'overflow', 'auto');
+
+ // Measure borders
+ if (!f.type) {
+ dw += DOM.get(id + '_left').clientWidth;
+ dw += DOM.get(id + '_right').clientWidth;
+ dh += DOM.get(id + '_top').clientHeight;
+ dh += DOM.get(id + '_bottom').clientHeight;
+ }
+
+ // Resize window
+ DOM.setStyles(id, {top : f.top, left : f.left, width : f.width + dw, height : f.height + dh});
+
+ u = f.url || f.file;
+ if (u) {
+ if (tinymce.relaxedDomain)
+ u += (u.indexOf('?') == -1 ? '?' : '&') + 'mce_rdomain=' + tinymce.relaxedDomain;
+
+ u = tinymce._addVer(u);
+ }
+
+ if (!f.type) {
+ DOM.add(id + '_content', 'iframe', {id : id + '_ifr', src : 'javascript:""', frameBorder : 0, style : 'border:0;width:10px;height:10px'});
+ DOM.setStyles(id + '_ifr', {width : f.width, height : f.height});
+ DOM.setAttrib(id + '_ifr', 'src', u);
+ } else {
+ DOM.add(id + '_wrapper', 'a', {id : id + '_ok', 'class' : 'mceButton mceOk', href : 'javascript:;', onmousedown : 'return false;'}, 'Ok');
+
+ if (f.type == 'confirm')
+ DOM.add(id + '_wrapper', 'a', {'class' : 'mceButton mceCancel', href : 'javascript:;', onmousedown : 'return false;'}, 'Cancel');
+
+ DOM.add(id + '_middle', 'div', {'class' : 'mceIcon'});
+ DOM.setHTML(id + '_content', f.content.replace('\n', '<br />'));
+
+ Event.add(id, 'keyup', function(evt) {
+ var VK_ESCAPE = 27;
+ if (evt.keyCode === VK_ESCAPE) {
+ f.button_func(false);
+ return Event.cancel(evt);
+ }
+ });
+
+ Event.add(id, 'keydown', function(evt) {
+ var cancelButton, VK_TAB = 9;
+ if (evt.keyCode === VK_TAB) {
+ cancelButton = DOM.select('a.mceCancel', id + '_wrapper')[0];
+ if (cancelButton && cancelButton !== evt.target) {
+ cancelButton.focus();
+ } else {
+ DOM.get(id + '_ok').focus();
+ }
+ return Event.cancel(evt);
+ }
+ });
+ }
+
+ // Register events
+ mdf = Event.add(id, 'mousedown', function(e) {
+ var n = e.target, w, vp;
+
+ w = t.windows[id];
+ t.focus(id);
+
+ if (n.nodeName == 'A' || n.nodeName == 'a') {
+ if (n.className == 'mceClose') {
+ t.close(null, id);
+ return Event.cancel(e);
+ } else if (n.className == 'mceMax') {
+ w.oldPos = w.element.getXY();
+ w.oldSize = w.element.getSize();
+
+ vp = DOM.getViewPort();
+
+ // Reduce viewport size to avoid scrollbars
+ vp.w -= 2;
+ vp.h -= 2;
+
+ w.element.moveTo(vp.x, vp.y);
+ w.element.resizeTo(vp.w, vp.h);
+ DOM.setStyles(id + '_ifr', {width : vp.w - w.deltaWidth, height : vp.h - w.deltaHeight});
+ DOM.addClass(id + '_wrapper', 'mceMaximized');
+ } else if (n.className == 'mceMed') {
+ // Reset to old size
+ w.element.moveTo(w.oldPos.x, w.oldPos.y);
+ w.element.resizeTo(w.oldSize.w, w.oldSize.h);
+ w.iframeElement.resizeTo(w.oldSize.w - w.deltaWidth, w.oldSize.h - w.deltaHeight);
+
+ DOM.removeClass(id + '_wrapper', 'mceMaximized');
+ } else if (n.className == 'mceMove')
+ return t._startDrag(id, e, n.className);
+ else if (DOM.hasClass(n, 'mceResize'))
+ return t._startDrag(id, e, n.className.substring(13));
+ }
+ });
+
+ clf = Event.add(id, 'click', function(e) {
+ var n = e.target;
+
+ t.focus(id);
+
+ if (n.nodeName == 'A' || n.nodeName == 'a') {
+ switch (n.className) {
+ case 'mceClose':
+ t.close(null, id);
+ return Event.cancel(e);
+
+ case 'mceButton mceOk':
+ case 'mceButton mceCancel':
+ f.button_func(n.className == 'mceButton mceOk');
+ return Event.cancel(e);
+ }
+ }
+ });
+
+ // Make sure the tab order loops within the dialog.
+ Event.add([id + '_left', id + '_right'], 'focus', function(evt) {
+ var iframe = DOM.get(id + '_ifr');
+ if (iframe) {
+ var body = iframe.contentWindow.document.body;
+ var focusable = DOM.select(':input:enabled,*[tabindex=0]', body);
+ if (evt.target.id === (id + '_left')) {
+ focusable[focusable.length - 1].focus();
+ } else {
+ focusable[0].focus();
+ }
+ } else {
+ DOM.get(id + '_ok').focus();
+ }
+ });
+
+ // Add window
+ w = t.windows[id] = {
+ id : id,
+ mousedown_func : mdf,
+ click_func : clf,
+ element : new Element(id, {blocker : 1, container : ed.getContainer()}),
+ iframeElement : new Element(id + '_ifr'),
+ features : f,
+ deltaWidth : dw,
+ deltaHeight : dh
+ };
+
+ w.iframeElement.on('focus', function() {
+ t.focus(id);
+ });
+
+ // Setup blocker
+ if (t.count == 0 && t.editor.getParam('dialog_type', 'modal') == 'modal') {
+ DOM.add(DOM.doc.body, 'div', {
+ id : 'mceModalBlocker',
+ 'class' : (t.editor.settings.inlinepopups_skin || 'clearlooks2') + '_modalBlocker',
+ style : {zIndex : t.zIndex - 1}
+ });
+
+ DOM.show('mceModalBlocker'); // Reduces flicker in IE
+ DOM.setAttrib(DOM.doc.body, 'aria-hidden', 'true');
+ } else
+ DOM.setStyle('mceModalBlocker', 'z-index', t.zIndex - 1);
+
+ if (tinymce.isIE6 || /Firefox\/2\./.test(navigator.userAgent) || (tinymce.isIE && !DOM.boxModel))
+ DOM.setStyles('mceModalBlocker', {position : 'absolute', left : vp.x, top : vp.y, width : vp.w - 2, height : vp.h - 2});
+
+ DOM.setAttrib(id, 'aria-hidden', 'false');
+ t.focus(id);
+ t._fixIELayout(id, 1);
+
+ // Focus ok button
+ if (DOM.get(id + '_ok'))
+ DOM.get(id + '_ok').focus();
+ t.count++;
+
+ return w;
+ },
+
+ focus : function(id) {
+ var t = this, w;
+
+ if (w = t.windows[id]) {
+ w.zIndex = this.zIndex++;
+ w.element.setStyle('zIndex', w.zIndex);
+ w.element.update();
+
+ id = id + '_wrapper';
+ DOM.removeClass(t.lastId, 'mceFocus');
+ DOM.addClass(id, 'mceFocus');
+ t.lastId = id;
+
+ if (w.focussedElement) {
+ w.focussedElement.focus();
+ } else if (DOM.get(id + '_ok')) {
+ DOM.get(w.id + '_ok').focus();
+ } else if (DOM.get(w.id + '_ifr')) {
+ DOM.get(w.id + '_ifr').focus();
+ }
+ }
+ },
+
+ _addAll : function(te, ne) {
+ var i, n, t = this, dom = tinymce.DOM;
+
+ if (is(ne, 'string'))
+ te.appendChild(dom.doc.createTextNode(ne));
+ else if (ne.length) {
+ te = te.appendChild(dom.create(ne[0], ne[1]));
+
+ for (i=2; i<ne.length; i++)
+ t._addAll(te, ne[i]);
+ }
+ },
+
+ _startDrag : function(id, se, ac) {
+ var t = this, mu, mm, d = DOM.doc, eb, w = t.windows[id], we = w.element, sp = we.getXY(), p, sz, ph, cp, vp, sx, sy, sex, sey, dx, dy, dw, dh;
+
+ // Get positons and sizes
+// cp = DOM.getPos(t.editor.getContainer());
+ cp = {x : 0, y : 0};
+ vp = DOM.getViewPort();
+
+ // Reduce viewport size to avoid scrollbars while dragging
+ vp.w -= 2;
+ vp.h -= 2;
+
+ sex = se.screenX;
+ sey = se.screenY;
+ dx = dy = dw = dh = 0;
+
+ // Handle mouse up
+ mu = Event.add(d, 'mouseup', function(e) {
+ Event.remove(d, 'mouseup', mu);
+ Event.remove(d, 'mousemove', mm);
+
+ if (eb)
+ eb.remove();
+
+ we.moveBy(dx, dy);
+ we.resizeBy(dw, dh);
+ sz = we.getSize();
+ DOM.setStyles(id + '_ifr', {width : sz.w - w.deltaWidth, height : sz.h - w.deltaHeight});
+ t._fixIELayout(id, 1);
+
+ return Event.cancel(e);
+ });
+
+ if (ac != 'Move')
+ startMove();
+
+ function startMove() {
+ if (eb)
+ return;
+
+ t._fixIELayout(id, 0);
+
+ // Setup event blocker
+ DOM.add(d.body, 'div', {
+ id : 'mceEventBlocker',
+ 'class' : 'mceEventBlocker ' + (t.editor.settings.inlinepopups_skin || 'clearlooks2'),
+ style : {zIndex : t.zIndex + 1}
+ });
+
+ if (tinymce.isIE6 || (tinymce.isIE && !DOM.boxModel))
+ DOM.setStyles('mceEventBlocker', {position : 'absolute', left : vp.x, top : vp.y, width : vp.w - 2, height : vp.h - 2});
+
+ eb = new Element('mceEventBlocker');
+ eb.update();
+
+ // Setup placeholder
+ p = we.getXY();
+ sz = we.getSize();
+ sx = cp.x + p.x - vp.x;
+ sy = cp.y + p.y - vp.y;
+ DOM.add(eb.get(), 'div', {id : 'mcePlaceHolder', 'class' : 'mcePlaceHolder', style : {left : sx, top : sy, width : sz.w, height : sz.h}});
+ ph = new Element('mcePlaceHolder');
+ };
+
+ // Handle mouse move/drag
+ mm = Event.add(d, 'mousemove', function(e) {
+ var x, y, v;
+
+ startMove();
+
+ x = e.screenX - sex;
+ y = e.screenY - sey;
+
+ switch (ac) {
+ case 'ResizeW':
+ dx = x;
+ dw = 0 - x;
+ break;
+
+ case 'ResizeE':
+ dw = x;
+ break;
+
+ case 'ResizeN':
+ case 'ResizeNW':
+ case 'ResizeNE':
+ if (ac == "ResizeNW") {
+ dx = x;
+ dw = 0 - x;
+ } else if (ac == "ResizeNE")
+ dw = x;
+
+ dy = y;
+ dh = 0 - y;
+ break;
+
+ case 'ResizeS':
+ case 'ResizeSW':
+ case 'ResizeSE':
+ if (ac == "ResizeSW") {
+ dx = x;
+ dw = 0 - x;
+ } else if (ac == "ResizeSE")
+ dw = x;
+
+ dh = y;
+ break;
+
+ case 'mceMove':
+ dx = x;
+ dy = y;
+ break;
+ }
+
+ // Boundary check
+ if (dw < (v = w.features.min_width - sz.w)) {
+ if (dx !== 0)
+ dx += dw - v;
+
+ dw = v;
+ }
+
+ if (dh < (v = w.features.min_height - sz.h)) {
+ if (dy !== 0)
+ dy += dh - v;
+
+ dh = v;
+ }
+
+ dw = Math.min(dw, w.features.max_width - sz.w);
+ dh = Math.min(dh, w.features.max_height - sz.h);
+ dx = Math.max(dx, vp.x - (sx + vp.x));
+ dy = Math.max(dy, vp.y - (sy + vp.y));
+ dx = Math.min(dx, (vp.w + vp.x) - (sx + sz.w + vp.x));
+ dy = Math.min(dy, (vp.h + vp.y) - (sy + sz.h + vp.y));
+
+ // Move if needed
+ if (dx + dy !== 0) {
+ if (sx + dx < 0)
+ dx = 0;
+
+ if (sy + dy < 0)
+ dy = 0;
+
+ ph.moveTo(sx + dx, sy + dy);
+ }
+
+ // Resize if needed
+ if (dw + dh !== 0)
+ ph.resizeTo(sz.w + dw, sz.h + dh);
+
+ return Event.cancel(e);
+ });
+
+ return Event.cancel(se);
+ },
+
+ resizeBy : function(dw, dh, id) {
+ var w = this.windows[id];
+
+ if (w) {
+ w.element.resizeBy(dw, dh);
+ w.iframeElement.resizeBy(dw, dh);
+ }
+ },
+
+ close : function(win, id) {
+ var t = this, w, d = DOM.doc, fw, id;
+
+ id = t._findId(id || win);
+
+ // Probably not inline
+ if (!t.windows[id]) {
+ t.parent(win);
+ return;
+ }
+
+ t.count--;
+
+ if (t.count == 0) {
+ DOM.remove('mceModalBlocker');
+ DOM.setAttrib(DOM.doc.body, 'aria-hidden', 'false');
+ t.editor.focus();
+ }
+
+ if (w = t.windows[id]) {
+ t.onClose.dispatch(t);
+ Event.remove(d, 'mousedown', w.mousedownFunc);
+ Event.remove(d, 'click', w.clickFunc);
+ Event.clear(id);
+ Event.clear(id + '_ifr');
+
+ DOM.setAttrib(id + '_ifr', 'src', 'javascript:""'); // Prevent leak
+ w.element.remove();
+ delete t.windows[id];
+
+ fw = t._frontWindow();
+
+ if (fw)
+ t.focus(fw.id);
+ }
+ },
+
+ // Find front most window
+ _frontWindow : function() {
+ var fw, ix = 0;
+ // Find front most window and focus that
+ each (this.windows, function(w) {
+ if (w.zIndex > ix) {
+ fw = w;
+ ix = w.zIndex;
+ }
+ });
+ return fw;
+ },
+
+ setTitle : function(w, ti) {
+ var e;
+
+ w = this._findId(w);
+
+ if (e = DOM.get(w + '_title'))
+ e.innerHTML = DOM.encode(ti);
+ },
+
+ alert : function(txt, cb, s) {
+ var t = this, w;
+
+ w = t.open({
+ title : t,
+ type : 'alert',
+ button_func : function(s) {
+ if (cb)
+ cb.call(s || t, s);
+
+ t.close(null, w.id);
+ },
+ content : DOM.encode(t.editor.getLang(txt, txt)),
+ inline : 1,
+ width : 400,
+ height : 130
+ });
+ },
+
+ confirm : function(txt, cb, s) {
+ var t = this, w;
+
+ w = t.open({
+ title : t,
+ type : 'confirm',
+ button_func : function(s) {
+ if (cb)
+ cb.call(s || t, s);
+
+ t.close(null, w.id);
+ },
+ content : DOM.encode(t.editor.getLang(txt, txt)),
+ inline : 1,
+ width : 400,
+ height : 130
+ });
+ },
+
+ // Internal functions
+
+ _findId : function(w) {
+ var t = this;
+
+ if (typeof(w) == 'string')
+ return w;
+
+ each(t.windows, function(wo) {
+ var ifr = DOM.get(wo.id + '_ifr');
+
+ if (ifr && w == ifr.contentWindow) {
+ w = wo.id;
+ return false;
+ }
+ });
+
+ return w;
+ },
+
+ _fixIELayout : function(id, s) {
+ var w, img;
+
+ if (!tinymce.isIE6)
+ return;
+
+ // Fixes the bug where hover flickers and does odd things in IE6
+ each(['n','s','w','e','nw','ne','sw','se'], function(v) {
+ var e = DOM.get(id + '_resize_' + v);
+
+ DOM.setStyles(e, {
+ width : s ? e.clientWidth : '',
+ height : s ? e.clientHeight : '',
+ cursor : DOM.getStyle(e, 'cursor', 1)
+ });
+
+ DOM.setStyle(id + "_bottom", 'bottom', '-1px');
+
+ e = 0;
+ });
+
+ // Fixes graphics glitch
+ if (w = this.windows[id]) {
+ // Fixes rendering bug after resize
+ w.element.hide();
+ w.element.show();
+
+ // Forced a repaint of the window
+ //DOM.get(id).style.filter = '';
+
+ // IE has a bug where images used in CSS won't get loaded
+ // sometimes when the cache in the browser is disabled
+ // This fix tries to solve it by loading the images using the image object
+ each(DOM.select('div,a', id), function(e, i) {
+ if (e.currentStyle.backgroundImage != 'none') {
+ img = new Image();
+ img.src = e.currentStyle.backgroundImage.replace(/url\(\"(.+)\"\)/, '$1');
+ }
+ });
+
+ DOM.get(id).style.filter = '';
+ }
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('inlinepopups', tinymce.plugins.InlinePopups);
+})();
+
diff --git a/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/alert.gif b/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/alert.gif
new file mode 100644
index 00000000..21913985
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/alert.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/button.gif b/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/button.gif
new file mode 100644
index 00000000..f957e49a
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/button.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif b/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif
new file mode 100644
index 00000000..6baf64ad
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/buttons.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/confirm.gif b/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/confirm.gif
new file mode 100644
index 00000000..20acbbf7
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/confirm.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/corners.gif b/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/corners.gif
new file mode 100644
index 00000000..d5de1cc2
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/corners.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gif b/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gif
new file mode 100644
index 00000000..c2a2ad45
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/horizontal.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/vertical.gif b/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/vertical.gif
new file mode 100644
index 00000000..0b4cc368
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/img/vertical.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/window.css b/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/window.css
new file mode 100644
index 00000000..a50d4fc5
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/inlinepopups/skins/clearlooks2/window.css
@@ -0,0 +1,90 @@
+/* Clearlooks 2 */
+
+/* Reset */
+.clearlooks2, .clearlooks2 div, .clearlooks2 span, .clearlooks2 a {vertical-align:baseline; text-align:left; position:absolute; border:0; padding:0; margin:0; background:transparent; font-family:Arial,Verdana; font-size:11px; color:#000; text-decoration:none; font-weight:normal; width:auto; height:auto; overflow:hidden; display:block}
+
+/* General */
+.clearlooks2 {position:absolute; direction:ltr}
+.clearlooks2 .mceWrapper {position:static}
+.mceEventBlocker {position:fixed; left:0; top:0; background:url(img/horizontal.gif) no-repeat 0 -75px; width:100%; height:100%}
+.clearlooks2 .mcePlaceHolder {border:1px solid #000; background:#888; top:0; left:0; opacity:0.5; -ms-filter:'alpha(opacity=50)'; filter:alpha(opacity=50)}
+.clearlooks2_modalBlocker {position:fixed; left:0; top:0; width:100%; height:100%; background:#FFF; opacity:0.6; -ms-filter:'alpha(opacity=60)'; filter:alpha(opacity=60); display:none}
+
+/* Top */
+.clearlooks2 .mceTop, .clearlooks2 .mceTop div {top:0; width:100%; height:23px}
+.clearlooks2 .mceTop .mceLeft {width:6px; background:url(img/corners.gif)}
+.clearlooks2 .mceTop .mceCenter {right:6px; width:100%; height:23px; background:url(img/horizontal.gif) 12px 0; clip:rect(auto auto auto 12px)}
+.clearlooks2 .mceTop .mceRight {right:0; width:6px; height:23px; background:url(img/corners.gif) -12px 0}
+.clearlooks2 .mceTop span {width:100%; text-align:center; vertical-align:middle; line-height:23px; font-weight:bold}
+.clearlooks2 .mceFocus .mceTop .mceLeft {background:url(img/corners.gif) -6px 0}
+.clearlooks2 .mceFocus .mceTop .mceCenter {background:url(img/horizontal.gif) 0 -23px}
+.clearlooks2 .mceFocus .mceTop .mceRight {background:url(img/corners.gif) -18px 0}
+.clearlooks2 .mceFocus .mceTop span {color:#FFF}
+
+/* Middle */
+.clearlooks2 .mceMiddle, .clearlooks2 .mceMiddle div {top:0}
+.clearlooks2 .mceMiddle {width:100%; height:100%; clip:rect(23px auto auto auto)}
+.clearlooks2 .mceMiddle .mceLeft {left:0; width:5px; height:100%; background:url(img/vertical.gif) -5px 0}
+.clearlooks2 .mceMiddle span {top:23px; left:5px; width:100%; height:100%; background:#FFF}
+.clearlooks2 .mceMiddle .mceRight {right:0; width:5px; height:100%; background:url(img/vertical.gif)}
+
+/* Bottom */
+.clearlooks2 .mceBottom, .clearlooks2 .mceBottom div {height:6px}
+.clearlooks2 .mceBottom {left:0; bottom:0; width:100%}
+.clearlooks2 .mceBottom div {top:0}
+.clearlooks2 .mceBottom .mceLeft {left:0; width:5px; background:url(img/corners.gif) -34px -6px}
+.clearlooks2 .mceBottom .mceCenter {left:5px; width:100%; background:url(img/horizontal.gif) 0 -46px}
+.clearlooks2 .mceBottom .mceRight {right:0; width:5px; background: url(img/corners.gif) -34px 0}
+.clearlooks2 .mceBottom span {display:none}
+.clearlooks2 .mceStatusbar .mceBottom, .clearlooks2 .mceStatusbar .mceBottom div {height:23px}
+.clearlooks2 .mceStatusbar .mceBottom .mceLeft {background:url(img/corners.gif) -29px 0}
+.clearlooks2 .mceStatusbar .mceBottom .mceCenter {background:url(img/horizontal.gif) 0 -52px}
+.clearlooks2 .mceStatusbar .mceBottom .mceRight {background:url(img/corners.gif) -24px 0}
+.clearlooks2 .mceStatusbar .mceBottom span {display:block; left:7px; font-family:Arial, Verdana; font-size:11px; line-height:23px}
+
+/* Actions */
+.clearlooks2 a {width:29px; height:16px; top:3px;}
+.clearlooks2 .mceClose {right:6px; background:url(img/buttons.gif) -87px 0}
+.clearlooks2 .mceMin {display:none; right:68px; background:url(img/buttons.gif) 0 0}
+.clearlooks2 .mceMed {display:none; right:37px; background:url(img/buttons.gif) -29px 0}
+.clearlooks2 .mceMax {display:none; right:37px; background:url(img/buttons.gif) -58px 0}
+.clearlooks2 .mceMove {display:none;width:100%;cursor:move;background:url(img/corners.gif) no-repeat -100px -100px}
+.clearlooks2 .mceMovable .mceMove {display:block}
+.clearlooks2 .mceFocus .mceClose {right:6px; background:url(img/buttons.gif) -87px -16px}
+.clearlooks2 .mceFocus .mceMin {right:68px; background:url(img/buttons.gif) 0 -16px}
+.clearlooks2 .mceFocus .mceMed {right:37px; background:url(img/buttons.gif) -29px -16px}
+.clearlooks2 .mceFocus .mceMax {right:37px; background:url(img/buttons.gif) -58px -16px}
+.clearlooks2 .mceFocus .mceClose:hover {right:6px; background:url(img/buttons.gif) -87px -32px}
+.clearlooks2 .mceFocus .mceClose:hover {right:6px; background:url(img/buttons.gif) -87px -32px}
+.clearlooks2 .mceFocus .mceMin:hover {right:68px; background:url(img/buttons.gif) 0 -32px}
+.clearlooks2 .mceFocus .mceMed:hover {right:37px; background:url(img/buttons.gif) -29px -32px}
+.clearlooks2 .mceFocus .mceMax:hover {right:37px; background:url(img/buttons.gif) -58px -32px}
+
+/* Resize */
+.clearlooks2 .mceResize {top:auto; left:auto; display:none; width:5px; height:5px; background:url(img/horizontal.gif) no-repeat 0 -75px}
+.clearlooks2 .mceResizable .mceResize {display:block}
+.clearlooks2 .mceResizable .mceMin, .clearlooks2 .mceMax {display:none}
+.clearlooks2 .mceMinimizable .mceMin {display:block}
+.clearlooks2 .mceMaximizable .mceMax {display:block}
+.clearlooks2 .mceMaximized .mceMed {display:block}
+.clearlooks2 .mceMaximized .mceMax {display:none}
+.clearlooks2 a.mceResizeN {top:0; left:0; width:100%; cursor:n-resize}
+.clearlooks2 a.mceResizeNW {top:0; left:0; cursor:nw-resize}
+.clearlooks2 a.mceResizeNE {top:0; right:0; cursor:ne-resize}
+.clearlooks2 a.mceResizeW {top:0; left:0; height:100%; cursor:w-resize;}
+.clearlooks2 a.mceResizeE {top:0; right:0; height:100%; cursor:e-resize}
+.clearlooks2 a.mceResizeS {bottom:0; left:0; width:100%; cursor:s-resize}
+.clearlooks2 a.mceResizeSW {bottom:0; left:0; cursor:sw-resize}
+.clearlooks2 a.mceResizeSE {bottom:0; right:0; cursor:se-resize}
+
+/* Alert/Confirm */
+.clearlooks2 .mceButton {font-weight:bold; bottom:10px; width:80px; height:30px; background:url(img/button.gif); line-height:30px; vertical-align:middle; text-align:center; outline:0}
+.clearlooks2 .mceMiddle .mceIcon {left:15px; top:35px; width:32px; height:32px}
+.clearlooks2 .mceAlert .mceMiddle span, .clearlooks2 .mceConfirm .mceMiddle span {background:transparent;left:60px; top:35px; width:320px; height:50px; font-weight:bold; overflow:auto; white-space:normal}
+.clearlooks2 a:hover {font-weight:bold;}
+.clearlooks2 .mceAlert .mceMiddle, .clearlooks2 .mceConfirm .mceMiddle {background:#D6D7D5}
+.clearlooks2 .mceAlert .mceOk {left:50%; top:auto; margin-left: -40px}
+.clearlooks2 .mceAlert .mceIcon {background:url(img/alert.gif)}
+.clearlooks2 .mceConfirm .mceOk {left:50%; top:auto; margin-left: -90px}
+.clearlooks2 .mceConfirm .mceCancel {left:50%; top:auto}
+.clearlooks2 .mceConfirm .mceIcon {background:url(img/confirm.gif)}
diff --git a/askbot/media/js/tinymce/plugins/inlinepopups/template.htm b/askbot/media/js/tinymce/plugins/inlinepopups/template.htm
new file mode 100644
index 00000000..f9ec6421
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/inlinepopups/template.htm
@@ -0,0 +1,387 @@
+<!-- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>Template for dialogs</title>
+<link rel="stylesheet" type="text/css" href="skins/clearlooks2/window.css" />
+</head>
+<body>
+
+<div class="mceEditor">
+ <div class="clearlooks2" style="width:400px; height:100px; left:10px;">
+ <div class="mceWrapper">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Blured</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>Content</span>
+ <div class="mceRight"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar text.</span>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceMin" href="#"></a>
+ <a class="mceMax" href="#"></a>
+ <a class="mceMed" href="#"></a>
+ <a class="mceClose" href="#"></a>
+ <a class="mceResize mceResizeN" href="#"></a>
+ <a class="mceResize mceResizeS" href="#"></a>
+ <a class="mceResize mceResizeW" href="#"></a>
+ <a class="mceResize mceResizeE" href="#"></a>
+ <a class="mceResize mceResizeNW" href="#"></a>
+ <a class="mceResize mceResizeNE" href="#"></a>
+ <a class="mceResize mceResizeSW" href="#"></a>
+ <a class="mceResize mceResizeSE" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:100px; left:420px;">
+ <div class="mceWrapper mceMovable mceFocus">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Focused</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>Content</span>
+ <div class="mceRight"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar text.</span>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceMin" href="#"></a>
+ <a class="mceMax" href="#"></a>
+ <a class="mceMed" href="#"></a>
+ <a class="mceClose" href="#"></a>
+ <a class="mceResize mceResizeN" href="#"></a>
+ <a class="mceResize mceResizeS" href="#"></a>
+ <a class="mceResize mceResizeW" href="#"></a>
+ <a class="mceResize mceResizeE" href="#"></a>
+ <a class="mceResize mceResizeNW" href="#"></a>
+ <a class="mceResize mceResizeNE" href="#"></a>
+ <a class="mceResize mceResizeSW" href="#"></a>
+ <a class="mceResize mceResizeSE" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:100px; left:10px; top:120px;">
+ <div class="mceWrapper mceMovable mceFocus mceStatusbar">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>Content</span>
+ <div class="mceRight"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar text.</span>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceMin" href="#"></a>
+ <a class="mceMax" href="#"></a>
+ <a class="mceMed" href="#"></a>
+ <a class="mceClose" href="#"></a>
+ <a class="mceResize mceResizeN" href="#"></a>
+ <a class="mceResize mceResizeS" href="#"></a>
+ <a class="mceResize mceResizeW" href="#"></a>
+ <a class="mceResize mceResizeE" href="#"></a>
+ <a class="mceResize mceResizeNW" href="#"></a>
+ <a class="mceResize mceResizeNE" href="#"></a>
+ <a class="mceResize mceResizeSW" href="#"></a>
+ <a class="mceResize mceResizeSE" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:100px; left:420px; top:120px;">
+ <div class="mceWrapper mceMovable mceFocus mceStatusbar mceResizable">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar, Resizable</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>Content</span>
+ <div class="mceRight"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar text.</span>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceMin" href="#"></a>
+ <a class="mceMax" href="#"></a>
+ <a class="mceMed" href="#"></a>
+ <a class="mceClose" href="#"></a>
+ <a class="mceResize mceResizeN" href="#"></a>
+ <a class="mceResize mceResizeS" href="#"></a>
+ <a class="mceResize mceResizeW" href="#"></a>
+ <a class="mceResize mceResizeE" href="#"></a>
+ <a class="mceResize mceResizeNW" href="#"></a>
+ <a class="mceResize mceResizeNE" href="#"></a>
+ <a class="mceResize mceResizeSW" href="#"></a>
+ <a class="mceResize mceResizeSE" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:100px; left:10px; top:230px;">
+ <div class="mceWrapper mceMovable mceFocus mceResizable mceMaximizable">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Resizable, Maximizable</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>Content</span>
+ <div class="mceRight"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar text.</span>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceMin" href="#"></a>
+ <a class="mceMax" href="#"></a>
+ <a class="mceMed" href="#"></a>
+ <a class="mceClose" href="#"></a>
+ <a class="mceResize mceResizeN" href="#"></a>
+ <a class="mceResize mceResizeS" href="#"></a>
+ <a class="mceResize mceResizeW" href="#"></a>
+ <a class="mceResize mceResizeE" href="#"></a>
+ <a class="mceResize mceResizeNW" href="#"></a>
+ <a class="mceResize mceResizeNE" href="#"></a>
+ <a class="mceResize mceResizeSW" href="#"></a>
+ <a class="mceResize mceResizeSE" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:100px; left:420px; top:230px;">
+ <div class="mceWrapper mceMovable mceStatusbar mceResizable mceMaximizable">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Blurred, Maximizable, Statusbar, Resizable</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>Content</span>
+ <div class="mceRight"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar text.</span>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceMin" href="#"></a>
+ <a class="mceMax" href="#"></a>
+ <a class="mceMed" href="#"></a>
+ <a class="mceClose" href="#"></a>
+ <a class="mceResize mceResizeN" href="#"></a>
+ <a class="mceResize mceResizeS" href="#"></a>
+ <a class="mceResize mceResizeW" href="#"></a>
+ <a class="mceResize mceResizeE" href="#"></a>
+ <a class="mceResize mceResizeNW" href="#"></a>
+ <a class="mceResize mceResizeNE" href="#"></a>
+ <a class="mceResize mceResizeSW" href="#"></a>
+ <a class="mceResize mceResizeSE" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:100px; left:10px; top:340px;">
+ <div class="mceWrapper mceMovable mceFocus mceResizable mceMaximized mceMinimizable mceMaximizable">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Maximized, Maximizable, Minimizable</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>Content</span>
+ <div class="mceRight"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar text.</span>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceMin" href="#"></a>
+ <a class="mceMax" href="#"></a>
+ <a class="mceMed" href="#"></a>
+ <a class="mceClose" href="#"></a>
+ <a class="mceResize mceResizeN" href="#"></a>
+ <a class="mceResize mceResizeS" href="#"></a>
+ <a class="mceResize mceResizeW" href="#"></a>
+ <a class="mceResize mceResizeE" href="#"></a>
+ <a class="mceResize mceResizeNW" href="#"></a>
+ <a class="mceResize mceResizeNE" href="#"></a>
+ <a class="mceResize mceResizeSW" href="#"></a>
+ <a class="mceResize mceResizeSE" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:100px; left:420px; top:340px;">
+ <div class="mceWrapper mceMovable mceStatusbar mceResizable mceMaximized mceMinimizable mceMaximizable">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Blured</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>Content</span>
+ <div class="mceRight"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Statusbar text.</span>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceMin" href="#"></a>
+ <a class="mceMax" href="#"></a>
+ <a class="mceMed" href="#"></a>
+ <a class="mceClose" href="#"></a>
+ <a class="mceResize mceResizeN" href="#"></a>
+ <a class="mceResize mceResizeS" href="#"></a>
+ <a class="mceResize mceResizeW" href="#"></a>
+ <a class="mceResize mceResizeE" href="#"></a>
+ <a class="mceResize mceResizeNW" href="#"></a>
+ <a class="mceResize mceResizeNE" href="#"></a>
+ <a class="mceResize mceResizeSW" href="#"></a>
+ <a class="mceResize mceResizeSE" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:130px; left:10px; top:450px;">
+ <div class="mceWrapper mceMovable mceFocus mceModal mceAlert">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Alert</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ </span>
+ <div class="mceRight"></div>
+ <div class="mceIcon"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceButton mceOk" href="#">Ok</a>
+ <a class="mceClose" href="#"></a>
+ </div>
+ </div>
+
+ <div class="clearlooks2" style="width:400px; height:130px; left:420px; top:450px;">
+ <div class="mceWrapper mceMovable mceFocus mceModal mceConfirm">
+ <div class="mceTop">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ <span>Confirm</span>
+ </div>
+
+ <div class="mceMiddle">
+ <div class="mceLeft"></div>
+ <span>
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ This is a very long error message. This is a very long error message.
+ </span>
+ <div class="mceRight"></div>
+ <div class="mceIcon"></div>
+ </div>
+
+ <div class="mceBottom">
+ <div class="mceLeft"></div>
+ <div class="mceCenter"></div>
+ <div class="mceRight"></div>
+ </div>
+
+ <a class="mceMove" href="#"></a>
+ <a class="mceButton mceOk" href="#">Ok</a>
+ <a class="mceButton mceCancel" href="#">Cancel</a>
+ <a class="mceClose" href="#"></a>
+ </div>
+ </div>
+</div>
+
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/insertdatetime/editor_plugin.js b/askbot/media/js/tinymce/plugins/insertdatetime/editor_plugin.js
new file mode 100644
index 00000000..938ce6b1
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/insertdatetime/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.InsertDateTime",{init:function(a,b){var c=this;c.editor=a;a.addCommand("mceInsertDate",function(){var d=c._getDateTime(new Date(),a.getParam("plugin_insertdate_dateFormat",a.getLang("insertdatetime.date_fmt")));a.execCommand("mceInsertContent",false,d)});a.addCommand("mceInsertTime",function(){var d=c._getDateTime(new Date(),a.getParam("plugin_insertdate_timeFormat",a.getLang("insertdatetime.time_fmt")));a.execCommand("mceInsertContent",false,d)});a.addButton("insertdate",{title:"insertdatetime.insertdate_desc",cmd:"mceInsertDate"});a.addButton("inserttime",{title:"insertdatetime.inserttime_desc",cmd:"mceInsertTime"})},getInfo:function(){return{longname:"Insert date/time",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/insertdatetime",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_getDateTime:function(e,a){var c=this.editor;function b(g,d){g=""+g;if(g.length<d){for(var f=0;f<(d-g.length);f++){g="0"+g}}return g}a=a.replace("%D","%m/%d/%y");a=a.replace("%r","%I:%M:%S %p");a=a.replace("%Y",""+e.getFullYear());a=a.replace("%y",""+e.getYear());a=a.replace("%m",b(e.getMonth()+1,2));a=a.replace("%d",b(e.getDate(),2));a=a.replace("%H",""+b(e.getHours(),2));a=a.replace("%M",""+b(e.getMinutes(),2));a=a.replace("%S",""+b(e.getSeconds(),2));a=a.replace("%I",""+((e.getHours()+11)%12+1));a=a.replace("%p",""+(e.getHours()<12?"AM":"PM"));a=a.replace("%B",""+c.getLang("insertdatetime.months_long").split(",")[e.getMonth()]);a=a.replace("%b",""+c.getLang("insertdatetime.months_short").split(",")[e.getMonth()]);a=a.replace("%A",""+c.getLang("insertdatetime.day_long").split(",")[e.getDay()]);a=a.replace("%a",""+c.getLang("insertdatetime.day_short").split(",")[e.getDay()]);a=a.replace("%%","%");return a}});tinymce.PluginManager.add("insertdatetime",tinymce.plugins.InsertDateTime)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/insertdatetime/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/insertdatetime/editor_plugin_src.js
new file mode 100644
index 00000000..181c791e
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/insertdatetime/editor_plugin_src.js
@@ -0,0 +1,83 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.InsertDateTime', {
+ init : function(ed, url) {
+ var t = this;
+
+ t.editor = ed;
+
+ ed.addCommand('mceInsertDate', function() {
+ var str = t._getDateTime(new Date(), ed.getParam("plugin_insertdate_dateFormat", ed.getLang('insertdatetime.date_fmt')));
+
+ ed.execCommand('mceInsertContent', false, str);
+ });
+
+ ed.addCommand('mceInsertTime', function() {
+ var str = t._getDateTime(new Date(), ed.getParam("plugin_insertdate_timeFormat", ed.getLang('insertdatetime.time_fmt')));
+
+ ed.execCommand('mceInsertContent', false, str);
+ });
+
+ ed.addButton('insertdate', {title : 'insertdatetime.insertdate_desc', cmd : 'mceInsertDate'});
+ ed.addButton('inserttime', {title : 'insertdatetime.inserttime_desc', cmd : 'mceInsertTime'});
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Insert date/time',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/insertdatetime',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ // Private methods
+
+ _getDateTime : function(d, fmt) {
+ var ed = this.editor;
+
+ function addZeros(value, len) {
+ value = "" + value;
+
+ if (value.length < len) {
+ for (var i=0; i<(len-value.length); i++)
+ value = "0" + value;
+ }
+
+ return value;
+ };
+
+ fmt = fmt.replace("%D", "%m/%d/%y");
+ fmt = fmt.replace("%r", "%I:%M:%S %p");
+ fmt = fmt.replace("%Y", "" + d.getFullYear());
+ fmt = fmt.replace("%y", "" + d.getYear());
+ fmt = fmt.replace("%m", addZeros(d.getMonth()+1, 2));
+ fmt = fmt.replace("%d", addZeros(d.getDate(), 2));
+ fmt = fmt.replace("%H", "" + addZeros(d.getHours(), 2));
+ fmt = fmt.replace("%M", "" + addZeros(d.getMinutes(), 2));
+ fmt = fmt.replace("%S", "" + addZeros(d.getSeconds(), 2));
+ fmt = fmt.replace("%I", "" + ((d.getHours() + 11) % 12 + 1));
+ fmt = fmt.replace("%p", "" + (d.getHours() < 12 ? "AM" : "PM"));
+ fmt = fmt.replace("%B", "" + ed.getLang("insertdatetime.months_long").split(',')[d.getMonth()]);
+ fmt = fmt.replace("%b", "" + ed.getLang("insertdatetime.months_short").split(',')[d.getMonth()]);
+ fmt = fmt.replace("%A", "" + ed.getLang("insertdatetime.day_long").split(',')[d.getDay()]);
+ fmt = fmt.replace("%a", "" + ed.getLang("insertdatetime.day_short").split(',')[d.getDay()]);
+ fmt = fmt.replace("%%", "%");
+
+ return fmt;
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('insertdatetime', tinymce.plugins.InsertDateTime);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/layer/editor_plugin.js b/askbot/media/js/tinymce/plugins/layer/editor_plugin.js
new file mode 100644
index 00000000..ca3857a7
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/layer/editor_plugin.js
@@ -0,0 +1 @@
+(function(){function a(b){do{if(b.className&&b.className.indexOf("mceItemLayer")!=-1){return b}}while(b=b.parentNode)}tinymce.create("tinymce.plugins.Layer",{init:function(b,c){var d=this;d.editor=b;b.addCommand("mceInsertLayer",d._insertLayer,d);b.addCommand("mceMoveForward",function(){d._move(1)});b.addCommand("mceMoveBackward",function(){d._move(-1)});b.addCommand("mceMakeAbsolute",function(){d._toggleAbsolute()});b.addButton("moveforward",{title:"layer.forward_desc",cmd:"mceMoveForward"});b.addButton("movebackward",{title:"layer.backward_desc",cmd:"mceMoveBackward"});b.addButton("absolute",{title:"layer.absolute_desc",cmd:"mceMakeAbsolute"});b.addButton("insertlayer",{title:"layer.insertlayer_desc",cmd:"mceInsertLayer"});b.onInit.add(function(){var e=b.dom;if(tinymce.isIE){b.getDoc().execCommand("2D-Position",false,true)}});b.onMouseUp.add(function(f,h){var g=a(h.target);if(g){f.dom.setAttrib(g,"data-mce-style","")}});b.onMouseDown.add(function(f,j){var h=j.target,i=f.getDoc(),g;if(tinymce.isGecko){if(a(h)){if(i.designMode!=="on"){i.designMode="on";h=i.body;g=h.parentNode;g.removeChild(h);g.appendChild(h)}}else{if(i.designMode=="on"){i.designMode="off"}}}});b.onNodeChange.add(d._nodeChange,d);b.onVisualAid.add(d._visualAid,d)},getInfo:function(){return{longname:"Layer",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/layer",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_nodeChange:function(c,b,f){var d,e;d=this._getParentLayer(f);e=c.dom.getParent(f,"DIV,P,IMG");if(!e){b.setDisabled("absolute",1);b.setDisabled("moveforward",1);b.setDisabled("movebackward",1)}else{b.setDisabled("absolute",0);b.setDisabled("moveforward",!d);b.setDisabled("movebackward",!d);b.setActive("absolute",d&&d.style.position.toLowerCase()=="absolute")}},_visualAid:function(b,d,c){var f=b.dom;tinymce.each(f.select("div,p",d),function(g){if(/^(absolute|relative|fixed)$/i.test(g.style.position)){if(c){f.addClass(g,"mceItemVisualAid")}else{f.removeClass(g,"mceItemVisualAid")}f.addClass(g,"mceItemLayer")}})},_move:function(j){var c=this.editor,g,h=[],f=this._getParentLayer(c.selection.getNode()),e=-1,k=-1,b;b=[];tinymce.walk(c.getBody(),function(d){if(d.nodeType==1&&/^(absolute|relative|static)$/i.test(d.style.position)){b.push(d)}},"childNodes");for(g=0;g<b.length;g++){h[g]=b[g].style.zIndex?parseInt(b[g].style.zIndex):0;if(e<0&&b[g]==f){e=g}}if(j<0){for(g=0;g<h.length;g++){if(h[g]<h[e]){k=g;break}}if(k>-1){b[e].style.zIndex=h[k];b[k].style.zIndex=h[e]}else{if(h[e]>0){b[e].style.zIndex=h[e]-1}}}else{for(g=0;g<h.length;g++){if(h[g]>h[e]){k=g;break}}if(k>-1){b[e].style.zIndex=h[k];b[k].style.zIndex=h[e]}else{b[e].style.zIndex=h[e]+1}}c.execCommand("mceRepaint")},_getParentLayer:function(b){return this.editor.dom.getParent(b,function(c){return c.nodeType==1&&/^(absolute|relative|static)$/i.test(c.style.position)})},_insertLayer:function(){var c=this.editor,e=c.dom,d=e.getPos(e.getParent(c.selection.getNode(),"*")),b=c.getBody();c.dom.add(b,"div",{style:{position:"absolute",left:d.x,top:(d.y>20?d.y:20),width:100,height:100},"class":"mceItemVisualAid mceItemLayer"},c.selection.getContent()||c.getLang("layer.content"));if(tinymce.isIE){e.setHTML(b,b.innerHTML)}},_toggleAbsolute:function(){var b=this.editor,c=this._getParentLayer(b.selection.getNode());if(!c){c=b.dom.getParent(b.selection.getNode(),"DIV,P,IMG")}if(c){if(c.style.position.toLowerCase()=="absolute"){b.dom.setStyles(c,{position:"",left:"",top:"",width:"",height:""});b.dom.removeClass(c,"mceItemVisualAid");b.dom.removeClass(c,"mceItemLayer")}else{if(c.style.left==""){c.style.left=20+"px"}if(c.style.top==""){c.style.top=20+"px"}if(c.style.width==""){c.style.width=c.width?(c.width+"px"):"100px"}if(c.style.height==""){c.style.height=c.height?(c.height+"px"):"100px"}c.style.position="absolute";b.dom.setAttrib(c,"data-mce-style","");b.addVisual(b.getBody())}b.execCommand("mceRepaint");b.nodeChanged()}}});tinymce.PluginManager.add("layer",tinymce.plugins.Layer)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/layer/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/layer/editor_plugin_src.js
new file mode 100644
index 00000000..daed2806
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/layer/editor_plugin_src.js
@@ -0,0 +1,262 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ function findParentLayer(node) {
+ do {
+ if (node.className && node.className.indexOf('mceItemLayer') != -1) {
+ return node;
+ }
+ } while (node = node.parentNode);
+ };
+
+ tinymce.create('tinymce.plugins.Layer', {
+ init : function(ed, url) {
+ var t = this;
+
+ t.editor = ed;
+
+ // Register commands
+ ed.addCommand('mceInsertLayer', t._insertLayer, t);
+
+ ed.addCommand('mceMoveForward', function() {
+ t._move(1);
+ });
+
+ ed.addCommand('mceMoveBackward', function() {
+ t._move(-1);
+ });
+
+ ed.addCommand('mceMakeAbsolute', function() {
+ t._toggleAbsolute();
+ });
+
+ // Register buttons
+ ed.addButton('moveforward', {title : 'layer.forward_desc', cmd : 'mceMoveForward'});
+ ed.addButton('movebackward', {title : 'layer.backward_desc', cmd : 'mceMoveBackward'});
+ ed.addButton('absolute', {title : 'layer.absolute_desc', cmd : 'mceMakeAbsolute'});
+ ed.addButton('insertlayer', {title : 'layer.insertlayer_desc', cmd : 'mceInsertLayer'});
+
+ ed.onInit.add(function() {
+ var dom = ed.dom;
+
+ if (tinymce.isIE)
+ ed.getDoc().execCommand('2D-Position', false, true);
+ });
+
+ // Remove serialized styles when selecting a layer since it might be changed by a drag operation
+ ed.onMouseUp.add(function(ed, e) {
+ var layer = findParentLayer(e.target);
+
+ if (layer) {
+ ed.dom.setAttrib(layer, 'data-mce-style', '');
+ }
+ });
+
+ // Fixes edit focus issues with layers on Gecko
+ // This will enable designMode while inside a layer and disable it when outside
+ ed.onMouseDown.add(function(ed, e) {
+ var node = e.target, doc = ed.getDoc(), parent;
+
+ if (tinymce.isGecko) {
+ if (findParentLayer(node)) {
+ if (doc.designMode !== 'on') {
+ doc.designMode = 'on';
+
+ // Repaint caret
+ node = doc.body;
+ parent = node.parentNode;
+ parent.removeChild(node);
+ parent.appendChild(node);
+ }
+ } else if (doc.designMode == 'on') {
+ doc.designMode = 'off';
+ }
+ }
+ });
+
+ ed.onNodeChange.add(t._nodeChange, t);
+ ed.onVisualAid.add(t._visualAid, t);
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Layer',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/layer',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ // Private methods
+
+ _nodeChange : function(ed, cm, n) {
+ var le, p;
+
+ le = this._getParentLayer(n);
+ p = ed.dom.getParent(n, 'DIV,P,IMG');
+
+ if (!p) {
+ cm.setDisabled('absolute', 1);
+ cm.setDisabled('moveforward', 1);
+ cm.setDisabled('movebackward', 1);
+ } else {
+ cm.setDisabled('absolute', 0);
+ cm.setDisabled('moveforward', !le);
+ cm.setDisabled('movebackward', !le);
+ cm.setActive('absolute', le && le.style.position.toLowerCase() == "absolute");
+ }
+ },
+
+ // Private methods
+
+ _visualAid : function(ed, e, s) {
+ var dom = ed.dom;
+
+ tinymce.each(dom.select('div,p', e), function(e) {
+ if (/^(absolute|relative|fixed)$/i.test(e.style.position)) {
+ if (s)
+ dom.addClass(e, 'mceItemVisualAid');
+ else
+ dom.removeClass(e, 'mceItemVisualAid');
+
+ dom.addClass(e, 'mceItemLayer');
+ }
+ });
+ },
+
+ _move : function(d) {
+ var ed = this.editor, i, z = [], le = this._getParentLayer(ed.selection.getNode()), ci = -1, fi = -1, nl;
+
+ nl = [];
+ tinymce.walk(ed.getBody(), function(n) {
+ if (n.nodeType == 1 && /^(absolute|relative|static)$/i.test(n.style.position))
+ nl.push(n);
+ }, 'childNodes');
+
+ // Find z-indexes
+ for (i=0; i<nl.length; i++) {
+ z[i] = nl[i].style.zIndex ? parseInt(nl[i].style.zIndex) : 0;
+
+ if (ci < 0 && nl[i] == le)
+ ci = i;
+ }
+
+ if (d < 0) {
+ // Move back
+
+ // Try find a lower one
+ for (i=0; i<z.length; i++) {
+ if (z[i] < z[ci]) {
+ fi = i;
+ break;
+ }
+ }
+
+ if (fi > -1) {
+ nl[ci].style.zIndex = z[fi];
+ nl[fi].style.zIndex = z[ci];
+ } else {
+ if (z[ci] > 0)
+ nl[ci].style.zIndex = z[ci] - 1;
+ }
+ } else {
+ // Move forward
+
+ // Try find a higher one
+ for (i=0; i<z.length; i++) {
+ if (z[i] > z[ci]) {
+ fi = i;
+ break;
+ }
+ }
+
+ if (fi > -1) {
+ nl[ci].style.zIndex = z[fi];
+ nl[fi].style.zIndex = z[ci];
+ } else
+ nl[ci].style.zIndex = z[ci] + 1;
+ }
+
+ ed.execCommand('mceRepaint');
+ },
+
+ _getParentLayer : function(n) {
+ return this.editor.dom.getParent(n, function(n) {
+ return n.nodeType == 1 && /^(absolute|relative|static)$/i.test(n.style.position);
+ });
+ },
+
+ _insertLayer : function() {
+ var ed = this.editor, dom = ed.dom, p = dom.getPos(dom.getParent(ed.selection.getNode(), '*')), body = ed.getBody();
+
+ ed.dom.add(body, 'div', {
+ style : {
+ position : 'absolute',
+ left : p.x,
+ top : (p.y > 20 ? p.y : 20),
+ width : 100,
+ height : 100
+ },
+ 'class' : 'mceItemVisualAid mceItemLayer'
+ }, ed.selection.getContent() || ed.getLang('layer.content'));
+
+ // Workaround for IE where it messes up the JS engine if you insert a layer on IE 6,7
+ if (tinymce.isIE)
+ dom.setHTML(body, body.innerHTML);
+ },
+
+ _toggleAbsolute : function() {
+ var ed = this.editor, le = this._getParentLayer(ed.selection.getNode());
+
+ if (!le)
+ le = ed.dom.getParent(ed.selection.getNode(), 'DIV,P,IMG');
+
+ if (le) {
+ if (le.style.position.toLowerCase() == "absolute") {
+ ed.dom.setStyles(le, {
+ position : '',
+ left : '',
+ top : '',
+ width : '',
+ height : ''
+ });
+
+ ed.dom.removeClass(le, 'mceItemVisualAid');
+ ed.dom.removeClass(le, 'mceItemLayer');
+ } else {
+ if (le.style.left == "")
+ le.style.left = 20 + 'px';
+
+ if (le.style.top == "")
+ le.style.top = 20 + 'px';
+
+ if (le.style.width == "")
+ le.style.width = le.width ? (le.width + 'px') : '100px';
+
+ if (le.style.height == "")
+ le.style.height = le.height ? (le.height + 'px') : '100px';
+
+ le.style.position = "absolute";
+
+ ed.dom.setAttrib(le, 'data-mce-style', '');
+ ed.addVisual(ed.getBody());
+ }
+
+ ed.execCommand('mceRepaint');
+ ed.nodeChanged();
+ }
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('layer', tinymce.plugins.Layer);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/legacyoutput/editor_plugin.js b/askbot/media/js/tinymce/plugins/legacyoutput/editor_plugin.js
new file mode 100644
index 00000000..2ed5f41a
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/legacyoutput/editor_plugin.js
@@ -0,0 +1 @@
+(function(a){a.onAddEditor.addToTop(function(c,b){b.settings.inline_styles=false});a.create("tinymce.plugins.LegacyOutput",{init:function(b){b.onInit.add(function(){var c="p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img",e=a.explode(b.settings.font_size_style_values),d=b.schema;b.formatter.register({alignleft:{selector:c,attributes:{align:"left"}},aligncenter:{selector:c,attributes:{align:"center"}},alignright:{selector:c,attributes:{align:"right"}},alignfull:{selector:c,attributes:{align:"justify"}},bold:[{inline:"b",remove:"all"},{inline:"strong",remove:"all"},{inline:"span",styles:{fontWeight:"bold"}}],italic:[{inline:"i",remove:"all"},{inline:"em",remove:"all"},{inline:"span",styles:{fontStyle:"italic"}}],underline:[{inline:"u",remove:"all"},{inline:"span",styles:{textDecoration:"underline"},exact:true}],strikethrough:[{inline:"strike",remove:"all"},{inline:"span",styles:{textDecoration:"line-through"},exact:true}],fontname:{inline:"font",attributes:{face:"%value"}},fontsize:{inline:"font",attributes:{size:function(f){return a.inArray(e,f.value)+1}}},forecolor:{inline:"font",attributes:{color:"%value"}},hilitecolor:{inline:"font",styles:{backgroundColor:"%value"}}});a.each("b,i,u,strike".split(","),function(f){d.addValidElements(f+"[*]")});if(!d.getElementRule("font")){d.addValidElements("font[face|size|color|style]")}a.each(c.split(","),function(f){var h=d.getElementRule(f),g;if(h){if(!h.attributes.align){h.attributes.align={};h.attributesOrder.push("align")}}});b.onNodeChange.add(function(g,k){var j,f,h,i;f=g.dom.getParent(g.selection.getNode(),"font");if(f){h=f.face;i=f.size}if(j=k.get("fontselect")){j.select(function(l){return l==h})}if(j=k.get("fontsizeselect")){j.select(function(m){var l=a.inArray(e,m.fontSize);return l+1==i})}})})},getInfo:function(){return{longname:"LegacyOutput",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/legacyoutput",version:a.majorVersion+"."+a.minorVersion}}});a.PluginManager.add("legacyoutput",a.plugins.LegacyOutput)})(tinymce); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/legacyoutput/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/legacyoutput/editor_plugin_src.js
new file mode 100644
index 00000000..3cdcde57
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/legacyoutput/editor_plugin_src.js
@@ -0,0 +1,139 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ *
+ * This plugin will force TinyMCE to produce deprecated legacy output such as font elements, u elements, align
+ * attributes and so forth. There are a few cases where these old items might be needed for example in email applications or with Flash
+ *
+ * However you should NOT use this plugin if you are building some system that produces web contents such as a CMS. All these elements are
+ * not apart of the newer specifications for HTML and XHTML.
+ */
+
+(function(tinymce) {
+ // Override inline_styles setting to force TinyMCE to produce deprecated contents
+ tinymce.onAddEditor.addToTop(function(tinymce, editor) {
+ editor.settings.inline_styles = false;
+ });
+
+ // Create the legacy ouput plugin
+ tinymce.create('tinymce.plugins.LegacyOutput', {
+ init : function(editor) {
+ editor.onInit.add(function() {
+ var alignElements = 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img',
+ fontSizes = tinymce.explode(editor.settings.font_size_style_values),
+ schema = editor.schema;
+
+ // Override some internal formats to produce legacy elements and attributes
+ editor.formatter.register({
+ // Change alignment formats to use the deprecated align attribute
+ alignleft : {selector : alignElements, attributes : {align : 'left'}},
+ aligncenter : {selector : alignElements, attributes : {align : 'center'}},
+ alignright : {selector : alignElements, attributes : {align : 'right'}},
+ alignfull : {selector : alignElements, attributes : {align : 'justify'}},
+
+ // Change the basic formatting elements to use deprecated element types
+ bold : [
+ {inline : 'b', remove : 'all'},
+ {inline : 'strong', remove : 'all'},
+ {inline : 'span', styles : {fontWeight : 'bold'}}
+ ],
+ italic : [
+ {inline : 'i', remove : 'all'},
+ {inline : 'em', remove : 'all'},
+ {inline : 'span', styles : {fontStyle : 'italic'}}
+ ],
+ underline : [
+ {inline : 'u', remove : 'all'},
+ {inline : 'span', styles : {textDecoration : 'underline'}, exact : true}
+ ],
+ strikethrough : [
+ {inline : 'strike', remove : 'all'},
+ {inline : 'span', styles : {textDecoration: 'line-through'}, exact : true}
+ ],
+
+ // Change font size and font family to use the deprecated font element
+ fontname : {inline : 'font', attributes : {face : '%value'}},
+ fontsize : {
+ inline : 'font',
+ attributes : {
+ size : function(vars) {
+ return tinymce.inArray(fontSizes, vars.value) + 1;
+ }
+ }
+ },
+
+ // Setup font elements for colors as well
+ forecolor : {inline : 'font', attributes : {color : '%value'}},
+ hilitecolor : {inline : 'font', styles : {backgroundColor : '%value'}}
+ });
+
+ // Check that deprecated elements are allowed if not add them
+ tinymce.each('b,i,u,strike'.split(','), function(name) {
+ schema.addValidElements(name + '[*]');
+ });
+
+ // Add font element if it's missing
+ if (!schema.getElementRule("font"))
+ schema.addValidElements("font[face|size|color|style]");
+
+ // Add the missing and depreacted align attribute for the serialization engine
+ tinymce.each(alignElements.split(','), function(name) {
+ var rule = schema.getElementRule(name), found;
+
+ if (rule) {
+ if (!rule.attributes.align) {
+ rule.attributes.align = {};
+ rule.attributesOrder.push('align');
+ }
+ }
+ });
+
+ // Listen for the onNodeChange event so that we can do special logic for the font size and font name drop boxes
+ editor.onNodeChange.add(function(editor, control_manager) {
+ var control, fontElm, fontName, fontSize;
+
+ // Find font element get it's name and size
+ fontElm = editor.dom.getParent(editor.selection.getNode(), 'font');
+ if (fontElm) {
+ fontName = fontElm.face;
+ fontSize = fontElm.size;
+ }
+
+ // Select/unselect the font name in droplist
+ if (control = control_manager.get('fontselect')) {
+ control.select(function(value) {
+ return value == fontName;
+ });
+ }
+
+ // Select/unselect the font size in droplist
+ if (control = control_manager.get('fontsizeselect')) {
+ control.select(function(value) {
+ var index = tinymce.inArray(fontSizes, value.fontSize);
+
+ return index + 1 == fontSize;
+ });
+ }
+ });
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'LegacyOutput',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/legacyoutput',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('legacyoutput', tinymce.plugins.LegacyOutput);
+})(tinymce);
diff --git a/askbot/media/js/tinymce/plugins/lists/editor_plugin.js b/askbot/media/js/tinymce/plugins/lists/editor_plugin.js
new file mode 100644
index 00000000..507331fb
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/lists/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var e=tinymce.each,r=tinymce.dom.Event,g;function p(t,s){while(t&&(t.nodeType===8||(t.nodeType===3&&/^[ \t\n\r]*$/.test(t.nodeValue)))){t=s(t)}return t}function b(s){return p(s,function(t){return t.previousSibling})}function i(s){return p(s,function(t){return t.nextSibling})}function d(s,u,t){return s.dom.getParent(u,function(v){return tinymce.inArray(t,v)!==-1})}function n(s){return s&&(s.tagName==="OL"||s.tagName==="UL")}function c(u,v){var t,w,s;t=b(u.lastChild);while(n(t)){w=t;t=b(w.previousSibling)}if(w){s=v.create("li",{style:"list-style-type: none;"});v.split(u,w);v.insertAfter(s,w);s.appendChild(w);s.appendChild(w);u=s.previousSibling}return u}function m(t,s,u){t=a(t,s,u);return o(t,s,u)}function a(u,s,v){var t=b(u.previousSibling);if(t){return h(t,u,s?t:false,v)}else{return u}}function o(u,t,v){var s=i(u.nextSibling);if(s){return h(u,s,t?s:false,v)}else{return u}}function h(u,s,t,v){if(l(u,s,!!t,v)){return f(u,s,t)}else{if(u&&u.tagName==="LI"&&n(s)){u.appendChild(s)}}return s}function l(u,t,s,v){if(!u||!t){return false}else{if(u.tagName==="LI"&&t.tagName==="LI"){return t.style.listStyleType==="none"||j(t)}else{if(n(u)){return(u.tagName===t.tagName&&(s||u.style.listStyleType===t.style.listStyleType))||q(t)}else{return v&&u.tagName==="P"&&t.tagName==="P"}}}}function q(t){var s=i(t.firstChild),u=b(t.lastChild);return s&&u&&n(t)&&s===u&&(n(s)||s.style.listStyleType==="none"||j(s))}function j(u){var t=i(u.firstChild),s=b(u.lastChild);return t&&s&&t===s&&n(t)}function f(w,v,s){var u=b(w.lastChild),t=i(v.firstChild);if(w.tagName==="P"){w.appendChild(w.ownerDocument.createElement("br"))}while(v.firstChild){w.appendChild(v.firstChild)}if(s){w.style.listStyleType=s.style.listStyleType}v.parentNode.removeChild(v);h(u,t,false);return w}function k(t,u){var s;if(!u.is(t,"li,ol,ul")){s=u.getParent(t,"li");if(s){t=s}}return t}tinymce.create("tinymce.plugins.Lists",{init:function(y){var v="TABBING";var s="EMPTY";var J="ESCAPE";var z="PARAGRAPH";var N="UNKNOWN";var x=N;function E(U){return U.keyCode===tinymce.VK.TAB&&!(U.altKey||U.ctrlKey)&&(y.queryCommandState("InsertUnorderedList")||y.queryCommandState("InsertOrderedList"))}function w(){var U=B();var W=U.parentNode.parentNode;var V=U.parentNode.lastChild===U;return V&&!t(W)&&P(U)}function t(U){if(n(U)){return U.parentNode&&U.parentNode.tagName==="LI"}else{return U.tagName==="LI"}}function F(){return y.selection.isCollapsed()&&P(B())}function B(){var U=y.selection.getStart();return((U.tagName=="BR"||U.tagName=="")&&U.parentNode.tagName=="LI")?U.parentNode:U}function P(U){var V=U.childNodes.length;if(U.tagName==="LI"){return V==0?true:V==1&&(U.firstChild.tagName==""||U.firstChild.tagName=="BR"||H(U))}return false}function H(U){var V=tinymce.grep(U.parentNode.childNodes,function(Y){return Y.tagName=="LI"});var W=U==V[V.length-1];var X=U.firstChild;return tinymce.isIE9&&W&&(X.nodeValue==String.fromCharCode(160)||X.nodeValue==String.fromCharCode(32))}function T(U){return U.keyCode===tinymce.VK.ENTER}function A(U){return T(U)&&!U.shiftKey}function M(U){if(E(U)){return v}else{if(A(U)&&w()){return N}else{if(A(U)&&F()){return s}else{return N}}}}function D(U,V){if(x==v||x==s||tinymce.isGecko&&x==J){r.cancel(V)}}function C(){var U=y.selection.getRng(true);var V=U.startContainer;if(V.nodeType==3){var W=V.nodeValue;if(tinymce.isIE9&&W.length>1&&W.charCodeAt(W.length-1)==32){return(U.endOffset==W.length-1)}else{return(U.endOffset==W.length)}}else{if(V.nodeType==1){return U.endOffset==V.childNodes.length}}return false}function I(){var W=y.selection.getNode();var V="h1,h2,h3,h4,h5,h6,p,div";var U=y.dom.is(W,V)&&W.parentNode.tagName==="LI"&&W.parentNode.lastChild===W;return y.selection.isCollapsed()&&U&&C()}function K(W,Y){if(A(Y)&&I()){var X=W.selection.getNode();var V=W.dom.create("li");var U=W.dom.getParent(X,"li");W.dom.insertAfter(V,U);if(tinymce.isIE6||tinymce.isIE7||tinyMCE.isIE8){W.selection.setCursorLocation(V,1)}else{W.selection.setCursorLocation(V,0)}Y.preventDefault()}}function u(X,Z){var ac;if(!tinymce.isGecko){return}var V=X.selection.getStart();if(Z.keyCode!=tinymce.VK.BACKSPACE||V.tagName!=="IMG"){return}function W(ag){var ah=ag.firstChild;var af=null;do{if(!ah){break}if(ah.tagName==="LI"){af=ah}}while(ah=ah.nextSibling);return af}function ae(ag,af){while(ag.childNodes.length>0){af.appendChild(ag.childNodes[0])}}ac=V.parentNode.previousSibling;if(!ac){return}var aa;if(ac.tagName==="UL"||ac.tagName==="OL"){aa=ac}else{if(ac.previousSibling&&(ac.previousSibling.tagName==="UL"||ac.previousSibling.tagName==="OL")){aa=ac.previousSibling}else{return}}var ad=W(aa);var U=X.dom.createRng();U.setStart(ad,1);U.setEnd(ad,1);X.selection.setRng(U);X.selection.collapse(true);var Y=X.selection.getBookmark();var ab=V.parentNode.cloneNode(true);if(ab.tagName==="P"||ab.tagName==="DIV"){ae(ab,ad)}else{ad.appendChild(ab)}V.parentNode.parentNode.removeChild(V.parentNode);X.selection.moveToBookmark(Y)}function G(U){var V=y.dom.getParent(U,"ol,ul");if(V!=null){var W=V.lastChild;y.selection.setCursorLocation(W,0)}}this.ed=y;y.addCommand("Indent",this.indent,this);y.addCommand("Outdent",this.outdent,this);y.addCommand("InsertUnorderedList",function(){this.applyList("UL","OL")},this);y.addCommand("InsertOrderedList",function(){this.applyList("OL","UL")},this);y.onInit.add(function(){y.editorCommands.addCommands({outdent:function(){var V=y.selection,W=y.dom;function U(X){X=W.getParent(X,W.isBlock);return X&&(parseInt(y.dom.getStyle(X,"margin-left")||0,10)+parseInt(y.dom.getStyle(X,"padding-left")||0,10))>0}return U(V.getStart())||U(V.getEnd())||y.queryCommandState("InsertOrderedList")||y.queryCommandState("InsertUnorderedList")}},"state")});y.onKeyUp.add(function(V,W){if(x==v){V.execCommand(W.shiftKey?"Outdent":"Indent",true,null);x=N;return r.cancel(W)}else{if(x==s){var U=B();var Y=V.settings.list_outdent_on_enter===true||W.shiftKey;V.execCommand(Y?"Outdent":"Indent",true,null);if(tinymce.isIE){G(U)}return r.cancel(W)}else{if(x==J){if(tinymce.isIE6||tinymce.isIE7||tinymce.isIE8){var X=V.getDoc().createTextNode("\uFEFF");V.selection.getNode().appendChild(X)}else{if(tinymce.isIE9||tinymce.isGecko){V.execCommand("Outdent");return r.cancel(W)}}}}}});function L(V,U){var W=y.getDoc().createTextNode("\uFEFF");V.insertBefore(W,U);y.selection.setCursorLocation(W,0);y.execCommand("mceRepaint")}function R(V,X){if(T(X)){var U=B();if(U){var W=U.parentNode;var Y=W&&W.parentNode;if(Y&&Y.nodeName=="LI"&&Y.firstChild==W&&U==W.firstChild){L(Y,W)}}}}function S(V,X){if(T(X)){var U=B();if(V.dom.select("ul li",U).length===1){var W=U.firstChild;L(U,W)}}}function Q(V,Z){function W(ad,aa){var ac=[];var ae=new tinymce.dom.TreeWalker(aa,ad);for(var ab=ae.current();ab;ab=ae.next()){if(V.dom.is(ab,"ol,ul,li")){ac.push(ab)}}return ac}if(Z.keyCode==tinymce.VK.BACKSPACE){var U=B();if(U){var Y=V.dom.getParent(U,"ol,ul");if(Y&&Y.firstChild===U){var X=W(Y,U);V.execCommand("Outdent",false,X);V.undoManager.add();return r.cancel(Z)}}}}function O(V,X){var U=B();if(X.keyCode===tinymce.VK.BACKSPACE&&V.dom.is(U,"li")&&U.parentNode.firstChild!==U){if(V.dom.select("ul,ol",U).length===1){var Z=U.previousSibling;V.dom.remove(V.dom.select("br",U));V.dom.remove(U,true);var W=tinymce.grep(Z.childNodes,function(aa){return aa.nodeType===3});if(W.length===1){var Y=W[0];V.selection.setCursorLocation(Y,Y.length)}V.undoManager.add();return r.cancel(X)}}}y.onKeyDown.add(function(U,V){x=M(V)});y.onKeyDown.add(D);y.onKeyDown.add(u);y.onKeyDown.add(K);if(tinymce.isGecko){y.onKeyUp.add(R)}if(tinymce.isIE8){y.onKeyUp.add(S)}if(tinymce.isGecko||tinymce.isWebKit){y.onKeyDown.add(Q)}if(tinymce.isWebKit){y.onKeyDown.add(O)}},applyList:function(y,v){var C=this,z=C.ed,I=z.dom,s=[],H=false,u=false,w=false,B,G=z.selection.getSelectedBlocks();function E(t){if(t&&t.tagName==="BR"){I.remove(t)}}function F(M){var N=I.create(y),t;function L(O){if(O.style.marginLeft||O.style.paddingLeft){C.adjustPaddingFunction(false)(O)}}if(M.tagName==="LI"){}else{if(M.tagName==="P"||M.tagName==="DIV"||M.tagName==="BODY"){K(M,function(P,O){J(P,O,M.tagName==="BODY"?null:P.parentNode);t=P.parentNode;L(t);E(O)});if(t){if(t.tagName==="LI"&&(M.tagName==="P"||G.length>1)){I.split(t.parentNode.parentNode,t.parentNode)}m(t.parentNode,true)}return}else{t=I.create("li");I.insertAfter(t,M);t.appendChild(M);L(M);M=t}}I.insertAfter(N,M);N.appendChild(M);m(N,true);s.push(M)}function J(P,L,N){var t,O=P,M;while(!I.isBlock(P.parentNode)&&P.parentNode!==I.getRoot()){P=I.split(P.parentNode,P.previousSibling);P=P.nextSibling;O=P}if(N){t=N.cloneNode(true);P.parentNode.insertBefore(t,P);while(t.firstChild){I.remove(t.firstChild)}t=I.rename(t,"li")}else{t=I.create("li");P.parentNode.insertBefore(t,P)}while(O&&O!=L){M=O.nextSibling;t.appendChild(O);O=M}if(t.childNodes.length===0){t.innerHTML='<br _mce_bogus="1" />'}F(t)}function K(Q,T){var N,R,O=3,L=1,t="br,ul,ol,p,div,h1,h2,h3,h4,h5,h6,table,blockquote,address,pre,form,center,dl";function P(X,U){var V=I.createRng(),W;g.keep=true;z.selection.moveToBookmark(g);g.keep=false;W=z.selection.getRng(true);if(!U){U=X.parentNode.lastChild}V.setStartBefore(X);V.setEndAfter(U);return !(V.compareBoundaryPoints(O,W)>0||V.compareBoundaryPoints(L,W)<=0)}function S(U){if(U.nextSibling){return U.nextSibling}if(!I.isBlock(U.parentNode)&&U.parentNode!==I.getRoot()){return S(U.parentNode)}}N=Q.firstChild;var M=false;e(I.select(t,Q),function(U){if(U.hasAttribute&&U.hasAttribute("_mce_bogus")){return true}if(P(N,U)){I.addClass(U,"_mce_tagged_br");N=S(U)}});M=(N&&P(N,undefined));N=Q.firstChild;e(I.select(t,Q),function(V){var U=S(V);if(V.hasAttribute&&V.hasAttribute("_mce_bogus")){return true}if(I.hasClass(V,"_mce_tagged_br")){T(N,V,R);R=null}else{R=V}N=U});if(M){T(N,undefined,R)}}function D(t){K(t,function(M,L,N){J(M,L);E(L);E(N)})}function A(t){if(tinymce.inArray(s,t)!==-1){return}if(t.parentNode.tagName===v){I.split(t.parentNode,t);F(t);o(t.parentNode,false)}s.push(t)}function x(M){var O,N,L,t;if(tinymce.inArray(s,M)!==-1){return}M=c(M,I);while(I.is(M.parentNode,"ol,ul,li")){I.split(M.parentNode,M)}s.push(M);M=I.rename(M,"p");L=m(M,false,z.settings.force_br_newlines);if(L===M){O=M.firstChild;while(O){if(I.isBlock(O)){O=I.split(O.parentNode,O);t=true;N=O.nextSibling&&O.nextSibling.firstChild}else{N=O.nextSibling;if(t&&O.tagName==="BR"){I.remove(O)}t=false}O=N}}}e(G,function(t){t=k(t,I);if(t.tagName===v||(t.tagName==="LI"&&t.parentNode.tagName===v)){u=true}else{if(t.tagName===y||(t.tagName==="LI"&&t.parentNode.tagName===y)){H=true}else{w=true}}});if(w&&!H||u||G.length===0){B={LI:A,H1:F,H2:F,H3:F,H4:F,H5:F,H6:F,P:F,BODY:F,DIV:G.length>1?F:D,defaultAction:D,elements:this.selectedBlocks()}}else{B={defaultAction:x,elements:this.selectedBlocks(),processEvenIfEmpty:true}}this.process(B)},indent:function(){var u=this.ed,w=u.dom,x=[];function s(z){var y=w.create("li",{style:"list-style-type: none;"});w.insertAfter(y,z);return y}function t(B){var y=s(B),D=w.getParent(B,"ol,ul"),C=D.tagName,E=w.getStyle(D,"list-style-type"),A={},z;if(E!==""){A.style="list-style-type: "+E+";"}z=w.create(C,A);y.appendChild(z);return z}function v(z){if(!d(u,z,x)){z=c(z,w);var y=t(z);y.appendChild(z);m(y.parentNode,false);m(y,false);x.push(z)}}this.process({LI:v,defaultAction:this.adjustPaddingFunction(true),elements:this.selectedBlocks()})},outdent:function(y,x){var w=this,u=w.ed,z=u.dom,s=[];function A(t){var C,B,D;if(!d(u,t,s)){if(z.getStyle(t,"margin-left")!==""||z.getStyle(t,"padding-left")!==""){return w.adjustPaddingFunction(false)(t)}D=z.getStyle(t,"text-align",true);if(D==="center"||D==="right"){z.setStyle(t,"text-align","left");return}t=c(t,z);C=t.parentNode;B=t.parentNode.parentNode;if(B.tagName==="P"){z.split(B,t.parentNode)}else{z.split(C,t);if(B.tagName==="LI"){z.split(B,t)}else{if(!z.is(B,"ol,ul")){z.rename(t,"p")}}}s.push(t)}}var v=x&&tinymce.is(x,"array")?x:this.selectedBlocks();this.process({LI:A,defaultAction:this.adjustPaddingFunction(false),elements:v});e(s,m)},process:function(y){var F=this,w=F.ed.selection,z=F.ed.dom,E,u;function B(t){var s=tinymce.grep(t.childNodes,function(H){return !(H.nodeName==="BR"||H.nodeName==="SPAN"&&z.getAttrib(H,"data-mce-type")=="bookmark"||H.nodeType==3&&(H.nodeValue==String.fromCharCode(160)||H.nodeValue==""))});return s.length===0}function x(s){z.removeClass(s,"_mce_act_on");if(!s||s.nodeType!==1||!y.processEvenIfEmpty&&E.length>1&&B(s)){return}s=k(s,z);var t=y[s.tagName];if(!t){t=y.defaultAction}t(s)}function v(s){F.splitSafeEach(s.childNodes,x)}function C(s,t){return t>=0&&s.hasChildNodes()&&t<s.childNodes.length&&s.childNodes[t].tagName==="BR"}function D(){var t=w.getNode();var s=z.getParent(t,"td");return s!==null}E=y.elements;u=w.getRng(true);if(!u.collapsed){if(C(u.endContainer,u.endOffset-1)){u.setEnd(u.endContainer,u.endOffset-1);w.setRng(u)}if(C(u.startContainer,u.startOffset)){u.setStart(u.startContainer,u.startOffset+1);w.setRng(u)}}if(tinymce.isIE8){var G=F.ed.selection.getNode();if(G.tagName==="LI"&&!(G.parentNode.lastChild===G)){var A=F.ed.getDoc().createTextNode("\uFEFF");G.appendChild(A)}}g=w.getBookmark();y.OL=y.UL=v;F.splitSafeEach(E,x);w.moveToBookmark(g);g=null;if(!D()){F.ed.execCommand("mceRepaint")}},splitSafeEach:function(t,s){if(tinymce.isGecko&&(/Firefox\/[12]\.[0-9]/.test(navigator.userAgent)||/Firefox\/3\.[0-4]/.test(navigator.userAgent))){this.classBasedEach(t,s)}else{e(t,s)}},classBasedEach:function(v,u){var w=this.ed.dom,s,t;e(v,function(x){w.addClass(x,"_mce_act_on")});s=w.select("._mce_act_on");while(s.length>0){t=s.shift();w.removeClass(t,"_mce_act_on");u(t);s=w.select("._mce_act_on")}},adjustPaddingFunction:function(u){var s,v,t=this.ed;s=t.settings.indentation;v=/[a-z%]+/i.exec(s);s=parseInt(s,10);return function(w){var y,x;y=parseInt(t.dom.getStyle(w,"margin-left")||0,10)+parseInt(t.dom.getStyle(w,"padding-left")||0,10);if(u){x=y+s}else{x=y-s}t.dom.setStyle(w,"padding-left","");t.dom.setStyle(w,"margin-left",x>0?x+v:"")}},selectedBlocks:function(){var s=this.ed;var t=s.selection.getSelectedBlocks();return t.length==0?[s.dom.getRoot()]:t},getInfo:function(){return{longname:"Lists",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/lists",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("lists",tinymce.plugins.Lists)}()); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/lists/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/lists/editor_plugin_src.js
new file mode 100644
index 00000000..80e1a77c
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/lists/editor_plugin_src.js
@@ -0,0 +1,952 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2011, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var each = tinymce.each, Event = tinymce.dom.Event, bookmark;
+
+ // Skips text nodes that only contain whitespace since they aren't semantically important.
+ function skipWhitespaceNodes(e, next) {
+ while (e && (e.nodeType === 8 || (e.nodeType === 3 && /^[ \t\n\r]*$/.test(e.nodeValue)))) {
+ e = next(e);
+ }
+ return e;
+ }
+
+ function skipWhitespaceNodesBackwards(e) {
+ return skipWhitespaceNodes(e, function(e) {
+ return e.previousSibling;
+ });
+ }
+
+ function skipWhitespaceNodesForwards(e) {
+ return skipWhitespaceNodes(e, function(e) {
+ return e.nextSibling;
+ });
+ }
+
+ function hasParentInList(ed, e, list) {
+ return ed.dom.getParent(e, function(p) {
+ return tinymce.inArray(list, p) !== -1;
+ });
+ }
+
+ function isList(e) {
+ return e && (e.tagName === 'OL' || e.tagName === 'UL');
+ }
+
+ function splitNestedLists(element, dom) {
+ var tmp, nested, wrapItem;
+ tmp = skipWhitespaceNodesBackwards(element.lastChild);
+ while (isList(tmp)) {
+ nested = tmp;
+ tmp = skipWhitespaceNodesBackwards(nested.previousSibling);
+ }
+ if (nested) {
+ wrapItem = dom.create('li', { style: 'list-style-type: none;'});
+ dom.split(element, nested);
+ dom.insertAfter(wrapItem, nested);
+ wrapItem.appendChild(nested);
+ wrapItem.appendChild(nested);
+ element = wrapItem.previousSibling;
+ }
+ return element;
+ }
+
+ function attemptMergeWithAdjacent(e, allowDifferentListStyles, mergeParagraphs) {
+ e = attemptMergeWithPrevious(e, allowDifferentListStyles, mergeParagraphs);
+ return attemptMergeWithNext(e, allowDifferentListStyles, mergeParagraphs);
+ }
+
+ function attemptMergeWithPrevious(e, allowDifferentListStyles, mergeParagraphs) {
+ var prev = skipWhitespaceNodesBackwards(e.previousSibling);
+ if (prev) {
+ return attemptMerge(prev, e, allowDifferentListStyles ? prev : false, mergeParagraphs);
+ } else {
+ return e;
+ }
+ }
+
+ function attemptMergeWithNext(e, allowDifferentListStyles, mergeParagraphs) {
+ var next = skipWhitespaceNodesForwards(e.nextSibling);
+ if (next) {
+ return attemptMerge(e, next, allowDifferentListStyles ? next : false, mergeParagraphs);
+ } else {
+ return e;
+ }
+ }
+
+ function attemptMerge(e1, e2, differentStylesMasterElement, mergeParagraphs) {
+ if (canMerge(e1, e2, !!differentStylesMasterElement, mergeParagraphs)) {
+ return merge(e1, e2, differentStylesMasterElement);
+ } else if (e1 && e1.tagName === 'LI' && isList(e2)) {
+ // Fix invalidly nested lists.
+ e1.appendChild(e2);
+ }
+ return e2;
+ }
+
+ function canMerge(e1, e2, allowDifferentListStyles, mergeParagraphs) {
+ if (!e1 || !e2) {
+ return false;
+ } else if (e1.tagName === 'LI' && e2.tagName === 'LI') {
+ return e2.style.listStyleType === 'none' || containsOnlyAList(e2);
+ } else if (isList(e1)) {
+ return (e1.tagName === e2.tagName && (allowDifferentListStyles || e1.style.listStyleType === e2.style.listStyleType)) || isListForIndent(e2);
+ } else return mergeParagraphs && e1.tagName === 'P' && e2.tagName === 'P';
+ }
+
+ function isListForIndent(e) {
+ var firstLI = skipWhitespaceNodesForwards(e.firstChild), lastLI = skipWhitespaceNodesBackwards(e.lastChild);
+ return firstLI && lastLI && isList(e) && firstLI === lastLI && (isList(firstLI) || firstLI.style.listStyleType === 'none' || containsOnlyAList(firstLI));
+ }
+
+ function containsOnlyAList(e) {
+ var firstChild = skipWhitespaceNodesForwards(e.firstChild), lastChild = skipWhitespaceNodesBackwards(e.lastChild);
+ return firstChild && lastChild && firstChild === lastChild && isList(firstChild);
+ }
+
+ function merge(e1, e2, masterElement) {
+ var lastOriginal = skipWhitespaceNodesBackwards(e1.lastChild), firstNew = skipWhitespaceNodesForwards(e2.firstChild);
+ if (e1.tagName === 'P') {
+ e1.appendChild(e1.ownerDocument.createElement('br'));
+ }
+ while (e2.firstChild) {
+ e1.appendChild(e2.firstChild);
+ }
+ if (masterElement) {
+ e1.style.listStyleType = masterElement.style.listStyleType;
+ }
+ e2.parentNode.removeChild(e2);
+ attemptMerge(lastOriginal, firstNew, false);
+ return e1;
+ }
+
+ function findItemToOperateOn(e, dom) {
+ var item;
+ if (!dom.is(e, 'li,ol,ul')) {
+ item = dom.getParent(e, 'li');
+ if (item) {
+ e = item;
+ }
+ }
+ return e;
+ }
+
+ tinymce.create('tinymce.plugins.Lists', {
+ init: function(ed) {
+ var LIST_TABBING = 'TABBING';
+ var LIST_EMPTY_ITEM = 'EMPTY';
+ var LIST_ESCAPE = 'ESCAPE';
+ var LIST_PARAGRAPH = 'PARAGRAPH';
+ var LIST_UNKNOWN = 'UNKNOWN';
+ var state = LIST_UNKNOWN;
+
+ function isTabInList(e) {
+ // Don't indent on Ctrl+Tab or Alt+Tab
+ return e.keyCode === tinymce.VK.TAB && !(e.altKey || e.ctrlKey) &&
+ (ed.queryCommandState('InsertUnorderedList') || ed.queryCommandState('InsertOrderedList'));
+ }
+
+ function isOnLastListItem() {
+ var li = getLi();
+ var grandParent = li.parentNode.parentNode;
+ var isLastItem = li.parentNode.lastChild === li;
+ return isLastItem && !isNestedList(grandParent) && isEmptyListItem(li);
+ }
+
+ function isNestedList(grandParent) {
+ if (isList(grandParent)) {
+ return grandParent.parentNode && grandParent.parentNode.tagName === 'LI';
+ } else {
+ return grandParent.tagName === 'LI';
+ }
+ }
+
+ function isInEmptyListItem() {
+ return ed.selection.isCollapsed() && isEmptyListItem(getLi());
+ }
+
+ function getLi() {
+ var n = ed.selection.getStart();
+ // Get start will return BR if the LI only contains a BR or an empty element as we use these to fix caret position
+ return ((n.tagName == 'BR' || n.tagName == '') && n.parentNode.tagName == 'LI') ? n.parentNode : n;
+ }
+
+ function isEmptyListItem(li) {
+ var numChildren = li.childNodes.length;
+ if (li.tagName === 'LI') {
+ return numChildren == 0 ? true : numChildren == 1 && (li.firstChild.tagName == '' || li.firstChild.tagName == 'BR' || isEmptyIE9Li(li));
+ }
+ return false;
+ }
+
+ function isEmptyIE9Li(li) {
+ // only consider this to be last item if there is no list item content or that content is nbsp or space since IE9 creates these
+ var lis = tinymce.grep(li.parentNode.childNodes, function(n) {return n.tagName == 'LI'});
+ var isLastLi = li == lis[lis.length - 1];
+ var child = li.firstChild;
+ return tinymce.isIE9 && isLastLi && (child.nodeValue == String.fromCharCode(160) || child.nodeValue == String.fromCharCode(32));
+ }
+
+ function isEnter(e) {
+ return e.keyCode === tinymce.VK.ENTER;
+ }
+
+ function isEnterWithoutShift(e) {
+ return isEnter(e) && !e.shiftKey;
+ }
+
+ function getListKeyState(e) {
+ if (isTabInList(e)) {
+ return LIST_TABBING;
+ } else if (isEnterWithoutShift(e) && isOnLastListItem()) {
+ // Returns LIST_UNKNOWN since breaking out of lists is handled by the EnterKey.js logic now
+ //return LIST_ESCAPE;
+ return LIST_UNKNOWN;
+ } else if (isEnterWithoutShift(e) && isInEmptyListItem()) {
+ return LIST_EMPTY_ITEM;
+ } else {
+ return LIST_UNKNOWN;
+ }
+ }
+
+ function cancelDefaultEvents(ed, e) {
+ // list escape is done manually using outdent as it does not create paragraphs correctly in td's
+ if (state == LIST_TABBING || state == LIST_EMPTY_ITEM || tinymce.isGecko && state == LIST_ESCAPE) {
+ Event.cancel(e);
+ }
+ }
+
+ function isCursorAtEndOfContainer() {
+ var range = ed.selection.getRng(true);
+ var startContainer = range.startContainer;
+ if (startContainer.nodeType == 3) {
+ var value = startContainer.nodeValue;
+ if (tinymce.isIE9 && value.length > 1 && value.charCodeAt(value.length-1) == 32) {
+ // IE9 places a space on the end of the text in some cases so ignore last char
+ return (range.endOffset == value.length-1);
+ } else {
+ return (range.endOffset == value.length);
+ }
+ } else if (startContainer.nodeType == 1) {
+ return range.endOffset == startContainer.childNodes.length;
+ }
+ return false;
+ }
+
+ /*
+ If we are at the end of a list item surrounded with an element, pressing enter should create a
+ new list item instead without splitting the element e.g. don't want to create new P or H1 tag
+ */
+ function isEndOfListItem() {
+ var node = ed.selection.getNode();
+ var validElements = 'h1,h2,h3,h4,h5,h6,p,div';
+ var isLastParagraphOfLi = ed.dom.is(node, validElements) && node.parentNode.tagName === 'LI' && node.parentNode.lastChild === node;
+ return ed.selection.isCollapsed() && isLastParagraphOfLi && isCursorAtEndOfContainer();
+ }
+
+ // Creates a new list item after the current selection's list item parent
+ function createNewLi(ed, e) {
+ if (isEnterWithoutShift(e) && isEndOfListItem()) {
+ var node = ed.selection.getNode();
+ var li = ed.dom.create("li");
+ var parentLi = ed.dom.getParent(node, 'li');
+ ed.dom.insertAfter(li, parentLi);
+
+ // Move caret to new list element.
+ if (tinymce.isIE6 || tinymce.isIE7 || tinyMCE.isIE8) {
+ // Removed this line since it would create an odd <&nbsp;> tag and placing the caret inside an empty LI is handled and should be handled by the selection logic
+ //li.appendChild(ed.dom.create("&nbsp;")); // IE needs an element within the bullet point
+ ed.selection.setCursorLocation(li, 1);
+ } else {
+ ed.selection.setCursorLocation(li, 0);
+ }
+ e.preventDefault();
+ }
+ }
+
+ function imageJoiningListItem(ed, e) {
+ var prevSibling;
+
+ if (!tinymce.isGecko)
+ return;
+
+ var n = ed.selection.getStart();
+ if (e.keyCode != tinymce.VK.BACKSPACE || n.tagName !== 'IMG')
+ return;
+
+ function lastLI(node) {
+ var child = node.firstChild;
+ var li = null;
+ do {
+ if (!child)
+ break;
+
+ if (child.tagName === 'LI')
+ li = child;
+ } while (child = child.nextSibling);
+
+ return li;
+ }
+
+ function addChildren(parentNode, destination) {
+ while (parentNode.childNodes.length > 0)
+ destination.appendChild(parentNode.childNodes[0]);
+ }
+
+ // Check if there is a previous sibling
+ prevSibling = n.parentNode.previousSibling;
+ if (!prevSibling)
+ return;
+
+ var ul;
+ if (prevSibling.tagName === 'UL' || prevSibling.tagName === 'OL')
+ ul = prevSibling;
+ else if (prevSibling.previousSibling && (prevSibling.previousSibling.tagName === 'UL' || prevSibling.previousSibling.tagName === 'OL'))
+ ul = prevSibling.previousSibling;
+ else
+ return;
+
+ var li = lastLI(ul);
+
+ // move the caret to the end of the list item
+ var rng = ed.dom.createRng();
+ rng.setStart(li, 1);
+ rng.setEnd(li, 1);
+ ed.selection.setRng(rng);
+ ed.selection.collapse(true);
+
+ // save a bookmark at the end of the list item
+ var bookmark = ed.selection.getBookmark();
+
+ // copy the image an its text to the list item
+ var clone = n.parentNode.cloneNode(true);
+ if (clone.tagName === 'P' || clone.tagName === 'DIV')
+ addChildren(clone, li);
+ else
+ li.appendChild(clone);
+
+ // remove the old copy of the image
+ n.parentNode.parentNode.removeChild(n.parentNode);
+
+ // move the caret where we saved the bookmark
+ ed.selection.moveToBookmark(bookmark);
+ }
+
+ // fix the cursor position to ensure it is correct in IE
+ function setCursorPositionToOriginalLi(li) {
+ var list = ed.dom.getParent(li, 'ol,ul');
+ if (list != null) {
+ var lastLi = list.lastChild;
+ // Removed this line since IE9 would report an DOM character error and placing the caret inside an empty LI is handled and should be handled by the selection logic
+ //lastLi.appendChild(ed.getDoc().createElement(''));
+ ed.selection.setCursorLocation(lastLi, 0);
+ }
+ }
+
+ this.ed = ed;
+ ed.addCommand('Indent', this.indent, this);
+ ed.addCommand('Outdent', this.outdent, this);
+ ed.addCommand('InsertUnorderedList', function() {
+ this.applyList('UL', 'OL');
+ }, this);
+ ed.addCommand('InsertOrderedList', function() {
+ this.applyList('OL', 'UL');
+ }, this);
+
+ ed.onInit.add(function() {
+ ed.editorCommands.addCommands({
+ 'outdent': function() {
+ var sel = ed.selection, dom = ed.dom;
+
+ function hasStyleIndent(n) {
+ n = dom.getParent(n, dom.isBlock);
+ return n && (parseInt(ed.dom.getStyle(n, 'margin-left') || 0, 10) + parseInt(ed.dom.getStyle(n, 'padding-left') || 0, 10)) > 0;
+ }
+
+ return hasStyleIndent(sel.getStart()) || hasStyleIndent(sel.getEnd()) || ed.queryCommandState('InsertOrderedList') || ed.queryCommandState('InsertUnorderedList');
+ }
+ }, 'state');
+ });
+
+ ed.onKeyUp.add(function(ed, e) {
+ if (state == LIST_TABBING) {
+ ed.execCommand(e.shiftKey ? 'Outdent' : 'Indent', true, null);
+ state = LIST_UNKNOWN;
+ return Event.cancel(e);
+ } else if (state == LIST_EMPTY_ITEM) {
+ var li = getLi();
+ var shouldOutdent = ed.settings.list_outdent_on_enter === true || e.shiftKey;
+ ed.execCommand(shouldOutdent ? 'Outdent' : 'Indent', true, null);
+ if (tinymce.isIE) {
+ setCursorPositionToOriginalLi(li);
+ }
+
+ return Event.cancel(e);
+ } else if (state == LIST_ESCAPE) {
+ if (tinymce.isIE6 || tinymce.isIE7 || tinymce.isIE8) {
+ // append a zero sized nbsp so that caret is positioned correctly in IE after escaping and applying formatting.
+ // if there is no text then applying formatting for e.g a H1 to the P tag immediately following list after
+ // escaping from it will cause the caret to be positioned on the last li instead of staying the in P tag.
+ var n = ed.getDoc().createTextNode('\uFEFF');
+ ed.selection.getNode().appendChild(n);
+ } else if (tinymce.isIE9 || tinymce.isGecko) {
+ // IE9 does not escape the list so we use outdent to do this and cancel the default behaviour
+ // Gecko does not create a paragraph outdenting inside a TD so default behaviour is cancelled and we outdent ourselves
+ ed.execCommand('Outdent');
+ return Event.cancel(e);
+ }
+ }
+ });
+
+ function fixListItem(parent, reference) {
+ // a zero-sized non-breaking space is placed in the empty list item so that the nested list is
+ // displayed on the below line instead of next to it
+ var n = ed.getDoc().createTextNode('\uFEFF');
+ parent.insertBefore(n, reference);
+ ed.selection.setCursorLocation(n, 0);
+ // repaint to remove rendering artifact. only visible when creating new list
+ ed.execCommand('mceRepaint');
+ }
+
+ function fixIndentedListItemForGecko(ed, e) {
+ if (isEnter(e)) {
+ var li = getLi();
+ if (li) {
+ var parent = li.parentNode;
+ var grandParent = parent && parent.parentNode;
+ if (grandParent && grandParent.nodeName == 'LI' && grandParent.firstChild == parent && li == parent.firstChild) {
+ fixListItem(grandParent, parent);
+ }
+ }
+ }
+ }
+
+ function fixIndentedListItemForIE8(ed, e) {
+ if (isEnter(e)) {
+ var li = getLi();
+ if (ed.dom.select('ul li', li).length === 1) {
+ var list = li.firstChild;
+ fixListItem(li, list);
+ }
+ }
+ }
+
+ function fixDeletingFirstCharOfList(ed, e) {
+ function listElements(list, li) {
+ var elements = [];
+ var walker = new tinymce.dom.TreeWalker(li, list);
+ for (var node = walker.current(); node; node = walker.next()) {
+ if (ed.dom.is(node, 'ol,ul,li')) {
+ elements.push(node);
+ }
+ }
+ return elements;
+ }
+
+ if (e.keyCode == tinymce.VK.BACKSPACE) {
+ var li = getLi();
+ if (li) {
+ var list = ed.dom.getParent(li, 'ol,ul');
+ if (list && list.firstChild === li) {
+ var elements = listElements(list, li);
+ ed.execCommand("Outdent", false, elements);
+ ed.undoManager.add();
+ return Event.cancel(e);
+ }
+ }
+ }
+ }
+
+ function fixDeletingEmptyLiInWebkit(ed, e) {
+ var li = getLi();
+ if (e.keyCode === tinymce.VK.BACKSPACE && ed.dom.is(li, 'li') && li.parentNode.firstChild!==li) {
+ if (ed.dom.select('ul,ol', li).length === 1) {
+ var prevLi = li.previousSibling;
+ ed.dom.remove(ed.dom.select('br', li));
+ ed.dom.remove(li, true);
+ var textNodes = tinymce.grep(prevLi.childNodes, function(n){ return n.nodeType === 3 });
+ if (textNodes.length === 1) {
+ var textNode = textNodes[0]
+ ed.selection.setCursorLocation(textNode, textNode.length);
+ }
+ ed.undoManager.add();
+ return Event.cancel(e);
+ }
+ }
+ }
+
+ ed.onKeyDown.add(function(_, e) { state = getListKeyState(e); });
+ ed.onKeyDown.add(cancelDefaultEvents);
+ ed.onKeyDown.add(imageJoiningListItem);
+ ed.onKeyDown.add(createNewLi);
+
+ if (tinymce.isGecko) {
+ ed.onKeyUp.add(fixIndentedListItemForGecko);
+ }
+ if (tinymce.isIE8) {
+ ed.onKeyUp.add(fixIndentedListItemForIE8);
+ }
+ if (tinymce.isGecko || tinymce.isWebKit) {
+ ed.onKeyDown.add(fixDeletingFirstCharOfList);
+ }
+ if (tinymce.isWebKit) {
+ ed.onKeyDown.add(fixDeletingEmptyLiInWebkit);
+ }
+ },
+
+ applyList: function(targetListType, oppositeListType) {
+ var t = this, ed = t.ed, dom = ed.dom, applied = [], hasSameType = false, hasOppositeType = false, hasNonList = false, actions,
+ selectedBlocks = ed.selection.getSelectedBlocks();
+
+ function cleanupBr(e) {
+ if (e && e.tagName === 'BR') {
+ dom.remove(e);
+ }
+ }
+
+ function makeList(element) {
+ var list = dom.create(targetListType), li;
+
+ function adjustIndentForNewList(element) {
+ // If there's a margin-left, outdent one level to account for the extra list margin.
+ if (element.style.marginLeft || element.style.paddingLeft) {
+ t.adjustPaddingFunction(false)(element);
+ }
+ }
+
+ if (element.tagName === 'LI') {
+ // No change required.
+ } else if (element.tagName === 'P' || element.tagName === 'DIV' || element.tagName === 'BODY') {
+ processBrs(element, function(startSection, br) {
+ doWrapList(startSection, br, element.tagName === 'BODY' ? null : startSection.parentNode);
+ li = startSection.parentNode;
+ adjustIndentForNewList(li);
+ cleanupBr(br);
+ });
+ if (li) {
+ if (li.tagName === 'LI' && (element.tagName === 'P' || selectedBlocks.length > 1)) {
+ dom.split(li.parentNode.parentNode, li.parentNode);
+ }
+ attemptMergeWithAdjacent(li.parentNode, true);
+ }
+ return;
+ } else {
+ // Put the list around the element.
+ li = dom.create('li');
+ dom.insertAfter(li, element);
+ li.appendChild(element);
+ adjustIndentForNewList(element);
+ element = li;
+ }
+ dom.insertAfter(list, element);
+ list.appendChild(element);
+ attemptMergeWithAdjacent(list, true);
+ applied.push(element);
+ }
+
+ function doWrapList(start, end, template) {
+ var li, n = start, tmp;
+ while (!dom.isBlock(start.parentNode) && start.parentNode !== dom.getRoot()) {
+ start = dom.split(start.parentNode, start.previousSibling);
+ start = start.nextSibling;
+ n = start;
+ }
+ if (template) {
+ li = template.cloneNode(true);
+ start.parentNode.insertBefore(li, start);
+ while (li.firstChild) dom.remove(li.firstChild);
+ li = dom.rename(li, 'li');
+ } else {
+ li = dom.create('li');
+ start.parentNode.insertBefore(li, start);
+ }
+ while (n && n != end) {
+ tmp = n.nextSibling;
+ li.appendChild(n);
+ n = tmp;
+ }
+ if (li.childNodes.length === 0) {
+ li.innerHTML = '<br _mce_bogus="1" />';
+ }
+ makeList(li);
+ }
+
+ function processBrs(element, callback) {
+ var startSection, previousBR, END_TO_START = 3, START_TO_END = 1,
+ breakElements = 'br,ul,ol,p,div,h1,h2,h3,h4,h5,h6,table,blockquote,address,pre,form,center,dl';
+
+ function isAnyPartSelected(start, end) {
+ var r = dom.createRng(), sel;
+ bookmark.keep = true;
+ ed.selection.moveToBookmark(bookmark);
+ bookmark.keep = false;
+ sel = ed.selection.getRng(true);
+ if (!end) {
+ end = start.parentNode.lastChild;
+ }
+ r.setStartBefore(start);
+ r.setEndAfter(end);
+ return !(r.compareBoundaryPoints(END_TO_START, sel) > 0 || r.compareBoundaryPoints(START_TO_END, sel) <= 0);
+ }
+
+ function nextLeaf(br) {
+ if (br.nextSibling)
+ return br.nextSibling;
+ if (!dom.isBlock(br.parentNode) && br.parentNode !== dom.getRoot())
+ return nextLeaf(br.parentNode);
+ }
+
+ // Split on BRs within the range and process those.
+ startSection = element.firstChild;
+ // First mark the BRs that have any part of the previous section selected.
+ var trailingContentSelected = false;
+ each(dom.select(breakElements, element), function(br) {
+ if (br.hasAttribute && br.hasAttribute('_mce_bogus')) {
+ return true; // Skip the bogus Brs that are put in to appease Firefox and Safari.
+ }
+ if (isAnyPartSelected(startSection, br)) {
+ dom.addClass(br, '_mce_tagged_br');
+ startSection = nextLeaf(br);
+ }
+ });
+ trailingContentSelected = (startSection && isAnyPartSelected(startSection, undefined));
+ startSection = element.firstChild;
+ each(dom.select(breakElements, element), function(br) {
+ // Got a section from start to br.
+ var tmp = nextLeaf(br);
+ if (br.hasAttribute && br.hasAttribute('_mce_bogus')) {
+ return true; // Skip the bogus Brs that are put in to appease Firefox and Safari.
+ }
+ if (dom.hasClass(br, '_mce_tagged_br')) {
+ callback(startSection, br, previousBR);
+ previousBR = null;
+ } else {
+ previousBR = br;
+ }
+ startSection = tmp;
+ });
+ if (trailingContentSelected) {
+ callback(startSection, undefined, previousBR);
+ }
+ }
+
+ function wrapList(element) {
+ processBrs(element, function(startSection, br, previousBR) {
+ // Need to indent this part
+ doWrapList(startSection, br);
+ cleanupBr(br);
+ cleanupBr(previousBR);
+ });
+ }
+
+ function changeList(element) {
+ if (tinymce.inArray(applied, element) !== -1) {
+ return;
+ }
+ if (element.parentNode.tagName === oppositeListType) {
+ dom.split(element.parentNode, element);
+ makeList(element);
+ attemptMergeWithNext(element.parentNode, false);
+ }
+ applied.push(element);
+ }
+
+ function convertListItemToParagraph(element) {
+ var child, nextChild, mergedElement, splitLast;
+ if (tinymce.inArray(applied, element) !== -1) {
+ return;
+ }
+ element = splitNestedLists(element, dom);
+ while (dom.is(element.parentNode, 'ol,ul,li')) {
+ dom.split(element.parentNode, element);
+ }
+ // Push the original element we have from the selection, not the renamed one.
+ applied.push(element);
+ element = dom.rename(element, 'p');
+ mergedElement = attemptMergeWithAdjacent(element, false, ed.settings.force_br_newlines);
+ if (mergedElement === element) {
+ // Now split out any block elements that can't be contained within a P.
+ // Manually iterate to ensure we handle modifications correctly (doesn't work with tinymce.each)
+ child = element.firstChild;
+ while (child) {
+ if (dom.isBlock(child)) {
+ child = dom.split(child.parentNode, child);
+ splitLast = true;
+ nextChild = child.nextSibling && child.nextSibling.firstChild;
+ } else {
+ nextChild = child.nextSibling;
+ if (splitLast && child.tagName === 'BR') {
+ dom.remove(child);
+ }
+ splitLast = false;
+ }
+ child = nextChild;
+ }
+ }
+ }
+
+ each(selectedBlocks, function(e) {
+ e = findItemToOperateOn(e, dom);
+ if (e.tagName === oppositeListType || (e.tagName === 'LI' && e.parentNode.tagName === oppositeListType)) {
+ hasOppositeType = true;
+ } else if (e.tagName === targetListType || (e.tagName === 'LI' && e.parentNode.tagName === targetListType)) {
+ hasSameType = true;
+ } else {
+ hasNonList = true;
+ }
+ });
+
+ if (hasNonList &&!hasSameType || hasOppositeType || selectedBlocks.length === 0) {
+ actions = {
+ 'LI': changeList,
+ 'H1': makeList,
+ 'H2': makeList,
+ 'H3': makeList,
+ 'H4': makeList,
+ 'H5': makeList,
+ 'H6': makeList,
+ 'P': makeList,
+ 'BODY': makeList,
+ 'DIV': selectedBlocks.length > 1 ? makeList : wrapList,
+ defaultAction: wrapList,
+ elements: this.selectedBlocks()
+ };
+ } else {
+ actions = {
+ defaultAction: convertListItemToParagraph,
+ elements: this.selectedBlocks(),
+ processEvenIfEmpty: true
+ };
+ }
+ this.process(actions);
+ },
+
+ indent: function() {
+ var ed = this.ed, dom = ed.dom, indented = [];
+
+ function createWrapItem(element) {
+ var wrapItem = dom.create('li', { style: 'list-style-type: none;'});
+ dom.insertAfter(wrapItem, element);
+ return wrapItem;
+ }
+
+ function createWrapList(element) {
+ var wrapItem = createWrapItem(element),
+ list = dom.getParent(element, 'ol,ul'),
+ listType = list.tagName,
+ listStyle = dom.getStyle(list, 'list-style-type'),
+ attrs = {},
+ wrapList;
+ if (listStyle !== '') {
+ attrs.style = 'list-style-type: ' + listStyle + ';';
+ }
+ wrapList = dom.create(listType, attrs);
+ wrapItem.appendChild(wrapList);
+ return wrapList;
+ }
+
+ function indentLI(element) {
+ if (!hasParentInList(ed, element, indented)) {
+ element = splitNestedLists(element, dom);
+ var wrapList = createWrapList(element);
+ wrapList.appendChild(element);
+ attemptMergeWithAdjacent(wrapList.parentNode, false);
+ attemptMergeWithAdjacent(wrapList, false);
+ indented.push(element);
+ }
+ }
+
+ this.process({
+ 'LI': indentLI,
+ defaultAction: this.adjustPaddingFunction(true),
+ elements: this.selectedBlocks()
+ });
+
+ },
+
+ outdent: function(ui, elements) {
+ var t = this, ed = t.ed, dom = ed.dom, outdented = [];
+
+ function outdentLI(element) {
+ var listElement, targetParent, align;
+ if (!hasParentInList(ed, element, outdented)) {
+ if (dom.getStyle(element, 'margin-left') !== '' || dom.getStyle(element, 'padding-left') !== '') {
+ return t.adjustPaddingFunction(false)(element);
+ }
+ align = dom.getStyle(element, 'text-align', true);
+ if (align === 'center' || align === 'right') {
+ dom.setStyle(element, 'text-align', 'left');
+ return;
+ }
+ element = splitNestedLists(element, dom);
+ listElement = element.parentNode;
+ targetParent = element.parentNode.parentNode;
+ if (targetParent.tagName === 'P') {
+ dom.split(targetParent, element.parentNode);
+ } else {
+ dom.split(listElement, element);
+ if (targetParent.tagName === 'LI') {
+ // Nested list, need to split the LI and go back out to the OL/UL element.
+ dom.split(targetParent, element);
+ } else if (!dom.is(targetParent, 'ol,ul')) {
+ dom.rename(element, 'p');
+ }
+ }
+ outdented.push(element);
+ }
+ }
+
+ var listElements = elements && tinymce.is(elements, 'array') ? elements : this.selectedBlocks();
+ this.process({
+ 'LI': outdentLI,
+ defaultAction: this.adjustPaddingFunction(false),
+ elements: listElements
+ });
+
+ each(outdented, attemptMergeWithAdjacent);
+ },
+
+ process: function(actions) {
+ var t = this, sel = t.ed.selection, dom = t.ed.dom, selectedBlocks, r;
+
+ function isEmptyElement(element) {
+ var excludeBrsAndBookmarks = tinymce.grep(element.childNodes, function(n) {
+ return !(n.nodeName === 'BR' || n.nodeName === 'SPAN' && dom.getAttrib(n, 'data-mce-type') == 'bookmark'
+ || n.nodeType == 3 && (n.nodeValue == String.fromCharCode(160) || n.nodeValue == ''));
+ });
+ return excludeBrsAndBookmarks.length === 0;
+ }
+
+ function processElement(element) {
+ dom.removeClass(element, '_mce_act_on');
+ if (!element || element.nodeType !== 1 || ! actions.processEvenIfEmpty && selectedBlocks.length > 1 && isEmptyElement(element)) {
+ return;
+ }
+ element = findItemToOperateOn(element, dom);
+ var action = actions[element.tagName];
+ if (!action) {
+ action = actions.defaultAction;
+ }
+ action(element);
+ }
+
+ function recurse(element) {
+ t.splitSafeEach(element.childNodes, processElement);
+ }
+
+ function brAtEdgeOfSelection(container, offset) {
+ return offset >= 0 && container.hasChildNodes() && offset < container.childNodes.length &&
+ container.childNodes[offset].tagName === 'BR';
+ }
+
+ function isInTable() {
+ var n = sel.getNode();
+ var p = dom.getParent(n, 'td');
+ return p !== null;
+ }
+
+ selectedBlocks = actions.elements;
+
+ r = sel.getRng(true);
+ if (!r.collapsed) {
+ if (brAtEdgeOfSelection(r.endContainer, r.endOffset - 1)) {
+ r.setEnd(r.endContainer, r.endOffset - 1);
+ sel.setRng(r);
+ }
+ if (brAtEdgeOfSelection(r.startContainer, r.startOffset)) {
+ r.setStart(r.startContainer, r.startOffset + 1);
+ sel.setRng(r);
+ }
+ }
+
+
+ if (tinymce.isIE8) {
+ // append a zero sized nbsp so that caret is restored correctly using bookmark
+ var s = t.ed.selection.getNode();
+ if (s.tagName === 'LI' && !(s.parentNode.lastChild === s)) {
+ var i = t.ed.getDoc().createTextNode('\uFEFF');
+ s.appendChild(i);
+ }
+ }
+
+ bookmark = sel.getBookmark();
+ actions.OL = actions.UL = recurse;
+ t.splitSafeEach(selectedBlocks, processElement);
+ sel.moveToBookmark(bookmark);
+ bookmark = null;
+
+ // we avoid doing repaint in a table as this will move the caret out of the table in Firefox 3.6
+ if (!isInTable()) {
+ // Avoids table or image handles being left behind in Firefox.
+ t.ed.execCommand('mceRepaint');
+ }
+ },
+
+ splitSafeEach: function(elements, f) {
+ if (tinymce.isGecko && (/Firefox\/[12]\.[0-9]/.test(navigator.userAgent) ||
+ /Firefox\/3\.[0-4]/.test(navigator.userAgent))) {
+ this.classBasedEach(elements, f);
+ } else {
+ each(elements, f);
+ }
+ },
+
+ classBasedEach: function(elements, f) {
+ var dom = this.ed.dom, nodes, element;
+ // Mark nodes
+ each(elements, function(element) {
+ dom.addClass(element, '_mce_act_on');
+ });
+ nodes = dom.select('._mce_act_on');
+ while (nodes.length > 0) {
+ element = nodes.shift();
+ dom.removeClass(element, '_mce_act_on');
+ f(element);
+ nodes = dom.select('._mce_act_on');
+ }
+ },
+
+ adjustPaddingFunction: function(isIndent) {
+ var indentAmount, indentUnits, ed = this.ed;
+ indentAmount = ed.settings.indentation;
+ indentUnits = /[a-z%]+/i.exec(indentAmount);
+ indentAmount = parseInt(indentAmount, 10);
+ return function(element) {
+ var currentIndent, newIndentAmount;
+ currentIndent = parseInt(ed.dom.getStyle(element, 'margin-left') || 0, 10) + parseInt(ed.dom.getStyle(element, 'padding-left') || 0, 10);
+ if (isIndent) {
+ newIndentAmount = currentIndent + indentAmount;
+ } else {
+ newIndentAmount = currentIndent - indentAmount;
+ }
+ ed.dom.setStyle(element, 'padding-left', '');
+ ed.dom.setStyle(element, 'margin-left', newIndentAmount > 0 ? newIndentAmount + indentUnits : '');
+ };
+ },
+
+ selectedBlocks: function() {
+ var ed = this.ed
+ var selectedBlocks = ed.selection.getSelectedBlocks();
+ return selectedBlocks.length == 0 ? [ ed.dom.getRoot() ] : selectedBlocks;
+ },
+
+ getInfo: function() {
+ return {
+ longname : 'Lists',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/lists',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+ tinymce.PluginManager.add("lists", tinymce.plugins.Lists);
+}());
diff --git a/askbot/media/js/tinymce/plugins/media/css/media.css b/askbot/media/js/tinymce/plugins/media/css/media.css
new file mode 100644
index 00000000..0c45c7ff
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/media/css/media.css
@@ -0,0 +1,17 @@
+#id, #name, #hspace, #vspace, #class_name, #align { width: 100px }
+#hspace, #vspace { width: 50px }
+#flash_quality, #flash_align, #flash_scale, #flash_salign, #flash_wmode { width: 100px }
+#flash_base, #flash_flashvars, #html5_altsource1, #html5_altsource2, #html5_poster { width: 240px }
+#width, #height { width: 40px }
+#src, #media_type { width: 250px }
+#class { width: 120px }
+#prev { margin: 0; border: 1px solid black; width: 380px; height: 260px; overflow: auto }
+.panel_wrapper div.current { height: 420px; overflow: auto }
+#flash_options, #shockwave_options, #qt_options, #wmp_options, #rmp_options { display: none }
+.mceAddSelectValue { background-color: #DDDDDD }
+#qt_starttime, #qt_endtime, #qt_fov, #qt_href, #qt_moveid, #qt_moviename, #qt_node, #qt_pan, #qt_qtsrc, #qt_qtsrcchokespeed, #qt_target, #qt_tilt, #qt_urlsubstituten, #qt_volume { width: 70px }
+#wmp_balance, #wmp_baseurl, #wmp_captioningid, #wmp_currentmarker, #wmp_currentposition, #wmp_defaultframe, #wmp_playcount, #wmp_rate, #wmp_uimode, #wmp_volume { width: 70px }
+#rmp_console, #rmp_numloop, #rmp_controls, #rmp_scriptcallbacks { width: 70px }
+#shockwave_swvolume, #shockwave_swframe, #shockwave_swurl, #shockwave_swstretchvalign, #shockwave_swstretchhalign, #shockwave_swstretchstyle { width: 90px }
+#qt_qtsrc { width: 200px }
+iframe {border: 1px solid gray}
diff --git a/askbot/media/js/tinymce/plugins/media/editor_plugin.js b/askbot/media/js/tinymce/plugins/media/editor_plugin.js
new file mode 100644
index 00000000..37b4320b
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/media/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var d=tinymce.explode("id,name,width,height,style,align,class,hspace,vspace,bgcolor,type"),h=tinymce.makeMap(d.join(",")),b=tinymce.html.Node,f,a,g=tinymce.util.JSON,e;f=[["Flash","d27cdb6e-ae6d-11cf-96b8-444553540000","application/x-shockwave-flash","http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"],["ShockWave","166b1bca-3f9c-11cf-8075-444553540000","application/x-director","http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0"],["WindowsMedia","6bf52a52-394a-11d3-b153-00c04f79faa6,22d6f312-b0f6-11d0-94ab-0080c74c7e95,05589fa1-c356-11ce-bf01-00aa0055595a","application/x-mplayer2","http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701"],["QuickTime","02bf25d5-8c17-4b23-bc80-d3488abddc6b","video/quicktime","http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0"],["RealMedia","cfcdaa03-8be4-11cf-b84b-0020afbbccfa","audio/x-pn-realaudio-plugin","http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"],["Java","8ad9c840-044e-11d1-b3e9-00805f499d93","application/x-java-applet","http://java.sun.com/products/plugin/autodl/jinstall-1_5_0-windows-i586.cab#Version=1,5,0,0"],["Silverlight","dfeaf541-f3e1-4c24-acac-99c30715084a","application/x-silverlight-2"],["Iframe"],["Video"],["EmbeddedAudio"],["Audio"]];function c(m){var l,j,k;if(m&&!m.splice){j=[];for(k=0;true;k++){if(m[k]){j[k]=m[k]}else{break}}return j}return m}tinymce.create("tinymce.plugins.MediaPlugin",{init:function(n,j){var r=this,l={},m,p,q,k;function o(i){return i&&i.nodeName==="IMG"&&n.dom.hasClass(i,"mceItemMedia")}r.editor=n;r.url=j;a="";for(m=0;m<f.length;m++){k=f[m][0];q={name:k,clsids:tinymce.explode(f[m][1]||""),mimes:tinymce.explode(f[m][2]||""),codebase:f[m][3]};for(p=0;p<q.clsids.length;p++){l["clsid:"+q.clsids[p]]=q}for(p=0;p<q.mimes.length;p++){l[q.mimes[p]]=q}l["mceItem"+k]=q;l[k.toLowerCase()]=q;a+=(a?"|":"")+k}tinymce.each(n.getParam("media_types","video=mp4,m4v,ogv,webm;silverlight=xap;flash=swf,flv;shockwave=dcr;quicktime=mov,qt,mpg,mpeg;shockwave=dcr;windowsmedia=avi,wmv,wm,asf,asx,wmx,wvx;realmedia=rm,ra,ram;java=jar;audio=mp3,ogg").split(";"),function(v){var s,u,t;v=v.split(/=/);u=tinymce.explode(v[1].toLowerCase());for(s=0;s<u.length;s++){t=l[v[0].toLowerCase()];if(t){l[u[s]]=t}}});a=new RegExp("write("+a+")\\(([^)]+)\\)");r.lookup=l;n.onPreInit.add(function(){n.schema.addValidElements("object[id|style|width|height|classid|codebase|*],param[name|value],embed[id|style|width|height|type|src|*],video[*],audio[*],source[*]");n.parser.addNodeFilter("object,embed,video,audio,script,iframe",function(s){var t=s.length;while(t--){r.objectToImg(s[t])}});n.serializer.addNodeFilter("img",function(s,u,t){var v=s.length,w;while(v--){w=s[v];if((w.attr("class")||"").indexOf("mceItemMedia")!==-1){r.imgToObject(w,t)}}})});n.onInit.add(function(){if(n.theme&&n.theme.onResolveName){n.theme.onResolveName.add(function(i,s){if(s.name==="img"&&n.dom.hasClass(s.node,"mceItemMedia")){s.name="media"}})}if(n&&n.plugins.contextmenu){n.plugins.contextmenu.onContextMenu.add(function(s,t,i){if(i.nodeName==="IMG"&&i.className.indexOf("mceItemMedia")!==-1){t.add({title:"media.edit",icon:"media",cmd:"mceMedia"})}})}});n.addCommand("mceMedia",function(){var s,i;i=n.selection.getNode();if(o(i)){s=n.dom.getAttrib(i,"data-mce-json");if(s){s=g.parse(s);tinymce.each(d,function(t){var u=n.dom.getAttrib(i,t);if(u){s[t]=u}});s.type=r.getType(i.className).name.toLowerCase()}}if(!s){s={type:"flash",video:{sources:[]},params:{}}}n.windowManager.open({file:j+"/media.htm",width:430+parseInt(n.getLang("media.delta_width",0)),height:500+parseInt(n.getLang("media.delta_height",0)),inline:1},{plugin_url:j,data:s})});n.addButton("media",{title:"media.desc",cmd:"mceMedia"});n.onNodeChange.add(function(s,i,t){i.setActive("media",o(t))})},convertUrl:function(k,n){var j=this,m=j.editor,l=m.settings,o=l.url_converter,i=l.url_converter_scope||j;if(!k){return k}if(n){return m.documentBaseURI.toAbsolute(k)}return o.call(i,k,"src","object")},getInfo:function(){return{longname:"Media",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/media",version:tinymce.majorVersion+"."+tinymce.minorVersion}},dataToImg:function(m,k){var r=this,o=r.editor,p=o.documentBaseURI,j,q,n,l;m.params.src=r.convertUrl(m.params.src,k);q=m.video.attrs;if(q){q.src=r.convertUrl(q.src,k)}if(q){q.poster=r.convertUrl(q.poster,k)}j=c(m.video.sources);if(j){for(l=0;l<j.length;l++){j[l].src=r.convertUrl(j[l].src,k)}}n=r.editor.dom.create("img",{id:m.id,style:m.style,align:m.align,hspace:m.hspace,vspace:m.vspace,src:r.editor.theme.url+"/img/trans.gif","class":"mceItemMedia mceItem"+r.getType(m.type).name,"data-mce-json":g.serialize(m,"'")});n.width=m.width||(m.type=="audio"?"300":"320");n.height=m.height||(m.type=="audio"?"32":"240");return n},dataToHtml:function(i,j){return this.editor.serializer.serialize(this.dataToImg(i,j),{forced_root_block:"",force_absolute:j})},htmlToData:function(k){var j,i,l;l={type:"flash",video:{sources:[]},params:{}};j=this.editor.parser.parse(k);i=j.getAll("img")[0];if(i){l=g.parse(i.attr("data-mce-json"));l.type=this.getType(i.attr("class")).name.toLowerCase();tinymce.each(d,function(m){var n=i.attr(m);if(n){l[m]=n}})}return l},getType:function(m){var k,j,l;j=tinymce.explode(m," ");for(k=0;k<j.length;k++){l=this.lookup[j[k]];if(l){return l}}},imgToObject:function(z,o){var u=this,p=u.editor,C,H,j,t,I,y,G,w,k,E,s,q,A,D,m,x,l,B,F;function r(i,n){var M,L,N,K,J;J=p.getParam("flash_video_player_url",u.convertUrl(u.url+"/moxieplayer.swf"));if(J){M=p.documentBaseURI;G.params.src=J;if(p.getParam("flash_video_player_absvideourl",true)){i=M.toAbsolute(i||"",true);n=M.toAbsolute(n||"",true)}N="";L=p.getParam("flash_video_player_flashvars",{url:"$url",poster:"$poster"});tinymce.each(L,function(P,O){P=P.replace(/\$url/,i||"");P=P.replace(/\$poster/,n||"");if(P.length>0){N+=(N?"&":"")+O+"="+escape(P)}});if(N.length){G.params.flashvars=N}K=p.getParam("flash_video_player_params",{allowfullscreen:true,allowscriptaccess:true});tinymce.each(K,function(P,O){G.params[O]=""+P})}}G=z.attr("data-mce-json");if(!G){return}G=g.parse(G);q=this.getType(z.attr("class"));B=z.attr("data-mce-style");if(!B){B=z.attr("style");if(B){B=p.dom.serializeStyle(p.dom.parseStyle(B,"img"))}}if(q.name==="Iframe"){x=new b("iframe",1);tinymce.each(d,function(i){var n=z.attr(i);if(i=="class"&&n){n=n.replace(/mceItem.+ ?/g,"")}if(n&&n.length>0){x.attr(i,n)}});for(I in G.params){x.attr(I,G.params[I])}x.attr({style:B,src:G.params.src});z.replace(x);return}if(this.editor.settings.media_use_script){x=new b("script",1).attr("type","text/javascript");y=new b("#text",3);y.value="write"+q.name+"("+g.serialize(tinymce.extend(G.params,{width:z.attr("width"),height:z.attr("height")}))+");";x.append(y);z.replace(x);return}if(q.name==="Video"&&G.video.sources[0]){C=new b("video",1).attr(tinymce.extend({id:z.attr("id"),width:z.attr("width"),height:z.attr("height"),style:B},G.video.attrs));if(G.video.attrs){l=G.video.attrs.poster}k=G.video.sources=c(G.video.sources);for(A=0;A<k.length;A++){if(/\.mp4$/.test(k[A].src)){m=k[A].src}}if(!k[0].type){C.attr("src",k[0].src);k.splice(0,1)}for(A=0;A<k.length;A++){w=new b("source",1).attr(k[A]);w.shortEnded=true;C.append(w)}if(m){r(m,l);q=u.getType("flash")}else{G.params.src=""}}if(q.name==="Audio"&&G.video.sources[0]){F=new b("audio",1).attr(tinymce.extend({id:z.attr("id"),width:z.attr("width"),height:z.attr("height"),style:B},G.video.attrs));if(G.video.attrs){l=G.video.attrs.poster}k=G.video.sources=c(G.video.sources);if(!k[0].type){F.attr("src",k[0].src);k.splice(0,1)}for(A=0;A<k.length;A++){w=new b("source",1).attr(k[A]);w.shortEnded=true;F.append(w)}G.params.src=""}if(q.name==="EmbeddedAudio"){j=new b("embed",1);j.shortEnded=true;j.attr({id:z.attr("id"),width:z.attr("width"),height:z.attr("height"),style:B,type:z.attr("type")});for(I in G.params){j.attr(I,G.params[I])}tinymce.each(d,function(i){if(G[i]&&i!="type"){j.attr(i,G[i])}});G.params.src=""}if(G.params.src){if(/\.flv$/i.test(G.params.src)){r(G.params.src,"")}if(o&&o.force_absolute){G.params.src=p.documentBaseURI.toAbsolute(G.params.src)}H=new b("object",1).attr({id:z.attr("id"),width:z.attr("width"),height:z.attr("height"),style:B});tinymce.each(d,function(i){var n=G[i];if(i=="class"&&n){n=n.replace(/mceItem.+ ?/g,"")}if(n&&i!="type"){H.attr(i,n)}});for(I in G.params){s=new b("param",1);s.shortEnded=true;y=G.params[I];if(I==="src"&&q.name==="WindowsMedia"){I="url"}s.attr({name:I,value:y});H.append(s)}if(this.editor.getParam("media_strict",true)){H.attr({data:G.params.src,type:q.mimes[0]})}else{H.attr({classid:"clsid:"+q.clsids[0],codebase:q.codebase});j=new b("embed",1);j.shortEnded=true;j.attr({id:z.attr("id"),width:z.attr("width"),height:z.attr("height"),style:B,type:q.mimes[0]});for(I in G.params){j.attr(I,G.params[I])}tinymce.each(d,function(i){if(G[i]&&i!="type"){j.attr(i,G[i])}});H.append(j)}if(G.object_html){y=new b("#text",3);y.raw=true;y.value=G.object_html;H.append(y)}if(C){C.append(H)}}if(C){if(G.video_html){y=new b("#text",3);y.raw=true;y.value=G.video_html;C.append(y)}}if(F){if(G.video_html){y=new b("#text",3);y.raw=true;y.value=G.video_html;F.append(y)}}var v=C||F||H||j;if(v){z.replace(v)}else{z.remove()}},objectToImg:function(C){var L,k,F,s,M,N,y,A,x,G,E,t,q,I,B,l,K,o,H=this.lookup,m,z,v=this.editor.settings.url_converter,n=this.editor.settings.url_converter_scope,w,r,D,j;function u(i){return new tinymce.html.Serializer({inner:true,validate:false}).serialize(i)}function J(O,i){return H[(O.attr(i)||"").toLowerCase()]}function p(O){var i=O.replace(/^.*\.([^.]+)$/,"$1");return H[i.toLowerCase()||""]}if(!C.parent){return}if(C.name==="script"){if(C.firstChild){m=a.exec(C.firstChild.value)}if(!m){return}o=m[1];K={video:{},params:g.parse(m[2])};A=K.params.width;x=K.params.height}K=K||{video:{},params:{}};M=new b("img",1);M.attr({src:this.editor.theme.url+"/img/trans.gif"});N=C.name;if(N==="video"||N=="audio"){F=C;L=C.getAll("object")[0];k=C.getAll("embed")[0];A=F.attr("width");x=F.attr("height");y=F.attr("id");K.video={attrs:{},sources:[]};z=K.video.attrs;for(N in F.attributes.map){z[N]=F.attributes.map[N]}B=C.attr("src");if(B){K.video.sources.push({src:v.call(n,B,"src",C.name)})}l=F.getAll("source");for(E=0;E<l.length;E++){B=l[E].remove();K.video.sources.push({src:v.call(n,B.attr("src"),"src","source"),type:B.attr("type"),media:B.attr("media")})}if(z.poster){z.poster=v.call(n,z.poster,"poster",C.name)}}if(C.name==="object"){L=C;k=C.getAll("embed")[0]}if(C.name==="embed"){k=C}if(C.name==="iframe"){s=C;o="Iframe"}if(L){A=A||L.attr("width");x=x||L.attr("height");G=G||L.attr("style");y=y||L.attr("id");w=w||L.attr("hspace");r=r||L.attr("vspace");D=D||L.attr("align");j=j||L.attr("bgcolor");K.name=L.attr("name");I=L.getAll("param");for(E=0;E<I.length;E++){q=I[E];N=q.remove().attr("name");if(!h[N]){K.params[N]=q.attr("value")}}K.params.src=K.params.src||L.attr("data")}if(k){A=A||k.attr("width");x=x||k.attr("height");G=G||k.attr("style");y=y||k.attr("id");w=w||k.attr("hspace");r=r||k.attr("vspace");D=D||k.attr("align");j=j||k.attr("bgcolor");for(N in k.attributes.map){if(!h[N]&&!K.params[N]){K.params[N]=k.attributes.map[N]}}}if(s){A=s.attr("width");x=s.attr("height");G=G||s.attr("style");y=s.attr("id");w=s.attr("hspace");r=s.attr("vspace");D=s.attr("align");j=s.attr("bgcolor");tinymce.each(d,function(i){M.attr(i,s.attr(i))});for(N in s.attributes.map){if(!h[N]&&!K.params[N]){K.params[N]=s.attributes.map[N]}}}if(K.params.movie){K.params.src=K.params.src||K.params.movie;delete K.params.movie}if(K.params.src){K.params.src=v.call(n,K.params.src,"src","object")}if(F){if(C.name==="video"){o=H.video.name}else{if(C.name==="audio"){o=H.audio.name}}}if(L&&!o){o=(J(L,"clsid")||J(L,"classid")||J(L,"type")||{}).name}if(k&&!o){o=(J(k,"type")||p(K.params.src)||{}).name}if(k&&o=="EmbeddedAudio"){K.params.type=k.attr("type")}C.replace(M);if(k){k.remove()}if(L){t=u(L.remove());if(t){K.object_html=t}}if(F){t=u(F.remove());if(t){K.video_html=t}}K.hspace=w;K.vspace=r;K.align=D;K.bgcolor=j;M.attr({id:y,"class":"mceItemMedia mceItem"+(o||"Flash"),style:G,width:A||(C.name=="audio"?"300":"320"),height:x||(C.name=="audio"?"32":"240"),hspace:w,vspace:r,align:D,bgcolor:j,"data-mce-json":g.serialize(K,"'")})}});tinymce.PluginManager.add("media",tinymce.plugins.MediaPlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/media/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/media/editor_plugin_src.js
new file mode 100644
index 00000000..ea79db18
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/media/editor_plugin_src.js
@@ -0,0 +1,890 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var rootAttributes = tinymce.explode('id,name,width,height,style,align,class,hspace,vspace,bgcolor,type'), excludedAttrs = tinymce.makeMap(rootAttributes.join(',')), Node = tinymce.html.Node,
+ mediaTypes, scriptRegExp, JSON = tinymce.util.JSON, mimeTypes;
+
+ // Media types supported by this plugin
+ mediaTypes = [
+ // Type, clsid:s, mime types, codebase
+ ["Flash", "d27cdb6e-ae6d-11cf-96b8-444553540000", "application/x-shockwave-flash", "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"],
+ ["ShockWave", "166b1bca-3f9c-11cf-8075-444553540000", "application/x-director", "http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0"],
+ ["WindowsMedia", "6bf52a52-394a-11d3-b153-00c04f79faa6,22d6f312-b0f6-11d0-94ab-0080c74c7e95,05589fa1-c356-11ce-bf01-00aa0055595a", "application/x-mplayer2", "http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701"],
+ ["QuickTime", "02bf25d5-8c17-4b23-bc80-d3488abddc6b", "video/quicktime", "http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0"],
+ ["RealMedia", "cfcdaa03-8be4-11cf-b84b-0020afbbccfa", "audio/x-pn-realaudio-plugin", "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"],
+ ["Java", "8ad9c840-044e-11d1-b3e9-00805f499d93", "application/x-java-applet", "http://java.sun.com/products/plugin/autodl/jinstall-1_5_0-windows-i586.cab#Version=1,5,0,0"],
+ ["Silverlight", "dfeaf541-f3e1-4c24-acac-99c30715084a", "application/x-silverlight-2"],
+ ["Iframe"],
+ ["Video"],
+ ["EmbeddedAudio"],
+ ["Audio"]
+ ];
+
+ function toArray(obj) {
+ var undef, out, i;
+
+ if (obj && !obj.splice) {
+ out = [];
+
+ for (i = 0; true; i++) {
+ if (obj[i])
+ out[i] = obj[i];
+ else
+ break;
+ }
+
+ return out;
+ }
+
+ return obj;
+ };
+
+ tinymce.create('tinymce.plugins.MediaPlugin', {
+ init : function(ed, url) {
+ var self = this, lookup = {}, i, y, item, name;
+
+ function isMediaImg(node) {
+ return node && node.nodeName === 'IMG' && ed.dom.hasClass(node, 'mceItemMedia');
+ };
+
+ self.editor = ed;
+ self.url = url;
+
+ // Parse media types into a lookup table
+ scriptRegExp = '';
+ for (i = 0; i < mediaTypes.length; i++) {
+ name = mediaTypes[i][0];
+
+ item = {
+ name : name,
+ clsids : tinymce.explode(mediaTypes[i][1] || ''),
+ mimes : tinymce.explode(mediaTypes[i][2] || ''),
+ codebase : mediaTypes[i][3]
+ };
+
+ for (y = 0; y < item.clsids.length; y++)
+ lookup['clsid:' + item.clsids[y]] = item;
+
+ for (y = 0; y < item.mimes.length; y++)
+ lookup[item.mimes[y]] = item;
+
+ lookup['mceItem' + name] = item;
+ lookup[name.toLowerCase()] = item;
+
+ scriptRegExp += (scriptRegExp ? '|' : '') + name;
+ }
+
+ // Handle the media_types setting
+ tinymce.each(ed.getParam("media_types",
+ "video=mp4,m4v,ogv,webm;" +
+ "silverlight=xap;" +
+ "flash=swf,flv;" +
+ "shockwave=dcr;" +
+ "quicktime=mov,qt,mpg,mpeg;" +
+ "shockwave=dcr;" +
+ "windowsmedia=avi,wmv,wm,asf,asx,wmx,wvx;" +
+ "realmedia=rm,ra,ram;" +
+ "java=jar;" +
+ "audio=mp3,ogg"
+ ).split(';'), function(item) {
+ var i, extensions, type;
+
+ item = item.split(/=/);
+ extensions = tinymce.explode(item[1].toLowerCase());
+ for (i = 0; i < extensions.length; i++) {
+ type = lookup[item[0].toLowerCase()];
+
+ if (type)
+ lookup[extensions[i]] = type;
+ }
+ });
+
+ scriptRegExp = new RegExp('write(' + scriptRegExp + ')\\(([^)]+)\\)');
+ self.lookup = lookup;
+
+ ed.onPreInit.add(function() {
+ // Allow video elements
+ ed.schema.addValidElements('object[id|style|width|height|classid|codebase|*],param[name|value],embed[id|style|width|height|type|src|*],video[*],audio[*],source[*]');
+
+ // Convert video elements to image placeholder
+ ed.parser.addNodeFilter('object,embed,video,audio,script,iframe', function(nodes) {
+ var i = nodes.length;
+
+ while (i--)
+ self.objectToImg(nodes[i]);
+ });
+
+ // Convert image placeholders to video elements
+ ed.serializer.addNodeFilter('img', function(nodes, name, args) {
+ var i = nodes.length, node;
+
+ while (i--) {
+ node = nodes[i];
+ if ((node.attr('class') || '').indexOf('mceItemMedia') !== -1)
+ self.imgToObject(node, args);
+ }
+ });
+ });
+
+ ed.onInit.add(function() {
+ // Display "media" instead of "img" in element path
+ if (ed.theme && ed.theme.onResolveName) {
+ ed.theme.onResolveName.add(function(theme, path_object) {
+ if (path_object.name === 'img' && ed.dom.hasClass(path_object.node, 'mceItemMedia'))
+ path_object.name = 'media';
+ });
+ }
+
+ // Add contect menu if it's loaded
+ if (ed && ed.plugins.contextmenu) {
+ ed.plugins.contextmenu.onContextMenu.add(function(plugin, menu, element) {
+ if (element.nodeName === 'IMG' && element.className.indexOf('mceItemMedia') !== -1)
+ menu.add({title : 'media.edit', icon : 'media', cmd : 'mceMedia'});
+ });
+ }
+ });
+
+ // Register commands
+ ed.addCommand('mceMedia', function() {
+ var data, img;
+
+ img = ed.selection.getNode();
+ if (isMediaImg(img)) {
+ data = ed.dom.getAttrib(img, 'data-mce-json');
+ if (data) {
+ data = JSON.parse(data);
+
+ // Add some extra properties to the data object
+ tinymce.each(rootAttributes, function(name) {
+ var value = ed.dom.getAttrib(img, name);
+
+ if (value)
+ data[name] = value;
+ });
+
+ data.type = self.getType(img.className).name.toLowerCase();
+ }
+ }
+
+ if (!data) {
+ data = {
+ type : 'flash',
+ video: {sources:[]},
+ params: {}
+ };
+ }
+
+ ed.windowManager.open({
+ file : url + '/media.htm',
+ width : 430 + parseInt(ed.getLang('media.delta_width', 0)),
+ height : 500 + parseInt(ed.getLang('media.delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url,
+ data : data
+ });
+ });
+
+ // Register buttons
+ ed.addButton('media', {title : 'media.desc', cmd : 'mceMedia'});
+
+ // Update media selection status
+ ed.onNodeChange.add(function(ed, cm, node) {
+ cm.setActive('media', isMediaImg(node));
+ });
+ },
+
+ convertUrl : function(url, force_absolute) {
+ var self = this, editor = self.editor, settings = editor.settings,
+ urlConverter = settings.url_converter,
+ urlConverterScope = settings.url_converter_scope || self;
+
+ if (!url)
+ return url;
+
+ if (force_absolute)
+ return editor.documentBaseURI.toAbsolute(url);
+
+ return urlConverter.call(urlConverterScope, url, 'src', 'object');
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Media',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/media',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ /**
+ * Converts the JSON data object to an img node.
+ */
+ dataToImg : function(data, force_absolute) {
+ var self = this, editor = self.editor, baseUri = editor.documentBaseURI, sources, attrs, img, i;
+
+ data.params.src = self.convertUrl(data.params.src, force_absolute);
+
+ attrs = data.video.attrs;
+ if (attrs)
+ attrs.src = self.convertUrl(attrs.src, force_absolute);
+
+ if (attrs)
+ attrs.poster = self.convertUrl(attrs.poster, force_absolute);
+
+ sources = toArray(data.video.sources);
+ if (sources) {
+ for (i = 0; i < sources.length; i++)
+ sources[i].src = self.convertUrl(sources[i].src, force_absolute);
+ }
+
+ img = self.editor.dom.create('img', {
+ id : data.id,
+ style : data.style,
+ align : data.align,
+ hspace : data.hspace,
+ vspace : data.vspace,
+ src : self.editor.theme.url + '/img/trans.gif',
+ 'class' : 'mceItemMedia mceItem' + self.getType(data.type).name,
+ 'data-mce-json' : JSON.serialize(data, "'")
+ });
+
+ img.width = data.width || (data.type == 'audio' ? "300" : "320");
+ img.height = data.height || (data.type == 'audio' ? "32" : "240");
+
+ return img;
+ },
+
+ /**
+ * Converts the JSON data object to a HTML string.
+ */
+ dataToHtml : function(data, force_absolute) {
+ return this.editor.serializer.serialize(this.dataToImg(data, force_absolute), {forced_root_block : '', force_absolute : force_absolute});
+ },
+
+ /**
+ * Converts the JSON data object to a HTML string.
+ */
+ htmlToData : function(html) {
+ var fragment, img, data;
+
+ data = {
+ type : 'flash',
+ video: {sources:[]},
+ params: {}
+ };
+
+ fragment = this.editor.parser.parse(html);
+ img = fragment.getAll('img')[0];
+
+ if (img) {
+ data = JSON.parse(img.attr('data-mce-json'));
+ data.type = this.getType(img.attr('class')).name.toLowerCase();
+
+ // Add some extra properties to the data object
+ tinymce.each(rootAttributes, function(name) {
+ var value = img.attr(name);
+
+ if (value)
+ data[name] = value;
+ });
+ }
+
+ return data;
+ },
+
+ /**
+ * Get type item by extension, class, clsid or mime type.
+ *
+ * @method getType
+ * @param {String} value Value to get type item by.
+ * @return {Object} Type item object or undefined.
+ */
+ getType : function(value) {
+ var i, values, typeItem;
+
+ // Find type by checking the classes
+ values = tinymce.explode(value, ' ');
+ for (i = 0; i < values.length; i++) {
+ typeItem = this.lookup[values[i]];
+
+ if (typeItem)
+ return typeItem;
+ }
+ },
+
+ /**
+ * Converts a tinymce.html.Node image element to video/object/embed.
+ */
+ imgToObject : function(node, args) {
+ var self = this, editor = self.editor, video, object, embed, iframe, name, value, data,
+ source, sources, params, param, typeItem, i, item, mp4Source, replacement,
+ posterSrc, style, audio;
+
+ // Adds the flash player
+ function addPlayer(video_src, poster_src) {
+ var baseUri, flashVars, flashVarsOutput, params, flashPlayer;
+
+ flashPlayer = editor.getParam('flash_video_player_url', self.convertUrl(self.url + '/moxieplayer.swf'));
+ if (flashPlayer) {
+ baseUri = editor.documentBaseURI;
+ data.params.src = flashPlayer;
+
+ // Convert the movie url to absolute urls
+ if (editor.getParam('flash_video_player_absvideourl', true)) {
+ video_src = baseUri.toAbsolute(video_src || '', true);
+ poster_src = baseUri.toAbsolute(poster_src || '', true);
+ }
+
+ // Generate flash vars
+ flashVarsOutput = '';
+ flashVars = editor.getParam('flash_video_player_flashvars', {url : '$url', poster : '$poster'});
+ tinymce.each(flashVars, function(value, name) {
+ // Replace $url and $poster variables in flashvars value
+ value = value.replace(/\$url/, video_src || '');
+ value = value.replace(/\$poster/, poster_src || '');
+
+ if (value.length > 0)
+ flashVarsOutput += (flashVarsOutput ? '&' : '') + name + '=' + escape(value);
+ });
+
+ if (flashVarsOutput.length)
+ data.params.flashvars = flashVarsOutput;
+
+ params = editor.getParam('flash_video_player_params', {
+ allowfullscreen: true,
+ allowscriptaccess: true
+ });
+
+ tinymce.each(params, function(value, name) {
+ data.params[name] = "" + value;
+ });
+ }
+ };
+
+ data = node.attr('data-mce-json');
+ if (!data)
+ return;
+
+ data = JSON.parse(data);
+ typeItem = this.getType(node.attr('class'));
+
+ style = node.attr('data-mce-style')
+ if (!style) {
+ style = node.attr('style');
+
+ if (style)
+ style = editor.dom.serializeStyle(editor.dom.parseStyle(style, 'img'));
+ }
+
+ // Handle iframe
+ if (typeItem.name === 'Iframe') {
+ replacement = new Node('iframe', 1);
+
+ tinymce.each(rootAttributes, function(name) {
+ var value = node.attr(name);
+
+ if (name == 'class' && value)
+ value = value.replace(/mceItem.+ ?/g, '');
+
+ if (value && value.length > 0)
+ replacement.attr(name, value);
+ });
+
+ for (name in data.params)
+ replacement.attr(name, data.params[name]);
+
+ replacement.attr({
+ style: style,
+ src: data.params.src
+ });
+
+ node.replace(replacement);
+
+ return;
+ }
+
+ // Handle scripts
+ if (this.editor.settings.media_use_script) {
+ replacement = new Node('script', 1).attr('type', 'text/javascript');
+
+ value = new Node('#text', 3);
+ value.value = 'write' + typeItem.name + '(' + JSON.serialize(tinymce.extend(data.params, {
+ width: node.attr('width'),
+ height: node.attr('height')
+ })) + ');';
+
+ replacement.append(value);
+ node.replace(replacement);
+
+ return;
+ }
+
+ // Add HTML5 video element
+ if (typeItem.name === 'Video' && data.video.sources[0]) {
+ // Create new object element
+ video = new Node('video', 1).attr(tinymce.extend({
+ id : node.attr('id'),
+ width: node.attr('width'),
+ height: node.attr('height'),
+ style : style
+ }, data.video.attrs));
+
+ // Get poster source and use that for flash fallback
+ if (data.video.attrs)
+ posterSrc = data.video.attrs.poster;
+
+ sources = data.video.sources = toArray(data.video.sources);
+ for (i = 0; i < sources.length; i++) {
+ if (/\.mp4$/.test(sources[i].src))
+ mp4Source = sources[i].src;
+ }
+
+ if (!sources[0].type) {
+ video.attr('src', sources[0].src);
+ sources.splice(0, 1);
+ }
+
+ for (i = 0; i < sources.length; i++) {
+ source = new Node('source', 1).attr(sources[i]);
+ source.shortEnded = true;
+ video.append(source);
+ }
+
+ // Create flash fallback for video if we have a mp4 source
+ if (mp4Source) {
+ addPlayer(mp4Source, posterSrc);
+ typeItem = self.getType('flash');
+ } else
+ data.params.src = '';
+ }
+
+ // Add HTML5 audio element
+ if (typeItem.name === 'Audio' && data.video.sources[0]) {
+ // Create new object element
+ audio = new Node('audio', 1).attr(tinymce.extend({
+ id : node.attr('id'),
+ width: node.attr('width'),
+ height: node.attr('height'),
+ style : style
+ }, data.video.attrs));
+
+ // Get poster source and use that for flash fallback
+ if (data.video.attrs)
+ posterSrc = data.video.attrs.poster;
+
+ sources = data.video.sources = toArray(data.video.sources);
+ if (!sources[0].type) {
+ audio.attr('src', sources[0].src);
+ sources.splice(0, 1);
+ }
+
+ for (i = 0; i < sources.length; i++) {
+ source = new Node('source', 1).attr(sources[i]);
+ source.shortEnded = true;
+ audio.append(source);
+ }
+
+ data.params.src = '';
+ }
+
+ if (typeItem.name === 'EmbeddedAudio') {
+ embed = new Node('embed', 1);
+ embed.shortEnded = true;
+ embed.attr({
+ id: node.attr('id'),
+ width: node.attr('width'),
+ height: node.attr('height'),
+ style : style,
+ type: node.attr('type')
+ });
+
+ for (name in data.params)
+ embed.attr(name, data.params[name]);
+
+ tinymce.each(rootAttributes, function(name) {
+ if (data[name] && name != 'type')
+ embed.attr(name, data[name]);
+ });
+
+ data.params.src = '';
+ }
+
+ // Do we have a params src then we can generate object
+ if (data.params.src) {
+ // Is flv movie add player for it
+ if (/\.flv$/i.test(data.params.src))
+ addPlayer(data.params.src, '');
+
+ if (args && args.force_absolute)
+ data.params.src = editor.documentBaseURI.toAbsolute(data.params.src);
+
+ // Create new object element
+ object = new Node('object', 1).attr({
+ id : node.attr('id'),
+ width: node.attr('width'),
+ height: node.attr('height'),
+ style : style
+ });
+
+ tinymce.each(rootAttributes, function(name) {
+ var value = data[name];
+
+ if (name == 'class' && value)
+ value = value.replace(/mceItem.+ ?/g, '');
+
+ if (value && name != 'type')
+ object.attr(name, value);
+ });
+
+ // Add params
+ for (name in data.params) {
+ param = new Node('param', 1);
+ param.shortEnded = true;
+ value = data.params[name];
+
+ // Windows media needs to use url instead of src for the media URL
+ if (name === 'src' && typeItem.name === 'WindowsMedia')
+ name = 'url';
+
+ param.attr({name: name, value: value});
+ object.append(param);
+ }
+
+ // Setup add type and classid if strict is disabled
+ if (this.editor.getParam('media_strict', true)) {
+ object.attr({
+ data: data.params.src,
+ type: typeItem.mimes[0]
+ });
+ } else {
+ object.attr({
+ classid: "clsid:" + typeItem.clsids[0],
+ codebase: typeItem.codebase
+ });
+
+ embed = new Node('embed', 1);
+ embed.shortEnded = true;
+ embed.attr({
+ id: node.attr('id'),
+ width: node.attr('width'),
+ height: node.attr('height'),
+ style : style,
+ type: typeItem.mimes[0]
+ });
+
+ for (name in data.params)
+ embed.attr(name, data.params[name]);
+
+ tinymce.each(rootAttributes, function(name) {
+ if (data[name] && name != 'type')
+ embed.attr(name, data[name]);
+ });
+
+ object.append(embed);
+ }
+
+ // Insert raw HTML
+ if (data.object_html) {
+ value = new Node('#text', 3);
+ value.raw = true;
+ value.value = data.object_html;
+ object.append(value);
+ }
+
+ // Append object to video element if it exists
+ if (video)
+ video.append(object);
+ }
+
+ if (video) {
+ // Insert raw HTML
+ if (data.video_html) {
+ value = new Node('#text', 3);
+ value.raw = true;
+ value.value = data.video_html;
+ video.append(value);
+ }
+ }
+
+ if (audio) {
+ // Insert raw HTML
+ if (data.video_html) {
+ value = new Node('#text', 3);
+ value.raw = true;
+ value.value = data.video_html;
+ audio.append(value);
+ }
+ }
+
+ var n = video || audio || object || embed;
+ if (n)
+ node.replace(n);
+ else
+ node.remove();
+ },
+
+ /**
+ * Converts a tinymce.html.Node video/object/embed to an img element.
+ *
+ * The video/object/embed will be converted into an image placeholder with a JSON data attribute like this:
+ * <img class="mceItemMedia mceItemFlash" width="100" height="100" data-mce-json="{..}" />
+ *
+ * The JSON structure will be like this:
+ * {'params':{'flashvars':'something','quality':'high','src':'someurl'}, 'video':{'sources':[{src: 'someurl', type: 'video/mp4'}]}}
+ */
+ objectToImg : function(node) {
+ var object, embed, video, iframe, img, name, id, width, height, style, i, html,
+ param, params, source, sources, data, type, lookup = this.lookup,
+ matches, attrs, urlConverter = this.editor.settings.url_converter,
+ urlConverterScope = this.editor.settings.url_converter_scope,
+ hspace, vspace, align, bgcolor;
+
+ function getInnerHTML(node) {
+ return new tinymce.html.Serializer({
+ inner: true,
+ validate: false
+ }).serialize(node);
+ };
+
+ function lookupAttribute(o, attr) {
+ return lookup[(o.attr(attr) || '').toLowerCase()];
+ }
+
+ function lookupExtension(src) {
+ var ext = src.replace(/^.*\.([^.]+)$/, '$1');
+ return lookup[ext.toLowerCase() || ''];
+ }
+
+ // If node isn't in document
+ if (!node.parent)
+ return;
+
+ // Handle media scripts
+ if (node.name === 'script') {
+ if (node.firstChild)
+ matches = scriptRegExp.exec(node.firstChild.value);
+
+ if (!matches)
+ return;
+
+ type = matches[1];
+ data = {video : {}, params : JSON.parse(matches[2])};
+ width = data.params.width;
+ height = data.params.height;
+ }
+
+ // Setup data objects
+ data = data || {
+ video : {},
+ params : {}
+ };
+
+ // Setup new image object
+ img = new Node('img', 1);
+ img.attr({
+ src : this.editor.theme.url + '/img/trans.gif'
+ });
+
+ // Video element
+ name = node.name;
+ if (name === 'video' || name == 'audio') {
+ video = node;
+ object = node.getAll('object')[0];
+ embed = node.getAll('embed')[0];
+ width = video.attr('width');
+ height = video.attr('height');
+ id = video.attr('id');
+ data.video = {attrs : {}, sources : []};
+
+ // Get all video attributes
+ attrs = data.video.attrs;
+ for (name in video.attributes.map)
+ attrs[name] = video.attributes.map[name];
+
+ source = node.attr('src');
+ if (source)
+ data.video.sources.push({src : urlConverter.call(urlConverterScope, source, 'src', node.name)});
+
+ // Get all sources
+ sources = video.getAll("source");
+ for (i = 0; i < sources.length; i++) {
+ source = sources[i].remove();
+
+ data.video.sources.push({
+ src: urlConverter.call(urlConverterScope, source.attr('src'), 'src', 'source'),
+ type: source.attr('type'),
+ media: source.attr('media')
+ });
+ }
+
+ // Convert the poster URL
+ if (attrs.poster)
+ attrs.poster = urlConverter.call(urlConverterScope, attrs.poster, 'poster', node.name);
+ }
+
+ // Object element
+ if (node.name === 'object') {
+ object = node;
+ embed = node.getAll('embed')[0];
+ }
+
+ // Embed element
+ if (node.name === 'embed')
+ embed = node;
+
+ // Iframe element
+ if (node.name === 'iframe') {
+ iframe = node;
+ type = 'Iframe';
+ }
+
+ if (object) {
+ // Get width/height
+ width = width || object.attr('width');
+ height = height || object.attr('height');
+ style = style || object.attr('style');
+ id = id || object.attr('id');
+ hspace = hspace || object.attr('hspace');
+ vspace = vspace || object.attr('vspace');
+ align = align || object.attr('align');
+ bgcolor = bgcolor || object.attr('bgcolor');
+ data.name = object.attr('name');
+
+ // Get all object params
+ params = object.getAll("param");
+ for (i = 0; i < params.length; i++) {
+ param = params[i];
+ name = param.remove().attr('name');
+
+ if (!excludedAttrs[name])
+ data.params[name] = param.attr('value');
+ }
+
+ data.params.src = data.params.src || object.attr('data');
+ }
+
+ if (embed) {
+ // Get width/height
+ width = width || embed.attr('width');
+ height = height || embed.attr('height');
+ style = style || embed.attr('style');
+ id = id || embed.attr('id');
+ hspace = hspace || embed.attr('hspace');
+ vspace = vspace || embed.attr('vspace');
+ align = align || embed.attr('align');
+ bgcolor = bgcolor || embed.attr('bgcolor');
+
+ // Get all embed attributes
+ for (name in embed.attributes.map) {
+ if (!excludedAttrs[name] && !data.params[name])
+ data.params[name] = embed.attributes.map[name];
+ }
+ }
+
+ if (iframe) {
+ // Get width/height
+ width = iframe.attr('width');
+ height = iframe.attr('height');
+ style = style || iframe.attr('style');
+ id = iframe.attr('id');
+ hspace = iframe.attr('hspace');
+ vspace = iframe.attr('vspace');
+ align = iframe.attr('align');
+ bgcolor = iframe.attr('bgcolor');
+
+ tinymce.each(rootAttributes, function(name) {
+ img.attr(name, iframe.attr(name));
+ });
+
+ // Get all iframe attributes
+ for (name in iframe.attributes.map) {
+ if (!excludedAttrs[name] && !data.params[name])
+ data.params[name] = iframe.attributes.map[name];
+ }
+ }
+
+ // Use src not movie
+ if (data.params.movie) {
+ data.params.src = data.params.src || data.params.movie;
+ delete data.params.movie;
+ }
+
+ // Convert the URL to relative/absolute depending on configuration
+ if (data.params.src)
+ data.params.src = urlConverter.call(urlConverterScope, data.params.src, 'src', 'object');
+
+ if (video) {
+ if (node.name === 'video')
+ type = lookup.video.name;
+ else if (node.name === 'audio')
+ type = lookup.audio.name;
+ }
+
+ if (object && !type)
+ type = (lookupAttribute(object, 'clsid') || lookupAttribute(object, 'classid') || lookupAttribute(object, 'type') || {}).name;
+
+ if (embed && !type)
+ type = (lookupAttribute(embed, 'type') || lookupExtension(data.params.src) || {}).name;
+
+ // for embedded audio we preserve the original specified type
+ if (embed && type == 'EmbeddedAudio') {
+ data.params.type = embed.attr('type');
+ }
+
+ // Replace the video/object/embed element with a placeholder image containing the data
+ node.replace(img);
+
+ // Remove embed
+ if (embed)
+ embed.remove();
+
+ // Serialize the inner HTML of the object element
+ if (object) {
+ html = getInnerHTML(object.remove());
+
+ if (html)
+ data.object_html = html;
+ }
+
+ // Serialize the inner HTML of the video element
+ if (video) {
+ html = getInnerHTML(video.remove());
+
+ if (html)
+ data.video_html = html;
+ }
+
+ data.hspace = hspace;
+ data.vspace = vspace;
+ data.align = align;
+ data.bgcolor = bgcolor;
+
+ // Set width/height of placeholder
+ img.attr({
+ id : id,
+ 'class' : 'mceItemMedia mceItem' + (type || 'Flash'),
+ style : style,
+ width : width || (node.name == 'audio' ? "300" : "320"),
+ height : height || (node.name == 'audio' ? "32" : "240"),
+ hspace : hspace,
+ vspace : vspace,
+ align : align,
+ bgcolor : bgcolor,
+ "data-mce-json" : JSON.serialize(data, "'")
+ });
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('media', tinymce.plugins.MediaPlugin);
+})();
diff --git a/askbot/media/js/tinymce/plugins/media/js/embed.js b/askbot/media/js/tinymce/plugins/media/js/embed.js
new file mode 100644
index 00000000..f8dc8105
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/media/js/embed.js
@@ -0,0 +1,73 @@
+/**
+ * This script contains embed functions for common plugins. This scripts are complety free to use for any purpose.
+ */
+
+function writeFlash(p) {
+ writeEmbed(
+ 'D27CDB6E-AE6D-11cf-96B8-444553540000',
+ 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0',
+ 'application/x-shockwave-flash',
+ p
+ );
+}
+
+function writeShockWave(p) {
+ writeEmbed(
+ '166B1BCA-3F9C-11CF-8075-444553540000',
+ 'http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0',
+ 'application/x-director',
+ p
+ );
+}
+
+function writeQuickTime(p) {
+ writeEmbed(
+ '02BF25D5-8C17-4B23-BC80-D3488ABDDC6B',
+ 'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0',
+ 'video/quicktime',
+ p
+ );
+}
+
+function writeRealMedia(p) {
+ writeEmbed(
+ 'CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA',
+ 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0',
+ 'audio/x-pn-realaudio-plugin',
+ p
+ );
+}
+
+function writeWindowsMedia(p) {
+ p.url = p.src;
+ writeEmbed(
+ '6BF52A52-394A-11D3-B153-00C04F79FAA6',
+ 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701',
+ 'application/x-mplayer2',
+ p
+ );
+}
+
+function writeEmbed(cls, cb, mt, p) {
+ var h = '', n;
+
+ h += '<object classid="clsid:' + cls + '" codebase="' + cb + '"';
+ h += typeof(p.id) != "undefined" ? 'id="' + p.id + '"' : '';
+ h += typeof(p.name) != "undefined" ? 'name="' + p.name + '"' : '';
+ h += typeof(p.width) != "undefined" ? 'width="' + p.width + '"' : '';
+ h += typeof(p.height) != "undefined" ? 'height="' + p.height + '"' : '';
+ h += typeof(p.align) != "undefined" ? 'align="' + p.align + '"' : '';
+ h += '>';
+
+ for (n in p)
+ h += '<param name="' + n + '" value="' + p[n] + '">';
+
+ h += '<embed type="' + mt + '"';
+
+ for (n in p)
+ h += n + '="' + p[n] + '" ';
+
+ h += '></embed></object>';
+
+ document.write(h);
+}
diff --git a/askbot/media/js/tinymce/plugins/media/js/media.js b/askbot/media/js/tinymce/plugins/media/js/media.js
new file mode 100644
index 00000000..733c5f6c
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/media/js/media.js
@@ -0,0 +1,470 @@
+(function() {
+ var url;
+
+ if (url = tinyMCEPopup.getParam("media_external_list_url"))
+ document.write('<script language="javascript" type="text/javascript" src="' + tinyMCEPopup.editor.documentBaseURI.toAbsolute(url) + '"></script>');
+
+ function get(id) {
+ return document.getElementById(id);
+ }
+
+ function clone(obj) {
+ var i, len, copy, attr;
+
+ if (null == obj || "object" != typeof obj)
+ return obj;
+
+ // Handle Array
+ if ('length' in obj) {
+ copy = [];
+
+ for (i = 0, len = obj.length; i < len; ++i) {
+ copy[i] = clone(obj[i]);
+ }
+
+ return copy;
+ }
+
+ // Handle Object
+ copy = {};
+ for (attr in obj) {
+ if (obj.hasOwnProperty(attr))
+ copy[attr] = clone(obj[attr]);
+ }
+
+ return copy;
+ }
+
+ function getVal(id) {
+ var elm = get(id);
+
+ if (elm.nodeName == "SELECT")
+ return elm.options[elm.selectedIndex].value;
+
+ if (elm.type == "checkbox")
+ return elm.checked;
+
+ return elm.value;
+ }
+
+ function setVal(id, value, name) {
+ if (typeof(value) != 'undefined' && value != null) {
+ var elm = get(id);
+
+ if (elm.nodeName == "SELECT")
+ selectByValue(document.forms[0], id, value);
+ else if (elm.type == "checkbox") {
+ if (typeof(value) == 'string') {
+ value = value.toLowerCase();
+ value = (!name && value === 'true') || (name && value === name.toLowerCase());
+ }
+ elm.checked = !!value;
+ } else
+ elm.value = value;
+ }
+ }
+
+ window.Media = {
+ init : function() {
+ var html, editor, self = this;
+
+ self.editor = editor = tinyMCEPopup.editor;
+
+ // Setup file browsers and color pickers
+ get('filebrowsercontainer').innerHTML = getBrowserHTML('filebrowser','src','media','media');
+ get('qtsrcfilebrowsercontainer').innerHTML = getBrowserHTML('qtsrcfilebrowser','quicktime_qtsrc','media','media');
+ get('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor');
+ get('video_altsource1_filebrowser').innerHTML = getBrowserHTML('video_filebrowser_altsource1','video_altsource1','media','media');
+ get('video_altsource2_filebrowser').innerHTML = getBrowserHTML('video_filebrowser_altsource2','video_altsource2','media','media');
+ get('audio_altsource1_filebrowser').innerHTML = getBrowserHTML('audio_filebrowser_altsource1','audio_altsource1','media','media');
+ get('audio_altsource2_filebrowser').innerHTML = getBrowserHTML('audio_filebrowser_altsource2','audio_altsource2','media','media');
+ get('video_poster_filebrowser').innerHTML = getBrowserHTML('filebrowser_poster','video_poster','media','image');
+
+ html = self.getMediaListHTML('medialist', 'src', 'media', 'media');
+ if (html == "")
+ get("linklistrow").style.display = 'none';
+ else
+ get("linklistcontainer").innerHTML = html;
+
+ if (isVisible('filebrowser'))
+ get('src').style.width = '230px';
+
+ if (isVisible('video_filebrowser_altsource1'))
+ get('video_altsource1').style.width = '220px';
+
+ if (isVisible('video_filebrowser_altsource2'))
+ get('video_altsource2').style.width = '220px';
+
+ if (isVisible('audio_filebrowser_altsource1'))
+ get('audio_altsource1').style.width = '220px';
+
+ if (isVisible('audio_filebrowser_altsource2'))
+ get('audio_altsource2').style.width = '220px';
+
+ if (isVisible('filebrowser_poster'))
+ get('video_poster').style.width = '220px';
+
+ editor.dom.setOuterHTML(get('media_type'), self.getMediaTypeHTML(editor));
+
+ self.setDefaultDialogSettings(editor);
+ self.data = clone(tinyMCEPopup.getWindowArg('data'));
+ self.dataToForm();
+ self.preview();
+
+ updateColor('bgcolor_pick', 'bgcolor');
+ },
+
+ insert : function() {
+ var editor = tinyMCEPopup.editor;
+
+ this.formToData();
+ editor.execCommand('mceRepaint');
+ tinyMCEPopup.restoreSelection();
+ editor.selection.setNode(editor.plugins.media.dataToImg(this.data));
+ tinyMCEPopup.close();
+ },
+
+ preview : function() {
+ get('prev').innerHTML = this.editor.plugins.media.dataToHtml(this.data, true);
+ },
+
+ moveStates : function(to_form, field) {
+ var data = this.data, editor = this.editor,
+ mediaPlugin = editor.plugins.media, ext, src, typeInfo, defaultStates, src;
+
+ defaultStates = {
+ // QuickTime
+ quicktime_autoplay : true,
+ quicktime_controller : true,
+
+ // Flash
+ flash_play : true,
+ flash_loop : true,
+ flash_menu : true,
+
+ // WindowsMedia
+ windowsmedia_autostart : true,
+ windowsmedia_enablecontextmenu : true,
+ windowsmedia_invokeurls : true,
+
+ // RealMedia
+ realmedia_autogotourl : true,
+ realmedia_imagestatus : true
+ };
+
+ function parseQueryParams(str) {
+ var out = {};
+
+ if (str) {
+ tinymce.each(str.split('&'), function(item) {
+ var parts = item.split('=');
+
+ out[unescape(parts[0])] = unescape(parts[1]);
+ });
+ }
+
+ return out;
+ };
+
+ function setOptions(type, names) {
+ var i, name, formItemName, value, list;
+
+ if (type == data.type || type == 'global') {
+ names = tinymce.explode(names);
+ for (i = 0; i < names.length; i++) {
+ name = names[i];
+ formItemName = type == 'global' ? name : type + '_' + name;
+
+ if (type == 'global')
+ list = data;
+ else if (type == 'video' || type == 'audio') {
+ list = data.video.attrs;
+
+ if (!list && !to_form)
+ data.video.attrs = list = {};
+ } else
+ list = data.params;
+
+ if (list) {
+ if (to_form) {
+ setVal(formItemName, list[name], type == 'video' || type == 'audio' ? name : '');
+ } else {
+ delete list[name];
+
+ value = getVal(formItemName);
+ if ((type == 'video' || type == 'audio') && value === true)
+ value = name;
+
+ if (defaultStates[formItemName]) {
+ if (value !== defaultStates[formItemName]) {
+ value = "" + value;
+ list[name] = value;
+ }
+ } else if (value) {
+ value = "" + value;
+ list[name] = value;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!to_form) {
+ data.type = get('media_type').options[get('media_type').selectedIndex].value;
+ data.width = getVal('width');
+ data.height = getVal('height');
+
+ // Switch type based on extension
+ src = getVal('src');
+ if (field == 'src') {
+ ext = src.replace(/^.*\.([^.]+)$/, '$1');
+ if (typeInfo = mediaPlugin.getType(ext))
+ data.type = typeInfo.name.toLowerCase();
+
+ setVal('media_type', data.type);
+ }
+
+ if (data.type == "video" || data.type == "audio") {
+ if (!data.video.sources)
+ data.video.sources = [];
+
+ data.video.sources[0] = {src: getVal('src')};
+ }
+ }
+
+ // Hide all fieldsets and show the one active
+ get('video_options').style.display = 'none';
+ get('audio_options').style.display = 'none';
+ get('flash_options').style.display = 'none';
+ get('quicktime_options').style.display = 'none';
+ get('shockwave_options').style.display = 'none';
+ get('windowsmedia_options').style.display = 'none';
+ get('realmedia_options').style.display = 'none';
+ get('embeddedaudio_options').style.display = 'none';
+
+ if (get(data.type + '_options'))
+ get(data.type + '_options').style.display = 'block';
+
+ setVal('media_type', data.type);
+
+ setOptions('flash', 'play,loop,menu,swliveconnect,quality,scale,salign,wmode,base,flashvars');
+ setOptions('quicktime', 'loop,autoplay,cache,controller,correction,enablejavascript,kioskmode,autohref,playeveryframe,targetcache,scale,starttime,endtime,target,qtsrcchokespeed,volume,qtsrc');
+ setOptions('shockwave', 'sound,progress,autostart,swliveconnect,swvolume,swstretchstyle,swstretchhalign,swstretchvalign');
+ setOptions('windowsmedia', 'autostart,enabled,enablecontextmenu,fullscreen,invokeurls,mute,stretchtofit,windowlessvideo,balance,baseurl,captioningid,currentmarker,currentposition,defaultframe,playcount,rate,uimode,volume');
+ setOptions('realmedia', 'autostart,loop,autogotourl,center,imagestatus,maintainaspect,nojava,prefetch,shuffle,console,controls,numloop,scriptcallbacks');
+ setOptions('video', 'poster,autoplay,loop,muted,preload,controls');
+ setOptions('audio', 'autoplay,loop,preload,controls');
+ setOptions('embeddedaudio', 'autoplay,loop,controls');
+ setOptions('global', 'id,name,vspace,hspace,bgcolor,align,width,height');
+
+ if (to_form) {
+ if (data.type == 'video') {
+ if (data.video.sources[0])
+ setVal('src', data.video.sources[0].src);
+
+ src = data.video.sources[1];
+ if (src)
+ setVal('video_altsource1', src.src);
+
+ src = data.video.sources[2];
+ if (src)
+ setVal('video_altsource2', src.src);
+ } else if (data.type == 'audio') {
+ if (data.video.sources[0])
+ setVal('src', data.video.sources[0].src);
+
+ src = data.video.sources[1];
+ if (src)
+ setVal('audio_altsource1', src.src);
+
+ src = data.video.sources[2];
+ if (src)
+ setVal('audio_altsource2', src.src);
+ } else {
+ // Check flash vars
+ if (data.type == 'flash') {
+ tinymce.each(editor.getParam('flash_video_player_flashvars', {url : '$url', poster : '$poster'}), function(value, name) {
+ if (value == '$url')
+ data.params.src = parseQueryParams(data.params.flashvars)[name] || data.params.src || '';
+ });
+ }
+
+ setVal('src', data.params.src);
+ }
+ } else {
+ src = getVal("src");
+
+ // YouTube *NEW*
+ if (src.match(/youtu.be\/[a-z1-9.-_]+/)) {
+ data.width = 425;
+ data.height = 350;
+ data.params.frameborder = '0';
+ data.type = 'iframe';
+ src = 'http://www.youtube.com/embed/' + src.match(/youtu.be\/([a-z1-9.-_]+)/)[1];
+ setVal('src', src);
+ setVal('media_type', data.type);
+ }
+
+ // YouTube
+ if (src.match(/youtube.com(.+)v=([^&]+)/)) {
+ data.width = 425;
+ data.height = 350;
+ data.params.frameborder = '0';
+ data.type = 'iframe';
+ src = 'http://www.youtube.com/embed/' + src.match(/v=([^&]+)/)[1];
+ setVal('src', src);
+ setVal('media_type', data.type);
+ }
+
+ // Google video
+ if (src.match(/video.google.com(.+)docid=([^&]+)/)) {
+ data.width = 425;
+ data.height = 326;
+ data.type = 'flash';
+ src = 'http://video.google.com/googleplayer.swf?docId=' + src.match(/docid=([^&]+)/)[1] + '&hl=en';
+ setVal('src', src);
+ setVal('media_type', data.type);
+ }
+
+ if (data.type == 'video') {
+ if (!data.video.sources)
+ data.video.sources = [];
+
+ data.video.sources[0] = {src : src};
+
+ src = getVal("video_altsource1");
+ if (src)
+ data.video.sources[1] = {src : src};
+
+ src = getVal("video_altsource2");
+ if (src)
+ data.video.sources[2] = {src : src};
+ } else if (data.type == 'audio') {
+ if (!data.video.sources)
+ data.video.sources = [];
+
+ data.video.sources[0] = {src : src};
+
+ src = getVal("audio_altsource1");
+ if (src)
+ data.video.sources[1] = {src : src};
+
+ src = getVal("audio_altsource2");
+ if (src)
+ data.video.sources[2] = {src : src};
+ } else
+ data.params.src = src;
+
+ // Set default size
+ setVal('width', data.width || (data.type == 'audio' ? 300 : 320));
+ setVal('height', data.height || (data.type == 'audio' ? 32 : 240));
+ }
+ },
+
+ dataToForm : function() {
+ this.moveStates(true);
+ },
+
+ formToData : function(field) {
+ if (field == "width" || field == "height")
+ this.changeSize(field);
+
+ if (field == 'source') {
+ this.moveStates(false, field);
+ setVal('source', this.editor.plugins.media.dataToHtml(this.data));
+ this.panel = 'source';
+ } else {
+ if (this.panel == 'source') {
+ this.data = clone(this.editor.plugins.media.htmlToData(getVal('source')));
+ this.dataToForm();
+ this.panel = '';
+ }
+
+ this.moveStates(false, field);
+ this.preview();
+ }
+ },
+
+ beforeResize : function() {
+ this.width = parseInt(getVal('width') || (this.data.type == 'audio' ? "300" : "320"), 10);
+ this.height = parseInt(getVal('height') || (this.data.type == 'audio' ? "32" : "240"), 10);
+ },
+
+ changeSize : function(type) {
+ var width, height, scale, size;
+
+ if (get('constrain').checked) {
+ width = parseInt(getVal('width') || (this.data.type == 'audio' ? "300" : "320"), 10);
+ height = parseInt(getVal('height') || (this.data.type == 'audio' ? "32" : "240"), 10);
+
+ if (type == 'width') {
+ this.height = Math.round((width / this.width) * height);
+ setVal('height', this.height);
+ } else {
+ this.width = Math.round((height / this.height) * width);
+ setVal('width', this.width);
+ }
+ }
+ },
+
+ getMediaListHTML : function() {
+ if (typeof(tinyMCEMediaList) != "undefined" && tinyMCEMediaList.length > 0) {
+ var html = "";
+
+ html += '<select id="linklist" name="linklist" style="width: 250px" onchange="this.form.src.value=this.options[this.selectedIndex].value;Media.formToData(\'src\');">';
+ html += '<option value="">---</option>';
+
+ for (var i=0; i<tinyMCEMediaList.length; i++)
+ html += '<option value="' + tinyMCEMediaList[i][1] + '">' + tinyMCEMediaList[i][0] + '</option>';
+
+ html += '</select>';
+
+ return html;
+ }
+
+ return "";
+ },
+
+ getMediaTypeHTML : function(editor) {
+ function option(media_type, element) {
+ if (!editor.schema.getElementRule(element || media_type)) {
+ return '';
+ }
+
+ return '<option value="'+media_type+'">'+tinyMCEPopup.editor.translate("media_dlg."+media_type)+'</option>'
+ }
+
+ var html = "";
+
+ html += '<select id="media_type" name="media_type" onchange="Media.formToData(\'type\');">';
+ html += option("video");
+ html += option("audio");
+ html += option("flash", "object");
+ html += option("quicktime", "object");
+ html += option("shockwave", "object");
+ html += option("windowsmedia", "object");
+ html += option("realmedia", "object");
+ html += option("iframe");
+
+ if (editor.getParam('media_embedded_audio', false)) {
+ html += option('embeddedaudio', "object");
+ }
+
+ html += '</select>';
+ return html;
+ },
+
+ setDefaultDialogSettings : function(editor) {
+ var defaultDialogSettings = editor.getParam("media_dialog_defaults", {});
+ tinymce.each(defaultDialogSettings, function(v, k) {
+ setVal(k, v);
+ });
+ }
+ };
+
+ tinyMCEPopup.requireLangPack();
+ tinyMCEPopup.onInit.add(function() {
+ Media.init();
+ });
+})();
diff --git a/askbot/media/js/tinymce/plugins/media/langs/en_dlg.js b/askbot/media/js/tinymce/plugins/media/langs/en_dlg.js
new file mode 100644
index 00000000..ecef3a80
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/media/langs/en_dlg.js
@@ -0,0 +1 @@
+tinyMCE.addI18n('en.media_dlg',{list:"List",file:"File/URL",advanced:"Advanced",general:"General",title:"Insert/Edit Embedded Media","align_top_left":"Top Left","align_center":"Center","align_left":"Left","align_bottom":"Bottom","align_right":"Right","align_top":"Top","qt_stream_warn":"Streamed RTSP resources should be added to the QT Source field under the Advanced tab.\nYou should also add a non-streamed version to the Source field.",qtsrc:"QT Source",progress:"Progress",sound:"Sound",swstretchvalign:"Stretch V-Align",swstretchhalign:"Stretch H-Align",swstretchstyle:"Stretch Style",scriptcallbacks:"Script Callbacks","align_top_right":"Top Right",uimode:"UI Mode",rate:"Rate",playcount:"Play Count",defaultframe:"Default Frame",currentposition:"Current Position",currentmarker:"Current Marker",captioningid:"Captioning ID",baseurl:"Base URL",balance:"Balance",windowlessvideo:"Windowless Video",stretchtofit:"Stretch to Fit",mute:"Mute",invokeurls:"Invoke URLs",fullscreen:"Full Screen",enabled:"Enabled",autostart:"Auto Start",volume:"Volume",target:"Target",qtsrcchokespeed:"Choke Speed",href:"HREF",endtime:"End Time",starttime:"Start Time",enablejavascript:"Enable JavaScript",correction:"No Correction",targetcache:"Target Cache",playeveryframe:"Play Every Frame",kioskmode:"Kiosk Mode",controller:"Controller",menu:"Show Menu",loop:"Loop",play:"Auto Play",hspace:"H-Space",vspace:"V-Space","class_name":"Class",name:"Name",id:"ID",type:"Type",size:"Dimensions",preview:"Preview","constrain_proportions":"Constrain Proportions",controls:"Controls",numloop:"Num Loops",console:"Console",cache:"Cache",autohref:"Auto HREF",liveconnect:"SWLiveConnect",flashvars:"Flash Vars",base:"Base",bgcolor:"Background",wmode:"WMode",salign:"SAlign",align:"Align",scale:"Scale",quality:"Quality",shuffle:"Shuffle",prefetch:"Prefetch",nojava:"No Java",maintainaspect:"Maintain Aspect",imagestatus:"Image Status",center:"Center",autogotourl:"Auto Goto URL","shockwave_options":"Shockwave Options","rmp_options":"Real Media Player Options","wmp_options":"Windows Media Player Options","qt_options":"QuickTime Options","flash_options":"Flash Options",hidden:"Hidden","align_bottom_left":"Bottom Left","align_bottom_right":"Bottom Right","html5_video_options":"HTML5 Video Options",altsource1:"Alternative source 1",altsource2:"Alternative source 2",preload:"Preload",poster:"Poster",source:"Source","html5_audio_options":"Audio Options","preload_none":"Don\'t Preload","preload_metadata":"Preload video metadata","preload_auto":"Let user\'s browser decide", "embedded_audio_options":"Embedded Audio Options", video:"HTML5 Video", audio:"HTML5 Audio", flash:"Flash", quicktime:"QuickTime", shockwave:"Shockwave", windowsmedia:"Windows Media", realmedia:"Real Media", iframe:"Iframe", embeddedaudio:"Embedded Audio" });
diff --git a/askbot/media/js/tinymce/plugins/media/media.htm b/askbot/media/js/tinymce/plugins/media/media.htm
new file mode 100644
index 00000000..957d83a6
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/media/media.htm
@@ -0,0 +1,922 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#media_dlg.title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="js/media.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/validate.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="../../utils/editable_selects.js"></script>
+ <link href="css/media.css" rel="stylesheet" type="text/css" />
+</head>
+<body style="display: none" role="application">
+<form onsubmit="Media.insert();return false;" action="#">
+ <div class="tabs" role="presentation">
+ <ul>
+ <li id="general_tab" class="current" aria-controls="general_panel"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');Media.formToData();" onmousedown="return false;">{#media_dlg.general}</a></span></li>
+ <li id="advanced_tab" aria-controls="advanced_panel"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');Media.formToData();" onmousedown="return false;">{#media_dlg.advanced}</a></span></li>
+ <li id="source_tab" aria-controls="source_panel"><span><a href="javascript:mcTabs.displayTab('source_tab','source_panel');Media.formToData('source');" onmousedown="return false;">{#media_dlg.source}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <fieldset>
+ <legend>{#media_dlg.general}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td><label for="media_type">{#media_dlg.type}</label></td>
+ <td>
+ <select id="media_type"></select>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="src">{#media_dlg.file}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input id="src" name="src" type="text" value="" class="mceFocus" onchange="Media.formToData();" /></td>
+ <td id="filebrowsercontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr id="linklistrow">
+ <td><label for="linklist">{#media_dlg.list}</label></td>
+ <td id="linklistcontainer"><select id="linklist"><option value=""></option></select></td>
+ </tr>
+ <tr>
+ <td><label for="width">{#media_dlg.size}</label></td>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="text" id="width" name="width" value="" class="size" onchange="Media.formToData('width');" onfocus="Media.beforeResize();" /> x <input type="text" id="height" name="height" value="" class="size" onfocus="Media.beforeResize();" onchange="Media.formToData('height');" /></td>
+ <td>&nbsp;&nbsp;<input id="constrain" type="checkbox" name="constrain" class="checkbox" checked="checked" /></td>
+ <td><label id="constrainlabel" for="constrain">{#media_dlg.constrain_proportions}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset>
+ <legend>{#media_dlg.preview}</legend>
+ <div id="prev"></div>
+ </fieldset>
+ </div>
+
+ <div id="advanced_panel" class="panel">
+ <fieldset>
+ <legend>{#media_dlg.advanced}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0" width="100%">
+ <tr>
+ <td><label for="id">{#media_dlg.id}</label></td>
+ <td><input type="text" id="id" name="id" onchange="Media.formToData();" /></td>
+ <td><label for="name">{#media_dlg.name}</label></td>
+ <td><input type="text" id="name" name="name" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="align">{#media_dlg.align}</label></td>
+ <td>
+ <select id="align" name="align" onchange="Media.formToData();">
+ <option value="">{#not_set}</option>
+ <option value="top">{#media_dlg.align_top}</option>
+ <option value="right">{#media_dlg.align_right}</option>
+ <option value="bottom">{#media_dlg.align_bottom}</option>
+ <option value="left">{#media_dlg.align_left}</option>
+ </select>
+ </td>
+
+ <td><label for="bgcolor">{#media_dlg.bgcolor}</label></td>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="bgcolor" name="bgcolor" type="text" value="" size="9" onchange="updateColor('bgcolor_pick','bgcolor');Media.formToData();" /></td>
+ <td id="bgcolor_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="vspace">{#media_dlg.vspace}</label></td>
+ <td><input type="text" id="vspace" name="vspace" class="number" onchange="Media.formToData();" /></td>
+ <td><label for="hspace">{#media_dlg.hspace}</label></td>
+ <td><input type="text" id="hspace" name="hspace" class="number" onchange="Media.formToData();" /></td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset id="video_options">
+ <legend>{#media_dlg.html5_video_options}</legend>
+
+ <table role="presentation">
+ <tr>
+ <td><label for="video_altsource1">{#media_dlg.altsource1}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="video_altsource1" name="video_altsource1" onchange="Media.formToData();" style="width: 240px" /></td>
+ <td id="video_altsource1_filebrowser">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="video_altsource2">{#media_dlg.altsource2}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="video_altsource2" name="video_altsource2" onchange="Media.formToData();" style="width: 240px" /></td>
+ <td id="video_altsource2_filebrowser">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="video_poster">{#media_dlg.poster}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="video_poster" name="video_poster" onchange="Media.formToData();" style="width: 240px" /></td>
+ <td id="video_poster_filebrowser">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="video_preload">{#media_dlg.preload}</label></td>
+ <td>
+ <select id="video_preload" name="video_preload" onchange="Media.formToData();">
+ <option value="none">{#media_dlg.preload_none}</option>
+ <option value="metadata">{#media_dlg.preload_metadata}</option>
+ <option value="auto">{#media_dlg.preload_auto}</option>
+ </select>
+ </td>
+ </tr>
+ </table>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="video_autoplay" name="video_autoplay" onchange="Media.formToData();" /></td>
+ <td><label for="video_autoplay">{#media_dlg.play}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="video_muted" name="video_muted" onchange="Media.formToData();" /></td>
+ <td><label for="video_muted">{#media_dlg.mute}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="video_loop" name="video_loop" onchange="Media.formToData();" /></td>
+ <td><label for="video_loop">{#media_dlg.loop}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="video_controls" name="video_controls" onchange="Media.formToData();" /></td>
+ <td><label for="video_controls">{#media_dlg.controls}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset id="embeddedaudio_options">
+ <legend>{#media_dlg.embedded_audio_options}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="embeddedaudio_autoplay" name="audio_autoplay" onchange="Media.formToData();" /></td>
+ <td><label for="audio_autoplay">{#media_dlg.play}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="embeddedaudio_loop" name="audio_loop" onchange="Media.formToData();" /></td>
+ <td><label for="audio_loop">{#media_dlg.loop}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="embeddedaudio_controls" name="audio_controls" onchange="Media.formToData();" /></td>
+ <td><label for="audio_controls">{#media_dlg.controls}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset id="audio_options">
+ <legend>{#media_dlg.html5_audio_options}</legend>
+
+ <table role="presentation">
+ <tr>
+ <td><label for="audio_altsource1">{#media_dlg.altsource1}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="audio_altsource1" name="audio_altsource1" onchange="Media.formToData();" style="width: 240px" /></td>
+ <td id="audio_altsource1_filebrowser">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="audio_altsource2">{#media_dlg.altsource2}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="audio_altsource2" name="audio_altsource2" onchange="Media.formToData();" style="width: 240px" /></td>
+ <td id="audio_altsource2_filebrowser">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="audio_preload">{#media_dlg.preload}</label></td>
+ <td>
+ <select id="audio_preload" name="audio_preload" onchange="Media.formToData();">
+ <option value="none">{#media_dlg.preload_none}</option>
+ <option value="metadata">{#media_dlg.preload_metadata}</option>
+ <option value="auto">{#media_dlg.preload_auto}</option>
+ </select>
+ </td>
+ </tr>
+ </table>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="audio_autoplay" name="audio_autoplay" onchange="Media.formToData();" /></td>
+ <td><label for="audio_autoplay">{#media_dlg.play}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="audio_loop" name="audio_loop" onchange="Media.formToData();" /></td>
+ <td><label for="audio_loop">{#media_dlg.loop}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="audio_controls" name="audio_controls" onchange="Media.formToData();" /></td>
+ <td><label for="audio_controls">{#media_dlg.controls}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset id="flash_options">
+ <legend>{#media_dlg.flash_options}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td><label for="flash_quality">{#media_dlg.quality}</label></td>
+ <td>
+ <select id="flash_quality" name="flash_quality" onchange="Media.formToData();">
+ <option value="">{#not_set}</option>
+ <option value="high">high</option>
+ <option value="low">low</option>
+ <option value="autolow">autolow</option>
+ <option value="autohigh">autohigh</option>
+ <option value="best">best</option>
+ </select>
+ </td>
+
+ <td><label for="flash_scale">{#media_dlg.scale}</label></td>
+ <td>
+ <select id="flash_scale" name="flash_scale" onchange="Media.formToData();">
+ <option value="">{#not_set}</option>
+ <option value="showall">showall</option>
+ <option value="noborder">noborder</option>
+ <option value="exactfit">exactfit</option>
+ <option value="noscale">noscale</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="flash_wmode">{#media_dlg.wmode}</label></td>
+ <td>
+ <select id="flash_wmode" name="flash_wmode" onchange="Media.formToData();">
+ <option value="">{#not_set}</option>
+ <option value="window">window</option>
+ <option value="opaque">opaque</option>
+ <option value="transparent">transparent</option>
+ </select>
+ </td>
+
+ <td><label for="flash_salign">{#media_dlg.salign}</label></td>
+ <td>
+ <select id="flash_salign" name="flash_salign" onchange="Media.formToData();">
+ <option value="">{#not_set}</option>
+ <option value="l">{#media_dlg.align_left}</option>
+ <option value="t">{#media_dlg.align_top}</option>
+ <option value="r">{#media_dlg.align_right}</option>
+ <option value="b">{#media_dlg.align_bottom}</option>
+ <option value="tl">{#media_dlg.align_top_left}</option>
+ <option value="tr">{#media_dlg.align_top_right}</option>
+ <option value="bl">{#media_dlg.align_bottom_left}</option>
+ <option value="br">{#media_dlg.align_bottom_right}</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="flash_play" name="flash_play" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="flash_play">{#media_dlg.play}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="flash_loop" name="flash_loop" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="flash_loop">{#media_dlg.loop}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="flash_menu" name="flash_menu" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="flash_menu">{#media_dlg.menu}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="flash_swliveconnect" name="flash_swliveconnect" onchange="Media.formToData();" /></td>
+ <td><label for="flash_swliveconnect">{#media_dlg.liveconnect}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+
+ <table role="presentation">
+ <tr>
+ <td><label for="flash_base">{#media_dlg.base}</label></td>
+ <td><input type="text" id="flash_base" name="flash_base" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="flash_flashvars">{#media_dlg.flashvars}</label></td>
+ <td><input type="text" id="flash_flashvars" name="flash_flashvars" onchange="Media.formToData();" /></td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset id="quicktime_options">
+ <legend>{#media_dlg.qt_options}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_loop" name="quicktime_loop" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_loop">{#media_dlg.loop}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_autoplay" name="quicktime_autoplay" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_autoplay">{#media_dlg.play}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_cache" name="quicktime_cache" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_cache">{#media_dlg.cache}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_controller" name="quicktime_controller" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_controller">{#media_dlg.controller}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_correction" name="quicktime_correction" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_correction">{#media_dlg.correction}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_enablejavascript" name="quicktime_enablejavascript" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_enablejavascript">{#media_dlg.enablejavascript}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_kioskmode" name="quicktime_kioskmode" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_kioskmode">{#media_dlg.kioskmode}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_autohref" name="quicktime_autohref" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_autohref">{#media_dlg.autohref}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_playeveryframe" name="quicktime_playeveryframe" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_playeveryframe">{#media_dlg.playeveryframe}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="quicktime_targetcache" name="quicktime_targetcache" onchange="Media.formToData();" /></td>
+ <td><label for="quicktime_targetcache">{#media_dlg.targetcache}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="quicktime_scale">{#media_dlg.scale}</label></td>
+ <td><select id="quicktime_scale" name="quicktime_scale" class="mceEditableSelect" onchange="Media.formToData();">
+ <option value="">{#not_set}</option>
+ <option value="tofit">tofit</option>
+ <option value="aspect">aspect</option>
+ </select>
+ </td>
+
+ <td colspan="2">&nbsp;</td>
+ </tr>
+
+ <tr>
+ <td><label for="quicktime_starttime">{#media_dlg.starttime}</label></td>
+ <td><input type="text" id="quicktime_starttime" name="quicktime_starttime" onchange="Media.formToData();" /></td>
+
+ <td><label for="quicktime_endtime">{#media_dlg.endtime}</label></td>
+ <td><input type="text" id="quicktime_endtime" name="quicktime_endtime" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="quicktime_target">{#media_dlg.target}</label></td>
+ <td><input type="text" id="quicktime_target" name="quicktime_target" onchange="Media.formToData();" /></td>
+
+ <td><label for="quicktime_href">{#media_dlg.href}</label></td>
+ <td><input type="text" id="quicktime_href" name="quicktime_href" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="quicktime_qtsrcchokespeed">{#media_dlg.qtsrcchokespeed}</label></td>
+ <td><input type="text" id="quicktime_qtsrcchokespeed" name="quicktime_qtsrcchokespeed" onchange="Media.formToData();" /></td>
+
+ <td><label for="quicktime_volume">{#media_dlg.volume}</label></td>
+ <td><input type="text" id="quicktime_volume" name="quicktime_volume" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="quicktime_qtsrc">{#media_dlg.qtsrc}</label></td>
+ <td colspan="4">
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="quicktime_qtsrc" name="quicktime_qtsrc" onchange="Media.formToData();" /></td>
+ <td id="qtsrcfilebrowsercontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset id="windowsmedia_options">
+ <legend>{#media_dlg.wmp_options}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="windowsmedia_autostart" name="windowsmedia_autostart" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="windowsmedia_autostart">{#media_dlg.autostart}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="windowsmedia_enabled" name="windowsmedia_enabled" onchange="Media.formToData();" /></td>
+ <td><label for="windowsmedia_enabled">{#media_dlg.enabled}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="windowsmedia_enablecontextmenu" name="windowsmedia_enablecontextmenu" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="windowsmedia_enablecontextmenu">{#media_dlg.menu}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="windowsmedia_fullscreen" name="windowsmedia_fullscreen" onchange="Media.formToData();" /></td>
+ <td><label for="windowsmedia_fullscreen">{#media_dlg.fullscreen}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="windowsmedia_invokeurls" name="windowsmedia_invokeurls" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="windowsmedia_invokeurls">{#media_dlg.invokeurls}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="windowsmedia_mute" name="windowsmedia_mute" onchange="Media.formToData();" /></td>
+ <td><label for="windowsmedia_mute">{#media_dlg.mute}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="windowsmedia_stretchtofit" name="windowsmedia_stretchtofit" onchange="Media.formToData();" /></td>
+ <td><label for="windowsmedia_stretchtofit">{#media_dlg.stretchtofit}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="windowsmedia_windowlessvideo" name="windowsmedia_windowlessvideo" onchange="Media.formToData();" /></td>
+ <td><label for="windowsmedia_windowlessvideo">{#media_dlg.windowlessvideo}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="windowsmedia_balance">{#media_dlg.balance}</label></td>
+ <td><input type="text" id="windowsmedia_balance" name="windowsmedia_balance" onchange="Media.formToData();" /></td>
+
+ <td><label for="windowsmedia_baseurl">{#media_dlg.baseurl}</label></td>
+ <td><input type="text" id="windowsmedia_baseurl" name="windowsmedia_baseurl" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="windowsmedia_captioningid">{#media_dlg.captioningid}</label></td>
+ <td><input type="text" id="windowsmedia_captioningid" name="windowsmedia_captioningid" onchange="Media.formToData();" /></td>
+
+ <td><label for="windowsmedia_currentmarker">{#media_dlg.currentmarker}</label></td>
+ <td><input type="text" id="windowsmedia_currentmarker" name="windowsmedia_currentmarker" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="windowsmedia_currentposition">{#media_dlg.currentposition}</label></td>
+ <td><input type="text" id="windowsmedia_currentposition" name="windowsmedia_currentposition" onchange="Media.formToData();" /></td>
+
+ <td><label for="windowsmedia_defaultframe">{#media_dlg.defaultframe}</label></td>
+ <td><input type="text" id="windowsmedia_defaultframe" name="windowsmedia_defaultframe" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="windowsmedia_playcount">{#media_dlg.playcount}</label></td>
+ <td><input type="text" id="windowsmedia_playcount" name="windowsmedia_playcount" onchange="Media.formToData();" /></td>
+
+ <td><label for="windowsmedia_rate">{#media_dlg.rate}</label></td>
+ <td><input type="text" id="windowsmedia_rate" name="windowsmedia_rate" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="windowsmedia_uimode">{#media_dlg.uimode}</label></td>
+ <td><input type="text" id="windowsmedia_uimode" name="windowsmedia_uimode" onchange="Media.formToData();" /></td>
+
+ <td><label for="windowsmedia_volume">{#media_dlg.volume}</label></td>
+ <td><input type="text" id="windowsmedia_volume" name="windowsmedia_volume" onchange="Media.formToData();" /></td>
+ </tr>
+
+ </table>
+ </fieldset>
+
+ <fieldset id="realmedia_options">
+ <legend>{#media_dlg.rmp_options}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_autostart" name="realmedia_autostart" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_autostart">{#media_dlg.autostart}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_loop" name="realmedia_loop" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_loop">{#media_dlg.loop}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_autogotourl" name="realmedia_autogotourl" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_autogotourl">{#media_dlg.autogotourl}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_center" name="realmedia_center" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_center">{#media_dlg.center}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_imagestatus" name="realmedia_imagestatus" checked="checked" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_imagestatus">{#media_dlg.imagestatus}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_maintainaspect" name="realmedia_maintainaspect" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_maintainaspect">{#media_dlg.maintainaspect}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_nojava" name="realmedia_nojava" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_nojava">{#media_dlg.nojava}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_prefetch" name="realmedia_prefetch" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_prefetch">{#media_dlg.prefetch}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="realmedia_shuffle" name="realmedia_shuffle" onchange="Media.formToData();" /></td>
+ <td><label for="realmedia_shuffle">{#media_dlg.shuffle}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ &nbsp;
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="realmedia_console">{#media_dlg.console}</label></td>
+ <td><input type="text" id="realmedia_console" name="realmedia_console" onchange="Media.formToData();" /></td>
+
+ <td><label for="realmedia_controls">{#media_dlg.controls}</label></td>
+ <td><input type="text" id="realmedia_controls" name="realmedia_controls" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="realmedia_numloop">{#media_dlg.numloop}</label></td>
+ <td><input type="text" id="realmedia_numloop" name="realmedia_numloop" onchange="Media.formToData();" /></td>
+
+ <td><label for="realmedia_scriptcallbacks">{#media_dlg.scriptcallbacks}</label></td>
+ <td><input type="text" id="realmedia_scriptcallbacks" name="realmedia_scriptcallbacks" onchange="Media.formToData();" /></td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <fieldset id="shockwave_options">
+ <legend>{#media_dlg.shockwave_options}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td><label for="shockwave_swstretchstyle">{#media_dlg.swstretchstyle}</label></td>
+ <td>
+ <select id="shockwave_swstretchstyle" name="shockwave_swstretchstyle" onchange="Media.formToData();">
+ <option value="none">{#not_set}</option>
+ <option value="meet">Meet</option>
+ <option value="fill">Fill</option>
+ <option value="stage">Stage</option>
+ </select>
+ </td>
+
+ <td><label for="shockwave_swvolume">{#media_dlg.volume}</label></td>
+ <td><input type="text" id="shockwave_swvolume" name="shockwave_swvolume" onchange="Media.formToData();" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="shockwave_swstretchhalign">{#media_dlg.swstretchhalign}</label></td>
+ <td>
+ <select id="shockwave_swstretchhalign" name="shockwave_swstretchhalign" onchange="Media.formToData();">
+ <option value="none">{#not_set}</option>
+ <option value="left">{#media_dlg.align_left}</option>
+ <option value="center">{#media_dlg.align_center}</option>
+ <option value="right">{#media_dlg.align_right}</option>
+ </select>
+ </td>
+
+ <td><label for="shockwave_swstretchvalign">{#media_dlg.swstretchvalign}</label></td>
+ <td>
+ <select id="shockwave_swstretchvalign" name="shockwave_swstretchvalign" onchange="Media.formToData();">
+ <option value="none">{#not_set}</option>
+ <option value="meet">Meet</option>
+ <option value="fill">Fill</option>
+ <option value="stage">Stage</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="shockwave_autostart" name="shockwave_autostart" onchange="Media.formToData();" checked="checked" /></td>
+ <td><label for="shockwave_autostart">{#media_dlg.autostart}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="shockwave_sound" name="shockwave_sound" onchange="Media.formToData();" checked="checked" /></td>
+ <td><label for="shockwave_sound">{#media_dlg.sound}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="shockwave_swliveconnect" name="shockwave_swliveconnect" onchange="Media.formToData();" /></td>
+ <td><label for="shockwave_swliveconnect">{#media_dlg.liveconnect}</label></td>
+ </tr>
+ </table>
+ </td>
+
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input type="checkbox" class="checkbox" id="shockwave_progress" name="shockwave_progress" onchange="Media.formToData();" checked="checked" /></td>
+ <td><label for="shockwave_progress">{#media_dlg.progress}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+
+ <div id="source_panel" class="panel">
+ <fieldset>
+ <legend>{#media_dlg.source}</legend>
+ <textarea id="source" style="width: 99%; height: 390px"></textarea>
+ </fieldset>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#insert}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+ </form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/media/moxieplayer.swf b/askbot/media/js/tinymce/plugins/media/moxieplayer.swf
new file mode 100644
index 00000000..585d772d
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/media/moxieplayer.swf
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/nonbreaking/editor_plugin.js b/askbot/media/js/tinymce/plugins/nonbreaking/editor_plugin.js
new file mode 100644
index 00000000..687f5486
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/nonbreaking/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.Nonbreaking",{init:function(a,b){var c=this;c.editor=a;a.addCommand("mceNonBreaking",function(){a.execCommand("mceInsertContent",false,(a.plugins.visualchars&&a.plugins.visualchars.state)?'<span data-mce-bogus="1" class="mceItemHidden mceItemNbsp">&nbsp;</span>':"&nbsp;")});a.addButton("nonbreaking",{title:"nonbreaking.nonbreaking_desc",cmd:"mceNonBreaking"});if(a.getParam("nonbreaking_force_tab")){a.onKeyDown.add(function(d,f){if(f.keyCode==9){f.preventDefault();d.execCommand("mceNonBreaking");d.execCommand("mceNonBreaking");d.execCommand("mceNonBreaking")}})}},getInfo:function(){return{longname:"Nonbreaking space",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/nonbreaking",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("nonbreaking",tinymce.plugins.Nonbreaking)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/nonbreaking/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/nonbreaking/editor_plugin_src.js
new file mode 100644
index 00000000..d492fbef
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/nonbreaking/editor_plugin_src.js
@@ -0,0 +1,54 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.Nonbreaking', {
+ init : function(ed, url) {
+ var t = this;
+
+ t.editor = ed;
+
+ // Register commands
+ ed.addCommand('mceNonBreaking', function() {
+ ed.execCommand('mceInsertContent', false, (ed.plugins.visualchars && ed.plugins.visualchars.state) ? '<span data-mce-bogus="1" class="mceItemHidden mceItemNbsp">&nbsp;</span>' : '&nbsp;');
+ });
+
+ // Register buttons
+ ed.addButton('nonbreaking', {title : 'nonbreaking.nonbreaking_desc', cmd : 'mceNonBreaking'});
+
+ if (ed.getParam('nonbreaking_force_tab')) {
+ ed.onKeyDown.add(function(ed, e) {
+ if (e.keyCode == 9) {
+ e.preventDefault();
+
+ ed.execCommand('mceNonBreaking');
+ ed.execCommand('mceNonBreaking');
+ ed.execCommand('mceNonBreaking');
+ }
+ });
+ }
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Nonbreaking space',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/nonbreaking',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+
+ // Private methods
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('nonbreaking', tinymce.plugins.Nonbreaking);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/noneditable/editor_plugin.js b/askbot/media/js/tinymce/plugins/noneditable/editor_plugin.js
new file mode 100644
index 00000000..e204328d
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/noneditable/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var c=tinymce.dom.TreeWalker;var a="contenteditable",d="data-mce-"+a;var e=tinymce.VK;function b(n){var j=n.dom,p=n.selection,r,o="mce_noneditablecaret";r=tinymce.isGecko?"\u200B":"\uFEFF";function m(t){var s;if(t.nodeType===1){s=t.getAttribute(d);if(s&&s!=="inherit"){return s}s=t.contentEditable;if(s!=="inherit"){return s}}return null}function g(s){var t;while(s){t=m(s);if(t){return t==="false"?s:null}s=s.parentNode}}function l(s){while(s){if(s.id===o){return s}s=s.parentNode}}function k(s){var t;if(s){t=new c(s,s);for(s=t.current();s;s=t.next()){if(s.nodeType===3){return s}}}}function f(v,u){var s,t;if(m(v)==="false"){if(j.isBlock(v)){p.select(v);return}}t=j.createRng();if(m(v)==="true"){if(!v.firstChild){v.appendChild(n.getDoc().createTextNode("\u00a0"))}v=v.firstChild;u=true}s=j.create("span",{id:o,"data-mce-bogus":true},r);if(u){v.parentNode.insertBefore(s,v)}else{j.insertAfter(s,v)}t.setStart(s.firstChild,1);t.collapse(true);p.setRng(t);return s}function i(s){var v,t,u;if(s){rng=p.getRng(true);rng.setStartBefore(s);rng.setEndBefore(s);v=k(s);if(v&&v.nodeValue.charAt(0)==r){v=v.deleteData(0,1)}j.remove(s,true);p.setRng(rng)}else{t=l(p.getStart());while((s=j.get(o))&&s!==u){if(t!==s){v=k(s);if(v&&v.nodeValue.charAt(0)==r){v=v.deleteData(0,1)}j.remove(s,true)}u=s}}}function q(){var s,w,u,t,v;function x(B,D){var A,F,E,C,z;A=t.startContainer;F=t.startOffset;if(A.nodeType==3){z=A.nodeValue.length;if((F>0&&F<z)||(D?F==z:F==0)){return}}else{if(F<A.childNodes.length){var G=!D&&F>0?F-1:F;A=A.childNodes[G];if(A.hasChildNodes()){A=A.firstChild}}else{return !D?B:null}}E=new c(A,B);while(C=E[D?"prev":"next"]()){if(C.nodeType===3&&C.nodeValue.length>0){return}else{if(m(C)==="true"){return C}}}return B}i();u=p.isCollapsed();s=g(p.getStart());w=g(p.getEnd());if(s||w){t=p.getRng(true);if(u){s=s||w;var y=p.getStart();if(v=x(s,true)){f(v,true)}else{if(v=x(s,false)){f(v,false)}else{p.select(s)}}}else{t=p.getRng(true);if(s){t.setStartBefore(s)}if(w){t.setEndAfter(w)}p.setRng(t)}}}function h(z,B){var F=B.keyCode,x,C,D,v;function u(H,G){while(H=H[G?"previousSibling":"nextSibling"]){if(H.nodeType!==3||H.nodeValue.length>0){return H}}}function y(G,H){p.select(G);p.collapse(H)}function t(K){var J,I,M,H;function G(O){var N=I;while(N){if(N===O){return}N=N.parentNode}j.remove(O);q()}function L(){var O,P,N=z.schema.getNonEmptyElements();P=new tinymce.dom.TreeWalker(I,z.getBody());while(O=(K?P.prev():P.next())){if(N[O.nodeName.toLowerCase()]){break}if(O.nodeType===3&&tinymce.trim(O.nodeValue).length>0){break}if(m(O)==="false"){G(O);return true}}if(g(O)){return true}return false}if(p.isCollapsed()){J=p.getRng(true);I=J.startContainer;M=J.startOffset;I=l(I)||I;if(H=g(I)){G(H);return false}if(I.nodeType==3&&(K?M>0:M<I.nodeValue.length)){return true}if(I.nodeType==1){I=I.childNodes[M]||I}if(L()){return false}}return true}D=p.getStart();v=p.getEnd();x=g(D)||g(v);if(x&&(F<112||F>124)&&F!=e.DELETE&&F!=e.BACKSPACE){if((tinymce.isMac?B.metaKey:B.ctrlKey)&&(F==67||F==88||F==86)){return}B.preventDefault();if(F==e.LEFT||F==e.RIGHT){var w=F==e.LEFT;if(z.dom.isBlock(x)){var A=w?x.previousSibling:x.nextSibling;var s=new c(A,A);var E=w?s.prev():s.next();y(E,!w)}else{y(x,w)}}}else{if(F==e.LEFT||F==e.RIGHT||F==e.BACKSPACE||F==e.DELETE){C=l(D);if(C){if(F==e.LEFT||F==e.BACKSPACE){x=u(C,true);if(x&&m(x)==="false"){B.preventDefault();if(F==e.LEFT){y(x,true)}else{j.remove(x);return}}else{i(C)}}if(F==e.RIGHT||F==e.DELETE){x=u(C);if(x&&m(x)==="false"){B.preventDefault();if(F==e.RIGHT){y(x,false)}else{j.remove(x);return}}else{i(C)}}}if((F==e.BACKSPACE||F==e.DELETE)&&!t(F==e.BACKSPACE)){B.preventDefault();return false}}}}n.onMouseDown.addToTop(function(s,u){var t=s.selection.getNode();if(m(t)==="false"&&t==u.target){q()}});n.onMouseUp.addToTop(q);n.onKeyDown.addToTop(h);n.onKeyUp.addToTop(q)}tinymce.create("tinymce.plugins.NonEditablePlugin",{init:function(i,k){var h,g,j;function f(m,n){var o=j.length,p=n.content,l=tinymce.trim(g);if(n.format=="raw"){return}while(o--){p=p.replace(j[o],function(s){var r=arguments,q=r[r.length-2];if(q>0&&p.charAt(q-1)=='"'){return s}return'<span class="'+l+'" data-mce-content="'+m.dom.encode(r[0])+'">'+m.dom.encode(typeof(r[1])==="string"?r[1]:r[0])+"</span>"})}n.content=p}h=" "+tinymce.trim(i.getParam("noneditable_editable_class","mceEditable"))+" ";g=" "+tinymce.trim(i.getParam("noneditable_noneditable_class","mceNonEditable"))+" ";j=i.getParam("noneditable_regexp");if(j&&!j.length){j=[j]}i.onPreInit.add(function(){b(i);if(j){i.selection.onBeforeSetContent.add(f);i.onBeforeSetContent.add(f)}i.parser.addAttributeFilter("class",function(l){var m=l.length,n,o;while(m--){o=l[m];n=" "+o.attr("class")+" ";if(n.indexOf(h)!==-1){o.attr(d,"true")}else{if(n.indexOf(g)!==-1){o.attr(d,"false")}}}});i.serializer.addAttributeFilter(d,function(l,m){var n=l.length,o;while(n--){o=l[n];if(j&&o.attr("data-mce-content")){o.name="#text";o.type=3;o.raw=true;o.value=o.attr("data-mce-content")}else{o.attr(a,null);o.attr(d,null)}}});i.parser.addAttributeFilter(a,function(l,m){var n=l.length,o;while(n--){o=l[n];o.attr(d,o.attr(a));o.attr(a,null)}})})},getInfo:function(){return{longname:"Non editable elements",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/noneditable",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("noneditable",tinymce.plugins.NonEditablePlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/noneditable/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/noneditable/editor_plugin_src.js
new file mode 100644
index 00000000..c0efe749
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/noneditable/editor_plugin_src.js
@@ -0,0 +1,540 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var TreeWalker = tinymce.dom.TreeWalker;
+ var externalName = 'contenteditable', internalName = 'data-mce-' + externalName;
+ var VK = tinymce.VK;
+
+ function handleContentEditableSelection(ed) {
+ var dom = ed.dom, selection = ed.selection, invisibleChar, caretContainerId = 'mce_noneditablecaret';
+
+ // Setup invisible character use zero width space on Gecko since it doesn't change the height of the container
+ invisibleChar = tinymce.isGecko ? '\u200B' : '\uFEFF';
+
+ // Returns the content editable state of a node "true/false" or null
+ function getContentEditable(node) {
+ var contentEditable;
+
+ // Ignore non elements
+ if (node.nodeType === 1) {
+ // Check for fake content editable
+ contentEditable = node.getAttribute(internalName);
+ if (contentEditable && contentEditable !== "inherit") {
+ return contentEditable;
+ }
+
+ // Check for real content editable
+ contentEditable = node.contentEditable;
+ if (contentEditable !== "inherit") {
+ return contentEditable;
+ }
+ }
+
+ return null;
+ };
+
+ // Returns the noneditable parent or null if there is a editable before it or if it wasn't found
+ function getNonEditableParent(node) {
+ var state;
+
+ while (node) {
+ state = getContentEditable(node);
+ if (state) {
+ return state === "false" ? node : null;
+ }
+
+ node = node.parentNode;
+ }
+ };
+
+ // Get caret container parent for the specified node
+ function getParentCaretContainer(node) {
+ while (node) {
+ if (node.id === caretContainerId) {
+ return node;
+ }
+
+ node = node.parentNode;
+ }
+ };
+
+ // Finds the first text node in the specified node
+ function findFirstTextNode(node) {
+ var walker;
+
+ if (node) {
+ walker = new TreeWalker(node, node);
+
+ for (node = walker.current(); node; node = walker.next()) {
+ if (node.nodeType === 3) {
+ return node;
+ }
+ }
+ }
+ };
+
+ // Insert caret container before/after target or expand selection to include block
+ function insertCaretContainerOrExpandToBlock(target, before) {
+ var caretContainer, rng;
+
+ // Select block
+ if (getContentEditable(target) === "false") {
+ if (dom.isBlock(target)) {
+ selection.select(target);
+ return;
+ }
+ }
+
+ rng = dom.createRng();
+
+ if (getContentEditable(target) === "true") {
+ if (!target.firstChild) {
+ target.appendChild(ed.getDoc().createTextNode('\u00a0'));
+ }
+
+ target = target.firstChild;
+ before = true;
+ }
+
+ //caretContainer = dom.create('span', {id: caretContainerId, 'data-mce-bogus': true, style:'border: 1px solid red'}, invisibleChar);
+ caretContainer = dom.create('span', {id: caretContainerId, 'data-mce-bogus': true}, invisibleChar);
+
+ if (before) {
+ target.parentNode.insertBefore(caretContainer, target);
+ } else {
+ dom.insertAfter(caretContainer, target);
+ }
+
+ rng.setStart(caretContainer.firstChild, 1);
+ rng.collapse(true);
+ selection.setRng(rng);
+
+ return caretContainer;
+ };
+
+ // Removes any caret container except the one we might be in
+ function removeCaretContainer(caretContainer) {
+ var child, currentCaretContainer, lastContainer;
+
+ if (caretContainer) {
+ rng = selection.getRng(true);
+ rng.setStartBefore(caretContainer);
+ rng.setEndBefore(caretContainer);
+
+ child = findFirstTextNode(caretContainer);
+ if (child && child.nodeValue.charAt(0) == invisibleChar) {
+ child = child.deleteData(0, 1);
+ }
+
+ dom.remove(caretContainer, true);
+
+ selection.setRng(rng);
+ } else {
+ currentCaretContainer = getParentCaretContainer(selection.getStart());
+ while ((caretContainer = dom.get(caretContainerId)) && caretContainer !== lastContainer) {
+ if (currentCaretContainer !== caretContainer) {
+ child = findFirstTextNode(caretContainer);
+ if (child && child.nodeValue.charAt(0) == invisibleChar) {
+ child = child.deleteData(0, 1);
+ }
+
+ dom.remove(caretContainer, true);
+ }
+
+ lastContainer = caretContainer;
+ }
+ }
+ };
+
+ // Modifies the selection to include contentEditable false elements or insert caret containers
+ function moveSelection() {
+ var nonEditableStart, nonEditableEnd, isCollapsed, rng, element;
+
+ // Checks if there is any contents to the left/right side of caret returns the noneditable element or any editable element if it finds one inside
+ function hasSideContent(element, left) {
+ var container, offset, walker, node, len;
+
+ container = rng.startContainer;
+ offset = rng.startOffset;
+
+ // If endpoint is in middle of text node then expand to beginning/end of element
+ if (container.nodeType == 3) {
+ len = container.nodeValue.length;
+ if ((offset > 0 && offset < len) || (left ? offset == len : offset == 0)) {
+ return;
+ }
+ } else {
+ // Can we resolve the node by index
+ if (offset < container.childNodes.length) {
+ // Browser represents caret position as the offset at the start of an element. When moving right
+ // this is the element we are moving into so we consider our container to be child node at offset-1
+ var pos = !left && offset > 0 ? offset-1 : offset;
+ container = container.childNodes[pos];
+ if (container.hasChildNodes()) {
+ container = container.firstChild;
+ }
+ } else {
+ // If not then the caret is at the last position in it's container and the caret container should be inserted after the noneditable element
+ return !left ? element : null;
+ }
+ }
+
+ // Walk left/right to look for contents
+ walker = new TreeWalker(container, element);
+ while (node = walker[left ? 'prev' : 'next']()) {
+ if (node.nodeType === 3 && node.nodeValue.length > 0) {
+ return;
+ } else if (getContentEditable(node) === "true") {
+ // Found contentEditable=true element return this one to we can move the caret inside it
+ return node;
+ }
+ }
+
+ return element;
+ };
+
+ // Remove any existing caret containers
+ removeCaretContainer();
+
+ // Get noneditable start/end elements
+ isCollapsed = selection.isCollapsed();
+ nonEditableStart = getNonEditableParent(selection.getStart());
+ nonEditableEnd = getNonEditableParent(selection.getEnd());
+
+ // Is any fo the range endpoints noneditable
+ if (nonEditableStart || nonEditableEnd) {
+ rng = selection.getRng(true);
+
+ // If it's a caret selection then look left/right to see if we need to move the caret out side or expand
+ if (isCollapsed) {
+ nonEditableStart = nonEditableStart || nonEditableEnd;
+ var start = selection.getStart();
+ if (element = hasSideContent(nonEditableStart, true)) {
+ // We have no contents to the left of the caret then insert a caret container before the noneditable element
+ insertCaretContainerOrExpandToBlock(element, true);
+ } else if (element = hasSideContent(nonEditableStart, false)) {
+ // We have no contents to the right of the caret then insert a caret container after the noneditable element
+ insertCaretContainerOrExpandToBlock(element, false);
+ } else {
+ // We are in the middle of a noneditable so expand to select it
+ selection.select(nonEditableStart);
+ }
+ } else {
+ rng = selection.getRng(true);
+
+ // Expand selection to include start non editable element
+ if (nonEditableStart) {
+ rng.setStartBefore(nonEditableStart);
+ }
+
+ // Expand selection to include end non editable element
+ if (nonEditableEnd) {
+ rng.setEndAfter(nonEditableEnd);
+ }
+
+ selection.setRng(rng);
+ }
+ }
+ };
+
+ function handleKey(ed, e) {
+ var keyCode = e.keyCode, nonEditableParent, caretContainer, startElement, endElement;
+
+ function getNonEmptyTextNodeSibling(node, prev) {
+ while (node = node[prev ? 'previousSibling' : 'nextSibling']) {
+ if (node.nodeType !== 3 || node.nodeValue.length > 0) {
+ return node;
+ }
+ }
+ };
+
+ function positionCaretOnElement(element, start) {
+ selection.select(element);
+ selection.collapse(start);
+ }
+
+ function canDelete(backspace) {
+ var rng, container, offset, nonEditableParent;
+
+ function removeNodeIfNotParent(node) {
+ var parent = container;
+
+ while (parent) {
+ if (parent === node) {
+ return;
+ }
+
+ parent = parent.parentNode;
+ }
+
+ dom.remove(node);
+ moveSelection();
+ }
+
+ function isNextPrevTreeNodeNonEditable() {
+ var node, walker, nonEmptyElements = ed.schema.getNonEmptyElements();
+
+ walker = new tinymce.dom.TreeWalker(container, ed.getBody());
+ while (node = (backspace ? walker.prev() : walker.next())) {
+ // Found IMG/INPUT etc
+ if (nonEmptyElements[node.nodeName.toLowerCase()]) {
+ break;
+ }
+
+ // Found text node with contents
+ if (node.nodeType === 3 && tinymce.trim(node.nodeValue).length > 0) {
+ break;
+ }
+
+ // Found non editable node
+ if (getContentEditable(node) === "false") {
+ removeNodeIfNotParent(node);
+ return true;
+ }
+ }
+
+ // Check if the content node is within a non editable parent
+ if (getNonEditableParent(node)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ if (selection.isCollapsed()) {
+ rng = selection.getRng(true);
+ container = rng.startContainer;
+ offset = rng.startOffset;
+ container = getParentCaretContainer(container) || container;
+
+ // Is in noneditable parent
+ if (nonEditableParent = getNonEditableParent(container)) {
+ removeNodeIfNotParent(nonEditableParent);
+ return false;
+ }
+
+ // Check if the caret is in the middle of a text node
+ if (container.nodeType == 3 && (backspace ? offset > 0 : offset < container.nodeValue.length)) {
+ return true;
+ }
+
+ // Resolve container index
+ if (container.nodeType == 1) {
+ container = container.childNodes[offset] || container;
+ }
+
+ // Check if previous or next tree node is non editable then block the event
+ if (isNextPrevTreeNodeNonEditable()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ startElement = selection.getStart()
+ endElement = selection.getEnd();
+
+ // Disable all key presses in contentEditable=false except delete or backspace
+ nonEditableParent = getNonEditableParent(startElement) || getNonEditableParent(endElement);
+ if (nonEditableParent && (keyCode < 112 || keyCode > 124) && keyCode != VK.DELETE && keyCode != VK.BACKSPACE) {
+ // Is Ctrl+c, Ctrl+v or Ctrl+x then use default browser behavior
+ if ((tinymce.isMac ? e.metaKey : e.ctrlKey) && (keyCode == 67 || keyCode == 88 || keyCode == 86)) {
+ return;
+ }
+
+ e.preventDefault();
+
+ // Arrow left/right select the element and collapse left/right
+ if (keyCode == VK.LEFT || keyCode == VK.RIGHT) {
+ var left = keyCode == VK.LEFT;
+ // If a block element find previous or next element to position the caret
+ if (ed.dom.isBlock(nonEditableParent)) {
+ var targetElement = left ? nonEditableParent.previousSibling : nonEditableParent.nextSibling;
+ var walker = new TreeWalker(targetElement, targetElement);
+ var caretElement = left ? walker.prev() : walker.next();
+ positionCaretOnElement(caretElement, !left);
+ } else {
+ positionCaretOnElement(nonEditableParent, left);
+ }
+ }
+ } else {
+ // Is arrow left/right, backspace or delete
+ if (keyCode == VK.LEFT || keyCode == VK.RIGHT || keyCode == VK.BACKSPACE || keyCode == VK.DELETE) {
+ caretContainer = getParentCaretContainer(startElement);
+ if (caretContainer) {
+ // Arrow left or backspace
+ if (keyCode == VK.LEFT || keyCode == VK.BACKSPACE) {
+ nonEditableParent = getNonEmptyTextNodeSibling(caretContainer, true);
+
+ if (nonEditableParent && getContentEditable(nonEditableParent) === "false") {
+ e.preventDefault();
+
+ if (keyCode == VK.LEFT) {
+ positionCaretOnElement(nonEditableParent, true);
+ } else {
+ dom.remove(nonEditableParent);
+ return;
+ }
+ } else {
+ removeCaretContainer(caretContainer);
+ }
+ }
+
+ // Arrow right or delete
+ if (keyCode == VK.RIGHT || keyCode == VK.DELETE) {
+ nonEditableParent = getNonEmptyTextNodeSibling(caretContainer);
+
+ if (nonEditableParent && getContentEditable(nonEditableParent) === "false") {
+ e.preventDefault();
+
+ if (keyCode == VK.RIGHT) {
+ positionCaretOnElement(nonEditableParent, false);
+ } else {
+ dom.remove(nonEditableParent);
+ return;
+ }
+ } else {
+ removeCaretContainer(caretContainer);
+ }
+ }
+ }
+
+ if ((keyCode == VK.BACKSPACE || keyCode == VK.DELETE) && !canDelete(keyCode == VK.BACKSPACE)) {
+ e.preventDefault();
+ return false;
+ }
+ }
+ }
+ };
+
+ ed.onMouseDown.addToTop(function(ed, e) {
+ var node = ed.selection.getNode();
+
+ if (getContentEditable(node) === "false" && node == e.target) {
+ // Expand selection on mouse down we can't block the default event since it's used for drag/drop
+ moveSelection();
+ }
+ });
+
+ ed.onMouseUp.addToTop(moveSelection);
+ ed.onKeyDown.addToTop(handleKey);
+ ed.onKeyUp.addToTop(moveSelection);
+ };
+
+ tinymce.create('tinymce.plugins.NonEditablePlugin', {
+ init : function(ed, url) {
+ var editClass, nonEditClass, nonEditableRegExps;
+
+ // Converts configured regexps to noneditable span items
+ function convertRegExpsToNonEditable(ed, args) {
+ var i = nonEditableRegExps.length, content = args.content, cls = tinymce.trim(nonEditClass);
+
+ // Don't replace the variables when raw is used for example on undo/redo
+ if (args.format == "raw") {
+ return;
+ }
+
+ while (i--) {
+ content = content.replace(nonEditableRegExps[i], function(match) {
+ var args = arguments, index = args[args.length - 2];
+
+ // Is value inside an attribute then don't replace
+ if (index > 0 && content.charAt(index - 1) == '"') {
+ return match;
+ }
+
+ return '<span class="' + cls + '" data-mce-content="' + ed.dom.encode(args[0]) + '">' + ed.dom.encode(typeof(args[1]) === "string" ? args[1] : args[0]) + '</span>';
+ });
+ }
+
+ args.content = content;
+ };
+
+ editClass = " " + tinymce.trim(ed.getParam("noneditable_editable_class", "mceEditable")) + " ";
+ nonEditClass = " " + tinymce.trim(ed.getParam("noneditable_noneditable_class", "mceNonEditable")) + " ";
+
+ // Setup noneditable regexps array
+ nonEditableRegExps = ed.getParam("noneditable_regexp");
+ if (nonEditableRegExps && !nonEditableRegExps.length) {
+ nonEditableRegExps = [nonEditableRegExps];
+ }
+
+ ed.onPreInit.add(function() {
+ handleContentEditableSelection(ed);
+
+ if (nonEditableRegExps) {
+ ed.selection.onBeforeSetContent.add(convertRegExpsToNonEditable);
+ ed.onBeforeSetContent.add(convertRegExpsToNonEditable);
+ }
+
+ // Apply contentEditable true/false on elements with the noneditable/editable classes
+ ed.parser.addAttributeFilter('class', function(nodes) {
+ var i = nodes.length, className, node;
+
+ while (i--) {
+ node = nodes[i];
+ className = " " + node.attr("class") + " ";
+
+ if (className.indexOf(editClass) !== -1) {
+ node.attr(internalName, "true");
+ } else if (className.indexOf(nonEditClass) !== -1) {
+ node.attr(internalName, "false");
+ }
+ }
+ });
+
+ // Remove internal name
+ ed.serializer.addAttributeFilter(internalName, function(nodes, name) {
+ var i = nodes.length, node;
+
+ while (i--) {
+ node = nodes[i];
+
+ if (nonEditableRegExps && node.attr('data-mce-content')) {
+ node.name = "#text";
+ node.type = 3;
+ node.raw = true;
+ node.value = node.attr('data-mce-content');
+ } else {
+ node.attr(externalName, null);
+ node.attr(internalName, null);
+ }
+ }
+ });
+
+ // Convert external name into internal name
+ ed.parser.addAttributeFilter(externalName, function(nodes, name) {
+ var i = nodes.length, node;
+
+ while (i--) {
+ node = nodes[i];
+ node.attr(internalName, node.attr(externalName));
+ node.attr(externalName, null);
+ }
+ });
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Non editable elements',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/noneditable',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('noneditable', tinymce.plugins.NonEditablePlugin);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/pagebreak/editor_plugin.js b/askbot/media/js/tinymce/plugins/pagebreak/editor_plugin.js
new file mode 100644
index 00000000..35085e8a
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/pagebreak/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.PageBreakPlugin",{init:function(b,d){var f='<img src="'+b.theme.url+'/img/trans.gif" class="mcePageBreak mceItemNoResize" />',a="mcePageBreak",c=b.getParam("pagebreak_separator","<!-- pagebreak -->"),e;e=new RegExp(c.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,function(g){return"\\"+g}),"g");b.addCommand("mcePageBreak",function(){b.execCommand("mceInsertContent",0,f)});b.addButton("pagebreak",{title:"pagebreak.desc",cmd:a});b.onInit.add(function(){if(b.theme.onResolveName){b.theme.onResolveName.add(function(g,h){if(h.node.nodeName=="IMG"&&b.dom.hasClass(h.node,a)){h.name="pagebreak"}})}});b.onClick.add(function(g,h){h=h.target;if(h.nodeName==="IMG"&&g.dom.hasClass(h,a)){g.selection.select(h)}});b.onNodeChange.add(function(h,g,i){g.setActive("pagebreak",i.nodeName==="IMG"&&h.dom.hasClass(i,a))});b.onBeforeSetContent.add(function(g,h){h.content=h.content.replace(e,f)});b.onPostProcess.add(function(g,h){if(h.get){h.content=h.content.replace(/<img[^>]+>/g,function(i){if(i.indexOf('class="mcePageBreak')!==-1){i=c}return i})}})},getInfo:function(){return{longname:"PageBreak",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/pagebreak",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("pagebreak",tinymce.plugins.PageBreakPlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/pagebreak/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/pagebreak/editor_plugin_src.js
new file mode 100644
index 00000000..a094c191
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/pagebreak/editor_plugin_src.js
@@ -0,0 +1,74 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.PageBreakPlugin', {
+ init : function(ed, url) {
+ var pb = '<img src="' + ed.theme.url + '/img/trans.gif" class="mcePageBreak mceItemNoResize" />', cls = 'mcePageBreak', sep = ed.getParam('pagebreak_separator', '<!-- pagebreak -->'), pbRE;
+
+ pbRE = new RegExp(sep.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g, function(a) {return '\\' + a;}), 'g');
+
+ // Register commands
+ ed.addCommand('mcePageBreak', function() {
+ ed.execCommand('mceInsertContent', 0, pb);
+ });
+
+ // Register buttons
+ ed.addButton('pagebreak', {title : 'pagebreak.desc', cmd : cls});
+
+ ed.onInit.add(function() {
+ if (ed.theme.onResolveName) {
+ ed.theme.onResolveName.add(function(th, o) {
+ if (o.node.nodeName == 'IMG' && ed.dom.hasClass(o.node, cls))
+ o.name = 'pagebreak';
+ });
+ }
+ });
+
+ ed.onClick.add(function(ed, e) {
+ e = e.target;
+
+ if (e.nodeName === 'IMG' && ed.dom.hasClass(e, cls))
+ ed.selection.select(e);
+ });
+
+ ed.onNodeChange.add(function(ed, cm, n) {
+ cm.setActive('pagebreak', n.nodeName === 'IMG' && ed.dom.hasClass(n, cls));
+ });
+
+ ed.onBeforeSetContent.add(function(ed, o) {
+ o.content = o.content.replace(pbRE, pb);
+ });
+
+ ed.onPostProcess.add(function(ed, o) {
+ if (o.get)
+ o.content = o.content.replace(/<img[^>]+>/g, function(im) {
+ if (im.indexOf('class="mcePageBreak') !== -1)
+ im = sep;
+
+ return im;
+ });
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'PageBreak',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/pagebreak',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('pagebreak', tinymce.plugins.PageBreakPlugin);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/paste/editor_plugin.js b/askbot/media/js/tinymce/plugins/paste/editor_plugin.js
new file mode 100644
index 00000000..be7eee8f
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/paste/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var c=tinymce.each,a={paste_auto_cleanup_on_paste:true,paste_enable_default_filters:true,paste_block_drop:false,paste_retain_style_properties:"none",paste_strip_class_attributes:"mso",paste_remove_spans:false,paste_remove_styles:false,paste_remove_styles_if_webkit:true,paste_convert_middot_lists:true,paste_convert_headers_to_strong:false,paste_dialog_width:"450",paste_dialog_height:"400",paste_text_use_dialog:false,paste_text_sticky:false,paste_text_sticky_default:false,paste_text_notifyalways:false,paste_text_linebreaktype:"combined",paste_text_replacements:[[/\u2026/g,"..."],[/[\x93\x94\u201c\u201d]/g,'"'],[/[\x60\x91\x92\u2018\u2019]/g,"'"]]};function b(d,e){return d.getParam(e,a[e])}tinymce.create("tinymce.plugins.PastePlugin",{init:function(d,e){var f=this;f.editor=d;f.url=e;f.onPreProcess=new tinymce.util.Dispatcher(f);f.onPostProcess=new tinymce.util.Dispatcher(f);f.onPreProcess.add(f._preProcess);f.onPostProcess.add(f._postProcess);f.onPreProcess.add(function(i,j){d.execCallback("paste_preprocess",i,j)});f.onPostProcess.add(function(i,j){d.execCallback("paste_postprocess",i,j)});d.onKeyDown.addToTop(function(i,j){if(((tinymce.isMac?j.metaKey:j.ctrlKey)&&j.keyCode==86)||(j.shiftKey&&j.keyCode==45)){return false}});d.pasteAsPlainText=b(d,"paste_text_sticky_default");function h(l,j){var k=d.dom,i;f.onPreProcess.dispatch(f,l);l.node=k.create("div",0,l.content);if(tinymce.isGecko){i=d.selection.getRng(true);if(i.startContainer==i.endContainer&&i.startContainer.nodeType==3){if(l.node.childNodes.length===1&&/^(p|h[1-6]|pre)$/i.test(l.node.firstChild.nodeName)&&l.content.indexOf("__MCE_ITEM__")===-1){k.remove(l.node.firstChild,true)}}}f.onPostProcess.dispatch(f,l);l.content=d.serializer.serialize(l.node,{getInner:1,forced_root_block:""});if((!j)&&(d.pasteAsPlainText)){f._insertPlainText(l.content);if(!b(d,"paste_text_sticky")){d.pasteAsPlainText=false;d.controlManager.setActive("pastetext",false)}}else{f._insert(l.content)}}d.addCommand("mceInsertClipboardContent",function(i,j){h(j,true)});if(!b(d,"paste_text_use_dialog")){d.addCommand("mcePasteText",function(j,i){var k=tinymce.util.Cookie;d.pasteAsPlainText=!d.pasteAsPlainText;d.controlManager.setActive("pastetext",d.pasteAsPlainText);if((d.pasteAsPlainText)&&(!k.get("tinymcePasteText"))){if(b(d,"paste_text_sticky")){d.windowManager.alert(d.translate("paste.plaintext_mode_sticky"))}else{d.windowManager.alert(d.translate("paste.plaintext_mode"))}if(!b(d,"paste_text_notifyalways")){k.set("tinymcePasteText","1",new Date(new Date().getFullYear()+1,12,31))}}})}d.addButton("pastetext",{title:"paste.paste_text_desc",cmd:"mcePasteText"});d.addButton("selectall",{title:"paste.selectall_desc",cmd:"selectall"});function g(s){var l,p,j,t,k=d.selection,o=d.dom,q=d.getBody(),i,r;if(s.clipboardData||o.doc.dataTransfer){r=(s.clipboardData||o.doc.dataTransfer).getData("Text");if(d.pasteAsPlainText){s.preventDefault();h({content:o.encode(r).replace(/\r?\n/g,"<br />")});return}}if(o.get("_mcePaste")){return}l=o.add(q,"div",{id:"_mcePaste","class":"mcePaste","data-mce-bogus":"1"},"\uFEFF\uFEFF");if(q!=d.getDoc().body){i=o.getPos(d.selection.getStart(),q).y}else{i=q.scrollTop+o.getViewPort(d.getWin()).y}o.setStyles(l,{position:"absolute",left:tinymce.isGecko?-40:0,top:i-25,width:1,height:1,overflow:"hidden"});if(tinymce.isIE){t=k.getRng();j=o.doc.body.createTextRange();j.moveToElementText(l);j.execCommand("Paste");o.remove(l);if(l.innerHTML==="\uFEFF\uFEFF"){d.execCommand("mcePasteWord");s.preventDefault();return}k.setRng(t);k.setContent("");setTimeout(function(){h({content:l.innerHTML})},0);return tinymce.dom.Event.cancel(s)}else{function m(n){n.preventDefault()}o.bind(d.getDoc(),"mousedown",m);o.bind(d.getDoc(),"keydown",m);p=d.selection.getRng();l=l.firstChild;j=d.getDoc().createRange();j.setStart(l,0);j.setEnd(l,2);k.setRng(j);window.setTimeout(function(){var u="",n;if(!o.select("div.mcePaste > div.mcePaste").length){n=o.select("div.mcePaste");c(n,function(w){var v=w.firstChild;if(v&&v.nodeName=="DIV"&&v.style.marginTop&&v.style.backgroundColor){o.remove(v,1)}c(o.select("span.Apple-style-span",w),function(x){o.remove(x,1)});c(o.select("br[data-mce-bogus]",w),function(x){o.remove(x)});if(w.parentNode.className!="mcePaste"){u+=w.innerHTML}})}else{u="<p>"+o.encode(r).replace(/\r?\n\r?\n/g,"</p><p>").replace(/\r?\n/g,"<br />")+"</p>"}c(o.select("div.mcePaste"),function(v){o.remove(v)});if(p){k.setRng(p)}h({content:u});o.unbind(d.getDoc(),"mousedown",m);o.unbind(d.getDoc(),"keydown",m)},0)}}if(b(d,"paste_auto_cleanup_on_paste")){if(tinymce.isOpera||/Firefox\/2/.test(navigator.userAgent)){d.onKeyDown.addToTop(function(i,j){if(((tinymce.isMac?j.metaKey:j.ctrlKey)&&j.keyCode==86)||(j.shiftKey&&j.keyCode==45)){g(j)}})}else{d.onPaste.addToTop(function(i,j){return g(j)})}}d.onInit.add(function(){d.controlManager.setActive("pastetext",d.pasteAsPlainText);if(b(d,"paste_block_drop")){d.dom.bind(d.getBody(),["dragend","dragover","draggesture","dragdrop","drop","drag"],function(i){i.preventDefault();i.stopPropagation();return false})}});f._legacySupport()},getInfo:function(){return{longname:"Paste text/word",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/paste",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_preProcess:function(g,e){var k=this.editor,j=e.content,p=tinymce.grep,n=tinymce.explode,f=tinymce.trim,l,i;function d(h){c(h,function(o){if(o.constructor==RegExp){j=j.replace(o,"")}else{j=j.replace(o[0],o[1])}})}if(k.settings.paste_enable_default_filters==false){return}if(tinymce.isIE&&document.documentMode>=9&&/<(h[1-6r]|p|div|address|pre|form|table|tbody|thead|tfoot|th|tr|td|li|ol|ul|caption|blockquote|center|dl|dt|dd|dir|fieldset)/.test(e.content)){d([[/(?:<br>&nbsp;[\s\r\n]+|<br>)*(<\/?(h[1-6r]|p|div|address|pre|form|table|tbody|thead|tfoot|th|tr|td|li|ol|ul|caption|blockquote|center|dl|dt|dd|dir|fieldset)[^>]*>)(?:<br>&nbsp;[\s\r\n]+|<br>)*/g,"$1"]]);d([[/<br><br>/g,"<BR><BR>"],[/<br>/g," "],[/<BR><BR>/g,"<br>"]])}if(/class="?Mso|style="[^"]*\bmso-|w:WordDocument/i.test(j)||e.wordContent){e.wordContent=true;d([/^\s*(&nbsp;)+/gi,/(&nbsp;|<br[^>]*>)+\s*$/gi]);if(b(k,"paste_convert_headers_to_strong")){j=j.replace(/<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi,"<p><strong>$1</strong></p>")}if(b(k,"paste_convert_middot_lists")){d([[/<!--\[if !supportLists\]-->/gi,"$&__MCE_ITEM__"],[/(<span[^>]+(?:mso-list:|:\s*symbol)[^>]+>)/gi,"$1__MCE_ITEM__"],[/(<p[^>]+(?:MsoListParagraph)[^>]+>)/gi,"$1__MCE_ITEM__"]])}d([/<!--[\s\S]+?-->/gi,/<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi,[/<(\/?)s>/gi,"<$1strike>"],[/&nbsp;/gi,"\u00a0"]]);do{l=j.length;j=j.replace(/(<[a-z][^>]*\s)(?:id|name|language|type|on\w+|\w+:\w+)=(?:"[^"]*"|\w+)\s?/gi,"$1")}while(l!=j.length);if(b(k,"paste_retain_style_properties").replace(/^none$/i,"").length==0){j=j.replace(/<\/?span[^>]*>/gi,"")}else{d([[/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s\u00a0]*)<\/span>/gi,function(o,h){return(h.length>0)?h.replace(/./," ").slice(Math.floor(h.length/2)).split("").join("\u00a0"):""}],[/(<[a-z][^>]*)\sstyle="([^"]*)"/gi,function(t,h,r){var u=[],o=0,q=n(f(r).replace(/&quot;/gi,"'"),";");c(q,function(s){var w,y,z=n(s,":");function x(A){return A+((A!=="0")&&(/\d$/.test(A)))?"px":""}if(z.length==2){w=z[0].toLowerCase();y=z[1].toLowerCase();switch(w){case"mso-padding-alt":case"mso-padding-top-alt":case"mso-padding-right-alt":case"mso-padding-bottom-alt":case"mso-padding-left-alt":case"mso-margin-alt":case"mso-margin-top-alt":case"mso-margin-right-alt":case"mso-margin-bottom-alt":case"mso-margin-left-alt":case"mso-table-layout-alt":case"mso-height":case"mso-width":case"mso-vertical-align-alt":u[o++]=w.replace(/^mso-|-alt$/g,"")+":"+x(y);return;case"horiz-align":u[o++]="text-align:"+y;return;case"vert-align":u[o++]="vertical-align:"+y;return;case"font-color":case"mso-foreground":u[o++]="color:"+y;return;case"mso-background":case"mso-highlight":u[o++]="background:"+y;return;case"mso-default-height":u[o++]="min-height:"+x(y);return;case"mso-default-width":u[o++]="min-width:"+x(y);return;case"mso-padding-between-alt":u[o++]="border-collapse:separate;border-spacing:"+x(y);return;case"text-line-through":if((y=="single")||(y=="double")){u[o++]="text-decoration:line-through"}return;case"mso-zero-height":if(y=="yes"){u[o++]="display:none"}return}if(/^(mso|column|font-emph|lang|layout|line-break|list-image|nav|panose|punct|row|ruby|sep|size|src|tab-|table-border|text-(?!align|decor|indent|trans)|top-bar|version|vnd|word-break)/.test(w)){return}u[o++]=w+":"+z[1]}});if(o>0){return h+' style="'+u.join(";")+'"'}else{return h}}]])}}if(b(k,"paste_convert_headers_to_strong")){d([[/<h[1-6][^>]*>/gi,"<p><strong>"],[/<\/h[1-6][^>]*>/gi,"</strong></p>"]])}d([[/Version:[\d.]+\nStartHTML:\d+\nEndHTML:\d+\nStartFragment:\d+\nEndFragment:\d+/gi,""]]);i=b(k,"paste_strip_class_attributes");if(i!=="none"){function m(q,o){if(i==="all"){return""}var h=p(n(o.replace(/^(["'])(.*)\1$/,"$2")," "),function(r){return(/^(?!mso)/i.test(r))});return h.length?' class="'+h.join(" ")+'"':""}j=j.replace(/ class="([^"]+)"/gi,m);j=j.replace(/ class=([\-\w]+)/gi,m)}if(b(k,"paste_remove_spans")){j=j.replace(/<\/?span[^>]*>/gi,"")}e.content=j},_postProcess:function(g,i){var f=this,e=f.editor,h=e.dom,d;if(e.settings.paste_enable_default_filters==false){return}if(i.wordContent){c(h.select("a",i.node),function(j){if(!j.href||j.href.indexOf("#_Toc")!=-1){h.remove(j,1)}});if(b(e,"paste_convert_middot_lists")){f._convertLists(g,i)}d=b(e,"paste_retain_style_properties");if((tinymce.is(d,"string"))&&(d!=="all")&&(d!=="*")){d=tinymce.explode(d.replace(/^none$/i,""));c(h.select("*",i.node),function(m){var n={},k=0,l,o,j;if(d){for(l=0;l<d.length;l++){o=d[l];j=h.getStyle(m,o);if(j){n[o]=j;k++}}}h.setAttrib(m,"style","");if(d&&k>0){h.setStyles(m,n)}else{if(m.nodeName=="SPAN"&&!m.className){h.remove(m,true)}}})}}if(b(e,"paste_remove_styles")||(b(e,"paste_remove_styles_if_webkit")&&tinymce.isWebKit)){c(h.select("*[style]",i.node),function(j){j.removeAttribute("style");j.removeAttribute("data-mce-style")})}else{if(tinymce.isWebKit){c(h.select("*",i.node),function(j){j.removeAttribute("data-mce-style")})}}},_convertLists:function(g,e){var i=g.editor.dom,h,l,d=-1,f,m=[],k,j;c(i.select("p",e.node),function(t){var q,u="",s,r,n,o;for(q=t.firstChild;q&&q.nodeType==3;q=q.nextSibling){u+=q.nodeValue}u=t.innerHTML.replace(/<\/?\w+[^>]*>/gi,"").replace(/&nbsp;/g,"\u00a0");if(/^(__MCE_ITEM__)+[\u2022\u00b7\u00a7\u00d8o\u25CF]\s*\u00a0*/.test(u)){s="ul"}if(/^__MCE_ITEM__\s*\w+\.\s*\u00a0+/.test(u)){s="ol"}if(s){f=parseFloat(t.style.marginLeft||0);if(f>d){m.push(f)}if(!h||s!=k){h=i.create(s);i.insertAfter(h,t)}else{if(f>d){h=l.appendChild(i.create(s))}else{if(f<d){n=tinymce.inArray(m,f);o=i.getParents(h.parentNode,s);h=o[o.length-1-n]||h}}}c(i.select("span",t),function(v){var p=v.innerHTML.replace(/<\/?\w+[^>]*>/gi,"");if(s=="ul"&&/^__MCE_ITEM__[\u2022\u00b7\u00a7\u00d8o\u25CF]/.test(p)){i.remove(v)}else{if(/^__MCE_ITEM__[\s\S]*\w+\.(&nbsp;|\u00a0)*\s*/.test(p)){i.remove(v)}}});r=t.innerHTML;if(s=="ul"){r=t.innerHTML.replace(/__MCE_ITEM__/g,"").replace(/^[\u2022\u00b7\u00a7\u00d8o\u25CF]\s*(&nbsp;|\u00a0)+\s*/,"")}else{r=t.innerHTML.replace(/__MCE_ITEM__/g,"").replace(/^\s*\w+\.(&nbsp;|\u00a0)+\s*/,"")}l=h.appendChild(i.create("li",0,r));i.remove(t);d=f;k=s}else{h=d=0}});j=e.node.innerHTML;if(j.indexOf("__MCE_ITEM__")!=-1){e.node.innerHTML=j.replace(/__MCE_ITEM__/g,"")}},_insert:function(f,d){var e=this.editor,g=e.selection.getRng();if(!e.selection.isCollapsed()&&g.startContainer!=g.endContainer){e.getDoc().execCommand("Delete",false,null)}e.execCommand("mceInsertContent",false,f,{skip_undo:d})},_insertPlainText:function(g){var d=this.editor,e=b(d,"paste_text_linebreaktype"),i=b(d,"paste_text_replacements"),f=tinymce.is;function h(j){c(j,function(k){if(k.constructor==RegExp){g=g.replace(k,"")}else{g=g.replace(k[0],k[1])}})}if((typeof(g)==="string")&&(g.length>0)){if(/<(?:p|br|h[1-6]|ul|ol|dl|table|t[rdh]|div|blockquote|fieldset|pre|address|center)[^>]*>/i.test(g)){h([/[\n\r]+/g])}else{h([/\r+/g])}h([[/<\/(?:p|h[1-6]|ul|ol|dl|table|div|blockquote|fieldset|pre|address|center)>/gi,"\n\n"],[/<br[^>]*>|<\/tr>/gi,"\n"],[/<\/t[dh]>\s*<t[dh][^>]*>/gi,"\t"],/<[a-z!\/?][^>]*>/gi,[/&nbsp;/gi," "],[/(?:(?!\n)\s)*(\n+)(?:(?!\n)\s)*/gi,"$1"],[/\n{3,}/g,"\n\n"]]);g=d.dom.decode(tinymce.html.Entities.encodeRaw(g));if(f(i,"array")){h(i)}else{if(f(i,"string")){h(new RegExp(i,"gi"))}}if(e=="none"){h([[/\n+/g," "]])}else{if(e=="br"){h([[/\n/g,"<br />"]])}else{if(e=="p"){h([[/\n+/g,"</p><p>"],[/^(.*<\/p>)(<p>)$/,"<p>$1"]])}else{h([[/\n\n/g,"</p><p>"],[/^(.*<\/p>)(<p>)$/,"<p>$1"],[/\n/g,"<br />"]])}}}d.execCommand("mceInsertContent",false,g)}},_legacySupport:function(){var e=this,d=e.editor;d.addCommand("mcePasteWord",function(){d.windowManager.open({file:e.url+"/pasteword.htm",width:parseInt(b(d,"paste_dialog_width")),height:parseInt(b(d,"paste_dialog_height")),inline:1})});if(b(d,"paste_text_use_dialog")){d.addCommand("mcePasteText",function(){d.windowManager.open({file:e.url+"/pastetext.htm",width:parseInt(b(d,"paste_dialog_width")),height:parseInt(b(d,"paste_dialog_height")),inline:1})})}d.addButton("pasteword",{title:"paste.paste_word_desc",cmd:"mcePasteWord"})}});tinymce.PluginManager.add("paste",tinymce.plugins.PastePlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/paste/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/paste/editor_plugin_src.js
new file mode 100644
index 00000000..9f1c3547
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/paste/editor_plugin_src.js
@@ -0,0 +1,871 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var each = tinymce.each,
+ defs = {
+ paste_auto_cleanup_on_paste : true,
+ paste_enable_default_filters : true,
+ paste_block_drop : false,
+ paste_retain_style_properties : "none",
+ paste_strip_class_attributes : "mso",
+ paste_remove_spans : false,
+ paste_remove_styles : false,
+ paste_remove_styles_if_webkit : true,
+ paste_convert_middot_lists : true,
+ paste_convert_headers_to_strong : false,
+ paste_dialog_width : "450",
+ paste_dialog_height : "400",
+ paste_text_use_dialog : false,
+ paste_text_sticky : false,
+ paste_text_sticky_default : false,
+ paste_text_notifyalways : false,
+ paste_text_linebreaktype : "combined",
+ paste_text_replacements : [
+ [/\u2026/g, "..."],
+ [/[\x93\x94\u201c\u201d]/g, '"'],
+ [/[\x60\x91\x92\u2018\u2019]/g, "'"]
+ ]
+ };
+
+ function getParam(ed, name) {
+ return ed.getParam(name, defs[name]);
+ }
+
+ tinymce.create('tinymce.plugins.PastePlugin', {
+ init : function(ed, url) {
+ var t = this;
+
+ t.editor = ed;
+ t.url = url;
+
+ // Setup plugin events
+ t.onPreProcess = new tinymce.util.Dispatcher(t);
+ t.onPostProcess = new tinymce.util.Dispatcher(t);
+
+ // Register default handlers
+ t.onPreProcess.add(t._preProcess);
+ t.onPostProcess.add(t._postProcess);
+
+ // Register optional preprocess handler
+ t.onPreProcess.add(function(pl, o) {
+ ed.execCallback('paste_preprocess', pl, o);
+ });
+
+ // Register optional postprocess
+ t.onPostProcess.add(function(pl, o) {
+ ed.execCallback('paste_postprocess', pl, o);
+ });
+
+ ed.onKeyDown.addToTop(function(ed, e) {
+ // Block ctrl+v from adding an undo level since the default logic in tinymce.Editor will add that
+ if (((tinymce.isMac ? e.metaKey : e.ctrlKey) && e.keyCode == 86) || (e.shiftKey && e.keyCode == 45))
+ return false; // Stop other listeners
+ });
+
+ // Initialize plain text flag
+ ed.pasteAsPlainText = getParam(ed, 'paste_text_sticky_default');
+
+ // This function executes the process handlers and inserts the contents
+ // force_rich overrides plain text mode set by user, important for pasting with execCommand
+ function process(o, force_rich) {
+ var dom = ed.dom, rng;
+
+ // Execute pre process handlers
+ t.onPreProcess.dispatch(t, o);
+
+ // Create DOM structure
+ o.node = dom.create('div', 0, o.content);
+
+ // If pasting inside the same element and the contents is only one block
+ // remove the block and keep the text since Firefox will copy parts of pre and h1-h6 as a pre element
+ if (tinymce.isGecko) {
+ rng = ed.selection.getRng(true);
+ if (rng.startContainer == rng.endContainer && rng.startContainer.nodeType == 3) {
+ // Is only one block node and it doesn't contain word stuff
+ if (o.node.childNodes.length === 1 && /^(p|h[1-6]|pre)$/i.test(o.node.firstChild.nodeName) && o.content.indexOf('__MCE_ITEM__') === -1)
+ dom.remove(o.node.firstChild, true);
+ }
+ }
+
+ // Execute post process handlers
+ t.onPostProcess.dispatch(t, o);
+
+ // Serialize content
+ o.content = ed.serializer.serialize(o.node, {getInner : 1, forced_root_block : ''});
+
+ // Plain text option active?
+ if ((!force_rich) && (ed.pasteAsPlainText)) {
+ t._insertPlainText(o.content);
+
+ if (!getParam(ed, "paste_text_sticky")) {
+ ed.pasteAsPlainText = false;
+ ed.controlManager.setActive("pastetext", false);
+ }
+ } else {
+ t._insert(o.content);
+ }
+ }
+
+ // Add command for external usage
+ ed.addCommand('mceInsertClipboardContent', function(u, o) {
+ process(o, true);
+ });
+
+ if (!getParam(ed, "paste_text_use_dialog")) {
+ ed.addCommand('mcePasteText', function(u, v) {
+ var cookie = tinymce.util.Cookie;
+
+ ed.pasteAsPlainText = !ed.pasteAsPlainText;
+ ed.controlManager.setActive('pastetext', ed.pasteAsPlainText);
+
+ if ((ed.pasteAsPlainText) && (!cookie.get("tinymcePasteText"))) {
+ if (getParam(ed, "paste_text_sticky")) {
+ ed.windowManager.alert(ed.translate('paste.plaintext_mode_sticky'));
+ } else {
+ ed.windowManager.alert(ed.translate('paste.plaintext_mode'));
+ }
+
+ if (!getParam(ed, "paste_text_notifyalways")) {
+ cookie.set("tinymcePasteText", "1", new Date(new Date().getFullYear() + 1, 12, 31))
+ }
+ }
+ });
+ }
+
+ ed.addButton('pastetext', {title: 'paste.paste_text_desc', cmd: 'mcePasteText'});
+ ed.addButton('selectall', {title: 'paste.selectall_desc', cmd: 'selectall'});
+
+ // This function grabs the contents from the clipboard by adding a
+ // hidden div and placing the caret inside it and after the browser paste
+ // is done it grabs that contents and processes that
+ function grabContent(e) {
+ var n, or, rng, oldRng, sel = ed.selection, dom = ed.dom, body = ed.getBody(), posY, textContent;
+
+ // Check if browser supports direct plaintext access
+ if (e.clipboardData || dom.doc.dataTransfer) {
+ textContent = (e.clipboardData || dom.doc.dataTransfer).getData('Text');
+
+ if (ed.pasteAsPlainText) {
+ e.preventDefault();
+ process({content : dom.encode(textContent).replace(/\r?\n/g, '<br />')});
+ return;
+ }
+ }
+
+ if (dom.get('_mcePaste'))
+ return;
+
+ // Create container to paste into
+ n = dom.add(body, 'div', {id : '_mcePaste', 'class' : 'mcePaste', 'data-mce-bogus' : '1'}, '\uFEFF\uFEFF');
+
+ // If contentEditable mode we need to find out the position of the closest element
+ if (body != ed.getDoc().body)
+ posY = dom.getPos(ed.selection.getStart(), body).y;
+ else
+ posY = body.scrollTop + dom.getViewPort(ed.getWin()).y;
+
+ // Styles needs to be applied after the element is added to the document since WebKit will otherwise remove all styles
+ // If also needs to be in view on IE or the paste would fail
+ dom.setStyles(n, {
+ position : 'absolute',
+ left : tinymce.isGecko ? -40 : 0, // Need to move it out of site on Gecko since it will othewise display a ghost resize rect for the div
+ top : posY - 25,
+ width : 1,
+ height : 1,
+ overflow : 'hidden'
+ });
+
+ if (tinymce.isIE) {
+ // Store away the old range
+ oldRng = sel.getRng();
+
+ // Select the container
+ rng = dom.doc.body.createTextRange();
+ rng.moveToElementText(n);
+ rng.execCommand('Paste');
+
+ // Remove container
+ dom.remove(n);
+
+ // Check if the contents was changed, if it wasn't then clipboard extraction failed probably due
+ // to IE security settings so we pass the junk though better than nothing right
+ if (n.innerHTML === '\uFEFF\uFEFF') {
+ ed.execCommand('mcePasteWord');
+ e.preventDefault();
+ return;
+ }
+
+ // Restore the old range and clear the contents before pasting
+ sel.setRng(oldRng);
+ sel.setContent('');
+
+ // For some odd reason we need to detach the the mceInsertContent call from the paste event
+ // It's like IE has a reference to the parent element that you paste in and the selection gets messed up
+ // when it tries to restore the selection
+ setTimeout(function() {
+ // Process contents
+ process({content : n.innerHTML});
+ }, 0);
+
+ // Block the real paste event
+ return tinymce.dom.Event.cancel(e);
+ } else {
+ function block(e) {
+ e.preventDefault();
+ };
+
+ // Block mousedown and click to prevent selection change
+ dom.bind(ed.getDoc(), 'mousedown', block);
+ dom.bind(ed.getDoc(), 'keydown', block);
+
+ or = ed.selection.getRng();
+
+ // Move select contents inside DIV
+ n = n.firstChild;
+ rng = ed.getDoc().createRange();
+ rng.setStart(n, 0);
+ rng.setEnd(n, 2);
+ sel.setRng(rng);
+
+ // Wait a while and grab the pasted contents
+ window.setTimeout(function() {
+ var h = '', nl;
+
+ // Paste divs duplicated in paste divs seems to happen when you paste plain text so lets first look for that broken behavior in WebKit
+ if (!dom.select('div.mcePaste > div.mcePaste').length) {
+ nl = dom.select('div.mcePaste');
+
+ // WebKit will split the div into multiple ones so this will loop through then all and join them to get the whole HTML string
+ each(nl, function(n) {
+ var child = n.firstChild;
+
+ // WebKit inserts a DIV container with lots of odd styles
+ if (child && child.nodeName == 'DIV' && child.style.marginTop && child.style.backgroundColor) {
+ dom.remove(child, 1);
+ }
+
+ // Remove apply style spans
+ each(dom.select('span.Apple-style-span', n), function(n) {
+ dom.remove(n, 1);
+ });
+
+ // Remove bogus br elements
+ each(dom.select('br[data-mce-bogus]', n), function(n) {
+ dom.remove(n);
+ });
+
+ // WebKit will make a copy of the DIV for each line of plain text pasted and insert them into the DIV
+ if (n.parentNode.className != 'mcePaste')
+ h += n.innerHTML;
+ });
+ } else {
+ // Found WebKit weirdness so force the content into paragraphs this seems to happen when you paste plain text from Nodepad etc
+ // So this logic will replace double enter with paragraphs and single enter with br so it kind of looks the same
+ h = '<p>' + dom.encode(textContent).replace(/\r?\n\r?\n/g, '</p><p>').replace(/\r?\n/g, '<br />') + '</p>';
+ }
+
+ // Remove the nodes
+ each(dom.select('div.mcePaste'), function(n) {
+ dom.remove(n);
+ });
+
+ // Restore the old selection
+ if (or)
+ sel.setRng(or);
+
+ process({content : h});
+
+ // Unblock events ones we got the contents
+ dom.unbind(ed.getDoc(), 'mousedown', block);
+ dom.unbind(ed.getDoc(), 'keydown', block);
+ }, 0);
+ }
+ }
+
+ // Check if we should use the new auto process method
+ if (getParam(ed, "paste_auto_cleanup_on_paste")) {
+ // Is it's Opera or older FF use key handler
+ if (tinymce.isOpera || /Firefox\/2/.test(navigator.userAgent)) {
+ ed.onKeyDown.addToTop(function(ed, e) {
+ if (((tinymce.isMac ? e.metaKey : e.ctrlKey) && e.keyCode == 86) || (e.shiftKey && e.keyCode == 45))
+ grabContent(e);
+ });
+ } else {
+ // Grab contents on paste event on Gecko and WebKit
+ ed.onPaste.addToTop(function(ed, e) {
+ return grabContent(e);
+ });
+ }
+ }
+
+ ed.onInit.add(function() {
+ ed.controlManager.setActive("pastetext", ed.pasteAsPlainText);
+
+ // Block all drag/drop events
+ if (getParam(ed, "paste_block_drop")) {
+ ed.dom.bind(ed.getBody(), ['dragend', 'dragover', 'draggesture', 'dragdrop', 'drop', 'drag'], function(e) {
+ e.preventDefault();
+ e.stopPropagation();
+
+ return false;
+ });
+ }
+ });
+
+ // Add legacy support
+ t._legacySupport();
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Paste text/word',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/paste',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ _preProcess : function(pl, o) {
+ var ed = this.editor,
+ h = o.content,
+ grep = tinymce.grep,
+ explode = tinymce.explode,
+ trim = tinymce.trim,
+ len, stripClass;
+
+ //console.log('Before preprocess:' + o.content);
+
+ function process(items) {
+ each(items, function(v) {
+ // Remove or replace
+ if (v.constructor == RegExp)
+ h = h.replace(v, '');
+ else
+ h = h.replace(v[0], v[1]);
+ });
+ }
+
+ if (ed.settings.paste_enable_default_filters == false) {
+ return;
+ }
+
+ // IE9 adds BRs before/after block elements when contents is pasted from word or for example another browser
+ if (tinymce.isIE && document.documentMode >= 9 && /<(h[1-6r]|p|div|address|pre|form|table|tbody|thead|tfoot|th|tr|td|li|ol|ul|caption|blockquote|center|dl|dt|dd|dir|fieldset)/.test(o.content)) {
+ // IE9 adds BRs before/after block elements when contents is pasted from word or for example another browser
+ process([[/(?:<br>&nbsp;[\s\r\n]+|<br>)*(<\/?(h[1-6r]|p|div|address|pre|form|table|tbody|thead|tfoot|th|tr|td|li|ol|ul|caption|blockquote|center|dl|dt|dd|dir|fieldset)[^>]*>)(?:<br>&nbsp;[\s\r\n]+|<br>)*/g, '$1']]);
+
+ // IE9 also adds an extra BR element for each soft-linefeed and it also adds a BR for each word wrap break
+ process([
+ [/<br><br>/g, '<BR><BR>'], // Replace multiple BR elements with uppercase BR to keep them intact
+ [/<br>/g, ' '], // Replace single br elements with space since they are word wrap BR:s
+ [/<BR><BR>/g, '<br>'] // Replace back the double brs but into a single BR
+ ]);
+ }
+
+ // Detect Word content and process it more aggressive
+ if (/class="?Mso|style="[^"]*\bmso-|w:WordDocument/i.test(h) || o.wordContent) {
+ o.wordContent = true; // Mark the pasted contents as word specific content
+ //console.log('Word contents detected.');
+
+ // Process away some basic content
+ process([
+ /^\s*(&nbsp;)+/gi, // &nbsp; entities at the start of contents
+ /(&nbsp;|<br[^>]*>)+\s*$/gi // &nbsp; entities at the end of contents
+ ]);
+
+ if (getParam(ed, "paste_convert_headers_to_strong")) {
+ h = h.replace(/<p [^>]*class="?MsoHeading"?[^>]*>(.*?)<\/p>/gi, "<p><strong>$1</strong></p>");
+ }
+
+ if (getParam(ed, "paste_convert_middot_lists")) {
+ process([
+ [/<!--\[if !supportLists\]-->/gi, '$&__MCE_ITEM__'], // Convert supportLists to a list item marker
+ [/(<span[^>]+(?:mso-list:|:\s*symbol)[^>]+>)/gi, '$1__MCE_ITEM__'], // Convert mso-list and symbol spans to item markers
+ [/(<p[^>]+(?:MsoListParagraph)[^>]+>)/gi, '$1__MCE_ITEM__'] // Convert mso-list and symbol paragraphs to item markers (FF)
+ ]);
+ }
+
+ process([
+ // Word comments like conditional comments etc
+ /<!--[\s\S]+?-->/gi,
+
+ // Remove comments, scripts (e.g., msoShowComment), XML tag, VML content, MS Office namespaced tags, and a few other tags
+ /<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi,
+
+ // Convert <s> into <strike> for line-though
+ [/<(\/?)s>/gi, "<$1strike>"],
+
+ // Replace nsbp entites to char since it's easier to handle
+ [/&nbsp;/gi, "\u00a0"]
+ ]);
+
+ // Remove bad attributes, with or without quotes, ensuring that attribute text is really inside a tag.
+ // If JavaScript had a RegExp look-behind, we could have integrated this with the last process() array and got rid of the loop. But alas, it does not, so we cannot.
+ do {
+ len = h.length;
+ h = h.replace(/(<[a-z][^>]*\s)(?:id|name|language|type|on\w+|\w+:\w+)=(?:"[^"]*"|\w+)\s?/gi, "$1");
+ } while (len != h.length);
+
+ // Remove all spans if no styles is to be retained
+ if (getParam(ed, "paste_retain_style_properties").replace(/^none$/i, "").length == 0) {
+ h = h.replace(/<\/?span[^>]*>/gi, "");
+ } else {
+ // We're keeping styles, so at least clean them up.
+ // CSS Reference: http://msdn.microsoft.com/en-us/library/aa155477.aspx
+
+ process([
+ // Convert <span style="mso-spacerun:yes">___</span> to string of alternating breaking/non-breaking spaces of same length
+ [/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s\u00a0]*)<\/span>/gi,
+ function(str, spaces) {
+ return (spaces.length > 0)? spaces.replace(/./, " ").slice(Math.floor(spaces.length/2)).split("").join("\u00a0") : "";
+ }
+ ],
+
+ // Examine all styles: delete junk, transform some, and keep the rest
+ [/(<[a-z][^>]*)\sstyle="([^"]*)"/gi,
+ function(str, tag, style) {
+ var n = [],
+ i = 0,
+ s = explode(trim(style).replace(/&quot;/gi, "'"), ";");
+
+ // Examine each style definition within the tag's style attribute
+ each(s, function(v) {
+ var name, value,
+ parts = explode(v, ":");
+
+ function ensureUnits(v) {
+ return v + ((v !== "0") && (/\d$/.test(v)))? "px" : "";
+ }
+
+ if (parts.length == 2) {
+ name = parts[0].toLowerCase();
+ value = parts[1].toLowerCase();
+
+ // Translate certain MS Office styles into their CSS equivalents
+ switch (name) {
+ case "mso-padding-alt":
+ case "mso-padding-top-alt":
+ case "mso-padding-right-alt":
+ case "mso-padding-bottom-alt":
+ case "mso-padding-left-alt":
+ case "mso-margin-alt":
+ case "mso-margin-top-alt":
+ case "mso-margin-right-alt":
+ case "mso-margin-bottom-alt":
+ case "mso-margin-left-alt":
+ case "mso-table-layout-alt":
+ case "mso-height":
+ case "mso-width":
+ case "mso-vertical-align-alt":
+ n[i++] = name.replace(/^mso-|-alt$/g, "") + ":" + ensureUnits(value);
+ return;
+
+ case "horiz-align":
+ n[i++] = "text-align:" + value;
+ return;
+
+ case "vert-align":
+ n[i++] = "vertical-align:" + value;
+ return;
+
+ case "font-color":
+ case "mso-foreground":
+ n[i++] = "color:" + value;
+ return;
+
+ case "mso-background":
+ case "mso-highlight":
+ n[i++] = "background:" + value;
+ return;
+
+ case "mso-default-height":
+ n[i++] = "min-height:" + ensureUnits(value);
+ return;
+
+ case "mso-default-width":
+ n[i++] = "min-width:" + ensureUnits(value);
+ return;
+
+ case "mso-padding-between-alt":
+ n[i++] = "border-collapse:separate;border-spacing:" + ensureUnits(value);
+ return;
+
+ case "text-line-through":
+ if ((value == "single") || (value == "double")) {
+ n[i++] = "text-decoration:line-through";
+ }
+ return;
+
+ case "mso-zero-height":
+ if (value == "yes") {
+ n[i++] = "display:none";
+ }
+ return;
+ }
+
+ // Eliminate all MS Office style definitions that have no CSS equivalent by examining the first characters in the name
+ if (/^(mso|column|font-emph|lang|layout|line-break|list-image|nav|panose|punct|row|ruby|sep|size|src|tab-|table-border|text-(?!align|decor|indent|trans)|top-bar|version|vnd|word-break)/.test(name)) {
+ return;
+ }
+
+ // If it reached this point, it must be a valid CSS style
+ n[i++] = name + ":" + parts[1]; // Lower-case name, but keep value case
+ }
+ });
+
+ // If style attribute contained any valid styles the re-write it; otherwise delete style attribute.
+ if (i > 0) {
+ return tag + ' style="' + n.join(';') + '"';
+ } else {
+ return tag;
+ }
+ }
+ ]
+ ]);
+ }
+ }
+
+ // Replace headers with <strong>
+ if (getParam(ed, "paste_convert_headers_to_strong")) {
+ process([
+ [/<h[1-6][^>]*>/gi, "<p><strong>"],
+ [/<\/h[1-6][^>]*>/gi, "</strong></p>"]
+ ]);
+ }
+
+ process([
+ // Copy paste from Java like Open Office will produce this junk on FF
+ [/Version:[\d.]+\nStartHTML:\d+\nEndHTML:\d+\nStartFragment:\d+\nEndFragment:\d+/gi, '']
+ ]);
+
+ // Class attribute options are: leave all as-is ("none"), remove all ("all"), or remove only those starting with mso ("mso").
+ // Note:- paste_strip_class_attributes: "none", verify_css_classes: true is also a good variation.
+ stripClass = getParam(ed, "paste_strip_class_attributes");
+
+ if (stripClass !== "none") {
+ function removeClasses(match, g1) {
+ if (stripClass === "all")
+ return '';
+
+ var cls = grep(explode(g1.replace(/^(["'])(.*)\1$/, "$2"), " "),
+ function(v) {
+ return (/^(?!mso)/i.test(v));
+ }
+ );
+
+ return cls.length ? ' class="' + cls.join(" ") + '"' : '';
+ };
+
+ h = h.replace(/ class="([^"]+)"/gi, removeClasses);
+ h = h.replace(/ class=([\-\w]+)/gi, removeClasses);
+ }
+
+ // Remove spans option
+ if (getParam(ed, "paste_remove_spans")) {
+ h = h.replace(/<\/?span[^>]*>/gi, "");
+ }
+
+ //console.log('After preprocess:' + h);
+
+ o.content = h;
+ },
+
+ /**
+ * Various post process items.
+ */
+ _postProcess : function(pl, o) {
+ var t = this, ed = t.editor, dom = ed.dom, styleProps;
+
+ if (ed.settings.paste_enable_default_filters == false) {
+ return;
+ }
+
+ if (o.wordContent) {
+ // Remove named anchors or TOC links
+ each(dom.select('a', o.node), function(a) {
+ if (!a.href || a.href.indexOf('#_Toc') != -1)
+ dom.remove(a, 1);
+ });
+
+ if (getParam(ed, "paste_convert_middot_lists")) {
+ t._convertLists(pl, o);
+ }
+
+ // Process styles
+ styleProps = getParam(ed, "paste_retain_style_properties"); // retained properties
+
+ // Process only if a string was specified and not equal to "all" or "*"
+ if ((tinymce.is(styleProps, "string")) && (styleProps !== "all") && (styleProps !== "*")) {
+ styleProps = tinymce.explode(styleProps.replace(/^none$/i, ""));
+
+ // Retains some style properties
+ each(dom.select('*', o.node), function(el) {
+ var newStyle = {}, npc = 0, i, sp, sv;
+
+ // Store a subset of the existing styles
+ if (styleProps) {
+ for (i = 0; i < styleProps.length; i++) {
+ sp = styleProps[i];
+ sv = dom.getStyle(el, sp);
+
+ if (sv) {
+ newStyle[sp] = sv;
+ npc++;
+ }
+ }
+ }
+
+ // Remove all of the existing styles
+ dom.setAttrib(el, 'style', '');
+
+ if (styleProps && npc > 0)
+ dom.setStyles(el, newStyle); // Add back the stored subset of styles
+ else // Remove empty span tags that do not have class attributes
+ if (el.nodeName == 'SPAN' && !el.className)
+ dom.remove(el, true);
+ });
+ }
+ }
+
+ // Remove all style information or only specifically on WebKit to avoid the style bug on that browser
+ if (getParam(ed, "paste_remove_styles") || (getParam(ed, "paste_remove_styles_if_webkit") && tinymce.isWebKit)) {
+ each(dom.select('*[style]', o.node), function(el) {
+ el.removeAttribute('style');
+ el.removeAttribute('data-mce-style');
+ });
+ } else {
+ if (tinymce.isWebKit) {
+ // We need to compress the styles on WebKit since if you paste <img border="0" /> it will become <img border="0" style="... lots of junk ..." />
+ // Removing the mce_style that contains the real value will force the Serializer engine to compress the styles
+ each(dom.select('*', o.node), function(el) {
+ el.removeAttribute('data-mce-style');
+ });
+ }
+ }
+ },
+
+ /**
+ * Converts the most common bullet and number formats in Office into a real semantic UL/LI list.
+ */
+ _convertLists : function(pl, o) {
+ var dom = pl.editor.dom, listElm, li, lastMargin = -1, margin, levels = [], lastType, html;
+
+ // Convert middot lists into real semantic lists
+ each(dom.select('p', o.node), function(p) {
+ var sib, val = '', type, html, idx, parents;
+
+ // Get text node value at beginning of paragraph
+ for (sib = p.firstChild; sib && sib.nodeType == 3; sib = sib.nextSibling)
+ val += sib.nodeValue;
+
+ val = p.innerHTML.replace(/<\/?\w+[^>]*>/gi, '').replace(/&nbsp;/g, '\u00a0');
+
+ // Detect unordered lists look for bullets
+ if (/^(__MCE_ITEM__)+[\u2022\u00b7\u00a7\u00d8o\u25CF]\s*\u00a0*/.test(val))
+ type = 'ul';
+
+ // Detect ordered lists 1., a. or ixv.
+ if (/^__MCE_ITEM__\s*\w+\.\s*\u00a0+/.test(val))
+ type = 'ol';
+
+ // Check if node value matches the list pattern: o&nbsp;&nbsp;
+ if (type) {
+ margin = parseFloat(p.style.marginLeft || 0);
+
+ if (margin > lastMargin)
+ levels.push(margin);
+
+ if (!listElm || type != lastType) {
+ listElm = dom.create(type);
+ dom.insertAfter(listElm, p);
+ } else {
+ // Nested list element
+ if (margin > lastMargin) {
+ listElm = li.appendChild(dom.create(type));
+ } else if (margin < lastMargin) {
+ // Find parent level based on margin value
+ idx = tinymce.inArray(levels, margin);
+ parents = dom.getParents(listElm.parentNode, type);
+ listElm = parents[parents.length - 1 - idx] || listElm;
+ }
+ }
+
+ // Remove middot or number spans if they exists
+ each(dom.select('span', p), function(span) {
+ var html = span.innerHTML.replace(/<\/?\w+[^>]*>/gi, '');
+
+ // Remove span with the middot or the number
+ if (type == 'ul' && /^__MCE_ITEM__[\u2022\u00b7\u00a7\u00d8o\u25CF]/.test(html))
+ dom.remove(span);
+ else if (/^__MCE_ITEM__[\s\S]*\w+\.(&nbsp;|\u00a0)*\s*/.test(html))
+ dom.remove(span);
+ });
+
+ html = p.innerHTML;
+
+ // Remove middot/list items
+ if (type == 'ul')
+ html = p.innerHTML.replace(/__MCE_ITEM__/g, '').replace(/^[\u2022\u00b7\u00a7\u00d8o\u25CF]\s*(&nbsp;|\u00a0)+\s*/, '');
+ else
+ html = p.innerHTML.replace(/__MCE_ITEM__/g, '').replace(/^\s*\w+\.(&nbsp;|\u00a0)+\s*/, '');
+
+ // Create li and add paragraph data into the new li
+ li = listElm.appendChild(dom.create('li', 0, html));
+ dom.remove(p);
+
+ lastMargin = margin;
+ lastType = type;
+ } else
+ listElm = lastMargin = 0; // End list element
+ });
+
+ // Remove any left over makers
+ html = o.node.innerHTML;
+ if (html.indexOf('__MCE_ITEM__') != -1)
+ o.node.innerHTML = html.replace(/__MCE_ITEM__/g, '');
+ },
+
+ /**
+ * Inserts the specified contents at the caret position.
+ */
+ _insert : function(h, skip_undo) {
+ var ed = this.editor, r = ed.selection.getRng();
+
+ // First delete the contents seems to work better on WebKit when the selection spans multiple list items or multiple table cells.
+ if (!ed.selection.isCollapsed() && r.startContainer != r.endContainer)
+ ed.getDoc().execCommand('Delete', false, null);
+
+ ed.execCommand('mceInsertContent', false, h, {skip_undo : skip_undo});
+ },
+
+ /**
+ * Instead of the old plain text method which tried to re-create a paste operation, the
+ * new approach adds a plain text mode toggle switch that changes the behavior of paste.
+ * This function is passed the same input that the regular paste plugin produces.
+ * It performs additional scrubbing and produces (and inserts) the plain text.
+ * This approach leverages all of the great existing functionality in the paste
+ * plugin, and requires minimal changes to add the new functionality.
+ * Speednet - June 2009
+ */
+ _insertPlainText : function(content) {
+ var ed = this.editor,
+ linebr = getParam(ed, "paste_text_linebreaktype"),
+ rl = getParam(ed, "paste_text_replacements"),
+ is = tinymce.is;
+
+ function process(items) {
+ each(items, function(v) {
+ if (v.constructor == RegExp)
+ content = content.replace(v, "");
+ else
+ content = content.replace(v[0], v[1]);
+ });
+ };
+
+ if ((typeof(content) === "string") && (content.length > 0)) {
+ // If HTML content with line-breaking tags, then remove all cr/lf chars because only tags will break a line
+ if (/<(?:p|br|h[1-6]|ul|ol|dl|table|t[rdh]|div|blockquote|fieldset|pre|address|center)[^>]*>/i.test(content)) {
+ process([
+ /[\n\r]+/g
+ ]);
+ } else {
+ // Otherwise just get rid of carriage returns (only need linefeeds)
+ process([
+ /\r+/g
+ ]);
+ }
+
+ process([
+ [/<\/(?:p|h[1-6]|ul|ol|dl|table|div|blockquote|fieldset|pre|address|center)>/gi, "\n\n"], // Block tags get a blank line after them
+ [/<br[^>]*>|<\/tr>/gi, "\n"], // Single linebreak for <br /> tags and table rows
+ [/<\/t[dh]>\s*<t[dh][^>]*>/gi, "\t"], // Table cells get tabs betweem them
+ /<[a-z!\/?][^>]*>/gi, // Delete all remaining tags
+ [/&nbsp;/gi, " "], // Convert non-break spaces to regular spaces (remember, *plain text*)
+ [/(?:(?!\n)\s)*(\n+)(?:(?!\n)\s)*/gi, "$1"],// Cool little RegExp deletes whitespace around linebreak chars.
+ [/\n{3,}/g, "\n\n"] // Max. 2 consecutive linebreaks
+ ]);
+
+ content = ed.dom.decode(tinymce.html.Entities.encodeRaw(content));
+
+ // Perform default or custom replacements
+ if (is(rl, "array")) {
+ process(rl);
+ } else if (is(rl, "string")) {
+ process(new RegExp(rl, "gi"));
+ }
+
+ // Treat paragraphs as specified in the config
+ if (linebr == "none") {
+ // Convert all line breaks to space
+ process([
+ [/\n+/g, " "]
+ ]);
+ } else if (linebr == "br") {
+ // Convert all line breaks to <br />
+ process([
+ [/\n/g, "<br />"]
+ ]);
+ } else if (linebr == "p") {
+ // Convert all line breaks to <p>...</p>
+ process([
+ [/\n+/g, "</p><p>"],
+ [/^(.*<\/p>)(<p>)$/, '<p>$1']
+ ]);
+ } else {
+ // defaults to "combined"
+ // Convert single line breaks to <br /> and double line breaks to <p>...</p>
+ process([
+ [/\n\n/g, "</p><p>"],
+ [/^(.*<\/p>)(<p>)$/, '<p>$1'],
+ [/\n/g, "<br />"]
+ ]);
+ }
+
+ ed.execCommand('mceInsertContent', false, content);
+ }
+ },
+
+ /**
+ * This method will open the old style paste dialogs. Some users might want the old behavior but still use the new cleanup engine.
+ */
+ _legacySupport : function() {
+ var t = this, ed = t.editor;
+
+ // Register command(s) for backwards compatibility
+ ed.addCommand("mcePasteWord", function() {
+ ed.windowManager.open({
+ file: t.url + "/pasteword.htm",
+ width: parseInt(getParam(ed, "paste_dialog_width")),
+ height: parseInt(getParam(ed, "paste_dialog_height")),
+ inline: 1
+ });
+ });
+
+ if (getParam(ed, "paste_text_use_dialog")) {
+ ed.addCommand("mcePasteText", function() {
+ ed.windowManager.open({
+ file : t.url + "/pastetext.htm",
+ width: parseInt(getParam(ed, "paste_dialog_width")),
+ height: parseInt(getParam(ed, "paste_dialog_height")),
+ inline : 1
+ });
+ });
+ }
+
+ // Register button for backwards compatibility
+ ed.addButton("pasteword", {title : "paste.paste_word_desc", cmd : "mcePasteWord"});
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add("paste", tinymce.plugins.PastePlugin);
+})();
diff --git a/askbot/media/js/tinymce/plugins/paste/js/pastetext.js b/askbot/media/js/tinymce/plugins/paste/js/pastetext.js
new file mode 100644
index 00000000..c524f9eb
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/paste/js/pastetext.js
@@ -0,0 +1,36 @@
+tinyMCEPopup.requireLangPack();
+
+var PasteTextDialog = {
+ init : function() {
+ this.resize();
+ },
+
+ insert : function() {
+ var h = tinyMCEPopup.dom.encode(document.getElementById('content').value), lines;
+
+ // Convert linebreaks into paragraphs
+ if (document.getElementById('linebreaks').checked) {
+ lines = h.split(/\r?\n/);
+ if (lines.length > 1) {
+ h = '';
+ tinymce.each(lines, function(row) {
+ h += '<p>' + row + '</p>';
+ });
+ }
+ }
+
+ tinyMCEPopup.editor.execCommand('mceInsertClipboardContent', false, {content : h});
+ tinyMCEPopup.close();
+ },
+
+ resize : function() {
+ var vp = tinyMCEPopup.dom.getViewPort(window), el;
+
+ el = document.getElementById('content');
+
+ el.style.width = (vp.w - 20) + 'px';
+ el.style.height = (vp.h - 90) + 'px';
+ }
+};
+
+tinyMCEPopup.onInit.add(PasteTextDialog.init, PasteTextDialog);
diff --git a/askbot/media/js/tinymce/plugins/paste/js/pasteword.js b/askbot/media/js/tinymce/plugins/paste/js/pasteword.js
new file mode 100644
index 00000000..a52731c3
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/paste/js/pasteword.js
@@ -0,0 +1,51 @@
+tinyMCEPopup.requireLangPack();
+
+var PasteWordDialog = {
+ init : function() {
+ var ed = tinyMCEPopup.editor, el = document.getElementById('iframecontainer'), ifr, doc, css, cssHTML = '';
+
+ // Create iframe
+ el.innerHTML = '<iframe id="iframe" src="javascript:\'\';" frameBorder="0" style="border: 1px solid gray"></iframe>';
+ ifr = document.getElementById('iframe');
+ doc = ifr.contentWindow.document;
+
+ // Force absolute CSS urls
+ css = [ed.baseURI.toAbsolute("themes/" + ed.settings.theme + "/skins/" + ed.settings.skin + "/content.css")];
+ css = css.concat(tinymce.explode(ed.settings.content_css) || []);
+ tinymce.each(css, function(u) {
+ cssHTML += '<link href="' + ed.documentBaseURI.toAbsolute('' + u) + '" rel="stylesheet" type="text/css" />';
+ });
+
+ // Write content into iframe
+ doc.open();
+ doc.write('<html><head>' + cssHTML + '</head><body class="mceContentBody" spellcheck="false"></body></html>');
+ doc.close();
+
+ doc.designMode = 'on';
+ this.resize();
+
+ window.setTimeout(function() {
+ ifr.contentWindow.focus();
+ }, 10);
+ },
+
+ insert : function() {
+ var h = document.getElementById('iframe').contentWindow.document.body.innerHTML;
+
+ tinyMCEPopup.editor.execCommand('mceInsertClipboardContent', false, {content : h, wordContent : true});
+ tinyMCEPopup.close();
+ },
+
+ resize : function() {
+ var vp = tinyMCEPopup.dom.getViewPort(window), el;
+
+ el = document.getElementById('iframe');
+
+ if (el) {
+ el.style.width = (vp.w - 20) + 'px';
+ el.style.height = (vp.h - 90) + 'px';
+ }
+ }
+};
+
+tinyMCEPopup.onInit.add(PasteWordDialog.init, PasteWordDialog);
diff --git a/askbot/media/js/tinymce/plugins/paste/langs/en_dlg.js b/askbot/media/js/tinymce/plugins/paste/langs/en_dlg.js
new file mode 100644
index 00000000..bc74daf8
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/paste/langs/en_dlg.js
@@ -0,0 +1 @@
+tinyMCE.addI18n('en.paste_dlg',{"word_title":"Use Ctrl+V on your keyboard to paste the text into the window.","text_linebreaks":"Keep Linebreaks","text_title":"Use Ctrl+V on your keyboard to paste the text into the window."}); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/paste/pastetext.htm b/askbot/media/js/tinymce/plugins/paste/pastetext.htm
new file mode 100644
index 00000000..b6559454
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/paste/pastetext.htm
@@ -0,0 +1,27 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#paste.paste_text_desc}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="js/pastetext.js"></script>
+</head>
+<body onresize="PasteTextDialog.resize();" style="display:none; overflow:hidden;">
+ <form name="source" onsubmit="return PasteTextDialog.insert();" action="#">
+ <div style="float: left" class="title">{#paste.paste_text_desc}</div>
+
+ <div style="float: right">
+ <input type="checkbox" name="linebreaks" id="linebreaks" class="wordWrapCode" checked="checked" /><label for="linebreaks">{#paste_dlg.text_linebreaks}</label>
+ </div>
+
+ <br style="clear: both" />
+
+ <div>{#paste_dlg.text_title}</div>
+
+ <textarea id="content" name="content" rows="15" cols="100" style="width: 100%; height: 100%; font-family: 'Courier New',Courier,mono; font-size: 12px;" dir="ltr" wrap="soft" class="mceFocus"></textarea>
+
+ <div class="mceActionPanel">
+ <input type="submit" name="insert" value="{#insert}" id="insert" />
+ <input type="button" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" id="cancel" />
+ </div>
+ </form>
+</body>
+</html> \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/paste/pasteword.htm b/askbot/media/js/tinymce/plugins/paste/pasteword.htm
new file mode 100644
index 00000000..0f6bb412
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/paste/pasteword.htm
@@ -0,0 +1,21 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#paste.paste_word_desc}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="js/pasteword.js"></script>
+</head>
+<body onresize="PasteWordDialog.resize();" style="display:none; overflow:hidden;">
+ <form name="source" onsubmit="return PasteWordDialog.insert();" action="#">
+ <div class="title">{#paste.paste_word_desc}</div>
+
+ <div>{#paste_dlg.word_title}</div>
+
+ <div id="iframecontainer"></div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#insert}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+ </form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/preview/editor_plugin.js b/askbot/media/js/tinymce/plugins/preview/editor_plugin.js
new file mode 100644
index 00000000..507909c5
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/preview/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.Preview",{init:function(a,b){var d=this,c=tinymce.explode(a.settings.content_css);d.editor=a;tinymce.each(c,function(f,e){c[e]=a.documentBaseURI.toAbsolute(f)});a.addCommand("mcePreview",function(){a.windowManager.open({file:a.getParam("plugin_preview_pageurl",b+"/preview.html"),width:parseInt(a.getParam("plugin_preview_width","550")),height:parseInt(a.getParam("plugin_preview_height","600")),resizable:"yes",scrollbars:"yes",popup_css:c?c.join(","):a.baseURI.toAbsolute("themes/"+a.settings.theme+"/skins/"+a.settings.skin+"/content.css"),inline:a.getParam("plugin_preview_inline",1)},{base:a.documentBaseURI.getURI()})});a.addButton("preview",{title:"preview.preview_desc",cmd:"mcePreview"})},getInfo:function(){return{longname:"Preview",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/preview",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("preview",tinymce.plugins.Preview)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/preview/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/preview/editor_plugin_src.js
new file mode 100644
index 00000000..80f00f0d
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/preview/editor_plugin_src.js
@@ -0,0 +1,53 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.Preview', {
+ init : function(ed, url) {
+ var t = this, css = tinymce.explode(ed.settings.content_css);
+
+ t.editor = ed;
+
+ // Force absolute CSS urls
+ tinymce.each(css, function(u, k) {
+ css[k] = ed.documentBaseURI.toAbsolute(u);
+ });
+
+ ed.addCommand('mcePreview', function() {
+ ed.windowManager.open({
+ file : ed.getParam("plugin_preview_pageurl", url + "/preview.html"),
+ width : parseInt(ed.getParam("plugin_preview_width", "550")),
+ height : parseInt(ed.getParam("plugin_preview_height", "600")),
+ resizable : "yes",
+ scrollbars : "yes",
+ popup_css : css ? css.join(',') : ed.baseURI.toAbsolute("themes/" + ed.settings.theme + "/skins/" + ed.settings.skin + "/content.css"),
+ inline : ed.getParam("plugin_preview_inline", 1)
+ }, {
+ base : ed.documentBaseURI.getURI()
+ });
+ });
+
+ ed.addButton('preview', {title : 'preview.preview_desc', cmd : 'mcePreview'});
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Preview',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/preview',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('preview', tinymce.plugins.Preview);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/preview/example.html b/askbot/media/js/tinymce/plugins/preview/example.html
new file mode 100644
index 00000000..b2c3d90c
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/preview/example.html
@@ -0,0 +1,28 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<script language="javascript" src="../../tiny_mce_popup.js"></script>
+<script type="text/javascript" src="jscripts/embed.js"></script>
+<script type="text/javascript">
+tinyMCEPopup.onInit.add(function(ed) {
+ var dom = tinyMCEPopup.dom;
+
+ // Load editor content_css
+ tinymce.each(ed.settings.content_css.split(','), function(u) {
+ dom.loadCSS(ed.documentBaseURI.toAbsolute(u));
+ });
+
+ // Place contents inside div container
+ dom.setHTML('content', ed.getContent());
+});
+</script>
+<title>Example of a custom preview page</title>
+</head>
+<body>
+
+Editor contents: <br />
+<div id="content">
+<!-- Gets filled with editor contents -->
+</div>
+
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/preview/jscripts/embed.js b/askbot/media/js/tinymce/plugins/preview/jscripts/embed.js
new file mode 100644
index 00000000..f8dc8105
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/preview/jscripts/embed.js
@@ -0,0 +1,73 @@
+/**
+ * This script contains embed functions for common plugins. This scripts are complety free to use for any purpose.
+ */
+
+function writeFlash(p) {
+ writeEmbed(
+ 'D27CDB6E-AE6D-11cf-96B8-444553540000',
+ 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0',
+ 'application/x-shockwave-flash',
+ p
+ );
+}
+
+function writeShockWave(p) {
+ writeEmbed(
+ '166B1BCA-3F9C-11CF-8075-444553540000',
+ 'http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0',
+ 'application/x-director',
+ p
+ );
+}
+
+function writeQuickTime(p) {
+ writeEmbed(
+ '02BF25D5-8C17-4B23-BC80-D3488ABDDC6B',
+ 'http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0',
+ 'video/quicktime',
+ p
+ );
+}
+
+function writeRealMedia(p) {
+ writeEmbed(
+ 'CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA',
+ 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0',
+ 'audio/x-pn-realaudio-plugin',
+ p
+ );
+}
+
+function writeWindowsMedia(p) {
+ p.url = p.src;
+ writeEmbed(
+ '6BF52A52-394A-11D3-B153-00C04F79FAA6',
+ 'http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701',
+ 'application/x-mplayer2',
+ p
+ );
+}
+
+function writeEmbed(cls, cb, mt, p) {
+ var h = '', n;
+
+ h += '<object classid="clsid:' + cls + '" codebase="' + cb + '"';
+ h += typeof(p.id) != "undefined" ? 'id="' + p.id + '"' : '';
+ h += typeof(p.name) != "undefined" ? 'name="' + p.name + '"' : '';
+ h += typeof(p.width) != "undefined" ? 'width="' + p.width + '"' : '';
+ h += typeof(p.height) != "undefined" ? 'height="' + p.height + '"' : '';
+ h += typeof(p.align) != "undefined" ? 'align="' + p.align + '"' : '';
+ h += '>';
+
+ for (n in p)
+ h += '<param name="' + n + '" value="' + p[n] + '">';
+
+ h += '<embed type="' + mt + '"';
+
+ for (n in p)
+ h += n + '="' + p[n] + '" ';
+
+ h += '></embed></object>';
+
+ document.write(h);
+}
diff --git a/askbot/media/js/tinymce/plugins/preview/preview.html b/askbot/media/js/tinymce/plugins/preview/preview.html
new file mode 100644
index 00000000..67e7b142
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/preview/preview.html
@@ -0,0 +1,17 @@
+<!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">
+<head>
+<script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+<script type="text/javascript" src="jscripts/embed.js"></script>
+<script type="text/javascript"><!--
+document.write('<base href="' + tinyMCEPopup.getWindowArg("base") + '">');
+// -->
+</script>
+<title>{#preview.preview_desc}</title>
+</head>
+<body id="content">
+<script type="text/javascript">
+ document.write(tinyMCEPopup.editor.getContent());
+</script>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/print/editor_plugin.js b/askbot/media/js/tinymce/plugins/print/editor_plugin.js
new file mode 100644
index 00000000..b5b3a55e
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/print/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.Print",{init:function(a,b){a.addCommand("mcePrint",function(){a.getWin().print()});a.addButton("print",{title:"print.print_desc",cmd:"mcePrint"})},getInfo:function(){return{longname:"Print",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/print",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("print",tinymce.plugins.Print)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/print/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/print/editor_plugin_src.js
new file mode 100644
index 00000000..3933fe65
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/print/editor_plugin_src.js
@@ -0,0 +1,34 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.Print', {
+ init : function(ed, url) {
+ ed.addCommand('mcePrint', function() {
+ ed.getWin().print();
+ });
+
+ ed.addButton('print', {title : 'print.print_desc', cmd : 'mcePrint'});
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Print',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/print',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('print', tinymce.plugins.Print);
+})();
diff --git a/askbot/media/js/tinymce/plugins/save/editor_plugin.js b/askbot/media/js/tinymce/plugins/save/editor_plugin.js
new file mode 100644
index 00000000..8e939966
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/save/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.Save",{init:function(a,b){var c=this;c.editor=a;a.addCommand("mceSave",c._save,c);a.addCommand("mceCancel",c._cancel,c);a.addButton("save",{title:"save.save_desc",cmd:"mceSave"});a.addButton("cancel",{title:"save.cancel_desc",cmd:"mceCancel"});a.onNodeChange.add(c._nodeChange,c);a.addShortcut("ctrl+s",a.getLang("save.save_desc"),"mceSave")},getInfo:function(){return{longname:"Save",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/save",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_nodeChange:function(b,a,c){var b=this.editor;if(b.getParam("save_enablewhendirty")){a.setDisabled("save",!b.isDirty());a.setDisabled("cancel",!b.isDirty())}},_save:function(){var c=this.editor,a,e,d,b;a=tinymce.DOM.get(c.id).form||tinymce.DOM.getParent(c.id,"form");if(c.getParam("save_enablewhendirty")&&!c.isDirty()){return}tinyMCE.triggerSave();if(e=c.getParam("save_onsavecallback")){if(c.execCallback("save_onsavecallback",c)){c.startContent=tinymce.trim(c.getContent({format:"raw"}));c.nodeChanged()}return}if(a){c.isNotDirty=true;if(a.onsubmit==null||a.onsubmit()!=false){a.submit()}c.nodeChanged()}else{c.windowManager.alert("Error: No form element found.")}},_cancel:function(){var a=this.editor,c,b=tinymce.trim(a.startContent);if(c=a.getParam("save_oncancelcallback")){a.execCallback("save_oncancelcallback",a);return}a.setContent(b);a.undoManager.clear();a.nodeChanged()}});tinymce.PluginManager.add("save",tinymce.plugins.Save)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/save/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/save/editor_plugin_src.js
new file mode 100644
index 00000000..f5a3de8f
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/save/editor_plugin_src.js
@@ -0,0 +1,101 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.Save', {
+ init : function(ed, url) {
+ var t = this;
+
+ t.editor = ed;
+
+ // Register commands
+ ed.addCommand('mceSave', t._save, t);
+ ed.addCommand('mceCancel', t._cancel, t);
+
+ // Register buttons
+ ed.addButton('save', {title : 'save.save_desc', cmd : 'mceSave'});
+ ed.addButton('cancel', {title : 'save.cancel_desc', cmd : 'mceCancel'});
+
+ ed.onNodeChange.add(t._nodeChange, t);
+ ed.addShortcut('ctrl+s', ed.getLang('save.save_desc'), 'mceSave');
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Save',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/save',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ // Private methods
+
+ _nodeChange : function(ed, cm, n) {
+ var ed = this.editor;
+
+ if (ed.getParam('save_enablewhendirty')) {
+ cm.setDisabled('save', !ed.isDirty());
+ cm.setDisabled('cancel', !ed.isDirty());
+ }
+ },
+
+ // Private methods
+
+ _save : function() {
+ var ed = this.editor, formObj, os, i, elementId;
+
+ formObj = tinymce.DOM.get(ed.id).form || tinymce.DOM.getParent(ed.id, 'form');
+
+ if (ed.getParam("save_enablewhendirty") && !ed.isDirty())
+ return;
+
+ tinyMCE.triggerSave();
+
+ // Use callback instead
+ if (os = ed.getParam("save_onsavecallback")) {
+ if (ed.execCallback('save_onsavecallback', ed)) {
+ ed.startContent = tinymce.trim(ed.getContent({format : 'raw'}));
+ ed.nodeChanged();
+ }
+
+ return;
+ }
+
+ if (formObj) {
+ ed.isNotDirty = true;
+
+ if (formObj.onsubmit == null || formObj.onsubmit() != false)
+ formObj.submit();
+
+ ed.nodeChanged();
+ } else
+ ed.windowManager.alert("Error: No form element found.");
+ },
+
+ _cancel : function() {
+ var ed = this.editor, os, h = tinymce.trim(ed.startContent);
+
+ // Use callback instead
+ if (os = ed.getParam("save_oncancelcallback")) {
+ ed.execCallback('save_oncancelcallback', ed);
+ return;
+ }
+
+ ed.setContent(h);
+ ed.undoManager.clear();
+ ed.nodeChanged();
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('save', tinymce.plugins.Save);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/searchreplace/css/searchreplace.css b/askbot/media/js/tinymce/plugins/searchreplace/css/searchreplace.css
new file mode 100644
index 00000000..ecdf58c7
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/searchreplace/css/searchreplace.css
@@ -0,0 +1,6 @@
+.panel_wrapper {height:85px;}
+.panel_wrapper div.current {height:85px;}
+
+/* IE */
+* html .panel_wrapper {height:100px;}
+* html .panel_wrapper div.current {height:100px;}
diff --git a/askbot/media/js/tinymce/plugins/searchreplace/editor_plugin.js b/askbot/media/js/tinymce/plugins/searchreplace/editor_plugin.js
new file mode 100644
index 00000000..165bc12d
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/searchreplace/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.SearchReplacePlugin",{init:function(a,c){function b(d){window.focus();a.windowManager.open({file:c+"/searchreplace.htm",width:420+parseInt(a.getLang("searchreplace.delta_width",0)),height:170+parseInt(a.getLang("searchreplace.delta_height",0)),inline:1,auto_focus:0},{mode:d,search_string:a.selection.getContent({format:"text"}),plugin_url:c})}a.addCommand("mceSearch",function(){b("search")});a.addCommand("mceReplace",function(){b("replace")});a.addButton("search",{title:"searchreplace.search_desc",cmd:"mceSearch"});a.addButton("replace",{title:"searchreplace.replace_desc",cmd:"mceReplace"});a.addShortcut("ctrl+f","searchreplace.search_desc","mceSearch")},getInfo:function(){return{longname:"Search/Replace",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/searchreplace",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("searchreplace",tinymce.plugins.SearchReplacePlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/searchreplace/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/searchreplace/editor_plugin_src.js
new file mode 100644
index 00000000..4c87e8fa
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/searchreplace/editor_plugin_src.js
@@ -0,0 +1,61 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.SearchReplacePlugin', {
+ init : function(ed, url) {
+ function open(m) {
+ // Keep IE from writing out the f/r character to the editor
+ // instance while initializing a new dialog. See: #3131190
+ window.focus();
+
+ ed.windowManager.open({
+ file : url + '/searchreplace.htm',
+ width : 420 + parseInt(ed.getLang('searchreplace.delta_width', 0)),
+ height : 170 + parseInt(ed.getLang('searchreplace.delta_height', 0)),
+ inline : 1,
+ auto_focus : 0
+ }, {
+ mode : m,
+ search_string : ed.selection.getContent({format : 'text'}),
+ plugin_url : url
+ });
+ };
+
+ // Register commands
+ ed.addCommand('mceSearch', function() {
+ open('search');
+ });
+
+ ed.addCommand('mceReplace', function() {
+ open('replace');
+ });
+
+ // Register buttons
+ ed.addButton('search', {title : 'searchreplace.search_desc', cmd : 'mceSearch'});
+ ed.addButton('replace', {title : 'searchreplace.replace_desc', cmd : 'mceReplace'});
+
+ ed.addShortcut('ctrl+f', 'searchreplace.search_desc', 'mceSearch');
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Search/Replace',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/searchreplace',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('searchreplace', tinymce.plugins.SearchReplacePlugin);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/searchreplace/js/searchreplace.js b/askbot/media/js/tinymce/plugins/searchreplace/js/searchreplace.js
new file mode 100644
index 00000000..80284b9f
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/searchreplace/js/searchreplace.js
@@ -0,0 +1,142 @@
+tinyMCEPopup.requireLangPack();
+
+var SearchReplaceDialog = {
+ init : function(ed) {
+ var t = this, f = document.forms[0], m = tinyMCEPopup.getWindowArg("mode");
+
+ t.switchMode(m);
+
+ f[m + '_panel_searchstring'].value = tinyMCEPopup.getWindowArg("search_string");
+
+ // Focus input field
+ f[m + '_panel_searchstring'].focus();
+
+ mcTabs.onChange.add(function(tab_id, panel_id) {
+ t.switchMode(tab_id.substring(0, tab_id.indexOf('_')));
+ });
+ },
+
+ switchMode : function(m) {
+ var f, lm = this.lastMode;
+
+ if (lm != m) {
+ f = document.forms[0];
+
+ if (lm) {
+ f[m + '_panel_searchstring'].value = f[lm + '_panel_searchstring'].value;
+ f[m + '_panel_backwardsu'].checked = f[lm + '_panel_backwardsu'].checked;
+ f[m + '_panel_backwardsd'].checked = f[lm + '_panel_backwardsd'].checked;
+ f[m + '_panel_casesensitivebox'].checked = f[lm + '_panel_casesensitivebox'].checked;
+ }
+
+ mcTabs.displayTab(m + '_tab', m + '_panel');
+ document.getElementById("replaceBtn").style.display = (m == "replace") ? "inline" : "none";
+ document.getElementById("replaceAllBtn").style.display = (m == "replace") ? "inline" : "none";
+ this.lastMode = m;
+ }
+ },
+
+ searchNext : function(a) {
+ var ed = tinyMCEPopup.editor, se = ed.selection, r = se.getRng(), f, m = this.lastMode, s, b, fl = 0, w = ed.getWin(), wm = ed.windowManager, fo = 0;
+
+ // Get input
+ f = document.forms[0];
+ s = f[m + '_panel_searchstring'].value;
+ b = f[m + '_panel_backwardsu'].checked;
+ ca = f[m + '_panel_casesensitivebox'].checked;
+ rs = f['replace_panel_replacestring'].value;
+
+ if (tinymce.isIE) {
+ r = ed.getDoc().selection.createRange();
+ }
+
+ if (s == '')
+ return;
+
+ function fix() {
+ // Correct Firefox graphics glitches
+ // TODO: Verify if this is actually needed any more, maybe it was for very old FF versions?
+ r = se.getRng().cloneRange();
+ ed.getDoc().execCommand('SelectAll', false, null);
+ se.setRng(r);
+ };
+
+ function replace() {
+ ed.selection.setContent(rs); // Needs to be duplicated due to selection bug in IE
+ };
+
+ // IE flags
+ if (ca)
+ fl = fl | 4;
+
+ switch (a) {
+ case 'all':
+ // Move caret to beginning of text
+ ed.execCommand('SelectAll');
+ ed.selection.collapse(true);
+
+ if (tinymce.isIE) {
+ ed.focus();
+ r = ed.getDoc().selection.createRange();
+
+ while (r.findText(s, b ? -1 : 1, fl)) {
+ r.scrollIntoView();
+ r.select();
+ replace();
+ fo = 1;
+
+ if (b) {
+ r.moveEnd("character", -(rs.length)); // Otherwise will loop forever
+ }
+ }
+
+ tinyMCEPopup.storeSelection();
+ } else {
+ while (w.find(s, ca, b, false, false, false, false)) {
+ replace();
+ fo = 1;
+ }
+ }
+
+ if (fo)
+ tinyMCEPopup.alert(ed.getLang('searchreplace_dlg.allreplaced'));
+ else
+ tinyMCEPopup.alert(ed.getLang('searchreplace_dlg.notfound'));
+
+ return;
+
+ case 'current':
+ if (!ed.selection.isCollapsed())
+ replace();
+
+ break;
+ }
+
+ se.collapse(b);
+ r = se.getRng();
+
+ // Whats the point
+ if (!s)
+ return;
+
+ if (tinymce.isIE) {
+ ed.focus();
+ r = ed.getDoc().selection.createRange();
+
+ if (r.findText(s, b ? -1 : 1, fl)) {
+ r.scrollIntoView();
+ r.select();
+ } else
+ tinyMCEPopup.alert(ed.getLang('searchreplace_dlg.notfound'));
+
+ tinyMCEPopup.storeSelection();
+ } else {
+ if (!w.find(s, ca, b, false, false, false, false))
+ tinyMCEPopup.alert(ed.getLang('searchreplace_dlg.notfound'));
+ else
+ fix();
+ }
+ }
+};
+
+tinyMCEPopup.onInit.add(SearchReplaceDialog.init, SearchReplaceDialog);
diff --git a/askbot/media/js/tinymce/plugins/searchreplace/langs/en_dlg.js b/askbot/media/js/tinymce/plugins/searchreplace/langs/en_dlg.js
new file mode 100644
index 00000000..8a659009
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/searchreplace/langs/en_dlg.js
@@ -0,0 +1 @@
+tinyMCE.addI18n('en.searchreplace_dlg',{findwhat:"Find What",replacewith:"Replace with",direction:"Direction",up:"Up",down:"Down",mcase:"Match Case",findnext:"Find Next",allreplaced:"All occurrences of the search string were replaced.","searchnext_desc":"Find Again",notfound:"The search has been completed. The search string could not be found.","search_title":"Find","replace_title":"Find/Replace",replaceall:"Replace All",replace:"Replace"}); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/searchreplace/searchreplace.htm b/askbot/media/js/tinymce/plugins/searchreplace/searchreplace.htm
new file mode 100644
index 00000000..2443a918
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/searchreplace/searchreplace.htm
@@ -0,0 +1,100 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#searchreplace_dlg.replace_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="js/searchreplace.js"></script>
+ <link rel="stylesheet" type="text/css" href="css/searchreplace.css" />
+</head>
+<body style="display:none;" role="application" aria-labelledby="app_title">
+<span id="app_title" style="display:none">{#searchreplace_dlg.replace_title}</span>
+<form onsubmit="SearchReplaceDialog.searchNext('none');return false;" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="search_tab" aria-controls="search_panel"><span><a href="javascript:SearchReplaceDialog.switchMode('search');" onmousedown="return false;">{#searchreplace.search_desc}</a></span></li>
+ <li id="replace_tab" aria-controls="replace_panel"><span><a href="javascript:SearchReplaceDialog.switchMode('replace');" onmousedown="return false;">{#searchreplace_dlg.replace}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="search_panel" class="panel">
+ <table role="presentation" border="0" cellspacing="0" cellpadding="2">
+ <tr>
+ <td><label for="search_panel_searchstring">{#searchreplace_dlg.findwhat}</label></td>
+ <td><input type="text" id="search_panel_searchstring" name="search_panel_searchstring" style="width: 200px" aria-required="true" /></td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0" class="direction">
+ <tr role="group" aria-labelledby="search_panel_backwards_label">
+ <td><label id="search_panel_backwards_label">{#searchreplace_dlg.direction}</label></td>
+ <td><input id="search_panel_backwardsu" name="search_panel_backwards" class="radio" type="radio" /></td>
+ <td><label for="search_panel_backwardsu">{#searchreplace_dlg.up}</label></td>
+ <td><input id="search_panel_backwardsd" name="search_panel_backwards" class="radio" type="radio" checked="checked" /></td>
+ <td><label for="search_panel_backwardsd">{#searchreplace_dlg.down}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input id="search_panel_casesensitivebox" name="search_panel_casesensitivebox" class="checkbox" type="checkbox" /></td>
+ <td><label for="search_panel_casesensitivebox">{#searchreplace_dlg.mcase}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </div>
+
+ <div id="replace_panel" class="panel">
+ <table role="presentation" border="0" cellspacing="0" cellpadding="2">
+ <tr>
+ <td><label for="replace_panel_searchstring">{#searchreplace_dlg.findwhat}</label></td>
+ <td><input type="text" id="replace_panel_searchstring" name="replace_panel_searchstring" style="width: 200px" aria-required="true" /></td>
+ </tr>
+ <tr>
+ <td><label for="replace_panel_replacestring">{#searchreplace_dlg.replacewith}</label></td>
+ <td><input type="text" id="replace_panel_replacestring" name="replace_panel_replacestring" style="width: 200px" aria-required="true" /></td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0" class="direction">
+ <tr role="group" aria-labelledby="replace_panel_dir_label">
+ <td><label id="replace_panel_dir_label">{#searchreplace_dlg.direction}</label></td>
+ <td><input id="replace_panel_backwardsu" name="replace_panel_backwards" class="radio" type="radio" /></td>
+ <td><label for="replace_panel_backwardsu">{#searchreplace_dlg.up}</label></td>
+ <td><input id="replace_panel_backwardsd" name="replace_panel_backwards" class="radio" type="radio" checked="checked" /></td>
+ <td><label for="replace_panel_backwardsd">{#searchreplace_dlg.down}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input id="replace_panel_casesensitivebox" name="replace_panel_casesensitivebox" class="checkbox" type="checkbox" /></td>
+ <td><label for="replace_panel_casesensitivebox">{#searchreplace_dlg.mcase}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </div>
+
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#searchreplace_dlg.findnext}" />
+ <input type="button" class="button" id="replaceBtn" name="replaceBtn" value="{#searchreplace_dlg.replace}" onclick="SearchReplaceDialog.searchNext('current');" />
+ <input type="button" class="button" id="replaceAllBtn" name="replaceAllBtn" value="{#searchreplace_dlg.replaceall}" onclick="SearchReplaceDialog.searchNext('all');" />
+ <input type="button" id="cancel" name="close" value="{#close}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/spellchecker/css/content.css b/askbot/media/js/tinymce/plugins/spellchecker/css/content.css
new file mode 100644
index 00000000..24efa021
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/spellchecker/css/content.css
@@ -0,0 +1 @@
+.mceItemHiddenSpellWord {background:url(../img/wline.gif) repeat-x bottom left; cursor:default;}
diff --git a/askbot/media/js/tinymce/plugins/spellchecker/editor_plugin.js b/askbot/media/js/tinymce/plugins/spellchecker/editor_plugin.js
new file mode 100644
index 00000000..48549c92
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/spellchecker/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var a=tinymce.util.JSONRequest,c=tinymce.each,b=tinymce.DOM;tinymce.create("tinymce.plugins.SpellcheckerPlugin",{getInfo:function(){return{longname:"Spellchecker",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker",version:tinymce.majorVersion+"."+tinymce.minorVersion}},init:function(e,f){var g=this,d;g.url=f;g.editor=e;g.rpcUrl=e.getParam("spellchecker_rpc_url","{backend}");if(g.rpcUrl=="{backend}"){if(tinymce.isIE){return}g.hasSupport=true;e.onContextMenu.addToTop(function(h,i){if(g.active){return false}})}e.addCommand("mceSpellCheck",function(){if(g.rpcUrl=="{backend}"){g.editor.getBody().spellcheck=g.active=!g.active;return}if(!g.active){e.setProgressState(1);g._sendRPC("checkWords",[g.selectedLang,g._getWords()],function(h){if(h.length>0){g.active=1;g._markWords(h);e.setProgressState(0);e.nodeChanged()}else{e.setProgressState(0);if(e.getParam("spellchecker_report_no_misspellings",true)){e.windowManager.alert("spellchecker.no_mpell")}}})}else{g._done()}});if(e.settings.content_css!==false){e.contentCSS.push(f+"/css/content.css")}e.onClick.add(g._showMenu,g);e.onContextMenu.add(g._showMenu,g);e.onBeforeGetContent.add(function(){if(g.active){g._removeWords()}});e.onNodeChange.add(function(i,h){h.setActive("spellchecker",g.active)});e.onSetContent.add(function(){g._done()});e.onBeforeGetContent.add(function(){g._done()});e.onBeforeExecCommand.add(function(h,i){if(i=="mceFullScreen"){g._done()}});g.languages={};c(e.getParam("spellchecker_languages","+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv","hash"),function(i,h){if(h.indexOf("+")===0){h=h.substring(1);g.selectedLang=i}g.languages[h]=i})},createControl:function(h,d){var f=this,g,e=f.editor;if(h=="spellchecker"){if(f.rpcUrl=="{backend}"){if(f.hasSupport){g=d.createButton(h,{title:"spellchecker.desc",cmd:"mceSpellCheck",scope:f})}return g}g=d.createSplitButton(h,{title:"spellchecker.desc",cmd:"mceSpellCheck",scope:f});g.onRenderMenu.add(function(j,i){i.add({title:"spellchecker.langs","class":"mceMenuItemTitle"}).setDisabled(1);c(f.languages,function(n,m){var p={icon:1},l;p.onclick=function(){if(n==f.selectedLang){return}l.setSelected(1);f.selectedItem.setSelected(0);f.selectedItem=l;f.selectedLang=n};p.title=m;l=i.add(p);l.setSelected(n==f.selectedLang);if(n==f.selectedLang){f.selectedItem=l}})});return g}},_walk:function(i,g){var h=this.editor.getDoc(),e;if(h.createTreeWalker){e=h.createTreeWalker(i,NodeFilter.SHOW_TEXT,null,false);while((i=e.nextNode())!=null){g.call(this,i)}}else{tinymce.walk(i,g,"childNodes")}},_getSeparators:function(){var e="",d,f=this.editor.getParam("spellchecker_word_separator_chars",'\\s!"#$%&()*+,-./:;<=>?@[]^_{|}§©«®±¶·¸»¼½¾¿×÷¤\u201d\u201c');for(d=0;d<f.length;d++){e+="\\"+f.charAt(d)}return e},_getWords:function(){var e=this.editor,g=[],d="",f={},h=[];this._walk(e.getBody(),function(i){if(i.nodeType==3){d+=i.nodeValue+" "}});if(e.getParam("spellchecker_word_pattern")){h=d.match("("+e.getParam("spellchecker_word_pattern")+")","gi")}else{d=d.replace(new RegExp("([0-9]|["+this._getSeparators()+"])","g")," ");d=tinymce.trim(d.replace(/(\s+)/g," "));h=d.split(" ")}c(h,function(i){if(!f[i]){g.push(i);f[i]=1}});return g},_removeWords:function(d){var e=this.editor,h=e.dom,g=e.selection,f=g.getRng(true);c(h.select("span").reverse(),function(i){if(i&&(h.hasClass(i,"mceItemHiddenSpellWord")||h.hasClass(i,"mceItemHidden"))){if(!d||h.decode(i.innerHTML)==d){h.remove(i,1)}}});g.setRng(f)},_markWords:function(l){var h=this.editor,g=h.dom,j=h.getDoc(),i=h.selection,d=i.getRng(true),e=[],k=l.join("|"),m=this._getSeparators(),f=new RegExp("(^|["+m+"])("+k+")(?=["+m+"]|$)","g");this._walk(h.getBody(),function(o){if(o.nodeType==3){e.push(o)}});c(e,function(t){var r,q,o,s,p=t.nodeValue;if(f.test(p)){p=g.encode(p);q=g.create("span",{"class":"mceItemHidden"});if(tinymce.isIE){p=p.replace(f,"$1<mcespell>$2</mcespell>");while((s=p.indexOf("<mcespell>"))!=-1){o=p.substring(0,s);if(o.length){r=j.createTextNode(g.decode(o));q.appendChild(r)}p=p.substring(s+10);s=p.indexOf("</mcespell>");o=p.substring(0,s);p=p.substring(s+11);q.appendChild(g.create("span",{"class":"mceItemHiddenSpellWord"},o))}if(p.length){r=j.createTextNode(g.decode(p));q.appendChild(r)}}else{q.innerHTML=p.replace(f,'$1<span class="mceItemHiddenSpellWord">$2</span>')}g.replace(q,t)}});i.setRng(d)},_showMenu:function(h,j){var i=this,h=i.editor,d=i._menu,l,k=h.dom,g=k.getViewPort(h.getWin()),f=j.target;j=0;if(!d){d=h.controlManager.createDropMenu("spellcheckermenu",{"class":"mceNoIcons"});i._menu=d}if(k.hasClass(f,"mceItemHiddenSpellWord")){d.removeAll();d.add({title:"spellchecker.wait","class":"mceMenuItemTitle"}).setDisabled(1);i._sendRPC("getSuggestions",[i.selectedLang,k.decode(f.innerHTML)],function(m){var e;d.removeAll();if(m.length>0){d.add({title:"spellchecker.sug","class":"mceMenuItemTitle"}).setDisabled(1);c(m,function(n){d.add({title:n,onclick:function(){k.replace(h.getDoc().createTextNode(n),f);i._checkDone()}})});d.addSeparator()}else{d.add({title:"spellchecker.no_sug","class":"mceMenuItemTitle"}).setDisabled(1)}if(h.getParam("show_ignore_words",true)){e=i.editor.getParam("spellchecker_enable_ignore_rpc","");d.add({title:"spellchecker.ignore_word",onclick:function(){var n=f.innerHTML;k.remove(f,1);i._checkDone();if(e){h.setProgressState(1);i._sendRPC("ignoreWord",[i.selectedLang,n],function(o){h.setProgressState(0)})}}});d.add({title:"spellchecker.ignore_words",onclick:function(){var n=f.innerHTML;i._removeWords(k.decode(n));i._checkDone();if(e){h.setProgressState(1);i._sendRPC("ignoreWords",[i.selectedLang,n],function(o){h.setProgressState(0)})}}})}if(i.editor.getParam("spellchecker_enable_learn_rpc")){d.add({title:"spellchecker.learn_word",onclick:function(){var n=f.innerHTML;k.remove(f,1);i._checkDone();h.setProgressState(1);i._sendRPC("learnWord",[i.selectedLang,n],function(o){h.setProgressState(0)})}})}d.update()});l=b.getPos(h.getContentAreaContainer());d.settings.offset_x=l.x;d.settings.offset_y=l.y;h.selection.select(f);l=k.getPos(f);d.showMenu(l.x,l.y+f.offsetHeight-g.y);return tinymce.dom.Event.cancel(j)}else{d.hideMenu()}},_checkDone:function(){var e=this,d=e.editor,g=d.dom,f;c(g.select("span"),function(h){if(h&&g.hasClass(h,"mceItemHiddenSpellWord")){f=true;return false}});if(!f){e._done()}},_done:function(){var d=this,e=d.active;if(d.active){d.active=0;d._removeWords();if(d._menu){d._menu.hideMenu()}if(e){d.editor.nodeChanged()}}},_sendRPC:function(e,g,d){var f=this;a.sendRPC({url:f.rpcUrl,method:e,params:g,success:d,error:function(i,h){f.editor.setProgressState(0);f.editor.windowManager.alert(i.errstr||("Error response: "+h.responseText))}})}});tinymce.PluginManager.add("spellchecker",tinymce.plugins.SpellcheckerPlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/spellchecker/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/spellchecker/editor_plugin_src.js
new file mode 100644
index 00000000..86fdfceb
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/spellchecker/editor_plugin_src.js
@@ -0,0 +1,436 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var JSONRequest = tinymce.util.JSONRequest, each = tinymce.each, DOM = tinymce.DOM;
+
+ tinymce.create('tinymce.plugins.SpellcheckerPlugin', {
+ getInfo : function() {
+ return {
+ longname : 'Spellchecker',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/spellchecker',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ init : function(ed, url) {
+ var t = this, cm;
+
+ t.url = url;
+ t.editor = ed;
+ t.rpcUrl = ed.getParam("spellchecker_rpc_url", "{backend}");
+
+ if (t.rpcUrl == '{backend}') {
+ // Sniff if the browser supports native spellchecking (Don't know of a better way)
+ if (tinymce.isIE)
+ return;
+
+ t.hasSupport = true;
+
+ // Disable the context menu when spellchecking is active
+ ed.onContextMenu.addToTop(function(ed, e) {
+ if (t.active)
+ return false;
+ });
+ }
+
+ // Register commands
+ ed.addCommand('mceSpellCheck', function() {
+ if (t.rpcUrl == '{backend}') {
+ // Enable/disable native spellchecker
+ t.editor.getBody().spellcheck = t.active = !t.active;
+ return;
+ }
+
+ if (!t.active) {
+ ed.setProgressState(1);
+ t._sendRPC('checkWords', [t.selectedLang, t._getWords()], function(r) {
+ if (r.length > 0) {
+ t.active = 1;
+ t._markWords(r);
+ ed.setProgressState(0);
+ ed.nodeChanged();
+ } else {
+ ed.setProgressState(0);
+
+ if (ed.getParam('spellchecker_report_no_misspellings', true))
+ ed.windowManager.alert('spellchecker.no_mpell');
+ }
+ });
+ } else
+ t._done();
+ });
+
+ if (ed.settings.content_css !== false)
+ ed.contentCSS.push(url + '/css/content.css');
+
+ ed.onClick.add(t._showMenu, t);
+ ed.onContextMenu.add(t._showMenu, t);
+ ed.onBeforeGetContent.add(function() {
+ if (t.active)
+ t._removeWords();
+ });
+
+ ed.onNodeChange.add(function(ed, cm) {
+ cm.setActive('spellchecker', t.active);
+ });
+
+ ed.onSetContent.add(function() {
+ t._done();
+ });
+
+ ed.onBeforeGetContent.add(function() {
+ t._done();
+ });
+
+ ed.onBeforeExecCommand.add(function(ed, cmd) {
+ if (cmd == 'mceFullScreen')
+ t._done();
+ });
+
+ // Find selected language
+ t.languages = {};
+ each(ed.getParam('spellchecker_languages', '+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,Portuguese=pt,Spanish=es,Swedish=sv', 'hash'), function(v, k) {
+ if (k.indexOf('+') === 0) {
+ k = k.substring(1);
+ t.selectedLang = v;
+ }
+
+ t.languages[k] = v;
+ });
+ },
+
+ createControl : function(n, cm) {
+ var t = this, c, ed = t.editor;
+
+ if (n == 'spellchecker') {
+ // Use basic button if we use the native spellchecker
+ if (t.rpcUrl == '{backend}') {
+ // Create simple toggle button if we have native support
+ if (t.hasSupport)
+ c = cm.createButton(n, {title : 'spellchecker.desc', cmd : 'mceSpellCheck', scope : t});
+
+ return c;
+ }
+
+ c = cm.createSplitButton(n, {title : 'spellchecker.desc', cmd : 'mceSpellCheck', scope : t});
+
+ c.onRenderMenu.add(function(c, m) {
+ m.add({title : 'spellchecker.langs', 'class' : 'mceMenuItemTitle'}).setDisabled(1);
+ each(t.languages, function(v, k) {
+ var o = {icon : 1}, mi;
+
+ o.onclick = function() {
+ if (v == t.selectedLang) {
+ return;
+ }
+ mi.setSelected(1);
+ t.selectedItem.setSelected(0);
+ t.selectedItem = mi;
+ t.selectedLang = v;
+ };
+
+ o.title = k;
+ mi = m.add(o);
+ mi.setSelected(v == t.selectedLang);
+
+ if (v == t.selectedLang)
+ t.selectedItem = mi;
+ })
+ });
+
+ return c;
+ }
+ },
+
+ // Internal functions
+
+ _walk : function(n, f) {
+ var d = this.editor.getDoc(), w;
+
+ if (d.createTreeWalker) {
+ w = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);
+
+ while ((n = w.nextNode()) != null)
+ f.call(this, n);
+ } else
+ tinymce.walk(n, f, 'childNodes');
+ },
+
+ _getSeparators : function() {
+ var re = '', i, str = this.editor.getParam('spellchecker_word_separator_chars', '\\s!"#$%&()*+,-./:;<=>?@[\]^_{|}§©«®±¶·¸»¼½¾¿×÷¤\u201d\u201c');
+
+ // Build word separator regexp
+ for (i=0; i<str.length; i++)
+ re += '\\' + str.charAt(i);
+
+ return re;
+ },
+
+ _getWords : function() {
+ var ed = this.editor, wl = [], tx = '', lo = {}, rawWords = [];
+
+ // Get area text
+ this._walk(ed.getBody(), function(n) {
+ if (n.nodeType == 3)
+ tx += n.nodeValue + ' ';
+ });
+
+ // split the text up into individual words
+ if (ed.getParam('spellchecker_word_pattern')) {
+ // look for words that match the pattern
+ rawWords = tx.match('(' + ed.getParam('spellchecker_word_pattern') + ')', 'gi');
+ } else {
+ // Split words by separator
+ tx = tx.replace(new RegExp('([0-9]|[' + this._getSeparators() + '])', 'g'), ' ');
+ tx = tinymce.trim(tx.replace(/(\s+)/g, ' '));
+ rawWords = tx.split(' ');
+ }
+
+ // Build word array and remove duplicates
+ each(rawWords, function(v) {
+ if (!lo[v]) {
+ wl.push(v);
+ lo[v] = 1;
+ }
+ });
+
+ return wl;
+ },
+
+ _removeWords : function(w) {
+ var ed = this.editor, dom = ed.dom, se = ed.selection, r = se.getRng(true);
+
+ each(dom.select('span').reverse(), function(n) {
+ if (n && (dom.hasClass(n, 'mceItemHiddenSpellWord') || dom.hasClass(n, 'mceItemHidden'))) {
+ if (!w || dom.decode(n.innerHTML) == w)
+ dom.remove(n, 1);
+ }
+ });
+
+ se.setRng(r);
+ },
+
+ _markWords : function(wl) {
+ var ed = this.editor, dom = ed.dom, doc = ed.getDoc(), se = ed.selection, r = se.getRng(true), nl = [],
+ w = wl.join('|'), re = this._getSeparators(), rx = new RegExp('(^|[' + re + '])(' + w + ')(?=[' + re + ']|$)', 'g');
+
+ // Collect all text nodes
+ this._walk(ed.getBody(), function(n) {
+ if (n.nodeType == 3) {
+ nl.push(n);
+ }
+ });
+
+ // Wrap incorrect words in spans
+ each(nl, function(n) {
+ var node, elem, txt, pos, v = n.nodeValue;
+
+ if (rx.test(v)) {
+ // Encode the content
+ v = dom.encode(v);
+ // Create container element
+ elem = dom.create('span', {'class' : 'mceItemHidden'});
+
+ // Following code fixes IE issues by creating text nodes
+ // using DOM methods instead of innerHTML.
+ // Bug #3124: <PRE> elements content is broken after spellchecking.
+ // Bug #1408: Preceding whitespace characters are removed
+ // @TODO: I'm not sure that both are still issues on IE9.
+ if (tinymce.isIE) {
+ // Enclose mispelled words with temporal tag
+ v = v.replace(rx, '$1<mcespell>$2</mcespell>');
+ // Loop over the content finding mispelled words
+ while ((pos = v.indexOf('<mcespell>')) != -1) {
+ // Add text node for the content before the word
+ txt = v.substring(0, pos);
+ if (txt.length) {
+ node = doc.createTextNode(dom.decode(txt));
+ elem.appendChild(node);
+ }
+ v = v.substring(pos+10);
+ pos = v.indexOf('</mcespell>');
+ txt = v.substring(0, pos);
+ v = v.substring(pos+11);
+ // Add span element for the word
+ elem.appendChild(dom.create('span', {'class' : 'mceItemHiddenSpellWord'}, txt));
+ }
+ // Add text node for the rest of the content
+ if (v.length) {
+ node = doc.createTextNode(dom.decode(v));
+ elem.appendChild(node);
+ }
+ } else {
+ // Other browsers preserve whitespace characters on innerHTML usage
+ elem.innerHTML = v.replace(rx, '$1<span class="mceItemHiddenSpellWord">$2</span>');
+ }
+
+ // Finally, replace the node with the container
+ dom.replace(elem, n);
+ }
+ });
+
+ se.setRng(r);
+ },
+
+ _showMenu : function(ed, e) {
+ var t = this, ed = t.editor, m = t._menu, p1, dom = ed.dom, vp = dom.getViewPort(ed.getWin()), wordSpan = e.target;
+
+ e = 0; // Fixes IE memory leak
+
+ if (!m) {
+ m = ed.controlManager.createDropMenu('spellcheckermenu', {'class' : 'mceNoIcons'});
+ t._menu = m;
+ }
+
+ if (dom.hasClass(wordSpan, 'mceItemHiddenSpellWord')) {
+ m.removeAll();
+ m.add({title : 'spellchecker.wait', 'class' : 'mceMenuItemTitle'}).setDisabled(1);
+
+ t._sendRPC('getSuggestions', [t.selectedLang, dom.decode(wordSpan.innerHTML)], function(r) {
+ var ignoreRpc;
+
+ m.removeAll();
+
+ if (r.length > 0) {
+ m.add({title : 'spellchecker.sug', 'class' : 'mceMenuItemTitle'}).setDisabled(1);
+ each(r, function(v) {
+ m.add({title : v, onclick : function() {
+ dom.replace(ed.getDoc().createTextNode(v), wordSpan);
+ t._checkDone();
+ }});
+ });
+
+ m.addSeparator();
+ } else
+ m.add({title : 'spellchecker.no_sug', 'class' : 'mceMenuItemTitle'}).setDisabled(1);
+
+ if (ed.getParam('show_ignore_words', true)) {
+ ignoreRpc = t.editor.getParam("spellchecker_enable_ignore_rpc", '');
+ m.add({
+ title : 'spellchecker.ignore_word',
+ onclick : function() {
+ var word = wordSpan.innerHTML;
+
+ dom.remove(wordSpan, 1);
+ t._checkDone();
+
+ // tell the server if we need to
+ if (ignoreRpc) {
+ ed.setProgressState(1);
+ t._sendRPC('ignoreWord', [t.selectedLang, word], function(r) {
+ ed.setProgressState(0);
+ });
+ }
+ }
+ });
+
+ m.add({
+ title : 'spellchecker.ignore_words',
+ onclick : function() {
+ var word = wordSpan.innerHTML;
+
+ t._removeWords(dom.decode(word));
+ t._checkDone();
+
+ // tell the server if we need to
+ if (ignoreRpc) {
+ ed.setProgressState(1);
+ t._sendRPC('ignoreWords', [t.selectedLang, word], function(r) {
+ ed.setProgressState(0);
+ });
+ }
+ }
+ });
+ }
+
+ if (t.editor.getParam("spellchecker_enable_learn_rpc")) {
+ m.add({
+ title : 'spellchecker.learn_word',
+ onclick : function() {
+ var word = wordSpan.innerHTML;
+
+ dom.remove(wordSpan, 1);
+ t._checkDone();
+
+ ed.setProgressState(1);
+ t._sendRPC('learnWord', [t.selectedLang, word], function(r) {
+ ed.setProgressState(0);
+ });
+ }
+ });
+ }
+
+ m.update();
+ });
+
+ p1 = DOM.getPos(ed.getContentAreaContainer());
+ m.settings.offset_x = p1.x;
+ m.settings.offset_y = p1.y;
+
+ ed.selection.select(wordSpan);
+ p1 = dom.getPos(wordSpan);
+ m.showMenu(p1.x, p1.y + wordSpan.offsetHeight - vp.y);
+
+ return tinymce.dom.Event.cancel(e);
+ } else
+ m.hideMenu();
+ },
+
+ _checkDone : function() {
+ var t = this, ed = t.editor, dom = ed.dom, o;
+
+ each(dom.select('span'), function(n) {
+ if (n && dom.hasClass(n, 'mceItemHiddenSpellWord')) {
+ o = true;
+ return false;
+ }
+ });
+
+ if (!o)
+ t._done();
+ },
+
+ _done : function() {
+ var t = this, la = t.active;
+
+ if (t.active) {
+ t.active = 0;
+ t._removeWords();
+
+ if (t._menu)
+ t._menu.hideMenu();
+
+ if (la)
+ t.editor.nodeChanged();
+ }
+ },
+
+ _sendRPC : function(m, p, cb) {
+ var t = this;
+
+ JSONRequest.sendRPC({
+ url : t.rpcUrl,
+ method : m,
+ params : p,
+ success : cb,
+ error : function(e, x) {
+ t.editor.setProgressState(0);
+ t.editor.windowManager.alert(e.errstr || ('Error response: ' + x.responseText));
+ }
+ });
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('spellchecker', tinymce.plugins.SpellcheckerPlugin);
+})();
diff --git a/askbot/media/js/tinymce/plugins/spellchecker/img/wline.gif b/askbot/media/js/tinymce/plugins/spellchecker/img/wline.gif
new file mode 100644
index 00000000..7d0a4dbc
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/spellchecker/img/wline.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/plugins/style/css/props.css b/askbot/media/js/tinymce/plugins/style/css/props.css
new file mode 100644
index 00000000..3b8f0ee7
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/style/css/props.css
@@ -0,0 +1,14 @@
+#text_font {width:250px;}
+#text_size {width:70px;}
+.mceAddSelectValue {background:#DDD;}
+select, #block_text_indent, #box_width, #box_height, #box_padding_top, #box_padding_right, #box_padding_bottom, #box_padding_left {width:70px;}
+#box_margin_top, #box_margin_right, #box_margin_bottom, #box_margin_left, #positioning_width, #positioning_height, #positioning_zindex {width:70px;}
+#positioning_placement_top, #positioning_placement_right, #positioning_placement_bottom, #positioning_placement_left {width:70px;}
+#positioning_clip_top, #positioning_clip_right, #positioning_clip_bottom, #positioning_clip_left {width:70px;}
+.panel_toggle_insert_span {padding-top:10px;}
+.panel_wrapper div.current {padding-top:10px;height:230px;}
+.delim {border-left:1px solid gray;}
+.tdelim {border-bottom:1px solid gray;}
+#block_display {width:145px;}
+#list_type {width:115px;}
+.disabled {background:#EEE;}
diff --git a/askbot/media/js/tinymce/plugins/style/editor_plugin.js b/askbot/media/js/tinymce/plugins/style/editor_plugin.js
new file mode 100644
index 00000000..dda9f928
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/style/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.StylePlugin",{init:function(a,b){a.addCommand("mceStyleProps",function(){var c=false;var f=a.selection.getSelectedBlocks();var d=[];if(f.length===1){d.push(a.selection.getNode().style.cssText)}else{tinymce.each(f,function(g){d.push(a.dom.getAttrib(g,"style"))});c=true}a.windowManager.open({file:b+"/props.htm",width:480+parseInt(a.getLang("style.delta_width",0)),height:340+parseInt(a.getLang("style.delta_height",0)),inline:1},{applyStyleToBlocks:c,plugin_url:b,styles:d})});a.addCommand("mceSetElementStyle",function(d,c){if(e=a.selection.getNode()){a.dom.setAttrib(e,"style",c);a.execCommand("mceRepaint")}});a.onNodeChange.add(function(d,c,f){c.setDisabled("styleprops",f.nodeName==="BODY")});a.addButton("styleprops",{title:"style.desc",cmd:"mceStyleProps"})},getInfo:function(){return{longname:"Style",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/style",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("style",tinymce.plugins.StylePlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/style/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/style/editor_plugin_src.js
new file mode 100644
index 00000000..eaa7c771
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/style/editor_plugin_src.js
@@ -0,0 +1,71 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.StylePlugin', {
+ init : function(ed, url) {
+ // Register commands
+ ed.addCommand('mceStyleProps', function() {
+
+ var applyStyleToBlocks = false;
+ var blocks = ed.selection.getSelectedBlocks();
+ var styles = [];
+
+ if (blocks.length === 1) {
+ styles.push(ed.selection.getNode().style.cssText);
+ }
+ else {
+ tinymce.each(blocks, function(block) {
+ styles.push(ed.dom.getAttrib(block, 'style'));
+ });
+ applyStyleToBlocks = true;
+ }
+
+ ed.windowManager.open({
+ file : url + '/props.htm',
+ width : 480 + parseInt(ed.getLang('style.delta_width', 0)),
+ height : 340 + parseInt(ed.getLang('style.delta_height', 0)),
+ inline : 1
+ }, {
+ applyStyleToBlocks : applyStyleToBlocks,
+ plugin_url : url,
+ styles : styles
+ });
+ });
+
+ ed.addCommand('mceSetElementStyle', function(ui, v) {
+ if (e = ed.selection.getNode()) {
+ ed.dom.setAttrib(e, 'style', v);
+ ed.execCommand('mceRepaint');
+ }
+ });
+
+ ed.onNodeChange.add(function(ed, cm, n) {
+ cm.setDisabled('styleprops', n.nodeName === 'BODY');
+ });
+
+ // Register buttons
+ ed.addButton('styleprops', {title : 'style.desc', cmd : 'mceStyleProps'});
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Style',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/style',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('style', tinymce.plugins.StylePlugin);
+})();
diff --git a/askbot/media/js/tinymce/plugins/style/js/props.js b/askbot/media/js/tinymce/plugins/style/js/props.js
new file mode 100644
index 00000000..0a8a8ec3
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/style/js/props.js
@@ -0,0 +1,709 @@
+tinyMCEPopup.requireLangPack();
+
+var defaultFonts = "" +
+ "Arial, Helvetica, sans-serif=Arial, Helvetica, sans-serif;" +
+ "Times New Roman, Times, serif=Times New Roman, Times, serif;" +
+ "Courier New, Courier, mono=Courier New, Courier, mono;" +
+ "Times New Roman, Times, serif=Times New Roman, Times, serif;" +
+ "Georgia, Times New Roman, Times, serif=Georgia, Times New Roman, Times, serif;" +
+ "Verdana, Arial, Helvetica, sans-serif=Verdana, Arial, Helvetica, sans-serif;" +
+ "Geneva, Arial, Helvetica, sans-serif=Geneva, Arial, Helvetica, sans-serif";
+
+var defaultSizes = "9;10;12;14;16;18;24;xx-small;x-small;small;medium;large;x-large;xx-large;smaller;larger";
+var defaultMeasurement = "+pixels=px;points=pt;inches=in;centimetres=cm;millimetres=mm;picas=pc;ems=em;exs=ex;%";
+var defaultSpacingMeasurement = "pixels=px;points=pt;inches=in;centimetres=cm;millimetres=mm;picas=pc;+ems=em;exs=ex;%";
+var defaultIndentMeasurement = "pixels=px;+points=pt;inches=in;centimetres=cm;millimetres=mm;picas=pc;ems=em;exs=ex;%";
+var defaultWeight = "normal;bold;bolder;lighter;100;200;300;400;500;600;700;800;900";
+var defaultTextStyle = "normal;italic;oblique";
+var defaultVariant = "normal;small-caps";
+var defaultLineHeight = "normal";
+var defaultAttachment = "fixed;scroll";
+var defaultRepeat = "no-repeat;repeat;repeat-x;repeat-y";
+var defaultPosH = "left;center;right";
+var defaultPosV = "top;center;bottom";
+var defaultVAlign = "baseline;sub;super;top;text-top;middle;bottom;text-bottom";
+var defaultDisplay = "inline;block;list-item;run-in;compact;marker;table;inline-table;table-row-group;table-header-group;table-footer-group;table-row;table-column-group;table-column;table-cell;table-caption;none";
+var defaultBorderStyle = "none;solid;dashed;dotted;double;groove;ridge;inset;outset";
+var defaultBorderWidth = "thin;medium;thick";
+var defaultListType = "disc;circle;square;decimal;lower-roman;upper-roman;lower-alpha;upper-alpha;none";
+
+function aggregateStyles(allStyles) {
+ var mergedStyles = {};
+
+ tinymce.each(allStyles, function(style) {
+ if (style !== '') {
+ var parsedStyles = tinyMCEPopup.editor.dom.parseStyle(style);
+ for (var name in parsedStyles) {
+ if (parsedStyles.hasOwnProperty(name)) {
+ if (mergedStyles[name] === undefined) {
+ mergedStyles[name] = parsedStyles[name];
+ }
+ else if (name === 'text-decoration') {
+ if (mergedStyles[name].indexOf(parsedStyles[name]) === -1) {
+ mergedStyles[name] = mergedStyles[name] +' '+ parsedStyles[name];
+ }
+ }
+ }
+ }
+ }
+ });
+
+ return mergedStyles;
+}
+
+var applyActionIsInsert;
+var existingStyles;
+
+function init(ed) {
+ var ce = document.getElementById('container'), h;
+
+ existingStyles = aggregateStyles(tinyMCEPopup.getWindowArg('styles'));
+ ce.style.cssText = tinyMCEPopup.editor.dom.serializeStyle(existingStyles);
+
+ applyActionIsInsert = ed.getParam("edit_css_style_insert_span", false);
+ document.getElementById('toggle_insert_span').checked = applyActionIsInsert;
+
+ h = getBrowserHTML('background_image_browser','background_image','image','advimage');
+ document.getElementById("background_image_browser").innerHTML = h;
+
+ document.getElementById('text_color_pickcontainer').innerHTML = getColorPickerHTML('text_color_pick','text_color');
+ document.getElementById('background_color_pickcontainer').innerHTML = getColorPickerHTML('background_color_pick','background_color');
+ document.getElementById('border_color_top_pickcontainer').innerHTML = getColorPickerHTML('border_color_top_pick','border_color_top');
+ document.getElementById('border_color_right_pickcontainer').innerHTML = getColorPickerHTML('border_color_right_pick','border_color_right');
+ document.getElementById('border_color_bottom_pickcontainer').innerHTML = getColorPickerHTML('border_color_bottom_pick','border_color_bottom');
+ document.getElementById('border_color_left_pickcontainer').innerHTML = getColorPickerHTML('border_color_left_pick','border_color_left');
+
+ fillSelect(0, 'text_font', 'style_font', defaultFonts, ';', true);
+ fillSelect(0, 'text_size', 'style_font_size', defaultSizes, ';', true);
+ fillSelect(0, 'text_size_measurement', 'style_font_size_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'text_case', 'style_text_case', "capitalize;uppercase;lowercase", ';', true);
+ fillSelect(0, 'text_weight', 'style_font_weight', defaultWeight, ';', true);
+ fillSelect(0, 'text_style', 'style_font_style', defaultTextStyle, ';', true);
+ fillSelect(0, 'text_variant', 'style_font_variant', defaultVariant, ';', true);
+ fillSelect(0, 'text_lineheight', 'style_font_line_height', defaultLineHeight, ';', true);
+ fillSelect(0, 'text_lineheight_measurement', 'style_font_line_height_measurement', defaultMeasurement, ';', true);
+
+ fillSelect(0, 'background_attachment', 'style_background_attachment', defaultAttachment, ';', true);
+ fillSelect(0, 'background_repeat', 'style_background_repeat', defaultRepeat, ';', true);
+
+ fillSelect(0, 'background_hpos_measurement', 'style_background_hpos_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'background_vpos_measurement', 'style_background_vpos_measurement', defaultMeasurement, ';', true);
+
+ fillSelect(0, 'background_hpos', 'style_background_hpos', defaultPosH, ';', true);
+ fillSelect(0, 'background_vpos', 'style_background_vpos', defaultPosV, ';', true);
+
+ fillSelect(0, 'block_wordspacing', 'style_wordspacing', 'normal', ';', true);
+ fillSelect(0, 'block_wordspacing_measurement', 'style_wordspacing_measurement', defaultSpacingMeasurement, ';', true);
+ fillSelect(0, 'block_letterspacing', 'style_letterspacing', 'normal', ';', true);
+ fillSelect(0, 'block_letterspacing_measurement', 'style_letterspacing_measurement', defaultSpacingMeasurement, ';', true);
+ fillSelect(0, 'block_vertical_alignment', 'style_vertical_alignment', defaultVAlign, ';', true);
+ fillSelect(0, 'block_text_align', 'style_text_align', "left;right;center;justify", ';', true);
+ fillSelect(0, 'block_whitespace', 'style_whitespace', "normal;pre;nowrap", ';', true);
+ fillSelect(0, 'block_display', 'style_display', defaultDisplay, ';', true);
+ fillSelect(0, 'block_text_indent_measurement', 'style_text_indent_measurement', defaultIndentMeasurement, ';', true);
+
+ fillSelect(0, 'box_width_measurement', 'style_box_width_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'box_height_measurement', 'style_box_height_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'box_float', 'style_float', 'left;right;none', ';', true);
+ fillSelect(0, 'box_clear', 'style_clear', 'left;right;both;none', ';', true);
+ fillSelect(0, 'box_padding_left_measurement', 'style_padding_left_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'box_padding_top_measurement', 'style_padding_top_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'box_padding_bottom_measurement', 'style_padding_bottom_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'box_padding_right_measurement', 'style_padding_right_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'box_margin_left_measurement', 'style_margin_left_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'box_margin_top_measurement', 'style_margin_top_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'box_margin_bottom_measurement', 'style_margin_bottom_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'box_margin_right_measurement', 'style_margin_right_measurement', defaultMeasurement, ';', true);
+
+ fillSelect(0, 'border_style_top', 'style_border_style_top', defaultBorderStyle, ';', true);
+ fillSelect(0, 'border_style_right', 'style_border_style_right', defaultBorderStyle, ';', true);
+ fillSelect(0, 'border_style_bottom', 'style_border_style_bottom', defaultBorderStyle, ';', true);
+ fillSelect(0, 'border_style_left', 'style_border_style_left', defaultBorderStyle, ';', true);
+
+ fillSelect(0, 'border_width_top', 'style_border_width_top', defaultBorderWidth, ';', true);
+ fillSelect(0, 'border_width_right', 'style_border_width_right', defaultBorderWidth, ';', true);
+ fillSelect(0, 'border_width_bottom', 'style_border_width_bottom', defaultBorderWidth, ';', true);
+ fillSelect(0, 'border_width_left', 'style_border_width_left', defaultBorderWidth, ';', true);
+
+ fillSelect(0, 'border_width_top_measurement', 'style_border_width_top_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'border_width_right_measurement', 'style_border_width_right_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'border_width_bottom_measurement', 'style_border_width_bottom_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'border_width_left_measurement', 'style_border_width_left_measurement', defaultMeasurement, ';', true);
+
+ fillSelect(0, 'list_type', 'style_list_type', defaultListType, ';', true);
+ fillSelect(0, 'list_position', 'style_list_position', "inside;outside", ';', true);
+
+ fillSelect(0, 'positioning_type', 'style_positioning_type', "absolute;relative;static", ';', true);
+ fillSelect(0, 'positioning_visibility', 'style_positioning_visibility', "inherit;visible;hidden", ';', true);
+
+ fillSelect(0, 'positioning_width_measurement', 'style_positioning_width_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'positioning_height_measurement', 'style_positioning_height_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'positioning_overflow', 'style_positioning_overflow', "visible;hidden;scroll;auto", ';', true);
+
+ fillSelect(0, 'positioning_placement_top_measurement', 'style_positioning_placement_top_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'positioning_placement_right_measurement', 'style_positioning_placement_right_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'positioning_placement_bottom_measurement', 'style_positioning_placement_bottom_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'positioning_placement_left_measurement', 'style_positioning_placement_left_measurement', defaultMeasurement, ';', true);
+
+ fillSelect(0, 'positioning_clip_top_measurement', 'style_positioning_clip_top_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'positioning_clip_right_measurement', 'style_positioning_clip_right_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'positioning_clip_bottom_measurement', 'style_positioning_clip_bottom_measurement', defaultMeasurement, ';', true);
+ fillSelect(0, 'positioning_clip_left_measurement', 'style_positioning_clip_left_measurement', defaultMeasurement, ';', true);
+
+ TinyMCE_EditableSelects.init();
+ setupFormData();
+ showDisabledControls();
+}
+
+function setupFormData() {
+ var ce = document.getElementById('container'), f = document.forms[0], s, b, i;
+
+ // Setup text fields
+
+ selectByValue(f, 'text_font', ce.style.fontFamily, true, true);
+ selectByValue(f, 'text_size', getNum(ce.style.fontSize), true, true);
+ selectByValue(f, 'text_size_measurement', getMeasurement(ce.style.fontSize));
+ selectByValue(f, 'text_weight', ce.style.fontWeight, true, true);
+ selectByValue(f, 'text_style', ce.style.fontStyle, true, true);
+ selectByValue(f, 'text_lineheight', getNum(ce.style.lineHeight), true, true);
+ selectByValue(f, 'text_lineheight_measurement', getMeasurement(ce.style.lineHeight));
+ selectByValue(f, 'text_case', ce.style.textTransform, true, true);
+ selectByValue(f, 'text_variant', ce.style.fontVariant, true, true);
+ f.text_color.value = tinyMCEPopup.editor.dom.toHex(ce.style.color);
+ updateColor('text_color_pick', 'text_color');
+ f.text_underline.checked = inStr(ce.style.textDecoration, 'underline');
+ f.text_overline.checked = inStr(ce.style.textDecoration, 'overline');
+ f.text_linethrough.checked = inStr(ce.style.textDecoration, 'line-through');
+ f.text_blink.checked = inStr(ce.style.textDecoration, 'blink');
+ f.text_none.checked = inStr(ce.style.textDecoration, 'none');
+ updateTextDecorations();
+
+ // Setup background fields
+
+ f.background_color.value = tinyMCEPopup.editor.dom.toHex(ce.style.backgroundColor);
+ updateColor('background_color_pick', 'background_color');
+ f.background_image.value = ce.style.backgroundImage.replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
+ selectByValue(f, 'background_repeat', ce.style.backgroundRepeat, true, true);
+ selectByValue(f, 'background_attachment', ce.style.backgroundAttachment, true, true);
+ selectByValue(f, 'background_hpos', getNum(getVal(ce.style.backgroundPosition, 0)), true, true);
+ selectByValue(f, 'background_hpos_measurement', getMeasurement(getVal(ce.style.backgroundPosition, 0)));
+ selectByValue(f, 'background_vpos', getNum(getVal(ce.style.backgroundPosition, 1)), true, true);
+ selectByValue(f, 'background_vpos_measurement', getMeasurement(getVal(ce.style.backgroundPosition, 1)));
+
+ // Setup block fields
+
+ selectByValue(f, 'block_wordspacing', getNum(ce.style.wordSpacing), true, true);
+ selectByValue(f, 'block_wordspacing_measurement', getMeasurement(ce.style.wordSpacing));
+ selectByValue(f, 'block_letterspacing', getNum(ce.style.letterSpacing), true, true);
+ selectByValue(f, 'block_letterspacing_measurement', getMeasurement(ce.style.letterSpacing));
+ selectByValue(f, 'block_vertical_alignment', ce.style.verticalAlign, true, true);
+ selectByValue(f, 'block_text_align', ce.style.textAlign, true, true);
+ f.block_text_indent.value = getNum(ce.style.textIndent);
+ selectByValue(f, 'block_text_indent_measurement', getMeasurement(ce.style.textIndent));
+ selectByValue(f, 'block_whitespace', ce.style.whiteSpace, true, true);
+ selectByValue(f, 'block_display', ce.style.display, true, true);
+
+ // Setup box fields
+
+ f.box_width.value = getNum(ce.style.width);
+ selectByValue(f, 'box_width_measurement', getMeasurement(ce.style.width));
+
+ f.box_height.value = getNum(ce.style.height);
+ selectByValue(f, 'box_height_measurement', getMeasurement(ce.style.height));
+ selectByValue(f, 'box_float', ce.style.cssFloat || ce.style.styleFloat, true, true);
+
+ selectByValue(f, 'box_clear', ce.style.clear, true, true);
+
+ setupBox(f, ce, 'box_padding', 'padding', '');
+ setupBox(f, ce, 'box_margin', 'margin', '');
+
+ // Setup border fields
+
+ setupBox(f, ce, 'border_style', 'border', 'Style');
+ setupBox(f, ce, 'border_width', 'border', 'Width');
+ setupBox(f, ce, 'border_color', 'border', 'Color');
+
+ updateColor('border_color_top_pick', 'border_color_top');
+ updateColor('border_color_right_pick', 'border_color_right');
+ updateColor('border_color_bottom_pick', 'border_color_bottom');
+ updateColor('border_color_left_pick', 'border_color_left');
+
+ f.elements.border_color_top.value = tinyMCEPopup.editor.dom.toHex(f.elements.border_color_top.value);
+ f.elements.border_color_right.value = tinyMCEPopup.editor.dom.toHex(f.elements.border_color_right.value);
+ f.elements.border_color_bottom.value = tinyMCEPopup.editor.dom.toHex(f.elements.border_color_bottom.value);
+ f.elements.border_color_left.value = tinyMCEPopup.editor.dom.toHex(f.elements.border_color_left.value);
+
+ // Setup list fields
+
+ selectByValue(f, 'list_type', ce.style.listStyleType, true, true);
+ selectByValue(f, 'list_position', ce.style.listStylePosition, true, true);
+ f.list_bullet_image.value = ce.style.listStyleImage.replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
+
+ // Setup box fields
+
+ selectByValue(f, 'positioning_type', ce.style.position, true, true);
+ selectByValue(f, 'positioning_visibility', ce.style.visibility, true, true);
+ selectByValue(f, 'positioning_overflow', ce.style.overflow, true, true);
+ f.positioning_zindex.value = ce.style.zIndex ? ce.style.zIndex : "";
+
+ f.positioning_width.value = getNum(ce.style.width);
+ selectByValue(f, 'positioning_width_measurement', getMeasurement(ce.style.width));
+
+ f.positioning_height.value = getNum(ce.style.height);
+ selectByValue(f, 'positioning_height_measurement', getMeasurement(ce.style.height));
+
+ setupBox(f, ce, 'positioning_placement', '', '', ['top', 'right', 'bottom', 'left']);
+
+ s = ce.style.clip.replace(new RegExp("rect\\('?([^']*)'?\\)", 'gi'), "$1");
+ s = s.replace(/,/g, ' ');
+
+ if (!hasEqualValues([getVal(s, 0), getVal(s, 1), getVal(s, 2), getVal(s, 3)])) {
+ f.positioning_clip_top.value = getNum(getVal(s, 0));
+ selectByValue(f, 'positioning_clip_top_measurement', getMeasurement(getVal(s, 0)));
+ f.positioning_clip_right.value = getNum(getVal(s, 1));
+ selectByValue(f, 'positioning_clip_right_measurement', getMeasurement(getVal(s, 1)));
+ f.positioning_clip_bottom.value = getNum(getVal(s, 2));
+ selectByValue(f, 'positioning_clip_bottom_measurement', getMeasurement(getVal(s, 2)));
+ f.positioning_clip_left.value = getNum(getVal(s, 3));
+ selectByValue(f, 'positioning_clip_left_measurement', getMeasurement(getVal(s, 3)));
+ } else {
+ f.positioning_clip_top.value = getNum(getVal(s, 0));
+ selectByValue(f, 'positioning_clip_top_measurement', getMeasurement(getVal(s, 0)));
+ f.positioning_clip_right.value = f.positioning_clip_bottom.value = f.positioning_clip_left.value;
+ }
+
+// setupBox(f, ce, '', 'border', 'Color');
+}
+
+function getMeasurement(s) {
+ return s.replace(/^([0-9.]+)(.*)$/, "$2");
+}
+
+function getNum(s) {
+ if (new RegExp('^(?:[0-9.]+)(?:[a-z%]+)$', 'gi').test(s))
+ return s.replace(/[^0-9.]/g, '');
+
+ return s;
+}
+
+function inStr(s, n) {
+ return new RegExp(n, 'gi').test(s);
+}
+
+function getVal(s, i) {
+ var a = s.split(' ');
+
+ if (a.length > 1)
+ return a[i];
+
+ return "";
+}
+
+function setValue(f, n, v) {
+ if (f.elements[n].type == "text")
+ f.elements[n].value = v;
+ else
+ selectByValue(f, n, v, true, true);
+}
+
+function setupBox(f, ce, fp, pr, sf, b) {
+ if (typeof(b) == "undefined")
+ b = ['Top', 'Right', 'Bottom', 'Left'];
+
+ if (isSame(ce, pr, sf, b)) {
+ f.elements[fp + "_same"].checked = true;
+
+ setValue(f, fp + "_top", getNum(ce.style[pr + b[0] + sf]));
+ f.elements[fp + "_top"].disabled = false;
+
+ f.elements[fp + "_right"].value = "";
+ f.elements[fp + "_right"].disabled = true;
+ f.elements[fp + "_bottom"].value = "";
+ f.elements[fp + "_bottom"].disabled = true;
+ f.elements[fp + "_left"].value = "";
+ f.elements[fp + "_left"].disabled = true;
+
+ if (f.elements[fp + "_top_measurement"]) {
+ selectByValue(f, fp + '_top_measurement', getMeasurement(ce.style[pr + b[0] + sf]));
+ f.elements[fp + "_left_measurement"].disabled = true;
+ f.elements[fp + "_bottom_measurement"].disabled = true;
+ f.elements[fp + "_right_measurement"].disabled = true;
+ }
+ } else {
+ f.elements[fp + "_same"].checked = false;
+
+ setValue(f, fp + "_top", getNum(ce.style[pr + b[0] + sf]));
+ f.elements[fp + "_top"].disabled = false;
+
+ setValue(f, fp + "_right", getNum(ce.style[pr + b[1] + sf]));
+ f.elements[fp + "_right"].disabled = false;
+
+ setValue(f, fp + "_bottom", getNum(ce.style[pr + b[2] + sf]));
+ f.elements[fp + "_bottom"].disabled = false;
+
+ setValue(f, fp + "_left", getNum(ce.style[pr + b[3] + sf]));
+ f.elements[fp + "_left"].disabled = false;
+
+ if (f.elements[fp + "_top_measurement"]) {
+ selectByValue(f, fp + '_top_measurement', getMeasurement(ce.style[pr + b[0] + sf]));
+ selectByValue(f, fp + '_right_measurement', getMeasurement(ce.style[pr + b[1] + sf]));
+ selectByValue(f, fp + '_bottom_measurement', getMeasurement(ce.style[pr + b[2] + sf]));
+ selectByValue(f, fp + '_left_measurement', getMeasurement(ce.style[pr + b[3] + sf]));
+ f.elements[fp + "_left_measurement"].disabled = false;
+ f.elements[fp + "_bottom_measurement"].disabled = false;
+ f.elements[fp + "_right_measurement"].disabled = false;
+ }
+ }
+}
+
+function isSame(e, pr, sf, b) {
+ var a = [], i, x;
+
+ if (typeof(b) == "undefined")
+ b = ['Top', 'Right', 'Bottom', 'Left'];
+
+ if (typeof(sf) == "undefined" || sf == null)
+ sf = "";
+
+ a[0] = e.style[pr + b[0] + sf];
+ a[1] = e.style[pr + b[1] + sf];
+ a[2] = e.style[pr + b[2] + sf];
+ a[3] = e.style[pr + b[3] + sf];
+
+ for (i=0; i<a.length; i++) {
+ if (a[i] == null)
+ return false;
+
+ for (x=0; x<a.length; x++) {
+ if (a[x] != a[i])
+ return false;
+ }
+ }
+
+ return true;
+};
+
+function hasEqualValues(a) {
+ var i, x;
+
+ for (i=0; i<a.length; i++) {
+ if (a[i] == null)
+ return false;
+
+ for (x=0; x<a.length; x++) {
+ if (a[x] != a[i])
+ return false;
+ }
+ }
+
+ return true;
+}
+
+function toggleApplyAction() {
+ applyActionIsInsert = ! applyActionIsInsert;
+}
+
+function applyAction() {
+ var ce = document.getElementById('container'), ed = tinyMCEPopup.editor;
+
+ generateCSS();
+
+ tinyMCEPopup.restoreSelection();
+
+ var newStyles = tinyMCEPopup.editor.dom.parseStyle(ce.style.cssText);
+
+ if (applyActionIsInsert) {
+ ed.formatter.register('plugin_style', {
+ inline: 'span', styles: existingStyles
+ });
+ ed.formatter.remove('plugin_style');
+
+ ed.formatter.register('plugin_style', {
+ inline: 'span', styles: newStyles
+ });
+ ed.formatter.apply('plugin_style');
+ } else {
+ var nodes;
+
+ if (tinyMCEPopup.getWindowArg('applyStyleToBlocks')) {
+ nodes = ed.selection.getSelectedBlocks();
+ }
+ else {
+ nodes = ed.selection.getNode();
+ }
+
+ ed.dom.setAttrib(nodes, 'style', tinyMCEPopup.editor.dom.serializeStyle(newStyles));
+ }
+}
+
+function updateAction() {
+ applyAction();
+ tinyMCEPopup.close();
+}
+
+function generateCSS() {
+ var ce = document.getElementById('container'), f = document.forms[0], num = new RegExp('[0-9]+', 'g'), s, t;
+
+ ce.style.cssText = "";
+
+ // Build text styles
+ ce.style.fontFamily = f.text_font.value;
+ ce.style.fontSize = f.text_size.value + (isNum(f.text_size.value) ? (f.text_size_measurement.value || 'px') : "");
+ ce.style.fontStyle = f.text_style.value;
+ ce.style.lineHeight = f.text_lineheight.value + (isNum(f.text_lineheight.value) ? f.text_lineheight_measurement.value : "");
+ ce.style.textTransform = f.text_case.value;
+ ce.style.fontWeight = f.text_weight.value;
+ ce.style.fontVariant = f.text_variant.value;
+ ce.style.color = f.text_color.value;
+
+ s = "";
+ s += f.text_underline.checked ? " underline" : "";
+ s += f.text_overline.checked ? " overline" : "";
+ s += f.text_linethrough.checked ? " line-through" : "";
+ s += f.text_blink.checked ? " blink" : "";
+ s = s.length > 0 ? s.substring(1) : s;
+
+ if (f.text_none.checked)
+ s = "none";
+
+ ce.style.textDecoration = s;
+
+ // Build background styles
+
+ ce.style.backgroundColor = f.background_color.value;
+ ce.style.backgroundImage = f.background_image.value != "" ? "url(" + f.background_image.value + ")" : "";
+ ce.style.backgroundRepeat = f.background_repeat.value;
+ ce.style.backgroundAttachment = f.background_attachment.value;
+
+ if (f.background_hpos.value != "") {
+ s = "";
+ s += f.background_hpos.value + (isNum(f.background_hpos.value) ? f.background_hpos_measurement.value : "") + " ";
+ s += f.background_vpos.value + (isNum(f.background_vpos.value) ? f.background_vpos_measurement.value : "");
+ ce.style.backgroundPosition = s;
+ }
+
+ // Build block styles
+
+ ce.style.wordSpacing = f.block_wordspacing.value + (isNum(f.block_wordspacing.value) ? f.block_wordspacing_measurement.value : "");
+ ce.style.letterSpacing = f.block_letterspacing.value + (isNum(f.block_letterspacing.value) ? f.block_letterspacing_measurement.value : "");
+ ce.style.verticalAlign = f.block_vertical_alignment.value;
+ ce.style.textAlign = f.block_text_align.value;
+ ce.style.textIndent = f.block_text_indent.value + (isNum(f.block_text_indent.value) ? f.block_text_indent_measurement.value : "");
+ ce.style.whiteSpace = f.block_whitespace.value;
+ ce.style.display = f.block_display.value;
+
+ // Build box styles
+
+ ce.style.width = f.box_width.value + (isNum(f.box_width.value) ? f.box_width_measurement.value : "");
+ ce.style.height = f.box_height.value + (isNum(f.box_height.value) ? f.box_height_measurement.value : "");
+ ce.style.styleFloat = f.box_float.value;
+ ce.style.cssFloat = f.box_float.value;
+
+ ce.style.clear = f.box_clear.value;
+
+ if (!f.box_padding_same.checked) {
+ ce.style.paddingTop = f.box_padding_top.value + (isNum(f.box_padding_top.value) ? f.box_padding_top_measurement.value : "");
+ ce.style.paddingRight = f.box_padding_right.value + (isNum(f.box_padding_right.value) ? f.box_padding_right_measurement.value : "");
+ ce.style.paddingBottom = f.box_padding_bottom.value + (isNum(f.box_padding_bottom.value) ? f.box_padding_bottom_measurement.value : "");
+ ce.style.paddingLeft = f.box_padding_left.value + (isNum(f.box_padding_left.value) ? f.box_padding_left_measurement.value : "");
+ } else
+ ce.style.padding = f.box_padding_top.value + (isNum(f.box_padding_top.value) ? f.box_padding_top_measurement.value : "");
+
+ if (!f.box_margin_same.checked) {
+ ce.style.marginTop = f.box_margin_top.value + (isNum(f.box_margin_top.value) ? f.box_margin_top_measurement.value : "");
+ ce.style.marginRight = f.box_margin_right.value + (isNum(f.box_margin_right.value) ? f.box_margin_right_measurement.value : "");
+ ce.style.marginBottom = f.box_margin_bottom.value + (isNum(f.box_margin_bottom.value) ? f.box_margin_bottom_measurement.value : "");
+ ce.style.marginLeft = f.box_margin_left.value + (isNum(f.box_margin_left.value) ? f.box_margin_left_measurement.value : "");
+ } else
+ ce.style.margin = f.box_margin_top.value + (isNum(f.box_margin_top.value) ? f.box_margin_top_measurement.value : "");
+
+ // Build border styles
+
+ if (!f.border_style_same.checked) {
+ ce.style.borderTopStyle = f.border_style_top.value;
+ ce.style.borderRightStyle = f.border_style_right.value;
+ ce.style.borderBottomStyle = f.border_style_bottom.value;
+ ce.style.borderLeftStyle = f.border_style_left.value;
+ } else
+ ce.style.borderStyle = f.border_style_top.value;
+
+ if (!f.border_width_same.checked) {
+ ce.style.borderTopWidth = f.border_width_top.value + (isNum(f.border_width_top.value) ? f.border_width_top_measurement.value : "");
+ ce.style.borderRightWidth = f.border_width_right.value + (isNum(f.border_width_right.value) ? f.border_width_right_measurement.value : "");
+ ce.style.borderBottomWidth = f.border_width_bottom.value + (isNum(f.border_width_bottom.value) ? f.border_width_bottom_measurement.value : "");
+ ce.style.borderLeftWidth = f.border_width_left.value + (isNum(f.border_width_left.value) ? f.border_width_left_measurement.value : "");
+ } else
+ ce.style.borderWidth = f.border_width_top.value + (isNum(f.border_width_top.value) ? f.border_width_top_measurement.value : "");
+
+ if (!f.border_color_same.checked) {
+ ce.style.borderTopColor = f.border_color_top.value;
+ ce.style.borderRightColor = f.border_color_right.value;
+ ce.style.borderBottomColor = f.border_color_bottom.value;
+ ce.style.borderLeftColor = f.border_color_left.value;
+ } else
+ ce.style.borderColor = f.border_color_top.value;
+
+ // Build list styles
+
+ ce.style.listStyleType = f.list_type.value;
+ ce.style.listStylePosition = f.list_position.value;
+ ce.style.listStyleImage = f.list_bullet_image.value != "" ? "url(" + f.list_bullet_image.value + ")" : "";
+
+ // Build positioning styles
+
+ ce.style.position = f.positioning_type.value;
+ ce.style.visibility = f.positioning_visibility.value;
+
+ if (ce.style.width == "")
+ ce.style.width = f.positioning_width.value + (isNum(f.positioning_width.value) ? f.positioning_width_measurement.value : "");
+
+ if (ce.style.height == "")
+ ce.style.height = f.positioning_height.value + (isNum(f.positioning_height.value) ? f.positioning_height_measurement.value : "");
+
+ ce.style.zIndex = f.positioning_zindex.value;
+ ce.style.overflow = f.positioning_overflow.value;
+
+ if (!f.positioning_placement_same.checked) {
+ ce.style.top = f.positioning_placement_top.value + (isNum(f.positioning_placement_top.value) ? f.positioning_placement_top_measurement.value : "");
+ ce.style.right = f.positioning_placement_right.value + (isNum(f.positioning_placement_right.value) ? f.positioning_placement_right_measurement.value : "");
+ ce.style.bottom = f.positioning_placement_bottom.value + (isNum(f.positioning_placement_bottom.value) ? f.positioning_placement_bottom_measurement.value : "");
+ ce.style.left = f.positioning_placement_left.value + (isNum(f.positioning_placement_left.value) ? f.positioning_placement_left_measurement.value : "");
+ } else {
+ s = f.positioning_placement_top.value + (isNum(f.positioning_placement_top.value) ? f.positioning_placement_top_measurement.value : "");
+ ce.style.top = s;
+ ce.style.right = s;
+ ce.style.bottom = s;
+ ce.style.left = s;
+ }
+
+ if (!f.positioning_clip_same.checked) {
+ s = "rect(";
+ s += (isNum(f.positioning_clip_top.value) ? f.positioning_clip_top.value + f.positioning_clip_top_measurement.value : "auto") + " ";
+ s += (isNum(f.positioning_clip_right.value) ? f.positioning_clip_right.value + f.positioning_clip_right_measurement.value : "auto") + " ";
+ s += (isNum(f.positioning_clip_bottom.value) ? f.positioning_clip_bottom.value + f.positioning_clip_bottom_measurement.value : "auto") + " ";
+ s += (isNum(f.positioning_clip_left.value) ? f.positioning_clip_left.value + f.positioning_clip_left_measurement.value : "auto");
+ s += ")";
+
+ if (s != "rect(auto auto auto auto)")
+ ce.style.clip = s;
+ } else {
+ s = "rect(";
+ t = isNum(f.positioning_clip_top.value) ? f.positioning_clip_top.value + f.positioning_clip_top_measurement.value : "auto";
+ s += t + " ";
+ s += t + " ";
+ s += t + " ";
+ s += t + ")";
+
+ if (s != "rect(auto auto auto auto)")
+ ce.style.clip = s;
+ }
+
+ ce.style.cssText = ce.style.cssText;
+}
+
+function isNum(s) {
+ return new RegExp('[0-9]+', 'g').test(s);
+}
+
+function showDisabledControls() {
+ var f = document.forms, i, a;
+
+ for (i=0; i<f.length; i++) {
+ for (a=0; a<f[i].elements.length; a++) {
+ if (f[i].elements[a].disabled)
+ tinyMCEPopup.editor.dom.addClass(f[i].elements[a], "disabled");
+ else
+ tinyMCEPopup.editor.dom.removeClass(f[i].elements[a], "disabled");
+ }
+ }
+}
+
+function fillSelect(f, s, param, dval, sep, em) {
+ var i, ar, p, se;
+
+ f = document.forms[f];
+ sep = typeof(sep) == "undefined" ? ";" : sep;
+
+ if (em)
+ addSelectValue(f, s, "", "");
+
+ ar = tinyMCEPopup.getParam(param, dval).split(sep);
+ for (i=0; i<ar.length; i++) {
+ se = false;
+
+ if (ar[i].charAt(0) == '+') {
+ ar[i] = ar[i].substring(1);
+ se = true;
+ }
+
+ p = ar[i].split('=');
+
+ if (p.length > 1) {
+ addSelectValue(f, s, p[0], p[1]);
+
+ if (se)
+ selectByValue(f, s, p[1]);
+ } else {
+ addSelectValue(f, s, p[0], p[0]);
+
+ if (se)
+ selectByValue(f, s, p[0]);
+ }
+ }
+}
+
+function toggleSame(ce, pre) {
+ var el = document.forms[0].elements, i;
+
+ if (ce.checked) {
+ el[pre + "_top"].disabled = false;
+ el[pre + "_right"].disabled = true;
+ el[pre + "_bottom"].disabled = true;
+ el[pre + "_left"].disabled = true;
+
+ if (el[pre + "_top_measurement"]) {
+ el[pre + "_top_measurement"].disabled = false;
+ el[pre + "_right_measurement"].disabled = true;
+ el[pre + "_bottom_measurement"].disabled = true;
+ el[pre + "_left_measurement"].disabled = true;
+ }
+ } else {
+ el[pre + "_top"].disabled = false;
+ el[pre + "_right"].disabled = false;
+ el[pre + "_bottom"].disabled = false;
+ el[pre + "_left"].disabled = false;
+
+ if (el[pre + "_top_measurement"]) {
+ el[pre + "_top_measurement"].disabled = false;
+ el[pre + "_right_measurement"].disabled = false;
+ el[pre + "_bottom_measurement"].disabled = false;
+ el[pre + "_left_measurement"].disabled = false;
+ }
+ }
+
+ showDisabledControls();
+}
+
+function synch(fr, to) {
+ var f = document.forms[0];
+
+ f.elements[to].value = f.elements[fr].value;
+
+ if (f.elements[fr + "_measurement"])
+ selectByValue(f, to + "_measurement", f.elements[fr + "_measurement"].value);
+}
+
+function updateTextDecorations(){
+ var el = document.forms[0].elements;
+
+ var textDecorations = ["text_underline", "text_overline", "text_linethrough", "text_blink"];
+ var noneChecked = el["text_none"].checked;
+ tinymce.each(textDecorations, function(id) {
+ el[id].disabled = noneChecked;
+ if (noneChecked) {
+ el[id].checked = false;
+ }
+ });
+}
+
+tinyMCEPopup.onInit.add(init);
diff --git a/askbot/media/js/tinymce/plugins/style/langs/en_dlg.js b/askbot/media/js/tinymce/plugins/style/langs/en_dlg.js
new file mode 100644
index 00000000..35881b3a
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/style/langs/en_dlg.js
@@ -0,0 +1 @@
+tinyMCE.addI18n('en.style_dlg',{"text_lineheight":"Line Height","text_variant":"Variant","text_style":"Style","text_weight":"Weight","text_size":"Size","text_font":"Font","text_props":"Text","positioning_tab":"Positioning","list_tab":"List","border_tab":"Border","box_tab":"Box","block_tab":"Block","background_tab":"Background","text_tab":"Text",apply:"Apply",toggle_insert_span:"Insert span at selection",title:"Edit CSS Style",clip:"Clip",placement:"Placement",overflow:"Overflow",zindex:"Z-index",visibility:"Visibility","positioning_type":"Type",position:"Position","bullet_image":"Bullet Image","list_type":"Type",color:"Color",height:"Height",width:"Width",style:"Style",margin:"Margin",left:"Left",bottom:"Bottom",right:"Right",top:"Top",same:"Same for All",padding:"Padding","box_clear":"Clear","box_float":"Float","box_height":"Height","box_width":"Width","block_display":"Display","block_whitespace":"Whitespace","block_text_indent":"Text Indent","block_text_align":"Text Align","block_vertical_alignment":"Vertical Alignment","block_letterspacing":"Letter Spacing","block_wordspacing":"Word Spacing","background_vpos":"Vertical Position","background_hpos":"Horizontal Position","background_attachment":"Attachment","background_repeat":"Repeat","background_image":"Background Image","background_color":"Background Color","text_none":"None","text_blink":"Blink","text_case":"Case","text_striketrough":"Strikethrough","text_underline":"Underline","text_overline":"Overline","text_decoration":"Decoration","text_color":"Color",text:"Text",background:"Background",block:"Block",box:"Box",border:"Border",list:"List"});
diff --git a/askbot/media/js/tinymce/plugins/style/props.htm b/askbot/media/js/tinymce/plugins/style/props.htm
new file mode 100644
index 00000000..7dc087a3
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/style/props.htm
@@ -0,0 +1,845 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#style_dlg.title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/editable_selects.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="js/props.js"></script>
+ <link href="css/props.css" rel="stylesheet" type="text/css" />
+</head>
+
+<body id="styleprops" style="display: none" role="application" aria-labelledby="app_title">
+<span id="app_title" style="display:none">{#style_dlg.title}</span>
+<form onsubmit="updateAction();return false;" action="#">
+<div class="tabs">
+ <ul>
+ <li id="text_tab" class="current" aria-controls="text_panel"><span><a href="javascript:mcTabs.displayTab('text_tab','text_panel');" onMouseDown="return false;">{#style_dlg.text_tab}</a></span></li>
+ <li id="background_tab" aria-controls="background_panel"><span><a href="javascript:mcTabs.displayTab('background_tab','background_panel');" onMouseDown="return false;">{#style_dlg.background_tab}</a></span></li>
+ <li id="block_tab" aria-controls="block_panel"><span><a href="javascript:mcTabs.displayTab('block_tab','block_panel');" onMouseDown="return false;">{#style_dlg.block_tab}</a></span></li>
+ <li id="box_tab" aria-controls="box_panel"><span><a href="javascript:mcTabs.displayTab('box_tab','box_panel');" onMouseDown="return false;">{#style_dlg.box_tab}</a></span></li>
+ <li id="border_tab" aria-controls="border_panel"><span><a href="javascript:mcTabs.displayTab('border_tab','border_panel');" onMouseDown="return false;">{#style_dlg.border_tab}</a></span></li>
+ <li id="list_tab" aria-controls="list_panel"><span><a href="javascript:mcTabs.displayTab('list_tab','list_panel');" onMouseDown="return false;">{#style_dlg.list_tab}</a></span></li>
+ <li id="positioning_tab" aria-controls="positioning_panel"><span><a href="javascript:mcTabs.displayTab('positioning_tab','positioning_panel');" onMouseDown="return false;">{#style_dlg.positioning_tab}</a></span></li>
+ </ul>
+</div>
+
+<div class="panel_wrapper">
+<div id="text_panel" class="panel current">
+ <fieldset>
+ <legend>{#style_dlg.text}</legend>
+ <table role="presentation" border="0" width="100%">
+ <tr>
+ <td><label for="text_font">{#style_dlg.text_font}</label></td>
+ <td colspan="3">
+ <select id="text_font" name="text_font" class="mceEditableSelect mceFocus"></select>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="text_size">{#style_dlg.text_size}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><select id="text_size" name="text_size" class="mceEditableSelect"></select></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="text_size_measurement_label" for="text_size_measurement" style="display: none; visibility: hidden;">Text Size Measurement Unit</label>
+ <select id="text_size_measurement" name="text_size_measurement" aria-labelledby="text_size_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td><label for="text_weight">{#style_dlg.text_weight}</label></td>
+ <td>
+ <select id="text_weight" name="text_weight"></select>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="text_style">{#style_dlg.text_style}</label></td>
+ <td>
+ <select id="text_style" name="text_style" class="mceEditableSelect"></select>
+ </td>
+ <td><label for="text_variant">{#style_dlg.text_variant}</label></td>
+ <td>
+ <select id="text_variant" name="text_variant"></select>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="text_lineheight">{#style_dlg.text_lineheight}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td>
+ <select id="text_lineheight" name="text_lineheight" class="mceEditableSelect"></select>
+ </td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="text_lineheight_measurement_label" for="text_lineheight_measurement" style="display: none; visibility: hidden;">Line Height Measurement Unit</label>
+ <select id="text_lineheight_measurement" name="text_lineheight_measurement" aria-labelledby="text_lineheight_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td><label for="text_case">{#style_dlg.text_case}</label></td>
+ <td>
+ <select id="text_case" name="text_case"></select>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="text_color">{#style_dlg.text_color}</label></td>
+ <td colspan="2">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="text_color" name="text_color" type="text" value="" size="9" onChange="updateColor('text_color_pick','text_color');" /></td>
+ <td id="text_color_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" style="vertical-align: top; padding-top: 3px;">{#style_dlg.text_decoration}</td>
+ <td colspan="2">
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input id="text_underline" name="text_underline" class="checkbox" type="checkbox" /></td>
+ <td><label for="text_underline">{#style_dlg.text_underline}</label></td>
+ </tr>
+ <tr>
+ <td><input id="text_overline" name="text_overline" class="checkbox" type="checkbox" /></td>
+ <td><label for="text_overline">{#style_dlg.text_overline}</label></td>
+ </tr>
+ <tr>
+ <td><input id="text_linethrough" name="text_linethrough" class="checkbox" type="checkbox" /></td>
+ <td><label for="text_linethrough">{#style_dlg.text_striketrough}</label></td>
+ </tr>
+ <tr>
+ <td><input id="text_blink" name="text_blink" class="checkbox" type="checkbox" /></td>
+ <td><label for="text_blink">{#style_dlg.text_blink}</label></td>
+ </tr>
+ <tr>
+ <td><input id="text_none" name="text_none" class="checkbox" type="checkbox" onclick="updateTextDecorations();"/></td>
+ <td><label for="text_none">{#style_dlg.text_none}</label></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+</div>
+
+<div id="background_panel" class="panel">
+ <fieldset>
+ <legend>{#style_dlg.background}</legend>
+ <table role="presentation" border="0">
+ <tr>
+ <td><label for="background_color">{#style_dlg.background_color}</label></td>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="background_color" name="background_color" type="text" value="" size="9" onChange="updateColor('background_color_pick','background_color');" /></td>
+ <td id="background_color_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="background_image">{#style_dlg.background_image}</label></td>
+ <td><table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input id="background_image" name="background_image" type="text" /></td>
+ <td id="background_image_browser">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="background_repeat">{#style_dlg.background_repeat}</label></td>
+ <td><select id="background_repeat" name="background_repeat" class="mceEditableSelect"></select></td>
+ </tr>
+
+ <tr>
+ <td><label for="background_attachment">{#style_dlg.background_attachment}</label></td>
+ <td><select id="background_attachment" name="background_attachment" class="mceEditableSelect"></select></td>
+ </tr>
+
+ <tr>
+ <td><label for="background_hpos">{#style_dlg.background_hpos}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><select id="background_hpos" name="background_hpos" class="mceEditableSelect"></select></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="background_hpos_measurement_label" for="background_hpos_measurement" style="display: none; visibility: hidden;">Horizontal position measurement unit</label>
+ <select id="background_hpos_measurement" name="background_hpos_measurement" aria-labelledby="background_hpos_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="background_vpos">{#style_dlg.background_vpos}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><select id="background_vpos" name="background_vpos" class="mceEditableSelect"></select></td>
+ <td>&nbsp;</td>
+ <td>
+
+ <label id="background_vpos_measurement_label" for="background_vpos_measurement" style="display: none; visibility: hidden;">Vertical position measurement unit</label>
+ <select id="background_vpos_measurement" name="background_vpos_measurement" aria-labelledby="background_vpos_measurement_label">></select></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+</div>
+
+<div id="block_panel" class="panel">
+ <fieldset>
+ <legend>{#style_dlg.block}</legend>
+ <table role="presentation" border="0">
+ <tr>
+ <td><label for="block_wordspacing">{#style_dlg.block_wordspacing}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><select id="block_wordspacing" name="block_wordspacing" class="mceEditableSelect"></select></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="block_wordspacing_measurement_label" for="block_wordspacing_measurement" style="display: none; visibility: hidden;">Word spacing measurement unit</label>
+ <select id="block_wordspacing_measurement" name="block_wordspacing_measurement" aria-labelledby="block_wordspacing_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="block_letterspacing">{#style_dlg.block_letterspacing}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><select id="block_letterspacing" name="block_letterspacing" class="mceEditableSelect"></select></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="block_letterspacing_measurement_label" for="block_letterspacing_measurement" style="display: none; visibility: hidden;">Letter spacing measurement unit</label>
+ <select id="block_letterspacing_measurement" name="block_letterspacing_measurement" aria-labelledby="block_letterspacing_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="block_vertical_alignment">{#style_dlg.block_vertical_alignment}</label></td>
+ <td><select id="block_vertical_alignment" name="block_vertical_alignment" class="mceEditableSelect"></select></td>
+ </tr>
+
+ <tr>
+ <td><label for="block_text_align">{#style_dlg.block_text_align}</label></td>
+ <td><select id="block_text_align" name="block_text_align" class="mceEditableSelect"></select></td>
+ </tr>
+
+ <tr>
+ <td><label for="block_text_indent">{#style_dlg.block_text_indent}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="block_text_indent" name="block_text_indent" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="block_text_indent_measurement_label" for="block_text_indent_measurement" style="display: none; visibility: hidden;">Text Indent Measurement Unit</label>
+
+ <select id="block_text_indent_measurement" name="block_text_indent_measurement" aria-labelledby="block_text_indent_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="block_whitespace">{#style_dlg.block_whitespace}</label></td>
+ <td><select id="block_whitespace" name="block_whitespace" class="mceEditableSelect"></select></td>
+ </tr>
+
+ <tr>
+ <td><label for="block_display">{#style_dlg.block_display}</label></td>
+ <td><select id="block_display" name="block_display" class="mceEditableSelect"></select></td>
+ </tr>
+ </table>
+ </fieldset>
+</div>
+
+<div id="box_panel" class="panel">
+ <fieldset>
+ <legend>{#style_dlg.box}</legend>
+ <table role="presentation" border="0">
+ <tr>
+ <td><label for="box_width">{#style_dlg.box_width}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="box_width" name="box_width" class="mceEditableSelect" onChange="synch('box_width','positioning_width');" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="box_width_measurement_label" for="box_width_measurement" style="display: none; visibility: hidden;">Box Width Measurement Unit</label>
+ <select id="box_width_measurement" name="box_width_measurement" aria-labelledby="box_width_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td>&nbsp;&nbsp;&nbsp;<label for="box_float">{#style_dlg.box_float}</label></td>
+ <td><select id="box_float" name="box_float" class="mceEditableSelect"></select></td>
+ </tr>
+
+ <tr>
+ <td><label for="box_height">{#style_dlg.box_height}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="box_height" name="box_height" class="mceEditableSelect" onChange="synch('box_height','positioning_height');" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="box_height_measurement_label" for="box_height_measurement" style="display: none; visibility: hidden;">Box Height Measurement Unit</label>
+ <select id="box_height_measurement" name="box_height_measurement" aria-labelledby="box_height_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td>&nbsp;&nbsp;&nbsp;<label for="box_clear">{#style_dlg.box_clear}</label></td>
+ <td><select id="box_clear" name="box_clear" class="mceEditableSelect"></select></td>
+ </tr>
+ </table>
+ </fieldset>
+
+<div style="float: left; width: 49%">
+ <fieldset>
+ <legend>{#style_dlg.padding}</legend>
+
+ <table role="presentation" border="0">
+ <tr>
+ <td>&nbsp;</td>
+ <td><input type="checkbox" id="box_padding_same" name="box_padding_same" class="checkbox" checked="checked" onClick="toggleSame(this,'box_padding');" /> <label for="box_padding_same">{#style_dlg.same}</label></td>
+ </tr>
+ <tr>
+ <td><label for="box_padding_top">{#style_dlg.top}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="box_padding_top" name="box_padding_top" class="mceEditableSelect" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="box_padding_top_measurement_label" for="box_padding_top_measurement" style="display: none; visibility: hidden;">Padding Top Measurement Unit</label>
+ <select id="box_padding_top_measurement" name="box_padding_top_measurement" aria-labelledby="box_padding_top_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="box_padding_right">{#style_dlg.right}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="box_padding_right" name="box_padding_right" class="mceEditableSelect" disabled="disabled" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="box_padding_right_measurement_label" for="box_padding_right_measurement" style="display: none; visibility: hidden;">Padding Right Measurement Unit</label>
+ <select id="box_padding_right_measurement" name="box_padding_right_measurement" disabled="disabled" aria-labelledby="box_padding_right_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="box_padding_bottom">{#style_dlg.bottom}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="box_padding_bottom" name="box_padding_bottom" class="mceEditableSelect" disabled="disabled" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="box_padding_bottom_measurement_label" for="box_padding_bottom_measurement" style="display: none; visibility: hidden;">Padding Bottom Measurement Unit</label>
+ <select id="box_padding_bottom_measurement" name="box_padding_bottom_measurement" disabled="disabled" aria-labelledby="box_padding_bottom_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="box_padding_left">{#style_dlg.left}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="box_padding_left" name="box_padding_left" class="mceEditableSelect" disabled="disabled" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="box_padding_left_measurement_label" for="box_padding_left_measurement" style="display: none; visibility: hidden;">Padding Left Measurement Unit</label>
+ <select id="box_padding_left_measurement" name="box_padding_left_measurement" disabled="disabled" aria-labelledby="box_padding_left_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+</div>
+
+<div style="float: right; width: 49%">
+ <fieldset>
+ <legend>{#style_dlg.margin}</legend>
+
+ <table role="presentation" border="0">
+ <tr>
+ <td>&nbsp;</td>
+ <td><input type="checkbox" id="box_margin_same" name="box_margin_same" class="checkbox" checked="checked" onClick="toggleSame(this,'box_margin');" /> <label for="box_margin_same">{#style_dlg.same}</label></td>
+ </tr>
+ <tr>
+ <td><label for="box_margin_top">{#style_dlg.top}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="box_margin_top" name="box_margin_top" class="mceEditableSelect" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="box_margin_top_measurement_label" for="box_margin_top_measurement" style="display: none; visibility: hidden;">Margin Top Measurement Unit</label>
+ <select id="box_margin_top_measurement" name="box_margin_top_measurement" aria-labelledby="box_margin_top_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="box_margin_right">{#style_dlg.right}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="box_margin_right" name="box_margin_right" class="mceEditableSelect" disabled="disabled" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="box_margin_right_measurement_label" for="box_margin_right_measurement" style="display: none; visibility: hidden;">Margin Right Measurement Unit</label>
+ <select id="box_margin_right_measurement" name="box_margin_right_measurement" disabled="disabled" aria-labelledby="box_margin_right_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="box_margin_bottom">{#style_dlg.bottom}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="box_margin_bottom" name="box_margin_bottom" class="mceEditableSelect" disabled="disabled" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="box_margin_bottom_measurement_label" for="box_margin_bottom_measurement" style="display: none; visibility: hidden;">Margin Bottom Measurement Unit</label>
+ <select id="box_margin_bottom_measurement" name="box_margin_bottom_measurement" disabled="disabled" aria-labelledby="box_margin_bottom_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="box_margin_left">{#style_dlg.left}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="box_margin_left" name="box_margin_left" class="mceEditableSelect" disabled="disabled" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="box_margin_left_measurement_label" for="box_margin_left_measurement" style="display: none; visibility: hidden;">Margin Left Measurement Unit</label>
+ <select id="box_margin_left_measurement" name="box_margin_left_measurement" disabled="disabled" aria-labelledby="box_margin_left_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+</div>
+<br style="clear: both" />
+</div>
+
+<div id="border_panel" class="panel">
+ <fieldset>
+ <legend>{#style_dlg.border}</legend>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0" width="100%">
+ <tr>
+ <td class="tdelim">&nbsp;</td>
+ <td class="tdelim delim">&nbsp;</td>
+ <td class="tdelim">{#style_dlg.style}</td>
+ <td class="tdelim delim">&nbsp;</td>
+ <td class="tdelim">{#style_dlg.width}</td>
+ <td class="tdelim delim">&nbsp;</td>
+ <td class="tdelim">{#style_dlg.color}</td>
+ </tr>
+
+ <tr>
+ <td>&nbsp;</td>
+ <td class="delim">&nbsp;</td>
+ <td><input type="checkbox" id="border_style_same" name="border_style_same" class="checkbox" checked="checked" onClick="toggleSame(this,'border_style');" /> <label for="border_style_same">{#style_dlg.same}</label></td>
+ <td class="delim">&nbsp;</td>
+ <td><input type="checkbox" id="border_width_same" name="border_width_same" class="checkbox" checked="checked" onClick="toggleSame(this,'border_width');" /> <label for="border_width_same">{#style_dlg.same}</label></td>
+ <td class="delim">&nbsp;</td>
+ <td><input type="checkbox" id="border_color_same" name="border_color_same" class="checkbox" checked="checked" onClick="toggleSame(this,'border_color');" /> <label for="border_color_same">{#style_dlg.same}</label></td>
+ </tr>
+
+ <tr>
+ <td>{#style_dlg.top}</td>
+ <td class="delim">&nbsp;</td>
+ <td><select id="border_style_top" name="border_style_top" class="mceEditableSelect"></select></td>
+ <td class="delim">&nbsp;</td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><select id="border_width_top" name="border_width_top" class="mceEditableSelect"></select></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="border_width_top_measurement_label" for="border_width_top_measurement" style="display: none; visibility: hidden;">Width top Measurement Unit</label>
+ <select id="border_width_top_measurement" name="border_width_top_measurement" aria-labelledby="border_width_top_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td class="delim">&nbsp;</td>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="border_color_top" name="border_color_top" type="text" value="" size="9" onChange="updateColor('border_color_top_pick','border_color_top');" /></td>
+ <td id="border_color_top_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>{#style_dlg.right}</td>
+ <td class="delim">&nbsp;</td>
+ <td><select id="border_style_right" name="border_style_right" class="mceEditableSelect" disabled="disabled"></select></td>
+ <td class="delim">&nbsp;</td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><select id="border_width_right" name="border_width_right" class="mceEditableSelect" disabled="disabled"></select></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="border_width_right_measurement_label" for="border_width_right_measurement" style="display: none; visibility: hidden;">Width Right Measurement Unit</label>
+ <select id="border_width_right_measurement" name="border_width_right_measurement" disabled="disabled" aria-labelledby="border_width_right_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td class="delim">&nbsp;</td>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="border_color_right" name="border_color_right" type="text" value="" size="9" onChange="updateColor('border_color_right_pick','border_color_right');" disabled="disabled" /></td>
+ <td id="border_color_right_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>{#style_dlg.bottom}</td>
+ <td class="delim">&nbsp;</td>
+ <td><select id="border_style_bottom" name="border_style_bottom" class="mceEditableSelect" disabled="disabled"></select></td>
+ <td class="delim">&nbsp;</td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><select id="border_width_bottom" name="border_width_bottom" class="mceEditableSelect" disabled="disabled"></select></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="border_width_bottom_measurement_label" for="border_width_bottom_measurement" style="display: none; visibility: hidden;">Width Bottom Measurement Unit</label>
+ <select id="border_width_bottom_measurement" name="border_width_bottom_measurement" disabled="disabled" aria-labelledby="border_width_bottom_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td class="delim">&nbsp;</td>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="border_color_bottom" name="border_color_bottom" type="text" value="" size="9" onChange="updateColor('border_color_bottom_pick','border_color_bottom');" disabled="disabled" /></td>
+ <td id="border_color_bottom_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td>{#style_dlg.left}</td>
+ <td class="delim">&nbsp;</td>
+ <td><select id="border_style_left" name="border_style_left" class="mceEditableSelect" disabled="disabled"></select></td>
+ <td class="delim">&nbsp;</td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><select id="border_width_left" name="border_width_left" class="mceEditableSelect" disabled="disabled"></select></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="border_width_left_measurement_label" for="border_width_left_measurement" style="display: none; visibility: hidden;">Width Left Measurement Unit</label>
+ <select id="border_width_left_measurement" name="border_width_left_measurement" disabled="disabled" aria-labelledby="border_width_left_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td class="delim">&nbsp;</td>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="border_color_left" name="border_color_left" type="text" value="" size="9" onChange="updateColor('border_color_left_pick','border_color_left');" disabled="disabled" /></td>
+ <td id="border_color_left_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+</div>
+
+<div id="list_panel" class="panel">
+<fieldset>
+ <legend>{#style_dlg.list}</legend>
+ <table role="presentation" border="0">
+ <tr>
+ <td><label for="list_type">{#style_dlg.list_type}</label></td>
+ <td><select id="list_type" name="list_type" class="mceEditableSelect"></select></td>
+ </tr>
+
+ <tr>
+ <td><label for="list_bullet_image">{#style_dlg.bullet_image}</label></td>
+ <td><input id="list_bullet_image" name="list_bullet_image" type="text" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="list_position">{#style_dlg.position}</label></td>
+ <td><select id="list_position" name="list_position" class="mceEditableSelect"></select></td>
+ </tr>
+ </table>
+</fieldset>
+</div>
+
+<div id="positioning_panel" class="panel">
+<fieldset>
+ <legend>{#style_dlg.position}</legend>
+<table role="presentation" border="0">
+ <tr>
+ <td><label for="positioning_type">{#style_dlg.positioning_type}</label></td>
+ <td><select id="positioning_type" name="positioning_type" class="mceEditableSelect"></select></td>
+ <td>&nbsp;&nbsp;&nbsp;<label for="positioning_visibility">{#style_dlg.visibility}</label></td>
+ <td><select id="positioning_visibility" name="positioning_visibility" class="mceEditableSelect"></select></td>
+ </tr>
+
+ <tr>
+ <td><label for="positioning_width">{#style_dlg.width}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="positioning_width" name="positioning_width" onChange="synch('positioning_width','box_width');" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="positioning_width_measurement_label" for="positioning_width_measurement" style="display: none; visibility: hidden;">Positioning width Measurement Unit</label>
+ <select id="positioning_width_measurement" name="positioning_width_measurement" aria-labelledby="positioning_width_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td>&nbsp;&nbsp;&nbsp;<label for="positioning_zindex">{#style_dlg.zindex}</label></td>
+ <td><input type="text" id="positioning_zindex" name="positioning_zindex" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="positioning_height">{#style_dlg.height}</label></td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="positioning_height" name="positioning_height" onChange="synch('positioning_height','box_height');" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="positioning_height_measurement_label" for="positioning_height_measurement" style="display: none; visibility: hidden;">Positioning Height Measurement Unit</label>
+ <select id="positioning_height_measurement" name="positioning_height_measurement" aria-labelledby="positioning_height_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td>&nbsp;&nbsp;&nbsp;<label for="positioning_overflow">{#style_dlg.overflow}</label></td>
+ <td><select id="positioning_overflow" name="positioning_overflow" class="mceEditableSelect"></select></td>
+ </tr>
+</table>
+</fieldset>
+
+<div style="float: left; width: 49%">
+ <fieldset>
+ <legend>{#style_dlg.placement}</legend>
+
+ <table role="presentation" border="0">
+ <tr>
+ <td>&nbsp;</td>
+ <td><input type="checkbox" id="positioning_placement_same" name="positioning_placement_same" class="checkbox" checked="checked" onClick="toggleSame(this,'positioning_placement');" /> <label for="positioning_placement_same">{#style_dlg.same}</label></td>
+ </tr>
+ <tr>
+ <td>{#style_dlg.top}</td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="positioning_placement_top" name="positioning_placement_top" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="positioning_placement_top_measurement_label" for="positioning_placement_top_measurement" style="display: none; visibility: hidden;">Placement Top Measurement Unit</label>
+ <select id="positioning_placement_top_measurement" name="positioning_placement_top_measurement" aria-labelledby="positioning_placement_top_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>{#style_dlg.right}</td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="positioning_placement_right" name="positioning_placement_right" disabled="disabled" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="positioning_placement_right_measurement_label" for="positioning_placement_right_measurement" style="display: none; visibility: hidden;">Placement Right Measurement Unit</label>
+ <select id="positioning_placement_right_measurement" name="positioning_placement_right_measurement" disabled="disabled" aria-labelledby="positioning_placement_right_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>{#style_dlg.bottom}</td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="positioning_placement_bottom" name="positioning_placement_bottom" disabled="disabled" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="positioning_placement_bottom_measurement_label" for="positioning_placement_bottom_measurement" style="display: none; visibility: hidden;">Placement Bottom Measurement Unit</label>
+ <select id="positioning_placement_bottom_measurement" name="positioning_placement_bottom_measurement" disabled="disabled" aria-labelledby="positioning_placement_bottom_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>{#style_dlg.left}</td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="positioning_placement_left" name="positioning_placement_left" disabled="disabled" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="positioning_placement_left_measurement_label" for="positioning_placement_left_measurement" style="display: none; visibility: hidden;">Placement Left Measurement Unit</label>
+ <select id="positioning_placement_left_measurement" name="positioning_placement_left_measurement" disabled="disabled" aria-labelledby="positioning_placement_left_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+</div>
+
+<div style="float: right; width: 49%">
+ <fieldset>
+ <legend>{#style_dlg.clip}</legend>
+
+ <table role="presentation" border="0">
+ <tr>
+ <td>&nbsp;</td>
+ <td><input type="checkbox" id="positioning_clip_same" name="positioning_clip_same" class="checkbox" checked="checked" onClick="toggleSame(this,'positioning_clip');" /> <label for="positioning_clip_same">{#style_dlg.same}</label></td>
+ </tr>
+ <tr>
+ <td>{#style_dlg.top}</td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="positioning_clip_top" name="positioning_clip_top" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="positioning_clip_top_measurement_label" for="positioning_clip_top_measurement" style="display: none; visibility: hidden;">Clip Top Measurement Unit</label>
+ <select id="positioning_clip_top_measurement" name="positioning_clip_top_measurement" aria-labelledby="positioning_clip_top_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>{#style_dlg.right}</td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="positioning_clip_right" name="positioning_clip_right" disabled="disabled" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="positioning_clip_right_measurement_label" for="positioning_clip_right_measurement" style="display: none; visibility: hidden;">Clip Right Measurement Unit</label>
+ <select id="positioning_clip_right_measurement" name="positioning_clip_right_measurement" disabled="disabled" aria-labelledby="positioning_clip_right_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>{#style_dlg.bottom}</td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="positioning_clip_bottom" name="positioning_clip_bottom" disabled="disabled" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="positioning_clip_bottom_measurement_label" for="positioning_clip_bottom_measurement" style="display: none; visibility: hidden;">Clip Bottom Measurement Unit</label>
+ <select id="positioning_clip_bottom_measurement" name="positioning_clip_bottom_measurement" disabled="disabled" aria-labelledby="positioning_clip_bottom_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>{#style_dlg.left}</td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input type="text" id="positioning_clip_left" name="positioning_clip_left" disabled="disabled" /></td>
+ <td>&nbsp;</td>
+ <td>
+ <label id="positioning_clip_left_measurement_label" for="positioning_clip_left_measurement" style="display: none; visibility: hidden;">Clip Left Measurement Unit</label>
+ <select id="positioning_clip_left_measurement" name="positioning_clip_left_measurement" disabled="disabled" aria-labelledby="positioning_clip_left_measurement_label"></select>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+</div>
+<br style="clear: both" />
+</div>
+</div>
+
+<div class="panel_toggle_insert_span">
+ <input type="checkbox" class="checkbox" id="toggle_insert_span" name="toggle_insert_span" onClick="toggleApplyAction();" />
+ <label for="toggle_insert_span">{#style_dlg.toggle_insert_span}</label>
+</div>
+
+<div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#update}" />
+ <input type="button" class="button" id="apply" name="apply" value="{#style_dlg.apply}" onClick="applyAction();" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onClick="tinyMCEPopup.close();" />
+</div>
+</form>
+
+<div style="display: none">
+ <div id="container"></div>
+</div>
+
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/style/readme.txt b/askbot/media/js/tinymce/plugins/style/readme.txt
new file mode 100644
index 00000000..5bac3020
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/style/readme.txt
@@ -0,0 +1,19 @@
+Edit CSS Style plug-in notes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Unlike WYSIWYG editor functionality that operates only on the selected text,
+typically by inserting new HTML elements with the specified styles.
+This plug-in operates on the HTML blocks surrounding the selected text.
+No new HTML elements are created.
+
+This plug-in only operates on the surrounding blocks and not the nearest
+parent node. This means that if a block encapsulates a node,
+e.g <p><span>text</span></p>, then only the styles in the block are
+recognized, not those in the span.
+
+When selecting text that includes multiple blocks at the same level (peers),
+this plug-in accumulates the specified styles in all of the surrounding blocks
+and populates the dialogue checkboxes accordingly. There is no differentiation
+between styles set in all the blocks versus styles set in some of the blocks.
+
+When the [Update] or [Apply] buttons are pressed, the styles selected in the
+checkboxes are applied to all blocks that surround the selected text.
diff --git a/askbot/media/js/tinymce/plugins/tabfocus/editor_plugin.js b/askbot/media/js/tinymce/plugins/tabfocus/editor_plugin.js
new file mode 100644
index 00000000..2c512916
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/tabfocus/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var c=tinymce.DOM,a=tinymce.dom.Event,d=tinymce.each,b=tinymce.explode;tinymce.create("tinymce.plugins.TabFocusPlugin",{init:function(f,g){function e(i,j){if(j.keyCode===9){return a.cancel(j)}}function h(l,p){var j,m,o,n,k;function q(t){n=c.select(":input:enabled,*[tabindex]:not(iframe)");function s(v){return v.nodeName==="BODY"||(v.type!="hidden"&&!(v.style.display=="none")&&!(v.style.visibility=="hidden")&&s(v.parentNode))}function i(v){return v.attributes.tabIndex.specified||v.nodeName=="INPUT"||v.nodeName=="TEXTAREA"}function u(){return tinymce.isIE6||tinymce.isIE7}function r(v){return((!u()||i(v)))&&v.getAttribute("tabindex")!="-1"&&s(v)}d(n,function(w,v){if(w.id==l.id){j=v;return false}});if(t>0){for(m=j+1;m<n.length;m++){if(r(n[m])){return n[m]}}}else{for(m=j-1;m>=0;m--){if(r(n[m])){return n[m]}}}return null}if(p.keyCode===9){k=b(l.getParam("tab_focus",l.getParam("tabfocus_elements",":prev,:next")));if(k.length==1){k[1]=k[0];k[0]=":prev"}if(p.shiftKey){if(k[0]==":prev"){n=q(-1)}else{n=c.get(k[0])}}else{if(k[1]==":next"){n=q(1)}else{n=c.get(k[1])}}if(n){if(n.id&&(l=tinymce.get(n.id||n.name))){l.focus()}else{window.setTimeout(function(){if(!tinymce.isWebKit){window.focus()}n.focus()},10)}return a.cancel(p)}}}f.onKeyUp.add(e);if(tinymce.isGecko){f.onKeyPress.add(h);f.onKeyDown.add(e)}else{f.onKeyDown.add(h)}},getInfo:function(){return{longname:"Tabfocus",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/tabfocus",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("tabfocus",tinymce.plugins.TabFocusPlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/tabfocus/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/tabfocus/editor_plugin_src.js
new file mode 100644
index 00000000..94f45320
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/tabfocus/editor_plugin_src.js
@@ -0,0 +1,122 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, explode = tinymce.explode;
+
+ tinymce.create('tinymce.plugins.TabFocusPlugin', {
+ init : function(ed, url) {
+ function tabCancel(ed, e) {
+ if (e.keyCode === 9)
+ return Event.cancel(e);
+ }
+
+ function tabHandler(ed, e) {
+ var x, i, f, el, v;
+
+ function find(d) {
+ el = DOM.select(':input:enabled,*[tabindex]:not(iframe)');
+
+ function canSelectRecursive(e) {
+ return e.nodeName==="BODY" || (e.type != 'hidden' &&
+ !(e.style.display == "none") &&
+ !(e.style.visibility == "hidden") && canSelectRecursive(e.parentNode));
+ }
+ function canSelectInOldIe(el) {
+ return el.attributes["tabIndex"].specified || el.nodeName == "INPUT" || el.nodeName == "TEXTAREA";
+ }
+ function isOldIe() {
+ return tinymce.isIE6 || tinymce.isIE7;
+ }
+ function canSelect(el) {
+ return ((!isOldIe() || canSelectInOldIe(el))) && el.getAttribute("tabindex") != '-1' && canSelectRecursive(el);
+ }
+
+ each(el, function(e, i) {
+ if (e.id == ed.id) {
+ x = i;
+ return false;
+ }
+ });
+ if (d > 0) {
+ for (i = x + 1; i < el.length; i++) {
+ if (canSelect(el[i]))
+ return el[i];
+ }
+ } else {
+ for (i = x - 1; i >= 0; i--) {
+ if (canSelect(el[i]))
+ return el[i];
+ }
+ }
+
+ return null;
+ }
+
+ if (e.keyCode === 9) {
+ v = explode(ed.getParam('tab_focus', ed.getParam('tabfocus_elements', ':prev,:next')));
+
+ if (v.length == 1) {
+ v[1] = v[0];
+ v[0] = ':prev';
+ }
+
+ // Find element to focus
+ if (e.shiftKey) {
+ if (v[0] == ':prev')
+ el = find(-1);
+ else
+ el = DOM.get(v[0]);
+ } else {
+ if (v[1] == ':next')
+ el = find(1);
+ else
+ el = DOM.get(v[1]);
+ }
+
+ if (el) {
+ if (el.id && (ed = tinymce.get(el.id || el.name)))
+ ed.focus();
+ else
+ window.setTimeout(function() {
+ if (!tinymce.isWebKit)
+ window.focus();
+ el.focus();
+ }, 10);
+
+ return Event.cancel(e);
+ }
+ }
+ }
+
+ ed.onKeyUp.add(tabCancel);
+
+ if (tinymce.isGecko) {
+ ed.onKeyPress.add(tabHandler);
+ ed.onKeyDown.add(tabCancel);
+ } else
+ ed.onKeyDown.add(tabHandler);
+
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Tabfocus',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/tabfocus',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('tabfocus', tinymce.plugins.TabFocusPlugin);
+})();
diff --git a/askbot/media/js/tinymce/plugins/table/cell.htm b/askbot/media/js/tinymce/plugins/table/cell.htm
new file mode 100644
index 00000000..a72a8d69
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/table/cell.htm
@@ -0,0 +1,180 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#table_dlg.cell_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="../../utils/validate.js"></script>
+ <script type="text/javascript" src="../../utils/editable_selects.js"></script>
+ <script type="text/javascript" src="js/cell.js"></script>
+ <link href="css/cell.css" rel="stylesheet" type="text/css" />
+</head>
+<body id="tablecell" style="display: none" role="application">
+ <form onsubmit="updateAction();return false;" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" class="current" aria-controls="general_panel"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#table_dlg.general_tab}</a></span></li>
+ <li id="advanced_tab" aria-controls="advanced_panel"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');" onmousedown="return false;">{#table_dlg.advanced_tab}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <fieldset>
+ <legend>{#table_dlg.general_props}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td><label for="align">{#table_dlg.align}</label></td>
+ <td>
+ <select id="align" name="align" class="mceFocus">
+ <option value="">{#not_set}</option>
+ <option value="center">{#table_dlg.align_middle}</option>
+ <option value="left">{#table_dlg.align_left}</option>
+ <option value="right">{#table_dlg.align_right}</option>
+ </select>
+ </td>
+
+ <td><label for="celltype">{#table_dlg.cell_type}</label></td>
+ <td>
+ <select id="celltype" name="celltype">
+ <option value="td">{#table_dlg.td}</option>
+ <option value="th">{#table_dlg.th}</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="valign">{#table_dlg.valign}</label></td>
+ <td>
+ <select id="valign" name="valign">
+ <option value="">{#not_set}</option>
+ <option value="top">{#table_dlg.align_top}</option>
+ <option value="middle">{#table_dlg.align_middle}</option>
+ <option value="bottom">{#table_dlg.align_bottom}</option>
+ </select>
+ </td>
+
+ <td><label for="scope">{#table_dlg.scope}</label></td>
+ <td>
+ <select id="scope" name="scope">
+ <option value="">{#not_set}</option>
+ <option value="col">{#table.col}</option>
+ <option value="row">{#table.row}</option>
+ <option value="rowgroup">{#table_dlg.rowgroup}</option>
+ <option value="colgroup">{#table_dlg.colgroup}</option>
+ </select>
+ </td>
+
+ </tr>
+
+ <tr>
+ <td><label for="width">{#table_dlg.width}</label></td>
+ <td><input id="width" name="width" type="text" value="" size="7" maxlength="7" onchange="changedSize();" class="size" /></td>
+
+ <td><label for="height">{#table_dlg.height}</label></td>
+ <td><input id="height" name="height" type="text" value="" size="7" maxlength="7" onchange="changedSize();" class="size" /></td>
+ </tr>
+
+ <tr id="styleSelectRow">
+ <td><label for="class">{#class_name}</label></td>
+ <td colspan="3">
+ <select id="class" name="class" class="mceEditableSelect">
+ <option value="" selected="selected">{#not_set}</option>
+ </select>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+
+ <div id="advanced_panel" class="panel">
+ <fieldset>
+ <legend>{#table_dlg.advanced_props}</legend>
+
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="column1"><label for="id">{#table_dlg.id}</label></td>
+ <td><input id="id" name="id" type="text" value="" style="width: 200px" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="style">{#table_dlg.style}</label></td>
+ <td><input type="text" id="style" name="style" value="" style="width: 200px;" onchange="changedStyle();" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="dir">{#table_dlg.langdir}</label></td>
+ <td>
+ <select id="dir" name="dir" style="width: 200px">
+ <option value="">{#not_set}</option>
+ <option value="ltr">{#table_dlg.ltr}</option>
+ <option value="rtl">{#table_dlg.rtl}</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="lang">{#table_dlg.langcode}</label></td>
+ <td>
+ <input id="lang" name="lang" type="text" value="" style="width: 200px" />
+ </td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="backgroundimage">{#table_dlg.bgimage}</label></td>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="backgroundimage" name="backgroundimage" type="text" value="" style="width: 200px" onchange="changedBackgroundImage();" /></td>
+ <td id="backgroundimagebrowsercontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr role="group" aria-labelledby="bordercolor_label">
+ <td class="column1"><label id="bordercolor_label" for="bordercolor">{#table_dlg.bordercolor}</label></td>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="bordercolor" name="bordercolor" type="text" value="" size="9" onchange="updateColor('bordercolor_pick','bordercolor');changedColor();" /></td>
+ <td id="bordercolor_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr role="group" aria-labelledby="bgcolor_label">
+ <td class="column1"><label id="bgcolor_label" for="bgcolor">{#table_dlg.bgcolor}</label></td>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="bgcolor" name="bgcolor" type="text" value="" size="9" onchange="updateColor('bgcolor_pick','bgcolor');changedColor();" /></td>
+ <td id="bgcolor_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <div>
+ <select id="action" name="action">
+ <option value="cell">{#table_dlg.cell_cell}</option>
+ <option value="row">{#table_dlg.cell_row}</option>
+ <option value="col">{#table_dlg.cell_col}</option>
+ <option value="all">{#table_dlg.cell_all}</option>
+ </select>
+ </div>
+
+ <input type="submit" id="insert" name="insert" value="{#update}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+ </form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/table/css/cell.css b/askbot/media/js/tinymce/plugins/table/css/cell.css
new file mode 100644
index 00000000..a067ecdf
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/table/css/cell.css
@@ -0,0 +1,17 @@
+/* CSS file for cell dialog in the table plugin */
+
+.panel_wrapper div.current {
+ height: 200px;
+}
+
+.advfield {
+ width: 200px;
+}
+
+#action {
+ margin-bottom: 3px;
+}
+
+#class {
+ width: 150px;
+} \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/table/css/row.css b/askbot/media/js/tinymce/plugins/table/css/row.css
new file mode 100644
index 00000000..1f7755da
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/table/css/row.css
@@ -0,0 +1,25 @@
+/* CSS file for row dialog in the table plugin */
+
+.panel_wrapper div.current {
+ height: 200px;
+}
+
+.advfield {
+ width: 200px;
+}
+
+#action {
+ margin-bottom: 3px;
+}
+
+#rowtype,#align,#valign,#class,#height {
+ width: 150px;
+}
+
+#height {
+ width: 50px;
+}
+
+.col2 {
+ padding-left: 20px;
+}
diff --git a/askbot/media/js/tinymce/plugins/table/css/table.css b/askbot/media/js/tinymce/plugins/table/css/table.css
new file mode 100644
index 00000000..d11c3f69
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/table/css/table.css
@@ -0,0 +1,13 @@
+/* CSS file for table dialog in the table plugin */
+
+.panel_wrapper div.current {
+ height: 245px;
+}
+
+.advfield {
+ width: 200px;
+}
+
+#class {
+ width: 150px;
+}
diff --git a/askbot/media/js/tinymce/plugins/table/editor_plugin.js b/askbot/media/js/tinymce/plugins/table/editor_plugin.js
new file mode 100644
index 00000000..23c1a83f
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/table/editor_plugin.js
@@ -0,0 +1 @@
+(function(d){var e=d.each;function c(g,h){var j=h.ownerDocument,f=j.createRange(),k;f.setStartBefore(h);f.setEnd(g.endContainer,g.endOffset);k=j.createElement("body");k.appendChild(f.cloneContents());return k.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi,"-").replace(/<[^>]+>/g,"").length==0}function a(g,f){return parseInt(g.getAttribute(f)||1)}function b(H,G,K){var g,L,D,o;t();o=G.getParent(K.getStart(),"th,td");if(o){L=F(o);D=I();o=z(L.x,L.y)}function A(N,M){N=N.cloneNode(M);N.removeAttribute("id");return N}function t(){var M=0;g=[];e(["thead","tbody","tfoot"],function(N){var O=G.select("> "+N+" tr",H);e(O,function(P,Q){Q+=M;e(G.select("> td, > th",P),function(W,R){var S,T,U,V;if(g[Q]){while(g[Q][R]){R++}}U=a(W,"rowspan");V=a(W,"colspan");for(T=Q;T<Q+U;T++){if(!g[T]){g[T]=[]}for(S=R;S<R+V;S++){g[T][S]={part:N,real:T==Q&&S==R,elm:W,rowspan:U,colspan:V}}}})});M+=O.length})}function z(M,O){var N;N=g[O];if(N){return N[M]}}function s(O,M,N){if(O){N=parseInt(N);if(N===1){O.removeAttribute(M,1)}else{O.setAttribute(M,N,1)}}}function j(M){return M&&(G.hasClass(M.elm,"mceSelected")||M==o)}function k(){var M=[];e(H.rows,function(N){e(N.cells,function(O){if(G.hasClass(O,"mceSelected")||O==o.elm){M.push(N);return false}})});return M}function r(){var M=G.createRng();M.setStartAfter(H);M.setEndAfter(H);K.setRng(M);G.remove(H)}function f(M){var N;d.walk(M,function(P){var O;if(P.nodeType==3){e(G.getParents(P.parentNode,null,M).reverse(),function(Q){Q=A(Q,false);if(!N){N=O=Q}else{if(O){O.appendChild(Q)}}O=Q});if(O){O.innerHTML=d.isIE?"&nbsp;":'<br data-mce-bogus="1" />'}return false}},"childNodes");M=A(M,false);s(M,"rowSpan",1);s(M,"colSpan",1);if(N){M.appendChild(N)}else{if(!d.isIE){M.innerHTML='<br data-mce-bogus="1" />'}}return M}function q(){var M=G.createRng();e(G.select("tr",H),function(N){if(N.cells.length==0){G.remove(N)}});if(G.select("tr",H).length==0){M.setStartAfter(H);M.setEndAfter(H);K.setRng(M);G.remove(H);return}e(G.select("thead,tbody,tfoot",H),function(N){if(N.rows.length==0){G.remove(N)}});t();row=g[Math.min(g.length-1,L.y)];if(row){K.select(row[Math.min(row.length-1,L.x)].elm,true);K.collapse(true)}}function u(S,Q,U,R){var P,N,M,O,T;P=g[Q][S].elm.parentNode;for(M=1;M<=U;M++){P=G.getNext(P,"tr");if(P){for(N=S;N>=0;N--){T=g[Q+M][N].elm;if(T.parentNode==P){for(O=1;O<=R;O++){G.insertAfter(f(T),T)}break}}if(N==-1){for(O=1;O<=R;O++){P.insertBefore(f(P.cells[0]),P.cells[0])}}}}}function C(){e(g,function(M,N){e(M,function(P,O){var S,R,T,Q;if(j(P)){P=P.elm;S=a(P,"colspan");R=a(P,"rowspan");if(S>1||R>1){s(P,"rowSpan",1);s(P,"colSpan",1);for(Q=0;Q<S-1;Q++){G.insertAfter(f(P),P)}u(O,N,R-1,S)}}})})}function p(V,S,Y){var P,O,X,W,U,R,T,M,V,N,Q;if(V){pos=F(V);P=pos.x;O=pos.y;X=P+(S-1);W=O+(Y-1)}else{L=D=null;e(g,function(Z,aa){e(Z,function(ac,ab){if(j(ac)){if(!L){L={x:ab,y:aa}}D={x:ab,y:aa}}})});P=L.x;O=L.y;X=D.x;W=D.y}T=z(P,O);M=z(X,W);if(T&&M&&T.part==M.part){C();t();T=z(P,O).elm;s(T,"colSpan",(X-P)+1);s(T,"rowSpan",(W-O)+1);for(R=O;R<=W;R++){for(U=P;U<=X;U++){if(!g[R]||!g[R][U]){continue}V=g[R][U].elm;if(V!=T){N=d.grep(V.childNodes);e(N,function(Z){T.appendChild(Z)});if(N.length){N=d.grep(T.childNodes);Q=0;e(N,function(Z){if(Z.nodeName=="BR"&&G.getAttrib(Z,"data-mce-bogus")&&Q++<N.length-1){T.removeChild(Z)}})}G.remove(V)}}}q()}}function l(Q){var M,S,P,R,T,U,N,V,O;e(g,function(W,X){e(W,function(Z,Y){if(j(Z)){Z=Z.elm;T=Z.parentNode;U=A(T,false);M=X;if(Q){return false}}});if(Q){return !M}});for(R=0;R<g[0].length;R++){if(!g[M][R]){continue}S=g[M][R].elm;if(S!=P){if(!Q){O=a(S,"rowspan");if(O>1){s(S,"rowSpan",O+1);continue}}else{if(M>0&&g[M-1][R]){V=g[M-1][R].elm;O=a(V,"rowSpan");if(O>1){s(V,"rowSpan",O+1);continue}}}N=f(S);s(N,"colSpan",S.colSpan);U.appendChild(N);P=S}}if(U.hasChildNodes()){if(!Q){G.insertAfter(U,T)}else{T.parentNode.insertBefore(U,T)}}}function h(N){var O,M;e(g,function(P,Q){e(P,function(S,R){if(j(S)){O=R;if(N){return false}}});if(N){return !O}});e(g,function(S,T){var P,Q,R;if(!S[O]){return}P=S[O].elm;if(P!=M){R=a(P,"colspan");Q=a(P,"rowspan");if(R==1){if(!N){G.insertAfter(f(P),P);u(O,T,Q-1,R)}else{P.parentNode.insertBefore(f(P),P);u(O,T,Q-1,R)}}else{s(P,"colSpan",P.colSpan+1)}M=P}})}function n(){var M=[];e(g,function(N,O){e(N,function(Q,P){if(j(Q)&&d.inArray(M,P)===-1){e(g,function(T){var R=T[P].elm,S;S=a(R,"colSpan");if(S>1){s(R,"colSpan",S-1)}else{G.remove(R)}});M.push(P)}})});q()}function m(){var N;function M(Q){var P,R,O;P=G.getNext(Q,"tr");e(Q.cells,function(S){var T=a(S,"rowSpan");if(T>1){s(S,"rowSpan",T-1);R=F(S);u(R.x,R.y,1,1)}});R=F(Q.cells[0]);e(g[R.y],function(S){var T;S=S.elm;if(S!=O){T=a(S,"rowSpan");if(T<=1){G.remove(S)}else{s(S,"rowSpan",T-1)}O=S}})}N=k();e(N.reverse(),function(O){M(O)});q()}function E(){var M=k();G.remove(M);q();return M}function J(){var M=k();e(M,function(O,N){M[N]=A(O,true)});return M}function B(O,N){var P=k(),M=P[N?0:P.length-1],Q=M.cells.length;e(g,function(S){var R;Q=0;e(S,function(U,T){if(U.real){Q+=U.colspan}if(U.elm.parentNode==M){R=1}});if(R){return false}});if(!N){O.reverse()}e(O,function(T){var S=T.cells.length,R;for(i=0;i<S;i++){R=T.cells[i];s(R,"colSpan",1);s(R,"rowSpan",1)}for(i=S;i<Q;i++){T.appendChild(f(T.cells[S-1]))}for(i=Q;i<S;i++){G.remove(T.cells[i])}if(N){M.parentNode.insertBefore(T,M)}else{G.insertAfter(T,M)}});G.removeClass(G.select("td.mceSelected,th.mceSelected"),"mceSelected")}function F(M){var N;e(g,function(O,P){e(O,function(R,Q){if(R.elm==M){N={x:Q,y:P};return false}});return !N});return N}function w(M){L=F(M)}function I(){var O,N,M;N=M=0;e(g,function(P,Q){e(P,function(S,R){var U,T;if(j(S)){S=g[Q][R];if(R>N){N=R}if(Q>M){M=Q}if(S.real){U=S.colspan-1;T=S.rowspan-1;if(U){if(R+U>N){N=R+U}}if(T){if(Q+T>M){M=Q+T}}}}})});return{x:N,y:M}}function v(S){var P,O,U,T,N,M,Q,R;D=F(S);if(L&&D){P=Math.min(L.x,D.x);O=Math.min(L.y,D.y);U=Math.max(L.x,D.x);T=Math.max(L.y,D.y);N=U;M=T;for(y=O;y<=M;y++){S=g[y][P];if(!S.real){if(P-(S.colspan-1)<P){P-=S.colspan-1}}}for(x=P;x<=N;x++){S=g[O][x];if(!S.real){if(O-(S.rowspan-1)<O){O-=S.rowspan-1}}}for(y=O;y<=T;y++){for(x=P;x<=U;x++){S=g[y][x];if(S.real){Q=S.colspan-1;R=S.rowspan-1;if(Q){if(x+Q>N){N=x+Q}}if(R){if(y+R>M){M=y+R}}}}}G.removeClass(G.select("td.mceSelected,th.mceSelected"),"mceSelected");for(y=O;y<=M;y++){for(x=P;x<=N;x++){if(g[y][x]){G.addClass(g[y][x].elm,"mceSelected")}}}}}d.extend(this,{deleteTable:r,split:C,merge:p,insertRow:l,insertCol:h,deleteCols:n,deleteRows:m,cutRows:E,copyRows:J,pasteRows:B,getPos:F,setStartCell:w,setEndCell:v})}d.create("tinymce.plugins.TablePlugin",{init:function(g,h){var f,m,j=true;function l(p){var o=g.selection,n=g.dom.getParent(p||o.getNode(),"table");if(n){return new b(n,g.dom,o)}}function k(){g.getBody().style.webkitUserSelect="";if(j){g.dom.removeClass(g.dom.select("td.mceSelected,th.mceSelected"),"mceSelected");j=false}}e([["table","table.desc","mceInsertTable",true],["delete_table","table.del","mceTableDelete"],["delete_col","table.delete_col_desc","mceTableDeleteCol"],["delete_row","table.delete_row_desc","mceTableDeleteRow"],["col_after","table.col_after_desc","mceTableInsertColAfter"],["col_before","table.col_before_desc","mceTableInsertColBefore"],["row_after","table.row_after_desc","mceTableInsertRowAfter"],["row_before","table.row_before_desc","mceTableInsertRowBefore"],["row_props","table.row_desc","mceTableRowProps",true],["cell_props","table.cell_desc","mceTableCellProps",true],["split_cells","table.split_cells_desc","mceTableSplitCells",true],["merge_cells","table.merge_cells_desc","mceTableMergeCells",true]],function(n){g.addButton(n[0],{title:n[1],cmd:n[2],ui:n[3]})});if(!d.isIE){g.onClick.add(function(n,o){o=o.target;if(o.nodeName==="TABLE"){n.selection.select(o);n.nodeChanged()}})}g.onPreProcess.add(function(o,p){var n,q,r,t=o.dom,s;n=t.select("table",p.node);q=n.length;while(q--){r=n[q];t.setAttrib(r,"data-mce-style","");if((s=t.getAttrib(r,"width"))){t.setStyle(r,"width",s);t.setAttrib(r,"width","")}if((s=t.getAttrib(r,"height"))){t.setStyle(r,"height",s);t.setAttrib(r,"height","")}}});g.onNodeChange.add(function(q,o,s){var r;s=q.selection.getStart();r=q.dom.getParent(s,"td,th,caption");o.setActive("table",s.nodeName==="TABLE"||!!r);if(r&&r.nodeName==="CAPTION"){r=0}o.setDisabled("delete_table",!r);o.setDisabled("delete_col",!r);o.setDisabled("delete_table",!r);o.setDisabled("delete_row",!r);o.setDisabled("col_after",!r);o.setDisabled("col_before",!r);o.setDisabled("row_after",!r);o.setDisabled("row_before",!r);o.setDisabled("row_props",!r);o.setDisabled("cell_props",!r);o.setDisabled("split_cells",!r);o.setDisabled("merge_cells",!r)});g.onInit.add(function(r){var p,t,q=r.dom,u;f=r.windowManager;r.onMouseDown.add(function(w,z){if(z.button!=2){k();t=q.getParent(z.target,"td,th");p=q.getParent(t,"table")}});q.bind(r.getDoc(),"mouseover",function(C){var A,z,B=C.target;if(t&&(u||B!=t)&&(B.nodeName=="TD"||B.nodeName=="TH")){z=q.getParent(B,"table");if(z==p){if(!u){u=l(z);u.setStartCell(t);r.getBody().style.webkitUserSelect="none"}u.setEndCell(B);j=true}A=r.selection.getSel();try{if(A.removeAllRanges){A.removeAllRanges()}else{A.empty()}}catch(w){}C.preventDefault()}});r.onMouseUp.add(function(F,G){var z,B=F.selection,H,I=B.getSel(),w,C,A,E;if(t){if(u){F.getBody().style.webkitUserSelect=""}function D(J,L){var K=new d.dom.TreeWalker(J,J);do{if(J.nodeType==3&&d.trim(J.nodeValue).length!=0){if(L){z.setStart(J,0)}else{z.setEnd(J,J.nodeValue.length)}return}if(J.nodeName=="BR"){if(L){z.setStartBefore(J)}else{z.setEndBefore(J)}return}}while(J=(L?K.next():K.prev()))}H=q.select("td.mceSelected,th.mceSelected");if(H.length>0){z=q.createRng();C=H[0];E=H[H.length-1];z.setStartBefore(C);z.setEndAfter(C);D(C,1);w=new d.dom.TreeWalker(C,q.getParent(H[0],"table"));do{if(C.nodeName=="TD"||C.nodeName=="TH"){if(!q.hasClass(C,"mceSelected")){break}A=C}}while(C=w.next());D(A);B.setRng(z)}F.nodeChanged();t=u=p=null}});r.onKeyUp.add(function(w,z){k()});r.onKeyDown.add(function(w,z){n(w)});r.onMouseDown.add(function(w,z){if(z.button!=2){n(w)}});function o(D,z,A,F){var B=3,G=D.dom.getParent(z.startContainer,"TABLE"),C,w,E;if(G){C=G.parentNode}w=z.startContainer.nodeType==B&&z.startOffset==0&&z.endOffset==0&&F&&(A.nodeName=="TR"||A==C);E=(A.nodeName=="TD"||A.nodeName=="TH")&&!F;return w||E}function n(A){if(!d.isWebKit){return}var z=A.selection.getRng();var C=A.selection.getNode();var B=A.dom.getParent(z.startContainer,"TD,TH");if(!o(A,z,C,B)){return}if(!B){B=C}var w=B.lastChild;while(w.lastChild){w=w.lastChild}z.setEnd(w,w.nodeValue.length);A.selection.setRng(z)}r.plugins.table.fixTableCellSelection=n;if(r&&r.plugins.contextmenu){r.plugins.contextmenu.onContextMenu.add(function(A,w,C){var D,B=r.selection,z=B.getNode()||r.getBody();if(r.dom.getParent(C,"td")||r.dom.getParent(C,"th")||r.dom.select("td.mceSelected,th.mceSelected").length){w.removeAll();if(z.nodeName=="A"&&!r.dom.getAttrib(z,"name")){w.add({title:"advanced.link_desc",icon:"link",cmd:r.plugins.advlink?"mceAdvLink":"mceLink",ui:true});w.add({title:"advanced.unlink_desc",icon:"unlink",cmd:"UnLink"});w.addSeparator()}if(z.nodeName=="IMG"&&z.className.indexOf("mceItem")==-1){w.add({title:"advanced.image_desc",icon:"image",cmd:r.plugins.advimage?"mceAdvImage":"mceImage",ui:true});w.addSeparator()}w.add({title:"table.desc",icon:"table",cmd:"mceInsertTable",value:{action:"insert"}});w.add({title:"table.props_desc",icon:"table_props",cmd:"mceInsertTable"});w.add({title:"table.del",icon:"delete_table",cmd:"mceTableDelete"});w.addSeparator();D=w.addMenu({title:"table.cell"});D.add({title:"table.cell_desc",icon:"cell_props",cmd:"mceTableCellProps"});D.add({title:"table.split_cells_desc",icon:"split_cells",cmd:"mceTableSplitCells"});D.add({title:"table.merge_cells_desc",icon:"merge_cells",cmd:"mceTableMergeCells"});D=w.addMenu({title:"table.row"});D.add({title:"table.row_desc",icon:"row_props",cmd:"mceTableRowProps"});D.add({title:"table.row_before_desc",icon:"row_before",cmd:"mceTableInsertRowBefore"});D.add({title:"table.row_after_desc",icon:"row_after",cmd:"mceTableInsertRowAfter"});D.add({title:"table.delete_row_desc",icon:"delete_row",cmd:"mceTableDeleteRow"});D.addSeparator();D.add({title:"table.cut_row_desc",icon:"cut",cmd:"mceTableCutRow"});D.add({title:"table.copy_row_desc",icon:"copy",cmd:"mceTableCopyRow"});D.add({title:"table.paste_row_before_desc",icon:"paste",cmd:"mceTablePasteRowBefore"}).setDisabled(!m);D.add({title:"table.paste_row_after_desc",icon:"paste",cmd:"mceTablePasteRowAfter"}).setDisabled(!m);D=w.addMenu({title:"table.col"});D.add({title:"table.col_before_desc",icon:"col_before",cmd:"mceTableInsertColBefore"});D.add({title:"table.col_after_desc",icon:"col_after",cmd:"mceTableInsertColAfter"});D.add({title:"table.delete_col_desc",icon:"delete_col",cmd:"mceTableDeleteCol"})}else{w.add({title:"table.desc",icon:"table",cmd:"mceInsertTable"})}})}if(d.isWebKit){function v(C,N){var L=d.VK;var Q=N.keyCode;function O(Y,U,S){var T=Y?"previousSibling":"nextSibling";var Z=C.dom.getParent(U,"tr");var X=Z[T];if(X){z(C,U,X,Y);d.dom.Event.cancel(S);return true}else{var aa=C.dom.getParent(Z,"table");var W=Z.parentNode;var R=W.nodeName.toLowerCase();if(R==="tbody"||R===(Y?"tfoot":"thead")){var V=w(Y,aa,W,"tbody");if(V!==null){return K(Y,V,U,S)}}return M(Y,Z,T,aa,S)}}function w(V,T,U,X){var S=C.dom.select(">"+X,T);var R=S.indexOf(U);if(V&&R===0||!V&&R===S.length-1){return B(V,T)}else{if(R===-1){var W=U.tagName.toLowerCase()==="thead"?0:S.length-1;return S[W]}else{return S[R+(V?-1:1)]}}}function B(U,T){var S=U?"thead":"tfoot";var R=C.dom.select(">"+S,T);return R.length!==0?R[0]:null}function K(V,T,S,U){var R=J(T,V);R&&z(C,S,R,V);d.dom.Event.cancel(U);return true}function M(Y,U,R,X,W){var S=X[R];if(S){F(S);return true}else{var V=C.dom.getParent(X,"td,th");if(V){return O(Y,V,W)}else{var T=J(U,!Y);F(T);return d.dom.Event.cancel(W)}}}function J(S,R){var T=S&&S[R?"lastChild":"firstChild"];return T&&T.nodeName==="BR"?C.dom.getParent(T,"td,th"):T}function F(R){C.selection.setCursorLocation(R,0)}function A(){return Q==L.UP||Q==L.DOWN}function D(R){var T=R.selection.getNode();var S=R.dom.getParent(T,"tr");return S!==null}function P(S){var R=0;var T=S;while(T.previousSibling){T=T.previousSibling;R=R+a(T,"colspan")}return R}function E(T,R){var U=0;var S=0;e(T.children,function(V,W){U=U+a(V,"colspan");S=W;if(U>R){return false}});return S}function z(T,W,Y,V){var X=P(T.dom.getParent(W,"td,th"));var S=E(Y,X);var R=Y.childNodes[S];var U=J(R,V);F(U||R)}function H(R){var T=C.selection.getNode();var U=C.dom.getParent(T,"td,th");var S=C.dom.getParent(R,"td,th");return U&&U!==S&&I(U,S)}function I(S,R){return C.dom.getParent(S,"TABLE")===C.dom.getParent(R,"TABLE")}if(A()&&D(C)){var G=C.selection.getNode();setTimeout(function(){if(H(G)){O(!N.shiftKey&&Q===L.UP,G,N)}},0)}}r.onKeyDown.add(v)}function s(){var w;for(w=r.getBody().lastChild;w&&w.nodeType==3&&!w.nodeValue.length;w=w.previousSibling){}if(w&&w.nodeName=="TABLE"){if(r.settings.forced_root_block){r.dom.add(r.getBody(),r.settings.forced_root_block,null,d.isIE?"&nbsp;":'<br data-mce-bogus="1" />')}else{r.dom.add(r.getBody(),"br",{"data-mce-bogus":"1"})}}}if(d.isGecko){r.onKeyDown.add(function(z,B){var w,A,C=z.dom;if(B.keyCode==37||B.keyCode==38){w=z.selection.getRng();A=C.getParent(w.startContainer,"table");if(A&&z.getBody().firstChild==A){if(c(w,A)){w=C.createRng();w.setStartBefore(A);w.setEndBefore(A);z.selection.setRng(w);B.preventDefault()}}}})}r.onKeyUp.add(s);r.onSetContent.add(s);r.onVisualAid.add(s);r.onPreProcess.add(function(w,A){var z=A.node.lastChild;if(z&&(z.nodeName=="BR"||(z.childNodes.length==1&&(z.firstChild.nodeName=="BR"||z.firstChild.nodeValue=="\u00a0")))&&z.previousSibling&&z.previousSibling.nodeName=="TABLE"){w.dom.remove(z)}});if(d.isGecko){r.onKeyDown.add(function(z,B){if(B.keyCode===d.VK.ENTER&&B.shiftKey){var A=z.selection.getRng().startContainer;var C=q.getParent(A,"td,th");if(C){var w=z.getDoc().createTextNode("\uFEFF");q.insertAfter(w,A)}}})}s();r.startContent=r.getContent({format:"raw"})});e({mceTableSplitCells:function(n){n.split()},mceTableMergeCells:function(o){var p,q,n;n=g.dom.getParent(g.selection.getNode(),"th,td");if(n){p=n.rowSpan;q=n.colSpan}if(!g.dom.select("td.mceSelected,th.mceSelected").length){f.open({url:h+"/merge_cells.htm",width:240+parseInt(g.getLang("table.merge_cells_delta_width",0)),height:110+parseInt(g.getLang("table.merge_cells_delta_height",0)),inline:1},{rows:p,cols:q,onaction:function(r){o.merge(n,r.cols,r.rows)},plugin_url:h})}else{o.merge()}},mceTableInsertRowBefore:function(n){n.insertRow(true)},mceTableInsertRowAfter:function(n){n.insertRow()},mceTableInsertColBefore:function(n){n.insertCol(true)},mceTableInsertColAfter:function(n){n.insertCol()},mceTableDeleteCol:function(n){n.deleteCols()},mceTableDeleteRow:function(n){n.deleteRows()},mceTableCutRow:function(n){m=n.cutRows()},mceTableCopyRow:function(n){m=n.copyRows()},mceTablePasteRowBefore:function(n){n.pasteRows(m,true)},mceTablePasteRowAfter:function(n){n.pasteRows(m)},mceTableDelete:function(n){n.deleteTable()}},function(o,n){g.addCommand(n,function(){var p=l();if(p){o(p);g.execCommand("mceRepaint");k()}})});e({mceInsertTable:function(n){f.open({url:h+"/table.htm",width:400+parseInt(g.getLang("table.table_delta_width",0)),height:320+parseInt(g.getLang("table.table_delta_height",0)),inline:1},{plugin_url:h,action:n?n.action:0})},mceTableRowProps:function(){f.open({url:h+"/row.htm",width:400+parseInt(g.getLang("table.rowprops_delta_width",0)),height:295+parseInt(g.getLang("table.rowprops_delta_height",0)),inline:1},{plugin_url:h})},mceTableCellProps:function(){f.open({url:h+"/cell.htm",width:400+parseInt(g.getLang("table.cellprops_delta_width",0)),height:295+parseInt(g.getLang("table.cellprops_delta_height",0)),inline:1},{plugin_url:h})}},function(o,n){g.addCommand(n,function(p,q){o(q)})})}});d.PluginManager.add("table",d.plugins.TablePlugin)})(tinymce); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/table/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/table/editor_plugin_src.js
new file mode 100644
index 00000000..54bab56c
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/table/editor_plugin_src.js
@@ -0,0 +1,1449 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function(tinymce) {
+ var each = tinymce.each;
+
+ // Checks if the selection/caret is at the start of the specified block element
+ function isAtStart(rng, par) {
+ var doc = par.ownerDocument, rng2 = doc.createRange(), elm;
+
+ rng2.setStartBefore(par);
+ rng2.setEnd(rng.endContainer, rng.endOffset);
+
+ elm = doc.createElement('body');
+ elm.appendChild(rng2.cloneContents());
+
+ // Check for text characters of other elements that should be treated as content
+ return elm.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi, '-').replace(/<[^>]+>/g, '').length == 0;
+ };
+
+ function getSpanVal(td, name) {
+ return parseInt(td.getAttribute(name) || 1);
+ }
+
+ /**
+ * Table Grid class.
+ */
+ function TableGrid(table, dom, selection) {
+ var grid, startPos, endPos, selectedCell;
+
+ buildGrid();
+ selectedCell = dom.getParent(selection.getStart(), 'th,td');
+ if (selectedCell) {
+ startPos = getPos(selectedCell);
+ endPos = findEndPos();
+ selectedCell = getCell(startPos.x, startPos.y);
+ }
+
+ function cloneNode(node, children) {
+ node = node.cloneNode(children);
+ node.removeAttribute('id');
+
+ return node;
+ }
+
+ function buildGrid() {
+ var startY = 0;
+
+ grid = [];
+
+ each(['thead', 'tbody', 'tfoot'], function(part) {
+ var rows = dom.select('> ' + part + ' tr', table);
+
+ each(rows, function(tr, y) {
+ y += startY;
+
+ each(dom.select('> td, > th', tr), function(td, x) {
+ var x2, y2, rowspan, colspan;
+
+ // Skip over existing cells produced by rowspan
+ if (grid[y]) {
+ while (grid[y][x])
+ x++;
+ }
+
+ // Get col/rowspan from cell
+ rowspan = getSpanVal(td, 'rowspan');
+ colspan = getSpanVal(td, 'colspan');
+
+ // Fill out rowspan/colspan right and down
+ for (y2 = y; y2 < y + rowspan; y2++) {
+ if (!grid[y2])
+ grid[y2] = [];
+
+ for (x2 = x; x2 < x + colspan; x2++) {
+ grid[y2][x2] = {
+ part : part,
+ real : y2 == y && x2 == x,
+ elm : td,
+ rowspan : rowspan,
+ colspan : colspan
+ };
+ }
+ }
+ });
+ });
+
+ startY += rows.length;
+ });
+ };
+
+ function getCell(x, y) {
+ var row;
+
+ row = grid[y];
+ if (row)
+ return row[x];
+ };
+
+ function setSpanVal(td, name, val) {
+ if (td) {
+ val = parseInt(val);
+
+ if (val === 1)
+ td.removeAttribute(name, 1);
+ else
+ td.setAttribute(name, val, 1);
+ }
+ }
+
+ function isCellSelected(cell) {
+ return cell && (dom.hasClass(cell.elm, 'mceSelected') || cell == selectedCell);
+ };
+
+ function getSelectedRows() {
+ var rows = [];
+
+ each(table.rows, function(row) {
+ each(row.cells, function(cell) {
+ if (dom.hasClass(cell, 'mceSelected') || cell == selectedCell.elm) {
+ rows.push(row);
+ return false;
+ }
+ });
+ });
+
+ return rows;
+ };
+
+ function deleteTable() {
+ var rng = dom.createRng();
+
+ rng.setStartAfter(table);
+ rng.setEndAfter(table);
+
+ selection.setRng(rng);
+
+ dom.remove(table);
+ };
+
+ function cloneCell(cell) {
+ var formatNode;
+
+ // Clone formats
+ tinymce.walk(cell, function(node) {
+ var curNode;
+
+ if (node.nodeType == 3) {
+ each(dom.getParents(node.parentNode, null, cell).reverse(), function(node) {
+ node = cloneNode(node, false);
+
+ if (!formatNode)
+ formatNode = curNode = node;
+ else if (curNode)
+ curNode.appendChild(node);
+
+ curNode = node;
+ });
+
+ // Add something to the inner node
+ if (curNode)
+ curNode.innerHTML = tinymce.isIE ? '&nbsp;' : '<br data-mce-bogus="1" />';
+
+ return false;
+ }
+ }, 'childNodes');
+
+ cell = cloneNode(cell, false);
+ setSpanVal(cell, 'rowSpan', 1);
+ setSpanVal(cell, 'colSpan', 1);
+
+ if (formatNode) {
+ cell.appendChild(formatNode);
+ } else {
+ if (!tinymce.isIE)
+ cell.innerHTML = '<br data-mce-bogus="1" />';
+ }
+
+ return cell;
+ };
+
+ function cleanup() {
+ var rng = dom.createRng();
+
+ // Empty rows
+ each(dom.select('tr', table), function(tr) {
+ if (tr.cells.length == 0)
+ dom.remove(tr);
+ });
+
+ // Empty table
+ if (dom.select('tr', table).length == 0) {
+ rng.setStartAfter(table);
+ rng.setEndAfter(table);
+ selection.setRng(rng);
+ dom.remove(table);
+ return;
+ }
+
+ // Empty header/body/footer
+ each(dom.select('thead,tbody,tfoot', table), function(part) {
+ if (part.rows.length == 0)
+ dom.remove(part);
+ });
+
+ // Restore selection to start position if it still exists
+ buildGrid();
+
+ // Restore the selection to the closest table position
+ row = grid[Math.min(grid.length - 1, startPos.y)];
+ if (row) {
+ selection.select(row[Math.min(row.length - 1, startPos.x)].elm, true);
+ selection.collapse(true);
+ }
+ };
+
+ function fillLeftDown(x, y, rows, cols) {
+ var tr, x2, r, c, cell;
+
+ tr = grid[y][x].elm.parentNode;
+ for (r = 1; r <= rows; r++) {
+ tr = dom.getNext(tr, 'tr');
+
+ if (tr) {
+ // Loop left to find real cell
+ for (x2 = x; x2 >= 0; x2--) {
+ cell = grid[y + r][x2].elm;
+
+ if (cell.parentNode == tr) {
+ // Append clones after
+ for (c = 1; c <= cols; c++)
+ dom.insertAfter(cloneCell(cell), cell);
+
+ break;
+ }
+ }
+
+ if (x2 == -1) {
+ // Insert nodes before first cell
+ for (c = 1; c <= cols; c++)
+ tr.insertBefore(cloneCell(tr.cells[0]), tr.cells[0]);
+ }
+ }
+ }
+ };
+
+ function split() {
+ each(grid, function(row, y) {
+ each(row, function(cell, x) {
+ var colSpan, rowSpan, newCell, i;
+
+ if (isCellSelected(cell)) {
+ cell = cell.elm;
+ colSpan = getSpanVal(cell, 'colspan');
+ rowSpan = getSpanVal(cell, 'rowspan');
+
+ if (colSpan > 1 || rowSpan > 1) {
+ setSpanVal(cell, 'rowSpan', 1);
+ setSpanVal(cell, 'colSpan', 1);
+
+ // Insert cells right
+ for (i = 0; i < colSpan - 1; i++)
+ dom.insertAfter(cloneCell(cell), cell);
+
+ fillLeftDown(x, y, rowSpan - 1, colSpan);
+ }
+ }
+ });
+ });
+ };
+
+ function merge(cell, cols, rows) {
+ var startX, startY, endX, endY, x, y, startCell, endCell, cell, children, count;
+
+ // Use specified cell and cols/rows
+ if (cell) {
+ pos = getPos(cell);
+ startX = pos.x;
+ startY = pos.y;
+ endX = startX + (cols - 1);
+ endY = startY + (rows - 1);
+ } else {
+ startPos = endPos = null;
+
+ // Calculate start/end pos by checking for selected cells in grid works better with context menu
+ each(grid, function(row, y) {
+ each(row, function(cell, x) {
+ if (isCellSelected(cell)) {
+ if (!startPos) {
+ startPos = {x: x, y: y};
+ }
+
+ endPos = {x: x, y: y};
+ }
+ });
+ });
+
+ // Use selection
+ startX = startPos.x;
+ startY = startPos.y;
+ endX = endPos.x;
+ endY = endPos.y;
+ }
+
+ // Find start/end cells
+ startCell = getCell(startX, startY);
+ endCell = getCell(endX, endY);
+
+ // Check if the cells exists and if they are of the same part for example tbody = tbody
+ if (startCell && endCell && startCell.part == endCell.part) {
+ // Split and rebuild grid
+ split();
+ buildGrid();
+
+ // Set row/col span to start cell
+ startCell = getCell(startX, startY).elm;
+ setSpanVal(startCell, 'colSpan', (endX - startX) + 1);
+ setSpanVal(startCell, 'rowSpan', (endY - startY) + 1);
+
+ // Remove other cells and add it's contents to the start cell
+ for (y = startY; y <= endY; y++) {
+ for (x = startX; x <= endX; x++) {
+ if (!grid[y] || !grid[y][x])
+ continue;
+
+ cell = grid[y][x].elm;
+
+ if (cell != startCell) {
+ // Move children to startCell
+ children = tinymce.grep(cell.childNodes);
+ each(children, function(node) {
+ startCell.appendChild(node);
+ });
+
+ // Remove bogus nodes if there is children in the target cell
+ if (children.length) {
+ children = tinymce.grep(startCell.childNodes);
+ count = 0;
+ each(children, function(node) {
+ if (node.nodeName == 'BR' && dom.getAttrib(node, 'data-mce-bogus') && count++ < children.length - 1)
+ startCell.removeChild(node);
+ });
+ }
+
+ // Remove cell
+ dom.remove(cell);
+ }
+ }
+ }
+
+ // Remove empty rows etc and restore caret location
+ cleanup();
+ }
+ };
+
+ function insertRow(before) {
+ var posY, cell, lastCell, x, rowElm, newRow, newCell, otherCell, rowSpan;
+
+ // Find first/last row
+ each(grid, function(row, y) {
+ each(row, function(cell, x) {
+ if (isCellSelected(cell)) {
+ cell = cell.elm;
+ rowElm = cell.parentNode;
+ newRow = cloneNode(rowElm, false);
+ posY = y;
+
+ if (before)
+ return false;
+ }
+ });
+
+ if (before)
+ return !posY;
+ });
+
+ for (x = 0; x < grid[0].length; x++) {
+ // Cell not found could be because of an invalid table structure
+ if (!grid[posY][x])
+ continue;
+
+ cell = grid[posY][x].elm;
+
+ if (cell != lastCell) {
+ if (!before) {
+ rowSpan = getSpanVal(cell, 'rowspan');
+ if (rowSpan > 1) {
+ setSpanVal(cell, 'rowSpan', rowSpan + 1);
+ continue;
+ }
+ } else {
+ // Check if cell above can be expanded
+ if (posY > 0 && grid[posY - 1][x]) {
+ otherCell = grid[posY - 1][x].elm;
+ rowSpan = getSpanVal(otherCell, 'rowSpan');
+ if (rowSpan > 1) {
+ setSpanVal(otherCell, 'rowSpan', rowSpan + 1);
+ continue;
+ }
+ }
+ }
+
+ // Insert new cell into new row
+ newCell = cloneCell(cell);
+ setSpanVal(newCell, 'colSpan', cell.colSpan);
+
+ newRow.appendChild(newCell);
+
+ lastCell = cell;
+ }
+ }
+
+ if (newRow.hasChildNodes()) {
+ if (!before)
+ dom.insertAfter(newRow, rowElm);
+ else
+ rowElm.parentNode.insertBefore(newRow, rowElm);
+ }
+ };
+
+ function insertCol(before) {
+ var posX, lastCell;
+
+ // Find first/last column
+ each(grid, function(row, y) {
+ each(row, function(cell, x) {
+ if (isCellSelected(cell)) {
+ posX = x;
+
+ if (before)
+ return false;
+ }
+ });
+
+ if (before)
+ return !posX;
+ });
+
+ each(grid, function(row, y) {
+ var cell, rowSpan, colSpan;
+
+ if (!row[posX])
+ return;
+
+ cell = row[posX].elm;
+ if (cell != lastCell) {
+ colSpan = getSpanVal(cell, 'colspan');
+ rowSpan = getSpanVal(cell, 'rowspan');
+
+ if (colSpan == 1) {
+ if (!before) {
+ dom.insertAfter(cloneCell(cell), cell);
+ fillLeftDown(posX, y, rowSpan - 1, colSpan);
+ } else {
+ cell.parentNode.insertBefore(cloneCell(cell), cell);
+ fillLeftDown(posX, y, rowSpan - 1, colSpan);
+ }
+ } else
+ setSpanVal(cell, 'colSpan', cell.colSpan + 1);
+
+ lastCell = cell;
+ }
+ });
+ };
+
+ function deleteCols() {
+ var cols = [];
+
+ // Get selected column indexes
+ each(grid, function(row, y) {
+ each(row, function(cell, x) {
+ if (isCellSelected(cell) && tinymce.inArray(cols, x) === -1) {
+ each(grid, function(row) {
+ var cell = row[x].elm, colSpan;
+
+ colSpan = getSpanVal(cell, 'colSpan');
+
+ if (colSpan > 1)
+ setSpanVal(cell, 'colSpan', colSpan - 1);
+ else
+ dom.remove(cell);
+ });
+
+ cols.push(x);
+ }
+ });
+ });
+
+ cleanup();
+ };
+
+ function deleteRows() {
+ var rows;
+
+ function deleteRow(tr) {
+ var nextTr, pos, lastCell;
+
+ nextTr = dom.getNext(tr, 'tr');
+
+ // Move down row spanned cells
+ each(tr.cells, function(cell) {
+ var rowSpan = getSpanVal(cell, 'rowSpan');
+
+ if (rowSpan > 1) {
+ setSpanVal(cell, 'rowSpan', rowSpan - 1);
+ pos = getPos(cell);
+ fillLeftDown(pos.x, pos.y, 1, 1);
+ }
+ });
+
+ // Delete cells
+ pos = getPos(tr.cells[0]);
+ each(grid[pos.y], function(cell) {
+ var rowSpan;
+
+ cell = cell.elm;
+
+ if (cell != lastCell) {
+ rowSpan = getSpanVal(cell, 'rowSpan');
+
+ if (rowSpan <= 1)
+ dom.remove(cell);
+ else
+ setSpanVal(cell, 'rowSpan', rowSpan - 1);
+
+ lastCell = cell;
+ }
+ });
+ };
+
+ // Get selected rows and move selection out of scope
+ rows = getSelectedRows();
+
+ // Delete all selected rows
+ each(rows.reverse(), function(tr) {
+ deleteRow(tr);
+ });
+
+ cleanup();
+ };
+
+ function cutRows() {
+ var rows = getSelectedRows();
+
+ dom.remove(rows);
+ cleanup();
+
+ return rows;
+ };
+
+ function copyRows() {
+ var rows = getSelectedRows();
+
+ each(rows, function(row, i) {
+ rows[i] = cloneNode(row, true);
+ });
+
+ return rows;
+ };
+
+ function pasteRows(rows, before) {
+ var selectedRows = getSelectedRows(),
+ targetRow = selectedRows[before ? 0 : selectedRows.length - 1],
+ targetCellCount = targetRow.cells.length;
+
+ // Calc target cell count
+ each(grid, function(row) {
+ var match;
+
+ targetCellCount = 0;
+ each(row, function(cell, x) {
+ if (cell.real)
+ targetCellCount += cell.colspan;
+
+ if (cell.elm.parentNode == targetRow)
+ match = 1;
+ });
+
+ if (match)
+ return false;
+ });
+
+ if (!before)
+ rows.reverse();
+
+ each(rows, function(row) {
+ var cellCount = row.cells.length, cell;
+
+ // Remove col/rowspans
+ for (i = 0; i < cellCount; i++) {
+ cell = row.cells[i];
+ setSpanVal(cell, 'colSpan', 1);
+ setSpanVal(cell, 'rowSpan', 1);
+ }
+
+ // Needs more cells
+ for (i = cellCount; i < targetCellCount; i++)
+ row.appendChild(cloneCell(row.cells[cellCount - 1]));
+
+ // Needs less cells
+ for (i = targetCellCount; i < cellCount; i++)
+ dom.remove(row.cells[i]);
+
+ // Add before/after
+ if (before)
+ targetRow.parentNode.insertBefore(row, targetRow);
+ else
+ dom.insertAfter(row, targetRow);
+ });
+
+ // Remove current selection
+ dom.removeClass(dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');
+ };
+
+ function getPos(target) {
+ var pos;
+
+ each(grid, function(row, y) {
+ each(row, function(cell, x) {
+ if (cell.elm == target) {
+ pos = {x : x, y : y};
+ return false;
+ }
+ });
+
+ return !pos;
+ });
+
+ return pos;
+ };
+
+ function setStartCell(cell) {
+ startPos = getPos(cell);
+ };
+
+ function findEndPos() {
+ var pos, maxX, maxY;
+
+ maxX = maxY = 0;
+
+ each(grid, function(row, y) {
+ each(row, function(cell, x) {
+ var colSpan, rowSpan;
+
+ if (isCellSelected(cell)) {
+ cell = grid[y][x];
+
+ if (x > maxX)
+ maxX = x;
+
+ if (y > maxY)
+ maxY = y;
+
+ if (cell.real) {
+ colSpan = cell.colspan - 1;
+ rowSpan = cell.rowspan - 1;
+
+ if (colSpan) {
+ if (x + colSpan > maxX)
+ maxX = x + colSpan;
+ }
+
+ if (rowSpan) {
+ if (y + rowSpan > maxY)
+ maxY = y + rowSpan;
+ }
+ }
+ }
+ });
+ });
+
+ return {x : maxX, y : maxY};
+ };
+
+ function setEndCell(cell) {
+ var startX, startY, endX, endY, maxX, maxY, colSpan, rowSpan;
+
+ endPos = getPos(cell);
+
+ if (startPos && endPos) {
+ // Get start/end positions
+ startX = Math.min(startPos.x, endPos.x);
+ startY = Math.min(startPos.y, endPos.y);
+ endX = Math.max(startPos.x, endPos.x);
+ endY = Math.max(startPos.y, endPos.y);
+
+ // Expand end positon to include spans
+ maxX = endX;
+ maxY = endY;
+
+ // Expand startX
+ for (y = startY; y <= maxY; y++) {
+ cell = grid[y][startX];
+
+ if (!cell.real) {
+ if (startX - (cell.colspan - 1) < startX)
+ startX -= cell.colspan - 1;
+ }
+ }
+
+ // Expand startY
+ for (x = startX; x <= maxX; x++) {
+ cell = grid[startY][x];
+
+ if (!cell.real) {
+ if (startY - (cell.rowspan - 1) < startY)
+ startY -= cell.rowspan - 1;
+ }
+ }
+
+ // Find max X, Y
+ for (y = startY; y <= endY; y++) {
+ for (x = startX; x <= endX; x++) {
+ cell = grid[y][x];
+
+ if (cell.real) {
+ colSpan = cell.colspan - 1;
+ rowSpan = cell.rowspan - 1;
+
+ if (colSpan) {
+ if (x + colSpan > maxX)
+ maxX = x + colSpan;
+ }
+
+ if (rowSpan) {
+ if (y + rowSpan > maxY)
+ maxY = y + rowSpan;
+ }
+ }
+ }
+ }
+
+ // Remove current selection
+ dom.removeClass(dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');
+
+ // Add new selection
+ for (y = startY; y <= maxY; y++) {
+ for (x = startX; x <= maxX; x++) {
+ if (grid[y][x])
+ dom.addClass(grid[y][x].elm, 'mceSelected');
+ }
+ }
+ }
+ };
+
+ // Expose to public
+ tinymce.extend(this, {
+ deleteTable : deleteTable,
+ split : split,
+ merge : merge,
+ insertRow : insertRow,
+ insertCol : insertCol,
+ deleteCols : deleteCols,
+ deleteRows : deleteRows,
+ cutRows : cutRows,
+ copyRows : copyRows,
+ pasteRows : pasteRows,
+ getPos : getPos,
+ setStartCell : setStartCell,
+ setEndCell : setEndCell
+ });
+ };
+
+ tinymce.create('tinymce.plugins.TablePlugin', {
+ init : function(ed, url) {
+ var winMan, clipboardRows, hasCellSelection = true; // Might be selected cells on reload
+
+ function createTableGrid(node) {
+ var selection = ed.selection, tblElm = ed.dom.getParent(node || selection.getNode(), 'table');
+
+ if (tblElm)
+ return new TableGrid(tblElm, ed.dom, selection);
+ };
+
+ function cleanup() {
+ // Restore selection possibilities
+ ed.getBody().style.webkitUserSelect = '';
+
+ if (hasCellSelection) {
+ ed.dom.removeClass(ed.dom.select('td.mceSelected,th.mceSelected'), 'mceSelected');
+ hasCellSelection = false;
+ }
+ };
+
+ // Register buttons
+ each([
+ ['table', 'table.desc', 'mceInsertTable', true],
+ ['delete_table', 'table.del', 'mceTableDelete'],
+ ['delete_col', 'table.delete_col_desc', 'mceTableDeleteCol'],
+ ['delete_row', 'table.delete_row_desc', 'mceTableDeleteRow'],
+ ['col_after', 'table.col_after_desc', 'mceTableInsertColAfter'],
+ ['col_before', 'table.col_before_desc', 'mceTableInsertColBefore'],
+ ['row_after', 'table.row_after_desc', 'mceTableInsertRowAfter'],
+ ['row_before', 'table.row_before_desc', 'mceTableInsertRowBefore'],
+ ['row_props', 'table.row_desc', 'mceTableRowProps', true],
+ ['cell_props', 'table.cell_desc', 'mceTableCellProps', true],
+ ['split_cells', 'table.split_cells_desc', 'mceTableSplitCells', true],
+ ['merge_cells', 'table.merge_cells_desc', 'mceTableMergeCells', true]
+ ], function(c) {
+ ed.addButton(c[0], {title : c[1], cmd : c[2], ui : c[3]});
+ });
+
+ // Select whole table is a table border is clicked
+ if (!tinymce.isIE) {
+ ed.onClick.add(function(ed, e) {
+ e = e.target;
+
+ if (e.nodeName === 'TABLE') {
+ ed.selection.select(e);
+ ed.nodeChanged();
+ }
+ });
+ }
+
+ ed.onPreProcess.add(function(ed, args) {
+ var nodes, i, node, dom = ed.dom, value;
+
+ nodes = dom.select('table', args.node);
+ i = nodes.length;
+ while (i--) {
+ node = nodes[i];
+ dom.setAttrib(node, 'data-mce-style', '');
+
+ if ((value = dom.getAttrib(node, 'width'))) {
+ dom.setStyle(node, 'width', value);
+ dom.setAttrib(node, 'width', '');
+ }
+
+ if ((value = dom.getAttrib(node, 'height'))) {
+ dom.setStyle(node, 'height', value);
+ dom.setAttrib(node, 'height', '');
+ }
+ }
+ });
+
+ // Handle node change updates
+ ed.onNodeChange.add(function(ed, cm, n) {
+ var p;
+
+ n = ed.selection.getStart();
+ p = ed.dom.getParent(n, 'td,th,caption');
+ cm.setActive('table', n.nodeName === 'TABLE' || !!p);
+
+ // Disable table tools if we are in caption
+ if (p && p.nodeName === 'CAPTION')
+ p = 0;
+
+ cm.setDisabled('delete_table', !p);
+ cm.setDisabled('delete_col', !p);
+ cm.setDisabled('delete_table', !p);
+ cm.setDisabled('delete_row', !p);
+ cm.setDisabled('col_after', !p);
+ cm.setDisabled('col_before', !p);
+ cm.setDisabled('row_after', !p);
+ cm.setDisabled('row_before', !p);
+ cm.setDisabled('row_props', !p);
+ cm.setDisabled('cell_props', !p);
+ cm.setDisabled('split_cells', !p);
+ cm.setDisabled('merge_cells', !p);
+ });
+
+ ed.onInit.add(function(ed) {
+ var startTable, startCell, dom = ed.dom, tableGrid;
+
+ winMan = ed.windowManager;
+
+ // Add cell selection logic
+ ed.onMouseDown.add(function(ed, e) {
+ if (e.button != 2) {
+ cleanup();
+
+ startCell = dom.getParent(e.target, 'td,th');
+ startTable = dom.getParent(startCell, 'table');
+ }
+ });
+
+ dom.bind(ed.getDoc(), 'mouseover', function(e) {
+ var sel, table, target = e.target;
+
+ if (startCell && (tableGrid || target != startCell) && (target.nodeName == 'TD' || target.nodeName == 'TH')) {
+ table = dom.getParent(target, 'table');
+ if (table == startTable) {
+ if (!tableGrid) {
+ tableGrid = createTableGrid(table);
+ tableGrid.setStartCell(startCell);
+
+ ed.getBody().style.webkitUserSelect = 'none';
+ }
+
+ tableGrid.setEndCell(target);
+ hasCellSelection = true;
+ }
+
+ // Remove current selection
+ sel = ed.selection.getSel();
+
+ try {
+ if (sel.removeAllRanges)
+ sel.removeAllRanges();
+ else
+ sel.empty();
+ } catch (ex) {
+ // IE9 might throw errors here
+ }
+
+ e.preventDefault();
+ }
+ });
+
+ ed.onMouseUp.add(function(ed, e) {
+ var rng, sel = ed.selection, selectedCells, nativeSel = sel.getSel(), walker, node, lastNode, endNode;
+
+ // Move selection to startCell
+ if (startCell) {
+ if (tableGrid)
+ ed.getBody().style.webkitUserSelect = '';
+
+ function setPoint(node, start) {
+ var walker = new tinymce.dom.TreeWalker(node, node);
+
+ do {
+ // Text node
+ if (node.nodeType == 3 && tinymce.trim(node.nodeValue).length != 0) {
+ if (start)
+ rng.setStart(node, 0);
+ else
+ rng.setEnd(node, node.nodeValue.length);
+
+ return;
+ }
+
+ // BR element
+ if (node.nodeName == 'BR') {
+ if (start)
+ rng.setStartBefore(node);
+ else
+ rng.setEndBefore(node);
+
+ return;
+ }
+ } while (node = (start ? walker.next() : walker.prev()));
+ }
+
+ // Try to expand text selection as much as we can only Gecko supports cell selection
+ selectedCells = dom.select('td.mceSelected,th.mceSelected');
+ if (selectedCells.length > 0) {
+ rng = dom.createRng();
+ node = selectedCells[0];
+ endNode = selectedCells[selectedCells.length - 1];
+ rng.setStartBefore(node);
+ rng.setEndAfter(node);
+
+ setPoint(node, 1);
+ walker = new tinymce.dom.TreeWalker(node, dom.getParent(selectedCells[0], 'table'));
+
+ do {
+ if (node.nodeName == 'TD' || node.nodeName == 'TH') {
+ if (!dom.hasClass(node, 'mceSelected'))
+ break;
+
+ lastNode = node;
+ }
+ } while (node = walker.next());
+
+ setPoint(lastNode);
+
+ sel.setRng(rng);
+ }
+
+ ed.nodeChanged();
+ startCell = tableGrid = startTable = null;
+ }
+ });
+
+ ed.onKeyUp.add(function(ed, e) {
+ cleanup();
+ });
+
+ ed.onKeyDown.add(function (ed, e) {
+ fixTableCellSelection(ed);
+ });
+
+ ed.onMouseDown.add(function (ed, e) {
+ if (e.button != 2) {
+ fixTableCellSelection(ed);
+ }
+ });
+ function tableCellSelected(ed, rng, n, currentCell) {
+ // The decision of when a table cell is selected is somewhat involved. The fact that this code is
+ // required is actually a pointer to the root cause of this bug. A cell is selected when the start
+ // and end offsets are 0, the start container is a text, and the selection node is either a TR (most cases)
+ // or the parent of the table (in the case of the selection containing the last cell of a table).
+ var TEXT_NODE = 3, table = ed.dom.getParent(rng.startContainer, 'TABLE'),
+ tableParent, allOfCellSelected, tableCellSelection;
+ if (table)
+ tableParent = table.parentNode;
+ allOfCellSelected =rng.startContainer.nodeType == TEXT_NODE &&
+ rng.startOffset == 0 &&
+ rng.endOffset == 0 &&
+ currentCell &&
+ (n.nodeName=="TR" || n==tableParent);
+ tableCellSelection = (n.nodeName=="TD"||n.nodeName=="TH")&& !currentCell;
+ return allOfCellSelected || tableCellSelection;
+ // return false;
+ }
+
+ // this nasty hack is here to work around some WebKit selection bugs.
+ function fixTableCellSelection(ed) {
+ if (!tinymce.isWebKit)
+ return;
+
+ var rng = ed.selection.getRng();
+ var n = ed.selection.getNode();
+ var currentCell = ed.dom.getParent(rng.startContainer, 'TD,TH');
+
+ if (!tableCellSelected(ed, rng, n, currentCell))
+ return;
+ if (!currentCell) {
+ currentCell=n;
+ }
+
+ // Get the very last node inside the table cell
+ var end = currentCell.lastChild;
+ while (end.lastChild)
+ end = end.lastChild;
+
+ // Select the entire table cell. Nothing outside of the table cell should be selected.
+ rng.setEnd(end, end.nodeValue.length);
+ ed.selection.setRng(rng);
+ }
+ ed.plugins.table.fixTableCellSelection=fixTableCellSelection;
+
+ // Add context menu
+ if (ed && ed.plugins.contextmenu) {
+ ed.plugins.contextmenu.onContextMenu.add(function(th, m, e) {
+ var sm, se = ed.selection, el = se.getNode() || ed.getBody();
+
+ if (ed.dom.getParent(e, 'td') || ed.dom.getParent(e, 'th') || ed.dom.select('td.mceSelected,th.mceSelected').length) {
+ m.removeAll();
+
+ if (el.nodeName == 'A' && !ed.dom.getAttrib(el, 'name')) {
+ m.add({title : 'advanced.link_desc', icon : 'link', cmd : ed.plugins.advlink ? 'mceAdvLink' : 'mceLink', ui : true});
+ m.add({title : 'advanced.unlink_desc', icon : 'unlink', cmd : 'UnLink'});
+ m.addSeparator();
+ }
+
+ if (el.nodeName == 'IMG' && el.className.indexOf('mceItem') == -1) {
+ m.add({title : 'advanced.image_desc', icon : 'image', cmd : ed.plugins.advimage ? 'mceAdvImage' : 'mceImage', ui : true});
+ m.addSeparator();
+ }
+
+ m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable', value : {action : 'insert'}});
+ m.add({title : 'table.props_desc', icon : 'table_props', cmd : 'mceInsertTable'});
+ m.add({title : 'table.del', icon : 'delete_table', cmd : 'mceTableDelete'});
+ m.addSeparator();
+
+ // Cell menu
+ sm = m.addMenu({title : 'table.cell'});
+ sm.add({title : 'table.cell_desc', icon : 'cell_props', cmd : 'mceTableCellProps'});
+ sm.add({title : 'table.split_cells_desc', icon : 'split_cells', cmd : 'mceTableSplitCells'});
+ sm.add({title : 'table.merge_cells_desc', icon : 'merge_cells', cmd : 'mceTableMergeCells'});
+
+ // Row menu
+ sm = m.addMenu({title : 'table.row'});
+ sm.add({title : 'table.row_desc', icon : 'row_props', cmd : 'mceTableRowProps'});
+ sm.add({title : 'table.row_before_desc', icon : 'row_before', cmd : 'mceTableInsertRowBefore'});
+ sm.add({title : 'table.row_after_desc', icon : 'row_after', cmd : 'mceTableInsertRowAfter'});
+ sm.add({title : 'table.delete_row_desc', icon : 'delete_row', cmd : 'mceTableDeleteRow'});
+ sm.addSeparator();
+ sm.add({title : 'table.cut_row_desc', icon : 'cut', cmd : 'mceTableCutRow'});
+ sm.add({title : 'table.copy_row_desc', icon : 'copy', cmd : 'mceTableCopyRow'});
+ sm.add({title : 'table.paste_row_before_desc', icon : 'paste', cmd : 'mceTablePasteRowBefore'}).setDisabled(!clipboardRows);
+ sm.add({title : 'table.paste_row_after_desc', icon : 'paste', cmd : 'mceTablePasteRowAfter'}).setDisabled(!clipboardRows);
+
+ // Column menu
+ sm = m.addMenu({title : 'table.col'});
+ sm.add({title : 'table.col_before_desc', icon : 'col_before', cmd : 'mceTableInsertColBefore'});
+ sm.add({title : 'table.col_after_desc', icon : 'col_after', cmd : 'mceTableInsertColAfter'});
+ sm.add({title : 'table.delete_col_desc', icon : 'delete_col', cmd : 'mceTableDeleteCol'});
+ } else
+ m.add({title : 'table.desc', icon : 'table', cmd : 'mceInsertTable'});
+ });
+ }
+
+ // Fix to allow navigating up and down in a table in WebKit browsers.
+ if (tinymce.isWebKit) {
+ function moveSelection(ed, e) {
+ var VK = tinymce.VK;
+ var key = e.keyCode;
+
+ function handle(upBool, sourceNode, event) {
+ var siblingDirection = upBool ? 'previousSibling' : 'nextSibling';
+ var currentRow = ed.dom.getParent(sourceNode, 'tr');
+ var siblingRow = currentRow[siblingDirection];
+
+ if (siblingRow) {
+ moveCursorToRow(ed, sourceNode, siblingRow, upBool);
+ tinymce.dom.Event.cancel(event);
+ return true;
+ } else {
+ var tableNode = ed.dom.getParent(currentRow, 'table');
+ var middleNode = currentRow.parentNode;
+ var parentNodeName = middleNode.nodeName.toLowerCase();
+ if (parentNodeName === 'tbody' || parentNodeName === (upBool ? 'tfoot' : 'thead')) {
+ var targetParent = getTargetParent(upBool, tableNode, middleNode, 'tbody');
+ if (targetParent !== null) {
+ return moveToRowInTarget(upBool, targetParent, sourceNode, event);
+ }
+ }
+ return escapeTable(upBool, currentRow, siblingDirection, tableNode, event);
+ }
+ }
+
+ function getTargetParent(upBool, topNode, secondNode, nodeName) {
+ var tbodies = ed.dom.select('>' + nodeName, topNode);
+ var position = tbodies.indexOf(secondNode);
+ if (upBool && position === 0 || !upBool && position === tbodies.length - 1) {
+ return getFirstHeadOrFoot(upBool, topNode);
+ } else if (position === -1) {
+ var topOrBottom = secondNode.tagName.toLowerCase() === 'thead' ? 0 : tbodies.length - 1;
+ return tbodies[topOrBottom];
+ } else {
+ return tbodies[position + (upBool ? -1 : 1)];
+ }
+ }
+
+ function getFirstHeadOrFoot(upBool, parent) {
+ var tagName = upBool ? 'thead' : 'tfoot';
+ var headOrFoot = ed.dom.select('>' + tagName, parent);
+ return headOrFoot.length !== 0 ? headOrFoot[0] : null;
+ }
+
+ function moveToRowInTarget(upBool, targetParent, sourceNode, event) {
+ var targetRow = getChildForDirection(targetParent, upBool);
+ targetRow && moveCursorToRow(ed, sourceNode, targetRow, upBool);
+ tinymce.dom.Event.cancel(event);
+ return true;
+ }
+
+ function escapeTable(upBool, currentRow, siblingDirection, table, event) {
+ var tableSibling = table[siblingDirection];
+ if (tableSibling) {
+ moveCursorToStartOfElement(tableSibling);
+ return true;
+ } else {
+ var parentCell = ed.dom.getParent(table, 'td,th');
+ if (parentCell) {
+ return handle(upBool, parentCell, event);
+ } else {
+ var backUpSibling = getChildForDirection(currentRow, !upBool);
+ moveCursorToStartOfElement(backUpSibling);
+ return tinymce.dom.Event.cancel(event);
+ }
+ }
+ }
+
+ function getChildForDirection(parent, up) {
+ var child = parent && parent[up ? 'lastChild' : 'firstChild'];
+ // BR is not a valid table child to return in this case we return the table cell
+ return child && child.nodeName === 'BR' ? ed.dom.getParent(child, 'td,th') : child;
+ }
+
+ function moveCursorToStartOfElement(n) {
+ ed.selection.setCursorLocation(n, 0);
+ }
+
+ function isVerticalMovement() {
+ return key == VK.UP || key == VK.DOWN;
+ }
+
+ function isInTable(ed) {
+ var node = ed.selection.getNode();
+ var currentRow = ed.dom.getParent(node, 'tr');
+ return currentRow !== null;
+ }
+
+ function columnIndex(column) {
+ var colIndex = 0;
+ var c = column;
+ while (c.previousSibling) {
+ c = c.previousSibling;
+ colIndex = colIndex + getSpanVal(c, "colspan");
+ }
+ return colIndex;
+ }
+
+ function findColumn(rowElement, columnIndex) {
+ var c = 0;
+ var r = 0;
+ each(rowElement.children, function(cell, i) {
+ c = c + getSpanVal(cell, "colspan");
+ r = i;
+ if (c > columnIndex)
+ return false;
+ });
+ return r;
+ }
+
+ function moveCursorToRow(ed, node, row, upBool) {
+ var srcColumnIndex = columnIndex(ed.dom.getParent(node, 'td,th'));
+ var tgtColumnIndex = findColumn(row, srcColumnIndex);
+ var tgtNode = row.childNodes[tgtColumnIndex];
+ var rowCellTarget = getChildForDirection(tgtNode, upBool);
+ moveCursorToStartOfElement(rowCellTarget || tgtNode);
+ }
+
+ function shouldFixCaret(preBrowserNode) {
+ var newNode = ed.selection.getNode();
+ var newParent = ed.dom.getParent(newNode, 'td,th');
+ var oldParent = ed.dom.getParent(preBrowserNode, 'td,th');
+ return newParent && newParent !== oldParent && checkSameParentTable(newParent, oldParent)
+ }
+
+ function checkSameParentTable(nodeOne, NodeTwo) {
+ return ed.dom.getParent(nodeOne, 'TABLE') === ed.dom.getParent(NodeTwo, 'TABLE');
+ }
+
+ if (isVerticalMovement() && isInTable(ed)) {
+ var preBrowserNode = ed.selection.getNode();
+ setTimeout(function() {
+ if (shouldFixCaret(preBrowserNode)) {
+ handle(!e.shiftKey && key === VK.UP, preBrowserNode, e);
+ }
+ }, 0);
+ }
+ }
+
+ ed.onKeyDown.add(moveSelection);
+ }
+
+ // Fixes an issue on Gecko where it's impossible to place the caret behind a table
+ // This fix will force a paragraph element after the table but only when the forced_root_block setting is enabled
+ function fixTableCaretPos() {
+ var last;
+
+ // Skip empty text nodes form the end
+ for (last = ed.getBody().lastChild; last && last.nodeType == 3 && !last.nodeValue.length; last = last.previousSibling) ;
+
+ if (last && last.nodeName == 'TABLE') {
+ if (ed.settings.forced_root_block)
+ ed.dom.add(ed.getBody(), ed.settings.forced_root_block, null, tinymce.isIE ? '&nbsp;' : '<br data-mce-bogus="1" />');
+ else
+ ed.dom.add(ed.getBody(), 'br', {'data-mce-bogus': '1'});
+ }
+ };
+
+ // Fixes an bug where it's impossible to place the caret before a table in Gecko
+ // this fix solves it by detecting when the caret is at the beginning of such a table
+ // and then manually moves the caret infront of the table
+ if (tinymce.isGecko) {
+ ed.onKeyDown.add(function(ed, e) {
+ var rng, table, dom = ed.dom;
+
+ // On gecko it's not possible to place the caret before a table
+ if (e.keyCode == 37 || e.keyCode == 38) {
+ rng = ed.selection.getRng();
+ table = dom.getParent(rng.startContainer, 'table');
+
+ if (table && ed.getBody().firstChild == table) {
+ if (isAtStart(rng, table)) {
+ rng = dom.createRng();
+
+ rng.setStartBefore(table);
+ rng.setEndBefore(table);
+
+ ed.selection.setRng(rng);
+
+ e.preventDefault();
+ }
+ }
+ }
+ });
+ }
+
+ ed.onKeyUp.add(fixTableCaretPos);
+ ed.onSetContent.add(fixTableCaretPos);
+ ed.onVisualAid.add(fixTableCaretPos);
+
+ ed.onPreProcess.add(function(ed, o) {
+ var last = o.node.lastChild;
+
+ if (last && (last.nodeName == "BR" || (last.childNodes.length == 1 && (last.firstChild.nodeName == 'BR' || last.firstChild.nodeValue == '\u00a0'))) && last.previousSibling && last.previousSibling.nodeName == "TABLE") {
+ ed.dom.remove(last);
+ }
+ });
+
+
+ /**
+ * Fixes bug in Gecko where shift-enter in table cell does not place caret on new line
+ */
+ if (tinymce.isGecko) {
+ ed.onKeyDown.add(function(ed, e) {
+ if (e.keyCode === tinymce.VK.ENTER && e.shiftKey) {
+ var node = ed.selection.getRng().startContainer;
+ var tableCell = dom.getParent(node, 'td,th');
+ if (tableCell) {
+ var zeroSizedNbsp = ed.getDoc().createTextNode("\uFEFF");
+ dom.insertAfter(zeroSizedNbsp, node);
+ }
+ }
+ });
+ }
+
+
+ fixTableCaretPos();
+ ed.startContent = ed.getContent({format : 'raw'});
+ });
+
+ // Register action commands
+ each({
+ mceTableSplitCells : function(grid) {
+ grid.split();
+ },
+
+ mceTableMergeCells : function(grid) {
+ var rowSpan, colSpan, cell;
+
+ cell = ed.dom.getParent(ed.selection.getNode(), 'th,td');
+ if (cell) {
+ rowSpan = cell.rowSpan;
+ colSpan = cell.colSpan;
+ }
+
+ if (!ed.dom.select('td.mceSelected,th.mceSelected').length) {
+ winMan.open({
+ url : url + '/merge_cells.htm',
+ width : 240 + parseInt(ed.getLang('table.merge_cells_delta_width', 0)),
+ height : 110 + parseInt(ed.getLang('table.merge_cells_delta_height', 0)),
+ inline : 1
+ }, {
+ rows : rowSpan,
+ cols : colSpan,
+ onaction : function(data) {
+ grid.merge(cell, data.cols, data.rows);
+ },
+ plugin_url : url
+ });
+ } else
+ grid.merge();
+ },
+
+ mceTableInsertRowBefore : function(grid) {
+ grid.insertRow(true);
+ },
+
+ mceTableInsertRowAfter : function(grid) {
+ grid.insertRow();
+ },
+
+ mceTableInsertColBefore : function(grid) {
+ grid.insertCol(true);
+ },
+
+ mceTableInsertColAfter : function(grid) {
+ grid.insertCol();
+ },
+
+ mceTableDeleteCol : function(grid) {
+ grid.deleteCols();
+ },
+
+ mceTableDeleteRow : function(grid) {
+ grid.deleteRows();
+ },
+
+ mceTableCutRow : function(grid) {
+ clipboardRows = grid.cutRows();
+ },
+
+ mceTableCopyRow : function(grid) {
+ clipboardRows = grid.copyRows();
+ },
+
+ mceTablePasteRowBefore : function(grid) {
+ grid.pasteRows(clipboardRows, true);
+ },
+
+ mceTablePasteRowAfter : function(grid) {
+ grid.pasteRows(clipboardRows);
+ },
+
+ mceTableDelete : function(grid) {
+ grid.deleteTable();
+ }
+ }, function(func, name) {
+ ed.addCommand(name, function() {
+ var grid = createTableGrid();
+
+ if (grid) {
+ func(grid);
+ ed.execCommand('mceRepaint');
+ cleanup();
+ }
+ });
+ });
+
+ // Register dialog commands
+ each({
+ mceInsertTable : function(val) {
+ winMan.open({
+ url : url + '/table.htm',
+ width : 400 + parseInt(ed.getLang('table.table_delta_width', 0)),
+ height : 320 + parseInt(ed.getLang('table.table_delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url,
+ action : val ? val.action : 0
+ });
+ },
+
+ mceTableRowProps : function() {
+ winMan.open({
+ url : url + '/row.htm',
+ width : 400 + parseInt(ed.getLang('table.rowprops_delta_width', 0)),
+ height : 295 + parseInt(ed.getLang('table.rowprops_delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url
+ });
+ },
+
+ mceTableCellProps : function() {
+ winMan.open({
+ url : url + '/cell.htm',
+ width : 400 + parseInt(ed.getLang('table.cellprops_delta_width', 0)),
+ height : 295 + parseInt(ed.getLang('table.cellprops_delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url
+ });
+ }
+ }, function(func, name) {
+ ed.addCommand(name, function(ui, val) {
+ func(val);
+ });
+ });
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('table', tinymce.plugins.TablePlugin);
+})(tinymce);
diff --git a/askbot/media/js/tinymce/plugins/table/js/cell.js b/askbot/media/js/tinymce/plugins/table/js/cell.js
new file mode 100644
index 00000000..02ecf22c
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/table/js/cell.js
@@ -0,0 +1,319 @@
+tinyMCEPopup.requireLangPack();
+
+var ed;
+
+function init() {
+ ed = tinyMCEPopup.editor;
+ tinyMCEPopup.resizeToInnerSize();
+
+ document.getElementById('backgroundimagebrowsercontainer').innerHTML = getBrowserHTML('backgroundimagebrowser','backgroundimage','image','table');
+ document.getElementById('bordercolor_pickcontainer').innerHTML = getColorPickerHTML('bordercolor_pick','bordercolor');
+ document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor')
+
+ var inst = ed;
+ var tdElm = ed.dom.getParent(ed.selection.getStart(), "td,th");
+ var formObj = document.forms[0];
+ var st = ed.dom.parseStyle(ed.dom.getAttrib(tdElm, "style"));
+
+ // Get table cell data
+ var celltype = tdElm.nodeName.toLowerCase();
+ var align = ed.dom.getAttrib(tdElm, 'align');
+ var valign = ed.dom.getAttrib(tdElm, 'valign');
+ var width = trimSize(getStyle(tdElm, 'width', 'width'));
+ var height = trimSize(getStyle(tdElm, 'height', 'height'));
+ var bordercolor = convertRGBToHex(getStyle(tdElm, 'bordercolor', 'borderLeftColor'));
+ var bgcolor = convertRGBToHex(getStyle(tdElm, 'bgcolor', 'backgroundColor'));
+ var className = ed.dom.getAttrib(tdElm, 'class');
+ var backgroundimage = getStyle(tdElm, 'background', 'backgroundImage').replace(new RegExp("url\\(['\"]?([^'\"]*)['\"]?\\)", 'gi'), "$1");
+ var id = ed.dom.getAttrib(tdElm, 'id');
+ var lang = ed.dom.getAttrib(tdElm, 'lang');
+ var dir = ed.dom.getAttrib(tdElm, 'dir');
+ var scope = ed.dom.getAttrib(tdElm, 'scope');
+
+ // Setup form
+ addClassesToList('class', 'table_cell_styles');
+ TinyMCE_EditableSelects.init();
+
+ if (!ed.dom.hasClass(tdElm, 'mceSelected')) {
+ formObj.bordercolor.value = bordercolor;
+ formObj.bgcolor.value = bgcolor;
+ formObj.backgroundimage.value = backgroundimage;
+ formObj.width.value = width;
+ formObj.height.value = height;
+ formObj.id.value = id;
+ formObj.lang.value = lang;
+ formObj.style.value = ed.dom.serializeStyle(st);
+ selectByValue(formObj, 'align', align);
+ selectByValue(formObj, 'valign', valign);
+ selectByValue(formObj, 'class', className, true, true);
+ selectByValue(formObj, 'celltype', celltype);
+ selectByValue(formObj, 'dir', dir);
+ selectByValue(formObj, 'scope', scope);
+
+ // Resize some elements
+ if (isVisible('backgroundimagebrowser'))
+ document.getElementById('backgroundimage').style.width = '180px';
+
+ updateColor('bordercolor_pick', 'bordercolor');
+ updateColor('bgcolor_pick', 'bgcolor');
+ } else
+ tinyMCEPopup.dom.hide('action');
+}
+
+function updateAction() {
+ var el, inst = ed, tdElm, trElm, tableElm, formObj = document.forms[0];
+
+ if (!AutoValidator.validate(formObj)) {
+ tinyMCEPopup.alert(AutoValidator.getErrorMessages(formObj).join('. ') + '.');
+ return false;
+ }
+
+ tinyMCEPopup.restoreSelection();
+ el = ed.selection.getStart();
+ tdElm = ed.dom.getParent(el, "td,th");
+ trElm = ed.dom.getParent(el, "tr");
+ tableElm = ed.dom.getParent(el, "table");
+
+ // Cell is selected
+ if (ed.dom.hasClass(tdElm, 'mceSelected')) {
+ // Update all selected sells
+ tinymce.each(ed.dom.select('td.mceSelected,th.mceSelected'), function(td) {
+ updateCell(td);
+ });
+
+ ed.addVisual();
+ ed.nodeChanged();
+ inst.execCommand('mceEndUndoLevel');
+ tinyMCEPopup.close();
+ return;
+ }
+
+ switch (getSelectValue(formObj, 'action')) {
+ case "cell":
+ var celltype = getSelectValue(formObj, 'celltype');
+ var scope = getSelectValue(formObj, 'scope');
+
+ function doUpdate(s) {
+ if (s) {
+ updateCell(tdElm);
+
+ ed.addVisual();
+ ed.nodeChanged();
+ inst.execCommand('mceEndUndoLevel');
+ tinyMCEPopup.close();
+ }
+ };
+
+ if (ed.getParam("accessibility_warnings", 1)) {
+ if (celltype == "th" && scope == "")
+ tinyMCEPopup.confirm(ed.getLang('table_dlg.missing_scope', '', true), doUpdate);
+ else
+ doUpdate(1);
+
+ return;
+ }
+
+ updateCell(tdElm);
+ break;
+
+ case "row":
+ var cell = trElm.firstChild;
+
+ if (cell.nodeName != "TD" && cell.nodeName != "TH")
+ cell = nextCell(cell);
+
+ do {
+ cell = updateCell(cell, true);
+ } while ((cell = nextCell(cell)) != null);
+
+ break;
+
+ case "col":
+ var curr, col = 0, cell = trElm.firstChild, rows = tableElm.getElementsByTagName("tr");
+
+ if (cell.nodeName != "TD" && cell.nodeName != "TH")
+ cell = nextCell(cell);
+
+ do {
+ if (cell == tdElm)
+ break;
+ col += cell.getAttribute("colspan")?cell.getAttribute("colspan"):1;
+ } while ((cell = nextCell(cell)) != null);
+
+ for (var i=0; i<rows.length; i++) {
+ cell = rows[i].firstChild;
+
+ if (cell.nodeName != "TD" && cell.nodeName != "TH")
+ cell = nextCell(cell);
+
+ curr = 0;
+ do {
+ if (curr == col) {
+ cell = updateCell(cell, true);
+ break;
+ }
+ curr += cell.getAttribute("colspan")?cell.getAttribute("colspan"):1;
+ } while ((cell = nextCell(cell)) != null);
+ }
+
+ break;
+
+ case "all":
+ var rows = tableElm.getElementsByTagName("tr");
+
+ for (var i=0; i<rows.length; i++) {
+ var cell = rows[i].firstChild;
+
+ if (cell.nodeName != "TD" && cell.nodeName != "TH")
+ cell = nextCell(cell);
+
+ do {
+ cell = updateCell(cell, true);
+ } while ((cell = nextCell(cell)) != null);
+ }
+
+ break;
+ }
+
+ ed.addVisual();
+ ed.nodeChanged();
+ inst.execCommand('mceEndUndoLevel');
+ tinyMCEPopup.close();
+}
+
+function nextCell(elm) {
+ while ((elm = elm.nextSibling) != null) {
+ if (elm.nodeName == "TD" || elm.nodeName == "TH")
+ return elm;
+ }
+
+ return null;
+}
+
+function updateCell(td, skip_id) {
+ var inst = ed;
+ var formObj = document.forms[0];
+ var curCellType = td.nodeName.toLowerCase();
+ var celltype = getSelectValue(formObj, 'celltype');
+ var doc = inst.getDoc();
+ var dom = ed.dom;
+
+ if (!skip_id)
+ dom.setAttrib(td, 'id', formObj.id.value);
+
+ dom.setAttrib(td, 'align', formObj.align.value);
+ dom.setAttrib(td, 'vAlign', formObj.valign.value);
+ dom.setAttrib(td, 'lang', formObj.lang.value);
+ dom.setAttrib(td, 'dir', getSelectValue(formObj, 'dir'));
+ dom.setAttrib(td, 'style', ed.dom.serializeStyle(ed.dom.parseStyle(formObj.style.value)));
+ dom.setAttrib(td, 'scope', formObj.scope.value);
+ dom.setAttrib(td, 'class', getSelectValue(formObj, 'class'));
+
+ // Clear deprecated attributes
+ ed.dom.setAttrib(td, 'width', '');
+ ed.dom.setAttrib(td, 'height', '');
+ ed.dom.setAttrib(td, 'bgColor', '');
+ ed.dom.setAttrib(td, 'borderColor', '');
+ ed.dom.setAttrib(td, 'background', '');
+
+ // Set styles
+ td.style.width = getCSSSize(formObj.width.value);
+ td.style.height = getCSSSize(formObj.height.value);
+ if (formObj.bordercolor.value != "") {
+ td.style.borderColor = formObj.bordercolor.value;
+ td.style.borderStyle = td.style.borderStyle == "" ? "solid" : td.style.borderStyle;
+ td.style.borderWidth = td.style.borderWidth == "" ? "1px" : td.style.borderWidth;
+ } else
+ td.style.borderColor = '';
+
+ td.style.backgroundColor = formObj.bgcolor.value;
+
+ if (formObj.backgroundimage.value != "")
+ td.style.backgroundImage = "url('" + formObj.backgroundimage.value + "')";
+ else
+ td.style.backgroundImage = '';
+
+ if (curCellType != celltype) {
+ // changing to a different node type
+ var newCell = doc.createElement(celltype);
+
+ for (var c=0; c<td.childNodes.length; c++)
+ newCell.appendChild(td.childNodes[c].cloneNode(1));
+
+ for (var a=0; a<td.attributes.length; a++)
+ ed.dom.setAttrib(newCell, td.attributes[a].name, ed.dom.getAttrib(td, td.attributes[a].name));
+
+ td.parentNode.replaceChild(newCell, td);
+ td = newCell;
+ }
+
+ dom.setAttrib(td, 'style', dom.serializeStyle(dom.parseStyle(td.style.cssText)));
+
+ return td;
+}
+
+function changedBackgroundImage() {
+ var formObj = document.forms[0];
+ var st = ed.dom.parseStyle(formObj.style.value);
+
+ st['background-image'] = "url('" + formObj.backgroundimage.value + "')";
+
+ formObj.style.value = ed.dom.serializeStyle(st);
+}
+
+function changedSize() {
+ var formObj = document.forms[0];
+ var st = ed.dom.parseStyle(formObj.style.value);
+
+ var width = formObj.width.value;
+ if (width != "")
+ st['width'] = getCSSSize(width);
+ else
+ st['width'] = "";
+
+ var height = formObj.height.value;
+ if (height != "")
+ st['height'] = getCSSSize(height);
+ else
+ st['height'] = "";
+
+ formObj.style.value = ed.dom.serializeStyle(st);
+}
+
+function changedColor() {
+ var formObj = document.forms[0];
+ var st = ed.dom.parseStyle(formObj.style.value);
+
+ st['background-color'] = formObj.bgcolor.value;
+ st['border-color'] = formObj.bordercolor.value;
+
+ formObj.style.value = ed.dom.serializeStyle(st);
+}
+
+function changedStyle() {
+ var formObj = document.forms[0];
+ var st = ed.dom.parseStyle(formObj.style.value);
+
+ if (st['background-image'])
+ formObj.backgroundimage.value = st['background-image'].replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
+ else
+ formObj.backgroundimage.value = '';
+
+ if (st['width'])
+ formObj.width.value = trimSize(st['width']);
+
+ if (st['height'])
+ formObj.height.value = trimSize(st['height']);
+
+ if (st['background-color']) {
+ formObj.bgcolor.value = st['background-color'];
+ updateColor('bgcolor_pick','bgcolor');
+ }
+
+ if (st['border-color']) {
+ formObj.bordercolor.value = st['border-color'];
+ updateColor('bordercolor_pick','bordercolor');
+ }
+}
+
+tinyMCEPopup.onInit.add(init);
diff --git a/askbot/media/js/tinymce/plugins/table/js/merge_cells.js b/askbot/media/js/tinymce/plugins/table/js/merge_cells.js
new file mode 100644
index 00000000..7ee4bf04
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/table/js/merge_cells.js
@@ -0,0 +1,27 @@
+tinyMCEPopup.requireLangPack();
+
+var MergeCellsDialog = {
+ init : function() {
+ var f = document.forms[0];
+
+ f.numcols.value = tinyMCEPopup.getWindowArg('cols', 1);
+ f.numrows.value = tinyMCEPopup.getWindowArg('rows', 1);
+ },
+
+ merge : function() {
+ var func, f = document.forms[0];
+
+ tinyMCEPopup.restoreSelection();
+
+ func = tinyMCEPopup.getWindowArg('onaction');
+
+ func({
+ cols : f.numcols.value,
+ rows : f.numrows.value
+ });
+
+ tinyMCEPopup.close();
+ }
+};
+
+tinyMCEPopup.onInit.add(MergeCellsDialog.init, MergeCellsDialog);
diff --git a/askbot/media/js/tinymce/plugins/table/js/row.js b/askbot/media/js/tinymce/plugins/table/js/row.js
new file mode 100644
index 00000000..a13d6959
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/table/js/row.js
@@ -0,0 +1,237 @@
+tinyMCEPopup.requireLangPack();
+
+function init() {
+ tinyMCEPopup.resizeToInnerSize();
+
+ document.getElementById('backgroundimagebrowsercontainer').innerHTML = getBrowserHTML('backgroundimagebrowser','backgroundimage','image','table');
+ document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor');
+
+ var inst = tinyMCEPopup.editor;
+ var dom = inst.dom;
+ var trElm = dom.getParent(inst.selection.getStart(), "tr");
+ var formObj = document.forms[0];
+ var st = dom.parseStyle(dom.getAttrib(trElm, "style"));
+
+ // Get table row data
+ var rowtype = trElm.parentNode.nodeName.toLowerCase();
+ var align = dom.getAttrib(trElm, 'align');
+ var valign = dom.getAttrib(trElm, 'valign');
+ var height = trimSize(getStyle(trElm, 'height', 'height'));
+ var className = dom.getAttrib(trElm, 'class');
+ var bgcolor = convertRGBToHex(getStyle(trElm, 'bgcolor', 'backgroundColor'));
+ var backgroundimage = getStyle(trElm, 'background', 'backgroundImage').replace(new RegExp("url\\(['\"]?([^'\"]*)['\"]?\\)", 'gi'), "$1");
+ var id = dom.getAttrib(trElm, 'id');
+ var lang = dom.getAttrib(trElm, 'lang');
+ var dir = dom.getAttrib(trElm, 'dir');
+
+ selectByValue(formObj, 'rowtype', rowtype);
+
+ // Any cells selected
+ if (dom.select('td.mceSelected,th.mceSelected', trElm).length == 0) {
+ // Setup form
+ addClassesToList('class', 'table_row_styles');
+ TinyMCE_EditableSelects.init();
+
+ formObj.bgcolor.value = bgcolor;
+ formObj.backgroundimage.value = backgroundimage;
+ formObj.height.value = height;
+ formObj.id.value = id;
+ formObj.lang.value = lang;
+ formObj.style.value = dom.serializeStyle(st);
+ selectByValue(formObj, 'align', align);
+ selectByValue(formObj, 'valign', valign);
+ selectByValue(formObj, 'class', className, true, true);
+ selectByValue(formObj, 'dir', dir);
+
+ // Resize some elements
+ if (isVisible('backgroundimagebrowser'))
+ document.getElementById('backgroundimage').style.width = '180px';
+
+ updateColor('bgcolor_pick', 'bgcolor');
+ } else
+ tinyMCEPopup.dom.hide('action');
+}
+
+function updateAction() {
+ var inst = tinyMCEPopup.editor, dom = inst.dom, trElm, tableElm, formObj = document.forms[0];
+ var action = getSelectValue(formObj, 'action');
+
+ if (!AutoValidator.validate(formObj)) {
+ tinyMCEPopup.alert(AutoValidator.getErrorMessages(formObj).join('. ') + '.');
+ return false;
+ }
+
+ tinyMCEPopup.restoreSelection();
+ trElm = dom.getParent(inst.selection.getStart(), "tr");
+ tableElm = dom.getParent(inst.selection.getStart(), "table");
+
+ // Update all selected rows
+ if (dom.select('td.mceSelected,th.mceSelected', trElm).length > 0) {
+ tinymce.each(tableElm.rows, function(tr) {
+ var i;
+
+ for (i = 0; i < tr.cells.length; i++) {
+ if (dom.hasClass(tr.cells[i], 'mceSelected')) {
+ updateRow(tr, true);
+ return;
+ }
+ }
+ });
+
+ inst.addVisual();
+ inst.nodeChanged();
+ inst.execCommand('mceEndUndoLevel');
+ tinyMCEPopup.close();
+ return;
+ }
+
+ switch (action) {
+ case "row":
+ updateRow(trElm);
+ break;
+
+ case "all":
+ var rows = tableElm.getElementsByTagName("tr");
+
+ for (var i=0; i<rows.length; i++)
+ updateRow(rows[i], true);
+
+ break;
+
+ case "odd":
+ case "even":
+ var rows = tableElm.getElementsByTagName("tr");
+
+ for (var i=0; i<rows.length; i++) {
+ if ((i % 2 == 0 && action == "odd") || (i % 2 != 0 && action == "even"))
+ updateRow(rows[i], true, true);
+ }
+
+ break;
+ }
+
+ inst.addVisual();
+ inst.nodeChanged();
+ inst.execCommand('mceEndUndoLevel');
+ tinyMCEPopup.close();
+}
+
+function updateRow(tr_elm, skip_id, skip_parent) {
+ var inst = tinyMCEPopup.editor;
+ var formObj = document.forms[0];
+ var dom = inst.dom;
+ var curRowType = tr_elm.parentNode.nodeName.toLowerCase();
+ var rowtype = getSelectValue(formObj, 'rowtype');
+ var doc = inst.getDoc();
+
+ // Update row element
+ if (!skip_id)
+ dom.setAttrib(tr_elm, 'id', formObj.id.value);
+
+ dom.setAttrib(tr_elm, 'align', getSelectValue(formObj, 'align'));
+ dom.setAttrib(tr_elm, 'vAlign', getSelectValue(formObj, 'valign'));
+ dom.setAttrib(tr_elm, 'lang', formObj.lang.value);
+ dom.setAttrib(tr_elm, 'dir', getSelectValue(formObj, 'dir'));
+ dom.setAttrib(tr_elm, 'style', dom.serializeStyle(dom.parseStyle(formObj.style.value)));
+ dom.setAttrib(tr_elm, 'class', getSelectValue(formObj, 'class'));
+
+ // Clear deprecated attributes
+ dom.setAttrib(tr_elm, 'background', '');
+ dom.setAttrib(tr_elm, 'bgColor', '');
+ dom.setAttrib(tr_elm, 'height', '');
+
+ // Set styles
+ tr_elm.style.height = getCSSSize(formObj.height.value);
+ tr_elm.style.backgroundColor = formObj.bgcolor.value;
+
+ if (formObj.backgroundimage.value != "")
+ tr_elm.style.backgroundImage = "url('" + formObj.backgroundimage.value + "')";
+ else
+ tr_elm.style.backgroundImage = '';
+
+ // Setup new rowtype
+ if (curRowType != rowtype && !skip_parent) {
+ // first, clone the node we are working on
+ var newRow = tr_elm.cloneNode(1);
+
+ // next, find the parent of its new destination (creating it if necessary)
+ var theTable = dom.getParent(tr_elm, "table");
+ var dest = rowtype;
+ var newParent = null;
+ for (var i = 0; i < theTable.childNodes.length; i++) {
+ if (theTable.childNodes[i].nodeName.toLowerCase() == dest)
+ newParent = theTable.childNodes[i];
+ }
+
+ if (newParent == null) {
+ newParent = doc.createElement(dest);
+
+ if (theTable.firstChild.nodeName == 'CAPTION')
+ inst.dom.insertAfter(newParent, theTable.firstChild);
+ else
+ theTable.insertBefore(newParent, theTable.firstChild);
+ }
+
+ // append the row to the new parent
+ newParent.appendChild(newRow);
+
+ // remove the original
+ tr_elm.parentNode.removeChild(tr_elm);
+
+ // set tr_elm to the new node
+ tr_elm = newRow;
+ }
+
+ dom.setAttrib(tr_elm, 'style', dom.serializeStyle(dom.parseStyle(tr_elm.style.cssText)));
+}
+
+function changedBackgroundImage() {
+ var formObj = document.forms[0], dom = tinyMCEPopup.editor.dom;
+ var st = dom.parseStyle(formObj.style.value);
+
+ st['background-image'] = "url('" + formObj.backgroundimage.value + "')";
+
+ formObj.style.value = dom.serializeStyle(st);
+}
+
+function changedStyle() {
+ var formObj = document.forms[0], dom = tinyMCEPopup.editor.dom;
+ var st = dom.parseStyle(formObj.style.value);
+
+ if (st['background-image'])
+ formObj.backgroundimage.value = st['background-image'].replace(new RegExp("url\\('?([^']*)'?\\)", 'gi'), "$1");
+ else
+ formObj.backgroundimage.value = '';
+
+ if (st['height'])
+ formObj.height.value = trimSize(st['height']);
+
+ if (st['background-color']) {
+ formObj.bgcolor.value = st['background-color'];
+ updateColor('bgcolor_pick','bgcolor');
+ }
+}
+
+function changedSize() {
+ var formObj = document.forms[0], dom = tinyMCEPopup.editor.dom;
+ var st = dom.parseStyle(formObj.style.value);
+
+ var height = formObj.height.value;
+ if (height != "")
+ st['height'] = getCSSSize(height);
+ else
+ st['height'] = "";
+
+ formObj.style.value = dom.serializeStyle(st);
+}
+
+function changedColor() {
+ var formObj = document.forms[0], dom = tinyMCEPopup.editor.dom;
+ var st = dom.parseStyle(formObj.style.value);
+
+ st['background-color'] = formObj.bgcolor.value;
+
+ formObj.style.value = dom.serializeStyle(st);
+}
+
+tinyMCEPopup.onInit.add(init);
diff --git a/askbot/media/js/tinymce/plugins/table/js/table.js b/askbot/media/js/tinymce/plugins/table/js/table.js
new file mode 100644
index 00000000..1db243b6
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/table/js/table.js
@@ -0,0 +1,501 @@
+tinyMCEPopup.requireLangPack();
+
+var action, orgTableWidth, orgTableHeight, dom = tinyMCEPopup.editor.dom;
+
+function insertTable() {
+ var formObj = document.forms[0];
+ var inst = tinyMCEPopup.editor, dom = inst.dom;
+ var cols = 2, rows = 2, border = 0, cellpadding = -1, cellspacing = -1, align, width, height, className, caption, frame, rules;
+ var html = '', capEl, elm;
+ var cellLimit, rowLimit, colLimit;
+
+ tinyMCEPopup.restoreSelection();
+
+ if (!AutoValidator.validate(formObj)) {
+ tinyMCEPopup.alert(AutoValidator.getErrorMessages(formObj).join('. ') + '.');
+ return false;
+ }
+
+ elm = dom.getParent(inst.selection.getNode(), 'table');
+
+ // Get form data
+ cols = formObj.elements['cols'].value;
+ rows = formObj.elements['rows'].value;
+ border = formObj.elements['border'].value != "" ? formObj.elements['border'].value : 0;
+ cellpadding = formObj.elements['cellpadding'].value != "" ? formObj.elements['cellpadding'].value : "";
+ cellspacing = formObj.elements['cellspacing'].value != "" ? formObj.elements['cellspacing'].value : "";
+ align = getSelectValue(formObj, "align");
+ frame = getSelectValue(formObj, "tframe");
+ rules = getSelectValue(formObj, "rules");
+ width = formObj.elements['width'].value;
+ height = formObj.elements['height'].value;
+ bordercolor = formObj.elements['bordercolor'].value;
+ bgcolor = formObj.elements['bgcolor'].value;
+ className = getSelectValue(formObj, "class");
+ id = formObj.elements['id'].value;
+ summary = formObj.elements['summary'].value;
+ style = formObj.elements['style'].value;
+ dir = formObj.elements['dir'].value;
+ lang = formObj.elements['lang'].value;
+ background = formObj.elements['backgroundimage'].value;
+ caption = formObj.elements['caption'].checked;
+
+ cellLimit = tinyMCEPopup.getParam('table_cell_limit', false);
+ rowLimit = tinyMCEPopup.getParam('table_row_limit', false);
+ colLimit = tinyMCEPopup.getParam('table_col_limit', false);
+
+ // Validate table size
+ if (colLimit && cols > colLimit) {
+ tinyMCEPopup.alert(inst.getLang('table_dlg.col_limit').replace(/\{\$cols\}/g, colLimit));
+ return false;
+ } else if (rowLimit && rows > rowLimit) {
+ tinyMCEPopup.alert(inst.getLang('table_dlg.row_limit').replace(/\{\$rows\}/g, rowLimit));
+ return false;
+ } else if (cellLimit && cols * rows > cellLimit) {
+ tinyMCEPopup.alert(inst.getLang('table_dlg.cell_limit').replace(/\{\$cells\}/g, cellLimit));
+ return false;
+ }
+
+ // Update table
+ if (action == "update") {
+ dom.setAttrib(elm, 'cellPadding', cellpadding, true);
+ dom.setAttrib(elm, 'cellSpacing', cellspacing, true);
+
+ if (!isCssSize(border)) {
+ dom.setAttrib(elm, 'border', border);
+ } else {
+ dom.setAttrib(elm, 'border', '');
+ }
+
+ if (border == '') {
+ dom.setStyle(elm, 'border-width', '');
+ dom.setStyle(elm, 'border', '');
+ dom.setAttrib(elm, 'border', '');
+ }
+
+ dom.setAttrib(elm, 'align', align);
+ dom.setAttrib(elm, 'frame', frame);
+ dom.setAttrib(elm, 'rules', rules);
+ dom.setAttrib(elm, 'class', className);
+ dom.setAttrib(elm, 'style', style);
+ dom.setAttrib(elm, 'id', id);
+ dom.setAttrib(elm, 'summary', summary);
+ dom.setAttrib(elm, 'dir', dir);
+ dom.setAttrib(elm, 'lang', lang);
+
+ capEl = inst.dom.select('caption', elm)[0];
+
+ if (capEl && !caption)
+ capEl.parentNode.removeChild(capEl);
+
+ if (!capEl && caption) {
+ capEl = elm.ownerDocument.createElement('caption');
+
+ if (!tinymce.isIE)
+ capEl.innerHTML = '<br data-mce-bogus="1"/>';
+
+ elm.insertBefore(capEl, elm.firstChild);
+ }
+
+ if (width && inst.settings.inline_styles) {
+ dom.setStyle(elm, 'width', width);
+ dom.setAttrib(elm, 'width', '');
+ } else {
+ dom.setAttrib(elm, 'width', width, true);
+ dom.setStyle(elm, 'width', '');
+ }
+
+ // Remove these since they are not valid XHTML
+ dom.setAttrib(elm, 'borderColor', '');
+ dom.setAttrib(elm, 'bgColor', '');
+ dom.setAttrib(elm, 'background', '');
+
+ if (height && inst.settings.inline_styles) {
+ dom.setStyle(elm, 'height', height);
+ dom.setAttrib(elm, 'height', '');
+ } else {
+ dom.setAttrib(elm, 'height', height, true);
+ dom.setStyle(elm, 'height', '');
+ }
+
+ if (background != '')
+ elm.style.backgroundImage = "url('" + background + "')";
+ else
+ elm.style.backgroundImage = '';
+
+/* if (tinyMCEPopup.getParam("inline_styles")) {
+ if (width != '')
+ elm.style.width = getCSSSize(width);
+ }*/
+
+ if (bordercolor != "") {
+ elm.style.borderColor = bordercolor;
+ elm.style.borderStyle = elm.style.borderStyle == "" ? "solid" : elm.style.borderStyle;
+ elm.style.borderWidth = cssSize(border);
+ } else
+ elm.style.borderColor = '';
+
+ elm.style.backgroundColor = bgcolor;
+ elm.style.height = getCSSSize(height);
+
+ inst.addVisual();
+
+ // Fix for stange MSIE align bug
+ //elm.outerHTML = elm.outerHTML;
+
+ inst.nodeChanged();
+ inst.execCommand('mceEndUndoLevel', false, {}, {skip_undo: true});
+
+ // Repaint if dimensions changed
+ if (formObj.width.value != orgTableWidth || formObj.height.value != orgTableHeight)
+ inst.execCommand('mceRepaint');
+
+ tinyMCEPopup.close();
+ return true;
+ }
+
+ // Create new table
+ html += '<table';
+
+ html += makeAttrib('id', id);
+ if (!isCssSize(border)) {
+ html += makeAttrib('border', border);
+ }
+
+ html += makeAttrib('cellpadding', cellpadding);
+ html += makeAttrib('cellspacing', cellspacing);
+ html += makeAttrib('data-mce-new', '1');
+
+ if (width && inst.settings.inline_styles) {
+ if (style)
+ style += '; ';
+
+ // Force px
+ if (/^[0-9\.]+$/.test(width))
+ width += 'px';
+
+ style += 'width: ' + width;
+ } else
+ html += makeAttrib('width', width);
+
+/* if (height) {
+ if (style)
+ style += '; ';
+
+ style += 'height: ' + height;
+ }*/
+
+ //html += makeAttrib('height', height);
+ //html += makeAttrib('bordercolor', bordercolor);
+ //html += makeAttrib('bgcolor', bgcolor);
+ html += makeAttrib('align', align);
+ html += makeAttrib('frame', frame);
+ html += makeAttrib('rules', rules);
+ html += makeAttrib('class', className);
+ html += makeAttrib('style', style);
+ html += makeAttrib('summary', summary);
+ html += makeAttrib('dir', dir);
+ html += makeAttrib('lang', lang);
+ html += '>';
+
+ if (caption) {
+ if (!tinymce.isIE)
+ html += '<caption><br data-mce-bogus="1"/></caption>';
+ else
+ html += '<caption></caption>';
+ }
+
+ for (var y=0; y<rows; y++) {
+ html += "<tr>";
+
+ for (var x=0; x<cols; x++) {
+ if (!tinymce.isIE)
+ html += '<td><br data-mce-bogus="1"/></td>';
+ else
+ html += '<td></td>';
+ }
+
+ html += "</tr>";
+ }
+
+ html += "</table>";
+
+ // Move table
+ if (inst.settings.fix_table_elements) {
+ var patt = '';
+
+ inst.focus();
+ inst.selection.setContent('<br class="_mce_marker" />');
+
+ tinymce.each('h1,h2,h3,h4,h5,h6,p'.split(','), function(n) {
+ if (patt)
+ patt += ',';
+
+ patt += n + ' ._mce_marker';
+ });
+
+ tinymce.each(inst.dom.select(patt), function(n) {
+ inst.dom.split(inst.dom.getParent(n, 'h1,h2,h3,h4,h5,h6,p'), n);
+ });
+
+ dom.setOuterHTML(dom.select('br._mce_marker')[0], html);
+ } else
+ inst.execCommand('mceInsertContent', false, html);
+
+ tinymce.each(dom.select('table[data-mce-new]'), function(node) {
+ var tdorth = dom.select('td,th', node);
+
+ // Fixes a bug in IE where the caret cannot be placed after the table if the table is at the end of the document
+ if (tinymce.isIE && node.nextSibling == null) {
+ if (inst.settings.forced_root_block)
+ dom.insertAfter(dom.create(inst.settings.forced_root_block), node);
+ else
+ dom.insertAfter(dom.create('br', {'data-mce-bogus': '1'}), node);
+ }
+
+ try {
+ // IE9 might fail to do this selection
+ inst.selection.setCursorLocation(tdorth[0], 0);
+ } catch (ex) {
+ // Ignore
+ }
+
+ dom.setAttrib(node, 'data-mce-new', '');
+ });
+
+ inst.addVisual();
+ inst.execCommand('mceEndUndoLevel', false, {}, {skip_undo: true});
+
+ tinyMCEPopup.close();
+}
+
+function makeAttrib(attrib, value) {
+ var formObj = document.forms[0];
+ var valueElm = formObj.elements[attrib];
+
+ if (typeof(value) == "undefined" || value == null) {
+ value = "";
+
+ if (valueElm)
+ value = valueElm.value;
+ }
+
+ if (value == "")
+ return "";
+
+ // XML encode it
+ value = value.replace(/&/g, '&amp;');
+ value = value.replace(/\"/g, '&quot;');
+ value = value.replace(/</g, '&lt;');
+ value = value.replace(/>/g, '&gt;');
+
+ return ' ' + attrib + '="' + value + '"';
+}
+
+function init() {
+ tinyMCEPopup.resizeToInnerSize();
+
+ document.getElementById('backgroundimagebrowsercontainer').innerHTML = getBrowserHTML('backgroundimagebrowser','backgroundimage','image','table');
+ document.getElementById('backgroundimagebrowsercontainer').innerHTML = getBrowserHTML('backgroundimagebrowser','backgroundimage','image','table');
+ document.getElementById('bordercolor_pickcontainer').innerHTML = getColorPickerHTML('bordercolor_pick','bordercolor');
+ document.getElementById('bgcolor_pickcontainer').innerHTML = getColorPickerHTML('bgcolor_pick','bgcolor');
+
+ var cols = 2, rows = 2, border = tinyMCEPopup.getParam('table_default_border', '0'), cellpadding = tinyMCEPopup.getParam('table_default_cellpadding', ''), cellspacing = tinyMCEPopup.getParam('table_default_cellspacing', '');
+ var align = "", width = "", height = "", bordercolor = "", bgcolor = "", className = "";
+ var id = "", summary = "", style = "", dir = "", lang = "", background = "", bgcolor = "", bordercolor = "", rules = "", frame = "";
+ var inst = tinyMCEPopup.editor, dom = inst.dom;
+ var formObj = document.forms[0];
+ var elm = dom.getParent(inst.selection.getNode(), "table");
+
+ // Hide advanced fields that isn't available in the schema
+ tinymce.each("summary id rules dir style frame".split(" "), function(name) {
+ var tr = tinyMCEPopup.dom.getParent(name, "tr") || tinyMCEPopup.dom.getParent("t" + name, "tr");
+
+ if (tr && !tinyMCEPopup.editor.schema.isValid("table", name)) {
+ tr.style.display = 'none';
+ }
+ });
+
+ action = tinyMCEPopup.getWindowArg('action');
+
+ if (!action)
+ action = elm ? "update" : "insert";
+
+ if (elm && action != "insert") {
+ var rowsAr = elm.rows;
+ var cols = 0;
+ for (var i=0; i<rowsAr.length; i++)
+ if (rowsAr[i].cells.length > cols)
+ cols = rowsAr[i].cells.length;
+
+ cols = cols;
+ rows = rowsAr.length;
+
+ st = dom.parseStyle(dom.getAttrib(elm, "style"));
+ border = trimSize(getStyle(elm, 'border', 'borderWidth'));
+ cellpadding = dom.getAttrib(elm, 'cellpadding', "");
+ cellspacing = dom.getAttrib(elm, 'cellspacing', "");
+ width = trimSize(getStyle(elm, 'width', 'width'));
+ height = trimSize(getStyle(elm, 'height', 'height'));
+ bordercolor = convertRGBToHex(getStyle(elm, 'bordercolor', 'borderLeftColor'));
+ bgcolor = convertRGBToHex(getStyle(elm, 'bgcolor', 'backgroundColor'));
+ align = dom.getAttrib(elm, 'align', align);
+ frame = dom.getAttrib(elm, 'frame');
+ rules = dom.getAttrib(elm, 'rules');
+ className = tinymce.trim(dom.getAttrib(elm, 'class').replace(/mceItem.+/g, ''));
+ id = dom.getAttrib(elm, 'id');
+ summary = dom.getAttrib(elm, 'summary');
+ style = dom.serializeStyle(st);
+ dir = dom.getAttrib(elm, 'dir');
+ lang = dom.getAttrib(elm, 'lang');
+ background = getStyle(elm, 'background', 'backgroundImage').replace(new RegExp("url\\(['\"]?([^'\"]*)['\"]?\\)", 'gi'), "$1");
+ formObj.caption.checked = elm.getElementsByTagName('caption').length > 0;
+
+ orgTableWidth = width;
+ orgTableHeight = height;
+
+ action = "update";
+ formObj.insert.value = inst.getLang('update');
+ }
+
+ addClassesToList('class', "table_styles");
+ TinyMCE_EditableSelects.init();
+
+ // Update form
+ selectByValue(formObj, 'align', align);
+ selectByValue(formObj, 'tframe', frame);
+ selectByValue(formObj, 'rules', rules);
+ selectByValue(formObj, 'class', className, true, true);
+ formObj.cols.value = cols;
+ formObj.rows.value = rows;
+ formObj.border.value = border;
+ formObj.cellpadding.value = cellpadding;
+ formObj.cellspacing.value = cellspacing;
+ formObj.width.value = width;
+ formObj.height.value = height;
+ formObj.bordercolor.value = bordercolor;
+ formObj.bgcolor.value = bgcolor;
+ formObj.id.value = id;
+ formObj.summary.value = summary;
+ formObj.style.value = style;
+ formObj.dir.value = dir;
+ formObj.lang.value = lang;
+ formObj.backgroundimage.value = background;
+
+ updateColor('bordercolor_pick', 'bordercolor');
+ updateColor('bgcolor_pick', 'bgcolor');
+
+ // Resize some elements
+ if (isVisible('backgroundimagebrowser'))
+ document.getElementById('backgroundimage').style.width = '180px';
+
+ // Disable some fields in update mode
+ if (action == "update") {
+ formObj.cols.disabled = true;
+ formObj.rows.disabled = true;
+ }
+}
+
+function changedSize() {
+ var formObj = document.forms[0];
+ var st = dom.parseStyle(formObj.style.value);
+
+/* var width = formObj.width.value;
+ if (width != "")
+ st['width'] = tinyMCEPopup.getParam("inline_styles") ? getCSSSize(width) : "";
+ else
+ st['width'] = "";*/
+
+ var height = formObj.height.value;
+ if (height != "")
+ st['height'] = getCSSSize(height);
+ else
+ st['height'] = "";
+
+ formObj.style.value = dom.serializeStyle(st);
+}
+
+function isCssSize(value) {
+ return /^[0-9.]+(%|in|cm|mm|em|ex|pt|pc|px)$/.test(value);
+}
+
+function cssSize(value, def) {
+ value = tinymce.trim(value || def);
+
+ if (!isCssSize(value)) {
+ return parseInt(value, 10) + 'px';
+ }
+
+ return value;
+}
+
+function changedBackgroundImage() {
+ var formObj = document.forms[0];
+ var st = dom.parseStyle(formObj.style.value);
+
+ st['background-image'] = "url('" + formObj.backgroundimage.value + "')";
+
+ formObj.style.value = dom.serializeStyle(st);
+}
+
+function changedBorder() {
+ var formObj = document.forms[0];
+ var st = dom.parseStyle(formObj.style.value);
+
+ // Update border width if the element has a color
+ if (formObj.border.value != "" && (isCssSize(formObj.border.value) || formObj.bordercolor.value != ""))
+ st['border-width'] = cssSize(formObj.border.value);
+ else {
+ if (!formObj.border.value) {
+ st['border'] = '';
+ st['border-width'] = '';
+ }
+ }
+
+ formObj.style.value = dom.serializeStyle(st);
+}
+
+function changedColor() {
+ var formObj = document.forms[0];
+ var st = dom.parseStyle(formObj.style.value);
+
+ st['background-color'] = formObj.bgcolor.value;
+
+ if (formObj.bordercolor.value != "") {
+ st['border-color'] = formObj.bordercolor.value;
+
+ // Add border-width if it's missing
+ if (!st['border-width'])
+ st['border-width'] = cssSize(formObj.border.value, 1);
+ }
+
+ formObj.style.value = dom.serializeStyle(st);
+}
+
+function changedStyle() {
+ var formObj = document.forms[0];
+ var st = dom.parseStyle(formObj.style.value);
+
+ if (st['background-image'])
+ formObj.backgroundimage.value = st['background-image'].replace(new RegExp("url\\(['\"]?([^'\"]*)['\"]?\\)", 'gi'), "$1");
+ else
+ formObj.backgroundimage.value = '';
+
+ if (st['width'])
+ formObj.width.value = trimSize(st['width']);
+
+ if (st['height'])
+ formObj.height.value = trimSize(st['height']);
+
+ if (st['background-color']) {
+ formObj.bgcolor.value = st['background-color'];
+ updateColor('bgcolor_pick','bgcolor');
+ }
+
+ if (st['border-color']) {
+ formObj.bordercolor.value = st['border-color'];
+ updateColor('bordercolor_pick','bordercolor');
+ }
+}
+
+tinyMCEPopup.onInit.add(init);
diff --git a/askbot/media/js/tinymce/plugins/table/langs/en_dlg.js b/askbot/media/js/tinymce/plugins/table/langs/en_dlg.js
new file mode 100644
index 00000000..463e09ee
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/table/langs/en_dlg.js
@@ -0,0 +1 @@
+tinyMCE.addI18n('en.table_dlg',{"rules_border":"border","rules_box":"box","rules_vsides":"vsides","rules_rhs":"rhs","rules_lhs":"lhs","rules_hsides":"hsides","rules_below":"below","rules_above":"above","rules_void":"void",rules:"Rules","frame_all":"all","frame_cols":"cols","frame_rows":"rows","frame_groups":"groups","frame_none":"none",frame:"Frame",caption:"Table Caption","missing_scope":"Are you sure you want to continue without specifying a scope for this table header cell. Without it, it may be difficult for some users with disabilities to understand the content or data displayed of the table.","cell_limit":"You\'ve exceeded the maximum number of cells of {$cells}.","row_limit":"You\'ve exceeded the maximum number of rows of {$rows}.","col_limit":"You\'ve exceeded the maximum number of columns of {$cols}.",colgroup:"Col Group",rowgroup:"Row Group",scope:"Scope",tfoot:"Footer",tbody:"Body",thead:"Header","row_all":"Update All Rows in Table","row_even":"Update Even Rows in Table","row_odd":"Update Odd Rows in Table","row_row":"Update Current Row","cell_all":"Update All Cells in Table","cell_row":"Update All Cells in Row","cell_cell":"Update Current Cell",th:"Header",td:"Data",summary:"Summary",bgimage:"Background Image",rtl:"Right to Left",ltr:"Left to Right",mime:"Target MIME Type",langcode:"Language Code",langdir:"Language Direction",style:"Style",id:"ID","merge_cells_title":"Merge Table Cells",bgcolor:"Background Color",bordercolor:"Border Color","align_bottom":"Bottom","align_top":"Top",valign:"Vertical Alignment","cell_type":"Cell Type","cell_title":"Table Cell Properties","row_title":"Table Row Properties","align_middle":"Center","align_right":"Right","align_left":"Left","align_default":"Default",align:"Alignment",border:"Border",cellpadding:"Cell Padding",cellspacing:"Cell Spacing",rows:"Rows",cols:"Columns",height:"Height",width:"Width",title:"Insert/Edit Table",rowtype:"Row Type","advanced_props":"Advanced Properties","general_props":"General Properties","advanced_tab":"Advanced","general_tab":"General","cell_col":"Update all cells in column"}); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/table/merge_cells.htm b/askbot/media/js/tinymce/plugins/table/merge_cells.htm
new file mode 100644
index 00000000..d231090e
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/table/merge_cells.htm
@@ -0,0 +1,32 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#table_dlg.merge_cells_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/validate.js"></script>
+ <script type="text/javascript" src="js/merge_cells.js"></script>
+</head>
+<body style="margin: 8px" role="application">
+<form onsubmit="MergeCellsDialog.merge();return false;" action="#">
+ <fieldset>
+ <legend>{#table_dlg.merge_cells_title}</legend>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="3" width="100%">
+ <tr>
+ <td><label for="numcols">{#table_dlg.cols}</label>:</td>
+ <td align="right"><input type="text" id="numcols" name="numcols" value="" class="number min1 mceFocus" style="width: 30px" aria-required="true" /></td>
+ </tr>
+ <tr>
+ <td><label for="numrows">{#table_dlg.rows}</label>:</td>
+ <td align="right"><input type="text" id="numrows" name="numrows" value="" class="number min1" style="width: 30px" aria-required="true" /></td>
+ </tr>
+ </table>
+ </fieldset>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#update}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/table/row.htm b/askbot/media/js/tinymce/plugins/table/row.htm
new file mode 100644
index 00000000..1885401f
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/table/row.htm
@@ -0,0 +1,158 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#table_dlg.row_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="../../utils/validate.js"></script>
+ <script type="text/javascript" src="../../utils/editable_selects.js"></script>
+ <script type="text/javascript" src="js/row.js"></script>
+ <link href="css/row.css" rel="stylesheet" type="text/css" />
+</head>
+<body id="tablerow" style="display: none" role="application">
+ <form onsubmit="updateAction();return false;" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" class="current" aria-controls="general_panel"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#table_dlg.general_tab}</a></span></li>
+ <li id="advanced_tab" aria-controls="advanced_panel"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');" onmousedown="return false;">{#table_dlg.advanced_tab}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <fieldset>
+ <legend>{#table_dlg.general_props}</legend>
+
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td><label for="rowtype">{#table_dlg.rowtype}</label></td>
+ <td class="col2">
+ <select id="rowtype" name="rowtype" class="mceFocus">
+ <option value="thead">{#table_dlg.thead}</option>
+ <option value="tbody">{#table_dlg.tbody}</option>
+ <option value="tfoot">{#table_dlg.tfoot}</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="align">{#table_dlg.align}</label></td>
+ <td class="col2">
+ <select id="align" name="align">
+ <option value="">{#not_set}</option>
+ <option value="center">{#table_dlg.align_middle}</option>
+ <option value="left">{#table_dlg.align_left}</option>
+ <option value="right">{#table_dlg.align_right}</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="valign">{#table_dlg.valign}</label></td>
+ <td class="col2">
+ <select id="valign" name="valign">
+ <option value="">{#not_set}</option>
+ <option value="top">{#table_dlg.align_top}</option>
+ <option value="middle">{#table_dlg.align_middle}</option>
+ <option value="bottom">{#table_dlg.align_bottom}</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr id="styleSelectRow">
+ <td><label for="class">{#class_name}</label></td>
+ <td class="col2">
+ <select id="class" name="class" class="mceEditableSelect">
+ <option value="" selected="selected">{#not_set}</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td><label for="height">{#table_dlg.height}</label></td>
+ <td class="col2"><input name="height" type="text" id="height" value="" size="7" maxlength="7" onchange="changedSize();" class="size" /></td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+
+ <div id="advanced_panel" class="panel">
+ <fieldset>
+ <legend>{#table_dlg.advanced_props}</legend>
+
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="column1"><label for="id">{#table_dlg.id}</label></td>
+ <td><input id="id" name="id" type="text" value="" style="width: 200px" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="style">{#table_dlg.style}</label></td>
+ <td><input type="text" id="style" name="style" value="" style="width: 200px;" onchange="changedStyle();" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="dir">{#table_dlg.langdir}</label></td>
+ <td>
+ <select id="dir" name="dir" style="width: 200px">
+ <option value="">{#not_set}</option>
+ <option value="ltr">{#table_dlg.ltr}</option>
+ <option value="rtl">{#table_dlg.rtl}</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="lang">{#table_dlg.langcode}</label></td>
+ <td>
+ <input id="lang" name="lang" type="text" value="" style="width: 200px" />
+ </td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="backgroundimage">{#table_dlg.bgimage}</label></td>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="backgroundimage" name="backgroundimage" type="text" value="" style="width: 200px" onchange="changedBackgroundImage();" /></td>
+ <td id="backgroundimagebrowsercontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="bgcolor" id="bgcolor_label">{#table_dlg.bgcolor}</label></td>
+ <td>
+ <span role="group" aria-labelledby="bgcolor_label">
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="bgcolor" name="bgcolor" type="text" value="" size="9" onchange="updateColor('bgcolor_pick','bgcolor');changedColor();" /></td>
+ <td id="bgcolor_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </span>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <div>
+ <select id="action" name="action">
+ <option value="row">{#table_dlg.row_row}</option>
+ <option value="odd">{#table_dlg.row_odd}</option>
+ <option value="even">{#table_dlg.row_even}</option>
+ <option value="all">{#table_dlg.row_all}</option>
+ </select>
+ </div>
+
+ <input type="submit" id="insert" name="insert" value="{#update}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+ </form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/table/table.htm b/askbot/media/js/tinymce/plugins/table/table.htm
new file mode 100644
index 00000000..b92fa741
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/table/table.htm
@@ -0,0 +1,188 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#table_dlg.title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="../../utils/validate.js"></script>
+ <script type="text/javascript" src="../../utils/editable_selects.js"></script>
+ <script type="text/javascript" src="js/table.js"></script>
+ <link href="css/table.css" rel="stylesheet" type="text/css" />
+</head>
+<body id="table" style="display: none" role="application" aria-labelledby="app_title">
+ <span style="display:none;" id="app_title">{#table_dlg.title}</span>
+ <form onsubmit="insertTable();return false;" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" aria-controls="general_panel" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#table_dlg.general_tab}</a></span></li>
+ <li id="advanced_tab" aria-controls="advanced_panel"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');" onmousedown="return false;">{#table_dlg.advanced_tab}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <fieldset>
+ <legend>{#table_dlg.general_props}</legend>
+ <table role="presentation" border="0" cellpadding="4" cellspacing="0" width="100%">
+ <tr>
+ <td><label id="colslabel" for="cols">{#table_dlg.cols}</label></td>
+ <td><input id="cols" name="cols" type="text" value="" size="3" maxlength="3" class="required number min1 mceFocus" aria-required="true" /></td>
+ <td><label id="rowslabel" for="rows">{#table_dlg.rows}</label></td>
+ <td><input id="rows" name="rows" type="text" value="" size="3" maxlength="3" class="required number min1" aria-required="true" /></td>
+ </tr>
+ <tr>
+ <td><label id="cellpaddinglabel" for="cellpadding">{#table_dlg.cellpadding}</label></td>
+ <td><input id="cellpadding" name="cellpadding" type="text" value="" size="3" maxlength="3" class="number" /></td>
+ <td><label id="cellspacinglabel" for="cellspacing">{#table_dlg.cellspacing}</label></td>
+ <td><input id="cellspacing" name="cellspacing" type="text" value="" size="3" maxlength="3" class="number" /></td>
+ </tr>
+ <tr>
+ <td><label id="alignlabel" for="align">{#table_dlg.align}</label></td>
+ <td><select id="align" name="align">
+ <option value="">{#not_set}</option>
+ <option value="center">{#table_dlg.align_middle}</option>
+ <option value="left">{#table_dlg.align_left}</option>
+ <option value="right">{#table_dlg.align_right}</option>
+ </select></td>
+ <td><label id="borderlabel" for="border">{#table_dlg.border}</label></td>
+ <td><input id="border" name="border" type="text" value="" size="3" maxlength="5" onchange="changedBorder();" class="size" /></td>
+ </tr>
+ <tr id="width_row">
+ <td><label id="widthlabel" for="width">{#table_dlg.width}</label></td>
+ <td><input name="width" type="text" id="width" value="" size="7" maxlength="7" onchange="changedSize();" class="size" /></td>
+ <td><label id="heightlabel" for="height">{#table_dlg.height}</label></td>
+ <td><input name="height" type="text" id="height" value="" size="7" maxlength="7" onchange="changedSize();" class="size" /></td>
+ </tr>
+ <tr id="styleSelectRow" >
+ <td><label id="classlabel" for="class">{#class_name}</label></td>
+ <td colspan="3" >
+ <select id="class" name="class" class="mceEditableSelect">
+ <option value="" selected="selected">{#not_set}</option>
+ </select></td>
+ </tr>
+ <tr>
+ <td class="column1" ><label for="caption">{#table_dlg.caption}</label></td>
+ <td><input id="caption" name="caption" type="checkbox" class="checkbox" value="true" /></td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+
+ <div id="advanced_panel" class="panel">
+ <fieldset>
+ <legend>{#table_dlg.advanced_props}</legend>
+
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="column1"><label for="id">{#table_dlg.id}</label></td>
+ <td><input id="id" name="id" type="text" value="" class="advfield" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="summary">{#table_dlg.summary}</label></td>
+ <td><input id="summary" name="summary" type="text" value="" class="advfield" /></td>
+ </tr>
+
+ <tr>
+ <td><label for="style">{#table_dlg.style}</label></td>
+ <td><input type="text" id="style" name="style" value="" class="advfield" onchange="changedStyle();" /></td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label id="langlabel" for="lang">{#table_dlg.langcode}</label></td>
+ <td>
+ <input id="lang" name="lang" type="text" value="" class="advfield" />
+ </td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="backgroundimage">{#table_dlg.bgimage}</label></td>
+ <td>
+ <table role="presentation" aria-labelledby="backgroundimage_label" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="backgroundimage" name="backgroundimage" type="text" value="" class="advfield" onchange="changedBackgroundImage();" /></td>
+ <td id="backgroundimagebrowsercontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="tframe">{#table_dlg.frame}</label></td>
+ <td>
+ <select id="tframe" name="tframe" class="advfield">
+ <option value="">{#not_set}</option>
+ <option value="void">{#table_dlg.rules_void}</option>
+ <option value="above">{#table_dlg.rules_above}</option>
+ <option value="below">{#table_dlg.rules_below}</option>
+ <option value="hsides">{#table_dlg.rules_hsides}</option>
+ <option value="lhs">{#table_dlg.rules_lhs}</option>
+ <option value="rhs">{#table_dlg.rules_rhs}</option>
+ <option value="vsides">{#table_dlg.rules_vsides}</option>
+ <option value="box">{#table_dlg.rules_box}</option>
+ <option value="border">{#table_dlg.rules_border}</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="rules">{#table_dlg.rules}</label></td>
+ <td>
+ <select id="rules" name="rules" class="advfield">
+ <option value="">{#not_set}</option>
+ <option value="none">{#table_dlg.frame_none}</option>
+ <option value="groups">{#table_dlg.frame_groups}</option>
+ <option value="rows">{#table_dlg.frame_rows}</option>
+ <option value="cols">{#table_dlg.frame_cols}</option>
+ <option value="all">{#table_dlg.frame_all}</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr>
+ <td class="column1"><label for="dir">{#table_dlg.langdir}</label></td>
+ <td>
+ <select id="dir" name="dir" class="advfield">
+ <option value="">{#not_set}</option>
+ <option value="ltr">{#table_dlg.ltr}</option>
+ <option value="rtl">{#table_dlg.rtl}</option>
+ </select>
+ </td>
+ </tr>
+
+ <tr role="group" aria-labelledby="bordercolor_label">
+ <td class="column1"><label id="bordercolor_label" for="bordercolor">{#table_dlg.bordercolor}</label></td>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="bordercolor" name="bordercolor" type="text" value="" size="9" onchange="updateColor('bordercolor_pick','bordercolor');changedColor();" /></td>
+ <td id="bordercolor_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+
+ <tr role="group" aria-labelledby="bgcolor_label">
+ <td class="column1"><label id="bgcolor_label" for="bgcolor">{#table_dlg.bgcolor}</label></td>
+ <td>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td><input id="bgcolor" name="bgcolor" type="text" value="" size="9" onchange="updateColor('bgcolor_pick','bgcolor');changedColor();" /></td>
+ <td id="bgcolor_pickcontainer">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#insert}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+ </form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/template/blank.htm b/askbot/media/js/tinymce/plugins/template/blank.htm
new file mode 100644
index 00000000..ecde53fa
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/template/blank.htm
@@ -0,0 +1,12 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>blank_page</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <script type="text/javascript">
+ parent.TemplateDialog.loadCSSFiles(document);
+ </script>
+</head>
+<body id="mceTemplatePreview" class="mceContentBody">
+
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/template/css/template.css b/askbot/media/js/tinymce/plugins/template/css/template.css
new file mode 100644
index 00000000..2d23a493
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/template/css/template.css
@@ -0,0 +1,23 @@
+#frmbody {
+ padding: 10px;
+ background-color: #FFF;
+ border: 1px solid #CCC;
+}
+
+.frmRow {
+ margin-bottom: 10px;
+}
+
+#templatesrc {
+ border: none;
+ width: 320px;
+ height: 240px;
+}
+
+.title {
+ padding-bottom: 5px;
+}
+
+.mceActionPanel {
+ padding-top: 5px;
+}
diff --git a/askbot/media/js/tinymce/plugins/template/editor_plugin.js b/askbot/media/js/tinymce/plugins/template/editor_plugin.js
new file mode 100644
index 00000000..ebe3c27d
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/template/editor_plugin.js
@@ -0,0 +1 @@
+(function(){var a=tinymce.each;tinymce.create("tinymce.plugins.TemplatePlugin",{init:function(b,c){var d=this;d.editor=b;b.addCommand("mceTemplate",function(e){b.windowManager.open({file:c+"/template.htm",width:b.getParam("template_popup_width",750),height:b.getParam("template_popup_height",600),inline:1},{plugin_url:c})});b.addCommand("mceInsertTemplate",d._insertTemplate,d);b.addButton("template",{title:"template.desc",cmd:"mceTemplate"});b.onPreProcess.add(function(e,g){var f=e.dom;a(f.select("div",g.node),function(h){if(f.hasClass(h,"mceTmpl")){a(f.select("*",h),function(i){if(f.hasClass(i,e.getParam("template_mdate_classes","mdate").replace(/\s+/g,"|"))){i.innerHTML=d._getDateTime(new Date(),e.getParam("template_mdate_format",e.getLang("template.mdate_format")))}});d._replaceVals(h)}})})},getInfo:function(){return{longname:"Template plugin",author:"Moxiecode Systems AB",authorurl:"http://www.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/template",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_insertTemplate:function(i,j){var k=this,g=k.editor,f,c,d=g.dom,b=g.selection.getContent();f=j.content;a(k.editor.getParam("template_replace_values"),function(l,h){if(typeof(l)!="function"){f=f.replace(new RegExp("\\{\\$"+h+"\\}","g"),l)}});c=d.create("div",null,f);n=d.select(".mceTmpl",c);if(n&&n.length>0){c=d.create("div",null);c.appendChild(n[0].cloneNode(true))}function e(l,h){return new RegExp("\\b"+h+"\\b","g").test(l.className)}a(d.select("*",c),function(h){if(e(h,g.getParam("template_cdate_classes","cdate").replace(/\s+/g,"|"))){h.innerHTML=k._getDateTime(new Date(),g.getParam("template_cdate_format",g.getLang("template.cdate_format")))}if(e(h,g.getParam("template_mdate_classes","mdate").replace(/\s+/g,"|"))){h.innerHTML=k._getDateTime(new Date(),g.getParam("template_mdate_format",g.getLang("template.mdate_format")))}if(e(h,g.getParam("template_selected_content_classes","selcontent").replace(/\s+/g,"|"))){h.innerHTML=b}});k._replaceVals(c);g.execCommand("mceInsertContent",false,c.innerHTML);g.addVisual()},_replaceVals:function(c){var d=this.editor.dom,b=this.editor.getParam("template_replace_values");a(d.select("*",c),function(f){a(b,function(g,e){if(d.hasClass(f,e)){if(typeof(b[e])=="function"){b[e](f)}}})})},_getDateTime:function(e,b){if(!b){return""}function c(g,d){var f;g=""+g;if(g.length<d){for(f=0;f<(d-g.length);f++){g="0"+g}}return g}b=b.replace("%D","%m/%d/%y");b=b.replace("%r","%I:%M:%S %p");b=b.replace("%Y",""+e.getFullYear());b=b.replace("%y",""+e.getYear());b=b.replace("%m",c(e.getMonth()+1,2));b=b.replace("%d",c(e.getDate(),2));b=b.replace("%H",""+c(e.getHours(),2));b=b.replace("%M",""+c(e.getMinutes(),2));b=b.replace("%S",""+c(e.getSeconds(),2));b=b.replace("%I",""+((e.getHours()+11)%12+1));b=b.replace("%p",""+(e.getHours()<12?"AM":"PM"));b=b.replace("%B",""+this.editor.getLang("template_months_long").split(",")[e.getMonth()]);b=b.replace("%b",""+this.editor.getLang("template_months_short").split(",")[e.getMonth()]);b=b.replace("%A",""+this.editor.getLang("template_day_long").split(",")[e.getDay()]);b=b.replace("%a",""+this.editor.getLang("template_day_short").split(",")[e.getDay()]);b=b.replace("%%","%");return b}});tinymce.PluginManager.add("template",tinymce.plugins.TemplatePlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/template/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/template/editor_plugin_src.js
new file mode 100644
index 00000000..9cac2699
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/template/editor_plugin_src.js
@@ -0,0 +1,159 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var each = tinymce.each;
+
+ tinymce.create('tinymce.plugins.TemplatePlugin', {
+ init : function(ed, url) {
+ var t = this;
+
+ t.editor = ed;
+
+ // Register commands
+ ed.addCommand('mceTemplate', function(ui) {
+ ed.windowManager.open({
+ file : url + '/template.htm',
+ width : ed.getParam('template_popup_width', 750),
+ height : ed.getParam('template_popup_height', 600),
+ inline : 1
+ }, {
+ plugin_url : url
+ });
+ });
+
+ ed.addCommand('mceInsertTemplate', t._insertTemplate, t);
+
+ // Register buttons
+ ed.addButton('template', {title : 'template.desc', cmd : 'mceTemplate'});
+
+ ed.onPreProcess.add(function(ed, o) {
+ var dom = ed.dom;
+
+ each(dom.select('div', o.node), function(e) {
+ if (dom.hasClass(e, 'mceTmpl')) {
+ each(dom.select('*', e), function(e) {
+ if (dom.hasClass(e, ed.getParam('template_mdate_classes', 'mdate').replace(/\s+/g, '|')))
+ e.innerHTML = t._getDateTime(new Date(), ed.getParam("template_mdate_format", ed.getLang("template.mdate_format")));
+ });
+
+ t._replaceVals(e);
+ }
+ });
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Template plugin',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://www.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/template',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ _insertTemplate : function(ui, v) {
+ var t = this, ed = t.editor, h, el, dom = ed.dom, sel = ed.selection.getContent();
+
+ h = v.content;
+
+ each(t.editor.getParam('template_replace_values'), function(v, k) {
+ if (typeof(v) != 'function')
+ h = h.replace(new RegExp('\\{\\$' + k + '\\}', 'g'), v);
+ });
+
+ el = dom.create('div', null, h);
+
+ // Find template element within div
+ n = dom.select('.mceTmpl', el);
+ if (n && n.length > 0) {
+ el = dom.create('div', null);
+ el.appendChild(n[0].cloneNode(true));
+ }
+
+ function hasClass(n, c) {
+ return new RegExp('\\b' + c + '\\b', 'g').test(n.className);
+ };
+
+ each(dom.select('*', el), function(n) {
+ // Replace cdate
+ if (hasClass(n, ed.getParam('template_cdate_classes', 'cdate').replace(/\s+/g, '|')))
+ n.innerHTML = t._getDateTime(new Date(), ed.getParam("template_cdate_format", ed.getLang("template.cdate_format")));
+
+ // Replace mdate
+ if (hasClass(n, ed.getParam('template_mdate_classes', 'mdate').replace(/\s+/g, '|')))
+ n.innerHTML = t._getDateTime(new Date(), ed.getParam("template_mdate_format", ed.getLang("template.mdate_format")));
+
+ // Replace selection
+ if (hasClass(n, ed.getParam('template_selected_content_classes', 'selcontent').replace(/\s+/g, '|')))
+ n.innerHTML = sel;
+ });
+
+ t._replaceVals(el);
+
+ ed.execCommand('mceInsertContent', false, el.innerHTML);
+ ed.addVisual();
+ },
+
+ _replaceVals : function(e) {
+ var dom = this.editor.dom, vl = this.editor.getParam('template_replace_values');
+
+ each(dom.select('*', e), function(e) {
+ each(vl, function(v, k) {
+ if (dom.hasClass(e, k)) {
+ if (typeof(vl[k]) == 'function')
+ vl[k](e);
+ }
+ });
+ });
+ },
+
+ _getDateTime : function(d, fmt) {
+ if (!fmt)
+ return "";
+
+ function addZeros(value, len) {
+ var i;
+
+ value = "" + value;
+
+ if (value.length < len) {
+ for (i=0; i<(len-value.length); i++)
+ value = "0" + value;
+ }
+
+ return value;
+ }
+
+ fmt = fmt.replace("%D", "%m/%d/%y");
+ fmt = fmt.replace("%r", "%I:%M:%S %p");
+ fmt = fmt.replace("%Y", "" + d.getFullYear());
+ fmt = fmt.replace("%y", "" + d.getYear());
+ fmt = fmt.replace("%m", addZeros(d.getMonth()+1, 2));
+ fmt = fmt.replace("%d", addZeros(d.getDate(), 2));
+ fmt = fmt.replace("%H", "" + addZeros(d.getHours(), 2));
+ fmt = fmt.replace("%M", "" + addZeros(d.getMinutes(), 2));
+ fmt = fmt.replace("%S", "" + addZeros(d.getSeconds(), 2));
+ fmt = fmt.replace("%I", "" + ((d.getHours() + 11) % 12 + 1));
+ fmt = fmt.replace("%p", "" + (d.getHours() < 12 ? "AM" : "PM"));
+ fmt = fmt.replace("%B", "" + this.editor.getLang("template_months_long").split(',')[d.getMonth()]);
+ fmt = fmt.replace("%b", "" + this.editor.getLang("template_months_short").split(',')[d.getMonth()]);
+ fmt = fmt.replace("%A", "" + this.editor.getLang("template_day_long").split(',')[d.getDay()]);
+ fmt = fmt.replace("%a", "" + this.editor.getLang("template_day_short").split(',')[d.getDay()]);
+ fmt = fmt.replace("%%", "%");
+
+ return fmt;
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('template', tinymce.plugins.TemplatePlugin);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/template/js/template.js b/askbot/media/js/tinymce/plugins/template/js/template.js
new file mode 100644
index 00000000..bc3045d2
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/template/js/template.js
@@ -0,0 +1,106 @@
+tinyMCEPopup.requireLangPack();
+
+var TemplateDialog = {
+ preInit : function() {
+ var url = tinyMCEPopup.getParam("template_external_list_url");
+
+ if (url != null)
+ document.write('<sc'+'ript language="javascript" type="text/javascript" src="' + tinyMCEPopup.editor.documentBaseURI.toAbsolute(url) + '"></sc'+'ript>');
+ },
+
+ init : function() {
+ var ed = tinyMCEPopup.editor, tsrc, sel, x, u;
+
+ tsrc = ed.getParam("template_templates", false);
+ sel = document.getElementById('tpath');
+
+ // Setup external template list
+ if (!tsrc && typeof(tinyMCETemplateList) != 'undefined') {
+ for (x=0, tsrc = []; x<tinyMCETemplateList.length; x++)
+ tsrc.push({title : tinyMCETemplateList[x][0], src : tinyMCETemplateList[x][1], description : tinyMCETemplateList[x][2]});
+ }
+
+ for (x=0; x<tsrc.length; x++)
+ sel.options[sel.options.length] = new Option(tsrc[x].title, tinyMCEPopup.editor.documentBaseURI.toAbsolute(tsrc[x].src));
+
+ this.resize();
+ this.tsrc = tsrc;
+ },
+
+ resize : function() {
+ var w, h, e;
+
+ if (!self.innerWidth) {
+ w = document.body.clientWidth - 50;
+ h = document.body.clientHeight - 160;
+ } else {
+ w = self.innerWidth - 50;
+ h = self.innerHeight - 170;
+ }
+
+ e = document.getElementById('templatesrc');
+
+ if (e) {
+ e.style.height = Math.abs(h) + 'px';
+ e.style.width = Math.abs(w - 5) + 'px';
+ }
+ },
+
+ loadCSSFiles : function(d) {
+ var ed = tinyMCEPopup.editor;
+
+ tinymce.each(ed.getParam("content_css", '').split(','), function(u) {
+ d.write('<link href="' + ed.documentBaseURI.toAbsolute(u) + '" rel="stylesheet" type="text/css" />');
+ });
+ },
+
+ selectTemplate : function(u, ti) {
+ var d = window.frames['templatesrc'].document, x, tsrc = this.tsrc;
+
+ if (!u)
+ return;
+
+ d.body.innerHTML = this.templateHTML = this.getFileContents(u);
+
+ for (x=0; x<tsrc.length; x++) {
+ if (tsrc[x].title == ti)
+ document.getElementById('tmpldesc').innerHTML = tsrc[x].description || '';
+ }
+ },
+
+ insert : function() {
+ tinyMCEPopup.execCommand('mceInsertTemplate', false, {
+ content : this.templateHTML,
+ selection : tinyMCEPopup.editor.selection.getContent()
+ });
+
+ tinyMCEPopup.close();
+ },
+
+ getFileContents : function(u) {
+ var x, d, t = 'text/plain';
+
+ function g(s) {
+ x = 0;
+
+ try {
+ x = new ActiveXObject(s);
+ } catch (s) {
+ }
+
+ return x;
+ };
+
+ x = window.ActiveXObject ? g('Msxml2.XMLHTTP') || g('Microsoft.XMLHTTP') : new XMLHttpRequest();
+
+ // Synchronous AJAX load file
+ x.overrideMimeType && x.overrideMimeType(t);
+ x.open("GET", u, false);
+ x.send(null);
+
+ return x.responseText;
+ }
+};
+
+TemplateDialog.preInit();
+tinyMCEPopup.onInit.add(TemplateDialog.init, TemplateDialog);
diff --git a/askbot/media/js/tinymce/plugins/template/langs/en_dlg.js b/askbot/media/js/tinymce/plugins/template/langs/en_dlg.js
new file mode 100644
index 00000000..83e599d6
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/template/langs/en_dlg.js
@@ -0,0 +1 @@
+tinyMCE.addI18n('en.template_dlg',{title:"Templates",label:"Template","desc_label":"Description",desc:"Insert Predefined Template Content",select:"Select a Template",preview:"Preview",warning:"Warning: Updating a template with a different one may cause data loss.","mdate_format":"%Y-%m-%d %H:%M:%S","cdate_format":"%Y-%m-%d %H:%M:%S","months_long":"January,February,March,April,May,June,July,August,September,October,November,December","months_short":"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec","day_long":"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday","day_short":"Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun"}); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/template/template.htm b/askbot/media/js/tinymce/plugins/template/template.htm
new file mode 100644
index 00000000..b2182e63
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/template/template.htm
@@ -0,0 +1,31 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#template_dlg.title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="js/template.js"></script>
+ <link href="css/template.css" rel="stylesheet" type="text/css" />
+</head>
+<body onresize="TemplateDialog.resize();">
+ <form onsubmit="TemplateDialog.insert();return false;">
+ <div id="frmbody">
+ <div class="title">{#template_dlg.desc}</div>
+ <div class="frmRow"><label for="tpath" title="{#template_dlg.select}">{#template_dlg.label}:</label>
+ <select id="tpath" name="tpath" onchange="TemplateDialog.selectTemplate(this.options[this.selectedIndex].value, this.options[this.selectedIndex].text);" class="mceFocus">
+ <option value="">{#template_dlg.select}...</option>
+ </select>
+ <span id="warning"></span></div>
+ <div class="frmRow"><label for="tdesc">{#template_dlg.desc_label}:</label>
+ <span id="tmpldesc"></span></div>
+ <fieldset>
+ <legend>{#template_dlg.preview}</legend>
+ <iframe id="templatesrc" name="templatesrc" src="blank.htm" width="690" height="400" frameborder="0"></iframe>
+ </fieldset>
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#insert}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+ </form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/visualblocks/css/visualblocks.css b/askbot/media/js/tinymce/plugins/visualblocks/css/visualblocks.css
new file mode 100644
index 00000000..76bc92b5
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/visualblocks/css/visualblocks.css
@@ -0,0 +1,21 @@
+p, h1, h2, h3, h4, h5, h6, hgroup, aside, div, section, article, blockquote, address, pre, figure {display: block; padding-top: 10px; border: 1px dashed #BBB; background: transparent no-repeat}
+p, h1, h2, h3, h4, h5, h6, hgroup, aside, div, section, article, address, pre, figure {margin-left: 3px}
+section, article, address, hgroup, aside, figure {margin: 0 0 1em 3px}
+
+p {background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}
+h1 {background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}
+h2 {background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}
+h3 {background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}
+h4 {background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}
+h5 {background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}
+h6 {background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}
+div {background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}
+section {background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}
+article {background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}
+blockquote {background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}
+address {background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}
+pre {background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}
+hgroup {background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}
+aside {background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}
+figure {background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}
+figcaption {border: 1px dashed #BBB}
diff --git a/askbot/media/js/tinymce/plugins/visualblocks/editor_plugin.js b/askbot/media/js/tinymce/plugins/visualblocks/editor_plugin.js
new file mode 100644
index 00000000..c65eaf2b
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/visualblocks/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.VisualBlocks",{init:function(a,b){var c;if(!window.NodeList){return}a.addCommand("mceVisualBlocks",function(){var e=a.dom,d;if(!c){c=e.uniqueId();d=e.create("link",{id:c,rel:"stylesheet",href:b+"/css/visualblocks.css"});a.getDoc().getElementsByTagName("head")[0].appendChild(d)}else{d=e.get(c);d.disabled=!d.disabled}a.controlManager.setActive("visualblocks",!d.disabled)});a.addButton("visualblocks",{title:"visualblocks.desc",cmd:"mceVisualBlocks"});a.onInit.add(function(){if(a.settings.visualblocks_default_state){a.execCommand("mceVisualBlocks",false,null,{skip_focus:true})}})},getInfo:function(){return{longname:"Visual blocks",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/visualblocks",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("visualblocks",tinymce.plugins.VisualBlocks)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/visualblocks/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/visualblocks/editor_plugin_src.js
new file mode 100644
index 00000000..b9d2ab2e
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/visualblocks/editor_plugin_src.js
@@ -0,0 +1,63 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2012, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.VisualBlocks', {
+ init : function(ed, url) {
+ var cssId;
+
+ // We don't support older browsers like IE6/7 and they don't provide prototypes for DOM objects
+ if (!window.NodeList) {
+ return;
+ }
+
+ ed.addCommand('mceVisualBlocks', function() {
+ var dom = ed.dom, linkElm;
+
+ if (!cssId) {
+ cssId = dom.uniqueId();
+ linkElm = dom.create('link', {
+ id: cssId,
+ rel : 'stylesheet',
+ href : url + '/css/visualblocks.css'
+ });
+
+ ed.getDoc().getElementsByTagName('head')[0].appendChild(linkElm);
+ } else {
+ linkElm = dom.get(cssId);
+ linkElm.disabled = !linkElm.disabled;
+ }
+
+ ed.controlManager.setActive('visualblocks', !linkElm.disabled);
+ });
+
+ ed.addButton('visualblocks', {title : 'visualblocks.desc', cmd : 'mceVisualBlocks'});
+
+ ed.onInit.add(function() {
+ if (ed.settings.visualblocks_default_state) {
+ ed.execCommand('mceVisualBlocks', false, null, {skip_focus : true});
+ }
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Visual blocks',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/visualblocks',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('visualblocks', tinymce.plugins.VisualBlocks);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/visualchars/editor_plugin.js b/askbot/media/js/tinymce/plugins/visualchars/editor_plugin.js
new file mode 100644
index 00000000..1a148e8b
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/visualchars/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.VisualChars",{init:function(a,b){var c=this;c.editor=a;a.addCommand("mceVisualChars",c._toggleVisualChars,c);a.addButton("visualchars",{title:"visualchars.desc",cmd:"mceVisualChars"});a.onBeforeGetContent.add(function(d,e){if(c.state&&e.format!="raw"&&!e.draft){c.state=true;c._toggleVisualChars(false)}})},getInfo:function(){return{longname:"Visual characters",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/visualchars",version:tinymce.majorVersion+"."+tinymce.minorVersion}},_toggleVisualChars:function(m){var p=this,k=p.editor,a,g,j,n=k.getDoc(),o=k.getBody(),l,q=k.selection,e,c,f;p.state=!p.state;k.controlManager.setActive("visualchars",p.state);if(m){f=q.getBookmark()}if(p.state){a=[];tinymce.walk(o,function(b){if(b.nodeType==3&&b.nodeValue&&b.nodeValue.indexOf("\u00a0")!=-1){a.push(b)}},"childNodes");for(g=0;g<a.length;g++){l=a[g].nodeValue;l=l.replace(/(\u00a0)/g,'<span data-mce-bogus="1" class="mceItemHidden mceItemNbsp">$1</span>');c=k.dom.create("div",null,l);while(node=c.lastChild){k.dom.insertAfter(node,a[g])}k.dom.remove(a[g])}}else{a=k.dom.select("span.mceItemNbsp",o);for(g=a.length-1;g>=0;g--){k.dom.remove(a[g],1)}}q.moveToBookmark(f)}});tinymce.PluginManager.add("visualchars",tinymce.plugins.VisualChars)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/visualchars/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/visualchars/editor_plugin_src.js
new file mode 100644
index 00000000..df985905
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/visualchars/editor_plugin_src.js
@@ -0,0 +1,83 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.VisualChars', {
+ init : function(ed, url) {
+ var t = this;
+
+ t.editor = ed;
+
+ // Register commands
+ ed.addCommand('mceVisualChars', t._toggleVisualChars, t);
+
+ // Register buttons
+ ed.addButton('visualchars', {title : 'visualchars.desc', cmd : 'mceVisualChars'});
+
+ ed.onBeforeGetContent.add(function(ed, o) {
+ if (t.state && o.format != 'raw' && !o.draft) {
+ t.state = true;
+ t._toggleVisualChars(false);
+ }
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Visual characters',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/visualchars',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ },
+
+ // Private methods
+
+ _toggleVisualChars : function(bookmark) {
+ var t = this, ed = t.editor, nl, i, h, d = ed.getDoc(), b = ed.getBody(), nv, s = ed.selection, bo, div, bm;
+
+ t.state = !t.state;
+ ed.controlManager.setActive('visualchars', t.state);
+
+ if (bookmark)
+ bm = s.getBookmark();
+
+ if (t.state) {
+ nl = [];
+ tinymce.walk(b, function(n) {
+ if (n.nodeType == 3 && n.nodeValue && n.nodeValue.indexOf('\u00a0') != -1)
+ nl.push(n);
+ }, 'childNodes');
+
+ for (i = 0; i < nl.length; i++) {
+ nv = nl[i].nodeValue;
+ nv = nv.replace(/(\u00a0)/g, '<span data-mce-bogus="1" class="mceItemHidden mceItemNbsp">$1</span>');
+
+ div = ed.dom.create('div', null, nv);
+ while (node = div.lastChild)
+ ed.dom.insertAfter(node, nl[i]);
+
+ ed.dom.remove(nl[i]);
+ }
+ } else {
+ nl = ed.dom.select('span.mceItemNbsp', b);
+
+ for (i = nl.length - 1; i >= 0; i--)
+ ed.dom.remove(nl[i], 1);
+ }
+
+ s.moveToBookmark(bm);
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('visualchars', tinymce.plugins.VisualChars);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/wordcount/editor_plugin.js b/askbot/media/js/tinymce/plugins/wordcount/editor_plugin.js
new file mode 100644
index 00000000..42ece209
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/wordcount/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.WordCount",{block:0,id:null,countre:null,cleanre:null,init:function(c,d){var e=this,f=0,g=tinymce.VK;e.countre=c.getParam("wordcount_countregex",/[\w\u2019\'-]+/g);e.cleanre=c.getParam("wordcount_cleanregex",/[0-9.(),;:!?%#$?\'\"_+=\\\/-]*/g);e.update_rate=c.getParam("wordcount_update_rate",2000);e.update_on_delete=c.getParam("wordcount_update_on_delete",false);e.id=c.id+"-word-count";c.onPostRender.add(function(i,h){var j,k;k=i.getParam("wordcount_target_id");if(!k){j=tinymce.DOM.get(i.id+"_path_row");if(j){tinymce.DOM.add(j.parentNode,"div",{style:"float: right"},i.getLang("wordcount.words","Words: ")+'<span id="'+e.id+'">0</span>')}}else{tinymce.DOM.add(k,"span",{},'<span id="'+e.id+'">0</span>')}});c.onInit.add(function(h){h.selection.onSetContent.add(function(){e._count(h)});e._count(h)});c.onSetContent.add(function(h){e._count(h)});function b(h){return h!==f&&(h===g.ENTER||f===g.SPACEBAR||a(f))}function a(h){return h===g.DELETE||h===g.BACKSPACE}c.onKeyUp.add(function(h,i){if(b(i.keyCode)||e.update_on_delete&&a(i.keyCode)){e._count(h)}f=i.keyCode})},_getCount:function(c){var a=0;var b=c.getContent({format:"raw"});if(b){b=b.replace(/\.\.\./g," ");b=b.replace(/<.[^<>]*?>/g," ").replace(/&nbsp;|&#160;/gi," ");b=b.replace(/(\w+)(&.+?;)+(\w+)/,"$1$3").replace(/&.+?;/g," ");b=b.replace(this.cleanre,"");var d=b.match(this.countre);if(d){a=d.length}}return a},_count:function(a){var b=this;if(b.block){return}b.block=1;setTimeout(function(){if(!a.destroyed){var c=b._getCount(a);tinymce.DOM.setHTML(b.id,c.toString());setTimeout(function(){b.block=0},b.update_rate)}},1)},getInfo:function(){return{longname:"Word Count plugin",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/wordcount",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("wordcount",tinymce.plugins.WordCount)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/wordcount/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/wordcount/editor_plugin_src.js
new file mode 100644
index 00000000..34b26555
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/wordcount/editor_plugin_src.js
@@ -0,0 +1,122 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.WordCount', {
+ block : 0,
+ id : null,
+ countre : null,
+ cleanre : null,
+
+ init : function(ed, url) {
+ var t = this, last = 0, VK = tinymce.VK;
+
+ t.countre = ed.getParam('wordcount_countregex', /[\w\u2019\'-]+/g); // u2019 == &rsquo;
+ t.cleanre = ed.getParam('wordcount_cleanregex', /[0-9.(),;:!?%#$?\'\"_+=\\\/-]*/g);
+ t.update_rate = ed.getParam('wordcount_update_rate', 2000);
+ t.update_on_delete = ed.getParam('wordcount_update_on_delete', false);
+ t.id = ed.id + '-word-count';
+
+ ed.onPostRender.add(function(ed, cm) {
+ var row, id;
+
+ // Add it to the specified id or the theme advanced path
+ id = ed.getParam('wordcount_target_id');
+ if (!id) {
+ row = tinymce.DOM.get(ed.id + '_path_row');
+
+ if (row)
+ tinymce.DOM.add(row.parentNode, 'div', {'style': 'float: right'}, ed.getLang('wordcount.words', 'Words: ') + '<span id="' + t.id + '">0</span>');
+ } else {
+ tinymce.DOM.add(id, 'span', {}, '<span id="' + t.id + '">0</span>');
+ }
+ });
+
+ ed.onInit.add(function(ed) {
+ ed.selection.onSetContent.add(function() {
+ t._count(ed);
+ });
+
+ t._count(ed);
+ });
+
+ ed.onSetContent.add(function(ed) {
+ t._count(ed);
+ });
+
+ function checkKeys(key) {
+ return key !== last && (key === VK.ENTER || last === VK.SPACEBAR || checkDelOrBksp(last));
+ }
+
+ function checkDelOrBksp(key) {
+ return key === VK.DELETE || key === VK.BACKSPACE;
+ }
+
+ ed.onKeyUp.add(function(ed, e) {
+ if (checkKeys(e.keyCode) || t.update_on_delete && checkDelOrBksp(e.keyCode)) {
+ t._count(ed);
+ }
+
+ last = e.keyCode;
+ });
+ },
+
+ _getCount : function(ed) {
+ var tc = 0;
+ var tx = ed.getContent({ format: 'raw' });
+
+ if (tx) {
+ tx = tx.replace(/\.\.\./g, ' '); // convert ellipses to spaces
+ tx = tx.replace(/<.[^<>]*?>/g, ' ').replace(/&nbsp;|&#160;/gi, ' '); // remove html tags and space chars
+
+ // deal with html entities
+ tx = tx.replace(/(\w+)(&.+?;)+(\w+)/, "$1$3").replace(/&.+?;/g, ' ');
+ tx = tx.replace(this.cleanre, ''); // remove numbers and punctuation
+
+ var wordArray = tx.match(this.countre);
+ if (wordArray) {
+ tc = wordArray.length;
+ }
+ }
+
+ return tc;
+ },
+
+ _count : function(ed) {
+ var t = this;
+
+ // Keep multiple calls from happening at the same time
+ if (t.block)
+ return;
+
+ t.block = 1;
+
+ setTimeout(function() {
+ if (!ed.destroyed) {
+ var tc = t._getCount(ed);
+ tinymce.DOM.setHTML(t.id, tc.toString());
+ setTimeout(function() {t.block = 0;}, t.update_rate);
+ }
+ }, 1);
+ },
+
+ getInfo: function() {
+ return {
+ longname : 'Word Count plugin',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/wordcount',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ tinymce.PluginManager.add('wordcount', tinymce.plugins.WordCount);
+})();
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/abbr.htm b/askbot/media/js/tinymce/plugins/xhtmlxtras/abbr.htm
new file mode 100644
index 00000000..30a894f7
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/abbr.htm
@@ -0,0 +1,142 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#xhtmlxtras_dlg.title_abbr_element}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="../../utils/editable_selects.js"></script>
+ <script type="text/javascript" src="js/element_common.js"></script>
+ <script type="text/javascript" src="js/abbr.js"></script>
+ <link rel="stylesheet" type="text/css" href="css/popup.css" />
+</head>
+<body style="display: none" role="application" aria-labelledby="app_title">
+<span style="display:none;" id="app_title">{#xhtmlxtras_dlg.title_abbr_element}</span>
+<form onsubmit="insertAbbr();return false;" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" class="current" aria-controls="general_panel"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#xhtmlxtras_dlg.general_tab}</a></span></li>
+ <!-- <li id="events_tab"><span><a href="javascript:mcTabs.displayTab('events_tab','events_panel');" onmousedown="return false;">{#xhtmlxtras_dlg.events_tab}</a></span></li> -->
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <fieldset>
+ <legend>{#xhtmlxtras_dlg.fieldset_attrib_tab}</legend>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="label"><label id="titlelabel" for="title">{#xhtmlxtras_dlg.attribute_label_title}</label>:</td>
+ <td><input id="title" name="title" type="text" value="" class="field mceFocus" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="idlabel" for="id">{#xhtmlxtras_dlg.attribute_label_id}</label>:</td>
+ <td><input id="id" name="id" type="text" value="" class="field" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="classlabel" for="class">{#xhtmlxtras_dlg.attribute_label_class}</label>:</td>
+ <td>
+ <select id="class" name="class" class="field mceEditableSelect">
+ <option value="">{#not_set}</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="label"><label id="stylelabel" for="style">{#xhtmlxtras_dlg.attribute_label_style}</label>:</td>
+ <td><input id="style" name="style" type="text" value="" class="field" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="dirlabel" for="dir">{#xhtmlxtras_dlg.attribute_label_langdir}</label>:</td>
+ <td>
+ <select id="dir" name="dir" class="field">
+ <option value="">{#not_set}</option>
+ <option value="ltr">{#xhtmlxtras_dlg.attribute_option_ltr}</option>
+ <option value="rtl">{#xhtmlxtras_dlg.attribute_option_rtl}</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="label"><label id="langlabel" for="lang">{#xhtmlxtras_dlg.attribute_label_langcode}</label>:</td>
+ <td>
+ <input id="lang" name="lang" type="text" value="" class="field" />
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ <div id="events_panel" class="panel">
+ <fieldset>
+ <legend>{#xhtmlxtras_dlg.fieldset_events_tab}</legend>
+
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="label"><label for="onfocus">onfocus</label>:</td>
+ <td><input id="onfocus" name="onfocus" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onblur">onblur</label>:</td>
+ <td><input id="onblur" name="onblur" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onclick">onclick</label>:</td>
+ <td><input id="onclick" name="onclick" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="ondblclick">ondblclick</label>:</td>
+ <td><input id="ondblclick" name="ondblclick" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmousedown">onmousedown</label>:</td>
+ <td><input id="onmousedown" name="onmousedown" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseup">onmouseup</label>:</td>
+ <td><input id="onmouseup" name="onmouseup" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseover">onmouseover</label>:</td>
+ <td><input id="onmouseover" name="onmouseover" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmousemove">onmousemove</label>:</td>
+ <td><input id="onmousemove" name="onmousemove" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseout">onmouseout</label>:</td>
+ <td><input id="onmouseout" name="onmouseout" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeypress">onkeypress</label>:</td>
+ <td><input id="onkeypress" name="onkeypress" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeydown">onkeydown</label>:</td>
+ <td><input id="onkeydown" name="onkeydown" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeyup">onkeyup</label>:</td>
+ <td><input id="onkeyup" name="onkeyup" type="text" value="" class="field" /></td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ </div>
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#update}" />
+ <input type="button" id="remove" name="remove" class="button" value="{#xhtmlxtras_dlg.remove}" onclick="removeAbbr();" style="display: none;" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/acronym.htm b/askbot/media/js/tinymce/plugins/xhtmlxtras/acronym.htm
new file mode 100644
index 00000000..c1093459
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/acronym.htm
@@ -0,0 +1,142 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#xhtmlxtras_dlg.title_acronym_element}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="../../utils/editable_selects.js"></script>
+ <script type="text/javascript" src="js/element_common.js"></script>
+ <script type="text/javascript" src="js/acronym.js"></script>
+ <link rel="stylesheet" type="text/css" href="css/popup.css" />
+</head>
+<body style="display: none" role="application" aria-labelledby="app_title">
+<span style="display:none;" id="app_title">{#xhtmlxtras_dlg.title_acronym_element}</span>
+<form onsubmit="insertAcronym();return false;" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" class="current" aria-controls="general_panel"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#xhtmlxtras_dlg.general_tab}</a></span></li>
+ <!-- <li id="events_tab"><span><a href="javascript:mcTabs.displayTab('events_tab','events_panel');" onmousedown="return false;">{#xhtmlxtras_dlg.events_tab}</a></span></li> -->
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <fieldset>
+ <legend>{#xhtmlxtras_dlg.fieldset_attrib_tab}</legend>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="label"><label id="titlelabel" for="title">{#xhtmlxtras_dlg.attribute_label_title}</label>:</td>
+ <td><input id="title" name="title" type="text" value="" class="field mceFocus" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="idlabel" for="id">{#xhtmlxtras_dlg.attribute_label_id}</label>:</td>
+ <td><input id="id" name="id" type="text" value="" class="field" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="classlabel" for="class">{#xhtmlxtras_dlg.attribute_label_class}</label>:</td>
+ <td>
+ <select id="class" name="class" class="field mceEditableSelect">
+ <option value="">{#not_set}</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="label"><label id="stylelabel" for="style">{#xhtmlxtras_dlg.attribute_label_style}</label>:</td>
+ <td><input id="style" name="style" type="text" value="" class="field" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="dirlabel" for="dir">{#xhtmlxtras_dlg.attribute_label_langdir}</label>:</td>
+ <td>
+ <select id="dir" name="dir" class="field">
+ <option value="">{#not_set}</option>
+ <option value="ltr">{#xhtmlxtras_dlg.attribute_option_ltr}</option>
+ <option value="rtl">{#xhtmlxtras_dlg.attribute_option_rtl}</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="label"><label id="langlabel" for="lang">{#xhtmlxtras_dlg.attribute_label_langcode}</label>:</td>
+ <td>
+ <input id="lang" name="lang" type="text" value="" class="field" />
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ <div id="events_panel" class="panel">
+ <fieldset>
+ <legend>{#xhtmlxtras_dlg.fieldset_events_tab}</legend>
+
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="label"><label for="onfocus">onfocus</label>:</td>
+ <td><input id="onfocus" name="onfocus" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onblur">onblur</label>:</td>
+ <td><input id="onblur" name="onblur" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onclick">onclick</label>:</td>
+ <td><input id="onclick" name="onclick" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="ondblclick">ondblclick</label>:</td>
+ <td><input id="ondblclick" name="ondblclick" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmousedown">onmousedown</label>:</td>
+ <td><input id="onmousedown" name="onmousedown" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseup">onmouseup</label>:</td>
+ <td><input id="onmouseup" name="onmouseup" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseover">onmouseover</label>:</td>
+ <td><input id="onmouseover" name="onmouseover" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmousemove">onmousemove</label>:</td>
+ <td><input id="onmousemove" name="onmousemove" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseout">onmouseout</label>:</td>
+ <td><input id="onmouseout" name="onmouseout" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeypress">onkeypress</label>:</td>
+ <td><input id="onkeypress" name="onkeypress" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeydown">onkeydown</label>:</td>
+ <td><input id="onkeydown" name="onkeydown" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeyup">onkeyup</label>:</td>
+ <td><input id="onkeyup" name="onkeyup" type="text" value="" class="field" /></td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ </div>
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#update}" />
+ <input type="button" id="remove" name="remove" class="button" value="{#xhtmlxtras_dlg.remove}" onclick="removeAcronym();" style="display: none;" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/attributes.htm b/askbot/media/js/tinymce/plugins/xhtmlxtras/attributes.htm
new file mode 100644
index 00000000..e8d606a3
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/attributes.htm
@@ -0,0 +1,149 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#xhtmlxtras_dlg.attribs_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/editable_selects.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="js/attributes.js"></script>
+ <link rel="stylesheet" type="text/css" href="css/attributes.css" />
+</head>
+<body style="display: none" role="application" aria-labelledby="app_title">
+<span style="display:none;" id="app_title">{#xhtmlxtras_dlg.attribs_title}</span>
+<form onsubmit="insertAction();return false;" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" class="current" aria-controls="general_panel"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#xhtmlxtras_dlg.attribute_attrib_tab}</a></span></li>
+ <li id="events_tab" aria-controls="events_panel"><span><a href="javascript:mcTabs.displayTab('events_tab','events_panel');" onmousedown="return false;">{#xhtmlxtras_dlg.attribute_events_tab}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <fieldset>
+ <legend>{#xhtmlxtras_dlg.attribute_attrib_tab}</legend>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="label"><label id="titlelabel" for="title">{#xhtmlxtras_dlg.attribute_label_title}</label>:</td>
+ <td><input id="title" name="title" type="text" value="" class="mceFocus" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="idlabel" for="id">{#xhtmlxtras_dlg.attribute_label_id}</label>:</td>
+ <td><input id="id" name="id" type="text" value="" /></td>
+ </tr>
+ <tr>
+ <td><label id="classlabel" for="classlist">{#class_name}</label></td>
+ <td>
+ <select id="classlist" name="classlist" class="mceEditableSelect">
+ <option value="" selected="selected">{#not_set}</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="label"><label id="stylelabel" for="style">{#xhtmlxtras_dlg.attribute_label_style}</label>:</td>
+ <td><input id="style" name="style" type="text" value="" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="dirlabel" for="dir">{#xhtmlxtras_dlg.attribute_label_langdir}</label>:</td>
+ <td>
+ <select id="dir" name="dir">
+ <option value="">{#not_set}</option>
+ <option value="ltr">{#xhtmlxtras_dlg.option_ltr}</option>
+ <option value="rtl">{#xhtmlxtras_dlg.option_rtl}</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="label"><label id="langlabel" for="lang">{#xhtmlxtras_dlg.attribute_label_langcode}</label>:</td>
+ <td>
+ <input id="lang" name="lang" type="text" value="" />
+ </td>
+ </tr>
+ <tr>
+ <td><label id="tabindexlabel" for="tabindex">{#xhtmlxtras_dlg.attribute_label_tabindex}</label></td>
+ <td><input type="text" id="tabindex" name="tabindex" value="" /></td>
+ </tr>
+
+ <tr>
+ <td><label id="accesskeylabel" for="accesskey">{#xhtmlxtras_dlg.attribute_label_accesskey}</label></td>
+ <td><input type="text" id="accesskey" name="accesskey" value="" /></td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ <div id="events_panel" class="panel">
+ <fieldset>
+ <legend>{#xhtmlxtras_dlg.attribute_events_tab}</legend>
+
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="label"><label for="onfocus">onfocus</label>:</td>
+ <td><input id="onfocus" name="onfocus" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onblur">onblur</label>:</td>
+ <td><input id="onblur" name="onblur" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onclick">onclick</label>:</td>
+ <td><input id="onclick" name="onclick" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="ondblclick">ondblclick</label>:</td>
+ <td><input id="ondblclick" name="ondblclick" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmousedown">onmousedown</label>:</td>
+ <td><input id="onmousedown" name="onmousedown" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseup">onmouseup</label>:</td>
+ <td><input id="onmouseup" name="onmouseup" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseover">onmouseover</label>:</td>
+ <td><input id="onmouseover" name="onmouseover" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmousemove">onmousemove</label>:</td>
+ <td><input id="onmousemove" name="onmousemove" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseout">onmouseout</label>:</td>
+ <td><input id="onmouseout" name="onmouseout" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeypress">onkeypress</label>:</td>
+ <td><input id="onkeypress" name="onkeypress" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeydown">onkeydown</label>:</td>
+ <td><input id="onkeydown" name="onkeydown" type="text" value="" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeyup">onkeyup</label>:</td>
+ <td><input id="onkeyup" name="onkeyup" type="text" value="" /></td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ </div>
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#insert}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/cite.htm b/askbot/media/js/tinymce/plugins/xhtmlxtras/cite.htm
new file mode 100644
index 00000000..0ac6bdb6
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/cite.htm
@@ -0,0 +1,142 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#xhtmlxtras_dlg.title_cite_element}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="../../utils/editable_selects.js"></script>
+ <script type="text/javascript" src="js/element_common.js"></script>
+ <script type="text/javascript" src="js/cite.js"></script>
+ <link rel="stylesheet" type="text/css" href="css/popup.css" />
+</head>
+<body style="display: none" role="application" aria-labelledby="app_title">
+<span style="display:none;" id="app_title">{#xhtmlxtras_dlg.title_cite_element}</span>
+<form onsubmit="insertCite();return false;" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" class="current" aria-controls="general_panel"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#xhtmlxtras_dlg.general_tab}</a></span></li>
+ <!-- <li id="events_tab"><span><a href="javascript:mcTabs.displayTab('events_tab','events_panel');" onmousedown="return false;">{#xhtmlxtras_dlg.events_tab}</a></span></li> -->
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <fieldset>
+ <legend>{#xhtmlxtras_dlg.fieldset_attrib_tab}</legend>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="label"><label id="titlelabel" for="title">{#xhtmlxtras_dlg.attribute_label_title}</label>:</td>
+ <td><input id="title" name="title" type="text" value="" class="field mceFocus" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="idlabel" for="id">{#xhtmlxtras_dlg.attribute_label_id}</label>:</td>
+ <td><input id="id" name="id" type="text" value="" class="field" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="classlabel" for="class">{#xhtmlxtras_dlg.attribute_label_class}</label>:</td>
+ <td>
+ <select id="class" name="class" class="field mceEditableSelect">
+ <option value="">{#not_set}</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="label"><label id="stylelabel" for="class">{#xhtmlxtras_dlg.attribute_label_style}</label>:</td>
+ <td><input id="style" name="style" type="text" value="" class="field" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="dirlabel" for="dir">{#xhtmlxtras_dlg.attribute_label_langdir}</label>:</td>
+ <td>
+ <select id="dir" name="dir" class="field">
+ <option value="">{#not_set}</option>
+ <option value="ltr">{#xhtmlxtras_dlg.attribute_option_ltr}</option>
+ <option value="rtl">{#xhtmlxtras_dlg.attribute_option_rtl}</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="label"><label id="langlabel" for="lang">{#xhtmlxtras_dlg.attribute_label_langcode}</label>:</td>
+ <td>
+ <input id="lang" name="lang" type="text" value="" class="field" />
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ <div id="events_panel" class="panel">
+ <fieldset>
+ <legend>{#xhtmlxtras_dlg.fieldset_events_tab}</legend>
+
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="label"><label for="onfocus">onfocus</label>:</td>
+ <td><input id="onfocus" name="onfocus" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onblur">onblur</label>:</td>
+ <td><input id="onblur" name="onblur" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onclick">onclick</label>:</td>
+ <td><input id="onclick" name="onclick" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="ondblclick">ondblclick</label>:</td>
+ <td><input id="ondblclick" name="ondblclick" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmousedown">onmousedown</label>:</td>
+ <td><input id="onmousedown" name="onmousedown" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseup">onmouseup</label>:</td>
+ <td><input id="onmouseup" name="onmouseup" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseover">onmouseover</label>:</td>
+ <td><input id="onmouseover" name="onmouseover" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmousemove">onmousemove</label>:</td>
+ <td><input id="onmousemove" name="onmousemove" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseout">onmouseout</label>:</td>
+ <td><input id="onmouseout" name="onmouseout" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeypress">onkeypress</label>:</td>
+ <td><input id="onkeypress" name="onkeypress" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeydown">onkeydown</label>:</td>
+ <td><input id="onkeydown" name="onkeydown" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeyup">onkeyup</label>:</td>
+ <td><input id="onkeyup" name="onkeyup" type="text" value="" class="field" /></td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ </div>
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#update}" />
+ <input type="button" id="remove" name="remove" class="button" value="{#xhtmlxtras_dlg.remove}" onclick="removeCite();" style="display: none;" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/css/attributes.css b/askbot/media/js/tinymce/plugins/xhtmlxtras/css/attributes.css
new file mode 100644
index 00000000..9a6a235c
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/css/attributes.css
@@ -0,0 +1,11 @@
+.panel_wrapper div.current {
+ height: 290px;
+}
+
+#id, #style, #title, #dir, #hreflang, #lang, #classlist, #tabindex, #accesskey {
+ width: 200px;
+}
+
+#events_panel input {
+ width: 200px;
+}
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/css/popup.css b/askbot/media/js/tinymce/plugins/xhtmlxtras/css/popup.css
new file mode 100644
index 00000000..e67114db
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/css/popup.css
@@ -0,0 +1,9 @@
+input.field, select.field {width:200px;}
+input.picker {width:179px; margin-left: 5px;}
+input.disabled {border-color:#F2F2F2;}
+img.picker {vertical-align:text-bottom; cursor:pointer;}
+h1 {padding: 0 0 5px 0;}
+.panel_wrapper div.current {height:160px;}
+#xhtmlxtrasdel .panel_wrapper div.current, #xhtmlxtrasins .panel_wrapper div.current {height: 230px;}
+a.browse span {display:block; width:20px; height:20px; background:url('../../../themes/advanced/img/icons.gif') -140px -20px;}
+#datetime {width:180px;}
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/del.htm b/askbot/media/js/tinymce/plugins/xhtmlxtras/del.htm
new file mode 100644
index 00000000..5f667510
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/del.htm
@@ -0,0 +1,162 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#xhtmlxtras_dlg.title_del_element}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="../../utils/editable_selects.js"></script>
+ <script type="text/javascript" src="js/element_common.js"></script>
+ <script type="text/javascript" src="js/del.js"></script>
+ <link rel="stylesheet" type="text/css" href="css/popup.css" />
+</head>
+<body id="xhtmlxtrasins" style="display: none" role="application" aria-labelledby="app_title">
+<span style="display:none;" id="app_title">{#xhtmlxtras_dlg.title_del_element}</span>
+<form onsubmit="insertDel();return false;" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" class="current" aria-controls="general_panel"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#xhtmlxtras_dlg.general_tab}</a></span></li>
+ <!-- <li id="events_tab"><span><a href="javascript:mcTabs.displayTab('events_tab','events_panel');" onmousedown="return false;">{#xhtmlxtras_dlg.events_tab}</a></span></li> -->
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <fieldset>
+ <legend>{#xhtmlxtras_dlg.fieldset_general_tab}</legend>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="label"><label id="datetimelabel" for="datetime">{#xhtmlxtras_dlg.attribute_label_datetime}</label>:</td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input id="datetime" name="datetime" type="text" value="" maxlength="19" class="field mceFocus" /></td>
+ <td><a href="javascript:insertDateTime('datetime');" onmousedown="return false;" class="browse" role="button" aria-labelledby="datetimelabel"><span class="datetime" title="{#xhtmlxtras_dlg.insert_date}"></span></a></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td class="label"><label id="citelabel" for="cite">{#xhtmlxtras_dlg.attribute_label_cite}</label>:</td>
+ <td><input id="cite" name="cite" type="text" value="" class="field" /></td>
+ </tr>
+ </table>
+ </fieldset>
+ <fieldset>
+ <legend>{#xhtmlxtras_dlg.fieldset_attrib_tab}</legend>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="label"><label id="titlelabel" for="title">{#xhtmlxtras_dlg.attribute_label_title}</label>:</td>
+ <td><input id="title" name="title" type="text" value="" class="field" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="idlabel" for="id">{#xhtmlxtras_dlg.attribute_label_id}</label>:</td>
+ <td><input id="id" name="id" type="text" value="" class="field" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="classlabel" for="class">{#xhtmlxtras_dlg.attribute_label_class}</label>:</td>
+ <td>
+ <select id="class" name="class" class="field mceEditableSelect">
+ <option value="">{#not_set}</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="label"><label id="stylelabel" for="style">{#xhtmlxtras_dlg.attribute_label_style}</label>:</td>
+ <td><input id="style" name="style" type="text" value="" class="field" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="dirlabel" for="dir">{#xhtmlxtras_dlg.attribute_label_langdir}</label>:</td>
+ <td>
+ <select id="dir" name="dir" class="field">
+ <option value="">{#not_set}</option>
+ <option value="ltr">{#xhtmlxtras_dlg.attribute_option_ltr}</option>
+ <option value="rtl">{#xhtmlxtras_dlg.attribute_option_rtl}</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="label"><label id="langlabel" for="lang">{#xhtmlxtras_dlg.attribute_label_langcode}</label>:</td>
+ <td>
+ <input id="lang" name="lang" type="text" value="" class="field" />
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ <div id="events_panel" class="panel">
+ <fieldset>
+ <legend>{#xhtmlxtras_dlg.fieldset_events_tab}</legend>
+
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="label"><label for="onfocus">onfocus</label>:</td>
+ <td><input id="onfocus" name="onfocus" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onblur">onblur</label>:</td>
+ <td><input id="onblur" name="onblur" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onclick">onclick</label>:</td>
+ <td><input id="onclick" name="onclick" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="ondblclick">ondblclick</label>:</td>
+ <td><input id="ondblclick" name="ondblclick" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmousedown">onmousedown</label>:</td>
+ <td><input id="onmousedown" name="onmousedown" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseup">onmouseup</label>:</td>
+ <td><input id="onmouseup" name="onmouseup" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseover">onmouseover</label>:</td>
+ <td><input id="onmouseover" name="onmouseover" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmousemove">onmousemove</label>:</td>
+ <td><input id="onmousemove" name="onmousemove" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseout">onmouseout</label>:</td>
+ <td><input id="onmouseout" name="onmouseout" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeypress">onkeypress</label>:</td>
+ <td><input id="onkeypress" name="onkeypress" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeydown">onkeydown</label>:</td>
+ <td><input id="onkeydown" name="onkeydown" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeyup">onkeyup</label>:</td>
+ <td><input id="onkeyup" name="onkeyup" type="text" value="" class="field" /></td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ </div>
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#update}" />
+ <input type="button" id="remove" name="remove" class="button" value="{#xhtmlxtras_dlg.remove}" onclick="removeDel();" style="display: none;" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/editor_plugin.js b/askbot/media/js/tinymce/plugins/xhtmlxtras/editor_plugin.js
new file mode 100644
index 00000000..9b98a515
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/editor_plugin.js
@@ -0,0 +1 @@
+(function(){tinymce.create("tinymce.plugins.XHTMLXtrasPlugin",{init:function(a,b){a.addCommand("mceCite",function(){a.windowManager.open({file:b+"/cite.htm",width:350+parseInt(a.getLang("xhtmlxtras.cite_delta_width",0)),height:250+parseInt(a.getLang("xhtmlxtras.cite_delta_height",0)),inline:1},{plugin_url:b})});a.addCommand("mceAcronym",function(){a.windowManager.open({file:b+"/acronym.htm",width:350+parseInt(a.getLang("xhtmlxtras.acronym_delta_width",0)),height:250+parseInt(a.getLang("xhtmlxtras.acronym_delta_height",0)),inline:1},{plugin_url:b})});a.addCommand("mceAbbr",function(){a.windowManager.open({file:b+"/abbr.htm",width:350+parseInt(a.getLang("xhtmlxtras.abbr_delta_width",0)),height:250+parseInt(a.getLang("xhtmlxtras.abbr_delta_height",0)),inline:1},{plugin_url:b})});a.addCommand("mceDel",function(){a.windowManager.open({file:b+"/del.htm",width:340+parseInt(a.getLang("xhtmlxtras.del_delta_width",0)),height:310+parseInt(a.getLang("xhtmlxtras.del_delta_height",0)),inline:1},{plugin_url:b})});a.addCommand("mceIns",function(){a.windowManager.open({file:b+"/ins.htm",width:340+parseInt(a.getLang("xhtmlxtras.ins_delta_width",0)),height:310+parseInt(a.getLang("xhtmlxtras.ins_delta_height",0)),inline:1},{plugin_url:b})});a.addCommand("mceAttributes",function(){a.windowManager.open({file:b+"/attributes.htm",width:380+parseInt(a.getLang("xhtmlxtras.attr_delta_width",0)),height:370+parseInt(a.getLang("xhtmlxtras.attr_delta_height",0)),inline:1},{plugin_url:b})});a.addButton("cite",{title:"xhtmlxtras.cite_desc",cmd:"mceCite"});a.addButton("acronym",{title:"xhtmlxtras.acronym_desc",cmd:"mceAcronym"});a.addButton("abbr",{title:"xhtmlxtras.abbr_desc",cmd:"mceAbbr"});a.addButton("del",{title:"xhtmlxtras.del_desc",cmd:"mceDel"});a.addButton("ins",{title:"xhtmlxtras.ins_desc",cmd:"mceIns"});a.addButton("attribs",{title:"xhtmlxtras.attribs_desc",cmd:"mceAttributes"});a.onNodeChange.add(function(d,c,f,e){f=d.dom.getParent(f,"CITE,ACRONYM,ABBR,DEL,INS");c.setDisabled("cite",e);c.setDisabled("acronym",e);c.setDisabled("abbr",e);c.setDisabled("del",e);c.setDisabled("ins",e);c.setDisabled("attribs",f&&f.nodeName=="BODY");c.setActive("cite",0);c.setActive("acronym",0);c.setActive("abbr",0);c.setActive("del",0);c.setActive("ins",0);if(f){do{c.setDisabled(f.nodeName.toLowerCase(),0);c.setActive(f.nodeName.toLowerCase(),1)}while(f=f.parentNode)}});a.onPreInit.add(function(){a.dom.create("abbr")})},getInfo:function(){return{longname:"XHTML Xtras Plugin",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",infourl:"http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/xhtmlxtras",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.PluginManager.add("xhtmlxtras",tinymce.plugins.XHTMLXtrasPlugin)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/editor_plugin_src.js b/askbot/media/js/tinymce/plugins/xhtmlxtras/editor_plugin_src.js
new file mode 100644
index 00000000..f2405721
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/editor_plugin_src.js
@@ -0,0 +1,132 @@
+/**
+ * editor_plugin_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ tinymce.create('tinymce.plugins.XHTMLXtrasPlugin', {
+ init : function(ed, url) {
+ // Register commands
+ ed.addCommand('mceCite', function() {
+ ed.windowManager.open({
+ file : url + '/cite.htm',
+ width : 350 + parseInt(ed.getLang('xhtmlxtras.cite_delta_width', 0)),
+ height : 250 + parseInt(ed.getLang('xhtmlxtras.cite_delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url
+ });
+ });
+
+ ed.addCommand('mceAcronym', function() {
+ ed.windowManager.open({
+ file : url + '/acronym.htm',
+ width : 350 + parseInt(ed.getLang('xhtmlxtras.acronym_delta_width', 0)),
+ height : 250 + parseInt(ed.getLang('xhtmlxtras.acronym_delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url
+ });
+ });
+
+ ed.addCommand('mceAbbr', function() {
+ ed.windowManager.open({
+ file : url + '/abbr.htm',
+ width : 350 + parseInt(ed.getLang('xhtmlxtras.abbr_delta_width', 0)),
+ height : 250 + parseInt(ed.getLang('xhtmlxtras.abbr_delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url
+ });
+ });
+
+ ed.addCommand('mceDel', function() {
+ ed.windowManager.open({
+ file : url + '/del.htm',
+ width : 340 + parseInt(ed.getLang('xhtmlxtras.del_delta_width', 0)),
+ height : 310 + parseInt(ed.getLang('xhtmlxtras.del_delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url
+ });
+ });
+
+ ed.addCommand('mceIns', function() {
+ ed.windowManager.open({
+ file : url + '/ins.htm',
+ width : 340 + parseInt(ed.getLang('xhtmlxtras.ins_delta_width', 0)),
+ height : 310 + parseInt(ed.getLang('xhtmlxtras.ins_delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url
+ });
+ });
+
+ ed.addCommand('mceAttributes', function() {
+ ed.windowManager.open({
+ file : url + '/attributes.htm',
+ width : 380 + parseInt(ed.getLang('xhtmlxtras.attr_delta_width', 0)),
+ height : 370 + parseInt(ed.getLang('xhtmlxtras.attr_delta_height', 0)),
+ inline : 1
+ }, {
+ plugin_url : url
+ });
+ });
+
+ // Register buttons
+ ed.addButton('cite', {title : 'xhtmlxtras.cite_desc', cmd : 'mceCite'});
+ ed.addButton('acronym', {title : 'xhtmlxtras.acronym_desc', cmd : 'mceAcronym'});
+ ed.addButton('abbr', {title : 'xhtmlxtras.abbr_desc', cmd : 'mceAbbr'});
+ ed.addButton('del', {title : 'xhtmlxtras.del_desc', cmd : 'mceDel'});
+ ed.addButton('ins', {title : 'xhtmlxtras.ins_desc', cmd : 'mceIns'});
+ ed.addButton('attribs', {title : 'xhtmlxtras.attribs_desc', cmd : 'mceAttributes'});
+
+ ed.onNodeChange.add(function(ed, cm, n, co) {
+ n = ed.dom.getParent(n, 'CITE,ACRONYM,ABBR,DEL,INS');
+
+ cm.setDisabled('cite', co);
+ cm.setDisabled('acronym', co);
+ cm.setDisabled('abbr', co);
+ cm.setDisabled('del', co);
+ cm.setDisabled('ins', co);
+ cm.setDisabled('attribs', n && n.nodeName == 'BODY');
+ cm.setActive('cite', 0);
+ cm.setActive('acronym', 0);
+ cm.setActive('abbr', 0);
+ cm.setActive('del', 0);
+ cm.setActive('ins', 0);
+
+ // Activate all
+ if (n) {
+ do {
+ cm.setDisabled(n.nodeName.toLowerCase(), 0);
+ cm.setActive(n.nodeName.toLowerCase(), 1);
+ } while (n = n.parentNode);
+ }
+ });
+
+ ed.onPreInit.add(function() {
+ // Fixed IE issue where it can't handle these elements correctly
+ ed.dom.create('abbr');
+ });
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'XHTML Xtras Plugin',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/xhtmlxtras',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ };
+ }
+ });
+
+ // Register plugin
+ tinymce.PluginManager.add('xhtmlxtras', tinymce.plugins.XHTMLXtrasPlugin);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/ins.htm b/askbot/media/js/tinymce/plugins/xhtmlxtras/ins.htm
new file mode 100644
index 00000000..d001ac7c
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/ins.htm
@@ -0,0 +1,162 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#xhtmlxtras_dlg.title_ins_element}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="../../utils/editable_selects.js"></script>
+ <script type="text/javascript" src="js/element_common.js"></script>
+ <script type="text/javascript" src="js/ins.js"></script>
+ <link rel="stylesheet" type="text/css" href="css/popup.css" />
+</head>
+<body id="xhtmlxtrasins" style="display: none" role="application" aria-labelledby="app_title">
+<span style="display:none;" id="app_title">{#xhtmlxtras_dlg.title_ins_element}</span>
+<form onsubmit="insertIns();return false;" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" class="current" aria-controls="general_panel"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#xhtmlxtras_dlg.general_tab}</a></span></li>
+ <!-- <li id="events_tab"><span><a href="javascript:mcTabs.displayTab('events_tab','events_panel');" onmousedown="return false;">{#xhtmlxtras_dlg.events_tab}</a></span></li> -->
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <fieldset>
+ <legend>{#xhtmlxtras_dlg.fieldset_general_tab}</legend>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="label"><label id="datetimelabel" for="datetime">{#xhtmlxtras_dlg.attribute_label_datetime}</label>:</td>
+ <td>
+ <table role="presentation" border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input id="datetime" name="datetime" type="text" value="" maxlength="19" class="field mceFocus" /></td>
+ <td ><a href="javascript:insertDateTime('datetime');" onmousedown="return false;" class="browse" role="button" aria-labelledby="datetimelabel"><span class="datetime" title="{#xhtmlxtras_dlg.insert_date}"></span></a></td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr >
+ <td class="label"><label id="citelabel" for="cite">{#xhtmlxtras_dlg.attribute_label_cite}</label>:</td>
+ <td><input id="cite" name="cite" type="text" value="" class="field" /></td>
+ </tr>
+ </table>
+ </fieldset>
+ <fieldset>
+ <legend>{#xhtmlxtras_dlg.fieldset_attrib_tab}</legend>
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="label"><label id="titlelabel" for="title">{#xhtmlxtras_dlg.attribute_label_title}</label>:</td>
+ <td><input id="title" name="title" type="text" value="" class="field" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="idlabel" for="id">{#xhtmlxtras_dlg.attribute_label_id}</label>:</td>
+ <td><input id="id" name="id" type="text" value="" class="field" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="classlabel" for="class">{#xhtmlxtras_dlg.attribute_label_class}</label>:</td>
+ <td>
+ <select id="class" name="class" class="field mceEditableSelect">
+ <option value="">{#not_set}</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="label"><label id="stylelabel" for="style">{#xhtmlxtras_dlg.attribute_label_style}</label>:</td>
+ <td><input id="style" name="style" type="text" value="" class="field" /></td>
+ </tr>
+ <tr>
+ <td class="label"><label id="dirlabel" for="dir">{#xhtmlxtras_dlg.attribute_label_langdir}</label>:</td>
+ <td>
+ <select id="dir" name="dir" class="field">
+ <option value="">{#not_set}</option>
+ <option value="ltr">{#xhtmlxtras_dlg.attribute_option_ltr}</option>
+ <option value="rtl">{#xhtmlxtras_dlg.attribute_option_rtl}</option>
+ </select>
+ </td>
+ </tr>
+ <tr>
+ <td class="label"><label id="langlabel" for="lang">{#xhtmlxtras_dlg.attribute_label_langcode}</label>:</td>
+ <td>
+ <input id="lang" name="lang" type="text" value="" class="field" />
+ </td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ <div id="events_panel" class="panel">
+ <fieldset>
+ <legend>{#xhtmlxtras_dlg.fieldset_events_tab}</legend>
+
+ <table role="presentation" border="0" cellpadding="0" cellspacing="4">
+ <tr>
+ <td class="label"><label for="onfocus">onfocus</label>:</td>
+ <td><input id="onfocus" name="onfocus" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onblur">onblur</label>:</td>
+ <td><input id="onblur" name="onblur" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onclick">onclick</label>:</td>
+ <td><input id="onclick" name="onclick" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="ondblclick">ondblclick</label>:</td>
+ <td><input id="ondblclick" name="ondblclick" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmousedown">onmousedown</label>:</td>
+ <td><input id="onmousedown" name="onmousedown" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseup">onmouseup</label>:</td>
+ <td><input id="onmouseup" name="onmouseup" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseover">onmouseover</label>:</td>
+ <td><input id="onmouseover" name="onmouseover" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmousemove">onmousemove</label>:</td>
+ <td><input id="onmousemove" name="onmousemove" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onmouseout">onmouseout</label>:</td>
+ <td><input id="onmouseout" name="onmouseout" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeypress">onkeypress</label>:</td>
+ <td><input id="onkeypress" name="onkeypress" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeydown">onkeydown</label>:</td>
+ <td><input id="onkeydown" name="onkeydown" type="text" value="" class="field" /></td>
+ </tr>
+
+ <tr>
+ <td class="label"><label for="onkeyup">onkeyup</label>:</td>
+ <td><input id="onkeyup" name="onkeyup" type="text" value="" class="field" /></td>
+ </tr>
+ </table>
+ </fieldset>
+ </div>
+ </div>
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#update}" />
+ <input type="button" id="remove" name="remove" class="button" value="{#xhtmlxtras_dlg.remove}" onclick="removeIns();" style="display: none;" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/js/abbr.js b/askbot/media/js/tinymce/plugins/xhtmlxtras/js/abbr.js
new file mode 100644
index 00000000..4b51a257
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/js/abbr.js
@@ -0,0 +1,28 @@
+/**
+ * abbr.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+function init() {
+ SXE.initElementDialog('abbr');
+ if (SXE.currentAction == "update") {
+ SXE.showRemoveButton();
+ }
+}
+
+function insertAbbr() {
+ SXE.insertElement('abbr');
+ tinyMCEPopup.close();
+}
+
+function removeAbbr() {
+ SXE.removeElement('abbr');
+ tinyMCEPopup.close();
+}
+
+tinyMCEPopup.onInit.add(init);
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/js/acronym.js b/askbot/media/js/tinymce/plugins/xhtmlxtras/js/acronym.js
new file mode 100644
index 00000000..6ec2f887
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/js/acronym.js
@@ -0,0 +1,28 @@
+/**
+ * acronym.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+function init() {
+ SXE.initElementDialog('acronym');
+ if (SXE.currentAction == "update") {
+ SXE.showRemoveButton();
+ }
+}
+
+function insertAcronym() {
+ SXE.insertElement('acronym');
+ tinyMCEPopup.close();
+}
+
+function removeAcronym() {
+ SXE.removeElement('acronym');
+ tinyMCEPopup.close();
+}
+
+tinyMCEPopup.onInit.add(init);
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/js/attributes.js b/askbot/media/js/tinymce/plugins/xhtmlxtras/js/attributes.js
new file mode 100644
index 00000000..9c99995a
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/js/attributes.js
@@ -0,0 +1,111 @@
+/**
+ * attributes.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+function init() {
+ tinyMCEPopup.resizeToInnerSize();
+ var inst = tinyMCEPopup.editor;
+ var dom = inst.dom;
+ var elm = inst.selection.getNode();
+ var f = document.forms[0];
+ var onclick = dom.getAttrib(elm, 'onclick');
+
+ setFormValue('title', dom.getAttrib(elm, 'title'));
+ setFormValue('id', dom.getAttrib(elm, 'id'));
+ setFormValue('style', dom.getAttrib(elm, "style"));
+ setFormValue('dir', dom.getAttrib(elm, 'dir'));
+ setFormValue('lang', dom.getAttrib(elm, 'lang'));
+ setFormValue('tabindex', dom.getAttrib(elm, 'tabindex', typeof(elm.tabindex) != "undefined" ? elm.tabindex : ""));
+ setFormValue('accesskey', dom.getAttrib(elm, 'accesskey', typeof(elm.accesskey) != "undefined" ? elm.accesskey : ""));
+ setFormValue('onfocus', dom.getAttrib(elm, 'onfocus'));
+ setFormValue('onblur', dom.getAttrib(elm, 'onblur'));
+ setFormValue('onclick', onclick);
+ setFormValue('ondblclick', dom.getAttrib(elm, 'ondblclick'));
+ setFormValue('onmousedown', dom.getAttrib(elm, 'onmousedown'));
+ setFormValue('onmouseup', dom.getAttrib(elm, 'onmouseup'));
+ setFormValue('onmouseover', dom.getAttrib(elm, 'onmouseover'));
+ setFormValue('onmousemove', dom.getAttrib(elm, 'onmousemove'));
+ setFormValue('onmouseout', dom.getAttrib(elm, 'onmouseout'));
+ setFormValue('onkeypress', dom.getAttrib(elm, 'onkeypress'));
+ setFormValue('onkeydown', dom.getAttrib(elm, 'onkeydown'));
+ setFormValue('onkeyup', dom.getAttrib(elm, 'onkeyup'));
+ className = dom.getAttrib(elm, 'class');
+
+ addClassesToList('classlist', 'advlink_styles');
+ selectByValue(f, 'classlist', className, true);
+
+ TinyMCE_EditableSelects.init();
+}
+
+function setFormValue(name, value) {
+ if(value && document.forms[0].elements[name]){
+ document.forms[0].elements[name].value = value;
+ }
+}
+
+function insertAction() {
+ var inst = tinyMCEPopup.editor;
+ var elm = inst.selection.getNode();
+
+ setAllAttribs(elm);
+ tinyMCEPopup.execCommand("mceEndUndoLevel");
+ tinyMCEPopup.close();
+}
+
+function setAttrib(elm, attrib, value) {
+ var formObj = document.forms[0];
+ var valueElm = formObj.elements[attrib.toLowerCase()];
+ var inst = tinyMCEPopup.editor;
+ var dom = inst.dom;
+
+ if (typeof(value) == "undefined" || value == null) {
+ value = "";
+
+ if (valueElm)
+ value = valueElm.value;
+ }
+
+ dom.setAttrib(elm, attrib.toLowerCase(), value);
+}
+
+function setAllAttribs(elm) {
+ var f = document.forms[0];
+
+ setAttrib(elm, 'title');
+ setAttrib(elm, 'id');
+ setAttrib(elm, 'style');
+ setAttrib(elm, 'class', getSelectValue(f, 'classlist'));
+ setAttrib(elm, 'dir');
+ setAttrib(elm, 'lang');
+ setAttrib(elm, 'tabindex');
+ setAttrib(elm, 'accesskey');
+ setAttrib(elm, 'onfocus');
+ setAttrib(elm, 'onblur');
+ setAttrib(elm, 'onclick');
+ setAttrib(elm, 'ondblclick');
+ setAttrib(elm, 'onmousedown');
+ setAttrib(elm, 'onmouseup');
+ setAttrib(elm, 'onmouseover');
+ setAttrib(elm, 'onmousemove');
+ setAttrib(elm, 'onmouseout');
+ setAttrib(elm, 'onkeypress');
+ setAttrib(elm, 'onkeydown');
+ setAttrib(elm, 'onkeyup');
+
+ // Refresh in old MSIE
+// if (tinyMCE.isMSIE5)
+// elm.outerHTML = elm.outerHTML;
+}
+
+function insertAttribute() {
+ tinyMCEPopup.close();
+}
+
+tinyMCEPopup.onInit.add(init);
+tinyMCEPopup.requireLangPack();
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/js/cite.js b/askbot/media/js/tinymce/plugins/xhtmlxtras/js/cite.js
new file mode 100644
index 00000000..009b7154
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/js/cite.js
@@ -0,0 +1,28 @@
+/**
+ * cite.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+function init() {
+ SXE.initElementDialog('cite');
+ if (SXE.currentAction == "update") {
+ SXE.showRemoveButton();
+ }
+}
+
+function insertCite() {
+ SXE.insertElement('cite');
+ tinyMCEPopup.close();
+}
+
+function removeCite() {
+ SXE.removeElement('cite');
+ tinyMCEPopup.close();
+}
+
+tinyMCEPopup.onInit.add(init);
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/js/del.js b/askbot/media/js/tinymce/plugins/xhtmlxtras/js/del.js
new file mode 100644
index 00000000..1f957dc7
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/js/del.js
@@ -0,0 +1,53 @@
+/**
+ * del.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+function init() {
+ SXE.initElementDialog('del');
+ if (SXE.currentAction == "update") {
+ setFormValue('datetime', tinyMCEPopup.editor.dom.getAttrib(SXE.updateElement, 'datetime'));
+ setFormValue('cite', tinyMCEPopup.editor.dom.getAttrib(SXE.updateElement, 'cite'));
+ SXE.showRemoveButton();
+ }
+}
+
+function setElementAttribs(elm) {
+ setAllCommonAttribs(elm);
+ setAttrib(elm, 'datetime');
+ setAttrib(elm, 'cite');
+ elm.removeAttribute('data-mce-new');
+}
+
+function insertDel() {
+ var elm = tinyMCEPopup.editor.dom.getParent(SXE.focusElement, 'DEL');
+
+ if (elm == null) {
+ var s = SXE.inst.selection.getContent();
+ if(s.length > 0) {
+ insertInlineElement('del');
+ var elementArray = SXE.inst.dom.select('del[data-mce-new]');
+ for (var i=0; i<elementArray.length; i++) {
+ var elm = elementArray[i];
+ setElementAttribs(elm);
+ }
+ }
+ } else {
+ setElementAttribs(elm);
+ }
+ tinyMCEPopup.editor.nodeChanged();
+ tinyMCEPopup.execCommand('mceEndUndoLevel');
+ tinyMCEPopup.close();
+}
+
+function removeDel() {
+ SXE.removeElement('del');
+ tinyMCEPopup.close();
+}
+
+tinyMCEPopup.onInit.add(init);
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/js/element_common.js b/askbot/media/js/tinymce/plugins/xhtmlxtras/js/element_common.js
new file mode 100644
index 00000000..4e5d9c3b
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/js/element_common.js
@@ -0,0 +1,229 @@
+/**
+ * element_common.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+tinyMCEPopup.requireLangPack();
+
+function initCommonAttributes(elm) {
+ var formObj = document.forms[0], dom = tinyMCEPopup.editor.dom;
+
+ // Setup form data for common element attributes
+ setFormValue('title', dom.getAttrib(elm, 'title'));
+ setFormValue('id', dom.getAttrib(elm, 'id'));
+ selectByValue(formObj, 'class', dom.getAttrib(elm, 'class'), true);
+ setFormValue('style', dom.getAttrib(elm, 'style'));
+ selectByValue(formObj, 'dir', dom.getAttrib(elm, 'dir'));
+ setFormValue('lang', dom.getAttrib(elm, 'lang'));
+ setFormValue('onfocus', dom.getAttrib(elm, 'onfocus'));
+ setFormValue('onblur', dom.getAttrib(elm, 'onblur'));
+ setFormValue('onclick', dom.getAttrib(elm, 'onclick'));
+ setFormValue('ondblclick', dom.getAttrib(elm, 'ondblclick'));
+ setFormValue('onmousedown', dom.getAttrib(elm, 'onmousedown'));
+ setFormValue('onmouseup', dom.getAttrib(elm, 'onmouseup'));
+ setFormValue('onmouseover', dom.getAttrib(elm, 'onmouseover'));
+ setFormValue('onmousemove', dom.getAttrib(elm, 'onmousemove'));
+ setFormValue('onmouseout', dom.getAttrib(elm, 'onmouseout'));
+ setFormValue('onkeypress', dom.getAttrib(elm, 'onkeypress'));
+ setFormValue('onkeydown', dom.getAttrib(elm, 'onkeydown'));
+ setFormValue('onkeyup', dom.getAttrib(elm, 'onkeyup'));
+}
+
+function setFormValue(name, value) {
+ if(document.forms[0].elements[name]) document.forms[0].elements[name].value = value;
+}
+
+function insertDateTime(id) {
+ document.getElementById(id).value = getDateTime(new Date(), "%Y-%m-%dT%H:%M:%S");
+}
+
+function getDateTime(d, fmt) {
+ fmt = fmt.replace("%D", "%m/%d/%y");
+ fmt = fmt.replace("%r", "%I:%M:%S %p");
+ fmt = fmt.replace("%Y", "" + d.getFullYear());
+ fmt = fmt.replace("%y", "" + d.getYear());
+ fmt = fmt.replace("%m", addZeros(d.getMonth()+1, 2));
+ fmt = fmt.replace("%d", addZeros(d.getDate(), 2));
+ fmt = fmt.replace("%H", "" + addZeros(d.getHours(), 2));
+ fmt = fmt.replace("%M", "" + addZeros(d.getMinutes(), 2));
+ fmt = fmt.replace("%S", "" + addZeros(d.getSeconds(), 2));
+ fmt = fmt.replace("%I", "" + ((d.getHours() + 11) % 12 + 1));
+ fmt = fmt.replace("%p", "" + (d.getHours() < 12 ? "AM" : "PM"));
+ fmt = fmt.replace("%%", "%");
+
+ return fmt;
+}
+
+function addZeros(value, len) {
+ var i;
+
+ value = "" + value;
+
+ if (value.length < len) {
+ for (i=0; i<(len-value.length); i++)
+ value = "0" + value;
+ }
+
+ return value;
+}
+
+function selectByValue(form_obj, field_name, value, add_custom, ignore_case) {
+ if (!form_obj || !form_obj.elements[field_name])
+ return;
+
+ var sel = form_obj.elements[field_name];
+
+ var found = false;
+ for (var i=0; i<sel.options.length; i++) {
+ var option = sel.options[i];
+
+ if (option.value == value || (ignore_case && option.value.toLowerCase() == value.toLowerCase())) {
+ option.selected = true;
+ found = true;
+ } else
+ option.selected = false;
+ }
+
+ if (!found && add_custom && value != '') {
+ var option = new Option('Value: ' + value, value);
+ option.selected = true;
+ sel.options[sel.options.length] = option;
+ }
+
+ return found;
+}
+
+function setAttrib(elm, attrib, value) {
+ var formObj = document.forms[0];
+ var valueElm = formObj.elements[attrib.toLowerCase()];
+ tinyMCEPopup.editor.dom.setAttrib(elm, attrib, value || valueElm.value);
+}
+
+function setAllCommonAttribs(elm) {
+ setAttrib(elm, 'title');
+ setAttrib(elm, 'id');
+ setAttrib(elm, 'class');
+ setAttrib(elm, 'style');
+ setAttrib(elm, 'dir');
+ setAttrib(elm, 'lang');
+ /*setAttrib(elm, 'onfocus');
+ setAttrib(elm, 'onblur');
+ setAttrib(elm, 'onclick');
+ setAttrib(elm, 'ondblclick');
+ setAttrib(elm, 'onmousedown');
+ setAttrib(elm, 'onmouseup');
+ setAttrib(elm, 'onmouseover');
+ setAttrib(elm, 'onmousemove');
+ setAttrib(elm, 'onmouseout');
+ setAttrib(elm, 'onkeypress');
+ setAttrib(elm, 'onkeydown');
+ setAttrib(elm, 'onkeyup');*/
+}
+
+SXE = {
+ currentAction : "insert",
+ inst : tinyMCEPopup.editor,
+ updateElement : null
+}
+
+SXE.focusElement = SXE.inst.selection.getNode();
+
+SXE.initElementDialog = function(element_name) {
+ addClassesToList('class', 'xhtmlxtras_styles');
+ TinyMCE_EditableSelects.init();
+
+ element_name = element_name.toLowerCase();
+ var elm = SXE.inst.dom.getParent(SXE.focusElement, element_name.toUpperCase());
+ if (elm != null && elm.nodeName.toUpperCase() == element_name.toUpperCase()) {
+ SXE.currentAction = "update";
+ }
+
+ if (SXE.currentAction == "update") {
+ initCommonAttributes(elm);
+ SXE.updateElement = elm;
+ }
+
+ document.forms[0].insert.value = tinyMCEPopup.getLang(SXE.currentAction, 'Insert', true);
+}
+
+SXE.insertElement = function(element_name) {
+ var elm = SXE.inst.dom.getParent(SXE.focusElement, element_name.toUpperCase()), h, tagName;
+
+ if (elm == null) {
+ var s = SXE.inst.selection.getContent();
+ if(s.length > 0) {
+ tagName = element_name;
+
+ insertInlineElement(element_name);
+ var elementArray = tinymce.grep(SXE.inst.dom.select(element_name));
+ for (var i=0; i<elementArray.length; i++) {
+ var elm = elementArray[i];
+
+ if (SXE.inst.dom.getAttrib(elm, 'data-mce-new')) {
+ elm.id = '';
+ elm.setAttribute('id', '');
+ elm.removeAttribute('id');
+ elm.removeAttribute('data-mce-new');
+
+ setAllCommonAttribs(elm);
+ }
+ }
+ }
+ } else {
+ setAllCommonAttribs(elm);
+ }
+ SXE.inst.nodeChanged();
+ tinyMCEPopup.execCommand('mceEndUndoLevel');
+}
+
+SXE.removeElement = function(element_name){
+ element_name = element_name.toLowerCase();
+ elm = SXE.inst.dom.getParent(SXE.focusElement, element_name.toUpperCase());
+ if(elm && elm.nodeName.toUpperCase() == element_name.toUpperCase()){
+ tinyMCE.execCommand('mceRemoveNode', false, elm);
+ SXE.inst.nodeChanged();
+ tinyMCEPopup.execCommand('mceEndUndoLevel');
+ }
+}
+
+SXE.showRemoveButton = function() {
+ document.getElementById("remove").style.display = '';
+}
+
+SXE.containsClass = function(elm,cl) {
+ return (elm.className.indexOf(cl) > -1) ? true : false;
+}
+
+SXE.removeClass = function(elm,cl) {
+ if(elm.className == null || elm.className == "" || !SXE.containsClass(elm,cl)) {
+ return true;
+ }
+ var classNames = elm.className.split(" ");
+ var newClassNames = "";
+ for (var x = 0, cnl = classNames.length; x < cnl; x++) {
+ if (classNames[x] != cl) {
+ newClassNames += (classNames[x] + " ");
+ }
+ }
+ elm.className = newClassNames.substring(0,newClassNames.length-1); //removes extra space at the end
+}
+
+SXE.addClass = function(elm,cl) {
+ if(!SXE.containsClass(elm,cl)) elm.className ? elm.className += " " + cl : elm.className = cl;
+ return true;
+}
+
+function insertInlineElement(en) {
+ var ed = tinyMCEPopup.editor, dom = ed.dom;
+
+ ed.getDoc().execCommand('FontName', false, 'mceinline');
+ tinymce.each(dom.select('span,font'), function(n) {
+ if (n.style.fontFamily == 'mceinline' || n.face == 'mceinline')
+ dom.replace(dom.create(en, {'data-mce-new' : 1}), n, 1);
+ });
+}
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/js/ins.js b/askbot/media/js/tinymce/plugins/xhtmlxtras/js/ins.js
new file mode 100644
index 00000000..c4addfb0
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/js/ins.js
@@ -0,0 +1,53 @@
+/**
+ * ins.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+function init() {
+ SXE.initElementDialog('ins');
+ if (SXE.currentAction == "update") {
+ setFormValue('datetime', tinyMCEPopup.editor.dom.getAttrib(SXE.updateElement, 'datetime'));
+ setFormValue('cite', tinyMCEPopup.editor.dom.getAttrib(SXE.updateElement, 'cite'));
+ SXE.showRemoveButton();
+ }
+}
+
+function setElementAttribs(elm) {
+ setAllCommonAttribs(elm);
+ setAttrib(elm, 'datetime');
+ setAttrib(elm, 'cite');
+ elm.removeAttribute('data-mce-new');
+}
+
+function insertIns() {
+ var elm = tinyMCEPopup.editor.dom.getParent(SXE.focusElement, 'INS');
+
+ if (elm == null) {
+ var s = SXE.inst.selection.getContent();
+ if(s.length > 0) {
+ insertInlineElement('ins');
+ var elementArray = SXE.inst.dom.select('ins[data-mce-new]');
+ for (var i=0; i<elementArray.length; i++) {
+ var elm = elementArray[i];
+ setElementAttribs(elm);
+ }
+ }
+ } else {
+ setElementAttribs(elm);
+ }
+ tinyMCEPopup.editor.nodeChanged();
+ tinyMCEPopup.execCommand('mceEndUndoLevel');
+ tinyMCEPopup.close();
+}
+
+function removeIns() {
+ SXE.removeElement('ins');
+ tinyMCEPopup.close();
+}
+
+tinyMCEPopup.onInit.add(init);
diff --git a/askbot/media/js/tinymce/plugins/xhtmlxtras/langs/en_dlg.js b/askbot/media/js/tinymce/plugins/xhtmlxtras/langs/en_dlg.js
new file mode 100644
index 00000000..c4569f85
--- /dev/null
+++ b/askbot/media/js/tinymce/plugins/xhtmlxtras/langs/en_dlg.js
@@ -0,0 +1 @@
+tinyMCE.addI18n('en.xhtmlxtras_dlg',{"attribs_title":"Insert/Edit Attributes","option_rtl":"Right to Left","option_ltr":"Left to Right","insert_date":"Insert Current Date/Time",remove:"Remove","title_cite_element":"Citation Element","title_abbr_element":"Abbreviation Element","title_acronym_element":"Acronym Element","title_del_element":"Deletion Element","title_ins_element":"Insertion Element","fieldset_events_tab":"Element Events","fieldset_attrib_tab":"Element Attributes","fieldset_general_tab":"General Settings","events_tab":"Events","attrib_tab":"Attributes","general_tab":"General","attribute_attrib_tab":"Attributes","attribute_events_tab":"Events","attribute_label_accesskey":"AccessKey","attribute_label_tabindex":"TabIndex","attribute_label_langcode":"Language","attribute_option_rtl":"Right to Left","attribute_option_ltr":"Left to Right","attribute_label_langdir":"Text Direction","attribute_label_datetime":"Date/Time","attribute_label_cite":"Cite","attribute_label_style":"Style","attribute_label_class":"Class","attribute_label_id":"ID","attribute_label_title":"Title"}); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/themes/advanced/about.htm b/askbot/media/js/tinymce/themes/advanced/about.htm
new file mode 100644
index 00000000..7a97cb71
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/about.htm
@@ -0,0 +1,52 @@
+<!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">
+<head>
+ <title>{#advanced_dlg.about_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="js/about.js"></script>
+</head>
+<body id="about" style="display: none">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" class="current" aria-controls="general_panel"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#advanced_dlg.about_general}</a></span></li>
+ <li id="help_tab" style="display:none" aria-hidden="true" aria-controls="help_panel"><span><a href="javascript:mcTabs.displayTab('help_tab','help_panel');" onmousedown="return false;">{#advanced_dlg.about_help}</a></span></li>
+ <li id="plugins_tab" aria-controls="plugins_panel"><span><a href="javascript:mcTabs.displayTab('plugins_tab','plugins_panel');" onmousedown="return false;">{#advanced_dlg.about_plugins}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <h3>{#advanced_dlg.about_title}</h3>
+ <p>Version: <span id="version"></span> (<span id="date"></span>)</p>
+ <p>TinyMCE is a platform independent web based Javascript HTML WYSIWYG editor control released as Open Source under <a href="../../license.txt" target="_blank">LGPL</a>
+ by Moxiecode Systems AB. It has the ability to convert HTML TEXTAREA fields or other HTML elements to editor instances.</p>
+ <p>Copyright &copy; 2003-2008, <a href="http://www.moxiecode.com" target="_blank">Moxiecode Systems AB</a>, All rights reserved.</p>
+ <p>For more information about this software visit the <a href="http://tinymce.moxiecode.com" target="_blank">TinyMCE website</a>.</p>
+
+ <div id="buttoncontainer">
+ <a href="http://www.moxiecode.com" target="_blank"><img src="http://tinymce.moxiecode.com/images/gotmoxie.png" alt="Got Moxie?" border="0" /></a>
+ </div>
+ </div>
+
+ <div id="plugins_panel" class="panel">
+ <div id="pluginscontainer">
+ <h3>{#advanced_dlg.about_loaded}</h3>
+
+ <div id="plugintablecontainer">
+ </div>
+
+ <p>&nbsp;</p>
+ </div>
+ </div>
+
+ <div id="help_panel" class="panel noscroll" style="overflow: visible;">
+ <div id="iframecontainer"></div>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="button" id="cancel" name="cancel" value="{#close}" onclick="tinyMCEPopup.close();" />
+ </div>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/themes/advanced/anchor.htm b/askbot/media/js/tinymce/themes/advanced/anchor.htm
new file mode 100644
index 00000000..75c93b79
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/anchor.htm
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#advanced_dlg.anchor_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="js/anchor.js"></script>
+</head>
+<body style="display: none" role="application" aria-labelledby="app_title">
+<form onsubmit="AnchorDialog.update();return false;" action="#">
+ <table border="0" cellpadding="4" cellspacing="0" role="presentation">
+ <tr>
+ <td colspan="2" class="title" id="app_title">{#advanced_dlg.anchor_title}</td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="anchorName">{#advanced_dlg.anchor_name}:</label></td>
+ <td><input name="anchorName" type="text" class="mceFocus" id="anchorName" value="" style="width: 200px" aria-required="true" /></td>
+ </tr>
+ </table>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#update}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/themes/advanced/charmap.htm b/askbot/media/js/tinymce/themes/advanced/charmap.htm
new file mode 100644
index 00000000..d4b6bdfb
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/charmap.htm
@@ -0,0 +1,55 @@
+<!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">
+<head>
+ <title>{#advanced_dlg.charmap_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="js/charmap.js"></script>
+</head>
+<body id="charmap" style="display:none" role="application">
+<table align="center" border="0" cellspacing="0" cellpadding="2" role="presentation">
+ <tr>
+ <td colspan="2" class="title" ><label for="charmapView" id="charmap_label">{#advanced_dlg.charmap_title}</label></td>
+ </tr>
+ <tr>
+ <td id="charmapView" rowspan="2" align="left" valign="top">
+ <!-- Chars will be rendered here -->
+ </td>
+ <td width="100" align="center" valign="top">
+ <table border="0" cellpadding="0" cellspacing="0" width="100" style="height:100px" role="presentation">
+ <tr>
+ <td id="codeV">&nbsp;</td>
+ </tr>
+ <tr>
+ <td id="codeN">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td valign="bottom" style="padding-bottom: 3px;">
+ <table width="100" align="center" border="0" cellpadding="2" cellspacing="0" role="presentation">
+ <tr>
+ <td align="center" style="border-left: 1px solid #666699; border-top: 1px solid #666699; border-right: 1px solid #666699;"><label for="codeA">HTML-Code</label></td>
+ </tr>
+ <tr>
+ <td style="font-size: 16px; font-weight: bold; border-left: 1px solid #666699; border-bottom: 1px solid #666699; border-right: 1px solid #666699;" id="codeA" align="center">&nbsp;</td>
+ </tr>
+ <tr>
+ <td style="font-size: 1px;">&nbsp;</td>
+ </tr>
+ <tr>
+ <td align="center" style="border-left: 1px solid #666699; border-top: 1px solid #666699; border-right: 1px solid #666699;"><label for="codeB">NUM-Code</label></td>
+ </tr>
+ <tr>
+ <td style="font-size: 16px; font-weight: bold; border-left: 1px solid #666699; border-bottom: 1px solid #666699; border-right: 1px solid #666699;" id="codeB" align="center">&nbsp;</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2" id="charmap_usage">{#advanced_dlg.charmap_usage}</td>
+ </tr>
+
+</table>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/themes/advanced/color_picker.htm b/askbot/media/js/tinymce/themes/advanced/color_picker.htm
new file mode 100644
index 00000000..b625531a
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/color_picker.htm
@@ -0,0 +1,70 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#advanced_dlg.colorpicker_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="js/color_picker.js"></script>
+</head>
+<body id="colorpicker" style="display: none" role="application" aria-labelledby="app_label">
+ <span class="mceVoiceLabel" id="app_label" style="display:none;">{#advanced_dlg.colorpicker_title}</span>
+<form onsubmit="insertAction();return false" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="picker_tab" aria-controls="picker_panel" class="current"><span><a href="javascript:mcTabs.displayTab('picker_tab','picker_panel');" onmousedown="return false;">{#advanced_dlg.colorpicker_picker_tab}</a></span></li>
+ <li id="rgb_tab" aria-controls="rgb_panel"><span><a href="javascript:;" onclick="mcTabs.displayTab('rgb_tab','rgb_panel');" onmousedown="return false;">{#advanced_dlg.colorpicker_palette_tab}</a></span></li>
+ <li id="named_tab" aria-controls="named_panel"><span><a href="javascript:;" onclick="javascript:mcTabs.displayTab('named_tab','named_panel');" onmousedown="return false;">{#advanced_dlg.colorpicker_named_tab}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="picker_panel" class="panel current">
+ <fieldset>
+ <legend>{#advanced_dlg.colorpicker_picker_title}</legend>
+ <div id="picker">
+ <img id="colors" src="img/colorpicker.jpg" onclick="computeColor(event)" onmousedown="isMouseDown = true;return false;" onmouseup="isMouseDown = false;" onmousemove="if (isMouseDown && isMouseOver) computeColor(event); return false;" onmouseover="isMouseOver=true;" onmouseout="isMouseOver=false;" alt="" />
+
+ <div id="light">
+ <!-- Will be filled with divs -->
+ </div>
+
+ <br style="clear: both" />
+ </div>
+ </fieldset>
+ </div>
+
+ <div id="rgb_panel" class="panel">
+ <fieldset>
+ <legend id="webcolors_title">{#advanced_dlg.colorpicker_palette_title}</legend>
+ <div id="webcolors">
+ <!-- Gets filled with web safe colors-->
+ </div>
+
+ <br style="clear: both" />
+ </fieldset>
+ </div>
+
+ <div id="named_panel" class="panel">
+ <fieldset id="named_picker_label">
+ <legend id="named_title">{#advanced_dlg.colorpicker_named_title}</legend>
+ <div id="namedcolors" role="listbox" tabindex="0" aria-labelledby="named_picker_label">
+ <!-- Gets filled with named colors-->
+ </div>
+
+ <br style="clear: both" />
+
+ <div id="colornamecontainer">
+ {#advanced_dlg.colorpicker_name} <span id="colorname"></span>
+ </div>
+ </fieldset>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#apply}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();"/>
+ <div id="preview_wrapper"><div id="previewblock"><label for="color">{#advanced_dlg.colorpicker_color}</label> <input id="color" type="text" size="8" class="text mceFocus" aria-required="true" /></div><span id="preview"></span></div>
+ </div>
+</form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/themes/advanced/editor_template.js b/askbot/media/js/tinymce/themes/advanced/editor_template.js
new file mode 100644
index 00000000..4d5acfb3
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/editor_template.js
@@ -0,0 +1 @@
+(function(h){var i=h.DOM,g=h.dom.Event,c=h.extend,f=h.each,a=h.util.Cookie,e,d=h.explode;function b(m,k){var q,p=m.dom,n="",o,l;previewStyles=m.settings.preview_styles;if(previewStyles===false){return""}if(!previewStyles){previewStyles="font-family font-size font-weight text-decoration text-transform color background-color"}function j(r){return r.replace(/%(\w+)/g,"")}name=k.block||k.inline||"span";q=p.create(name);f(k.styles,function(s,r){s=j(s);if(s){p.setStyle(q,r,s)}});f(k.attributes,function(s,r){s=j(s);if(s){p.setAttrib(q,r,s)}});f(k.classes,function(r){r=j(r);if(!p.hasClass(q,r)){p.addClass(q,r)}});p.setStyles(q,{position:"absolute",left:-65535});m.getBody().appendChild(q);o=p.getStyle(m.getBody(),"fontSize",true);o=/px$/.test(o)?parseInt(o,10):0;f(previewStyles.split(" "),function(r){var s=p.getStyle(q,r,true);if(r=="background-color"&&/transparent|rgba\s*\([^)]+,\s*0\)/.test(s)){s=p.getStyle(m.getBody(),r,true);if(p.toHex(s).toLowerCase()=="#ffffff"){return}}if(r=="font-size"){if(/em|%$/.test(s)){if(o===0){return}s=parseFloat(s,10)/(/%$/.test(s)?100:1);s=(s*o)+"px"}}n+=r+":"+s+";"});p.remove(q);return n}h.ThemeManager.requireLangPack("advanced");h.create("tinymce.themes.AdvancedTheme",{sizes:[8,10,12,14,18,24,36],controls:{bold:["bold_desc","Bold"],italic:["italic_desc","Italic"],underline:["underline_desc","Underline"],strikethrough:["striketrough_desc","Strikethrough"],justifyleft:["justifyleft_desc","JustifyLeft"],justifycenter:["justifycenter_desc","JustifyCenter"],justifyright:["justifyright_desc","JustifyRight"],justifyfull:["justifyfull_desc","JustifyFull"],bullist:["bullist_desc","InsertUnorderedList"],numlist:["numlist_desc","InsertOrderedList"],outdent:["outdent_desc","Outdent"],indent:["indent_desc","Indent"],cut:["cut_desc","Cut"],copy:["copy_desc","Copy"],paste:["paste_desc","Paste"],undo:["undo_desc","Undo"],redo:["redo_desc","Redo"],link:["link_desc","mceLink"],unlink:["unlink_desc","unlink"],image:["image_desc","mceImage"],cleanup:["cleanup_desc","mceCleanup"],help:["help_desc","mceHelp"],code:["code_desc","mceCodeEditor"],hr:["hr_desc","InsertHorizontalRule"],removeformat:["removeformat_desc","RemoveFormat"],sub:["sub_desc","subscript"],sup:["sup_desc","superscript"],forecolor:["forecolor_desc","ForeColor"],forecolorpicker:["forecolor_desc","mceForeColor"],backcolor:["backcolor_desc","HiliteColor"],backcolorpicker:["backcolor_desc","mceBackColor"],charmap:["charmap_desc","mceCharMap"],visualaid:["visualaid_desc","mceToggleVisualAid"],anchor:["anchor_desc","mceInsertAnchor"],newdocument:["newdocument_desc","mceNewDocument"],blockquote:["blockquote_desc","mceBlockQuote"]},stateControls:["bold","italic","underline","strikethrough","bullist","numlist","justifyleft","justifycenter","justifyright","justifyfull","sub","sup","blockquote"],init:function(k,l){var m=this,n,j,p;m.editor=k;m.url=l;m.onResolveName=new h.util.Dispatcher(this);n=k.settings;k.forcedHighContrastMode=k.settings.detect_highcontrast&&m._isHighContrast();k.settings.skin=k.forcedHighContrastMode?"highcontrast":k.settings.skin;if(!n.theme_advanced_buttons1){n=c({theme_advanced_buttons1:"bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect",theme_advanced_buttons2:"bullist,numlist,|,outdent,indent,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code",theme_advanced_buttons3:"hr,removeformat,visualaid,|,sub,sup,|,charmap"},n)}m.settings=n=c({theme_advanced_path:true,theme_advanced_toolbar_location:"top",theme_advanced_blockformats:"p,address,pre,h1,h2,h3,h4,h5,h6",theme_advanced_toolbar_align:"left",theme_advanced_statusbar_location:"bottom",theme_advanced_fonts:"Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats",theme_advanced_more_colors:1,theme_advanced_row_height:23,theme_advanced_resize_horizontal:1,theme_advanced_resizing_use_cookie:1,theme_advanced_font_sizes:"1,2,3,4,5,6,7",theme_advanced_font_selector:"span",theme_advanced_show_current_color:0,readonly:k.settings.readonly},n);if(!n.font_size_style_values){n.font_size_style_values="8pt,10pt,12pt,14pt,18pt,24pt,36pt"}if(h.is(n.theme_advanced_font_sizes,"string")){n.font_size_style_values=h.explode(n.font_size_style_values);n.font_size_classes=h.explode(n.font_size_classes||"");p={};k.settings.theme_advanced_font_sizes=n.theme_advanced_font_sizes;f(k.getParam("theme_advanced_font_sizes","","hash"),function(r,q){var o;if(q==r&&r>=1&&r<=7){q=r+" ("+m.sizes[r-1]+"pt)";o=n.font_size_classes[r-1];r=n.font_size_style_values[r-1]||(m.sizes[r-1]+"pt")}if(/^\s*\./.test(r)){o=r.replace(/\./g,"")}p[q]=o?{"class":o}:{fontSize:r}});n.theme_advanced_font_sizes=p}if((j=n.theme_advanced_path_location)&&j!="none"){n.theme_advanced_statusbar_location=n.theme_advanced_path_location}if(n.theme_advanced_statusbar_location=="none"){n.theme_advanced_statusbar_location=0}if(k.settings.content_css!==false){k.contentCSS.push(k.baseURI.toAbsolute(l+"/skins/"+k.settings.skin+"/content.css"))}k.onInit.add(function(){if(!k.settings.readonly){k.onNodeChange.add(m._nodeChanged,m);k.onKeyUp.add(m._updateUndoStatus,m);k.onMouseUp.add(m._updateUndoStatus,m);k.dom.bind(k.dom.getRoot(),"dragend",function(){m._updateUndoStatus(k)})}});k.onSetProgressState.add(function(r,o,s){var t,u=r.id,q;if(o){m.progressTimer=setTimeout(function(){t=r.getContainer();t=t.insertBefore(i.create("DIV",{style:"position:relative"}),t.firstChild);q=i.get(r.id+"_tbl");i.add(t,"div",{id:u+"_blocker","class":"mceBlocker",style:{width:q.clientWidth+2,height:q.clientHeight+2}});i.add(t,"div",{id:u+"_progress","class":"mceProgress",style:{left:q.clientWidth/2,top:q.clientHeight/2}})},s||0)}else{i.remove(u+"_blocker");i.remove(u+"_progress");clearTimeout(m.progressTimer)}});i.loadCSS(n.editor_css?k.documentBaseURI.toAbsolute(n.editor_css):l+"/skins/"+k.settings.skin+"/ui.css");if(n.skin_variant){i.loadCSS(l+"/skins/"+k.settings.skin+"/ui_"+n.skin_variant+".css")}},_isHighContrast:function(){var j,k=i.add(i.getRoot(),"div",{style:"background-color: rgb(171,239,86);"});j=(i.getStyle(k,"background-color",true)+"").toLowerCase().replace(/ /g,"");i.remove(k);return j!="rgb(171,239,86)"&&j!="#abef56"},createControl:function(m,j){var k,l;if(l=j.createControl(m)){return l}switch(m){case"styleselect":return this._createStyleSelect();case"formatselect":return this._createBlockFormats();case"fontselect":return this._createFontSelect();case"fontsizeselect":return this._createFontSizeSelect();case"forecolor":return this._createForeColorMenu();case"backcolor":return this._createBackColorMenu()}if((k=this.controls[m])){return j.createButton(m,{title:"advanced."+k[0],cmd:k[1],ui:k[2],value:k[3]})}},execCommand:function(l,k,m){var j=this["_"+l];if(j){j.call(this,k,m);return true}return false},_importClasses:function(l){var j=this.editor,k=j.controlManager.get("styleselect");if(k.getLength()==0){f(j.dom.getClasses(),function(q,m){var p="style_"+m,n;n={inline:"span",attributes:{"class":q["class"]},selector:"*"};j.formatter.register(p,n);k.add(q["class"],p,{style:function(){return b(j,n)}})})}},_createStyleSelect:function(o){var l=this,j=l.editor,k=j.controlManager,m;m=k.createListBox("styleselect",{title:"advanced.style_select",onselect:function(q){var r,n=[],p;f(m.items,function(s){n.push(s.value)});j.focus();j.undoManager.add();r=j.formatter.matchAll(n);h.each(r,function(s){if(!q||s==q){if(s){j.formatter.remove(s)}p=true}});if(!p){j.formatter.apply(q)}j.undoManager.add();j.nodeChanged();return false}});j.onPreInit.add(function(){var p=0,n=j.getParam("style_formats");if(n){f(n,function(q){var r,s=0;f(q,function(){s++});if(s>1){r=q.name=q.name||"style_"+(p++);j.formatter.register(r,q);m.add(q.title,r,{style:function(){return b(j,q)}})}else{m.add(q.title)}})}else{f(j.getParam("theme_advanced_styles","","hash"),function(t,s){var r,q;if(t){r="style_"+(p++);q={inline:"span",classes:t,selector:"*"};j.formatter.register(r,q);m.add(l.editor.translate(s),r,{style:function(){return b(j,q)}})}})}});if(m.getLength()==0){m.onPostRender.add(function(p,q){if(!m.NativeListBox){g.add(q.id+"_text","focus",l._importClasses,l);g.add(q.id+"_text","mousedown",l._importClasses,l);g.add(q.id+"_open","focus",l._importClasses,l);g.add(q.id+"_open","mousedown",l._importClasses,l)}else{g.add(q.id,"focus",l._importClasses,l)}})}return m},_createFontSelect:function(){var l,k=this,j=k.editor;l=j.controlManager.createListBox("fontselect",{title:"advanced.fontdefault",onselect:function(m){var n=l.items[l.selectedIndex];if(!m&&n){j.execCommand("FontName",false,n.value);return}j.execCommand("FontName",false,m);l.select(function(o){return m==o});if(n&&n.value==m){l.select(null)}return false}});if(l){f(j.getParam("theme_advanced_fonts",k.settings.theme_advanced_fonts,"hash"),function(n,m){l.add(j.translate(m),n,{style:n.indexOf("dings")==-1?"font-family:"+n:""})})}return l},_createFontSizeSelect:function(){var m=this,k=m.editor,n,l=0,j=[];n=k.controlManager.createListBox("fontsizeselect",{title:"advanced.font_size",onselect:function(o){var p=n.items[n.selectedIndex];if(!o&&p){p=p.value;if(p["class"]){k.formatter.toggle("fontsize_class",{value:p["class"]});k.undoManager.add();k.nodeChanged()}else{k.execCommand("FontSize",false,p.fontSize)}return}if(o["class"]){k.focus();k.undoManager.add();k.formatter.toggle("fontsize_class",{value:o["class"]});k.undoManager.add();k.nodeChanged()}else{k.execCommand("FontSize",false,o.fontSize)}n.select(function(q){return o==q});if(p&&(p.value.fontSize==o.fontSize||p.value["class"]&&p.value["class"]==o["class"])){n.select(null)}return false}});if(n){f(m.settings.theme_advanced_font_sizes,function(p,o){var q=p.fontSize;if(q>=1&&q<=7){q=m.sizes[parseInt(q)-1]+"pt"}n.add(o,p,{style:"font-size:"+q,"class":"mceFontSize"+(l++)+(" "+(p["class"]||""))})})}return n},_createBlockFormats:function(){var l,j={p:"advanced.paragraph",address:"advanced.address",pre:"advanced.pre",h1:"advanced.h1",h2:"advanced.h2",h3:"advanced.h3",h4:"advanced.h4",h5:"advanced.h5",h6:"advanced.h6",div:"advanced.div",blockquote:"advanced.blockquote",code:"advanced.code",dt:"advanced.dt",dd:"advanced.dd",samp:"advanced.samp"},k=this;l=k.editor.controlManager.createListBox("formatselect",{title:"advanced.block",onselect:function(m){k.editor.execCommand("FormatBlock",false,m);return false}});if(l){f(k.editor.getParam("theme_advanced_blockformats",k.settings.theme_advanced_blockformats,"hash"),function(n,m){l.add(k.editor.translate(m!=n?m:j[n]),n,{"class":"mce_formatPreview mce_"+n,style:function(){return b(k.editor,{block:n})}})})}return l},_createForeColorMenu:function(){var n,k=this,l=k.settings,m={},j;if(l.theme_advanced_more_colors){m.more_colors_func=function(){k._mceColorPicker(0,{color:n.value,func:function(o){n.setColor(o)}})}}if(j=l.theme_advanced_text_colors){m.colors=j}if(l.theme_advanced_default_foreground_color){m.default_color=l.theme_advanced_default_foreground_color}m.title="advanced.forecolor_desc";m.cmd="ForeColor";m.scope=this;n=k.editor.controlManager.createColorSplitButton("forecolor",m);return n},_createBackColorMenu:function(){var n,k=this,l=k.settings,m={},j;if(l.theme_advanced_more_colors){m.more_colors_func=function(){k._mceColorPicker(0,{color:n.value,func:function(o){n.setColor(o)}})}}if(j=l.theme_advanced_background_colors){m.colors=j}if(l.theme_advanced_default_background_color){m.default_color=l.theme_advanced_default_background_color}m.title="advanced.backcolor_desc";m.cmd="HiliteColor";m.scope=this;n=k.editor.controlManager.createColorSplitButton("backcolor",m);return n},renderUI:function(l){var q,m,r,w=this,u=w.editor,x=w.settings,v,k,j;if(u.settings){u.settings.aria_label=x.aria_label+u.getLang("advanced.help_shortcut")}q=k=i.create("span",{role:"application","aria-labelledby":u.id+"_voice",id:u.id+"_parent","class":"mceEditor "+u.settings.skin+"Skin"+(x.skin_variant?" "+u.settings.skin+"Skin"+w._ufirst(x.skin_variant):"")+(u.settings.directionality=="rtl"?" mceRtl":"")});i.add(q,"span",{"class":"mceVoiceLabel",style:"display:none;",id:u.id+"_voice"},x.aria_label);if(!i.boxModel){q=i.add(q,"div",{"class":"mceOldBoxModel"})}q=v=i.add(q,"table",{role:"presentation",id:u.id+"_tbl","class":"mceLayout",cellSpacing:0,cellPadding:0});q=r=i.add(q,"tbody");switch((x.theme_advanced_layout_manager||"").toLowerCase()){case"rowlayout":m=w._rowLayout(x,r,l);break;case"customlayout":m=u.execCallback("theme_advanced_custom_layout",x,r,l,k);break;default:m=w._simpleLayout(x,r,l,k)}q=l.targetNode;j=v.rows;i.addClass(j[0],"mceFirst");i.addClass(j[j.length-1],"mceLast");f(i.select("tr",r),function(o){i.addClass(o.firstChild,"mceFirst");i.addClass(o.childNodes[o.childNodes.length-1],"mceLast")});if(i.get(x.theme_advanced_toolbar_container)){i.get(x.theme_advanced_toolbar_container).appendChild(k)}else{i.insertAfter(k,q)}g.add(u.id+"_path_row","click",function(n){n=n.target;if(n.nodeName=="A"){w._sel(n.className.replace(/^.*mcePath_([0-9]+).*$/,"$1"));return false}});if(!u.getParam("accessibility_focus")){g.add(i.add(k,"a",{href:"#"},"<!-- IE -->"),"focus",function(){tinyMCE.get(u.id).focus()})}if(x.theme_advanced_toolbar_location=="external"){l.deltaHeight=0}w.deltaHeight=l.deltaHeight;l.targetNode=null;u.onKeyDown.add(function(p,n){var s=121,o=122;if(n.altKey){if(n.keyCode===s){if(h.isWebKit){window.focus()}w.toolbarGroup.focus();return g.cancel(n)}else{if(n.keyCode===o){i.get(p.id+"_path_row").focus();return g.cancel(n)}}}});u.addShortcut("alt+0","","mceShortcuts",w);return{iframeContainer:m,editorContainer:u.id+"_parent",sizeContainer:v,deltaHeight:l.deltaHeight}},getInfo:function(){return{longname:"Advanced theme",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",version:h.majorVersion+"."+h.minorVersion}},resizeBy:function(j,k){var l=i.get(this.editor.id+"_ifr");this.resizeTo(l.clientWidth+j,l.clientHeight+k)},resizeTo:function(j,n,l){var k=this.editor,m=this.settings,o=i.get(k.id+"_tbl"),p=i.get(k.id+"_ifr");j=Math.max(m.theme_advanced_resizing_min_width||100,j);n=Math.max(m.theme_advanced_resizing_min_height||100,n);j=Math.min(m.theme_advanced_resizing_max_width||65535,j);n=Math.min(m.theme_advanced_resizing_max_height||65535,n);i.setStyle(o,"height","");i.setStyle(p,"height",n);if(m.theme_advanced_resize_horizontal){i.setStyle(o,"width","");i.setStyle(p,"width",j);if(j<o.clientWidth){j=o.clientWidth;i.setStyle(p,"width",o.clientWidth)}}if(l&&m.theme_advanced_resizing_use_cookie){a.setHash("TinyMCE_"+k.id+"_size",{cw:j,ch:n})}},destroy:function(){var j=this.editor.id;g.clear(j+"_resize");g.clear(j+"_path_row");g.clear(j+"_external_close")},_simpleLayout:function(z,u,l,j){var y=this,v=y.editor,w=z.theme_advanced_toolbar_location,q=z.theme_advanced_statusbar_location,m,k,r,x;if(z.readonly){m=i.add(u,"tr");m=k=i.add(m,"td",{"class":"mceIframeContainer"});return k}if(w=="top"){y._addToolbars(u,l)}if(w=="external"){m=x=i.create("div",{style:"position:relative"});m=i.add(m,"div",{id:v.id+"_external","class":"mceExternalToolbar"});i.add(m,"a",{id:v.id+"_external_close",href:"javascript:;","class":"mceExternalClose"});m=i.add(m,"table",{id:v.id+"_tblext",cellSpacing:0,cellPadding:0});r=i.add(m,"tbody");if(j.firstChild.className=="mceOldBoxModel"){j.firstChild.appendChild(x)}else{j.insertBefore(x,j.firstChild)}y._addToolbars(r,l);v.onMouseUp.add(function(){var o=i.get(v.id+"_external");i.show(o);i.hide(e);var n=g.add(v.id+"_external_close","click",function(){i.hide(v.id+"_external");g.remove(v.id+"_external_close","click",n)});i.show(o);i.setStyle(o,"top",0-i.getRect(v.id+"_tblext").h-1);i.hide(o);i.show(o);o.style.filter="";e=v.id+"_external";o=null})}if(q=="top"){y._addStatusBar(u,l)}if(!z.theme_advanced_toolbar_container){m=i.add(u,"tr");m=k=i.add(m,"td",{"class":"mceIframeContainer"})}if(w=="bottom"){y._addToolbars(u,l)}if(q=="bottom"){y._addStatusBar(u,l)}return k},_rowLayout:function(x,p,l){var w=this,q=w.editor,v,y,j=q.controlManager,m,k,u,r;v=x.theme_advanced_containers_default_class||"";y=x.theme_advanced_containers_default_align||"center";f(d(x.theme_advanced_containers||""),function(s,o){var n=x["theme_advanced_container_"+s]||"";switch(s.toLowerCase()){case"mceeditor":m=i.add(p,"tr");m=k=i.add(m,"td",{"class":"mceIframeContainer"});break;case"mceelementpath":w._addStatusBar(p,l);break;default:r=(x["theme_advanced_container_"+s+"_align"]||y).toLowerCase();r="mce"+w._ufirst(r);m=i.add(i.add(p,"tr"),"td",{"class":"mceToolbar "+(x["theme_advanced_container_"+s+"_class"]||v)+" "+r||y});u=j.createToolbar("toolbar"+o);w._addControls(n,u);i.setHTML(m,u.renderHTML());l.deltaHeight-=x.theme_advanced_row_height}});return k},_addControls:function(k,j){var l=this,m=l.settings,n,o=l.editor.controlManager;if(m.theme_advanced_disable&&!l._disabled){n={};f(d(m.theme_advanced_disable),function(p){n[p]=1});l._disabled=n}else{n=l._disabled}f(d(k),function(q){var p;if(n&&n[q]){return}if(q=="tablecontrols"){f(["table","|","row_props","cell_props","|","row_before","row_after","delete_row","|","col_before","col_after","delete_col","|","split_cells","merge_cells"],function(r){r=l.createControl(r,o);if(r){j.add(r)}});return}p=l.createControl(q,o);if(p){j.add(p)}})},_addToolbars:function(y,k){var B=this,q,p,u=B.editor,C=B.settings,A,j=u.controlManager,w,l,r=[],z,x,m=false;x=j.createToolbarGroup("toolbargroup",{name:u.getLang("advanced.toolbar"),tab_focus_toolbar:u.getParam("theme_advanced_tab_focus_toolbar")});B.toolbarGroup=x;z=C.theme_advanced_toolbar_align.toLowerCase();z="mce"+B._ufirst(z);l=i.add(i.add(y,"tr",{role:"presentation"}),"td",{"class":"mceToolbar "+z,role:"presentation"});for(q=1;(A=C["theme_advanced_buttons"+q]);q++){m=true;p=j.createToolbar("toolbar"+q,{"class":"mceToolbarRow"+q});if(C["theme_advanced_buttons"+q+"_add"]){A+=","+C["theme_advanced_buttons"+q+"_add"]}if(C["theme_advanced_buttons"+q+"_add_before"]){A=C["theme_advanced_buttons"+q+"_add_before"]+","+A}B._addControls(A,p);x.add(p);k.deltaHeight-=C.theme_advanced_row_height}if(!m){k.deltaHeight-=C.theme_advanced_row_height}r.push(x.renderHTML());r.push(i.createHTML("a",{href:"#",accesskey:"z",title:u.getLang("advanced.toolbar_focus"),onfocus:"tinyMCE.getInstanceById('"+u.id+"').focus();"},"<!-- IE -->"));i.setHTML(l,r.join(""))},_addStatusBar:function(p,k){var l,w=this,q=w.editor,x=w.settings,j,u,v,m;l=i.add(p,"tr");l=m=i.add(l,"td",{"class":"mceStatusbar"});l=i.add(l,"div",{id:q.id+"_path_row",role:"group","aria-labelledby":q.id+"_path_voice"});if(x.theme_advanced_path){i.add(l,"span",{id:q.id+"_path_voice"},q.translate("advanced.path"));i.add(l,"span",{},": ")}else{i.add(l,"span",{},"&#160;")}if(x.theme_advanced_resizing){i.add(m,"a",{id:q.id+"_resize",href:"javascript:;",onclick:"return false;","class":"mceResize",tabIndex:"-1"});if(x.theme_advanced_resizing_use_cookie){q.onPostRender.add(function(){var n=a.getHash("TinyMCE_"+q.id+"_size"),r=i.get(q.id+"_tbl");if(!n){return}w.resizeTo(n.cw,n.ch)})}q.onPostRender.add(function(){g.add(q.id+"_resize","click",function(n){n.preventDefault()});g.add(q.id+"_resize","mousedown",function(E){var t,r,s,o,D,A,B,G,n,F,y;function z(H){H.preventDefault();n=B+(H.screenX-D);F=G+(H.screenY-A);w.resizeTo(n,F)}function C(H){g.remove(i.doc,"mousemove",t);g.remove(q.getDoc(),"mousemove",r);g.remove(i.doc,"mouseup",s);g.remove(q.getDoc(),"mouseup",o);n=B+(H.screenX-D);F=G+(H.screenY-A);w.resizeTo(n,F,true)}E.preventDefault();D=E.screenX;A=E.screenY;y=i.get(w.editor.id+"_ifr");B=n=y.clientWidth;G=F=y.clientHeight;t=g.add(i.doc,"mousemove",z);r=g.add(q.getDoc(),"mousemove",z);s=g.add(i.doc,"mouseup",C);o=g.add(q.getDoc(),"mouseup",C)})})}k.deltaHeight-=21;l=p=null},_updateUndoStatus:function(k){var j=k.controlManager,l=k.undoManager;j.setDisabled("undo",!l.hasUndo()&&!l.typing);j.setDisabled("redo",!l.hasRedo())},_nodeChanged:function(o,u,E,r,F){var z=this,D,G=0,y,H,A=z.settings,x,l,w,C,m,k,j;h.each(z.stateControls,function(n){u.setActive(n,o.queryCommandState(z.controls[n][1]))});function q(p){var s,n=F.parents,t=p;if(typeof(p)=="string"){t=function(v){return v.nodeName==p}}for(s=0;s<n.length;s++){if(t(n[s])){return n[s]}}}u.setActive("visualaid",o.hasVisual);z._updateUndoStatus(o);u.setDisabled("outdent",!o.queryCommandState("Outdent"));D=q("A");if(H=u.get("link")){H.setDisabled((!D&&r)||(D&&!D.href));H.setActive(!!D&&(!D.name&&!D.id))}if(H=u.get("unlink")){H.setDisabled(!D&&r);H.setActive(!!D&&!D.name&&!D.id)}if(H=u.get("anchor")){H.setActive(!r&&!!D&&(D.name||(D.id&&!D.href)))}D=q("IMG");if(H=u.get("image")){H.setActive(!r&&!!D&&E.className.indexOf("mceItem")==-1)}if(H=u.get("styleselect")){z._importClasses();k=[];f(H.items,function(n){k.push(n.value)});j=o.formatter.matchAll(k);H.select(j[0]);h.each(j,function(p,n){if(n>0){H.mark(p)}})}if(H=u.get("formatselect")){D=q(o.dom.isBlock);if(D){H.select(D.nodeName.toLowerCase())}}q(function(p){if(p.nodeName==="SPAN"){if(!x&&p.className){x=p.className}}if(o.dom.is(p,A.theme_advanced_font_selector)){if(!l&&p.style.fontSize){l=p.style.fontSize}if(!w&&p.style.fontFamily){w=p.style.fontFamily.replace(/[\"\']+/g,"").replace(/^([^,]+).*/,"$1").toLowerCase()}if(!C&&p.style.color){C=p.style.color}if(!m&&p.style.backgroundColor){m=p.style.backgroundColor}}return false});if(H=u.get("fontselect")){H.select(function(n){return n.replace(/^([^,]+).*/,"$1").toLowerCase()==w})}if(H=u.get("fontsizeselect")){if(A.theme_advanced_runtime_fontsize&&!l&&!x){l=o.dom.getStyle(E,"fontSize",true)}H.select(function(n){if(n.fontSize&&n.fontSize===l){return true}if(n["class"]&&n["class"]===x){return true}})}if(A.theme_advanced_show_current_color){function B(p,n){if(H=u.get(p)){if(!n){n=H.settings.default_color}if(n!==H.value){H.displayColor(n)}}}B("forecolor",C);B("backcolor",m)}if(A.theme_advanced_show_current_color){function B(p,n){if(H=u.get(p)){if(!n){n=H.settings.default_color}if(n!==H.value){H.displayColor(n)}}}B("forecolor",C);B("backcolor",m)}if(A.theme_advanced_path&&A.theme_advanced_statusbar_location){D=i.get(o.id+"_path")||i.add(o.id+"_path_row","span",{id:o.id+"_path"});if(z.statusKeyboardNavigation){z.statusKeyboardNavigation.destroy();z.statusKeyboardNavigation=null}i.setHTML(D,"");q(function(I){var p=I.nodeName.toLowerCase(),s,v,t="";if(I.nodeType!=1||p==="br"||I.getAttribute("data-mce-bogus")||i.hasClass(I,"mceItemHidden")||i.hasClass(I,"mceItemRemoved")){return}if(h.isIE&&I.scopeName!=="HTML"&&I.scopeName){p=I.scopeName+":"+p}p=p.replace(/mce\:/g,"");switch(p){case"b":p="strong";break;case"i":p="em";break;case"img":if(y=i.getAttrib(I,"src")){t+="src: "+y+" "}break;case"a":if(y=i.getAttrib(I,"name")){t+="name: "+y+" ";p+="#"+y}if(y=i.getAttrib(I,"href")){t+="href: "+y+" "}break;case"font":if(y=i.getAttrib(I,"face")){t+="font: "+y+" "}if(y=i.getAttrib(I,"size")){t+="size: "+y+" "}if(y=i.getAttrib(I,"color")){t+="color: "+y+" "}break;case"span":if(y=i.getAttrib(I,"style")){t+="style: "+y+" "}break}if(y=i.getAttrib(I,"id")){t+="id: "+y+" "}if(y=I.className){y=y.replace(/\b\s*(webkit|mce|Apple-)\w+\s*\b/g,"");if(y){t+="class: "+y+" ";if(o.dom.isBlock(I)||p=="img"||p=="span"){p+="."+y}}}p=p.replace(/(html:)/g,"");p={name:p,node:I,title:t};z.onResolveName.dispatch(z,p);t=p.title;p=p.name;v=i.create("a",{href:"javascript:;",role:"button",onmousedown:"return false;",title:t,"class":"mcePath_"+(G++)},p);if(D.hasChildNodes()){D.insertBefore(i.create("span",{"aria-hidden":"true"},"\u00a0\u00bb "),D.firstChild);D.insertBefore(v,D.firstChild)}else{D.appendChild(v)}},o.getBody());if(i.select("a",D).length>0){z.statusKeyboardNavigation=new h.ui.KeyboardNavigation({root:o.id+"_path_row",items:i.select("a",D),excludeFromTabOrder:true,onCancel:function(){o.focus()}},i)}}},_sel:function(j){this.editor.execCommand("mceSelectNodeDepth",false,j)},_mceInsertAnchor:function(l,k){var j=this.editor;j.windowManager.open({url:this.url+"/anchor.htm",width:320+parseInt(j.getLang("advanced.anchor_delta_width",0)),height:90+parseInt(j.getLang("advanced.anchor_delta_height",0)),inline:true},{theme_url:this.url})},_mceCharMap:function(){var j=this.editor;j.windowManager.open({url:this.url+"/charmap.htm",width:550+parseInt(j.getLang("advanced.charmap_delta_width",0)),height:265+parseInt(j.getLang("advanced.charmap_delta_height",0)),inline:true},{theme_url:this.url})},_mceHelp:function(){var j=this.editor;j.windowManager.open({url:this.url+"/about.htm",width:480,height:380,inline:true},{theme_url:this.url})},_mceShortcuts:function(){var j=this.editor;j.windowManager.open({url:this.url+"/shortcuts.htm",width:480,height:380,inline:true},{theme_url:this.url})},_mceColorPicker:function(l,k){var j=this.editor;k=k||{};j.windowManager.open({url:this.url+"/color_picker.htm",width:375+parseInt(j.getLang("advanced.colorpicker_delta_width",0)),height:250+parseInt(j.getLang("advanced.colorpicker_delta_height",0)),close_previous:false,inline:true},{input_color:k.color,func:k.func,theme_url:this.url})},_mceCodeEditor:function(k,l){var j=this.editor;j.windowManager.open({url:this.url+"/source_editor.htm",width:parseInt(j.getParam("theme_advanced_source_editor_width",720)),height:parseInt(j.getParam("theme_advanced_source_editor_height",580)),inline:true,resizable:true,maximizable:true},{theme_url:this.url})},_mceImage:function(k,l){var j=this.editor;if(j.dom.getAttrib(j.selection.getNode(),"class","").indexOf("mceItem")!=-1){return}j.windowManager.open({url:this.url+"/image.htm",width:355+parseInt(j.getLang("advanced.image_delta_width",0)),height:275+parseInt(j.getLang("advanced.image_delta_height",0)),inline:true},{theme_url:this.url})},_mceLink:function(k,l){var j=this.editor;j.windowManager.open({url:this.url+"/link.htm",width:310+parseInt(j.getLang("advanced.link_delta_width",0)),height:200+parseInt(j.getLang("advanced.link_delta_height",0)),inline:true},{theme_url:this.url})},_mceNewDocument:function(){var j=this.editor;j.windowManager.confirm("advanced.newdocument",function(k){if(k){j.execCommand("mceSetContent",false,"")}})},_mceForeColor:function(){var j=this;this._mceColorPicker(0,{color:j.fgColor,func:function(k){j.fgColor=k;j.editor.execCommand("ForeColor",false,k)}})},_mceBackColor:function(){var j=this;this._mceColorPicker(0,{color:j.bgColor,func:function(k){j.bgColor=k;j.editor.execCommand("HiliteColor",false,k)}})},_ufirst:function(j){return j.substring(0,1).toUpperCase()+j.substring(1)}});h.ThemeManager.add("advanced",h.themes.AdvancedTheme)}(tinymce)); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/themes/advanced/editor_template_src.js b/askbot/media/js/tinymce/themes/advanced/editor_template_src.js
new file mode 100644
index 00000000..28ba9828
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/editor_template_src.js
@@ -0,0 +1,1487 @@
+/**
+ * editor_template_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function(tinymce) {
+ var DOM = tinymce.DOM, Event = tinymce.dom.Event, extend = tinymce.extend, each = tinymce.each, Cookie = tinymce.util.Cookie, lastExtID, explode = tinymce.explode;
+
+ // Generates a preview for a format
+ function getPreviewCss(ed, fmt) {
+ var previewElm, dom = ed.dom, previewCss = '', parentFontSize, previewStylesName;
+
+ previewStyles = ed.settings.preview_styles;
+
+ // No preview forced
+ if (previewStyles === false)
+ return '';
+
+ // Default preview
+ if (!previewStyles)
+ previewStyles = 'font-family font-size font-weight text-decoration text-transform color background-color';
+
+ // Removes any variables since these can't be previewed
+ function removeVars(val) {
+ return val.replace(/%(\w+)/g, '');
+ };
+
+ // Create block/inline element to use for preview
+ name = fmt.block || fmt.inline || 'span';
+ previewElm = dom.create(name);
+
+ // Add format styles to preview element
+ each(fmt.styles, function(value, name) {
+ value = removeVars(value);
+
+ if (value)
+ dom.setStyle(previewElm, name, value);
+ });
+
+ // Add attributes to preview element
+ each(fmt.attributes, function(value, name) {
+ value = removeVars(value);
+
+ if (value)
+ dom.setAttrib(previewElm, name, value);
+ });
+
+ // Add classes to preview element
+ each(fmt.classes, function(value) {
+ value = removeVars(value);
+
+ if (!dom.hasClass(previewElm, value))
+ dom.addClass(previewElm, value);
+ });
+
+ // Add the previewElm outside the visual area
+ dom.setStyles(previewElm, {position: 'absolute', left: -0xFFFF});
+ ed.getBody().appendChild(previewElm);
+
+ // Get parent container font size so we can compute px values out of em/% for older IE:s
+ parentFontSize = dom.getStyle(ed.getBody(), 'fontSize', true);
+ parentFontSize = /px$/.test(parentFontSize) ? parseInt(parentFontSize, 10) : 0;
+
+ each(previewStyles.split(' '), function(name) {
+ var value = dom.getStyle(previewElm, name, true);
+
+ // If background is transparent then check if the body has a background color we can use
+ if (name == 'background-color' && /transparent|rgba\s*\([^)]+,\s*0\)/.test(value)) {
+ value = dom.getStyle(ed.getBody(), name, true);
+
+ // Ignore white since it's the default color, not the nicest fix
+ if (dom.toHex(value).toLowerCase() == '#ffffff') {
+ return;
+ }
+ }
+
+ // Old IE won't calculate the font size so we need to do that manually
+ if (name == 'font-size') {
+ if (/em|%$/.test(value)) {
+ if (parentFontSize === 0) {
+ return;
+ }
+
+ // Convert font size from em/% to px
+ value = parseFloat(value, 10) / (/%$/.test(value) ? 100 : 1);
+ value = (value * parentFontSize) + 'px';
+ }
+ }
+
+ previewCss += name + ':' + value + ';';
+ });
+
+ dom.remove(previewElm);
+
+ return previewCss;
+ };
+
+ // Tell it to load theme specific language pack(s)
+ tinymce.ThemeManager.requireLangPack('advanced');
+
+ tinymce.create('tinymce.themes.AdvancedTheme', {
+ sizes : [8, 10, 12, 14, 18, 24, 36],
+
+ // Control name lookup, format: title, command
+ controls : {
+ bold : ['bold_desc', 'Bold'],
+ italic : ['italic_desc', 'Italic'],
+ underline : ['underline_desc', 'Underline'],
+ strikethrough : ['striketrough_desc', 'Strikethrough'],
+ justifyleft : ['justifyleft_desc', 'JustifyLeft'],
+ justifycenter : ['justifycenter_desc', 'JustifyCenter'],
+ justifyright : ['justifyright_desc', 'JustifyRight'],
+ justifyfull : ['justifyfull_desc', 'JustifyFull'],
+ bullist : ['bullist_desc', 'InsertUnorderedList'],
+ numlist : ['numlist_desc', 'InsertOrderedList'],
+ outdent : ['outdent_desc', 'Outdent'],
+ indent : ['indent_desc', 'Indent'],
+ cut : ['cut_desc', 'Cut'],
+ copy : ['copy_desc', 'Copy'],
+ paste : ['paste_desc', 'Paste'],
+ undo : ['undo_desc', 'Undo'],
+ redo : ['redo_desc', 'Redo'],
+ link : ['link_desc', 'mceLink'],
+ unlink : ['unlink_desc', 'unlink'],
+ image : ['image_desc', 'mceImage'],
+ cleanup : ['cleanup_desc', 'mceCleanup'],
+ help : ['help_desc', 'mceHelp'],
+ code : ['code_desc', 'mceCodeEditor'],
+ hr : ['hr_desc', 'InsertHorizontalRule'],
+ removeformat : ['removeformat_desc', 'RemoveFormat'],
+ sub : ['sub_desc', 'subscript'],
+ sup : ['sup_desc', 'superscript'],
+ forecolor : ['forecolor_desc', 'ForeColor'],
+ forecolorpicker : ['forecolor_desc', 'mceForeColor'],
+ backcolor : ['backcolor_desc', 'HiliteColor'],
+ backcolorpicker : ['backcolor_desc', 'mceBackColor'],
+ charmap : ['charmap_desc', 'mceCharMap'],
+ visualaid : ['visualaid_desc', 'mceToggleVisualAid'],
+ anchor : ['anchor_desc', 'mceInsertAnchor'],
+ newdocument : ['newdocument_desc', 'mceNewDocument'],
+ blockquote : ['blockquote_desc', 'mceBlockQuote']
+ },
+
+ stateControls : ['bold', 'italic', 'underline', 'strikethrough', 'bullist', 'numlist', 'justifyleft', 'justifycenter', 'justifyright', 'justifyfull', 'sub', 'sup', 'blockquote'],
+
+ init : function(ed, url) {
+ var t = this, s, v, o;
+
+ t.editor = ed;
+ t.url = url;
+ t.onResolveName = new tinymce.util.Dispatcher(this);
+ s = ed.settings;
+
+ ed.forcedHighContrastMode = ed.settings.detect_highcontrast && t._isHighContrast();
+ ed.settings.skin = ed.forcedHighContrastMode ? 'highcontrast' : ed.settings.skin;
+
+ // Setup default buttons
+ if (!s.theme_advanced_buttons1) {
+ s = extend({
+ theme_advanced_buttons1 : "bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect",
+ theme_advanced_buttons2 : "bullist,numlist,|,outdent,indent,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code",
+ theme_advanced_buttons3 : "hr,removeformat,visualaid,|,sub,sup,|,charmap"
+ }, s);
+ }
+
+ // Default settings
+ t.settings = s = extend({
+ theme_advanced_path : true,
+ theme_advanced_toolbar_location : 'top',
+ theme_advanced_blockformats : "p,address,pre,h1,h2,h3,h4,h5,h6",
+ theme_advanced_toolbar_align : "left",
+ theme_advanced_statusbar_location : "bottom",
+ theme_advanced_fonts : "Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats",
+ theme_advanced_more_colors : 1,
+ theme_advanced_row_height : 23,
+ theme_advanced_resize_horizontal : 1,
+ theme_advanced_resizing_use_cookie : 1,
+ theme_advanced_font_sizes : "1,2,3,4,5,6,7",
+ theme_advanced_font_selector : "span",
+ theme_advanced_show_current_color: 0,
+ readonly : ed.settings.readonly
+ }, s);
+
+ // Setup default font_size_style_values
+ if (!s.font_size_style_values)
+ s.font_size_style_values = "8pt,10pt,12pt,14pt,18pt,24pt,36pt";
+
+ if (tinymce.is(s.theme_advanced_font_sizes, 'string')) {
+ s.font_size_style_values = tinymce.explode(s.font_size_style_values);
+ s.font_size_classes = tinymce.explode(s.font_size_classes || '');
+
+ // Parse string value
+ o = {};
+ ed.settings.theme_advanced_font_sizes = s.theme_advanced_font_sizes;
+ each(ed.getParam('theme_advanced_font_sizes', '', 'hash'), function(v, k) {
+ var cl;
+
+ if (k == v && v >= 1 && v <= 7) {
+ k = v + ' (' + t.sizes[v - 1] + 'pt)';
+ cl = s.font_size_classes[v - 1];
+ v = s.font_size_style_values[v - 1] || (t.sizes[v - 1] + 'pt');
+ }
+
+ if (/^\s*\./.test(v))
+ cl = v.replace(/\./g, '');
+
+ o[k] = cl ? {'class' : cl} : {fontSize : v};
+ });
+
+ s.theme_advanced_font_sizes = o;
+ }
+
+ if ((v = s.theme_advanced_path_location) && v != 'none')
+ s.theme_advanced_statusbar_location = s.theme_advanced_path_location;
+
+ if (s.theme_advanced_statusbar_location == 'none')
+ s.theme_advanced_statusbar_location = 0;
+
+ if (ed.settings.content_css !== false)
+ ed.contentCSS.push(ed.baseURI.toAbsolute(url + "/skins/" + ed.settings.skin + "/content.css"));
+
+ // Init editor
+ ed.onInit.add(function() {
+ if (!ed.settings.readonly) {
+ ed.onNodeChange.add(t._nodeChanged, t);
+ ed.onKeyUp.add(t._updateUndoStatus, t);
+ ed.onMouseUp.add(t._updateUndoStatus, t);
+ ed.dom.bind(ed.dom.getRoot(), 'dragend', function() {
+ t._updateUndoStatus(ed);
+ });
+ }
+ });
+
+ ed.onSetProgressState.add(function(ed, b, ti) {
+ var co, id = ed.id, tb;
+
+ if (b) {
+ t.progressTimer = setTimeout(function() {
+ co = ed.getContainer();
+ co = co.insertBefore(DOM.create('DIV', {style : 'position:relative'}), co.firstChild);
+ tb = DOM.get(ed.id + '_tbl');
+
+ DOM.add(co, 'div', {id : id + '_blocker', 'class' : 'mceBlocker', style : {width : tb.clientWidth + 2, height : tb.clientHeight + 2}});
+ DOM.add(co, 'div', {id : id + '_progress', 'class' : 'mceProgress', style : {left : tb.clientWidth / 2, top : tb.clientHeight / 2}});
+ }, ti || 0);
+ } else {
+ DOM.remove(id + '_blocker');
+ DOM.remove(id + '_progress');
+ clearTimeout(t.progressTimer);
+ }
+ });
+
+ DOM.loadCSS(s.editor_css ? ed.documentBaseURI.toAbsolute(s.editor_css) : url + "/skins/" + ed.settings.skin + "/ui.css");
+
+ if (s.skin_variant)
+ DOM.loadCSS(url + "/skins/" + ed.settings.skin + "/ui_" + s.skin_variant + ".css");
+ },
+
+ _isHighContrast : function() {
+ var actualColor, div = DOM.add(DOM.getRoot(), 'div', {'style': 'background-color: rgb(171,239,86);'});
+
+ actualColor = (DOM.getStyle(div, 'background-color', true) + '').toLowerCase().replace(/ /g, '');
+ DOM.remove(div);
+
+ return actualColor != 'rgb(171,239,86)' && actualColor != '#abef56';
+ },
+
+ createControl : function(n, cf) {
+ var cd, c;
+
+ if (c = cf.createControl(n))
+ return c;
+
+ switch (n) {
+ case "styleselect":
+ return this._createStyleSelect();
+
+ case "formatselect":
+ return this._createBlockFormats();
+
+ case "fontselect":
+ return this._createFontSelect();
+
+ case "fontsizeselect":
+ return this._createFontSizeSelect();
+
+ case "forecolor":
+ return this._createForeColorMenu();
+
+ case "backcolor":
+ return this._createBackColorMenu();
+ }
+
+ if ((cd = this.controls[n]))
+ return cf.createButton(n, {title : "advanced." + cd[0], cmd : cd[1], ui : cd[2], value : cd[3]});
+ },
+
+ execCommand : function(cmd, ui, val) {
+ var f = this['_' + cmd];
+
+ if (f) {
+ f.call(this, ui, val);
+ return true;
+ }
+
+ return false;
+ },
+
+ _importClasses : function(e) {
+ var ed = this.editor, ctrl = ed.controlManager.get('styleselect');
+
+ if (ctrl.getLength() == 0) {
+ each(ed.dom.getClasses(), function(o, idx) {
+ var name = 'style_' + idx, fmt;
+
+ fmt = {
+ inline : 'span',
+ attributes : {'class' : o['class']},
+ selector : '*'
+ };
+
+ ed.formatter.register(name, fmt);
+
+ ctrl.add(o['class'], name, {
+ style: function() {
+ return getPreviewCss(ed, fmt);
+ }
+ });
+ });
+ }
+ },
+
+ _createStyleSelect : function(n) {
+ var t = this, ed = t.editor, ctrlMan = ed.controlManager, ctrl;
+
+ // Setup style select box
+ ctrl = ctrlMan.createListBox('styleselect', {
+ title : 'advanced.style_select',
+ onselect : function(name) {
+ var matches, formatNames = [], removedFormat;
+
+ each(ctrl.items, function(item) {
+ formatNames.push(item.value);
+ });
+
+ ed.focus();
+ ed.undoManager.add();
+
+ // Toggle off the current format(s)
+ matches = ed.formatter.matchAll(formatNames);
+ tinymce.each(matches, function(match) {
+ if (!name || match == name) {
+ if (match)
+ ed.formatter.remove(match);
+
+ removedFormat = true;
+ }
+ });
+
+ if (!removedFormat)
+ ed.formatter.apply(name);
+
+ ed.undoManager.add();
+ ed.nodeChanged();
+
+ return false; // No auto select
+ }
+ });
+
+ // Handle specified format
+ ed.onPreInit.add(function() {
+ var counter = 0, formats = ed.getParam('style_formats');
+
+ if (formats) {
+ each(formats, function(fmt) {
+ var name, keys = 0;
+
+ each(fmt, function() {keys++;});
+
+ if (keys > 1) {
+ name = fmt.name = fmt.name || 'style_' + (counter++);
+ ed.formatter.register(name, fmt);
+ ctrl.add(fmt.title, name, {
+ style: function() {
+ return getPreviewCss(ed, fmt);
+ }
+ });
+ } else
+ ctrl.add(fmt.title);
+ });
+ } else {
+ each(ed.getParam('theme_advanced_styles', '', 'hash'), function(val, key) {
+ var name, fmt;
+
+ if (val) {
+ name = 'style_' + (counter++);
+ fmt = {
+ inline : 'span',
+ classes : val,
+ selector : '*'
+ };
+
+ ed.formatter.register(name, fmt);
+ ctrl.add(t.editor.translate(key), name, {
+ style: function() {
+ return getPreviewCss(ed, fmt);
+ }
+ });
+ }
+ });
+ }
+ });
+
+ // Auto import classes if the ctrl box is empty
+ if (ctrl.getLength() == 0) {
+ ctrl.onPostRender.add(function(ed, n) {
+ if (!ctrl.NativeListBox) {
+ Event.add(n.id + '_text', 'focus', t._importClasses, t);
+ Event.add(n.id + '_text', 'mousedown', t._importClasses, t);
+ Event.add(n.id + '_open', 'focus', t._importClasses, t);
+ Event.add(n.id + '_open', 'mousedown', t._importClasses, t);
+ } else
+ Event.add(n.id, 'focus', t._importClasses, t);
+ });
+ }
+
+ return ctrl;
+ },
+
+ _createFontSelect : function() {
+ var c, t = this, ed = t.editor;
+
+ c = ed.controlManager.createListBox('fontselect', {
+ title : 'advanced.fontdefault',
+ onselect : function(v) {
+ var cur = c.items[c.selectedIndex];
+
+ if (!v && cur) {
+ ed.execCommand('FontName', false, cur.value);
+ return;
+ }
+
+ ed.execCommand('FontName', false, v);
+
+ // Fake selection, execCommand will fire a nodeChange and update the selection
+ c.select(function(sv) {
+ return v == sv;
+ });
+
+ if (cur && cur.value == v) {
+ c.select(null);
+ }
+
+ return false; // No auto select
+ }
+ });
+
+ if (c) {
+ each(ed.getParam('theme_advanced_fonts', t.settings.theme_advanced_fonts, 'hash'), function(v, k) {
+ c.add(ed.translate(k), v, {style : v.indexOf('dings') == -1 ? 'font-family:' + v : ''});
+ });
+ }
+
+ return c;
+ },
+
+ _createFontSizeSelect : function() {
+ var t = this, ed = t.editor, c, i = 0, cl = [];
+
+ c = ed.controlManager.createListBox('fontsizeselect', {title : 'advanced.font_size', onselect : function(v) {
+ var cur = c.items[c.selectedIndex];
+
+ if (!v && cur) {
+ cur = cur.value;
+
+ if (cur['class']) {
+ ed.formatter.toggle('fontsize_class', {value : cur['class']});
+ ed.undoManager.add();
+ ed.nodeChanged();
+ } else {
+ ed.execCommand('FontSize', false, cur.fontSize);
+ }
+
+ return;
+ }
+
+ if (v['class']) {
+ ed.focus();
+ ed.undoManager.add();
+ ed.formatter.toggle('fontsize_class', {value : v['class']});
+ ed.undoManager.add();
+ ed.nodeChanged();
+ } else
+ ed.execCommand('FontSize', false, v.fontSize);
+
+ // Fake selection, execCommand will fire a nodeChange and update the selection
+ c.select(function(sv) {
+ return v == sv;
+ });
+
+ if (cur && (cur.value.fontSize == v.fontSize || cur.value['class'] && cur.value['class'] == v['class'])) {
+ c.select(null);
+ }
+
+ return false; // No auto select
+ }});
+
+ if (c) {
+ each(t.settings.theme_advanced_font_sizes, function(v, k) {
+ var fz = v.fontSize;
+
+ if (fz >= 1 && fz <= 7)
+ fz = t.sizes[parseInt(fz) - 1] + 'pt';
+
+ c.add(k, v, {'style' : 'font-size:' + fz, 'class' : 'mceFontSize' + (i++) + (' ' + (v['class'] || ''))});
+ });
+ }
+
+ return c;
+ },
+
+ _createBlockFormats : function() {
+ var c, fmts = {
+ p : 'advanced.paragraph',
+ address : 'advanced.address',
+ pre : 'advanced.pre',
+ h1 : 'advanced.h1',
+ h2 : 'advanced.h2',
+ h3 : 'advanced.h3',
+ h4 : 'advanced.h4',
+ h5 : 'advanced.h5',
+ h6 : 'advanced.h6',
+ div : 'advanced.div',
+ blockquote : 'advanced.blockquote',
+ code : 'advanced.code',
+ dt : 'advanced.dt',
+ dd : 'advanced.dd',
+ samp : 'advanced.samp'
+ }, t = this;
+
+ c = t.editor.controlManager.createListBox('formatselect', {title : 'advanced.block', onselect : function(v) {
+ t.editor.execCommand('FormatBlock', false, v);
+ return false;
+ }});
+
+ if (c) {
+ each(t.editor.getParam('theme_advanced_blockformats', t.settings.theme_advanced_blockformats, 'hash'), function(v, k) {
+ c.add(t.editor.translate(k != v ? k : fmts[v]), v, {'class' : 'mce_formatPreview mce_' + v, style: function() {
+ return getPreviewCss(t.editor, {block: v});
+ }});
+ });
+ }
+
+ return c;
+ },
+
+ _createForeColorMenu : function() {
+ var c, t = this, s = t.settings, o = {}, v;
+
+ if (s.theme_advanced_more_colors) {
+ o.more_colors_func = function() {
+ t._mceColorPicker(0, {
+ color : c.value,
+ func : function(co) {
+ c.setColor(co);
+ }
+ });
+ };
+ }
+
+ if (v = s.theme_advanced_text_colors)
+ o.colors = v;
+
+ if (s.theme_advanced_default_foreground_color)
+ o.default_color = s.theme_advanced_default_foreground_color;
+
+ o.title = 'advanced.forecolor_desc';
+ o.cmd = 'ForeColor';
+ o.scope = this;
+
+ c = t.editor.controlManager.createColorSplitButton('forecolor', o);
+
+ return c;
+ },
+
+ _createBackColorMenu : function() {
+ var c, t = this, s = t.settings, o = {}, v;
+
+ if (s.theme_advanced_more_colors) {
+ o.more_colors_func = function() {
+ t._mceColorPicker(0, {
+ color : c.value,
+ func : function(co) {
+ c.setColor(co);
+ }
+ });
+ };
+ }
+
+ if (v = s.theme_advanced_background_colors)
+ o.colors = v;
+
+ if (s.theme_advanced_default_background_color)
+ o.default_color = s.theme_advanced_default_background_color;
+
+ o.title = 'advanced.backcolor_desc';
+ o.cmd = 'HiliteColor';
+ o.scope = this;
+
+ c = t.editor.controlManager.createColorSplitButton('backcolor', o);
+
+ return c;
+ },
+
+ renderUI : function(o) {
+ var n, ic, tb, t = this, ed = t.editor, s = t.settings, sc, p, nl;
+
+ if (ed.settings) {
+ ed.settings.aria_label = s.aria_label + ed.getLang('advanced.help_shortcut');
+ }
+
+ // TODO: ACC Should have an aria-describedby attribute which is user-configurable to describe what this field is actually for.
+ // Maybe actually inherit it from the original textara?
+ n = p = DOM.create('span', {role : 'application', 'aria-labelledby' : ed.id + '_voice', id : ed.id + '_parent', 'class' : 'mceEditor ' + ed.settings.skin + 'Skin' + (s.skin_variant ? ' ' + ed.settings.skin + 'Skin' + t._ufirst(s.skin_variant) : '') + (ed.settings.directionality == "rtl" ? ' mceRtl' : '')});
+ DOM.add(n, 'span', {'class': 'mceVoiceLabel', 'style': 'display:none;', id: ed.id + '_voice'}, s.aria_label);
+
+ if (!DOM.boxModel)
+ n = DOM.add(n, 'div', {'class' : 'mceOldBoxModel'});
+
+ n = sc = DOM.add(n, 'table', {role : "presentation", id : ed.id + '_tbl', 'class' : 'mceLayout', cellSpacing : 0, cellPadding : 0});
+ n = tb = DOM.add(n, 'tbody');
+
+ switch ((s.theme_advanced_layout_manager || '').toLowerCase()) {
+ case "rowlayout":
+ ic = t._rowLayout(s, tb, o);
+ break;
+
+ case "customlayout":
+ ic = ed.execCallback("theme_advanced_custom_layout", s, tb, o, p);
+ break;
+
+ default:
+ ic = t._simpleLayout(s, tb, o, p);
+ }
+
+ n = o.targetNode;
+
+ // Add classes to first and last TRs
+ nl = sc.rows;
+ DOM.addClass(nl[0], 'mceFirst');
+ DOM.addClass(nl[nl.length - 1], 'mceLast');
+
+ // Add classes to first and last TDs
+ each(DOM.select('tr', tb), function(n) {
+ DOM.addClass(n.firstChild, 'mceFirst');
+ DOM.addClass(n.childNodes[n.childNodes.length - 1], 'mceLast');
+ });
+
+ if (DOM.get(s.theme_advanced_toolbar_container))
+ DOM.get(s.theme_advanced_toolbar_container).appendChild(p);
+ else
+ DOM.insertAfter(p, n);
+
+ Event.add(ed.id + '_path_row', 'click', function(e) {
+ e = e.target;
+
+ if (e.nodeName == 'A') {
+ t._sel(e.className.replace(/^.*mcePath_([0-9]+).*$/, '$1'));
+ return false;
+ }
+ });
+/*
+ if (DOM.get(ed.id + '_path_row')) {
+ Event.add(ed.id + '_tbl', 'mouseover', function(e) {
+ var re;
+
+ e = e.target;
+
+ if (e.nodeName == 'SPAN' && DOM.hasClass(e.parentNode, 'mceButton')) {
+ re = DOM.get(ed.id + '_path_row');
+ t.lastPath = re.innerHTML;
+ DOM.setHTML(re, e.parentNode.title);
+ }
+ });
+
+ Event.add(ed.id + '_tbl', 'mouseout', function(e) {
+ if (t.lastPath) {
+ DOM.setHTML(ed.id + '_path_row', t.lastPath);
+ t.lastPath = 0;
+ }
+ });
+ }
+*/
+
+ if (!ed.getParam('accessibility_focus'))
+ Event.add(DOM.add(p, 'a', {href : '#'}, '<!-- IE -->'), 'focus', function() {tinyMCE.get(ed.id).focus();});
+
+ if (s.theme_advanced_toolbar_location == 'external')
+ o.deltaHeight = 0;
+
+ t.deltaHeight = o.deltaHeight;
+ o.targetNode = null;
+
+ ed.onKeyDown.add(function(ed, evt) {
+ var DOM_VK_F10 = 121, DOM_VK_F11 = 122;
+
+ if (evt.altKey) {
+ if (evt.keyCode === DOM_VK_F10) {
+ // Make sure focus is given to toolbar in Safari.
+ // We can't do this in IE as it prevents giving focus to toolbar when editor is in a frame
+ if (tinymce.isWebKit) {
+ window.focus();
+ }
+ t.toolbarGroup.focus();
+ return Event.cancel(evt);
+ } else if (evt.keyCode === DOM_VK_F11) {
+ DOM.get(ed.id + '_path_row').focus();
+ return Event.cancel(evt);
+ }
+ }
+ });
+
+ // alt+0 is the UK recommended shortcut for accessing the list of access controls.
+ ed.addShortcut('alt+0', '', 'mceShortcuts', t);
+
+ return {
+ iframeContainer : ic,
+ editorContainer : ed.id + '_parent',
+ sizeContainer : sc,
+ deltaHeight : o.deltaHeight
+ };
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Advanced theme',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ }
+ },
+
+ resizeBy : function(dw, dh) {
+ var e = DOM.get(this.editor.id + '_ifr');
+
+ this.resizeTo(e.clientWidth + dw, e.clientHeight + dh);
+ },
+
+ resizeTo : function(w, h, store) {
+ var ed = this.editor, s = this.settings, e = DOM.get(ed.id + '_tbl'), ifr = DOM.get(ed.id + '_ifr');
+
+ // Boundery fix box
+ w = Math.max(s.theme_advanced_resizing_min_width || 100, w);
+ h = Math.max(s.theme_advanced_resizing_min_height || 100, h);
+ w = Math.min(s.theme_advanced_resizing_max_width || 0xFFFF, w);
+ h = Math.min(s.theme_advanced_resizing_max_height || 0xFFFF, h);
+
+ // Resize iframe and container
+ DOM.setStyle(e, 'height', '');
+ DOM.setStyle(ifr, 'height', h);
+
+ if (s.theme_advanced_resize_horizontal) {
+ DOM.setStyle(e, 'width', '');
+ DOM.setStyle(ifr, 'width', w);
+
+ // Make sure that the size is never smaller than the over all ui
+ if (w < e.clientWidth) {
+ w = e.clientWidth;
+ DOM.setStyle(ifr, 'width', e.clientWidth);
+ }
+ }
+
+ // Store away the size
+ if (store && s.theme_advanced_resizing_use_cookie) {
+ Cookie.setHash("TinyMCE_" + ed.id + "_size", {
+ cw : w,
+ ch : h
+ });
+ }
+ },
+
+ destroy : function() {
+ var id = this.editor.id;
+
+ Event.clear(id + '_resize');
+ Event.clear(id + '_path_row');
+ Event.clear(id + '_external_close');
+ },
+
+ // Internal functions
+
+ _simpleLayout : function(s, tb, o, p) {
+ var t = this, ed = t.editor, lo = s.theme_advanced_toolbar_location, sl = s.theme_advanced_statusbar_location, n, ic, etb, c;
+
+ if (s.readonly) {
+ n = DOM.add(tb, 'tr');
+ n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'});
+ return ic;
+ }
+
+ // Create toolbar container at top
+ if (lo == 'top')
+ t._addToolbars(tb, o);
+
+ // Create external toolbar
+ if (lo == 'external') {
+ n = c = DOM.create('div', {style : 'position:relative'});
+ n = DOM.add(n, 'div', {id : ed.id + '_external', 'class' : 'mceExternalToolbar'});
+ DOM.add(n, 'a', {id : ed.id + '_external_close', href : 'javascript:;', 'class' : 'mceExternalClose'});
+ n = DOM.add(n, 'table', {id : ed.id + '_tblext', cellSpacing : 0, cellPadding : 0});
+ etb = DOM.add(n, 'tbody');
+
+ if (p.firstChild.className == 'mceOldBoxModel')
+ p.firstChild.appendChild(c);
+ else
+ p.insertBefore(c, p.firstChild);
+
+ t._addToolbars(etb, o);
+
+ ed.onMouseUp.add(function() {
+ var e = DOM.get(ed.id + '_external');
+ DOM.show(e);
+
+ DOM.hide(lastExtID);
+
+ var f = Event.add(ed.id + '_external_close', 'click', function() {
+ DOM.hide(ed.id + '_external');
+ Event.remove(ed.id + '_external_close', 'click', f);
+ });
+
+ DOM.show(e);
+ DOM.setStyle(e, 'top', 0 - DOM.getRect(ed.id + '_tblext').h - 1);
+
+ // Fixes IE rendering bug
+ DOM.hide(e);
+ DOM.show(e);
+ e.style.filter = '';
+
+ lastExtID = ed.id + '_external';
+
+ e = null;
+ });
+ }
+
+ if (sl == 'top')
+ t._addStatusBar(tb, o);
+
+ // Create iframe container
+ if (!s.theme_advanced_toolbar_container) {
+ n = DOM.add(tb, 'tr');
+ n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'});
+ }
+
+ // Create toolbar container at bottom
+ if (lo == 'bottom')
+ t._addToolbars(tb, o);
+
+ if (sl == 'bottom')
+ t._addStatusBar(tb, o);
+
+ return ic;
+ },
+
+ _rowLayout : function(s, tb, o) {
+ var t = this, ed = t.editor, dc, da, cf = ed.controlManager, n, ic, to, a;
+
+ dc = s.theme_advanced_containers_default_class || '';
+ da = s.theme_advanced_containers_default_align || 'center';
+
+ each(explode(s.theme_advanced_containers || ''), function(c, i) {
+ var v = s['theme_advanced_container_' + c] || '';
+
+ switch (c.toLowerCase()) {
+ case 'mceeditor':
+ n = DOM.add(tb, 'tr');
+ n = ic = DOM.add(n, 'td', {'class' : 'mceIframeContainer'});
+ break;
+
+ case 'mceelementpath':
+ t._addStatusBar(tb, o);
+ break;
+
+ default:
+ a = (s['theme_advanced_container_' + c + '_align'] || da).toLowerCase();
+ a = 'mce' + t._ufirst(a);
+
+ n = DOM.add(DOM.add(tb, 'tr'), 'td', {
+ 'class' : 'mceToolbar ' + (s['theme_advanced_container_' + c + '_class'] || dc) + ' ' + a || da
+ });
+
+ to = cf.createToolbar("toolbar" + i);
+ t._addControls(v, to);
+ DOM.setHTML(n, to.renderHTML());
+ o.deltaHeight -= s.theme_advanced_row_height;
+ }
+ });
+
+ return ic;
+ },
+
+ _addControls : function(v, tb) {
+ var t = this, s = t.settings, di, cf = t.editor.controlManager;
+
+ if (s.theme_advanced_disable && !t._disabled) {
+ di = {};
+
+ each(explode(s.theme_advanced_disable), function(v) {
+ di[v] = 1;
+ });
+
+ t._disabled = di;
+ } else
+ di = t._disabled;
+
+ each(explode(v), function(n) {
+ var c;
+
+ if (di && di[n])
+ return;
+
+ // Compatiblity with 2.x
+ if (n == 'tablecontrols') {
+ each(["table","|","row_props","cell_props","|","row_before","row_after","delete_row","|","col_before","col_after","delete_col","|","split_cells","merge_cells"], function(n) {
+ n = t.createControl(n, cf);
+
+ if (n)
+ tb.add(n);
+ });
+
+ return;
+ }
+
+ c = t.createControl(n, cf);
+
+ if (c)
+ tb.add(c);
+ });
+ },
+
+ _addToolbars : function(c, o) {
+ var t = this, i, tb, ed = t.editor, s = t.settings, v, cf = ed.controlManager, di, n, h = [], a, toolbarGroup, toolbarsExist = false;
+
+ toolbarGroup = cf.createToolbarGroup('toolbargroup', {
+ 'name': ed.getLang('advanced.toolbar'),
+ 'tab_focus_toolbar':ed.getParam('theme_advanced_tab_focus_toolbar')
+ });
+
+ t.toolbarGroup = toolbarGroup;
+
+ a = s.theme_advanced_toolbar_align.toLowerCase();
+ a = 'mce' + t._ufirst(a);
+
+ n = DOM.add(DOM.add(c, 'tr', {role: 'presentation'}), 'td', {'class' : 'mceToolbar ' + a, "role":"presentation"});
+
+ // Create toolbar and add the controls
+ for (i=1; (v = s['theme_advanced_buttons' + i]); i++) {
+ toolbarsExist = true;
+ tb = cf.createToolbar("toolbar" + i, {'class' : 'mceToolbarRow' + i});
+
+ if (s['theme_advanced_buttons' + i + '_add'])
+ v += ',' + s['theme_advanced_buttons' + i + '_add'];
+
+ if (s['theme_advanced_buttons' + i + '_add_before'])
+ v = s['theme_advanced_buttons' + i + '_add_before'] + ',' + v;
+
+ t._addControls(v, tb);
+ toolbarGroup.add(tb);
+
+ o.deltaHeight -= s.theme_advanced_row_height;
+ }
+ // Handle case when there are no toolbar buttons and ensure editor height is adjusted accordingly
+ if (!toolbarsExist)
+ o.deltaHeight -= s.theme_advanced_row_height;
+ h.push(toolbarGroup.renderHTML());
+ h.push(DOM.createHTML('a', {href : '#', accesskey : 'z', title : ed.getLang("advanced.toolbar_focus"), onfocus : 'tinyMCE.getInstanceById(\'' + ed.id + '\').focus();'}, '<!-- IE -->'));
+ DOM.setHTML(n, h.join(''));
+ },
+
+ _addStatusBar : function(tb, o) {
+ var n, t = this, ed = t.editor, s = t.settings, r, mf, me, td;
+
+ n = DOM.add(tb, 'tr');
+ n = td = DOM.add(n, 'td', {'class' : 'mceStatusbar'});
+ n = DOM.add(n, 'div', {id : ed.id + '_path_row', 'role': 'group', 'aria-labelledby': ed.id + '_path_voice'});
+ if (s.theme_advanced_path) {
+ DOM.add(n, 'span', {id: ed.id + '_path_voice'}, ed.translate('advanced.path'));
+ DOM.add(n, 'span', {}, ': ');
+ } else {
+ DOM.add(n, 'span', {}, '&#160;');
+ }
+
+
+ if (s.theme_advanced_resizing) {
+ DOM.add(td, 'a', {id : ed.id + '_resize', href : 'javascript:;', onclick : "return false;", 'class' : 'mceResize', tabIndex:"-1"});
+
+ if (s.theme_advanced_resizing_use_cookie) {
+ ed.onPostRender.add(function() {
+ var o = Cookie.getHash("TinyMCE_" + ed.id + "_size"), c = DOM.get(ed.id + '_tbl');
+
+ if (!o)
+ return;
+
+ t.resizeTo(o.cw, o.ch);
+ });
+ }
+
+ ed.onPostRender.add(function() {
+ Event.add(ed.id + '_resize', 'click', function(e) {
+ e.preventDefault();
+ });
+
+ Event.add(ed.id + '_resize', 'mousedown', function(e) {
+ var mouseMoveHandler1, mouseMoveHandler2,
+ mouseUpHandler1, mouseUpHandler2,
+ startX, startY, startWidth, startHeight, width, height, ifrElm;
+
+ function resizeOnMove(e) {
+ e.preventDefault();
+
+ width = startWidth + (e.screenX - startX);
+ height = startHeight + (e.screenY - startY);
+
+ t.resizeTo(width, height);
+ };
+
+ function endResize(e) {
+ // Stop listening
+ Event.remove(DOM.doc, 'mousemove', mouseMoveHandler1);
+ Event.remove(ed.getDoc(), 'mousemove', mouseMoveHandler2);
+ Event.remove(DOM.doc, 'mouseup', mouseUpHandler1);
+ Event.remove(ed.getDoc(), 'mouseup', mouseUpHandler2);
+
+ width = startWidth + (e.screenX - startX);
+ height = startHeight + (e.screenY - startY);
+ t.resizeTo(width, height, true);
+ };
+
+ e.preventDefault();
+
+ // Get the current rect size
+ startX = e.screenX;
+ startY = e.screenY;
+ ifrElm = DOM.get(t.editor.id + '_ifr');
+ startWidth = width = ifrElm.clientWidth;
+ startHeight = height = ifrElm.clientHeight;
+
+ // Register envent handlers
+ mouseMoveHandler1 = Event.add(DOM.doc, 'mousemove', resizeOnMove);
+ mouseMoveHandler2 = Event.add(ed.getDoc(), 'mousemove', resizeOnMove);
+ mouseUpHandler1 = Event.add(DOM.doc, 'mouseup', endResize);
+ mouseUpHandler2 = Event.add(ed.getDoc(), 'mouseup', endResize);
+ });
+ });
+ }
+
+ o.deltaHeight -= 21;
+ n = tb = null;
+ },
+
+ _updateUndoStatus : function(ed) {
+ var cm = ed.controlManager, um = ed.undoManager;
+
+ cm.setDisabled('undo', !um.hasUndo() && !um.typing);
+ cm.setDisabled('redo', !um.hasRedo());
+ },
+
+ _nodeChanged : function(ed, cm, n, co, ob) {
+ var t = this, p, de = 0, v, c, s = t.settings, cl, fz, fn, fc, bc, formatNames, matches;
+
+ tinymce.each(t.stateControls, function(c) {
+ cm.setActive(c, ed.queryCommandState(t.controls[c][1]));
+ });
+
+ function getParent(name) {
+ var i, parents = ob.parents, func = name;
+
+ if (typeof(name) == 'string') {
+ func = function(node) {
+ return node.nodeName == name;
+ };
+ }
+
+ for (i = 0; i < parents.length; i++) {
+ if (func(parents[i]))
+ return parents[i];
+ }
+ };
+
+ cm.setActive('visualaid', ed.hasVisual);
+ t._updateUndoStatus(ed);
+ cm.setDisabled('outdent', !ed.queryCommandState('Outdent'));
+
+ p = getParent('A');
+ if (c = cm.get('link')) {
+ c.setDisabled((!p && co) || (p && !p.href));
+ c.setActive(!!p && (!p.name && !p.id));
+ }
+
+ if (c = cm.get('unlink')) {
+ c.setDisabled(!p && co);
+ c.setActive(!!p && !p.name && !p.id);
+ }
+
+ if (c = cm.get('anchor')) {
+ c.setActive(!co && !!p && (p.name || (p.id && !p.href)));
+ }
+
+ p = getParent('IMG');
+ if (c = cm.get('image'))
+ c.setActive(!co && !!p && n.className.indexOf('mceItem') == -1);
+
+ if (c = cm.get('styleselect')) {
+ t._importClasses();
+
+ formatNames = [];
+ each(c.items, function(item) {
+ formatNames.push(item.value);
+ });
+
+ matches = ed.formatter.matchAll(formatNames);
+ c.select(matches[0]);
+ tinymce.each(matches, function(match, index) {
+ if (index > 0) {
+ c.mark(match);
+ }
+ });
+ }
+
+ if (c = cm.get('formatselect')) {
+ p = getParent(ed.dom.isBlock);
+
+ if (p)
+ c.select(p.nodeName.toLowerCase());
+ }
+
+ // Find out current fontSize, fontFamily and fontClass
+ getParent(function(n) {
+ if (n.nodeName === 'SPAN') {
+ if (!cl && n.className)
+ cl = n.className;
+ }
+
+ if (ed.dom.is(n, s.theme_advanced_font_selector)) {
+ if (!fz && n.style.fontSize)
+ fz = n.style.fontSize;
+
+ if (!fn && n.style.fontFamily)
+ fn = n.style.fontFamily.replace(/[\"\']+/g, '').replace(/^([^,]+).*/, '$1').toLowerCase();
+
+ if (!fc && n.style.color)
+ fc = n.style.color;
+
+ if (!bc && n.style.backgroundColor)
+ bc = n.style.backgroundColor;
+ }
+
+ return false;
+ });
+
+ if (c = cm.get('fontselect')) {
+ c.select(function(v) {
+ return v.replace(/^([^,]+).*/, '$1').toLowerCase() == fn;
+ });
+ }
+
+ // Select font size
+ if (c = cm.get('fontsizeselect')) {
+ // Use computed style
+ if (s.theme_advanced_runtime_fontsize && !fz && !cl)
+ fz = ed.dom.getStyle(n, 'fontSize', true);
+
+ c.select(function(v) {
+ if (v.fontSize && v.fontSize === fz)
+ return true;
+
+ if (v['class'] && v['class'] === cl)
+ return true;
+ });
+ }
+
+ if (s.theme_advanced_show_current_color) {
+ function updateColor(controlId, color) {
+ if (c = cm.get(controlId)) {
+ if (!color)
+ color = c.settings.default_color;
+ if (color !== c.value) {
+ c.displayColor(color);
+ }
+ }
+ }
+ updateColor('forecolor', fc);
+ updateColor('backcolor', bc);
+ }
+
+ if (s.theme_advanced_show_current_color) {
+ function updateColor(controlId, color) {
+ if (c = cm.get(controlId)) {
+ if (!color)
+ color = c.settings.default_color;
+ if (color !== c.value) {
+ c.displayColor(color);
+ }
+ }
+ };
+
+ updateColor('forecolor', fc);
+ updateColor('backcolor', bc);
+ }
+
+ if (s.theme_advanced_path && s.theme_advanced_statusbar_location) {
+ p = DOM.get(ed.id + '_path') || DOM.add(ed.id + '_path_row', 'span', {id : ed.id + '_path'});
+
+ if (t.statusKeyboardNavigation) {
+ t.statusKeyboardNavigation.destroy();
+ t.statusKeyboardNavigation = null;
+ }
+
+ DOM.setHTML(p, '');
+
+ getParent(function(n) {
+ var na = n.nodeName.toLowerCase(), u, pi, ti = '';
+
+ // Ignore non element and bogus/hidden elements
+ if (n.nodeType != 1 || na === 'br' || n.getAttribute('data-mce-bogus') || DOM.hasClass(n, 'mceItemHidden') || DOM.hasClass(n, 'mceItemRemoved'))
+ return;
+
+ // Handle prefix
+ if (tinymce.isIE && n.scopeName !== 'HTML' && n.scopeName)
+ na = n.scopeName + ':' + na;
+
+ // Remove internal prefix
+ na = na.replace(/mce\:/g, '');
+
+ // Handle node name
+ switch (na) {
+ case 'b':
+ na = 'strong';
+ break;
+
+ case 'i':
+ na = 'em';
+ break;
+
+ case 'img':
+ if (v = DOM.getAttrib(n, 'src'))
+ ti += 'src: ' + v + ' ';
+
+ break;
+
+ case 'a':
+ if (v = DOM.getAttrib(n, 'name')) {
+ ti += 'name: ' + v + ' ';
+ na += '#' + v;
+ }
+
+ if (v = DOM.getAttrib(n, 'href'))
+ ti += 'href: ' + v + ' ';
+
+ break;
+
+ case 'font':
+ if (v = DOM.getAttrib(n, 'face'))
+ ti += 'font: ' + v + ' ';
+
+ if (v = DOM.getAttrib(n, 'size'))
+ ti += 'size: ' + v + ' ';
+
+ if (v = DOM.getAttrib(n, 'color'))
+ ti += 'color: ' + v + ' ';
+
+ break;
+
+ case 'span':
+ if (v = DOM.getAttrib(n, 'style'))
+ ti += 'style: ' + v + ' ';
+
+ break;
+ }
+
+ if (v = DOM.getAttrib(n, 'id'))
+ ti += 'id: ' + v + ' ';
+
+ if (v = n.className) {
+ v = v.replace(/\b\s*(webkit|mce|Apple-)\w+\s*\b/g, '')
+
+ if (v) {
+ ti += 'class: ' + v + ' ';
+
+ if (ed.dom.isBlock(n) || na == 'img' || na == 'span')
+ na += '.' + v;
+ }
+ }
+
+ na = na.replace(/(html:)/g, '');
+ na = {name : na, node : n, title : ti};
+ t.onResolveName.dispatch(t, na);
+ ti = na.title;
+ na = na.name;
+
+ //u = "javascript:tinymce.EditorManager.get('" + ed.id + "').theme._sel('" + (de++) + "');";
+ pi = DOM.create('a', {'href' : "javascript:;", role: 'button', onmousedown : "return false;", title : ti, 'class' : 'mcePath_' + (de++)}, na);
+
+ if (p.hasChildNodes()) {
+ p.insertBefore(DOM.create('span', {'aria-hidden': 'true'}, '\u00a0\u00bb '), p.firstChild);
+ p.insertBefore(pi, p.firstChild);
+ } else
+ p.appendChild(pi);
+ }, ed.getBody());
+
+ if (DOM.select('a', p).length > 0) {
+ t.statusKeyboardNavigation = new tinymce.ui.KeyboardNavigation({
+ root: ed.id + "_path_row",
+ items: DOM.select('a', p),
+ excludeFromTabOrder: true,
+ onCancel: function() {
+ ed.focus();
+ }
+ }, DOM);
+ }
+ }
+ },
+
+ // Commands gets called by execCommand
+
+ _sel : function(v) {
+ this.editor.execCommand('mceSelectNodeDepth', false, v);
+ },
+
+ _mceInsertAnchor : function(ui, v) {
+ var ed = this.editor;
+
+ ed.windowManager.open({
+ url : this.url + '/anchor.htm',
+ width : 320 + parseInt(ed.getLang('advanced.anchor_delta_width', 0)),
+ height : 90 + parseInt(ed.getLang('advanced.anchor_delta_height', 0)),
+ inline : true
+ }, {
+ theme_url : this.url
+ });
+ },
+
+ _mceCharMap : function() {
+ var ed = this.editor;
+
+ ed.windowManager.open({
+ url : this.url + '/charmap.htm',
+ width : 550 + parseInt(ed.getLang('advanced.charmap_delta_width', 0)),
+ height : 265 + parseInt(ed.getLang('advanced.charmap_delta_height', 0)),
+ inline : true
+ }, {
+ theme_url : this.url
+ });
+ },
+
+ _mceHelp : function() {
+ var ed = this.editor;
+
+ ed.windowManager.open({
+ url : this.url + '/about.htm',
+ width : 480,
+ height : 380,
+ inline : true
+ }, {
+ theme_url : this.url
+ });
+ },
+
+ _mceShortcuts : function() {
+ var ed = this.editor;
+ ed.windowManager.open({
+ url: this.url + '/shortcuts.htm',
+ width: 480,
+ height: 380,
+ inline: true
+ }, {
+ theme_url: this.url
+ });
+ },
+
+ _mceColorPicker : function(u, v) {
+ var ed = this.editor;
+
+ v = v || {};
+
+ ed.windowManager.open({
+ url : this.url + '/color_picker.htm',
+ width : 375 + parseInt(ed.getLang('advanced.colorpicker_delta_width', 0)),
+ height : 250 + parseInt(ed.getLang('advanced.colorpicker_delta_height', 0)),
+ close_previous : false,
+ inline : true
+ }, {
+ input_color : v.color,
+ func : v.func,
+ theme_url : this.url
+ });
+ },
+
+ _mceCodeEditor : function(ui, val) {
+ var ed = this.editor;
+
+ ed.windowManager.open({
+ url : this.url + '/source_editor.htm',
+ width : parseInt(ed.getParam("theme_advanced_source_editor_width", 720)),
+ height : parseInt(ed.getParam("theme_advanced_source_editor_height", 580)),
+ inline : true,
+ resizable : true,
+ maximizable : true
+ }, {
+ theme_url : this.url
+ });
+ },
+
+ _mceImage : function(ui, val) {
+ var ed = this.editor;
+
+ // Internal image object like a flash placeholder
+ if (ed.dom.getAttrib(ed.selection.getNode(), 'class', '').indexOf('mceItem') != -1)
+ return;
+
+ ed.windowManager.open({
+ url : this.url + '/image.htm',
+ width : 355 + parseInt(ed.getLang('advanced.image_delta_width', 0)),
+ height : 275 + parseInt(ed.getLang('advanced.image_delta_height', 0)),
+ inline : true
+ }, {
+ theme_url : this.url
+ });
+ },
+
+ _mceLink : function(ui, val) {
+ var ed = this.editor;
+
+ ed.windowManager.open({
+ url : this.url + '/link.htm',
+ width : 310 + parseInt(ed.getLang('advanced.link_delta_width', 0)),
+ height : 200 + parseInt(ed.getLang('advanced.link_delta_height', 0)),
+ inline : true
+ }, {
+ theme_url : this.url
+ });
+ },
+
+ _mceNewDocument : function() {
+ var ed = this.editor;
+
+ ed.windowManager.confirm('advanced.newdocument', function(s) {
+ if (s)
+ ed.execCommand('mceSetContent', false, '');
+ });
+ },
+
+ _mceForeColor : function() {
+ var t = this;
+
+ this._mceColorPicker(0, {
+ color: t.fgColor,
+ func : function(co) {
+ t.fgColor = co;
+ t.editor.execCommand('ForeColor', false, co);
+ }
+ });
+ },
+
+ _mceBackColor : function() {
+ var t = this;
+
+ this._mceColorPicker(0, {
+ color: t.bgColor,
+ func : function(co) {
+ t.bgColor = co;
+ t.editor.execCommand('HiliteColor', false, co);
+ }
+ });
+ },
+
+ _ufirst : function(s) {
+ return s.substring(0, 1).toUpperCase() + s.substring(1);
+ }
+ });
+
+ tinymce.ThemeManager.add('advanced', tinymce.themes.AdvancedTheme);
+}(tinymce));
diff --git a/askbot/media/js/tinymce/themes/advanced/image.htm b/askbot/media/js/tinymce/themes/advanced/image.htm
new file mode 100644
index 00000000..b8ba729f
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/image.htm
@@ -0,0 +1,80 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#advanced_dlg.image_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="js/image.js"></script>
+</head>
+<body id="image" style="display: none">
+<form onsubmit="ImageDialog.update();return false;" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#advanced_dlg.image_title}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <table border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td class="nowrap"><label for="src">{#advanced_dlg.image_src}</label></td>
+ <td><table border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input id="src" name="src" type="text" class="mceFocus" value="" style="width: 200px" onchange="ImageDialog.getImageData();" /></td>
+ <td id="srcbrowsercontainer">&nbsp;</td>
+ </tr>
+ </table></td>
+ </tr>
+ <tr>
+ <td><label for="image_list">{#advanced_dlg.image_list}</label></td>
+ <td><select id="image_list" name="image_list" onchange="document.getElementById('src').value=this.options[this.selectedIndex].value;document.getElementById('alt').value=this.options[this.selectedIndex].text;"></select></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="alt">{#advanced_dlg.image_alt}</label></td>
+ <td><input id="alt" name="alt" type="text" value="" style="width: 200px" /></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="align">{#advanced_dlg.image_align}</label></td>
+ <td><select id="align" name="align" onchange="ImageDialog.updateStyle();">
+ <option value="">{#not_set}</option>
+ <option value="baseline">{#advanced_dlg.image_align_baseline}</option>
+ <option value="top">{#advanced_dlg.image_align_top}</option>
+ <option value="middle">{#advanced_dlg.image_align_middle}</option>
+ <option value="bottom">{#advanced_dlg.image_align_bottom}</option>
+ <option value="text-top">{#advanced_dlg.image_align_texttop}</option>
+ <option value="text-bottom">{#advanced_dlg.image_align_textbottom}</option>
+ <option value="left">{#advanced_dlg.image_align_left}</option>
+ <option value="right">{#advanced_dlg.image_align_right}</option>
+ </select></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="width">{#advanced_dlg.image_dimensions}</label></td>
+ <td><input id="width" name="width" type="text" value="" size="3" maxlength="5" />
+ x
+ <input id="height" name="height" type="text" value="" size="3" maxlength="5" /></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="border">{#advanced_dlg.image_border}</label></td>
+ <td><input id="border" name="border" type="text" value="" size="3" maxlength="3" onchange="ImageDialog.updateStyle();" /></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="vspace">{#advanced_dlg.image_vspace}</label></td>
+ <td><input id="vspace" name="vspace" type="text" value="" size="3" maxlength="3" onchange="ImageDialog.updateStyle();" /></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="hspace">{#advanced_dlg.image_hspace}</label></td>
+ <td><input id="hspace" name="hspace" type="text" value="" size="3" maxlength="3" onchange="ImageDialog.updateStyle();" /></td>
+ </tr>
+ </table>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#insert}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/themes/advanced/img/colorpicker.jpg b/askbot/media/js/tinymce/themes/advanced/img/colorpicker.jpg
new file mode 100644
index 00000000..b1a377ab
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/img/colorpicker.jpg
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/img/flash.gif b/askbot/media/js/tinymce/themes/advanced/img/flash.gif
new file mode 100644
index 00000000..dec3f7c7
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/img/flash.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/img/icons.gif b/askbot/media/js/tinymce/themes/advanced/img/icons.gif
new file mode 100644
index 00000000..ca222490
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/img/icons.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/img/iframe.gif b/askbot/media/js/tinymce/themes/advanced/img/iframe.gif
new file mode 100644
index 00000000..410c7ad0
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/img/iframe.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/img/pagebreak.gif b/askbot/media/js/tinymce/themes/advanced/img/pagebreak.gif
new file mode 100644
index 00000000..acdf4085
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/img/pagebreak.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/img/quicktime.gif b/askbot/media/js/tinymce/themes/advanced/img/quicktime.gif
new file mode 100644
index 00000000..8f10e7aa
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/img/quicktime.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/img/realmedia.gif b/askbot/media/js/tinymce/themes/advanced/img/realmedia.gif
new file mode 100644
index 00000000..fdfe0b9a
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/img/realmedia.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/img/shockwave.gif b/askbot/media/js/tinymce/themes/advanced/img/shockwave.gif
new file mode 100644
index 00000000..9314d044
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/img/shockwave.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/img/trans.gif b/askbot/media/js/tinymce/themes/advanced/img/trans.gif
new file mode 100644
index 00000000..38848651
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/img/trans.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/img/video.gif b/askbot/media/js/tinymce/themes/advanced/img/video.gif
new file mode 100644
index 00000000..35701040
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/img/video.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/img/windowsmedia.gif b/askbot/media/js/tinymce/themes/advanced/img/windowsmedia.gif
new file mode 100644
index 00000000..ab50f2d8
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/img/windowsmedia.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/js/about.js b/askbot/media/js/tinymce/themes/advanced/js/about.js
new file mode 100644
index 00000000..5b358457
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/js/about.js
@@ -0,0 +1,73 @@
+tinyMCEPopup.requireLangPack();
+
+function init() {
+ var ed, tcont;
+
+ tinyMCEPopup.resizeToInnerSize();
+ ed = tinyMCEPopup.editor;
+
+ // Give FF some time
+ window.setTimeout(insertHelpIFrame, 10);
+
+ tcont = document.getElementById('plugintablecontainer');
+ document.getElementById('plugins_tab').style.display = 'none';
+
+ var html = "";
+ html += '<table id="plugintable">';
+ html += '<thead>';
+ html += '<tr>';
+ html += '<td>' + ed.getLang('advanced_dlg.about_plugin') + '</td>';
+ html += '<td>' + ed.getLang('advanced_dlg.about_author') + '</td>';
+ html += '<td>' + ed.getLang('advanced_dlg.about_version') + '</td>';
+ html += '</tr>';
+ html += '</thead>';
+ html += '<tbody>';
+
+ tinymce.each(ed.plugins, function(p, n) {
+ var info;
+
+ if (!p.getInfo)
+ return;
+
+ html += '<tr>';
+
+ info = p.getInfo();
+
+ if (info.infourl != null && info.infourl != '')
+ html += '<td width="50%" title="' + n + '"><a href="' + info.infourl + '" target="_blank">' + info.longname + '</a></td>';
+ else
+ html += '<td width="50%" title="' + n + '">' + info.longname + '</td>';
+
+ if (info.authorurl != null && info.authorurl != '')
+ html += '<td width="35%"><a href="' + info.authorurl + '" target="_blank">' + info.author + '</a></td>';
+ else
+ html += '<td width="35%">' + info.author + '</td>';
+
+ html += '<td width="15%">' + info.version + '</td>';
+ html += '</tr>';
+
+ document.getElementById('plugins_tab').style.display = '';
+
+ });
+
+ html += '</tbody>';
+ html += '</table>';
+
+ tcont.innerHTML = html;
+
+ tinyMCEPopup.dom.get('version').innerHTML = tinymce.majorVersion + "." + tinymce.minorVersion;
+ tinyMCEPopup.dom.get('date').innerHTML = tinymce.releaseDate;
+}
+
+function insertHelpIFrame() {
+ var html;
+
+ if (tinyMCEPopup.getParam('docs_url')) {
+ html = '<iframe width="100%" height="300" src="' + tinyMCEPopup.editor.baseURI.toAbsolute(tinyMCEPopup.getParam('docs_url')) + '"></iframe>';
+ document.getElementById('iframecontainer').innerHTML = html;
+ document.getElementById('help_tab').style.display = 'block';
+ document.getElementById('help_tab').setAttribute("aria-hidden", "false");
+ }
+}
+
+tinyMCEPopup.onInit.add(init);
diff --git a/askbot/media/js/tinymce/themes/advanced/js/anchor.js b/askbot/media/js/tinymce/themes/advanced/js/anchor.js
new file mode 100644
index 00000000..2909a3a4
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/js/anchor.js
@@ -0,0 +1,56 @@
+tinyMCEPopup.requireLangPack();
+
+var AnchorDialog = {
+ init : function(ed) {
+ var action, elm, f = document.forms[0];
+
+ this.editor = ed;
+ elm = ed.dom.getParent(ed.selection.getNode(), 'A');
+ v = ed.dom.getAttrib(elm, 'name') || ed.dom.getAttrib(elm, 'id');
+
+ if (v) {
+ this.action = 'update';
+ f.anchorName.value = v;
+ }
+
+ f.insert.value = ed.getLang(elm ? 'update' : 'insert');
+ },
+
+ update : function() {
+ var ed = this.editor, elm, name = document.forms[0].anchorName.value, attribName;
+
+ if (!name || !/^[a-z][a-z0-9\-\_:\.]*$/i.test(name)) {
+ tinyMCEPopup.alert('advanced_dlg.anchor_invalid');
+ return;
+ }
+
+ tinyMCEPopup.restoreSelection();
+
+ if (this.action != 'update')
+ ed.selection.collapse(1);
+
+ var aRule = ed.schema.getElementRule('a');
+ if (!aRule || aRule.attributes.name) {
+ attribName = 'name';
+ } else {
+ attribName = 'id';
+ }
+
+ elm = ed.dom.getParent(ed.selection.getNode(), 'A');
+ if (elm) {
+ elm.setAttribute(attribName, name);
+ elm[attribName] = name;
+ ed.undoManager.add();
+ } else {
+ // create with zero-sized nbsp so that in Webkit where anchor is on last line by itself caret cannot be placed after it
+ var attrs = {'class' : 'mceItemAnchor'};
+ attrs[attribName] = name;
+ ed.execCommand('mceInsertContent', 0, ed.dom.createHTML('a', attrs, '\uFEFF'));
+ ed.nodeChanged();
+ }
+
+ tinyMCEPopup.close();
+ }
+};
+
+tinyMCEPopup.onInit.add(AnchorDialog.init, AnchorDialog);
diff --git a/askbot/media/js/tinymce/themes/advanced/js/charmap.js b/askbot/media/js/tinymce/themes/advanced/js/charmap.js
new file mode 100644
index 00000000..bb186955
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/js/charmap.js
@@ -0,0 +1,363 @@
+/**
+ * charmap.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+tinyMCEPopup.requireLangPack();
+
+var charmap = [
+ ['&nbsp;', '&#160;', true, 'no-break space'],
+ ['&amp;', '&#38;', true, 'ampersand'],
+ ['&quot;', '&#34;', true, 'quotation mark'],
+// finance
+ ['&cent;', '&#162;', true, 'cent sign'],
+ ['&euro;', '&#8364;', true, 'euro sign'],
+ ['&pound;', '&#163;', true, 'pound sign'],
+ ['&yen;', '&#165;', true, 'yen sign'],
+// signs
+ ['&copy;', '&#169;', true, 'copyright sign'],
+ ['&reg;', '&#174;', true, 'registered sign'],
+ ['&trade;', '&#8482;', true, 'trade mark sign'],
+ ['&permil;', '&#8240;', true, 'per mille sign'],
+ ['&micro;', '&#181;', true, 'micro sign'],
+ ['&middot;', '&#183;', true, 'middle dot'],
+ ['&bull;', '&#8226;', true, 'bullet'],
+ ['&hellip;', '&#8230;', true, 'three dot leader'],
+ ['&prime;', '&#8242;', true, 'minutes / feet'],
+ ['&Prime;', '&#8243;', true, 'seconds / inches'],
+ ['&sect;', '&#167;', true, 'section sign'],
+ ['&para;', '&#182;', true, 'paragraph sign'],
+ ['&szlig;', '&#223;', true, 'sharp s / ess-zed'],
+// quotations
+ ['&lsaquo;', '&#8249;', true, 'single left-pointing angle quotation mark'],
+ ['&rsaquo;', '&#8250;', true, 'single right-pointing angle quotation mark'],
+ ['&laquo;', '&#171;', true, 'left pointing guillemet'],
+ ['&raquo;', '&#187;', true, 'right pointing guillemet'],
+ ['&lsquo;', '&#8216;', true, 'left single quotation mark'],
+ ['&rsquo;', '&#8217;', true, 'right single quotation mark'],
+ ['&ldquo;', '&#8220;', true, 'left double quotation mark'],
+ ['&rdquo;', '&#8221;', true, 'right double quotation mark'],
+ ['&sbquo;', '&#8218;', true, 'single low-9 quotation mark'],
+ ['&bdquo;', '&#8222;', true, 'double low-9 quotation mark'],
+ ['&lt;', '&#60;', true, 'less-than sign'],
+ ['&gt;', '&#62;', true, 'greater-than sign'],
+ ['&le;', '&#8804;', true, 'less-than or equal to'],
+ ['&ge;', '&#8805;', true, 'greater-than or equal to'],
+ ['&ndash;', '&#8211;', true, 'en dash'],
+ ['&mdash;', '&#8212;', true, 'em dash'],
+ ['&macr;', '&#175;', true, 'macron'],
+ ['&oline;', '&#8254;', true, 'overline'],
+ ['&curren;', '&#164;', true, 'currency sign'],
+ ['&brvbar;', '&#166;', true, 'broken bar'],
+ ['&uml;', '&#168;', true, 'diaeresis'],
+ ['&iexcl;', '&#161;', true, 'inverted exclamation mark'],
+ ['&iquest;', '&#191;', true, 'turned question mark'],
+ ['&circ;', '&#710;', true, 'circumflex accent'],
+ ['&tilde;', '&#732;', true, 'small tilde'],
+ ['&deg;', '&#176;', true, 'degree sign'],
+ ['&minus;', '&#8722;', true, 'minus sign'],
+ ['&plusmn;', '&#177;', true, 'plus-minus sign'],
+ ['&divide;', '&#247;', true, 'division sign'],
+ ['&frasl;', '&#8260;', true, 'fraction slash'],
+ ['&times;', '&#215;', true, 'multiplication sign'],
+ ['&sup1;', '&#185;', true, 'superscript one'],
+ ['&sup2;', '&#178;', true, 'superscript two'],
+ ['&sup3;', '&#179;', true, 'superscript three'],
+ ['&frac14;', '&#188;', true, 'fraction one quarter'],
+ ['&frac12;', '&#189;', true, 'fraction one half'],
+ ['&frac34;', '&#190;', true, 'fraction three quarters'],
+// math / logical
+ ['&fnof;', '&#402;', true, 'function / florin'],
+ ['&int;', '&#8747;', true, 'integral'],
+ ['&sum;', '&#8721;', true, 'n-ary sumation'],
+ ['&infin;', '&#8734;', true, 'infinity'],
+ ['&radic;', '&#8730;', true, 'square root'],
+ ['&sim;', '&#8764;', false,'similar to'],
+ ['&cong;', '&#8773;', false,'approximately equal to'],
+ ['&asymp;', '&#8776;', true, 'almost equal to'],
+ ['&ne;', '&#8800;', true, 'not equal to'],
+ ['&equiv;', '&#8801;', true, 'identical to'],
+ ['&isin;', '&#8712;', false,'element of'],
+ ['&notin;', '&#8713;', false,'not an element of'],
+ ['&ni;', '&#8715;', false,'contains as member'],
+ ['&prod;', '&#8719;', true, 'n-ary product'],
+ ['&and;', '&#8743;', false,'logical and'],
+ ['&or;', '&#8744;', false,'logical or'],
+ ['&not;', '&#172;', true, 'not sign'],
+ ['&cap;', '&#8745;', true, 'intersection'],
+ ['&cup;', '&#8746;', false,'union'],
+ ['&part;', '&#8706;', true, 'partial differential'],
+ ['&forall;', '&#8704;', false,'for all'],
+ ['&exist;', '&#8707;', false,'there exists'],
+ ['&empty;', '&#8709;', false,'diameter'],
+ ['&nabla;', '&#8711;', false,'backward difference'],
+ ['&lowast;', '&#8727;', false,'asterisk operator'],
+ ['&prop;', '&#8733;', false,'proportional to'],
+ ['&ang;', '&#8736;', false,'angle'],
+// undefined
+ ['&acute;', '&#180;', true, 'acute accent'],
+ ['&cedil;', '&#184;', true, 'cedilla'],
+ ['&ordf;', '&#170;', true, 'feminine ordinal indicator'],
+ ['&ordm;', '&#186;', true, 'masculine ordinal indicator'],
+ ['&dagger;', '&#8224;', true, 'dagger'],
+ ['&Dagger;', '&#8225;', true, 'double dagger'],
+// alphabetical special chars
+ ['&Agrave;', '&#192;', true, 'A - grave'],
+ ['&Aacute;', '&#193;', true, 'A - acute'],
+ ['&Acirc;', '&#194;', true, 'A - circumflex'],
+ ['&Atilde;', '&#195;', true, 'A - tilde'],
+ ['&Auml;', '&#196;', true, 'A - diaeresis'],
+ ['&Aring;', '&#197;', true, 'A - ring above'],
+ ['&AElig;', '&#198;', true, 'ligature AE'],
+ ['&Ccedil;', '&#199;', true, 'C - cedilla'],
+ ['&Egrave;', '&#200;', true, 'E - grave'],
+ ['&Eacute;', '&#201;', true, 'E - acute'],
+ ['&Ecirc;', '&#202;', true, 'E - circumflex'],
+ ['&Euml;', '&#203;', true, 'E - diaeresis'],
+ ['&Igrave;', '&#204;', true, 'I - grave'],
+ ['&Iacute;', '&#205;', true, 'I - acute'],
+ ['&Icirc;', '&#206;', true, 'I - circumflex'],
+ ['&Iuml;', '&#207;', true, 'I - diaeresis'],
+ ['&ETH;', '&#208;', true, 'ETH'],
+ ['&Ntilde;', '&#209;', true, 'N - tilde'],
+ ['&Ograve;', '&#210;', true, 'O - grave'],
+ ['&Oacute;', '&#211;', true, 'O - acute'],
+ ['&Ocirc;', '&#212;', true, 'O - circumflex'],
+ ['&Otilde;', '&#213;', true, 'O - tilde'],
+ ['&Ouml;', '&#214;', true, 'O - diaeresis'],
+ ['&Oslash;', '&#216;', true, 'O - slash'],
+ ['&OElig;', '&#338;', true, 'ligature OE'],
+ ['&Scaron;', '&#352;', true, 'S - caron'],
+ ['&Ugrave;', '&#217;', true, 'U - grave'],
+ ['&Uacute;', '&#218;', true, 'U - acute'],
+ ['&Ucirc;', '&#219;', true, 'U - circumflex'],
+ ['&Uuml;', '&#220;', true, 'U - diaeresis'],
+ ['&Yacute;', '&#221;', true, 'Y - acute'],
+ ['&Yuml;', '&#376;', true, 'Y - diaeresis'],
+ ['&THORN;', '&#222;', true, 'THORN'],
+ ['&agrave;', '&#224;', true, 'a - grave'],
+ ['&aacute;', '&#225;', true, 'a - acute'],
+ ['&acirc;', '&#226;', true, 'a - circumflex'],
+ ['&atilde;', '&#227;', true, 'a - tilde'],
+ ['&auml;', '&#228;', true, 'a - diaeresis'],
+ ['&aring;', '&#229;', true, 'a - ring above'],
+ ['&aelig;', '&#230;', true, 'ligature ae'],
+ ['&ccedil;', '&#231;', true, 'c - cedilla'],
+ ['&egrave;', '&#232;', true, 'e - grave'],
+ ['&eacute;', '&#233;', true, 'e - acute'],
+ ['&ecirc;', '&#234;', true, 'e - circumflex'],
+ ['&euml;', '&#235;', true, 'e - diaeresis'],
+ ['&igrave;', '&#236;', true, 'i - grave'],
+ ['&iacute;', '&#237;', true, 'i - acute'],
+ ['&icirc;', '&#238;', true, 'i - circumflex'],
+ ['&iuml;', '&#239;', true, 'i - diaeresis'],
+ ['&eth;', '&#240;', true, 'eth'],
+ ['&ntilde;', '&#241;', true, 'n - tilde'],
+ ['&ograve;', '&#242;', true, 'o - grave'],
+ ['&oacute;', '&#243;', true, 'o - acute'],
+ ['&ocirc;', '&#244;', true, 'o - circumflex'],
+ ['&otilde;', '&#245;', true, 'o - tilde'],
+ ['&ouml;', '&#246;', true, 'o - diaeresis'],
+ ['&oslash;', '&#248;', true, 'o slash'],
+ ['&oelig;', '&#339;', true, 'ligature oe'],
+ ['&scaron;', '&#353;', true, 's - caron'],
+ ['&ugrave;', '&#249;', true, 'u - grave'],
+ ['&uacute;', '&#250;', true, 'u - acute'],
+ ['&ucirc;', '&#251;', true, 'u - circumflex'],
+ ['&uuml;', '&#252;', true, 'u - diaeresis'],
+ ['&yacute;', '&#253;', true, 'y - acute'],
+ ['&thorn;', '&#254;', true, 'thorn'],
+ ['&yuml;', '&#255;', true, 'y - diaeresis'],
+ ['&Alpha;', '&#913;', true, 'Alpha'],
+ ['&Beta;', '&#914;', true, 'Beta'],
+ ['&Gamma;', '&#915;', true, 'Gamma'],
+ ['&Delta;', '&#916;', true, 'Delta'],
+ ['&Epsilon;', '&#917;', true, 'Epsilon'],
+ ['&Zeta;', '&#918;', true, 'Zeta'],
+ ['&Eta;', '&#919;', true, 'Eta'],
+ ['&Theta;', '&#920;', true, 'Theta'],
+ ['&Iota;', '&#921;', true, 'Iota'],
+ ['&Kappa;', '&#922;', true, 'Kappa'],
+ ['&Lambda;', '&#923;', true, 'Lambda'],
+ ['&Mu;', '&#924;', true, 'Mu'],
+ ['&Nu;', '&#925;', true, 'Nu'],
+ ['&Xi;', '&#926;', true, 'Xi'],
+ ['&Omicron;', '&#927;', true, 'Omicron'],
+ ['&Pi;', '&#928;', true, 'Pi'],
+ ['&Rho;', '&#929;', true, 'Rho'],
+ ['&Sigma;', '&#931;', true, 'Sigma'],
+ ['&Tau;', '&#932;', true, 'Tau'],
+ ['&Upsilon;', '&#933;', true, 'Upsilon'],
+ ['&Phi;', '&#934;', true, 'Phi'],
+ ['&Chi;', '&#935;', true, 'Chi'],
+ ['&Psi;', '&#936;', true, 'Psi'],
+ ['&Omega;', '&#937;', true, 'Omega'],
+ ['&alpha;', '&#945;', true, 'alpha'],
+ ['&beta;', '&#946;', true, 'beta'],
+ ['&gamma;', '&#947;', true, 'gamma'],
+ ['&delta;', '&#948;', true, 'delta'],
+ ['&epsilon;', '&#949;', true, 'epsilon'],
+ ['&zeta;', '&#950;', true, 'zeta'],
+ ['&eta;', '&#951;', true, 'eta'],
+ ['&theta;', '&#952;', true, 'theta'],
+ ['&iota;', '&#953;', true, 'iota'],
+ ['&kappa;', '&#954;', true, 'kappa'],
+ ['&lambda;', '&#955;', true, 'lambda'],
+ ['&mu;', '&#956;', true, 'mu'],
+ ['&nu;', '&#957;', true, 'nu'],
+ ['&xi;', '&#958;', true, 'xi'],
+ ['&omicron;', '&#959;', true, 'omicron'],
+ ['&pi;', '&#960;', true, 'pi'],
+ ['&rho;', '&#961;', true, 'rho'],
+ ['&sigmaf;', '&#962;', true, 'final sigma'],
+ ['&sigma;', '&#963;', true, 'sigma'],
+ ['&tau;', '&#964;', true, 'tau'],
+ ['&upsilon;', '&#965;', true, 'upsilon'],
+ ['&phi;', '&#966;', true, 'phi'],
+ ['&chi;', '&#967;', true, 'chi'],
+ ['&psi;', '&#968;', true, 'psi'],
+ ['&omega;', '&#969;', true, 'omega'],
+// symbols
+ ['&alefsym;', '&#8501;', false,'alef symbol'],
+ ['&piv;', '&#982;', false,'pi symbol'],
+ ['&real;', '&#8476;', false,'real part symbol'],
+ ['&thetasym;','&#977;', false,'theta symbol'],
+ ['&upsih;', '&#978;', false,'upsilon - hook symbol'],
+ ['&weierp;', '&#8472;', false,'Weierstrass p'],
+ ['&image;', '&#8465;', false,'imaginary part'],
+// arrows
+ ['&larr;', '&#8592;', true, 'leftwards arrow'],
+ ['&uarr;', '&#8593;', true, 'upwards arrow'],
+ ['&rarr;', '&#8594;', true, 'rightwards arrow'],
+ ['&darr;', '&#8595;', true, 'downwards arrow'],
+ ['&harr;', '&#8596;', true, 'left right arrow'],
+ ['&crarr;', '&#8629;', false,'carriage return'],
+ ['&lArr;', '&#8656;', false,'leftwards double arrow'],
+ ['&uArr;', '&#8657;', false,'upwards double arrow'],
+ ['&rArr;', '&#8658;', false,'rightwards double arrow'],
+ ['&dArr;', '&#8659;', false,'downwards double arrow'],
+ ['&hArr;', '&#8660;', false,'left right double arrow'],
+ ['&there4;', '&#8756;', false,'therefore'],
+ ['&sub;', '&#8834;', false,'subset of'],
+ ['&sup;', '&#8835;', false,'superset of'],
+ ['&nsub;', '&#8836;', false,'not a subset of'],
+ ['&sube;', '&#8838;', false,'subset of or equal to'],
+ ['&supe;', '&#8839;', false,'superset of or equal to'],
+ ['&oplus;', '&#8853;', false,'circled plus'],
+ ['&otimes;', '&#8855;', false,'circled times'],
+ ['&perp;', '&#8869;', false,'perpendicular'],
+ ['&sdot;', '&#8901;', false,'dot operator'],
+ ['&lceil;', '&#8968;', false,'left ceiling'],
+ ['&rceil;', '&#8969;', false,'right ceiling'],
+ ['&lfloor;', '&#8970;', false,'left floor'],
+ ['&rfloor;', '&#8971;', false,'right floor'],
+ ['&lang;', '&#9001;', false,'left-pointing angle bracket'],
+ ['&rang;', '&#9002;', false,'right-pointing angle bracket'],
+ ['&loz;', '&#9674;', true, 'lozenge'],
+ ['&spades;', '&#9824;', true, 'black spade suit'],
+ ['&clubs;', '&#9827;', true, 'black club suit'],
+ ['&hearts;', '&#9829;', true, 'black heart suit'],
+ ['&diams;', '&#9830;', true, 'black diamond suit'],
+ ['&ensp;', '&#8194;', false,'en space'],
+ ['&emsp;', '&#8195;', false,'em space'],
+ ['&thinsp;', '&#8201;', false,'thin space'],
+ ['&zwnj;', '&#8204;', false,'zero width non-joiner'],
+ ['&zwj;', '&#8205;', false,'zero width joiner'],
+ ['&lrm;', '&#8206;', false,'left-to-right mark'],
+ ['&rlm;', '&#8207;', false,'right-to-left mark'],
+ ['&shy;', '&#173;', false,'soft hyphen']
+];
+
+tinyMCEPopup.onInit.add(function() {
+ tinyMCEPopup.dom.setHTML('charmapView', renderCharMapHTML());
+ addKeyboardNavigation();
+});
+
+function addKeyboardNavigation(){
+ var tableElm, cells, settings;
+
+ cells = tinyMCEPopup.dom.select("a.charmaplink", "charmapgroup");
+
+ settings ={
+ root: "charmapgroup",
+ items: cells
+ };
+ cells[0].tabindex=0;
+ tinyMCEPopup.dom.addClass(cells[0], "mceFocus");
+ if (tinymce.isGecko) {
+ cells[0].focus();
+ } else {
+ setTimeout(function(){
+ cells[0].focus();
+ }, 100);
+ }
+ tinyMCEPopup.editor.windowManager.createInstance('tinymce.ui.KeyboardNavigation', settings, tinyMCEPopup.dom);
+}
+
+function renderCharMapHTML() {
+ var charsPerRow = 20, tdWidth=20, tdHeight=20, i;
+ var html = '<div id="charmapgroup" aria-labelledby="charmap_label" tabindex="0" role="listbox">'+
+ '<table role="presentation" border="0" cellspacing="1" cellpadding="0" width="' + (tdWidth*charsPerRow) +
+ '"><tr height="' + tdHeight + '">';
+ var cols=-1;
+
+ for (i=0; i<charmap.length; i++) {
+ var previewCharFn;
+
+ if (charmap[i][2]==true) {
+ cols++;
+ previewCharFn = 'previewChar(\'' + charmap[i][1].substring(1,charmap[i][1].length) + '\',\'' + charmap[i][0].substring(1,charmap[i][0].length) + '\',\'' + charmap[i][3] + '\');';
+ html += ''
+ + '<td class="charmap">'
+ + '<a class="charmaplink" role="button" onmouseover="'+previewCharFn+'" onfocus="'+previewCharFn+'" href="javascript:void(0)" onclick="insertChar(\'' + charmap[i][1].substring(2,charmap[i][1].length-1) + '\');" onclick="return false;" onmousedown="return false;" title="' + charmap[i][3] + ' '+ tinyMCEPopup.editor.translate("advanced_dlg.charmap_usage")+'">'
+ + charmap[i][1]
+ + '</a></td>';
+ if ((cols+1) % charsPerRow == 0)
+ html += '</tr><tr height="' + tdHeight + '">';
+ }
+ }
+
+ if (cols % charsPerRow > 0) {
+ var padd = charsPerRow - (cols % charsPerRow);
+ for (var i=0; i<padd-1; i++)
+ html += '<td width="' + tdWidth + '" height="' + tdHeight + '" class="charmap">&nbsp;</td>';
+ }
+
+ html += '</tr></table></div>';
+ html = html.replace(/<tr height="20"><\/tr>/g, '');
+
+ return html;
+}
+
+function insertChar(chr) {
+ tinyMCEPopup.execCommand('mceInsertContent', false, '&#' + chr + ';');
+
+ // Refocus in window
+ if (tinyMCEPopup.isWindow)
+ window.focus();
+
+ tinyMCEPopup.editor.focus();
+ tinyMCEPopup.close();
+}
+
+function previewChar(codeA, codeB, codeN) {
+ var elmA = document.getElementById('codeA');
+ var elmB = document.getElementById('codeB');
+ var elmV = document.getElementById('codeV');
+ var elmN = document.getElementById('codeN');
+
+ if (codeA=='#160;') {
+ elmV.innerHTML = '__';
+ } else {
+ elmV.innerHTML = '&' + codeA;
+ }
+
+ elmB.innerHTML = '&amp;' + codeA;
+ elmA.innerHTML = '&amp;' + codeB;
+ elmN.innerHTML = codeN;
+}
diff --git a/askbot/media/js/tinymce/themes/advanced/js/color_picker.js b/askbot/media/js/tinymce/themes/advanced/js/color_picker.js
new file mode 100644
index 00000000..cc891c17
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/js/color_picker.js
@@ -0,0 +1,345 @@
+tinyMCEPopup.requireLangPack();
+
+var detail = 50, strhex = "0123456789abcdef", i, isMouseDown = false, isMouseOver = false;
+
+var colors = [
+ "#000000","#000033","#000066","#000099","#0000cc","#0000ff","#330000","#330033",
+ "#330066","#330099","#3300cc","#3300ff","#660000","#660033","#660066","#660099",
+ "#6600cc","#6600ff","#990000","#990033","#990066","#990099","#9900cc","#9900ff",
+ "#cc0000","#cc0033","#cc0066","#cc0099","#cc00cc","#cc00ff","#ff0000","#ff0033",
+ "#ff0066","#ff0099","#ff00cc","#ff00ff","#003300","#003333","#003366","#003399",
+ "#0033cc","#0033ff","#333300","#333333","#333366","#333399","#3333cc","#3333ff",
+ "#663300","#663333","#663366","#663399","#6633cc","#6633ff","#993300","#993333",
+ "#993366","#993399","#9933cc","#9933ff","#cc3300","#cc3333","#cc3366","#cc3399",
+ "#cc33cc","#cc33ff","#ff3300","#ff3333","#ff3366","#ff3399","#ff33cc","#ff33ff",
+ "#006600","#006633","#006666","#006699","#0066cc","#0066ff","#336600","#336633",
+ "#336666","#336699","#3366cc","#3366ff","#666600","#666633","#666666","#666699",
+ "#6666cc","#6666ff","#996600","#996633","#996666","#996699","#9966cc","#9966ff",
+ "#cc6600","#cc6633","#cc6666","#cc6699","#cc66cc","#cc66ff","#ff6600","#ff6633",
+ "#ff6666","#ff6699","#ff66cc","#ff66ff","#009900","#009933","#009966","#009999",
+ "#0099cc","#0099ff","#339900","#339933","#339966","#339999","#3399cc","#3399ff",
+ "#669900","#669933","#669966","#669999","#6699cc","#6699ff","#999900","#999933",
+ "#999966","#999999","#9999cc","#9999ff","#cc9900","#cc9933","#cc9966","#cc9999",
+ "#cc99cc","#cc99ff","#ff9900","#ff9933","#ff9966","#ff9999","#ff99cc","#ff99ff",
+ "#00cc00","#00cc33","#00cc66","#00cc99","#00cccc","#00ccff","#33cc00","#33cc33",
+ "#33cc66","#33cc99","#33cccc","#33ccff","#66cc00","#66cc33","#66cc66","#66cc99",
+ "#66cccc","#66ccff","#99cc00","#99cc33","#99cc66","#99cc99","#99cccc","#99ccff",
+ "#cccc00","#cccc33","#cccc66","#cccc99","#cccccc","#ccccff","#ffcc00","#ffcc33",
+ "#ffcc66","#ffcc99","#ffcccc","#ffccff","#00ff00","#00ff33","#00ff66","#00ff99",
+ "#00ffcc","#00ffff","#33ff00","#33ff33","#33ff66","#33ff99","#33ffcc","#33ffff",
+ "#66ff00","#66ff33","#66ff66","#66ff99","#66ffcc","#66ffff","#99ff00","#99ff33",
+ "#99ff66","#99ff99","#99ffcc","#99ffff","#ccff00","#ccff33","#ccff66","#ccff99",
+ "#ccffcc","#ccffff","#ffff00","#ffff33","#ffff66","#ffff99","#ffffcc","#ffffff"
+];
+
+var named = {
+ '#F0F8FF':'Alice Blue','#FAEBD7':'Antique White','#00FFFF':'Aqua','#7FFFD4':'Aquamarine','#F0FFFF':'Azure','#F5F5DC':'Beige',
+ '#FFE4C4':'Bisque','#000000':'Black','#FFEBCD':'Blanched Almond','#0000FF':'Blue','#8A2BE2':'Blue Violet','#A52A2A':'Brown',
+ '#DEB887':'Burly Wood','#5F9EA0':'Cadet Blue','#7FFF00':'Chartreuse','#D2691E':'Chocolate','#FF7F50':'Coral','#6495ED':'Cornflower Blue',
+ '#FFF8DC':'Cornsilk','#DC143C':'Crimson','#00FFFF':'Cyan','#00008B':'Dark Blue','#008B8B':'Dark Cyan','#B8860B':'Dark Golden Rod',
+ '#A9A9A9':'Dark Gray','#A9A9A9':'Dark Grey','#006400':'Dark Green','#BDB76B':'Dark Khaki','#8B008B':'Dark Magenta','#556B2F':'Dark Olive Green',
+ '#FF8C00':'Darkorange','#9932CC':'Dark Orchid','#8B0000':'Dark Red','#E9967A':'Dark Salmon','#8FBC8F':'Dark Sea Green','#483D8B':'Dark Slate Blue',
+ '#2F4F4F':'Dark Slate Gray','#2F4F4F':'Dark Slate Grey','#00CED1':'Dark Turquoise','#9400D3':'Dark Violet','#FF1493':'Deep Pink','#00BFFF':'Deep Sky Blue',
+ '#696969':'Dim Gray','#696969':'Dim Grey','#1E90FF':'Dodger Blue','#B22222':'Fire Brick','#FFFAF0':'Floral White','#228B22':'Forest Green',
+ '#FF00FF':'Fuchsia','#DCDCDC':'Gainsboro','#F8F8FF':'Ghost White','#FFD700':'Gold','#DAA520':'Golden Rod','#808080':'Gray','#808080':'Grey',
+ '#008000':'Green','#ADFF2F':'Green Yellow','#F0FFF0':'Honey Dew','#FF69B4':'Hot Pink','#CD5C5C':'Indian Red','#4B0082':'Indigo','#FFFFF0':'Ivory',
+ '#F0E68C':'Khaki','#E6E6FA':'Lavender','#FFF0F5':'Lavender Blush','#7CFC00':'Lawn Green','#FFFACD':'Lemon Chiffon','#ADD8E6':'Light Blue',
+ '#F08080':'Light Coral','#E0FFFF':'Light Cyan','#FAFAD2':'Light Golden Rod Yellow','#D3D3D3':'Light Gray','#D3D3D3':'Light Grey','#90EE90':'Light Green',
+ '#FFB6C1':'Light Pink','#FFA07A':'Light Salmon','#20B2AA':'Light Sea Green','#87CEFA':'Light Sky Blue','#778899':'Light Slate Gray','#778899':'Light Slate Grey',
+ '#B0C4DE':'Light Steel Blue','#FFFFE0':'Light Yellow','#00FF00':'Lime','#32CD32':'Lime Green','#FAF0E6':'Linen','#FF00FF':'Magenta','#800000':'Maroon',
+ '#66CDAA':'Medium Aqua Marine','#0000CD':'Medium Blue','#BA55D3':'Medium Orchid','#9370D8':'Medium Purple','#3CB371':'Medium Sea Green','#7B68EE':'Medium Slate Blue',
+ '#00FA9A':'Medium Spring Green','#48D1CC':'Medium Turquoise','#C71585':'Medium Violet Red','#191970':'Midnight Blue','#F5FFFA':'Mint Cream','#FFE4E1':'Misty Rose','#FFE4B5':'Moccasin',
+ '#FFDEAD':'Navajo White','#000080':'Navy','#FDF5E6':'Old Lace','#808000':'Olive','#6B8E23':'Olive Drab','#FFA500':'Orange','#FF4500':'Orange Red','#DA70D6':'Orchid',
+ '#EEE8AA':'Pale Golden Rod','#98FB98':'Pale Green','#AFEEEE':'Pale Turquoise','#D87093':'Pale Violet Red','#FFEFD5':'Papaya Whip','#FFDAB9':'Peach Puff',
+ '#CD853F':'Peru','#FFC0CB':'Pink','#DDA0DD':'Plum','#B0E0E6':'Powder Blue','#800080':'Purple','#FF0000':'Red','#BC8F8F':'Rosy Brown','#4169E1':'Royal Blue',
+ '#8B4513':'Saddle Brown','#FA8072':'Salmon','#F4A460':'Sandy Brown','#2E8B57':'Sea Green','#FFF5EE':'Sea Shell','#A0522D':'Sienna','#C0C0C0':'Silver',
+ '#87CEEB':'Sky Blue','#6A5ACD':'Slate Blue','#708090':'Slate Gray','#708090':'Slate Grey','#FFFAFA':'Snow','#00FF7F':'Spring Green',
+ '#4682B4':'Steel Blue','#D2B48C':'Tan','#008080':'Teal','#D8BFD8':'Thistle','#FF6347':'Tomato','#40E0D0':'Turquoise','#EE82EE':'Violet',
+ '#F5DEB3':'Wheat','#FFFFFF':'White','#F5F5F5':'White Smoke','#FFFF00':'Yellow','#9ACD32':'Yellow Green'
+};
+
+var namedLookup = {};
+
+function init() {
+ var inputColor = convertRGBToHex(tinyMCEPopup.getWindowArg('input_color')), key, value;
+
+ tinyMCEPopup.resizeToInnerSize();
+
+ generatePicker();
+ generateWebColors();
+ generateNamedColors();
+
+ if (inputColor) {
+ changeFinalColor(inputColor);
+
+ col = convertHexToRGB(inputColor);
+
+ if (col)
+ updateLight(col.r, col.g, col.b);
+ }
+
+ for (key in named) {
+ value = named[key];
+ namedLookup[value.replace(/\s+/, '').toLowerCase()] = key.replace(/#/, '').toLowerCase();
+ }
+}
+
+function toHexColor(color) {
+ var matches, red, green, blue, toInt = parseInt;
+
+ function hex(value) {
+ value = parseInt(value).toString(16);
+
+ return value.length > 1 ? value : '0' + value; // Padd with leading zero
+ };
+
+ color = tinymce.trim(color);
+ color = color.replace(/^[#]/, '').toLowerCase(); // remove leading '#'
+ color = namedLookup[color] || color;
+
+ matches = /^rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)$/.exec(color);
+
+ if (matches) {
+ red = toInt(matches[1]);
+ green = toInt(matches[2]);
+ blue = toInt(matches[3]);
+ } else {
+ matches = /^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/.exec(color);
+
+ if (matches) {
+ red = toInt(matches[1], 16);
+ green = toInt(matches[2], 16);
+ blue = toInt(matches[3], 16);
+ } else {
+ matches = /^([0-9a-f])([0-9a-f])([0-9a-f])$/.exec(color);
+
+ if (matches) {
+ red = toInt(matches[1] + matches[1], 16);
+ green = toInt(matches[2] + matches[2], 16);
+ blue = toInt(matches[3] + matches[3], 16);
+ } else {
+ return '';
+ }
+ }
+ }
+
+ return '#' + hex(red) + hex(green) + hex(blue);
+}
+
+function insertAction() {
+ var color = document.getElementById("color").value, f = tinyMCEPopup.getWindowArg('func');
+
+ var hexColor = toHexColor(color);
+
+ if (hexColor === '') {
+ var text = tinyMCEPopup.editor.getLang('advanced_dlg.invalid_color_value');
+ tinyMCEPopup.alert(text + ': ' + color);
+ }
+ else {
+ tinyMCEPopup.restoreSelection();
+
+ if (f)
+ f(hexColor);
+
+ tinyMCEPopup.close();
+ }
+}
+
+function showColor(color, name) {
+ if (name)
+ document.getElementById("colorname").innerHTML = name;
+
+ document.getElementById("preview").style.backgroundColor = color;
+ document.getElementById("color").value = color.toUpperCase();
+}
+
+function convertRGBToHex(col) {
+ var re = new RegExp("rgb\\s*\\(\\s*([0-9]+).*,\\s*([0-9]+).*,\\s*([0-9]+).*\\)", "gi");
+
+ if (!col)
+ return col;
+
+ var rgb = col.replace(re, "$1,$2,$3").split(',');
+ if (rgb.length == 3) {
+ r = parseInt(rgb[0]).toString(16);
+ g = parseInt(rgb[1]).toString(16);
+ b = parseInt(rgb[2]).toString(16);
+
+ r = r.length == 1 ? '0' + r : r;
+ g = g.length == 1 ? '0' + g : g;
+ b = b.length == 1 ? '0' + b : b;
+
+ return "#" + r + g + b;
+ }
+
+ return col;
+}
+
+function convertHexToRGB(col) {
+ if (col.indexOf('#') != -1) {
+ col = col.replace(new RegExp('[^0-9A-F]', 'gi'), '');
+
+ r = parseInt(col.substring(0, 2), 16);
+ g = parseInt(col.substring(2, 4), 16);
+ b = parseInt(col.substring(4, 6), 16);
+
+ return {r : r, g : g, b : b};
+ }
+
+ return null;
+}
+
+function generatePicker() {
+ var el = document.getElementById('light'), h = '', i;
+
+ for (i = 0; i < detail; i++){
+ h += '<div id="gs'+i+'" style="background-color:#000000; width:15px; height:3px; border-style:none; border-width:0px;"'
+ + ' onclick="changeFinalColor(this.style.backgroundColor)"'
+ + ' onmousedown="isMouseDown = true; return false;"'
+ + ' onmouseup="isMouseDown = false;"'
+ + ' onmousemove="if (isMouseDown && isMouseOver) changeFinalColor(this.style.backgroundColor); return false;"'
+ + ' onmouseover="isMouseOver = true;"'
+ + ' onmouseout="isMouseOver = false;"'
+ + '></div>';
+ }
+
+ el.innerHTML = h;
+}
+
+function generateWebColors() {
+ var el = document.getElementById('webcolors'), h = '', i;
+
+ if (el.className == 'generated')
+ return;
+
+ // TODO: VoiceOver doesn't seem to support legend as a label referenced by labelledby.
+ h += '<div role="listbox" aria-labelledby="webcolors_title" tabindex="0"><table role="presentation" border="0" cellspacing="1" cellpadding="0">'
+ + '<tr>';
+
+ for (i=0; i<colors.length; i++) {
+ h += '<td bgcolor="' + colors[i] + '" width="10" height="10">'
+ + '<a href="javascript:insertAction();" role="option" tabindex="-1" aria-labelledby="web_colors_' + i + '" onfocus="showColor(\'' + colors[i] + '\');" onmouseover="showColor(\'' + colors[i] + '\');" style="display:block;width:10px;height:10px;overflow:hidden;">';
+ if (tinyMCEPopup.editor.forcedHighContrastMode) {
+ h += '<canvas class="mceColorSwatch" height="10" width="10" data-color="' + colors[i] + '"></canvas>';
+ }
+ h += '<span class="mceVoiceLabel" style="display:none;" id="web_colors_' + i + '">' + colors[i].toUpperCase() + '</span>';
+ h += '</a></td>';
+ if ((i+1) % 18 == 0)
+ h += '</tr><tr>';
+ }
+
+ h += '</table></div>';
+
+ el.innerHTML = h;
+ el.className = 'generated';
+
+ paintCanvas(el);
+ enableKeyboardNavigation(el.firstChild);
+}
+
+function paintCanvas(el) {
+ tinyMCEPopup.getWin().tinymce.each(tinyMCEPopup.dom.select('canvas.mceColorSwatch', el), function(canvas) {
+ var context;
+ if (canvas.getContext && (context = canvas.getContext("2d"))) {
+ context.fillStyle = canvas.getAttribute('data-color');
+ context.fillRect(0, 0, 10, 10);
+ }
+ });
+}
+function generateNamedColors() {
+ var el = document.getElementById('namedcolors'), h = '', n, v, i = 0;
+
+ if (el.className == 'generated')
+ return;
+
+ for (n in named) {
+ v = named[n];
+ h += '<a href="javascript:insertAction();" role="option" tabindex="-1" aria-labelledby="named_colors_' + i + '" onfocus="showColor(\'' + n + '\',\'' + v + '\');" onmouseover="showColor(\'' + n + '\',\'' + v + '\');" style="background-color: ' + n + '">';
+ if (tinyMCEPopup.editor.forcedHighContrastMode) {
+ h += '<canvas class="mceColorSwatch" height="10" width="10" data-color="' + colors[i] + '"></canvas>';
+ }
+ h += '<span class="mceVoiceLabel" style="display:none;" id="named_colors_' + i + '">' + v + '</span>';
+ h += '</a>';
+ i++;
+ }
+
+ el.innerHTML = h;
+ el.className = 'generated';
+
+ paintCanvas(el);
+ enableKeyboardNavigation(el);
+}
+
+function enableKeyboardNavigation(el) {
+ tinyMCEPopup.editor.windowManager.createInstance('tinymce.ui.KeyboardNavigation', {
+ root: el,
+ items: tinyMCEPopup.dom.select('a', el)
+ }, tinyMCEPopup.dom);
+}
+
+function dechex(n) {
+ return strhex.charAt(Math.floor(n / 16)) + strhex.charAt(n % 16);
+}
+
+function computeColor(e) {
+ var x, y, partWidth, partDetail, imHeight, r, g, b, coef, i, finalCoef, finalR, finalG, finalB, pos = tinyMCEPopup.dom.getPos(e.target);
+
+ x = e.offsetX ? e.offsetX : (e.target ? e.clientX - pos.x : 0);
+ y = e.offsetY ? e.offsetY : (e.target ? e.clientY - pos.y : 0);
+
+ partWidth = document.getElementById('colors').width / 6;
+ partDetail = detail / 2;
+ imHeight = document.getElementById('colors').height;
+
+ r = (x >= 0)*(x < partWidth)*255 + (x >= partWidth)*(x < 2*partWidth)*(2*255 - x * 255 / partWidth) + (x >= 4*partWidth)*(x < 5*partWidth)*(-4*255 + x * 255 / partWidth) + (x >= 5*partWidth)*(x < 6*partWidth)*255;
+ g = (x >= 0)*(x < partWidth)*(x * 255 / partWidth) + (x >= partWidth)*(x < 3*partWidth)*255 + (x >= 3*partWidth)*(x < 4*partWidth)*(4*255 - x * 255 / partWidth);
+ b = (x >= 2*partWidth)*(x < 3*partWidth)*(-2*255 + x * 255 / partWidth) + (x >= 3*partWidth)*(x < 5*partWidth)*255 + (x >= 5*partWidth)*(x < 6*partWidth)*(6*255 - x * 255 / partWidth);
+
+ coef = (imHeight - y) / imHeight;
+ r = 128 + (r - 128) * coef;
+ g = 128 + (g - 128) * coef;
+ b = 128 + (b - 128) * coef;
+
+ changeFinalColor('#' + dechex(r) + dechex(g) + dechex(b));
+ updateLight(r, g, b);
+}
+
+function updateLight(r, g, b) {
+ var i, partDetail = detail / 2, finalCoef, finalR, finalG, finalB, color;
+
+ for (i=0; i<detail; i++) {
+ if ((i>=0) && (i<partDetail)) {
+ finalCoef = i / partDetail;
+ finalR = dechex(255 - (255 - r) * finalCoef);
+ finalG = dechex(255 - (255 - g) * finalCoef);
+ finalB = dechex(255 - (255 - b) * finalCoef);
+ } else {
+ finalCoef = 2 - i / partDetail;
+ finalR = dechex(r * finalCoef);
+ finalG = dechex(g * finalCoef);
+ finalB = dechex(b * finalCoef);
+ }
+
+ color = finalR + finalG + finalB;
+
+ setCol('gs' + i, '#'+color);
+ }
+}
+
+function changeFinalColor(color) {
+ if (color.indexOf('#') == -1)
+ color = convertRGBToHex(color);
+
+ setCol('preview', color);
+ document.getElementById('color').value = color;
+}
+
+function setCol(e, c) {
+ try {
+ document.getElementById(e).style.backgroundColor = c;
+ } catch (ex) {
+ // Ignore IE warning
+ }
+}
+
+tinyMCEPopup.onInit.add(init);
diff --git a/askbot/media/js/tinymce/themes/advanced/js/image.js b/askbot/media/js/tinymce/themes/advanced/js/image.js
new file mode 100644
index 00000000..bb09e75b
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/js/image.js
@@ -0,0 +1,253 @@
+var ImageDialog = {
+ preInit : function() {
+ var url;
+
+ tinyMCEPopup.requireLangPack();
+
+ if (url = tinyMCEPopup.getParam("external_image_list_url"))
+ document.write('<script language="javascript" type="text/javascript" src="' + tinyMCEPopup.editor.documentBaseURI.toAbsolute(url) + '"></script>');
+ },
+
+ init : function() {
+ var f = document.forms[0], ed = tinyMCEPopup.editor;
+
+ // Setup browse button
+ document.getElementById('srcbrowsercontainer').innerHTML = getBrowserHTML('srcbrowser','src','image','theme_advanced_image');
+ if (isVisible('srcbrowser'))
+ document.getElementById('src').style.width = '180px';
+
+ e = ed.selection.getNode();
+
+ this.fillFileList('image_list', tinyMCEPopup.getParam('external_image_list', 'tinyMCEImageList'));
+
+ if (e.nodeName == 'IMG') {
+ f.src.value = ed.dom.getAttrib(e, 'src');
+ f.alt.value = ed.dom.getAttrib(e, 'alt');
+ f.border.value = this.getAttrib(e, 'border');
+ f.vspace.value = this.getAttrib(e, 'vspace');
+ f.hspace.value = this.getAttrib(e, 'hspace');
+ f.width.value = ed.dom.getAttrib(e, 'width');
+ f.height.value = ed.dom.getAttrib(e, 'height');
+ f.insert.value = ed.getLang('update');
+ this.styleVal = ed.dom.getAttrib(e, 'style');
+ selectByValue(f, 'image_list', f.src.value);
+ selectByValue(f, 'align', this.getAttrib(e, 'align'));
+ this.updateStyle();
+ }
+ },
+
+ fillFileList : function(id, l) {
+ var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl;
+
+ l = typeof(l) === 'function' ? l() : window[l];
+
+ if (l && l.length > 0) {
+ lst.options[lst.options.length] = new Option('', '');
+
+ tinymce.each(l, function(o) {
+ lst.options[lst.options.length] = new Option(o[0], o[1]);
+ });
+ } else
+ dom.remove(dom.getParent(id, 'tr'));
+ },
+
+ update : function() {
+ var f = document.forms[0], nl = f.elements, ed = tinyMCEPopup.editor, args = {}, el;
+
+ tinyMCEPopup.restoreSelection();
+
+ if (f.src.value === '') {
+ if (ed.selection.getNode().nodeName == 'IMG') {
+ ed.dom.remove(ed.selection.getNode());
+ ed.execCommand('mceRepaint');
+ }
+
+ tinyMCEPopup.close();
+ return;
+ }
+
+ if (!ed.settings.inline_styles) {
+ args = tinymce.extend(args, {
+ vspace : nl.vspace.value,
+ hspace : nl.hspace.value,
+ border : nl.border.value,
+ align : getSelectValue(f, 'align')
+ });
+ } else
+ args.style = this.styleVal;
+
+ tinymce.extend(args, {
+ src : f.src.value.replace(/ /g, '%20'),
+ alt : f.alt.value,
+ width : f.width.value,
+ height : f.height.value
+ });
+
+ el = ed.selection.getNode();
+
+ if (el && el.nodeName == 'IMG') {
+ ed.dom.setAttribs(el, args);
+ tinyMCEPopup.editor.execCommand('mceRepaint');
+ tinyMCEPopup.editor.focus();
+ } else {
+ tinymce.each(args, function(value, name) {
+ if (value === "") {
+ delete args[name];
+ }
+ });
+
+ ed.execCommand('mceInsertContent', false, tinyMCEPopup.editor.dom.createHTML('img', args), {skip_undo : 1});
+ ed.undoManager.add();
+ }
+
+ tinyMCEPopup.close();
+ },
+
+ updateStyle : function() {
+ var dom = tinyMCEPopup.dom, st = {}, v, f = document.forms[0];
+
+ if (tinyMCEPopup.editor.settings.inline_styles) {
+ tinymce.each(tinyMCEPopup.dom.parseStyle(this.styleVal), function(value, key) {
+ st[key] = value;
+ });
+
+ // Handle align
+ v = getSelectValue(f, 'align');
+ if (v) {
+ if (v == 'left' || v == 'right') {
+ st['float'] = v;
+ delete st['vertical-align'];
+ } else {
+ st['vertical-align'] = v;
+ delete st['float'];
+ }
+ } else {
+ delete st['float'];
+ delete st['vertical-align'];
+ }
+
+ // Handle border
+ v = f.border.value;
+ if (v || v == '0') {
+ if (v == '0')
+ st['border'] = '0';
+ else
+ st['border'] = v + 'px solid black';
+ } else
+ delete st['border'];
+
+ // Handle hspace
+ v = f.hspace.value;
+ if (v) {
+ delete st['margin'];
+ st['margin-left'] = v + 'px';
+ st['margin-right'] = v + 'px';
+ } else {
+ delete st['margin-left'];
+ delete st['margin-right'];
+ }
+
+ // Handle vspace
+ v = f.vspace.value;
+ if (v) {
+ delete st['margin'];
+ st['margin-top'] = v + 'px';
+ st['margin-bottom'] = v + 'px';
+ } else {
+ delete st['margin-top'];
+ delete st['margin-bottom'];
+ }
+
+ // Merge
+ st = tinyMCEPopup.dom.parseStyle(dom.serializeStyle(st), 'img');
+ this.styleVal = dom.serializeStyle(st, 'img');
+ }
+ },
+
+ getAttrib : function(e, at) {
+ var ed = tinyMCEPopup.editor, dom = ed.dom, v, v2;
+
+ if (ed.settings.inline_styles) {
+ switch (at) {
+ case 'align':
+ if (v = dom.getStyle(e, 'float'))
+ return v;
+
+ if (v = dom.getStyle(e, 'vertical-align'))
+ return v;
+
+ break;
+
+ case 'hspace':
+ v = dom.getStyle(e, 'margin-left')
+ v2 = dom.getStyle(e, 'margin-right');
+ if (v && v == v2)
+ return parseInt(v.replace(/[^0-9]/g, ''));
+
+ break;
+
+ case 'vspace':
+ v = dom.getStyle(e, 'margin-top')
+ v2 = dom.getStyle(e, 'margin-bottom');
+ if (v && v == v2)
+ return parseInt(v.replace(/[^0-9]/g, ''));
+
+ break;
+
+ case 'border':
+ v = 0;
+
+ tinymce.each(['top', 'right', 'bottom', 'left'], function(sv) {
+ sv = dom.getStyle(e, 'border-' + sv + '-width');
+
+ // False or not the same as prev
+ if (!sv || (sv != v && v !== 0)) {
+ v = 0;
+ return false;
+ }
+
+ if (sv)
+ v = sv;
+ });
+
+ if (v)
+ return parseInt(v.replace(/[^0-9]/g, ''));
+
+ break;
+ }
+ }
+
+ if (v = dom.getAttrib(e, at))
+ return v;
+
+ return '';
+ },
+
+ resetImageData : function() {
+ var f = document.forms[0];
+
+ f.width.value = f.height.value = "";
+ },
+
+ updateImageData : function() {
+ var f = document.forms[0], t = ImageDialog;
+
+ if (f.width.value == "")
+ f.width.value = t.preloadImg.width;
+
+ if (f.height.value == "")
+ f.height.value = t.preloadImg.height;
+ },
+
+ getImageData : function() {
+ var f = document.forms[0];
+
+ this.preloadImg = new Image();
+ this.preloadImg.onload = this.updateImageData;
+ this.preloadImg.onerror = this.resetImageData;
+ this.preloadImg.src = tinyMCEPopup.editor.documentBaseURI.toAbsolute(f.src.value);
+ }
+};
+
+ImageDialog.preInit();
+tinyMCEPopup.onInit.add(ImageDialog.init, ImageDialog);
diff --git a/askbot/media/js/tinymce/themes/advanced/js/link.js b/askbot/media/js/tinymce/themes/advanced/js/link.js
new file mode 100644
index 00000000..8c1d73c5
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/js/link.js
@@ -0,0 +1,159 @@
+tinyMCEPopup.requireLangPack();
+
+var LinkDialog = {
+ preInit : function() {
+ var url;
+
+ if (url = tinyMCEPopup.getParam("external_link_list_url"))
+ document.write('<script language="javascript" type="text/javascript" src="' + tinyMCEPopup.editor.documentBaseURI.toAbsolute(url) + '"></script>');
+ },
+
+ init : function() {
+ var f = document.forms[0], ed = tinyMCEPopup.editor;
+
+ // Setup browse button
+ document.getElementById('hrefbrowsercontainer').innerHTML = getBrowserHTML('hrefbrowser', 'href', 'file', 'theme_advanced_link');
+ if (isVisible('hrefbrowser'))
+ document.getElementById('href').style.width = '180px';
+
+ this.fillClassList('class_list');
+ this.fillFileList('link_list', 'tinyMCELinkList');
+ this.fillTargetList('target_list');
+
+ if (e = ed.dom.getParent(ed.selection.getNode(), 'A')) {
+ f.href.value = ed.dom.getAttrib(e, 'href');
+ f.linktitle.value = ed.dom.getAttrib(e, 'title');
+ f.insert.value = ed.getLang('update');
+ selectByValue(f, 'link_list', f.href.value);
+ selectByValue(f, 'target_list', ed.dom.getAttrib(e, 'target'));
+ selectByValue(f, 'class_list', ed.dom.getAttrib(e, 'class'));
+ }
+ },
+
+ update : function() {
+ var f = document.forms[0], ed = tinyMCEPopup.editor, e, b, href = f.href.value.replace(/ /g, '%20');
+
+ tinyMCEPopup.restoreSelection();
+ e = ed.dom.getParent(ed.selection.getNode(), 'A');
+
+ // Remove element if there is no href
+ if (!f.href.value) {
+ if (e) {
+ b = ed.selection.getBookmark();
+ ed.dom.remove(e, 1);
+ ed.selection.moveToBookmark(b);
+ tinyMCEPopup.execCommand("mceEndUndoLevel");
+ tinyMCEPopup.close();
+ return;
+ }
+ }
+
+ // Create new anchor elements
+ if (e == null) {
+ ed.getDoc().execCommand("unlink", false, null);
+ tinyMCEPopup.execCommand("mceInsertLink", false, "#mce_temp_url#", {skip_undo : 1});
+
+ tinymce.each(ed.dom.select("a"), function(n) {
+ if (ed.dom.getAttrib(n, 'href') == '#mce_temp_url#') {
+ e = n;
+
+ ed.dom.setAttribs(e, {
+ href : href,
+ title : f.linktitle.value,
+ target : f.target_list ? getSelectValue(f, "target_list") : null,
+ 'class' : f.class_list ? getSelectValue(f, "class_list") : null
+ });
+ }
+ });
+ } else {
+ ed.dom.setAttribs(e, {
+ href : href,
+ title : f.linktitle.value
+ });
+
+ if (f.target_list) {
+ ed.dom.setAttrib(e, 'target', getSelectValue(f, "target_list"));
+ }
+
+ if (f.class_list) {
+ ed.dom.setAttrib(e, 'class', getSelectValue(f, "class_list"));
+ }
+ }
+
+ // Don't move caret if selection was image
+ if (e.childNodes.length != 1 || e.firstChild.nodeName != 'IMG') {
+ ed.focus();
+ ed.selection.select(e);
+ ed.selection.collapse(0);
+ tinyMCEPopup.storeSelection();
+ }
+
+ tinyMCEPopup.execCommand("mceEndUndoLevel");
+ tinyMCEPopup.close();
+ },
+
+ checkPrefix : function(n) {
+ if (n.value && Validator.isEmail(n) && !/^\s*mailto:/i.test(n.value) && confirm(tinyMCEPopup.getLang('advanced_dlg.link_is_email')))
+ n.value = 'mailto:' + n.value;
+
+ if (/^\s*www\./i.test(n.value) && confirm(tinyMCEPopup.getLang('advanced_dlg.link_is_external')))
+ n.value = 'http://' + n.value;
+ },
+
+ fillFileList : function(id, l) {
+ var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl;
+
+ l = window[l];
+
+ if (l && l.length > 0) {
+ lst.options[lst.options.length] = new Option('', '');
+
+ tinymce.each(l, function(o) {
+ lst.options[lst.options.length] = new Option(o[0], o[1]);
+ });
+ } else
+ dom.remove(dom.getParent(id, 'tr'));
+ },
+
+ fillClassList : function(id) {
+ var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl;
+
+ if (v = tinyMCEPopup.getParam('theme_advanced_styles')) {
+ cl = [];
+
+ tinymce.each(v.split(';'), function(v) {
+ var p = v.split('=');
+
+ cl.push({'title' : p[0], 'class' : p[1]});
+ });
+ } else
+ cl = tinyMCEPopup.editor.dom.getClasses();
+
+ if (cl.length > 0) {
+ lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('not_set'), '');
+
+ tinymce.each(cl, function(o) {
+ lst.options[lst.options.length] = new Option(o.title || o['class'], o['class']);
+ });
+ } else
+ dom.remove(dom.getParent(id, 'tr'));
+ },
+
+ fillTargetList : function(id) {
+ var dom = tinyMCEPopup.dom, lst = dom.get(id), v;
+
+ lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('not_set'), '');
+ lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('advanced_dlg.link_target_same'), '_self');
+ lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('advanced_dlg.link_target_blank'), '_blank');
+
+ if (v = tinyMCEPopup.getParam('theme_advanced_link_targets')) {
+ tinymce.each(v.split(','), function(v) {
+ v = v.split('=');
+ lst.options[lst.options.length] = new Option(v[0], v[1]);
+ });
+ }
+ }
+};
+
+LinkDialog.preInit();
+tinyMCEPopup.onInit.add(LinkDialog.init, LinkDialog);
diff --git a/askbot/media/js/tinymce/themes/advanced/js/source_editor.js b/askbot/media/js/tinymce/themes/advanced/js/source_editor.js
new file mode 100644
index 00000000..dd5e366f
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/js/source_editor.js
@@ -0,0 +1,78 @@
+tinyMCEPopup.requireLangPack();
+tinyMCEPopup.onInit.add(onLoadInit);
+
+function saveContent() {
+ tinyMCEPopup.editor.setContent(document.getElementById('htmlSource').value, {source_view : true});
+ tinyMCEPopup.close();
+}
+
+function onLoadInit() {
+ tinyMCEPopup.resizeToInnerSize();
+
+ // Remove Gecko spellchecking
+ if (tinymce.isGecko)
+ document.body.spellcheck = tinyMCEPopup.editor.getParam("gecko_spellcheck");
+
+ document.getElementById('htmlSource').value = tinyMCEPopup.editor.getContent({source_view : true});
+
+ if (tinyMCEPopup.editor.getParam("theme_advanced_source_editor_wrap", true)) {
+ turnWrapOn();
+ document.getElementById('wraped').checked = true;
+ }
+
+ resizeInputs();
+}
+
+function setWrap(val) {
+ var v, n, s = document.getElementById('htmlSource');
+
+ s.wrap = val;
+
+ if (!tinymce.isIE) {
+ v = s.value;
+ n = s.cloneNode(false);
+ n.setAttribute("wrap", val);
+ s.parentNode.replaceChild(n, s);
+ n.value = v;
+ }
+}
+
+function setWhiteSpaceCss(value) {
+ var el = document.getElementById('htmlSource');
+ tinymce.DOM.setStyle(el, 'white-space', value);
+}
+
+function turnWrapOff() {
+ if (tinymce.isWebKit) {
+ setWhiteSpaceCss('pre');
+ } else {
+ setWrap('off');
+ }
+}
+
+function turnWrapOn() {
+ if (tinymce.isWebKit) {
+ setWhiteSpaceCss('pre-wrap');
+ } else {
+ setWrap('soft');
+ }
+}
+
+function toggleWordWrap(elm) {
+ if (elm.checked) {
+ turnWrapOn();
+ } else {
+ turnWrapOff();
+ }
+}
+
+function resizeInputs() {
+ var vp = tinyMCEPopup.dom.getViewPort(window), el;
+
+ el = document.getElementById('htmlSource');
+
+ if (el) {
+ el.style.width = (vp.w - 20) + 'px';
+ el.style.height = (vp.h - 65) + 'px';
+ }
+}
diff --git a/askbot/media/js/tinymce/themes/advanced/langs/en.js b/askbot/media/js/tinymce/themes/advanced/langs/en.js
new file mode 100644
index 00000000..6e584818
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/langs/en.js
@@ -0,0 +1 @@
+tinyMCE.addI18n('en.advanced',{"underline_desc":"Underline (Ctrl+U)","italic_desc":"Italic (Ctrl+I)","bold_desc":"Bold (Ctrl+B)",dd:"Definition Description",dt:"Definition Term ",samp:"Code Sample",code:"Code",blockquote:"Block Quote",h6:"Heading 6",h5:"Heading 5",h4:"Heading 4",h3:"Heading 3",h2:"Heading 2",h1:"Heading 1",pre:"Preformatted",address:"Address",div:"DIV",paragraph:"Paragraph",block:"Format",fontdefault:"Font Family","font_size":"Font Size","style_select":"Styles","anchor_delta_height":"","anchor_delta_width":"","charmap_delta_height":"","charmap_delta_width":"","colorpicker_delta_height":"","colorpicker_delta_width":"","link_delta_height":"","link_delta_width":"","image_delta_height":"","image_delta_width":"","more_colors":"More Colors...","toolbar_focus":"Jump to tool buttons - Alt+Q, Jump to editor - Alt-Z, Jump to element path - Alt-X",newdocument:"Are you sure you want clear all contents?",path:"Path","clipboard_msg":"Copy/Cut/Paste is not available in Mozilla and Firefox.\nDo you want more information about this issue?","blockquote_desc":"Block Quote","help_desc":"Help","newdocument_desc":"New Document","image_props_desc":"Image Properties","paste_desc":"Paste (Ctrl+V)","copy_desc":"Copy (Ctrl+C)","cut_desc":"Cut (Ctrl+X)","anchor_desc":"Insert/Edit Anchor","visualaid_desc":"show/Hide Guidelines/Invisible Elements","charmap_desc":"Insert Special Character","backcolor_desc":"Select Background Color","forecolor_desc":"Select Text Color","custom1_desc":"Your Custom Description Here","removeformat_desc":"Remove Formatting","hr_desc":"Insert Horizontal Line","sup_desc":"Superscript","sub_desc":"Subscript","code_desc":"Edit HTML Source","cleanup_desc":"Cleanup Messy Code","image_desc":"Insert/Edit Image","unlink_desc":"Unlink","link_desc":"Insert/Edit Link","redo_desc":"Redo (Ctrl+Y)","undo_desc":"Undo (Ctrl+Z)","indent_desc":"Increase Indent","outdent_desc":"Decrease Indent","numlist_desc":"Insert/Remove Numbered List","bullist_desc":"Insert/Remove Bulleted List","justifyfull_desc":"Align Full","justifyright_desc":"Align Right","justifycenter_desc":"Align Center","justifyleft_desc":"Align Left","striketrough_desc":"Strikethrough","help_shortcut":"Press ALT-F10 for toolbar. Press ALT-0 for help","rich_text_area":"Rich Text Area","shortcuts_desc":"Accessability Help",toolbar:"Toolbar"}); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/themes/advanced/langs/en_dlg.js b/askbot/media/js/tinymce/themes/advanced/langs/en_dlg.js
new file mode 100644
index 00000000..50cd87e3
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/langs/en_dlg.js
@@ -0,0 +1 @@
+tinyMCE.addI18n('en.advanced_dlg', {"link_list":"Link List","link_is_external":"The URL you entered seems to be an external link. Do you want to add the required http:// prefix?","link_is_email":"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?","link_titlefield":"Title","link_target_blank":"Open Link in a New Window","link_target_same":"Open Link in the Same Window","link_target":"Target","link_url":"Link URL","link_title":"Insert/Edit Link","image_align_right":"Right","image_align_left":"Left","image_align_textbottom":"Text Bottom","image_align_texttop":"Text Top","image_align_bottom":"Bottom","image_align_middle":"Middle","image_align_top":"Top","image_align_baseline":"Baseline","image_align":"Alignment","image_hspace":"Horizontal Space","image_vspace":"Vertical Space","image_dimensions":"Dimensions","image_alt":"Image Description","image_list":"Image List","image_border":"Border","image_src":"Image URL","image_title":"Insert/Edit Image","charmap_title":"Select Special Character", "charmap_usage":"Use left and right arrows to navigate.","colorpicker_name":"Name:","colorpicker_color":"Color:","colorpicker_named_title":"Named Colors","colorpicker_named_tab":"Named","colorpicker_palette_title":"Palette Colors","colorpicker_palette_tab":"Palette","colorpicker_picker_title":"Color Picker","colorpicker_picker_tab":"Picker","colorpicker_title":"Select a Color","code_wordwrap":"Word Wrap","code_title":"HTML Source Editor","anchor_name":"Anchor Name","anchor_title":"Insert/Edit Anchor","about_loaded":"Loaded Plugins","about_version":"Version","about_author":"Author","about_plugin":"Plugin","about_plugins":"Plugins","about_license":"License","about_help":"Help","about_general":"About","about_title":"About TinyMCE","anchor_invalid":"Please specify a valid anchor name.","accessibility_help":"Accessibility Help","accessibility_usage_title":"General Usage","invalid_color_value":"Invalid color value","":""});
diff --git a/askbot/media/js/tinymce/themes/advanced/link.htm b/askbot/media/js/tinymce/themes/advanced/link.htm
new file mode 100644
index 00000000..5d9dea9b
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/link.htm
@@ -0,0 +1,57 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#advanced_dlg.link_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="../../utils/mctabs.js"></script>
+ <script type="text/javascript" src="../../utils/form_utils.js"></script>
+ <script type="text/javascript" src="../../utils/validate.js"></script>
+ <script type="text/javascript" src="js/link.js"></script>
+</head>
+<body id="link" style="display: none">
+<form onsubmit="LinkDialog.update();return false;" action="#">
+ <div class="tabs">
+ <ul>
+ <li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#advanced_dlg.link_title}</a></span></li>
+ </ul>
+ </div>
+
+ <div class="panel_wrapper">
+ <div id="general_panel" class="panel current">
+ <table border="0" cellpadding="4" cellspacing="0">
+ <tr>
+ <td class="nowrap"><label for="href">{#advanced_dlg.link_url}</label></td>
+ <td><table border="0" cellspacing="0" cellpadding="0">
+ <tr>
+ <td><input id="href" name="href" type="text" class="mceFocus" value="" style="width: 200px" onchange="LinkDialog.checkPrefix(this);" /></td>
+ <td id="hrefbrowsercontainer">&nbsp;</td>
+ </tr>
+ </table></td>
+ </tr>
+ <tr>
+ <td><label for="link_list">{#advanced_dlg.link_list}</label></td>
+ <td><select id="link_list" name="link_list" onchange="document.getElementById('href').value=this.options[this.selectedIndex].value;"></select></td>
+ </tr>
+ <tr>
+ <td><label id="targetlistlabel" for="targetlist">{#advanced_dlg.link_target}</label></td>
+ <td><select id="target_list" name="target_list"></select></td>
+ </tr>
+ <tr>
+ <td class="nowrap"><label for="linktitle">{#advanced_dlg.link_titlefield}</label></td>
+ <td><input id="linktitle" name="linktitle" type="text" value="" style="width: 200px" /></td>
+ </tr>
+ <tr>
+ <td><label for="class_list">{#class_name}</label></td>
+ <td><select id="class_list" name="class_list"></select></td>
+ </tr>
+ </table>
+ </div>
+ </div>
+
+ <div class="mceActionPanel">
+ <input type="submit" id="insert" name="insert" value="{#insert}" />
+ <input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
+ </div>
+</form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/themes/advanced/shortcuts.htm b/askbot/media/js/tinymce/themes/advanced/shortcuts.htm
new file mode 100644
index 00000000..20ec2f5a
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/shortcuts.htm
@@ -0,0 +1,47 @@
+<!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">
+ <head>
+ <title>{#advanced_dlg.accessibility_help}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript">tinyMCEPopup.requireLangPack();</script>
+ </head>
+ <body id="content">
+ <h1>{#advanced_dlg.accessibility_usage_title}</h1>
+ <h2>Toolbars</h2>
+ <p>Press ALT-F10 to move focus to the toolbars. Navigate through the buttons using the arrow keys.
+ Press enter to activate a button and return focus to the editor.
+ Press escape to return focus to the editor without performing any actions.</p>
+
+ <h2>Status Bar</h2>
+ <p>To access the editor status bar, press ALT-F11. Use the left and right arrow keys to navigate between elements in the path.
+ Press enter or space to select an element. Press escape to return focus to the editor without changing the selection.</p>
+
+ <h2>Context Menu</h2>
+ <p>Press shift-F10 to activate the context menu. Use the up and down arrow keys to move between menu items. To open sub-menus press the right arrow key.
+ To close submenus press the left arrow key. Press escape to close the context menu.</p>
+
+ <h1>Keyboard Shortcuts</h1>
+ <table>
+ <thead>
+ <tr>
+ <th>Keystroke</th>
+ <th>Function</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Control-B</td><td>Bold</td>
+ </tr>
+ <tr>
+ <td>Control-I</td><td>Italic</td>
+ </tr>
+ <tr>
+ <td>Control-Z</td><td>Undo</td>
+ </tr>
+ <tr>
+ <td>Control-Y</td><td>Redo</td>
+ </tr>
+ </tbody>
+ </table>
+ </body>
+</html>
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/default/content.css b/askbot/media/js/tinymce/themes/advanced/skins/default/content.css
new file mode 100644
index 00000000..2fd94a1f
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/default/content.css
@@ -0,0 +1,50 @@
+body, td, pre {color:#000; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px; margin:8px;}
+body {background:#FFF;}
+body.mceForceColors {background:#FFF; color:#000;}
+body.mceBrowserDefaults {background:transparent; color:inherit; font-size:inherit; font-family:inherit;}
+h1 {font-size: 2em}
+h2 {font-size: 1.5em}
+h3 {font-size: 1.17em}
+h4 {font-size: 1em}
+h5 {font-size: .83em}
+h6 {font-size: .75em}
+.mceItemTable, .mceItemTable td, .mceItemTable th, .mceItemTable caption, .mceItemVisualAid {border: 1px dashed #BBB;}
+a.mceItemAnchor {display:inline-block; -webkit-user-select:all; -webkit-user-modify:read-only; -moz-user-select:all; -moz-user-modify:read-only; width:11px !important; height:11px !important; background:url(img/items.gif) no-repeat center center}
+span.mceItemNbsp {background: #DDD}
+td.mceSelected, th.mceSelected {background-color:#3399ff !important}
+img {border:0;}
+table, img, hr, .mceItemAnchor {cursor:default}
+table td, table th {cursor:text}
+ins {border-bottom:1px solid green; text-decoration: none; color:green}
+del {color:red; text-decoration:line-through}
+cite {border-bottom:1px dashed blue}
+acronym {border-bottom:1px dotted #CCC; cursor:help}
+abbr {border-bottom:1px dashed #CCC; cursor:help}
+
+/* IE */
+* html body {
+scrollbar-3dlight-color:#F0F0EE;
+scrollbar-arrow-color:#676662;
+scrollbar-base-color:#F0F0EE;
+scrollbar-darkshadow-color:#DDD;
+scrollbar-face-color:#E0E0DD;
+scrollbar-highlight-color:#F0F0EE;
+scrollbar-shadow-color:#F0F0EE;
+scrollbar-track-color:#F5F5F5;
+}
+
+img:-moz-broken {-moz-force-broken-image-icon:1; width:24px; height:24px}
+font[face=mceinline] {font-family:inherit !important}
+*[contentEditable]:focus {outline:0}
+
+.mceItemMedia {border:1px dotted #cc0000; background-position:center; background-repeat:no-repeat; background-color:#ffffcc}
+.mceItemShockWave {background-image:url(../../img/shockwave.gif)}
+.mceItemFlash {background-image:url(../../img/flash.gif)}
+.mceItemQuickTime {background-image:url(../../img/quicktime.gif)}
+.mceItemWindowsMedia {background-image:url(../../img/windowsmedia.gif)}
+.mceItemRealMedia {background-image:url(../../img/realmedia.gif)}
+.mceItemVideo {background-image:url(../../img/video.gif)}
+.mceItemAudio {background-image:url(../../img/video.gif)}
+.mceItemEmbeddedAudio {background-image:url(../../img/video.gif)}
+.mceItemIframe {background-image:url(../../img/iframe.gif)}
+.mcePageBreak {display:block;border:0;width:100%;height:12px;border-top:1px dotted #ccc;margin-top:15px;background:#fff url(../../img/pagebreak.gif) no-repeat center top;}
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/default/dialog.css b/askbot/media/js/tinymce/themes/advanced/skins/default/dialog.css
new file mode 100644
index 00000000..879786fc
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/default/dialog.css
@@ -0,0 +1,118 @@
+/* Generic */
+body {
+font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px;
+scrollbar-3dlight-color:#F0F0EE;
+scrollbar-arrow-color:#676662;
+scrollbar-base-color:#F0F0EE;
+scrollbar-darkshadow-color:#DDDDDD;
+scrollbar-face-color:#E0E0DD;
+scrollbar-highlight-color:#F0F0EE;
+scrollbar-shadow-color:#F0F0EE;
+scrollbar-track-color:#F5F5F5;
+background:#F0F0EE;
+padding:0;
+margin:8px 8px 0 8px;
+}
+
+html {background:#F0F0EE;}
+td {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;}
+textarea {resize:none;outline:none;}
+a:link, a:visited {color:black;}
+a:hover {color:#2B6FB6;}
+.nowrap {white-space: nowrap}
+
+/* Forms */
+fieldset {margin:0; padding:4px; border:1px solid #919B9C; font-family:Verdana, Arial; font-size:10px;}
+legend {color:#2B6FB6; font-weight:bold;}
+label.msg {display:none;}
+label.invalid {color:#EE0000; display:inline;}
+input.invalid {border:1px solid #EE0000;}
+input {background:#FFF; border:1px solid #CCC;}
+input, select, textarea {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;}
+input, select, textarea {border:1px solid #808080;}
+input.radio {border:1px none #000000; background:transparent; vertical-align:middle;}
+input.checkbox {border:1px none #000000; background:transparent; vertical-align:middle;}
+.input_noborder {border:0;}
+
+/* Buttons */
+#insert, #cancel, input.button, .updateButton {
+border:0; margin:0; padding:0;
+font-weight:bold;
+width:94px; height:26px;
+background:url(img/buttons.png) 0 -26px;
+cursor:pointer;
+padding-bottom:2px;
+float:left;
+}
+
+#insert {background:url(img/buttons.png) 0 -52px}
+#cancel {background:url(img/buttons.png) 0 0; float:right}
+
+/* Browse */
+a.pickcolor, a.browse {text-decoration:none}
+a.browse span {display:block; width:20px; height:18px; background:url(../../img/icons.gif) -860px 0; border:1px solid #FFF; margin-left:1px;}
+.mceOldBoxModel a.browse span {width:22px; height:20px;}
+a.browse:hover span {border:1px solid #0A246A; background-color:#B2BBD0;}
+a.browse span.disabled {border:1px solid white; opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+a.browse:hover span.disabled {border:1px solid white; background-color:transparent;}
+a.pickcolor span {display:block; width:20px; height:16px; background:url(../../img/icons.gif) -840px 0; margin-left:2px;}
+.mceOldBoxModel a.pickcolor span {width:21px; height:17px;}
+a.pickcolor:hover span {background-color:#B2BBD0;}
+a.pickcolor:hover span.disabled {}
+
+/* Charmap */
+table.charmap {border:1px solid #AAA; text-align:center}
+td.charmap, #charmap a {width:18px; height:18px; color:#000; border:1px solid #AAA; text-align:center; font-size:12px; vertical-align:middle; line-height: 18px;}
+#charmap a {display:block; color:#000; text-decoration:none; border:0}
+#charmap a:hover {background:#CCC;color:#2B6FB6}
+#charmap #codeN {font-size:10px; font-family:Arial,Helvetica,sans-serif; text-align:center}
+#charmap #codeV {font-size:40px; height:80px; border:1px solid #AAA; text-align:center}
+
+/* Source */
+.wordWrapCode {vertical-align:middle; border:1px none #000000; background:transparent;}
+.mceActionPanel {margin-top:5px;}
+
+/* Tabs classes */
+.tabs {width:100%; height:18px; line-height:normal; background:url(img/tabs.gif) repeat-x 0 -72px;}
+.tabs ul {margin:0; padding:0; list-style:none;}
+.tabs li {float:left; background:url(img/tabs.gif) no-repeat 0 0; margin:0 2px 0 0; padding:0 0 0 10px; line-height:17px; height:18px; display:block;}
+.tabs li.current {background:url(img/tabs.gif) no-repeat 0 -18px; margin-right:2px;}
+.tabs span {float:left; display:block; background:url(img/tabs.gif) no-repeat right -36px; padding:0px 10px 0 0;}
+.tabs .current span {background:url(img/tabs.gif) no-repeat right -54px;}
+.tabs a {text-decoration:none; font-family:Verdana, Arial; font-size:10px;}
+.tabs a:link, .tabs a:visited, .tabs a:hover {color:black;}
+
+/* Panels */
+.panel_wrapper div.panel {display:none;}
+.panel_wrapper div.current {display:block; width:100%; height:300px; overflow:visible;}
+.panel_wrapper {border:1px solid #919B9C; border-top:0px; padding:10px; padding-top:5px; clear:both; background:white;}
+
+/* Columns */
+.column {float:left;}
+.properties {width:100%;}
+.properties .column1 {}
+.properties .column2 {text-align:left;}
+
+/* Titles */
+h1, h2, h3, h4 {color:#2B6FB6; margin:0; padding:0; padding-top:5px;}
+h3 {font-size:14px;}
+.title {font-size:12px; font-weight:bold; color:#2B6FB6;}
+
+/* Dialog specific */
+#link .panel_wrapper, #link div.current {height:125px;}
+#image .panel_wrapper, #image div.current {height:200px;}
+#plugintable thead {font-weight:bold; background:#DDD;}
+#plugintable, #about #plugintable td {border:1px solid #919B9C;}
+#plugintable {width:96%; margin-top:10px;}
+#pluginscontainer {height:290px; overflow:auto;}
+#colorpicker #preview {display:inline-block; padding-left:40px; height:14px; border:1px solid black; margin-left:5px; margin-right: 5px}
+#colorpicker #previewblock {position: relative; top: -3px; padding-left:5px; padding-top: 0px; display:inline}
+#colorpicker #preview_wrapper { text-align:center; padding-top:4px; white-space: nowrap}
+#colorpicker #colors {float:left; border:1px solid gray; cursor:crosshair;}
+#colorpicker #light {border:1px solid gray; margin-left:5px; float:left;width:15px; height:150px; cursor:crosshair;}
+#colorpicker #light div {overflow:hidden;}
+#colorpicker .panel_wrapper div.current {height:175px;}
+#colorpicker #namedcolors {width:150px;}
+#colorpicker #namedcolors a {display:block; float:left; width:10px; height:10px; margin:1px 1px 0 0; overflow:hidden;}
+#colorpicker #colornamecontainer {margin-top:5px;}
+#colorpicker #picker_panel fieldset {margin:auto;width:325px;}
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/default/img/buttons.png b/askbot/media/js/tinymce/themes/advanced/skins/default/img/buttons.png
new file mode 100644
index 00000000..1e53560e
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/default/img/buttons.png
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/default/img/items.gif b/askbot/media/js/tinymce/themes/advanced/skins/default/img/items.gif
new file mode 100644
index 00000000..d2f93671
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/default/img/items.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/default/img/menu_arrow.gif b/askbot/media/js/tinymce/themes/advanced/skins/default/img/menu_arrow.gif
new file mode 100644
index 00000000..85e31dfb
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/default/img/menu_arrow.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/default/img/menu_check.gif b/askbot/media/js/tinymce/themes/advanced/skins/default/img/menu_check.gif
new file mode 100644
index 00000000..adfdddcc
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/default/img/menu_check.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/default/img/progress.gif b/askbot/media/js/tinymce/themes/advanced/skins/default/img/progress.gif
new file mode 100644
index 00000000..5bb90fd6
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/default/img/progress.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/default/img/tabs.gif b/askbot/media/js/tinymce/themes/advanced/skins/default/img/tabs.gif
new file mode 100644
index 00000000..06812cb4
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/default/img/tabs.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/default/ui.css b/askbot/media/js/tinymce/themes/advanced/skins/default/ui.css
new file mode 100644
index 00000000..77083f31
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/default/ui.css
@@ -0,0 +1,219 @@
+/* Reset */
+.defaultSkin table, .defaultSkin tbody, .defaultSkin a, .defaultSkin img, .defaultSkin tr, .defaultSkin div, .defaultSkin td, .defaultSkin iframe, .defaultSkin span, .defaultSkin *, .defaultSkin .mceText {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000; vertical-align:baseline; width:auto; border-collapse:separate; text-align:left}
+.defaultSkin a:hover, .defaultSkin a:link, .defaultSkin a:visited, .defaultSkin a:active {text-decoration:none; font-weight:normal; cursor:default; color:#000}
+.defaultSkin table td {vertical-align:middle}
+
+/* Containers */
+.defaultSkin table {direction:ltr;background:transparent}
+.defaultSkin iframe {display:block;}
+.defaultSkin .mceToolbar {height:26px}
+.defaultSkin .mceLeft {text-align:left}
+.defaultSkin .mceRight {text-align:right}
+
+/* External */
+.defaultSkin .mceExternalToolbar {position:absolute; border:1px solid #CCC; border-bottom:0; display:none;}
+.defaultSkin .mceExternalToolbar td.mceToolbar {padding-right:13px;}
+.defaultSkin .mceExternalClose {position:absolute; top:3px; right:3px; width:7px; height:7px; background:url(../../img/icons.gif) -820px 0}
+
+/* Layout */
+.defaultSkin table.mceLayout {border:0; border-left:1px solid #CCC; border-right:1px solid #CCC}
+.defaultSkin table.mceLayout tr.mceFirst td {border-top:1px solid #CCC}
+.defaultSkin table.mceLayout tr.mceLast td {border-bottom:1px solid #CCC}
+.defaultSkin table.mceToolbar, .defaultSkin tr.mceFirst .mceToolbar tr td, .defaultSkin tr.mceLast .mceToolbar tr td {border:0; margin:0; padding:0;}
+.defaultSkin td.mceToolbar {background:#F0F0EE; padding-top:1px; vertical-align:top}
+.defaultSkin .mceIframeContainer {border-top:1px solid #CCC; border-bottom:1px solid #CCC}
+.defaultSkin .mceStatusbar {background:#F0F0EE; font-family:'MS Sans Serif',sans-serif,Verdana,Arial; font-size:9pt; line-height:16px; overflow:visible; color:#000; display:block; height:20px}
+.defaultSkin .mceStatusbar div {float:left; margin:2px}
+.defaultSkin .mceStatusbar a.mceResize {display:block; float:right; background:url(../../img/icons.gif) -800px 0; width:20px; height:20px; cursor:se-resize; outline:0}
+.defaultSkin .mceStatusbar a:hover {text-decoration:underline}
+.defaultSkin table.mceToolbar {margin-left:3px}
+.defaultSkin span.mceIcon, .defaultSkin img.mceIcon {display:block; width:20px; height:20px}
+.defaultSkin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px}
+.defaultSkin td.mceCenter {text-align:center;}
+.defaultSkin td.mceCenter table {margin:0 auto; text-align:left;}
+.defaultSkin td.mceRight table {margin:0 0 0 auto;}
+
+/* Button */
+.defaultSkin .mceButton {display:block; border:1px solid #F0F0EE; width:20px; height:20px; margin-right:1px}
+.defaultSkin a.mceButtonEnabled:hover {border:1px solid #0A246A; background-color:#B2BBD0}
+.defaultSkin a.mceButtonActive, .defaultSkin a.mceButtonSelected {border:1px solid #0A246A; background-color:#C2CBE0}
+.defaultSkin .mceButtonDisabled .mceIcon {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+.defaultSkin .mceButtonLabeled {width:auto}
+.defaultSkin .mceButtonLabeled span.mceIcon {float:left}
+.defaultSkin span.mceButtonLabel {display:block; font-size:10px; padding:4px 6px 0 22px; font-family:Tahoma,Verdana,Arial,Helvetica}
+.defaultSkin .mceButtonDisabled .mceButtonLabel {color:#888}
+
+/* Separator */
+.defaultSkin .mceSeparator {display:block; background:url(../../img/icons.gif) -180px 0; width:2px; height:20px; margin:2px 2px 0 4px}
+
+/* ListBox */
+.defaultSkin .mceListBox, .defaultSkin .mceListBox a {display:block}
+.defaultSkin .mceListBox .mceText {padding-left:4px; width:70px; text-align:left; border:1px solid #CCC; border-right:0; background:#FFF; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; height:20px; line-height:20px; overflow:hidden}
+.defaultSkin .mceListBox .mceOpen {width:9px; height:20px; background:url(../../img/icons.gif) -741px 0; margin-right:2px; border:1px solid #CCC;}
+.defaultSkin table.mceListBoxEnabled:hover .mceText, .defaultSkin .mceListBoxHover .mceText, .defaultSkin .mceListBoxSelected .mceText {border:1px solid #A2ABC0; border-right:0; background:#FFF}
+.defaultSkin table.mceListBoxEnabled:hover .mceOpen, .defaultSkin .mceListBoxHover .mceOpen, .defaultSkin .mceListBoxSelected .mceOpen {background-color:#FFF; border:1px solid #A2ABC0}
+.defaultSkin .mceListBoxDisabled a.mceText {color:gray; background-color:transparent;}
+.defaultSkin .mceListBoxMenu {overflow:auto; overflow-x:hidden}
+.defaultSkin .mceOldBoxModel .mceListBox .mceText {height:22px}
+.defaultSkin .mceOldBoxModel .mceListBox .mceOpen {width:11px; height:22px;}
+.defaultSkin select.mceNativeListBox {font-family:'MS Sans Serif',sans-serif,Verdana,Arial; font-size:7pt; background:#F0F0EE; border:1px solid gray; margin-right:2px;}
+
+/* SplitButton */
+.defaultSkin .mceSplitButton {width:32px; height:20px; direction:ltr}
+.defaultSkin .mceSplitButton a, .defaultSkin .mceSplitButton span {height:20px; display:block}
+.defaultSkin .mceSplitButton a.mceAction {width:20px; border:1px solid #F0F0EE; border-right:0;}
+.defaultSkin .mceSplitButton span.mceAction {width:20px; background-image:url(../../img/icons.gif);}
+.defaultSkin .mceSplitButton a.mceOpen {width:9px; background:url(../../img/icons.gif) -741px 0; border:1px solid #F0F0EE;}
+.defaultSkin .mceSplitButton span.mceOpen {display:none}
+.defaultSkin table.mceSplitButtonEnabled:hover a.mceAction, .defaultSkin .mceSplitButtonHover a.mceAction, .defaultSkin .mceSplitButtonSelected a.mceAction {border:1px solid #0A246A; border-right:0; background-color:#B2BBD0}
+.defaultSkin table.mceSplitButtonEnabled:hover a.mceOpen, .defaultSkin .mceSplitButtonHover a.mceOpen, .defaultSkin .mceSplitButtonSelected a.mceOpen {background-color:#B2BBD0; border:1px solid #0A246A;}
+.defaultSkin .mceSplitButtonDisabled .mceAction, .defaultSkin .mceSplitButtonDisabled a.mceOpen {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+.defaultSkin .mceSplitButtonActive a.mceAction {border:1px solid #0A246A; background-color:#C2CBE0}
+.defaultSkin .mceSplitButtonActive a.mceOpen {border-left:0;}
+
+/* ColorSplitButton */
+.defaultSkin div.mceColorSplitMenu table {background:#FFF; border:1px solid gray}
+.defaultSkin .mceColorSplitMenu td {padding:2px}
+.defaultSkin .mceColorSplitMenu a {display:block; width:9px; height:9px; overflow:hidden; border:1px solid #808080}
+.defaultSkin .mceColorSplitMenu td.mceMoreColors {padding:1px 3px 1px 1px}
+.defaultSkin .mceColorSplitMenu a.mceMoreColors {width:100%; height:auto; text-align:center; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; line-height:20px; border:1px solid #FFF}
+.defaultSkin .mceColorSplitMenu a.mceMoreColors:hover {border:1px solid #0A246A; background-color:#B6BDD2}
+.defaultSkin a.mceMoreColors:hover {border:1px solid #0A246A}
+.defaultSkin .mceColorPreview {margin-left:2px; width:16px; height:4px; overflow:hidden; background:#9a9b9a}
+.defaultSkin .mce_forecolor span.mceAction, .defaultSkin .mce_backcolor span.mceAction {overflow:hidden; height:16px}
+
+/* Menu */
+.defaultSkin .mceMenu {position:absolute; left:0; top:0; z-index:1000; border:1px solid #D4D0C8; direction:ltr}
+.defaultSkin .mceNoIcons span.mceIcon {width:0;}
+.defaultSkin .mceNoIcons a .mceText {padding-left:10px}
+.defaultSkin .mceMenu table {background:#FFF}
+.defaultSkin .mceMenu a, .defaultSkin .mceMenu span, .defaultSkin .mceMenu {display:block}
+.defaultSkin .mceMenu td {height:20px}
+.defaultSkin .mceMenu a {position:relative;padding:3px 0 4px 0}
+.defaultSkin .mceMenu .mceText {position:relative; display:block; font-family:Tahoma,Verdana,Arial,Helvetica; color:#000; cursor:default; margin:0; padding:0 25px 0 25px; display:block}
+.defaultSkin .mceMenu span.mceText, .defaultSkin .mceMenu .mcePreview {font-size:11px}
+.defaultSkin .mceMenu pre.mceText {font-family:Monospace}
+.defaultSkin .mceMenu .mceIcon {position:absolute; top:0; left:0; width:22px;}
+.defaultSkin .mceMenu .mceMenuItemEnabled a:hover, .defaultSkin .mceMenu .mceMenuItemActive {background-color:#dbecf3}
+.defaultSkin td.mceMenuItemSeparator {background:#DDD; height:1px}
+.defaultSkin .mceMenuItemTitle a {border:0; background:#EEE; border-bottom:1px solid #DDD}
+.defaultSkin .mceMenuItemTitle span.mceText {color:#000; font-weight:bold; padding-left:4px}
+.defaultSkin .mceMenuItemDisabled .mceText {color:#888}
+.defaultSkin .mceMenuItemSelected .mceIcon {background:url(img/menu_check.gif)}
+.defaultSkin .mceNoIcons .mceMenuItemSelected a {background:url(img/menu_arrow.gif) no-repeat -6px center}
+.defaultSkin .mceMenu span.mceMenuLine {display:none}
+.defaultSkin .mceMenuItemSub a {background:url(img/menu_arrow.gif) no-repeat top right;}
+.defaultSkin .mceMenuItem td, .defaultSkin .mceMenuItem th {line-height: normal}
+
+/* Progress,Resize */
+.defaultSkin .mceBlocker {position:absolute; left:0; top:0; z-index:1000; opacity:0.5; -ms-filter:'alpha(opacity=50)'; filter:alpha(opacity=50); background:#FFF}
+.defaultSkin .mceProgress {position:absolute; left:0; top:0; z-index:1001; background:url(img/progress.gif) no-repeat; width:32px; height:32px; margin:-16px 0 0 -16px}
+
+/* Rtl */
+.mceRtl .mceListBox .mceText {text-align: right; padding: 0 4px 0 0}
+.mceRtl .mceMenuItem .mceText {text-align: right}
+
+/* Formats */
+.defaultSkin .mce_formatPreview a {font-size:10px}
+.defaultSkin .mce_p span.mceText {}
+.defaultSkin .mce_address span.mceText {font-style:italic}
+.defaultSkin .mce_pre span.mceText {font-family:monospace}
+.defaultSkin .mce_h1 span.mceText {font-weight:bolder; font-size: 2em}
+.defaultSkin .mce_h2 span.mceText {font-weight:bolder; font-size: 1.5em}
+.defaultSkin .mce_h3 span.mceText {font-weight:bolder; font-size: 1.17em}
+.defaultSkin .mce_h4 span.mceText {font-weight:bolder; font-size: 1em}
+.defaultSkin .mce_h5 span.mceText {font-weight:bolder; font-size: .83em}
+.defaultSkin .mce_h6 span.mceText {font-weight:bolder; font-size: .75em}
+
+/* Theme */
+.defaultSkin span.mce_bold {background-position:0 0}
+.defaultSkin span.mce_italic {background-position:-60px 0}
+.defaultSkin span.mce_underline {background-position:-140px 0}
+.defaultSkin span.mce_strikethrough {background-position:-120px 0}
+.defaultSkin span.mce_undo {background-position:-160px 0}
+.defaultSkin span.mce_redo {background-position:-100px 0}
+.defaultSkin span.mce_cleanup {background-position:-40px 0}
+.defaultSkin span.mce_bullist {background-position:-20px 0}
+.defaultSkin span.mce_numlist {background-position:-80px 0}
+.defaultSkin span.mce_justifyleft {background-position:-460px 0}
+.defaultSkin span.mce_justifyright {background-position:-480px 0}
+.defaultSkin span.mce_justifycenter {background-position:-420px 0}
+.defaultSkin span.mce_justifyfull {background-position:-440px 0}
+.defaultSkin span.mce_anchor {background-position:-200px 0}
+.defaultSkin span.mce_indent {background-position:-400px 0}
+.defaultSkin span.mce_outdent {background-position:-540px 0}
+.defaultSkin span.mce_link {background-position:-500px 0}
+.defaultSkin span.mce_unlink {background-position:-640px 0}
+.defaultSkin span.mce_sub {background-position:-600px 0}
+.defaultSkin span.mce_sup {background-position:-620px 0}
+.defaultSkin span.mce_removeformat {background-position:-580px 0}
+.defaultSkin span.mce_newdocument {background-position:-520px 0}
+.defaultSkin span.mce_image {background-position:-380px 0}
+.defaultSkin span.mce_help {background-position:-340px 0}
+.defaultSkin span.mce_code {background-position:-260px 0}
+.defaultSkin span.mce_hr {background-position:-360px 0}
+.defaultSkin span.mce_visualaid {background-position:-660px 0}
+.defaultSkin span.mce_charmap {background-position:-240px 0}
+.defaultSkin span.mce_paste {background-position:-560px 0}
+.defaultSkin span.mce_copy {background-position:-700px 0}
+.defaultSkin span.mce_cut {background-position:-680px 0}
+.defaultSkin span.mce_blockquote {background-position:-220px 0}
+.defaultSkin .mce_forecolor span.mceAction {background-position:-720px 0}
+.defaultSkin .mce_backcolor span.mceAction {background-position:-760px 0}
+.defaultSkin span.mce_forecolorpicker {background-position:-720px 0}
+.defaultSkin span.mce_backcolorpicker {background-position:-760px 0}
+
+/* Plugins */
+.defaultSkin span.mce_advhr {background-position:-0px -20px}
+.defaultSkin span.mce_ltr {background-position:-20px -20px}
+.defaultSkin span.mce_rtl {background-position:-40px -20px}
+.defaultSkin span.mce_emotions {background-position:-60px -20px}
+.defaultSkin span.mce_fullpage {background-position:-80px -20px}
+.defaultSkin span.mce_fullscreen {background-position:-100px -20px}
+.defaultSkin span.mce_iespell {background-position:-120px -20px}
+.defaultSkin span.mce_insertdate {background-position:-140px -20px}
+.defaultSkin span.mce_inserttime {background-position:-160px -20px}
+.defaultSkin span.mce_absolute {background-position:-180px -20px}
+.defaultSkin span.mce_backward {background-position:-200px -20px}
+.defaultSkin span.mce_forward {background-position:-220px -20px}
+.defaultSkin span.mce_insert_layer {background-position:-240px -20px}
+.defaultSkin span.mce_insertlayer {background-position:-260px -20px}
+.defaultSkin span.mce_movebackward {background-position:-280px -20px}
+.defaultSkin span.mce_moveforward {background-position:-300px -20px}
+.defaultSkin span.mce_media {background-position:-320px -20px}
+.defaultSkin span.mce_nonbreaking {background-position:-340px -20px}
+.defaultSkin span.mce_pastetext {background-position:-360px -20px}
+.defaultSkin span.mce_pasteword {background-position:-380px -20px}
+.defaultSkin span.mce_selectall {background-position:-400px -20px}
+.defaultSkin span.mce_preview {background-position:-420px -20px}
+.defaultSkin span.mce_print {background-position:-440px -20px}
+.defaultSkin span.mce_cancel {background-position:-460px -20px}
+.defaultSkin span.mce_save {background-position:-480px -20px}
+.defaultSkin span.mce_replace {background-position:-500px -20px}
+.defaultSkin span.mce_search {background-position:-520px -20px}
+.defaultSkin span.mce_styleprops {background-position:-560px -20px}
+.defaultSkin span.mce_table {background-position:-580px -20px}
+.defaultSkin span.mce_cell_props {background-position:-600px -20px}
+.defaultSkin span.mce_delete_table {background-position:-620px -20px}
+.defaultSkin span.mce_delete_col {background-position:-640px -20px}
+.defaultSkin span.mce_delete_row {background-position:-660px -20px}
+.defaultSkin span.mce_col_after {background-position:-680px -20px}
+.defaultSkin span.mce_col_before {background-position:-700px -20px}
+.defaultSkin span.mce_row_after {background-position:-720px -20px}
+.defaultSkin span.mce_row_before {background-position:-740px -20px}
+.defaultSkin span.mce_merge_cells {background-position:-760px -20px}
+.defaultSkin span.mce_table_props {background-position:-980px -20px}
+.defaultSkin span.mce_row_props {background-position:-780px -20px}
+.defaultSkin span.mce_split_cells {background-position:-800px -20px}
+.defaultSkin span.mce_template {background-position:-820px -20px}
+.defaultSkin span.mce_visualchars {background-position:-840px -20px}
+.defaultSkin span.mce_abbr {background-position:-860px -20px}
+.defaultSkin span.mce_acronym {background-position:-880px -20px}
+.defaultSkin span.mce_attribs {background-position:-900px -20px}
+.defaultSkin span.mce_cite {background-position:-920px -20px}
+.defaultSkin span.mce_del {background-position:-940px -20px}
+.defaultSkin span.mce_ins {background-position:-960px -20px}
+.defaultSkin span.mce_pagebreak {background-position:0 -40px}
+.defaultSkin span.mce_restoredraft {background-position:-20px -40px}
+.defaultSkin span.mce_spellchecker {background-position:-540px -20px}
+.defaultSkin span.mce_visualblocks {background-position: -40px -40px}
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/highcontrast/content.css b/askbot/media/js/tinymce/themes/advanced/skins/highcontrast/content.css
new file mode 100644
index 00000000..cbce6c6a
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/highcontrast/content.css
@@ -0,0 +1,24 @@
+body, td, pre { margin:8px;}
+body.mceForceColors {background:#FFF; color:#000;}
+h1 {font-size: 2em}
+h2 {font-size: 1.5em}
+h3 {font-size: 1.17em}
+h4 {font-size: 1em}
+h5 {font-size: .83em}
+h6 {font-size: .75em}
+.mceItemTable, .mceItemTable td, .mceItemTable th, .mceItemTable caption, .mceItemVisualAid {border: 1px dashed #BBB;}
+a.mceItemAnchor {display:inline-block; width:11px !important; height:11px !important; background:url(../default/img/items.gif) no-repeat 0 0;}
+span.mceItemNbsp {background: #DDD}
+td.mceSelected, th.mceSelected {background-color:#3399ff !important}
+img {border:0;}
+table, img, hr, .mceItemAnchor {cursor:default}
+table td, table th {cursor:text}
+ins {border-bottom:1px solid green; text-decoration: none; color:green}
+del {color:red; text-decoration:line-through}
+cite {border-bottom:1px dashed blue}
+acronym {border-bottom:1px dotted #CCC; cursor:help}
+abbr {border-bottom:1px dashed #CCC; cursor:help}
+
+img:-moz-broken {-moz-force-broken-image-icon:1; width:24px; height:24px}
+font[face=mceinline] {font-family:inherit !important}
+*[contentEditable]:focus {outline:0}
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/highcontrast/dialog.css b/askbot/media/js/tinymce/themes/advanced/skins/highcontrast/dialog.css
new file mode 100644
index 00000000..6d9fc8dd
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/highcontrast/dialog.css
@@ -0,0 +1,106 @@
+/* Generic */
+body {
+font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px;
+background:#F0F0EE;
+color: black;
+padding:0;
+margin:8px 8px 0 8px;
+}
+
+html {background:#F0F0EE; color:#000;}
+td {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;}
+textarea {resize:none;outline:none;}
+a:link, a:visited {color:black;background-color:transparent;}
+a:hover {color:#2B6FB6;background-color:transparent;}
+.nowrap {white-space: nowrap}
+
+/* Forms */
+fieldset {margin:0; padding:4px; border:1px solid #919B9C; font-family:Verdana, Arial; font-size:10px;}
+legend {color:#2B6FB6; font-weight:bold;}
+label.msg {display:none;}
+label.invalid {color:#EE0000; display:inline;background-color:transparent;}
+input.invalid {border:1px solid #EE0000;background-color:transparent;}
+input {background:#FFF; border:1px solid #CCC;color:black;}
+input, select, textarea {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;}
+input, select, textarea {border:1px solid #808080;}
+input.radio {border:1px none #000000; background:transparent; vertical-align:middle;}
+input.checkbox {border:1px none #000000; background:transparent; vertical-align:middle;}
+.input_noborder {border:0;}
+
+/* Buttons */
+#insert, #cancel, input.button, .updateButton {
+font-weight:bold;
+width:94px; height:23px;
+cursor:pointer;
+padding-bottom:2px;
+float:left;
+}
+
+#cancel {float:right}
+
+/* Browse */
+a.pickcolor, a.browse {text-decoration:none}
+a.browse span {display:block; width:20px; height:18px; background:url(../../img/icons.gif) -860px 0; border:1px solid #FFF; margin-left:1px;}
+.mceOldBoxModel a.browse span {width:22px; height:20px;}
+a.browse:hover span {border:1px solid #0A246A; background-color:#B2BBD0;}
+a.browse span.disabled {border:1px solid white; opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+a.browse:hover span.disabled {border:1px solid white; background-color:transparent;}
+a.pickcolor span {display:block; width:20px; height:16px; background:url(../../img/icons.gif) -840px 0; margin-left:2px;}
+.mceOldBoxModel a.pickcolor span {width:21px; height:17px;}
+a.pickcolor:hover span {background-color:#B2BBD0;}
+a.pickcolor:hover span.disabled {}
+
+/* Charmap */
+table.charmap {border:1px solid #AAA; text-align:center}
+td.charmap, #charmap a {width:18px; height:18px; color:#000; border:1px solid #AAA; text-align:center; font-size:12px; vertical-align:middle; line-height: 18px;}
+#charmap a {display:block; color:#000; text-decoration:none; border:0}
+#charmap a:hover {background:#CCC;color:#2B6FB6}
+#charmap #codeN {font-size:10px; font-family:Arial,Helvetica,sans-serif; text-align:center}
+#charmap #codeV {font-size:40px; height:80px; border:1px solid #AAA; text-align:center}
+
+/* Source */
+.wordWrapCode {vertical-align:middle; border:1px none #000000; background:transparent;}
+.mceActionPanel {margin-top:5px;}
+
+/* Tabs classes */
+.tabs {width:100%; height:18px; line-height:normal;}
+.tabs ul {margin:0; padding:0; list-style:none;}
+.tabs li {float:left; border: 1px solid black; border-bottom:0; margin:0 2px 0 0; padding:0 0 0 10px; line-height:17px; height:18px; display:block; cursor:pointer;}
+.tabs li.current {font-weight: bold; margin-right:2px;}
+.tabs span {float:left; display:block; padding:0px 10px 0 0;}
+.tabs a {text-decoration:none; font-family:Verdana, Arial; font-size:10px;}
+.tabs a:link, .tabs a:visited, .tabs a:hover {color:black;}
+
+/* Panels */
+.panel_wrapper div.panel {display:none;}
+.panel_wrapper div.current {display:block; width:100%; height:300px; overflow:visible;}
+.panel_wrapper {border:1px solid #919B9C; padding:10px; padding-top:5px; clear:both; background:white;}
+
+/* Columns */
+.column {float:left;}
+.properties {width:100%;}
+.properties .column1 {}
+.properties .column2 {text-align:left;}
+
+/* Titles */
+h1, h2, h3, h4 {color:#2B6FB6; margin:0; padding:0; padding-top:5px;}
+h3 {font-size:14px;}
+.title {font-size:12px; font-weight:bold; color:#2B6FB6;}
+
+/* Dialog specific */
+#link .panel_wrapper, #link div.current {height:125px;}
+#image .panel_wrapper, #image div.current {height:200px;}
+#plugintable thead {font-weight:bold; background:#DDD;}
+#plugintable, #about #plugintable td {border:1px solid #919B9C;}
+#plugintable {width:96%; margin-top:10px;}
+#pluginscontainer {height:290px; overflow:auto;}
+#colorpicker #preview {display:inline-block; padding-left:40px; height:14px; border:1px solid black; margin-left:5px; margin-right: 5px}
+#colorpicker #previewblock {position: relative; top: -3px; padding-left:5px; padding-top: 0px; display:inline}
+#colorpicker #preview_wrapper { text-align:center; padding-top:4px; white-space: nowrap}
+#colorpicker #colors {float:left; border:1px solid gray; cursor:crosshair;}
+#colorpicker #light {border:1px solid gray; margin-left:5px; float:left;width:15px; height:150px; cursor:crosshair;}
+#colorpicker #light div {overflow:hidden;}
+#colorpicker .panel_wrapper div.current {height:175px;}
+#colorpicker #namedcolors {width:150px;}
+#colorpicker #namedcolors a {display:block; float:left; width:10px; height:10px; margin:1px 1px 0 0; overflow:hidden;}
+#colorpicker #colornamecontainer {margin-top:5px;}
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/highcontrast/ui.css b/askbot/media/js/tinymce/themes/advanced/skins/highcontrast/ui.css
new file mode 100644
index 00000000..effbbe15
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/highcontrast/ui.css
@@ -0,0 +1,106 @@
+/* Reset */
+.highcontrastSkin table, .highcontrastSkin tbody, .highcontrastSkin a, .highcontrastSkin img, .highcontrastSkin tr, .highcontrastSkin div, .highcontrastSkin td, .highcontrastSkin iframe, .highcontrastSkin span, .highcontrastSkin *, .highcontrastSkin .mceText {border:0; margin:0; padding:0; vertical-align:baseline; border-collapse:separate;}
+.highcontrastSkin a:hover, .highcontrastSkin a:link, .highcontrastSkin a:visited, .highcontrastSkin a:active {text-decoration:none; font-weight:normal; cursor:default;}
+.highcontrastSkin table td {vertical-align:middle}
+
+.highcontrastSkin .mceIconOnly {display: block !important;}
+
+/* External */
+.highcontrastSkin .mceExternalToolbar {position:absolute; border:1px solid; border-bottom:0; display:none; background-color: white;}
+.highcontrastSkin .mceExternalToolbar td.mceToolbar {padding-right:13px;}
+.highcontrastSkin .mceExternalClose {position:absolute; top:3px; right:3px; width:7px; height:7px;}
+
+/* Layout */
+.highcontrastSkin table.mceLayout {border: 1px solid;}
+.highcontrastSkin .mceIframeContainer {border-top:1px solid; border-bottom:1px solid}
+.highcontrastSkin .mceStatusbar a:hover {text-decoration:underline}
+.highcontrastSkin .mceStatusbar {display:block; line-height:1.5em; overflow:visible;}
+.highcontrastSkin .mceStatusbar div {float:left}
+.highcontrastSkin .mceStatusbar a.mceResize {display:block; float:right; width:20px; height:20px; cursor:se-resize; outline:0}
+
+.highcontrastSkin .mceToolbar td { display: inline-block; float: left;}
+.highcontrastSkin .mceToolbar tr { display: block;}
+.highcontrastSkin .mceToolbar table { display: block; }
+
+/* Button */
+
+.highcontrastSkin .mceButton { display:block; margin: 2px; padding: 5px 10px;border: 1px solid; border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; -ms-border-radius: 3px; height: 2em;}
+.highcontrastSkin .mceButton .mceVoiceLabel { height: 100%; vertical-align: center; line-height: 2em}
+.highcontrastSkin .mceButtonDisabled .mceVoiceLabel { opacity:0.6; -ms-filter:'alpha(opacity=60)'; filter:alpha(opacity=60);}
+.highcontrastSkin .mceButtonActive, .highcontrastSkin .mceButton:focus, .highcontrastSkin .mceButton:active { border: 5px solid; padding: 1px 6px;-webkit-focus-ring-color:none;outline:none;}
+
+/* Separator */
+.highcontrastSkin .mceSeparator {display:block; width:16px; height:26px;}
+
+/* ListBox */
+.highcontrastSkin .mceListBox { display: block; margin:2px;-webkit-focus-ring-color:none;outline:none;}
+.highcontrastSkin .mceListBox .mceText {padding: 5px 6px; line-height: 2em; width: 15ex; overflow: hidden;}
+.highcontrastSkin .mceListBoxDisabled .mceText { opacity:0.6; -ms-filter:'alpha(opacity=60)'; filter:alpha(opacity=60);}
+.highcontrastSkin .mceListBox a.mceText { padding: 5px 10px; display: block; height: 2em; line-height: 2em; border: 1px solid; border-right: 0; border-radius: 3px 0px 0px 3px; -moz-border-radius: 3px 0px 0px 3px; -webkit-border-radius: 3px 0px 0px 3px; -ms-border-radius: 3px 0px 0px 3px;}
+.highcontrastSkin .mceListBox a.mceOpen { padding: 5px 4px; display: block; height: 2em; line-height: 2em; border: 1px solid; border-left: 0; border-radius: 0px 3px 3px 0px; -moz-border-radius: 0px 3px 3px 0px; -webkit-border-radius: 0px 3px 3px 0px; -ms-border-radius: 0px 3px 3px 0px;}
+.highcontrastSkin .mceListBox:focus a.mceText, .highcontrastSkin .mceListBox:active a.mceText { border-width: 5px; padding: 1px 10px 1px 6px;}
+.highcontrastSkin .mceListBox:focus a.mceOpen, .highcontrastSkin .mceListBox:active a.mceOpen { border-width: 5px; padding: 1px 0px 1px 4px;}
+
+.highcontrastSkin .mceListBoxMenu {overflow-y:auto}
+
+/* SplitButton */
+.highcontrastSkin .mceSplitButtonDisabled .mceAction {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+
+.highcontrastSkin .mceSplitButton { border-collapse: collapse; margin: 2px; height: 2em; line-height: 2em;-webkit-focus-ring-color:none;outline:none;}
+.highcontrastSkin .mceSplitButton td { display: table-cell; float: none; margin: 0; padding: 0; height: 2em;}
+.highcontrastSkin .mceSplitButton tr { display: table-row; }
+.highcontrastSkin table.mceSplitButton { display: table; }
+.highcontrastSkin .mceSplitButton a.mceAction { padding: 5px 10px; display: block; height: 2em; line-height: 2em; overflow: hidden; border: 1px solid; border-right: 0; border-radius: 3px 0px 0px 3px; -moz-border-radius: 3px 0px 0px 3px; -webkit-border-radius: 3px 0px 0px 3px; -ms-border-radius: 3px 0px 0px 3px;}
+.highcontrastSkin .mceSplitButton a.mceOpen { padding: 5px 4px; display: block; height: 2em; line-height: 2em; border: 1px solid; border-radius: 0px 3px 3px 0px; -moz-border-radius: 0px 3px 3px 0px; -webkit-border-radius: 0px 3px 3px 0px; -ms-border-radius: 0px 3px 3px 0px;}
+.highcontrastSkin .mceSplitButton .mceVoiceLabel { height: 2em; vertical-align: center; line-height: 2em; }
+.highcontrastSkin .mceSplitButton:focus a.mceAction, .highcontrastSkin .mceSplitButton:active a.mceAction { border-width: 5px; border-right-width: 1px; padding: 1px 10px 1px 6px;-webkit-focus-ring-color:none;outline:none;}
+.highcontrastSkin .mceSplitButton:focus a.mceOpen, .highcontrastSkin .mceSplitButton:active a.mceOpen { border-width: 5px; border-left-width: 1px; padding: 1px 0px 1px 4px;-webkit-focus-ring-color:none;outline:none;}
+
+/* Menu */
+.highcontrastSkin .mceNoIcons span.mceIcon {width:0;}
+.highcontrastSkin .mceMenu {position:absolute; left:0; top:0; z-index:1000; border:1px solid; direction:ltr}
+.highcontrastSkin .mceMenu table {background:white; color: black}
+.highcontrastSkin .mceNoIcons a .mceText {padding-left:10px}
+.highcontrastSkin .mceMenu a, .highcontrastSkin .mceMenu span, .highcontrastSkin .mceMenu {display:block;background:white; color: black}
+.highcontrastSkin .mceMenu td {height:2em}
+.highcontrastSkin .mceMenu a {position:relative;padding:3px 0 4px 0; display: block;}
+.highcontrastSkin .mceMenu .mceText {position:relative; display:block; cursor:default; margin:0; padding:0 25px 0 25px;}
+.highcontrastSkin .mceMenu pre.mceText {font-family:Monospace}
+.highcontrastSkin .mceMenu .mceIcon {position:absolute; top:0; left:0; width:26px;}
+.highcontrastSkin td.mceMenuItemSeparator {border-top:1px solid; height:1px}
+.highcontrastSkin .mceMenuItemTitle a {border:0; border-bottom:1px solid}
+.highcontrastSkin .mceMenuItemTitle span.mceText {font-weight:bold; padding-left:4px}
+.highcontrastSkin .mceNoIcons .mceMenuItemSelected span.mceText:before {content: "\2713\A0";}
+.highcontrastSkin .mceMenu span.mceMenuLine {display:none}
+.highcontrastSkin .mceMenuItemSub a .mceText:after {content: "\A0\25B8"}
+.highcontrastSkin .mceMenuItem td, .highcontrastSkin .mceMenuItem th {line-height: normal}
+
+/* ColorSplitButton */
+.highcontrastSkin div.mceColorSplitMenu table {background:#FFF; border:1px solid; color: #000}
+.highcontrastSkin .mceColorSplitMenu td {padding:2px}
+.highcontrastSkin .mceColorSplitMenu a {display:block; width:16px; height:16px; overflow:hidden; color:#000; margin: 0; padding: 0;}
+.highcontrastSkin .mceColorSplitMenu td.mceMoreColors {padding:1px 3px 1px 1px}
+.highcontrastSkin .mceColorSplitMenu a.mceMoreColors {width:100%; height:auto; text-align:center; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; line-height:20px; border:1px solid #FFF}
+.highcontrastSkin .mceColorSplitMenu a.mceMoreColors:hover {border:1px solid; background-color:#B6BDD2}
+.highcontrastSkin a.mceMoreColors:hover {border:1px solid #0A246A; color: #000;}
+.highcontrastSkin .mceColorPreview {display:none;}
+.highcontrastSkin .mce_forecolor span.mceAction, .highcontrastSkin .mce_backcolor span.mceAction {height:17px;overflow:hidden}
+
+/* Progress,Resize */
+.highcontrastSkin .mceBlocker {position:absolute; left:0; top:0; z-index:1000; opacity:0.5; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=50); background:#FFF}
+.highcontrastSkin .mceProgress {position:absolute; left:0; top:0; z-index:1001; background:url(../default/img/progress.gif) no-repeat; width:32px; height:32px; margin:-16px 0 0 -16px}
+
+/* Rtl */
+.mceRtl .mceListBox .mceText {text-align: right; padding: 0 4px 0 0}
+.mceRtl .mceMenuItem .mceText {text-align: right}
+
+/* Formats */
+.highcontrastSkin .mce_p span.mceText {}
+.highcontrastSkin .mce_address span.mceText {font-style:italic}
+.highcontrastSkin .mce_pre span.mceText {font-family:monospace}
+.highcontrastSkin .mce_h1 span.mceText {font-weight:bolder; font-size: 2em}
+.highcontrastSkin .mce_h2 span.mceText {font-weight:bolder; font-size: 1.5em}
+.highcontrastSkin .mce_h3 span.mceText {font-weight:bolder; font-size: 1.17em}
+.highcontrastSkin .mce_h4 span.mceText {font-weight:bolder; font-size: 1em}
+.highcontrastSkin .mce_h5 span.mceText {font-weight:bolder; font-size: .83em}
+.highcontrastSkin .mce_h6 span.mceText {font-weight:bolder; font-size: .75em}
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/o2k7/content.css b/askbot/media/js/tinymce/themes/advanced/skins/o2k7/content.css
new file mode 100644
index 00000000..a1a8f9bd
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/o2k7/content.css
@@ -0,0 +1,48 @@
+body, td, pre {color:#000; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px; margin:8px;}
+body {background:#FFF;}
+body.mceForceColors {background:#FFF; color:#000;}
+h1 {font-size: 2em}
+h2 {font-size: 1.5em}
+h3 {font-size: 1.17em}
+h4 {font-size: 1em}
+h5 {font-size: .83em}
+h6 {font-size: .75em}
+.mceItemTable, .mceItemTable td, .mceItemTable th, .mceItemTable caption, .mceItemVisualAid {border: 1px dashed #BBB;}
+a.mceItemAnchor {display:inline-block; width:11px !important; height:11px !important; background:url(../default/img/items.gif) no-repeat 0 0;}
+span.mceItemNbsp {background: #DDD}
+td.mceSelected, th.mceSelected {background-color:#3399ff !important}
+img {border:0;}
+table, img, hr, .mceItemAnchor {cursor:default}
+table td, table th {cursor:text}
+ins {border-bottom:1px solid green; text-decoration: none; color:green}
+del {color:red; text-decoration:line-through}
+cite {border-bottom:1px dashed blue}
+acronym {border-bottom:1px dotted #CCC; cursor:help}
+abbr {border-bottom:1px dashed #CCC; cursor:help}
+
+/* IE */
+* html body {
+scrollbar-3dlight-color:#F0F0EE;
+scrollbar-arrow-color:#676662;
+scrollbar-base-color:#F0F0EE;
+scrollbar-darkshadow-color:#DDD;
+scrollbar-face-color:#E0E0DD;
+scrollbar-highlight-color:#F0F0EE;
+scrollbar-shadow-color:#F0F0EE;
+scrollbar-track-color:#F5F5F5;
+}
+
+img:-moz-broken {-moz-force-broken-image-icon:1; width:24px; height:24px}
+font[face=mceinline] {font-family:inherit !important}
+*[contentEditable]:focus {outline:0}
+
+.mceItemMedia {border:1px dotted #cc0000; background-position:center; background-repeat:no-repeat; background-color:#ffffcc}
+.mceItemShockWave {background-image:url(../../img/shockwave.gif)}
+.mceItemFlash {background-image:url(../../img/flash.gif)}
+.mceItemQuickTime {background-image:url(../../img/quicktime.gif)}
+.mceItemWindowsMedia {background-image:url(../../img/windowsmedia.gif)}
+.mceItemRealMedia {background-image:url(../../img/realmedia.gif)}
+.mceItemVideo {background-image:url(../../img/video.gif)}
+.mceItemAudio {background-image:url(../../img/video.gif)}
+.mceItemIframe {background-image:url(../../img/iframe.gif)}
+.mcePageBreak {display:block;border:0;width:100%;height:12px;border-top:1px dotted #ccc;margin-top:15px;background:#fff url(../../img/pagebreak.gif) no-repeat center top;}
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/o2k7/dialog.css b/askbot/media/js/tinymce/themes/advanced/skins/o2k7/dialog.css
new file mode 100644
index 00000000..a54db98d
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/o2k7/dialog.css
@@ -0,0 +1,118 @@
+/* Generic */
+body {
+font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px;
+scrollbar-3dlight-color:#F0F0EE;
+scrollbar-arrow-color:#676662;
+scrollbar-base-color:#F0F0EE;
+scrollbar-darkshadow-color:#DDDDDD;
+scrollbar-face-color:#E0E0DD;
+scrollbar-highlight-color:#F0F0EE;
+scrollbar-shadow-color:#F0F0EE;
+scrollbar-track-color:#F5F5F5;
+background:#F0F0EE;
+padding:0;
+margin:8px 8px 0 8px;
+}
+
+html {background:#F0F0EE;}
+td {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;}
+textarea {resize:none;outline:none;}
+a:link, a:visited {color:black;}
+a:hover {color:#2B6FB6;}
+.nowrap {white-space: nowrap}
+
+/* Forms */
+fieldset {margin:0; padding:4px; border:1px solid #919B9C; font-family:Verdana, Arial; font-size:10px;}
+legend {color:#2B6FB6; font-weight:bold;}
+label.msg {display:none;}
+label.invalid {color:#EE0000; display:inline;}
+input.invalid {border:1px solid #EE0000;}
+input {background:#FFF; border:1px solid #CCC;}
+input, select, textarea {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;}
+input, select, textarea {border:1px solid #808080;}
+input.radio {border:1px none #000000; background:transparent; vertical-align:middle;}
+input.checkbox {border:1px none #000000; background:transparent; vertical-align:middle;}
+.input_noborder {border:0;}
+
+/* Buttons */
+#insert, #cancel, input.button, .updateButton {
+border:0; margin:0; padding:0;
+font-weight:bold;
+width:94px; height:26px;
+background:url(../default/img/buttons.png) 0 -26px;
+cursor:pointer;
+padding-bottom:2px;
+float:left;
+}
+
+#insert {background:url(../default/img/buttons.png) 0 -52px}
+#cancel {background:url(../default/img/buttons.png) 0 0; float:right}
+
+/* Browse */
+a.pickcolor, a.browse {text-decoration:none}
+a.browse span {display:block; width:20px; height:18px; background:url(../../img/icons.gif) -860px 0; border:1px solid #FFF; margin-left:1px;}
+.mceOldBoxModel a.browse span {width:22px; height:20px;}
+a.browse:hover span {border:1px solid #0A246A; background-color:#B2BBD0;}
+a.browse span.disabled {border:1px solid white; opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+a.browse:hover span.disabled {border:1px solid white; background-color:transparent;}
+a.pickcolor span {display:block; width:20px; height:16px; background:url(../../img/icons.gif) -840px 0; margin-left:2px;}
+.mceOldBoxModel a.pickcolor span {width:21px; height:17px;}
+a.pickcolor:hover span {background-color:#B2BBD0;}
+a.pickcolor:hover span.disabled {}
+
+/* Charmap */
+table.charmap {border:1px solid #AAA; text-align:center}
+td.charmap, #charmap a {width:18px; height:18px; color:#000; border:1px solid #AAA; text-align:center; font-size:12px; vertical-align:middle; line-height: 18px;}
+#charmap a {display:block; color:#000; text-decoration:none; border:0}
+#charmap a:hover {background:#CCC;color:#2B6FB6}
+#charmap #codeN {font-size:10px; font-family:Arial,Helvetica,sans-serif; text-align:center}
+#charmap #codeV {font-size:40px; height:80px; border:1px solid #AAA; text-align:center}
+
+/* Source */
+.wordWrapCode {vertical-align:middle; border:1px none #000000; background:transparent;}
+.mceActionPanel {margin-top:5px;}
+
+/* Tabs classes */
+.tabs {width:100%; height:18px; line-height:normal; background:url(../default/img/tabs.gif) repeat-x 0 -72px;}
+.tabs ul {margin:0; padding:0; list-style:none;}
+.tabs li {float:left; background:url(../default/img/tabs.gif) no-repeat 0 0; margin:0 2px 0 0; padding:0 0 0 10px; line-height:17px; height:18px; display:block;}
+.tabs li.current {background:url(../default/img/tabs.gif) no-repeat 0 -18px; margin-right:2px;}
+.tabs span {float:left; display:block; background:url(../default/img/tabs.gif) no-repeat right -36px; padding:0px 10px 0 0;}
+.tabs .current span {background:url(../default/img/tabs.gif) no-repeat right -54px;}
+.tabs a {text-decoration:none; font-family:Verdana, Arial; font-size:10px;}
+.tabs a:link, .tabs a:visited, .tabs a:hover {color:black;}
+
+/* Panels */
+.panel_wrapper div.panel {display:none;}
+.panel_wrapper div.current {display:block; width:100%; height:300px; overflow:visible;}
+.panel_wrapper {border:1px solid #919B9C; border-top:0px; padding:10px; padding-top:5px; clear:both; background:white;}
+
+/* Columns */
+.column {float:left;}
+.properties {width:100%;}
+.properties .column1 {}
+.properties .column2 {text-align:left;}
+
+/* Titles */
+h1, h2, h3, h4 {color:#2B6FB6; margin:0; padding:0; padding-top:5px;}
+h3 {font-size:14px;}
+.title {font-size:12px; font-weight:bold; color:#2B6FB6;}
+
+/* Dialog specific */
+#link .panel_wrapper, #link div.current {height:125px;}
+#image .panel_wrapper, #image div.current {height:200px;}
+#plugintable thead {font-weight:bold; background:#DDD;}
+#plugintable, #about #plugintable td {border:1px solid #919B9C;}
+#plugintable {width:96%; margin-top:10px;}
+#pluginscontainer {height:290px; overflow:auto;}
+#colorpicker #preview {display:inline-block; padding-left:40px; height:14px; border:1px solid black; margin-left:5px; margin-right: 5px}
+#colorpicker #previewblock {position: relative; top: -3px; padding-left:5px; padding-top: 0px; display:inline}
+#colorpicker #preview_wrapper { text-align:center; padding-top:4px; white-space: nowrap}
+#colorpicker #colors {float:left; border:1px solid gray; cursor:crosshair;}
+#colorpicker #light {border:1px solid gray; margin-left:5px; float:left;width:15px; height:150px; cursor:crosshair;}
+#colorpicker #light div {overflow:hidden;}
+#colorpicker .panel_wrapper div.current {height:175px;}
+#colorpicker #namedcolors {width:150px;}
+#colorpicker #namedcolors a {display:block; float:left; width:10px; height:10px; margin:1px 1px 0 0; overflow:hidden;}
+#colorpicker #colornamecontainer {margin-top:5px;}
+#colorpicker #picker_panel fieldset {margin:auto;width:325px;}
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/o2k7/img/button_bg.png b/askbot/media/js/tinymce/themes/advanced/skins/o2k7/img/button_bg.png
new file mode 100644
index 00000000..13a5cb03
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/o2k7/img/button_bg.png
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/o2k7/img/button_bg_black.png b/askbot/media/js/tinymce/themes/advanced/skins/o2k7/img/button_bg_black.png
new file mode 100644
index 00000000..7fc57f2b
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/o2k7/img/button_bg_black.png
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/o2k7/img/button_bg_silver.png b/askbot/media/js/tinymce/themes/advanced/skins/o2k7/img/button_bg_silver.png
new file mode 100644
index 00000000..c0dcc6ca
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/o2k7/img/button_bg_silver.png
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/o2k7/ui.css b/askbot/media/js/tinymce/themes/advanced/skins/o2k7/ui.css
new file mode 100644
index 00000000..a3102237
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/o2k7/ui.css
@@ -0,0 +1,222 @@
+/* Reset */
+.o2k7Skin table, .o2k7Skin tbody, .o2k7Skin a, .o2k7Skin img, .o2k7Skin tr, .o2k7Skin div, .o2k7Skin td, .o2k7Skin iframe, .o2k7Skin span, .o2k7Skin *, .o2k7Skin .mceText {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000; vertical-align:baseline; width:auto; border-collapse:separate; text-align:left}
+.o2k7Skin a:hover, .o2k7Skin a:link, .o2k7Skin a:visited, .o2k7Skin a:active {text-decoration:none; font-weight:normal; cursor:default; color:#000}
+.o2k7Skin table td {vertical-align:middle}
+
+/* Containers */
+.o2k7Skin table {background:transparent}
+.o2k7Skin iframe {display:block;}
+.o2k7Skin .mceToolbar {height:26px}
+
+/* External */
+.o2k7Skin .mceExternalToolbar {position:absolute; border:1px solid #ABC6DD; border-bottom:0; display:none}
+.o2k7Skin .mceExternalToolbar td.mceToolbar {padding-right:13px;}
+.o2k7Skin .mceExternalClose {position:absolute; top:3px; right:3px; width:7px; height:7px; background:url(../../img/icons.gif) -820px 0}
+
+/* Layout */
+.o2k7Skin table.mceLayout {border:0; border-left:1px solid #ABC6DD; border-right:1px solid #ABC6DD}
+.o2k7Skin table.mceLayout tr.mceFirst td {border-top:1px solid #ABC6DD}
+.o2k7Skin table.mceLayout tr.mceLast td {border-bottom:1px solid #ABC6DD}
+.o2k7Skin table.mceToolbar, .o2k7Skin tr.mceFirst .mceToolbar tr td, .o2k7Skin tr.mceLast .mceToolbar tr td {border:0; margin:0; padding:0}
+.o2k7Skin .mceIframeContainer {border-top:1px solid #ABC6DD; border-bottom:1px solid #ABC6DD}
+.o2k7Skin td.mceToolbar{background:#E5EFFD}
+.o2k7Skin .mceStatusbar {background:#E5EFFD; display:block; font-family:'MS Sans Serif',sans-serif,Verdana,Arial; font-size:9pt; line-height:16px; overflow:visible; color:#000; height:20px}
+.o2k7Skin .mceStatusbar div {float:left; padding:2px}
+.o2k7Skin .mceStatusbar a.mceResize {display:block; float:right; background:url(../../img/icons.gif) -800px 0; width:20px; height:20px; cursor:se-resize; outline:0}
+.o2k7Skin .mceStatusbar a:hover {text-decoration:underline}
+.o2k7Skin table.mceToolbar {margin-left:3px}
+.o2k7Skin .mceToolbar .mceToolbarStart span {display:block; background:url(img/button_bg.png) -22px 0; width:1px; height:22px; margin-left:3px;}
+.o2k7Skin .mceToolbar td.mceFirst span {margin:0}
+.o2k7Skin .mceToolbar .mceToolbarEnd span {display:block; background:url(img/button_bg.png) -22px 0; width:1px; height:22px}
+.o2k7Skin .mceToolbar .mceToolbarEndListBox span, .o2k7Skin .mceToolbar .mceToolbarStartListBox span {display:none}
+.o2k7Skin span.mceIcon, .o2k7Skin img.mceIcon {display:block; width:20px; height:20px}
+.o2k7Skin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px}
+.o2k7Skin td.mceCenter {text-align:center;}
+.o2k7Skin td.mceCenter table {margin:0 auto; text-align:left;}
+.o2k7Skin td.mceRight table {margin:0 0 0 auto;}
+
+/* Button */
+.o2k7Skin .mceButton {display:block; background:url(img/button_bg.png); width:22px; height:22px}
+.o2k7Skin a.mceButton span, .o2k7Skin a.mceButton img {margin-left:1px}
+.o2k7Skin .mceOldBoxModel a.mceButton span, .o2k7Skin .mceOldBoxModel a.mceButton img {margin:0 0 0 1px}
+.o2k7Skin a.mceButtonEnabled:hover {background-color:#B2BBD0; background-position:0 -22px}
+.o2k7Skin a.mceButtonActive, .o2k7Skin a.mceButtonSelected {background-position:0 -44px}
+.o2k7Skin .mceButtonDisabled .mceIcon {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+.o2k7Skin .mceButtonLabeled {width:auto}
+.o2k7Skin .mceButtonLabeled span.mceIcon {float:left}
+.o2k7Skin span.mceButtonLabel {display:block; font-size:10px; padding:4px 6px 0 22px; font-family:Tahoma,Verdana,Arial,Helvetica}
+.o2k7Skin .mceButtonDisabled .mceButtonLabel {color:#888}
+
+/* Separator */
+.o2k7Skin .mceSeparator {display:block; background:url(img/button_bg.png) -22px 0; width:5px; height:22px}
+
+/* ListBox */
+.o2k7Skin .mceListBox {padding-left: 3px}
+.o2k7Skin .mceListBox, .o2k7Skin .mceListBox a {display:block}
+.o2k7Skin .mceListBox .mceText {padding-left:4px; text-align:left; width:70px; border:1px solid #b3c7e1; border-right:0; background:#eaf2fb; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; height:20px; line-height:20px; overflow:hidden}
+.o2k7Skin .mceListBox .mceOpen {width:14px; height:22px; background:url(img/button_bg.png) -66px 0}
+.o2k7Skin table.mceListBoxEnabled:hover .mceText, .o2k7Skin .mceListBoxHover .mceText, .o2k7Skin .mceListBoxSelected .mceText {background:#FFF}
+.o2k7Skin table.mceListBoxEnabled:hover .mceOpen, .o2k7Skin .mceListBoxHover .mceOpen, .o2k7Skin .mceListBoxSelected .mceOpen {background-position:-66px -22px}
+.o2k7Skin .mceListBoxDisabled .mceText {color:gray}
+.o2k7Skin .mceListBoxMenu {overflow:auto; overflow-x:hidden; margin-left:3px}
+.o2k7Skin .mceOldBoxModel .mceListBox .mceText {height:22px}
+.o2k7Skin select.mceListBox {font-family:Tahoma,Verdana,Arial,Helvetica; font-size:12px; border:1px solid #b3c7e1; background:#FFF;}
+
+/* SplitButton */
+.o2k7Skin .mceSplitButton, .o2k7Skin .mceSplitButton a, .o2k7Skin .mceSplitButton span {display:block; height:22px; direction:ltr}
+.o2k7Skin .mceSplitButton {background:url(img/button_bg.png)}
+.o2k7Skin .mceSplitButton a.mceAction {width:22px}
+.o2k7Skin .mceSplitButton span.mceAction {width:22px; background-image:url(../../img/icons.gif)}
+.o2k7Skin .mceSplitButton a.mceOpen {width:10px; background:url(img/button_bg.png) -44px 0}
+.o2k7Skin .mceSplitButton span.mceOpen {display:none}
+.o2k7Skin table.mceSplitButtonEnabled:hover a.mceAction, .o2k7Skin .mceSplitButtonHover a.mceAction, .o2k7Skin .mceSplitButtonSelected {background:url(img/button_bg.png) 0 -22px}
+.o2k7Skin table.mceSplitButtonEnabled:hover a.mceOpen, .o2k7Skin .mceSplitButtonHover a.mceOpen, .o2k7Skin .mceSplitButtonSelected a.mceOpen {background-position:-44px -44px}
+.o2k7Skin .mceSplitButtonDisabled .mceAction {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+.o2k7Skin .mceSplitButtonActive {background-position:0 -44px}
+
+/* ColorSplitButton */
+.o2k7Skin div.mceColorSplitMenu table {background:#FFF; border:1px solid gray}
+.o2k7Skin .mceColorSplitMenu td {padding:2px}
+.o2k7Skin .mceColorSplitMenu a {display:block; width:9px; height:9px; overflow:hidden; border:1px solid #808080}
+.o2k7Skin .mceColorSplitMenu td.mceMoreColors {padding:1px 3px 1px 1px}
+.o2k7Skin .mceColorSplitMenu a.mceMoreColors {width:100%; height:auto; text-align:center; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; line-height:20px; border:1px solid #FFF}
+.o2k7Skin .mceColorSplitMenu a.mceMoreColors:hover {border:1px solid #0A246A; background-color:#B6BDD2}
+.o2k7Skin a.mceMoreColors:hover {border:1px solid #0A246A}
+.o2k7Skin .mceColorPreview {margin-left:2px; width:16px; height:4px; overflow:hidden; background:#9a9b9a;overflow:hidden}
+.o2k7Skin .mce_forecolor span.mceAction, .o2k7Skin .mce_backcolor span.mceAction {height:15px;overflow:hidden}
+
+/* Menu */
+.o2k7Skin .mceMenu {position:absolute; left:0; top:0; z-index:1000; border:1px solid #ABC6DD; direction:ltr}
+.o2k7Skin .mceNoIcons span.mceIcon {width:0;}
+.o2k7Skin .mceNoIcons a .mceText {padding-left:10px}
+.o2k7Skin .mceMenu table {background:#FFF}
+.o2k7Skin .mceMenu a, .o2k7Skin .mceMenu span, .o2k7Skin .mceMenu {display:block}
+.o2k7Skin .mceMenu td {height:20px}
+.o2k7Skin .mceMenu a {position:relative;padding:3px 0 4px 0}
+.o2k7Skin .mceMenu .mceText {position:relative; display:block; font-family:Tahoma,Verdana,Arial,Helvetica; color:#000; cursor:default; margin:0; padding:0 25px 0 25px; display:block}
+.o2k7Skin .mceMenu span.mceText, .o2k7Skin .mceMenu .mcePreview {font-size:11px}
+.o2k7Skin .mceMenu pre.mceText {font-family:Monospace}
+.o2k7Skin .mceMenu .mceIcon {position:absolute; top:0; left:0; width:22px;}
+.o2k7Skin .mceMenu .mceMenuItemEnabled a:hover, .o2k7Skin .mceMenu .mceMenuItemActive {background-color:#dbecf3}
+.o2k7Skin td.mceMenuItemSeparator {background:#DDD; height:1px}
+.o2k7Skin .mceMenuItemTitle a {border:0; background:#E5EFFD; border-bottom:1px solid #ABC6DD}
+.o2k7Skin .mceMenuItemTitle span.mceText {color:#000; font-weight:bold; padding-left:4px}
+.o2k7Skin .mceMenuItemDisabled .mceText {color:#888}
+.o2k7Skin .mceMenuItemSelected .mceIcon {background:url(../default/img/menu_check.gif)}
+.o2k7Skin .mceNoIcons .mceMenuItemSelected a {background:url(../default/img/menu_arrow.gif) no-repeat -6px center}
+.o2k7Skin .mceMenu span.mceMenuLine {display:none}
+.o2k7Skin .mceMenuItemSub a {background:url(../default/img/menu_arrow.gif) no-repeat top right;}
+.o2k7Skin .mceMenuItem td, .o2k7Skin .mceMenuItem th {line-height: normal}
+
+/* Progress,Resize */
+.o2k7Skin .mceBlocker {position:absolute; left:0; top:0; z-index:1000; opacity:0.5; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=50); background:#FFF}
+.o2k7Skin .mceProgress {position:absolute; left:0; top:0; z-index:1001; background:url(../default/img/progress.gif) no-repeat; width:32px; height:32px; margin:-16px 0 0 -16px}
+
+/* Rtl */
+.mceRtl .mceListBox .mceText {text-align: right; padding: 0 4px 0 0}
+.mceRtl .mceMenuItem .mceText {text-align: right}
+
+/* Formats */
+.o2k7Skin .mce_formatPreview a {font-size:10px}
+.o2k7Skin .mce_p span.mceText {}
+.o2k7Skin .mce_address span.mceText {font-style:italic}
+.o2k7Skin .mce_pre span.mceText {font-family:monospace}
+.o2k7Skin .mce_h1 span.mceText {font-weight:bolder; font-size: 2em}
+.o2k7Skin .mce_h2 span.mceText {font-weight:bolder; font-size: 1.5em}
+.o2k7Skin .mce_h3 span.mceText {font-weight:bolder; font-size: 1.17em}
+.o2k7Skin .mce_h4 span.mceText {font-weight:bolder; font-size: 1em}
+.o2k7Skin .mce_h5 span.mceText {font-weight:bolder; font-size: .83em}
+.o2k7Skin .mce_h6 span.mceText {font-weight:bolder; font-size: .75em}
+
+/* Theme */
+.o2k7Skin span.mce_bold {background-position:0 0}
+.o2k7Skin span.mce_italic {background-position:-60px 0}
+.o2k7Skin span.mce_underline {background-position:-140px 0}
+.o2k7Skin span.mce_strikethrough {background-position:-120px 0}
+.o2k7Skin span.mce_undo {background-position:-160px 0}
+.o2k7Skin span.mce_redo {background-position:-100px 0}
+.o2k7Skin span.mce_cleanup {background-position:-40px 0}
+.o2k7Skin span.mce_bullist {background-position:-20px 0}
+.o2k7Skin span.mce_numlist {background-position:-80px 0}
+.o2k7Skin span.mce_justifyleft {background-position:-460px 0}
+.o2k7Skin span.mce_justifyright {background-position:-480px 0}
+.o2k7Skin span.mce_justifycenter {background-position:-420px 0}
+.o2k7Skin span.mce_justifyfull {background-position:-440px 0}
+.o2k7Skin span.mce_anchor {background-position:-200px 0}
+.o2k7Skin span.mce_indent {background-position:-400px 0}
+.o2k7Skin span.mce_outdent {background-position:-540px 0}
+.o2k7Skin span.mce_link {background-position:-500px 0}
+.o2k7Skin span.mce_unlink {background-position:-640px 0}
+.o2k7Skin span.mce_sub {background-position:-600px 0}
+.o2k7Skin span.mce_sup {background-position:-620px 0}
+.o2k7Skin span.mce_removeformat {background-position:-580px 0}
+.o2k7Skin span.mce_newdocument {background-position:-520px 0}
+.o2k7Skin span.mce_image {background-position:-380px 0}
+.o2k7Skin span.mce_help {background-position:-340px 0}
+.o2k7Skin span.mce_code {background-position:-260px 0}
+.o2k7Skin span.mce_hr {background-position:-360px 0}
+.o2k7Skin span.mce_visualaid {background-position:-660px 0}
+.o2k7Skin span.mce_charmap {background-position:-240px 0}
+.o2k7Skin span.mce_paste {background-position:-560px 0}
+.o2k7Skin span.mce_copy {background-position:-700px 0}
+.o2k7Skin span.mce_cut {background-position:-680px 0}
+.o2k7Skin span.mce_blockquote {background-position:-220px 0}
+.o2k7Skin .mce_forecolor span.mceAction {background-position:-720px 0}
+.o2k7Skin .mce_backcolor span.mceAction {background-position:-760px 0}
+.o2k7Skin span.mce_forecolorpicker {background-position:-720px 0}
+.o2k7Skin span.mce_backcolorpicker {background-position:-760px 0}
+
+/* Plugins */
+.o2k7Skin span.mce_advhr {background-position:-0px -20px}
+.o2k7Skin span.mce_ltr {background-position:-20px -20px}
+.o2k7Skin span.mce_rtl {background-position:-40px -20px}
+.o2k7Skin span.mce_emotions {background-position:-60px -20px}
+.o2k7Skin span.mce_fullpage {background-position:-80px -20px}
+.o2k7Skin span.mce_fullscreen {background-position:-100px -20px}
+.o2k7Skin span.mce_iespell {background-position:-120px -20px}
+.o2k7Skin span.mce_insertdate {background-position:-140px -20px}
+.o2k7Skin span.mce_inserttime {background-position:-160px -20px}
+.o2k7Skin span.mce_absolute {background-position:-180px -20px}
+.o2k7Skin span.mce_backward {background-position:-200px -20px}
+.o2k7Skin span.mce_forward {background-position:-220px -20px}
+.o2k7Skin span.mce_insert_layer {background-position:-240px -20px}
+.o2k7Skin span.mce_insertlayer {background-position:-260px -20px}
+.o2k7Skin span.mce_movebackward {background-position:-280px -20px}
+.o2k7Skin span.mce_moveforward {background-position:-300px -20px}
+.o2k7Skin span.mce_media {background-position:-320px -20px}
+.o2k7Skin span.mce_nonbreaking {background-position:-340px -20px}
+.o2k7Skin span.mce_pastetext {background-position:-360px -20px}
+.o2k7Skin span.mce_pasteword {background-position:-380px -20px}
+.o2k7Skin span.mce_selectall {background-position:-400px -20px}
+.o2k7Skin span.mce_preview {background-position:-420px -20px}
+.o2k7Skin span.mce_print {background-position:-440px -20px}
+.o2k7Skin span.mce_cancel {background-position:-460px -20px}
+.o2k7Skin span.mce_save {background-position:-480px -20px}
+.o2k7Skin span.mce_replace {background-position:-500px -20px}
+.o2k7Skin span.mce_search {background-position:-520px -20px}
+.o2k7Skin span.mce_styleprops {background-position:-560px -20px}
+.o2k7Skin span.mce_table {background-position:-580px -20px}
+.o2k7Skin span.mce_cell_props {background-position:-600px -20px}
+.o2k7Skin span.mce_delete_table {background-position:-620px -20px}
+.o2k7Skin span.mce_delete_col {background-position:-640px -20px}
+.o2k7Skin span.mce_delete_row {background-position:-660px -20px}
+.o2k7Skin span.mce_col_after {background-position:-680px -20px}
+.o2k7Skin span.mce_col_before {background-position:-700px -20px}
+.o2k7Skin span.mce_row_after {background-position:-720px -20px}
+.o2k7Skin span.mce_row_before {background-position:-740px -20px}
+.o2k7Skin span.mce_merge_cells {background-position:-760px -20px}
+.o2k7Skin span.mce_table_props {background-position:-980px -20px}
+.o2k7Skin span.mce_row_props {background-position:-780px -20px}
+.o2k7Skin span.mce_split_cells {background-position:-800px -20px}
+.o2k7Skin span.mce_template {background-position:-820px -20px}
+.o2k7Skin span.mce_visualchars {background-position:-840px -20px}
+.o2k7Skin span.mce_abbr {background-position:-860px -20px}
+.o2k7Skin span.mce_acronym {background-position:-880px -20px}
+.o2k7Skin span.mce_attribs {background-position:-900px -20px}
+.o2k7Skin span.mce_cite {background-position:-920px -20px}
+.o2k7Skin span.mce_del {background-position:-940px -20px}
+.o2k7Skin span.mce_ins {background-position:-960px -20px}
+.o2k7Skin span.mce_pagebreak {background-position:0 -40px}
+.o2k7Skin span.mce_restoredraft {background-position:-20px -40px}
+.o2k7Skin span.mce_spellchecker {background-position:-540px -20px}
+.o2k7Skin span.mce_visualblocks {background-position: -40px -40px}
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/o2k7/ui_black.css b/askbot/media/js/tinymce/themes/advanced/skins/o2k7/ui_black.css
new file mode 100644
index 00000000..50c9b76a
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/o2k7/ui_black.css
@@ -0,0 +1,8 @@
+/* Black */
+.o2k7SkinBlack .mceToolbar .mceToolbarStart span, .o2k7SkinBlack .mceToolbar .mceToolbarEnd span, .o2k7SkinBlack .mceButton, .o2k7SkinBlack .mceSplitButton, .o2k7SkinBlack .mceSeparator, .o2k7SkinBlack .mceSplitButton a.mceOpen, .o2k7SkinBlack .mceListBox a.mceOpen {background-image:url(img/button_bg_black.png)}
+.o2k7SkinBlack td.mceToolbar, .o2k7SkinBlack td.mceStatusbar, .o2k7SkinBlack .mceMenuItemTitle a, .o2k7SkinBlack .mceMenuItemTitle span.mceText, .o2k7SkinBlack .mceStatusbar div, .o2k7SkinBlack .mceStatusbar span, .o2k7SkinBlack .mceStatusbar a {background:#535353; color:#FFF}
+.o2k7SkinBlack table.mceListBoxEnabled .mceText, o2k7SkinBlack .mceListBox .mceText {background:#FFF; border:1px solid #CBCFD4; border-bottom-color:#989FA9; border-right:0}
+.o2k7SkinBlack table.mceListBoxEnabled:hover .mceText, .o2k7SkinBlack .mceListBoxHover .mceText, .o2k7SkinBlack .mceListBoxSelected .mceText {background:#FFF; border:1px solid #FFBD69; border-right:0}
+.o2k7SkinBlack .mceExternalToolbar, .o2k7SkinBlack .mceListBox .mceText, .o2k7SkinBlack div.mceMenu, .o2k7SkinBlack table.mceLayout, .o2k7SkinBlack .mceMenuItemTitle a, .o2k7SkinBlack table.mceLayout tr.mceFirst td, .o2k7SkinBlack table.mceLayout, .o2k7SkinBlack .mceMenuItemTitle a, .o2k7SkinBlack table.mceLayout tr.mceLast td, .o2k7SkinBlack .mceIframeContainer {border-color: #535353;}
+.o2k7SkinBlack table.mceSplitButtonEnabled:hover a.mceAction, .o2k7SkinBlack .mceSplitButtonHover a.mceAction, .o2k7SkinBlack .mceSplitButtonSelected {background-image:url(img/button_bg_black.png)}
+.o2k7SkinBlack .mceMenu .mceMenuItemEnabled a:hover, .o2k7SkinBlack .mceMenu .mceMenuItemActive {background-color:#FFE7A1} \ No newline at end of file
diff --git a/askbot/media/js/tinymce/themes/advanced/skins/o2k7/ui_silver.css b/askbot/media/js/tinymce/themes/advanced/skins/o2k7/ui_silver.css
new file mode 100644
index 00000000..960a8e47
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/skins/o2k7/ui_silver.css
@@ -0,0 +1,5 @@
+/* Silver */
+.o2k7SkinSilver .mceToolbar .mceToolbarStart span, .o2k7SkinSilver .mceButton, .o2k7SkinSilver .mceSplitButton, .o2k7SkinSilver .mceSeparator, .o2k7SkinSilver .mceSplitButton a.mceOpen, .o2k7SkinSilver .mceListBox a.mceOpen {background-image:url(img/button_bg_silver.png)}
+.o2k7SkinSilver td.mceToolbar, .o2k7SkinSilver td.mceStatusbar, .o2k7SkinSilver .mceMenuItemTitle a {background:#eee}
+.o2k7SkinSilver .mceListBox .mceText {background:#FFF}
+.o2k7SkinSilver .mceExternalToolbar, .o2k7SkinSilver .mceListBox .mceText, .o2k7SkinSilver div.mceMenu, .o2k7SkinSilver table.mceLayout, .o2k7SkinSilver .mceMenuItemTitle a, .o2k7SkinSilver table.mceLayout tr.mceFirst td, .o2k7SkinSilver table.mceLayout, .o2k7SkinSilver .mceMenuItemTitle a, .o2k7SkinSilver table.mceLayout tr.mceLast td, .o2k7SkinSilver .mceIframeContainer {border-color: #bbb}
diff --git a/askbot/media/js/tinymce/themes/advanced/source_editor.htm b/askbot/media/js/tinymce/themes/advanced/source_editor.htm
new file mode 100644
index 00000000..dd973fcc
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/advanced/source_editor.htm
@@ -0,0 +1,25 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>{#advanced_dlg.code_title}</title>
+ <script type="text/javascript" src="../../tiny_mce_popup.js"></script>
+ <script type="text/javascript" src="js/source_editor.js"></script>
+</head>
+<body onresize="resizeInputs();" style="display:none; overflow:hidden;" spellcheck="false">
+ <form name="source" onsubmit="saveContent();return false;" action="#">
+ <div style="float: left" class="title"><label for="htmlSource">{#advanced_dlg.code_title}</label></div>
+
+ <div id="wrapline" style="float: right">
+ <input type="checkbox" name="wraped" id="wraped" onclick="toggleWordWrap(this);" class="wordWrapCode" /><label for="wraped">{#advanced_dlg.code_wordwrap}</label>
+ </div>
+
+ <br style="clear: both" />
+
+ <textarea name="htmlSource" id="htmlSource" rows="15" cols="100" style="width: 100%; height: 100%; font-family: 'Courier New',Courier,monospace; font-size: 12px;" dir="ltr" wrap="off" class="mceFocus"></textarea>
+
+ <div class="mceActionPanel">
+ <input type="submit" role="button" name="insert" value="{#update}" id="insert" />
+ <input type="button" role="button" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" id="cancel" />
+ </div>
+ </form>
+</body>
+</html>
diff --git a/askbot/media/js/tinymce/themes/simple/editor_template.js b/askbot/media/js/tinymce/themes/simple/editor_template.js
new file mode 100644
index 00000000..4b3209cc
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/simple/editor_template.js
@@ -0,0 +1 @@
+(function(){var a=tinymce.DOM;tinymce.ThemeManager.requireLangPack("simple");tinymce.create("tinymce.themes.SimpleTheme",{init:function(c,d){var e=this,b=["Bold","Italic","Underline","Strikethrough","InsertUnorderedList","InsertOrderedList"],f=c.settings;e.editor=c;c.contentCSS.push(d+"/skins/"+f.skin+"/content.css");c.onInit.add(function(){c.onNodeChange.add(function(h,g){tinymce.each(b,function(i){g.get(i.toLowerCase()).setActive(h.queryCommandState(i))})})});a.loadCSS((f.editor_css?c.documentBaseURI.toAbsolute(f.editor_css):"")||d+"/skins/"+f.skin+"/ui.css")},renderUI:function(h){var e=this,i=h.targetNode,b,c,d=e.editor,f=d.controlManager,g;i=a.insertAfter(a.create("span",{id:d.id+"_container","class":"mceEditor "+d.settings.skin+"SimpleSkin"}),i);i=g=a.add(i,"table",{cellPadding:0,cellSpacing:0,"class":"mceLayout"});i=c=a.add(i,"tbody");i=a.add(c,"tr");i=b=a.add(a.add(i,"td"),"div",{"class":"mceIframeContainer"});i=a.add(a.add(c,"tr",{"class":"last"}),"td",{"class":"mceToolbar mceLast",align:"center"});c=e.toolbar=f.createToolbar("tools1");c.add(f.createButton("bold",{title:"simple.bold_desc",cmd:"Bold"}));c.add(f.createButton("italic",{title:"simple.italic_desc",cmd:"Italic"}));c.add(f.createButton("underline",{title:"simple.underline_desc",cmd:"Underline"}));c.add(f.createButton("strikethrough",{title:"simple.striketrough_desc",cmd:"Strikethrough"}));c.add(f.createSeparator());c.add(f.createButton("undo",{title:"simple.undo_desc",cmd:"Undo"}));c.add(f.createButton("redo",{title:"simple.redo_desc",cmd:"Redo"}));c.add(f.createSeparator());c.add(f.createButton("cleanup",{title:"simple.cleanup_desc",cmd:"mceCleanup"}));c.add(f.createSeparator());c.add(f.createButton("insertunorderedlist",{title:"simple.bullist_desc",cmd:"InsertUnorderedList"}));c.add(f.createButton("insertorderedlist",{title:"simple.numlist_desc",cmd:"InsertOrderedList"}));c.renderTo(i);return{iframeContainer:b,editorContainer:d.id+"_container",sizeContainer:g,deltaHeight:-20}},getInfo:function(){return{longname:"Simple theme",author:"Moxiecode Systems AB",authorurl:"http://tinymce.moxiecode.com",version:tinymce.majorVersion+"."+tinymce.minorVersion}}});tinymce.ThemeManager.add("simple",tinymce.themes.SimpleTheme)})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/themes/simple/editor_template_src.js b/askbot/media/js/tinymce/themes/simple/editor_template_src.js
new file mode 100644
index 00000000..01ce87c5
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/simple/editor_template_src.js
@@ -0,0 +1,84 @@
+/**
+ * editor_template_src.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+(function() {
+ var DOM = tinymce.DOM;
+
+ // Tell it to load theme specific language pack(s)
+ tinymce.ThemeManager.requireLangPack('simple');
+
+ tinymce.create('tinymce.themes.SimpleTheme', {
+ init : function(ed, url) {
+ var t = this, states = ['Bold', 'Italic', 'Underline', 'Strikethrough', 'InsertUnorderedList', 'InsertOrderedList'], s = ed.settings;
+
+ t.editor = ed;
+ ed.contentCSS.push(url + "/skins/" + s.skin + "/content.css");
+
+ ed.onInit.add(function() {
+ ed.onNodeChange.add(function(ed, cm) {
+ tinymce.each(states, function(c) {
+ cm.get(c.toLowerCase()).setActive(ed.queryCommandState(c));
+ });
+ });
+ });
+
+ DOM.loadCSS((s.editor_css ? ed.documentBaseURI.toAbsolute(s.editor_css) : '') || url + "/skins/" + s.skin + "/ui.css");
+ },
+
+ renderUI : function(o) {
+ var t = this, n = o.targetNode, ic, tb, ed = t.editor, cf = ed.controlManager, sc;
+
+ n = DOM.insertAfter(DOM.create('span', {id : ed.id + '_container', 'class' : 'mceEditor ' + ed.settings.skin + 'SimpleSkin'}), n);
+ n = sc = DOM.add(n, 'table', {cellPadding : 0, cellSpacing : 0, 'class' : 'mceLayout'});
+ n = tb = DOM.add(n, 'tbody');
+
+ // Create iframe container
+ n = DOM.add(tb, 'tr');
+ n = ic = DOM.add(DOM.add(n, 'td'), 'div', {'class' : 'mceIframeContainer'});
+
+ // Create toolbar container
+ n = DOM.add(DOM.add(tb, 'tr', {'class' : 'last'}), 'td', {'class' : 'mceToolbar mceLast', align : 'center'});
+
+ // Create toolbar
+ tb = t.toolbar = cf.createToolbar("tools1");
+ tb.add(cf.createButton('bold', {title : 'simple.bold_desc', cmd : 'Bold'}));
+ tb.add(cf.createButton('italic', {title : 'simple.italic_desc', cmd : 'Italic'}));
+ tb.add(cf.createButton('underline', {title : 'simple.underline_desc', cmd : 'Underline'}));
+ tb.add(cf.createButton('strikethrough', {title : 'simple.striketrough_desc', cmd : 'Strikethrough'}));
+ tb.add(cf.createSeparator());
+ tb.add(cf.createButton('undo', {title : 'simple.undo_desc', cmd : 'Undo'}));
+ tb.add(cf.createButton('redo', {title : 'simple.redo_desc', cmd : 'Redo'}));
+ tb.add(cf.createSeparator());
+ tb.add(cf.createButton('cleanup', {title : 'simple.cleanup_desc', cmd : 'mceCleanup'}));
+ tb.add(cf.createSeparator());
+ tb.add(cf.createButton('insertunorderedlist', {title : 'simple.bullist_desc', cmd : 'InsertUnorderedList'}));
+ tb.add(cf.createButton('insertorderedlist', {title : 'simple.numlist_desc', cmd : 'InsertOrderedList'}));
+ tb.renderTo(n);
+
+ return {
+ iframeContainer : ic,
+ editorContainer : ed.id + '_container',
+ sizeContainer : sc,
+ deltaHeight : -20
+ };
+ },
+
+ getInfo : function() {
+ return {
+ longname : 'Simple theme',
+ author : 'Moxiecode Systems AB',
+ authorurl : 'http://tinymce.moxiecode.com',
+ version : tinymce.majorVersion + "." + tinymce.minorVersion
+ }
+ }
+ });
+
+ tinymce.ThemeManager.add('simple', tinymce.themes.SimpleTheme);
+})(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/themes/simple/img/icons.gif b/askbot/media/js/tinymce/themes/simple/img/icons.gif
new file mode 100644
index 00000000..6fcbcb5d
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/simple/img/icons.gif
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/simple/langs/en.js b/askbot/media/js/tinymce/themes/simple/langs/en.js
new file mode 100644
index 00000000..088ed0fc
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/simple/langs/en.js
@@ -0,0 +1 @@
+tinyMCE.addI18n('en.simple',{"cleanup_desc":"Cleanup Messy Code","redo_desc":"Redo (Ctrl+Y)","undo_desc":"Undo (Ctrl+Z)","numlist_desc":"Insert/Remove Numbered List","bullist_desc":"Insert/Remove Bulleted List","striketrough_desc":"Strikethrough","underline_desc":"Underline (Ctrl+U)","italic_desc":"Italic (Ctrl+I)","bold_desc":"Bold (Ctrl+B)"}); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/themes/simple/skins/default/content.css b/askbot/media/js/tinymce/themes/simple/skins/default/content.css
new file mode 100644
index 00000000..2506c807
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/simple/skins/default/content.css
@@ -0,0 +1,25 @@
+body, td, pre {
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-size: 10px;
+}
+
+body {
+ background-color: #FFFFFF;
+}
+
+.mceVisualAid {
+ border: 1px dashed #BBBBBB;
+}
+
+/* MSIE specific */
+
+* html body {
+ scrollbar-3dlight-color: #F0F0EE;
+ scrollbar-arrow-color: #676662;
+ scrollbar-base-color: #F0F0EE;
+ scrollbar-darkshadow-color: #DDDDDD;
+ scrollbar-face-color: #E0E0DD;
+ scrollbar-highlight-color: #F0F0EE;
+ scrollbar-shadow-color: #F0F0EE;
+ scrollbar-track-color: #F5F5F5;
+}
diff --git a/askbot/media/js/tinymce/themes/simple/skins/default/ui.css b/askbot/media/js/tinymce/themes/simple/skins/default/ui.css
new file mode 100644
index 00000000..076fe84e
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/simple/skins/default/ui.css
@@ -0,0 +1,32 @@
+/* Reset */
+.defaultSimpleSkin table, .defaultSimpleSkin tbody, .defaultSimpleSkin a, .defaultSimpleSkin img, .defaultSimpleSkin tr, .defaultSimpleSkin div, .defaultSimpleSkin td, .defaultSimpleSkin iframe, .defaultSimpleSkin span, .defaultSimpleSkin * {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000}
+
+/* Containers */
+.defaultSimpleSkin {position:relative}
+.defaultSimpleSkin table.mceLayout {background:#F0F0EE; border:1px solid #CCC;}
+.defaultSimpleSkin iframe {display:block; background:#FFF; border-bottom:1px solid #CCC;}
+.defaultSimpleSkin .mceToolbar {height:24px;}
+
+/* Layout */
+.defaultSimpleSkin span.mceIcon, .defaultSimpleSkin img.mceIcon {display:block; width:20px; height:20px}
+.defaultSimpleSkin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px}
+
+/* Button */
+.defaultSimpleSkin .mceButton {display:block; border:1px solid #F0F0EE; width:20px; height:20px}
+.defaultSimpleSkin a.mceButtonEnabled:hover {border:1px solid #0A246A; background-color:#B2BBD0}
+.defaultSimpleSkin a.mceButtonActive {border:1px solid #0A246A; background-color:#C2CBE0}
+.defaultSimpleSkin .mceButtonDisabled span {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+
+/* Separator */
+.defaultSimpleSkin .mceSeparator {display:block; background:url(../../img/icons.gif) -180px 0; width:2px; height:20px; margin:0 2px 0 4px}
+
+/* Theme */
+.defaultSimpleSkin span.mce_bold {background-position:0 0}
+.defaultSimpleSkin span.mce_italic {background-position:-60px 0}
+.defaultSimpleSkin span.mce_underline {background-position:-140px 0}
+.defaultSimpleSkin span.mce_strikethrough {background-position:-120px 0}
+.defaultSimpleSkin span.mce_undo {background-position:-160px 0}
+.defaultSimpleSkin span.mce_redo {background-position:-100px 0}
+.defaultSimpleSkin span.mce_cleanup {background-position:-40px 0}
+.defaultSimpleSkin span.mce_insertunorderedlist {background-position:-20px 0}
+.defaultSimpleSkin span.mce_insertorderedlist {background-position:-80px 0}
diff --git a/askbot/media/js/tinymce/themes/simple/skins/o2k7/content.css b/askbot/media/js/tinymce/themes/simple/skins/o2k7/content.css
new file mode 100644
index 00000000..595809fa
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/simple/skins/o2k7/content.css
@@ -0,0 +1,17 @@
+body, td, pre {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;}
+
+body {background: #FFF;}
+.mceVisualAid {border: 1px dashed #BBB;}
+
+/* IE */
+
+* html body {
+scrollbar-3dlight-color: #F0F0EE;
+scrollbar-arrow-color: #676662;
+scrollbar-base-color: #F0F0EE;
+scrollbar-darkshadow-color: #DDDDDD;
+scrollbar-face-color: #E0E0DD;
+scrollbar-highlight-color: #F0F0EE;
+scrollbar-shadow-color: #F0F0EE;
+scrollbar-track-color: #F5F5F5;
+}
diff --git a/askbot/media/js/tinymce/themes/simple/skins/o2k7/img/button_bg.png b/askbot/media/js/tinymce/themes/simple/skins/o2k7/img/button_bg.png
new file mode 100644
index 00000000..527e3495
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/simple/skins/o2k7/img/button_bg.png
Binary files differ
diff --git a/askbot/media/js/tinymce/themes/simple/skins/o2k7/ui.css b/askbot/media/js/tinymce/themes/simple/skins/o2k7/ui.css
new file mode 100644
index 00000000..cf6c35d1
--- /dev/null
+++ b/askbot/media/js/tinymce/themes/simple/skins/o2k7/ui.css
@@ -0,0 +1,35 @@
+/* Reset */
+.o2k7SimpleSkin table, .o2k7SimpleSkin tbody, .o2k7SimpleSkin a, .o2k7SimpleSkin img, .o2k7SimpleSkin tr, .o2k7SimpleSkin div, .o2k7SimpleSkin td, .o2k7SimpleSkin iframe, .o2k7SimpleSkin span, .o2k7SimpleSkin * {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000}
+
+/* Containers */
+.o2k7SimpleSkin {position:relative}
+.o2k7SimpleSkin table.mceLayout {background:#E5EFFD; border:1px solid #ABC6DD;}
+.o2k7SimpleSkin iframe {display:block; background:#FFF; border-bottom:1px solid #ABC6DD;}
+.o2k7SimpleSkin .mceToolbar {height:26px;}
+
+/* Layout */
+.o2k7SimpleSkin .mceToolbar .mceToolbarStart span {display:block; background:url(img/button_bg.png) -22px 0; width:1px; height:22px; }
+.o2k7SimpleSkin .mceToolbar .mceToolbarEnd span {display:block; background:url(img/button_bg.png) -22px 0; width:1px; height:22px}
+.o2k7SimpleSkin span.mceIcon, .o2k7SimpleSkin img.mceIcon {display:block; width:20px; height:20px}
+.o2k7SimpleSkin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px}
+
+/* Button */
+.o2k7SimpleSkin .mceButton {display:block; background:url(img/button_bg.png); width:22px; height:22px}
+.o2k7SimpleSkin a.mceButton span, .o2k7SimpleSkin a.mceButton img {margin:1px 0 0 1px}
+.o2k7SimpleSkin a.mceButtonEnabled:hover {background-color:#B2BBD0; background-position:0 -22px}
+.o2k7SimpleSkin a.mceButtonActive {background-position:0 -44px}
+.o2k7SimpleSkin .mceButtonDisabled span {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)}
+
+/* Separator */
+.o2k7SimpleSkin .mceSeparator {display:block; background:url(img/button_bg.png) -22px 0; width:5px; height:22px}
+
+/* Theme */
+.o2k7SimpleSkin span.mce_bold {background-position:0 0}
+.o2k7SimpleSkin span.mce_italic {background-position:-60px 0}
+.o2k7SimpleSkin span.mce_underline {background-position:-140px 0}
+.o2k7SimpleSkin span.mce_strikethrough {background-position:-120px 0}
+.o2k7SimpleSkin span.mce_undo {background-position:-160px 0}
+.o2k7SimpleSkin span.mce_redo {background-position:-100px 0}
+.o2k7SimpleSkin span.mce_cleanup {background-position:-40px 0}
+.o2k7SimpleSkin span.mce_insertunorderedlist {background-position:-20px 0}
+.o2k7SimpleSkin span.mce_insertorderedlist {background-position:-80px 0}
diff --git a/askbot/media/js/tinymce/tiny_mce.js b/askbot/media/js/tinymce/tiny_mce.js
new file mode 100644
index 00000000..ef712d82
--- /dev/null
+++ b/askbot/media/js/tinymce/tiny_mce.js
@@ -0,0 +1 @@
+(function(e){var a=/^\s*|\s*$/g,b,d="B".replace(/A(.)|B/,"$1")==="$1";var c={majorVersion:"3",minorVersion:"5.3",releaseDate:"2012-06-19",_init:function(){var s=this,q=document,o=navigator,g=o.userAgent,m,f,l,k,j,r;s.isOpera=e.opera&&opera.buildNumber;s.isWebKit=/WebKit/.test(g);s.isIE=!s.isWebKit&&!s.isOpera&&(/MSIE/gi).test(g)&&(/Explorer/gi).test(o.appName);s.isIE6=s.isIE&&/MSIE [56]/.test(g);s.isIE7=s.isIE&&/MSIE [7]/.test(g);s.isIE8=s.isIE&&/MSIE [8]/.test(g);s.isIE9=s.isIE&&/MSIE [9]/.test(g);s.isGecko=!s.isWebKit&&/Gecko/.test(g);s.isMac=g.indexOf("Mac")!=-1;s.isAir=/adobeair/i.test(g);s.isIDevice=/(iPad|iPhone)/.test(g);s.isIOS5=s.isIDevice&&g.match(/AppleWebKit\/(\d*)/)[1]>=534;if(e.tinyMCEPreInit){s.suffix=tinyMCEPreInit.suffix;s.baseURL=tinyMCEPreInit.base;s.query=tinyMCEPreInit.query;return}s.suffix="";f=q.getElementsByTagName("base");for(m=0;m<f.length;m++){r=f[m].href;if(r){if(/^https?:\/\/[^\/]+$/.test(r)){r+="/"}k=r?r.match(/.*\//)[0]:""}}function h(i){if(i.src&&/tiny_mce(|_gzip|_jquery|_prototype|_full)(_dev|_src)?.js/.test(i.src)){if(/_(src|dev)\.js/g.test(i.src)){s.suffix="_src"}if((j=i.src.indexOf("?"))!=-1){s.query=i.src.substring(j+1)}s.baseURL=i.src.substring(0,i.src.lastIndexOf("/"));if(k&&s.baseURL.indexOf("://")==-1&&s.baseURL.indexOf("/")!==0){s.baseURL=k+s.baseURL}return s.baseURL}return null}f=q.getElementsByTagName("script");for(m=0;m<f.length;m++){if(h(f[m])){return}}l=q.getElementsByTagName("head")[0];if(l){f=l.getElementsByTagName("script");for(m=0;m<f.length;m++){if(h(f[m])){return}}}return},is:function(g,f){if(!f){return g!==b}if(f=="array"&&(g.hasOwnProperty&&g instanceof Array)){return true}return typeof(g)==f},makeMap:function(f,j,h){var g;f=f||[];j=j||",";if(typeof(f)=="string"){f=f.split(j)}h=h||{};g=f.length;while(g--){h[f[g]]={}}return h},each:function(i,f,h){var j,g;if(!i){return 0}h=h||i;if(i.length!==b){for(j=0,g=i.length;j<g;j++){if(f.call(h,i[j],j,i)===false){return 0}}}else{for(j in i){if(i.hasOwnProperty(j)){if(f.call(h,i[j],j,i)===false){return 0}}}}return 1},map:function(g,h){var i=[];c.each(g,function(f){i.push(h(f))});return i},grep:function(g,h){var i=[];c.each(g,function(f){if(!h||h(f)){i.push(f)}});return i},inArray:function(g,h){var j,f;if(g){for(j=0,f=g.length;j<f;j++){if(g[j]===h){return j}}}return -1},extend:function(n,k){var j,f,h,g=arguments,m;for(j=1,f=g.length;j<f;j++){k=g[j];for(h in k){if(k.hasOwnProperty(h)){m=k[h];if(m!==b){n[h]=m}}}}return n},trim:function(f){return(f?""+f:"").replace(a,"")},create:function(o,f,j){var n=this,g,i,k,l,h,m=0;o=/^((static) )?([\w.]+)(:([\w.]+))?/.exec(o);k=o[3].match(/(^|\.)(\w+)$/i)[2];i=n.createNS(o[3].replace(/\.\w+$/,""),j);if(i[k]){return}if(o[2]=="static"){i[k]=f;if(this.onCreate){this.onCreate(o[2],o[3],i[k])}return}if(!f[k]){f[k]=function(){};m=1}i[k]=f[k];n.extend(i[k].prototype,f);if(o[5]){g=n.resolve(o[5]).prototype;l=o[5].match(/\.(\w+)$/i)[1];h=i[k];if(m){i[k]=function(){return g[l].apply(this,arguments)}}else{i[k]=function(){this.parent=g[l];return h.apply(this,arguments)}}i[k].prototype[k]=i[k];n.each(g,function(p,q){i[k].prototype[q]=g[q]});n.each(f,function(p,q){if(g[q]){i[k].prototype[q]=function(){this.parent=g[q];return p.apply(this,arguments)}}else{if(q!=k){i[k].prototype[q]=p}}})}n.each(f["static"],function(p,q){i[k][q]=p});if(this.onCreate){this.onCreate(o[2],o[3],i[k].prototype)}},walk:function(i,h,j,g){g=g||this;if(i){if(j){i=i[j]}c.each(i,function(k,f){if(h.call(g,k,f,j)===false){return false}c.walk(k,h,j,g)})}},createNS:function(j,h){var g,f;h=h||e;j=j.split(".");for(g=0;g<j.length;g++){f=j[g];if(!h[f]){h[f]={}}h=h[f]}return h},resolve:function(j,h){var g,f;h=h||e;j=j.split(".");for(g=0,f=j.length;g<f;g++){h=h[j[g]];if(!h){break}}return h},addUnload:function(j,i){var h=this,g;g=function(){var f=h.unloads,l,m;if(f){for(m in f){l=f[m];if(l&&l.func){l.func.call(l.scope,1)}}if(e.detachEvent){e.detachEvent("onbeforeunload",k);e.detachEvent("onunload",g)}else{if(e.removeEventListener){e.removeEventListener("unload",g,false)}}h.unloads=l=f=w=g=0;if(e.CollectGarbage){CollectGarbage()}}};function k(){var l=document;function f(){l.detachEvent("onstop",f);if(g){g()}l=0}if(l.readyState=="interactive"){if(l){l.attachEvent("onstop",f)}e.setTimeout(function(){if(l){l.detachEvent("onstop",f)}},0)}}j={func:j,scope:i||this};if(!h.unloads){if(e.attachEvent){e.attachEvent("onunload",g);e.attachEvent("onbeforeunload",k)}else{if(e.addEventListener){e.addEventListener("unload",g,false)}}h.unloads=[j]}else{h.unloads.push(j)}return j},removeUnload:function(i){var g=this.unloads,h=null;c.each(g,function(j,f){if(j&&j.func==i){g.splice(f,1);h=i;return false}});return h},explode:function(f,g){if(!f||c.is(f,"array")){return f}return c.map(f.split(g||","),c.trim)},_addVer:function(g){var f;if(!this.query){return g}f=(g.indexOf("?")==-1?"?":"&")+this.query;if(g.indexOf("#")==-1){return g+f}return g.replace("#",f+"#")},_replace:function(h,f,g){if(d){return g.replace(h,function(){var l=f,j=arguments,k;for(k=0;k<j.length-2;k++){if(j[k]===b){l=l.replace(new RegExp("\\$"+k,"g"),"")}else{l=l.replace(new RegExp("\\$"+k,"g"),j[k])}}return l})}return g.replace(h,f)}};c._init();e.tinymce=e.tinyMCE=c})(window);tinymce.create("tinymce.util.Dispatcher",{scope:null,listeners:null,inDispatch:false,Dispatcher:function(a){this.scope=a||this;this.listeners=[]},add:function(b,a){this.listeners.push({cb:b,scope:a||this.scope});return b},addToTop:function(d,b){var a=this,c={cb:d,scope:b||a.scope};if(a.inDispatch){a.listeners=[c].concat(a.listeners)}else{a.listeners.unshift(c)}return d},remove:function(c){var b=this.listeners,a=null;tinymce.each(b,function(e,d){if(c==e.cb){a=e;b.splice(d,1);return false}});return a},dispatch:function(){var a=this,e,b=arguments,c,d=a.listeners,f;a.inDispatch=true;for(c=0;c<d.length;c++){f=d[c];e=f.cb.apply(f.scope,b.length>0?b:[f.scope]);if(e===false){break}}a.inDispatch=false;return e}});(function(){var a=tinymce.each;tinymce.create("tinymce.util.URI",{URI:function(e,g){var f=this,i,d,c,h;e=tinymce.trim(e);g=f.settings=g||{};if(/^([\w\-]+):([^\/]{2})/i.test(e)||/^\s*#/.test(e)){f.source=e;return}if(e.indexOf("/")===0&&e.indexOf("//")!==0){e=(g.base_uri?g.base_uri.protocol||"http":"http")+"://mce_host"+e}if(!/^[\w\-]*:?\/\//.test(e)){h=g.base_uri?g.base_uri.path:new tinymce.util.URI(location.href).directory;e=((g.base_uri&&g.base_uri.protocol)||"http")+"://mce_host"+f.toAbsPath(h,e)}e=e.replace(/@@/g,"(mce_at)");e=/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(e);a(["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],function(b,j){var k=e[j];if(k){k=k.replace(/\(mce_at\)/g,"@@")}f[b]=k});c=g.base_uri;if(c){if(!f.protocol){f.protocol=c.protocol}if(!f.userInfo){f.userInfo=c.userInfo}if(!f.port&&f.host==="mce_host"){f.port=c.port}if(!f.host||f.host==="mce_host"){f.host=c.host}f.source=""}},setPath:function(c){var b=this;c=/^(.*?)\/?(\w+)?$/.exec(c);b.path=c[0];b.directory=c[1];b.file=c[2];b.source="";b.getURI()},toRelative:function(b){var d=this,f;if(b==="./"){return b}b=new tinymce.util.URI(b,{base_uri:d});if((b.host!="mce_host"&&d.host!=b.host&&b.host)||d.port!=b.port||d.protocol!=b.protocol){return b.getURI()}var c=d.getURI(),e=b.getURI();if(c==e||(c.charAt(c.length-1)=="/"&&c.substr(0,c.length-1)==e)){return c}f=d.toRelPath(d.path,b.path);if(b.query){f+="?"+b.query}if(b.anchor){f+="#"+b.anchor}return f},toAbsolute:function(b,c){b=new tinymce.util.URI(b,{base_uri:this});return b.getURI(this.host==b.host&&this.protocol==b.protocol?c:0)},toRelPath:function(g,h){var c,f=0,d="",e,b;g=g.substring(0,g.lastIndexOf("/"));g=g.split("/");c=h.split("/");if(g.length>=c.length){for(e=0,b=g.length;e<b;e++){if(e>=c.length||g[e]!=c[e]){f=e+1;break}}}if(g.length<c.length){for(e=0,b=c.length;e<b;e++){if(e>=g.length||g[e]!=c[e]){f=e+1;break}}}if(f===1){return h}for(e=0,b=g.length-(f-1);e<b;e++){d+="../"}for(e=f-1,b=c.length;e<b;e++){if(e!=f-1){d+="/"+c[e]}else{d+=c[e]}}return d},toAbsPath:function(e,f){var c,b=0,h=[],d,g;d=/\/$/.test(f)?"/":"";e=e.split("/");f=f.split("/");a(e,function(i){if(i){h.push(i)}});e=h;for(c=f.length-1,h=[];c>=0;c--){if(f[c].length===0||f[c]==="."){continue}if(f[c]===".."){b++;continue}if(b>0){b--;continue}h.push(f[c])}c=e.length-b;if(c<=0){g=h.reverse().join("/")}else{g=e.slice(0,c).join("/")+"/"+h.reverse().join("/")}if(g.indexOf("/")!==0){g="/"+g}if(d&&g.lastIndexOf("/")!==g.length-1){g+=d}return g},getURI:function(d){var c,b=this;if(!b.source||d){c="";if(!d){if(b.protocol){c+=b.protocol+"://"}if(b.userInfo){c+=b.userInfo+"@"}if(b.host){c+=b.host}if(b.port){c+=":"+b.port}}if(b.path){c+=b.path}if(b.query){c+="?"+b.query}if(b.anchor){c+="#"+b.anchor}b.source=c}return b.source}})})();(function(){var a=tinymce.each;tinymce.create("static tinymce.util.Cookie",{getHash:function(d){var b=this.get(d),c;if(b){a(b.split("&"),function(e){e=e.split("=");c=c||{};c[unescape(e[0])]=unescape(e[1])})}return c},setHash:function(j,b,g,f,i,c){var h="";a(b,function(e,d){h+=(!h?"":"&")+escape(d)+"="+escape(e)});this.set(j,h,g,f,i,c)},get:function(i){var h=document.cookie,g,f=i+"=",d;if(!h){return}d=h.indexOf("; "+f);if(d==-1){d=h.indexOf(f);if(d!==0){return null}}else{d+=2}g=h.indexOf(";",d);if(g==-1){g=h.length}return unescape(h.substring(d+f.length,g))},set:function(i,b,g,f,h,c){document.cookie=i+"="+escape(b)+((g)?"; expires="+g.toGMTString():"")+((f)?"; path="+escape(f):"")+((h)?"; domain="+h:"")+((c)?"; secure":"")},remove:function(c,e,d){var b=new Date();b.setTime(b.getTime()-1000);this.set(c,"",b,e,d)}})})();(function(){function serialize(o,quote){var i,v,t,name;quote=quote||'"';if(o==null){return"null"}t=typeof o;if(t=="string"){v="\bb\tt\nn\ff\rr\"\"''\\\\";return quote+o.replace(/([\u0080-\uFFFF\x00-\x1f\"\'\\])/g,function(a,b){if(quote==='"'&&a==="'"){return a}i=v.indexOf(b);if(i+1){return"\\"+v.charAt(i+1)}a=b.charCodeAt().toString(16);return"\\u"+"0000".substring(a.length)+a})+quote}if(t=="object"){if(o.hasOwnProperty&&o instanceof Array){for(i=0,v="[";i<o.length;i++){v+=(i>0?",":"")+serialize(o[i],quote)}return v+"]"}v="{";for(name in o){if(o.hasOwnProperty(name)){v+=typeof o[name]!="function"?(v.length>1?","+quote:quote)+name+quote+":"+serialize(o[name],quote):""}}return v+"}"}return""+o}tinymce.util.JSON={serialize:serialize,parse:function(s){try{return eval("("+s+")")}catch(ex){}}}})();tinymce.create("static tinymce.util.XHR",{send:function(g){var a,e,b=window,h=0;function f(){if(!g.async||a.readyState==4||h++>10000){if(g.success&&h<10000&&a.status==200){g.success.call(g.success_scope,""+a.responseText,a,g)}else{if(g.error){g.error.call(g.error_scope,h>10000?"TIMED_OUT":"GENERAL",a,g)}}a=null}else{b.setTimeout(f,10)}}g.scope=g.scope||this;g.success_scope=g.success_scope||g.scope;g.error_scope=g.error_scope||g.scope;g.async=g.async===false?false:true;g.data=g.data||"";function d(i){a=0;try{a=new ActiveXObject(i)}catch(c){}return a}a=b.XMLHttpRequest?new XMLHttpRequest():d("Microsoft.XMLHTTP")||d("Msxml2.XMLHTTP");if(a){if(a.overrideMimeType){a.overrideMimeType(g.content_type)}a.open(g.type||(g.data?"POST":"GET"),g.url,g.async);if(g.content_type){a.setRequestHeader("Content-Type",g.content_type)}a.setRequestHeader("X-Requested-With","XMLHttpRequest");a.send(g.data);if(!g.async){return f()}e=b.setTimeout(f,10)}}});(function(){var c=tinymce.extend,b=tinymce.util.JSON,a=tinymce.util.XHR;tinymce.create("tinymce.util.JSONRequest",{JSONRequest:function(d){this.settings=c({},d);this.count=0},send:function(f){var e=f.error,d=f.success;f=c(this.settings,f);f.success=function(h,g){h=b.parse(h);if(typeof(h)=="undefined"){h={error:"JSON Parse error."}}if(h.error){e.call(f.error_scope||f.scope,h.error,g)}else{d.call(f.success_scope||f.scope,h.result)}};f.error=function(h,g){if(e){e.call(f.error_scope||f.scope,h,g)}};f.data=b.serialize({id:f.id||"c"+(this.count++),method:f.method,params:f.params});f.content_type="application/json";a.send(f)},"static":{sendRPC:function(d){return new tinymce.util.JSONRequest().send(d)}}})}());(function(a){a.VK={BACKSPACE:8,DELETE:46,DOWN:40,ENTER:13,LEFT:37,RIGHT:39,SPACEBAR:32,TAB:9,UP:38,modifierPressed:function(b){return b.shiftKey||b.ctrlKey||b.altKey}}})(tinymce);tinymce.util.Quirks=function(d){var l=tinymce.VK,s=l.BACKSPACE,t=l.DELETE,o=d.dom,C=d.selection,r=d.settings;function c(G,F){try{d.getDoc().execCommand(G,false,F)}catch(E){}}function x(){var E=d.getDoc().documentMode;return E?E:6}function i(){function E(H){var F,J,G,I;F=C.getRng();J=o.getParent(F.startContainer,o.isBlock);if(H){J=o.getNext(J,o.isBlock)}if(J){G=J.firstChild;while(G&&G.nodeType==3&&G.nodeValue.length===0){G=G.nextSibling}if(G&&G.nodeName==="SPAN"){I=G.cloneNode(false)}}d.getDoc().execCommand(H?"ForwardDelete":"Delete",false,null);J=o.getParent(F.startContainer,o.isBlock);tinymce.each(o.select("span.Apple-style-span,font.Apple-style-span",J),function(K){var L=C.getBookmark();if(I){o.replace(I.cloneNode(false),K,true)}else{o.remove(K,true)}C.moveToBookmark(L)})}d.onKeyDown.add(function(F,H){var G;G=H.keyCode==t;if(!H.isDefaultPrevented()&&(G||H.keyCode==s)&&!l.modifierPressed(H)){H.preventDefault();E(G)}});d.addCommand("Delete",function(){E()})}function D(){function F(H,K){var G,J,I=K?"start":"end";G=H[I+"Container"];J=H[I+"Offset"];if(G.nodeType==1&&G.hasChildNodes()){G=G.childNodes[Math.min(K?J:(J>0?J-1:0),G.childNodes.length-1)]}return G}function E(J,N){var I,M,H,K,L=N?"start":"end",G;I=J[L+"Container"];M=J[L+"Offset"];H=o.getRoot();if(I.nodeType==1){G=M>=I.childNodes.length;I=F(J,N);if(I.nodeType==3){M=N&&!G?0:I.nodeValue.length}}if(I.nodeType==3&&((N&&M>0)||(!N&&M<I.nodeValue.length))){return false}while(I!==H){K=I.parentNode[N?"firstChild":"lastChild"];if(K.nodeName=="BR"){K=K[N?"nextSibling":"previousSibling"]||K}if(K!==I){return false}I=I.parentNode}return true}d.onKeyDown.addToTop(function(H,J){var G,I=J.keyCode;if(!J.isDefaultPrevented()&&(I==t||I==s)){G=C.getRng(true);if(E(G,true)&&E(G,false)&&(G.collapsed||o.findCommonAncestor(F(G,true),F(G))===o.getRoot())){H.setContent("");H.selection.setCursorLocation(H.getBody(),0);H.nodeChanged();J.preventDefault()}}})}function v(){if(!d.settings.content_editable){o.bind(d.getDoc(),"focusin",function(E){C.setRng(C.getRng())});o.bind(d.getDoc(),"mousedown",function(E){if(E.target==d.getDoc().documentElement){d.getWin().focus();C.setRng(C.getRng())}})}}function m(){d.onKeyDown.add(function(E,H){if(!H.isDefaultPrevented()&&H.keyCode===s){if(C.isCollapsed()&&C.getRng(true).startOffset===0){var G=C.getNode();var F=G.previousSibling;if(F&&F.nodeName&&F.nodeName.toLowerCase()==="hr"){o.remove(F);tinymce.dom.Event.cancel(H)}}}})}function b(){if(!Range.prototype.getClientRects){d.onMouseDown.add(function(F,G){if(G.target.nodeName==="HTML"){var E=F.getBody();E.blur();setTimeout(function(){E.focus()},0)}})}}function z(){d.onClick.add(function(E,F){F=F.target;if(/^(IMG|HR)$/.test(F.nodeName)){C.getSel().setBaseAndExtent(F,0,F,1)}if(F.nodeName=="A"&&o.hasClass(F,"mceItemAnchor")){C.select(F)}E.nodeChanged()})}function A(){function F(){var H=o.getAttribs(C.getStart().cloneNode(false));return function(){var I=C.getStart();if(I!==d.getBody()){o.setAttrib(I,"style",null);tinymce.each(H,function(J){I.setAttributeNode(J.cloneNode(true))})}}}function E(){return !C.isCollapsed()&&C.getStart()!=C.getEnd()}function G(H,I){I.preventDefault();return false}d.onKeyPress.add(function(H,J){var I;if((J.keyCode==8||J.keyCode==46)&&E()){I=F();H.getDoc().execCommand("delete",false,null);I();J.preventDefault();return false}});o.bind(d.getDoc(),"cut",function(I){var H;if(E()){H=F();d.onKeyUp.addToTop(G);setTimeout(function(){H();d.onKeyUp.remove(G)},0)}})}function j(){var F,E;o.bind(d.getDoc(),"selectionchange",function(){if(E){clearTimeout(E);E=0}E=window.setTimeout(function(){var G=C.getRng();if(!F||!tinymce.dom.RangeUtils.compareRanges(G,F)){d.nodeChanged();F=G}},50)})}function B(){document.body.setAttribute("role","application")}function y(){d.onKeyDown.add(function(E,G){if(!G.isDefaultPrevented()&&G.keyCode===s){if(C.isCollapsed()&&C.getRng(true).startOffset===0){var F=C.getNode().previousSibling;if(F&&F.nodeName&&F.nodeName.toLowerCase()==="table"){return tinymce.dom.Event.cancel(G)}}}})}function g(){if(x()>7){return}c("RespectVisibilityInDesign",true);d.contentStyles.push(".mceHideBrInPre pre br {display: none}");o.addClass(d.getBody(),"mceHideBrInPre");d.parser.addNodeFilter("pre",function(E,G){var H=E.length,J,F,K,I;while(H--){J=E[H].getAll("br");F=J.length;while(F--){K=J[F];I=K.prev;if(I&&I.type===3&&I.value.charAt(I.value-1)!="\n"){I.value+="\n"}else{K.parent.insert(new tinymce.html.Node("#text",3),K,true).value="\n"}}}});d.serializer.addNodeFilter("pre",function(E,G){var H=E.length,J,F,K,I;while(H--){J=E[H].getAll("br");F=J.length;while(F--){K=J[F];I=K.prev;if(I&&I.type==3){I.value=I.value.replace(/\r?\n$/,"")}}}})}function f(){o.bind(d.getBody(),"mouseup",function(G){var F,E=C.getNode();if(E.nodeName=="IMG"){if(F=o.getStyle(E,"width")){o.setAttrib(E,"width",F.replace(/[^0-9%]+/g,""));o.setStyle(E,"width","")}if(F=o.getStyle(E,"height")){o.setAttrib(E,"height",F.replace(/[^0-9%]+/g,""));o.setStyle(E,"height","")}}})}function q(){d.onKeyDown.add(function(K,L){var J,E,F,H,I,M,G;J=L.keyCode==t;if(!L.isDefaultPrevented()&&(J||L.keyCode==s)&&!l.modifierPressed(L)){E=C.getRng();F=E.startContainer;H=E.startOffset;G=E.collapsed;if(F.nodeType==3&&F.nodeValue.length>0&&((H===0&&!G)||(G&&H===(J?0:1)))){nonEmptyElements=K.schema.getNonEmptyElements();L.preventDefault();I=o.create("br",{id:"__tmp"});F.parentNode.insertBefore(I,F);K.getDoc().execCommand(J?"ForwardDelete":"Delete",false,null);F=C.getRng().startContainer;M=F.previousSibling;if(M&&M.nodeType==1&&!o.isBlock(M)&&o.isEmpty(M)&&!nonEmptyElements[M.nodeName.toLowerCase()]){o.remove(M)}o.remove("__tmp")}}})}function e(){d.onKeyDown.add(function(I,J){var G,F,K,E,H;if(J.isDefaultPrevented()||J.keyCode!=l.BACKSPACE){return}G=C.getRng();F=G.startContainer;K=G.startOffset;E=o.getRoot();H=F;if(!G.collapsed||K!==0){return}while(H&&H.parentNode&&H.parentNode.firstChild==H&&H.parentNode!=E){H=H.parentNode}if(H.tagName==="BLOCKQUOTE"){I.formatter.toggle("blockquote",null,H);G.setStart(F,0);G.setEnd(F,0);C.setRng(G);C.collapse(false)}})}function k(){function E(){d._refreshContentEditable();c("StyleWithCSS",false);c("enableInlineTableEditing",false);if(!r.object_resizing){c("enableObjectResizing",false)}}if(!r.readonly){d.onBeforeExecCommand.add(E);d.onMouseDown.add(E)}}function n(){function E(F,G){tinymce.each(o.select("a"),function(J){var H=J.parentNode,I=o.getRoot();if(H.lastChild===J){while(H&&!o.isBlock(H)){if(H.parentNode.lastChild!==H||H===I){return}H=H.parentNode}o.add(H,"br",{"data-mce-bogus":1})}})}d.onExecCommand.add(function(F,G){if(G==="CreateLink"){E(F)}});d.onSetContent.add(C.onSetContent.add(E))}function u(){if(r.forced_root_block){d.onInit.add(function(){c("DefaultParagraphSeparator",r.forced_root_block)})}}function a(){function E(G,F){if(!G||!F.initial){d.execCommand("mceRepaint")}}d.onUndo.add(E);d.onRedo.add(E);d.onSetContent.add(E)}function p(){d.onKeyDown.add(function(F,G){var E;if(!G.isDefaultPrevented()&&G.keyCode==s){E=F.getDoc().selection.createRange();if(E&&E.item){G.preventDefault();F.undoManager.beforeChange();o.remove(E.item(0));F.undoManager.add()}}})}function h(){var E;if(x()>=10){E="";tinymce.each("p div h1 h2 h3 h4 h5 h6".split(" "),function(F,G){E+=(G>0?",":"")+F+":empty"});d.contentStyles.push(E+"{padding-right: 1px !important}")}}y();e();D();if(tinymce.isWebKit){q();i();v();z();u();if(tinymce.isIDevice){j()}}if(tinymce.isIE){m();B();g();f();p();h()}if(tinymce.isGecko){m();b();A();k();n();a()}};(function(j){var a,g,d,k=/[&<>\"\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,b=/[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,f=/[<>&\"\']/g,c=/&(#x|#)?([\w]+);/g,i={128:"\u20AC",130:"\u201A",131:"\u0192",132:"\u201E",133:"\u2026",134:"\u2020",135:"\u2021",136:"\u02C6",137:"\u2030",138:"\u0160",139:"\u2039",140:"\u0152",142:"\u017D",145:"\u2018",146:"\u2019",147:"\u201C",148:"\u201D",149:"\u2022",150:"\u2013",151:"\u2014",152:"\u02DC",153:"\u2122",154:"\u0161",155:"\u203A",156:"\u0153",158:"\u017E",159:"\u0178"};g={'"':"&quot;","'":"&#39;","<":"&lt;",">":"&gt;","&":"&amp;"};d={"&lt;":"<","&gt;":">","&amp;":"&","&quot;":'"',"&apos;":"'"};function h(l){var m;m=document.createElement("div");m.innerHTML=l;return m.textContent||m.innerText||l}function e(m,p){var n,o,l,q={};if(m){m=m.split(",");p=p||10;for(n=0;n<m.length;n+=2){o=String.fromCharCode(parseInt(m[n],p));if(!g[o]){l="&"+m[n+1]+";";q[o]=l;q[l]=o}}return q}}a=e("50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,t9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro",32);j.html=j.html||{};j.html.Entities={encodeRaw:function(m,l){return m.replace(l?k:b,function(n){return g[n]||n})},encodeAllRaw:function(l){return(""+l).replace(f,function(m){return g[m]||m})},encodeNumeric:function(m,l){return m.replace(l?k:b,function(n){if(n.length>1){return"&#"+(((n.charCodeAt(0)-55296)*1024)+(n.charCodeAt(1)-56320)+65536)+";"}return g[n]||"&#"+n.charCodeAt(0)+";"})},encodeNamed:function(n,l,m){m=m||a;return n.replace(l?k:b,function(o){return g[o]||m[o]||o})},getEncodeFunc:function(l,o){var p=j.html.Entities;o=e(o)||a;function m(r,q){return r.replace(q?k:b,function(s){return g[s]||o[s]||"&#"+s.charCodeAt(0)+";"||s})}function n(r,q){return p.encodeNamed(r,q,o)}l=j.makeMap(l.replace(/\+/g,","));if(l.named&&l.numeric){return m}if(l.named){if(o){return n}return p.encodeNamed}if(l.numeric){return p.encodeNumeric}return p.encodeRaw},decode:function(l){return l.replace(c,function(n,m,o){if(m){o=parseInt(o,m.length===2?16:10);if(o>65535){o-=65536;return String.fromCharCode(55296+(o>>10),56320+(o&1023))}else{return i[o]||String.fromCharCode(o)}}return d[n]||a[n]||h(n)})}}})(tinymce);tinymce.html.Styles=function(d,f){var k=/rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi,h=/(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi,b=/\s*([^:]+):\s*([^;]+);?/g,l=/\s+$/,m=/rgb/,e,g,a={},j;d=d||{};j="\\\" \\' \\; \\: ; : \uFEFF".split(" ");for(g=0;g<j.length;g++){a[j[g]]="\uFEFF"+g;a["\uFEFF"+g]=j[g]}function c(n,q,p,i){function o(r){r=parseInt(r).toString(16);return r.length>1?r:"0"+r}return"#"+o(q)+o(p)+o(i)}return{toHex:function(i){return i.replace(k,c)},parse:function(s){var z={},q,n,x,r,v=d.url_converter,y=d.url_converter_scope||this;function p(D,G){var F,C,B,E;F=z[D+"-top"+G];if(!F){return}C=z[D+"-right"+G];if(F!=C){return}B=z[D+"-bottom"+G];if(C!=B){return}E=z[D+"-left"+G];if(B!=E){return}z[D+G]=E;delete z[D+"-top"+G];delete z[D+"-right"+G];delete z[D+"-bottom"+G];delete z[D+"-left"+G]}function u(C){var D=z[C],B;if(!D||D.indexOf(" ")<0){return}D=D.split(" ");B=D.length;while(B--){if(D[B]!==D[0]){return false}}z[C]=D[0];return true}function A(D,C,B,E){if(!u(C)){return}if(!u(B)){return}if(!u(E)){return}z[D]=z[C]+" "+z[B]+" "+z[E];delete z[C];delete z[B];delete z[E]}function t(B){r=true;return a[B]}function i(C,B){if(r){C=C.replace(/\uFEFF[0-9]/g,function(D){return a[D]})}if(!B){C=C.replace(/\\([\'\";:])/g,"$1")}return C}function o(C,B,F,E,G,D){G=G||D;if(G){G=i(G);return"'"+G.replace(/\'/g,"\\'")+"'"}B=i(B||F||E);if(v){B=v.call(y,B,"style")}return"url('"+B.replace(/\'/g,"\\'")+"')"}if(s){s=s.replace(/\\[\"\';:\uFEFF]/g,t).replace(/\"[^\"]+\"|\'[^\']+\'/g,function(B){return B.replace(/[;:]/g,t)});while(q=b.exec(s)){n=q[1].replace(l,"").toLowerCase();x=q[2].replace(l,"");if(n&&x.length>0){if(n==="font-weight"&&x==="700"){x="bold"}else{if(n==="color"||n==="background-color"){x=x.toLowerCase()}}x=x.replace(k,c);x=x.replace(h,o);z[n]=r?i(x,true):x}b.lastIndex=q.index+q[0].length}p("border","");p("border","-width");p("border","-color");p("border","-style");p("padding","");p("margin","");A("border","border-width","border-style","border-color");if(z.border==="medium none"){delete z.border}}return z},serialize:function(p,r){var o="",n,q;function i(t){var x,u,s,v;x=f.styles[t];if(x){for(u=0,s=x.length;u<s;u++){t=x[u];v=p[t];if(v!==e&&v.length>0){o+=(o.length>0?" ":"")+t+": "+v+";"}}}}if(r&&f&&f.styles){i("*");i(r)}else{for(n in p){q=p[n];if(q!==e&&q.length>0){o+=(o.length>0?" ":"")+n+": "+q+";"}}}return o}}};(function(f){var a={},e=f.makeMap,g=f.each;function d(j,i){return j.split(i||",")}function h(m,l){var j,k={};function i(n){return n.replace(/[A-Z]+/g,function(o){return i(m[o])})}for(j in m){if(m.hasOwnProperty(j)){m[j]=i(m[j])}}i(l).replace(/#/g,"#text").replace(/(\w+)\[([^\]]+)\]\[([^\]]*)\]/g,function(q,o,n,p){n=d(n,"|");k[o]={attributes:e(n),attributesOrder:n,children:e(p,"|",{"#comment":{}})}});return k}function b(){var i=a.html5;if(!i){i=a.html5=h({A:"id|accesskey|class|dir|draggable|item|hidden|itemprop|role|spellcheck|style|subject|title",B:"#|a|abbr|area|audio|b|bdo|br|button|canvas|cite|code|command|datalist|del|dfn|em|embed|i|iframe|img|input|ins|kbd|keygen|label|link|map|mark|meta|meter|noscript|object|output|progress|q|ruby|samp|script|select|small|span|strong|sub|sup|svg|textarea|time|var|video|wbr",C:"#|a|abbr|area|address|article|aside|audio|b|bdo|blockquote|br|button|canvas|cite|code|command|datalist|del|details|dfn|dialog|div|dl|em|embed|fieldset|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hgroup|hr|i|iframe|img|input|ins|kbd|keygen|label|link|map|mark|menu|meta|meter|nav|noscript|ol|object|output|p|pre|progress|q|ruby|samp|script|section|select|small|span|strong|style|sub|sup|svg|table|textarea|time|ul|var|video"},"html[A|manifest][body|head]head[A][base|command|link|meta|noscript|script|style|title]title[A][#]base[A|href|target][]link[A|href|rel|media|type|sizes][]meta[A|http-equiv|name|content|charset][]style[A|type|media|scoped][#]script[A|charset|type|src|defer|async][#]noscript[A][C]body[A][C]section[A][C]nav[A][C]article[A][C]aside[A][C]h1[A][B]h2[A][B]h3[A][B]h4[A][B]h5[A][B]h6[A][B]hgroup[A][h1|h2|h3|h4|h5|h6]header[A][C]footer[A][C]address[A][C]p[A][B]br[A][]pre[A][B]dialog[A][dd|dt]blockquote[A|cite][C]ol[A|start|reversed][li]ul[A][li]li[A|value][C]dl[A][dd|dt]dt[A][B]dd[A][C]a[A|href|target|ping|rel|media|type][B]em[A][B]strong[A][B]small[A][B]cite[A][B]q[A|cite][B]dfn[A][B]abbr[A][B]code[A][B]var[A][B]samp[A][B]kbd[A][B]sub[A][B]sup[A][B]i[A][B]b[A][B]mark[A][B]progress[A|value|max][B]meter[A|value|min|max|low|high|optimum][B]time[A|datetime][B]ruby[A][B|rt|rp]rt[A][B]rp[A][B]bdo[A][B]span[A][B]ins[A|cite|datetime][B]del[A|cite|datetime][B]figure[A][C|legend|figcaption]figcaption[A][C]img[A|alt|src|height|width|usemap|ismap][]iframe[A|name|src|height|width|sandbox|seamless][]embed[A|src|height|width|type][]object[A|data|type|height|width|usemap|name|form|classid][param]param[A|name|value][]details[A|open][C|legend]command[A|type|label|icon|disabled|checked|radiogroup][]menu[A|type|label][C|li]legend[A][C|B]div[A][C]source[A|src|type|media][]audio[A|src|autobuffer|autoplay|loop|controls][source]video[A|src|autobuffer|autoplay|loop|controls|width|height|poster][source]hr[A][]form[A|accept-charset|action|autocomplete|enctype|method|name|novalidate|target][C]fieldset[A|disabled|form|name][C|legend]label[A|form|for][B]input[A|type|accept|alt|autocomplete|checked|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|height|list|max|maxlength|min|multiple|pattern|placeholder|readonly|required|size|src|step|width|files|value|name][]button[A|autofocus|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|name|value|type][B]select[A|autofocus|disabled|form|multiple|name|size][option|optgroup]datalist[A][B|option]optgroup[A|disabled|label][option]option[A|disabled|selected|label|value][]textarea[A|autofocus|disabled|form|maxlength|name|placeholder|readonly|required|rows|cols|wrap][]keygen[A|autofocus|challenge|disabled|form|keytype|name][]output[A|for|form|name][B]canvas[A|width|height][]map[A|name][B|C]area[A|shape|coords|href|alt|target|media|rel|ping|type][]mathml[A][]svg[A][]table[A|border][caption|colgroup|thead|tfoot|tbody|tr]caption[A][C]colgroup[A|span][col]col[A|span][]thead[A][tr]tfoot[A][tr]tbody[A][tr]tr[A][th|td]th[A|headers|rowspan|colspan|scope][B]td[A|headers|rowspan|colspan][C]wbr[A][]")}return i}function c(){var i=a.html4;if(!i){i=a.html4=h({Z:"H|K|N|O|P",Y:"X|form|R|Q",ZG:"E|span|width|align|char|charoff|valign",X:"p|T|div|U|W|isindex|fieldset|table",ZF:"E|align|char|charoff|valign",W:"pre|hr|blockquote|address|center|noframes",ZE:"abbr|axis|headers|scope|rowspan|colspan|align|char|charoff|valign|nowrap|bgcolor|width|height",ZD:"[E][S]",U:"ul|ol|dl|menu|dir",ZC:"p|Y|div|U|W|table|br|span|bdo|object|applet|img|map|K|N|Q",T:"h1|h2|h3|h4|h5|h6",ZB:"X|S|Q",S:"R|P",ZA:"a|G|J|M|O|P",R:"a|H|K|N|O",Q:"noscript|P",P:"ins|del|script",O:"input|select|textarea|label|button",N:"M|L",M:"em|strong|dfn|code|q|samp|kbd|var|cite|abbr|acronym",L:"sub|sup",K:"J|I",J:"tt|i|b|u|s|strike",I:"big|small|font|basefont",H:"G|F",G:"br|span|bdo",F:"object|applet|img|map|iframe",E:"A|B|C",D:"accesskey|tabindex|onfocus|onblur",C:"onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup",B:"lang|xml:lang|dir",A:"id|class|style|title"},"script[id|charset|type|language|src|defer|xml:space][]style[B|id|type|media|title|xml:space][]object[E|declare|classid|codebase|data|type|codetype|archive|standby|width|height|usemap|name|tabindex|align|border|hspace|vspace][#|param|Y]param[id|name|value|valuetype|type][]p[E|align][#|S]a[E|D|charset|type|name|href|hreflang|rel|rev|shape|coords|target][#|Z]br[A|clear][]span[E][#|S]bdo[A|C|B][#|S]applet[A|codebase|archive|code|object|alt|name|width|height|align|hspace|vspace][#|param|Y]h1[E|align][#|S]img[E|src|alt|name|longdesc|width|height|usemap|ismap|align|border|hspace|vspace][]map[B|C|A|name][X|form|Q|area]h2[E|align][#|S]iframe[A|longdesc|name|src|frameborder|marginwidth|marginheight|scrolling|align|width|height][#|Y]h3[E|align][#|S]tt[E][#|S]i[E][#|S]b[E][#|S]u[E][#|S]s[E][#|S]strike[E][#|S]big[E][#|S]small[E][#|S]font[A|B|size|color|face][#|S]basefont[id|size|color|face][]em[E][#|S]strong[E][#|S]dfn[E][#|S]code[E][#|S]q[E|cite][#|S]samp[E][#|S]kbd[E][#|S]var[E][#|S]cite[E][#|S]abbr[E][#|S]acronym[E][#|S]sub[E][#|S]sup[E][#|S]input[E|D|type|name|value|checked|disabled|readonly|size|maxlength|src|alt|usemap|onselect|onchange|accept|align][]select[E|name|size|multiple|disabled|tabindex|onfocus|onblur|onchange][optgroup|option]optgroup[E|disabled|label][option]option[E|selected|disabled|label|value][]textarea[E|D|name|rows|cols|disabled|readonly|onselect|onchange][]label[E|for|accesskey|onfocus|onblur][#|S]button[E|D|name|value|type|disabled][#|p|T|div|U|W|table|G|object|applet|img|map|K|N|Q]h4[E|align][#|S]ins[E|cite|datetime][#|Y]h5[E|align][#|S]del[E|cite|datetime][#|Y]h6[E|align][#|S]div[E|align][#|Y]ul[E|type|compact][li]li[E|type|value][#|Y]ol[E|type|compact|start][li]dl[E|compact][dt|dd]dt[E][#|S]dd[E][#|Y]menu[E|compact][li]dir[E|compact][li]pre[E|width|xml:space][#|ZA]hr[E|align|noshade|size|width][]blockquote[E|cite][#|Y]address[E][#|S|p]center[E][#|Y]noframes[E][#|Y]isindex[A|B|prompt][]fieldset[E][#|legend|Y]legend[E|accesskey|align][#|S]table[E|summary|width|border|frame|rules|cellspacing|cellpadding|align|bgcolor][caption|col|colgroup|thead|tfoot|tbody|tr]caption[E|align][#|S]col[ZG][]colgroup[ZG][col]thead[ZF][tr]tr[ZF|bgcolor][th|td]th[E|ZE][#|Y]form[E|action|method|name|enctype|onsubmit|onreset|accept|accept-charset|target][#|X|R|Q]noscript[E][#|Y]td[E|ZE][#|Y]tfoot[ZF][tr]tbody[ZF][tr]area[E|D|shape|coords|href|nohref|alt|target][]base[id|href|target][]body[E|onload|onunload|background|bgcolor|text|link|vlink|alink][#|Y]")}return i}f.html.Schema=function(A){var u=this,s={},k={},j=[],D,y;var o,q,z,r,v,n,p={};function m(F,E,H){var G=A[F];if(!G){G=a[F];if(!G){G=e(E," ",e(E.toUpperCase()," "));G=f.extend(G,H);a[F]=G}}else{G=e(G,",",e(G.toUpperCase()," "))}return G}A=A||{};y=A.schema=="html5"?b():c();if(A.verify_html===false){A.valid_elements="*[*]"}if(A.valid_styles){D={};g(A.valid_styles,function(F,E){D[E]=f.explode(F)})}o=m("whitespace_elements","pre script style textarea");q=m("self_closing_elements","colgroup dd dt li option p td tfoot th thead tr");z=m("short_ended_elements","area base basefont br col frame hr img input isindex link meta param embed source wbr");r=m("boolean_attributes","checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected autoplay loop controls");n=m("non_empty_elements","td th iframe video audio object",z);v=m("block_elements","h1 h2 h3 h4 h5 h6 hr p div address pre form table tbody thead tfoot th tr td li ol ul caption blockquote center dl dt dd dir fieldset noscript menu isindex samp header footer article section hgroup aside nav figure option datalist select optgroup");function i(E){return new RegExp("^"+E.replace(/([?+*])/g,".$1")+"$")}function C(L){var K,G,Z,V,aa,F,I,U,X,Q,Y,ac,O,J,W,E,S,H,ab,ad,P,T,N=/^([#+\-])?([^\[\/]+)(?:\/([^\[]+))?(?:\[([^\]]+)\])?$/,R=/^([!\-])?(\w+::\w+|[^=:<]+)?(?:([=:<])(.*))?$/,M=/[*?+]/;if(L){L=d(L);if(s["@"]){S=s["@"].attributes;H=s["@"].attributesOrder}for(K=0,G=L.length;K<G;K++){F=N.exec(L[K]);if(F){W=F[1];Q=F[2];E=F[3];X=F[4];O={};J=[];I={attributes:O,attributesOrder:J};if(W==="#"){I.paddEmpty=true}if(W==="-"){I.removeEmpty=true}if(S){for(ad in S){O[ad]=S[ad]}J.push.apply(J,H)}if(X){X=d(X,"|");for(Z=0,V=X.length;Z<V;Z++){F=R.exec(X[Z]);if(F){U={};ac=F[1];Y=F[2].replace(/::/g,":");W=F[3];T=F[4];if(ac==="!"){I.attributesRequired=I.attributesRequired||[];I.attributesRequired.push(Y);U.required=true}if(ac==="-"){delete O[Y];J.splice(f.inArray(J,Y),1);continue}if(W){if(W==="="){I.attributesDefault=I.attributesDefault||[];I.attributesDefault.push({name:Y,value:T});U.defaultValue=T}if(W===":"){I.attributesForced=I.attributesForced||[];I.attributesForced.push({name:Y,value:T});U.forcedValue=T}if(W==="<"){U.validValues=e(T,"?")}}if(M.test(Y)){I.attributePatterns=I.attributePatterns||[];U.pattern=i(Y);I.attributePatterns.push(U)}else{if(!O[Y]){J.push(Y)}O[Y]=U}}}}if(!S&&Q=="@"){S=O;H=J}if(E){I.outputName=Q;s[E]=I}if(M.test(Q)){I.pattern=i(Q);j.push(I)}else{s[Q]=I}}}}}function t(E){s={};j=[];C(E);g(y,function(G,F){k[F]=G.children})}function l(F){var E=/^(~)?(.+)$/;if(F){g(d(F),function(J){var H=E.exec(J),I=H[1]==="~",K=I?"span":"div",G=H[2];k[G]=k[K];p[G]=K;if(!I){v[G]={}}g(k,function(L,M){if(L[K]){L[G]=L[K]}})})}}function x(F){var E=/^([+\-]?)(\w+)\[([^\]]+)\]$/;if(F){g(d(F),function(J){var I=E.exec(J),G,H;if(I){H=I[1];if(H){G=k[I[2]]}else{G=k[I[2]]={"#comment":{}}}G=k[I[2]];g(d(I[3],"|"),function(K){if(H==="-"){delete G[K]}else{G[K]={}}})}})}}function B(E){var G=s[E],F;if(G){return G}F=j.length;while(F--){G=j[F];if(G.pattern.test(E)){return G}}}if(!A.valid_elements){g(y,function(F,E){s[E]={attributes:F.attributes,attributesOrder:F.attributesOrder};k[E]=F.children});if(A.schema!="html5"){g(d("strong/b,em/i"),function(E){E=d(E,"/");s[E[1]].outputName=E[0]})}s.img.attributesDefault=[{name:"alt",value:""}];g(d("ol,ul,sub,sup,blockquote,span,font,a,table,tbody,tr,strong,em,b,i"),function(E){if(s[E]){s[E].removeEmpty=true}});g(d("p,h1,h2,h3,h4,h5,h6,th,td,pre,div,address,caption"),function(E){s[E].paddEmpty=true})}else{t(A.valid_elements)}l(A.custom_elements);x(A.valid_children);C(A.extended_valid_elements);x("+ol[ul|ol],+ul[ul|ol]");if(A.invalid_elements){f.each(f.explode(A.invalid_elements),function(E){if(s[E]){delete s[E]}})}if(!B("span")){C("span[!data-mce-type|*]")}u.children=k;u.styles=D;u.getBoolAttrs=function(){return r};u.getBlockElements=function(){return v};u.getShortEndedElements=function(){return z};u.getSelfClosingElements=function(){return q};u.getNonEmptyElements=function(){return n};u.getWhiteSpaceElements=function(){return o};u.isValidChild=function(E,G){var F=k[E];return !!(F&&F[G])};u.isValid=function(F,E){var H,G,I=B(F);if(I){if(E){if(I.attributes[E]){return true}H=I.attributePatterns;if(H){G=H.length;while(G--){if(H[G].pattern.test(F)){return true}}}}else{return true}}return false};u.getElementRule=B;u.getCustomElements=function(){return p};u.addValidElements=C;u.setValidElements=t;u.addCustomElements=l;u.addValidChildren=x}})(tinymce);(function(a){a.html.SaxParser=function(c,e){var b=this,d=function(){};c=c||{};b.schema=e=e||new a.html.Schema();if(c.fix_self_closing!==false){c.fix_self_closing=true}a.each("comment cdata text start end pi doctype".split(" "),function(f){if(f){b[f]=c[f]||d}});b.parse=function(E){var n=this,g,G=0,I,B,A=[],N,Q,C,r,z,s,M,H,O,v,m,k,t,R,o,P,F,S,L,f,J,l,D,K,h,x=0,j=a.html.Entities.decode,y,q;function u(T){var V,U;V=A.length;while(V--){if(A[V].name===T){break}}if(V>=0){for(U=A.length-1;U>=V;U--){T=A[U];if(T.valid){n.end(T.name)}}A.length=V}}function p(U,T,Y,X,W){var Z,V;T=T.toLowerCase();Y=T in H?T:j(Y||X||W||"");if(v&&!z&&T.indexOf("data-")!==0){Z=P[T];if(!Z&&F){V=F.length;while(V--){Z=F[V];if(Z.pattern.test(T)){break}}if(V===-1){Z=null}}if(!Z){return}if(Z.validValues&&!(Y in Z.validValues)){return}}N.map[T]=Y;N.push({name:T,value:Y})}l=new RegExp("<(?:(?:!--([\\w\\W]*?)-->)|(?:!\\[CDATA\\[([\\w\\W]*?)\\]\\]>)|(?:!DOCTYPE([\\w\\W]*?)>)|(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)|(?:\\/([^>]+)>)|(?:([A-Za-z0-9\\-\\:]+)((?:\\s+[^\"'>]+(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>]*))*|\\/|\\s+)>))","g");D=/([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:\\.|[^\"])*)\")|(?:\'((?:\\.|[^\'])*)\')|([^>\s]+)))?/g;K={script:/<\/script[^>]*>/gi,style:/<\/style[^>]*>/gi,noscript:/<\/noscript[^>]*>/gi};M=e.getShortEndedElements();J=c.self_closing_elements||e.getSelfClosingElements();H=e.getBoolAttrs();v=c.validate;s=c.remove_internals;y=c.fix_self_closing;q=a.isIE;o=/^:/;while(g=l.exec(E)){if(G<g.index){n.text(j(E.substr(G,g.index-G)))}if(I=g[6]){I=I.toLowerCase();if(q&&o.test(I)){I=I.substr(1)}u(I)}else{if(I=g[7]){I=I.toLowerCase();if(q&&o.test(I)){I=I.substr(1)}O=I in M;if(y&&J[I]&&A.length>0&&A[A.length-1].name===I){u(I)}if(!v||(m=e.getElementRule(I))){k=true;if(v){P=m.attributes;F=m.attributePatterns}if(R=g[8]){z=R.indexOf("data-mce-type")!==-1;if(z&&s){k=false}N=[];N.map={};R.replace(D,p)}else{N=[];N.map={}}if(v&&!z){S=m.attributesRequired;L=m.attributesDefault;f=m.attributesForced;if(f){Q=f.length;while(Q--){t=f[Q];r=t.name;h=t.value;if(h==="{$uid}"){h="mce_"+x++}N.map[r]=h;N.push({name:r,value:h})}}if(L){Q=L.length;while(Q--){t=L[Q];r=t.name;if(!(r in N.map)){h=t.value;if(h==="{$uid}"){h="mce_"+x++}N.map[r]=h;N.push({name:r,value:h})}}}if(S){Q=S.length;while(Q--){if(S[Q] in N.map){break}}if(Q===-1){k=false}}if(N.map["data-mce-bogus"]){k=false}}if(k){n.start(I,N,O)}}else{k=false}if(B=K[I]){B.lastIndex=G=g.index+g[0].length;if(g=B.exec(E)){if(k){C=E.substr(G,g.index-G)}G=g.index+g[0].length}else{C=E.substr(G);G=E.length}if(k&&C.length>0){n.text(C,true)}if(k){n.end(I)}l.lastIndex=G;continue}if(!O){if(!R||R.indexOf("/")!=R.length-1){A.push({name:I,valid:k})}else{if(k){n.end(I)}}}}else{if(I=g[1]){n.comment(I)}else{if(I=g[2]){n.cdata(I)}else{if(I=g[3]){n.doctype(I)}else{if(I=g[4]){n.pi(I,g[5])}}}}}}G=g.index+g[0].length}if(G<E.length){n.text(j(E.substr(G)))}for(Q=A.length-1;Q>=0;Q--){I=A[Q];if(I.valid){n.end(I.name)}}}}})(tinymce);(function(d){var c=/^[ \t\r\n]*$/,e={"#text":3,"#comment":8,"#cdata":4,"#pi":7,"#doctype":10,"#document-fragment":11};function a(k,l,j){var i,h,f=j?"lastChild":"firstChild",g=j?"prev":"next";if(k[f]){return k[f]}if(k!==l){i=k[g];if(i){return i}for(h=k.parent;h&&h!==l;h=h.parent){i=h[g];if(i){return i}}}}function b(f,g){this.name=f;this.type=g;if(g===1){this.attributes=[];this.attributes.map={}}}d.extend(b.prototype,{replace:function(g){var f=this;if(g.parent){g.remove()}f.insert(g,f);f.remove();return f},attr:function(h,l){var f=this,g,j,k;if(typeof h!=="string"){for(j in h){f.attr(j,h[j])}return f}if(g=f.attributes){if(l!==k){if(l===null){if(h in g.map){delete g.map[h];j=g.length;while(j--){if(g[j].name===h){g=g.splice(j,1);return f}}}return f}if(h in g.map){j=g.length;while(j--){if(g[j].name===h){g[j].value=l;break}}}else{g.push({name:h,value:l})}g.map[h]=l;return f}else{return g.map[h]}}},clone:function(){var g=this,n=new b(g.name,g.type),h,f,m,j,k;if(m=g.attributes){k=[];k.map={};for(h=0,f=m.length;h<f;h++){j=m[h];if(j.name!=="id"){k[k.length]={name:j.name,value:j.value};k.map[j.name]=j.value}}n.attributes=k}n.value=g.value;n.shortEnded=g.shortEnded;return n},wrap:function(g){var f=this;f.parent.insert(g,f);g.append(f);return f},unwrap:function(){var f=this,h,g;for(h=f.firstChild;h;){g=h.next;f.insert(h,f,true);h=g}f.remove()},remove:function(){var f=this,h=f.parent,g=f.next,i=f.prev;if(h){if(h.firstChild===f){h.firstChild=g;if(g){g.prev=null}}else{i.next=g}if(h.lastChild===f){h.lastChild=i;if(i){i.next=null}}else{g.prev=i}f.parent=f.next=f.prev=null}return f},append:function(h){var f=this,g;if(h.parent){h.remove()}g=f.lastChild;if(g){g.next=h;h.prev=g;f.lastChild=h}else{f.lastChild=f.firstChild=h}h.parent=f;return h},insert:function(h,f,i){var g;if(h.parent){h.remove()}g=f.parent||this;if(i){if(f===g.firstChild){g.firstChild=h}else{f.prev.next=h}h.prev=f.prev;h.next=f;f.prev=h}else{if(f===g.lastChild){g.lastChild=h}else{f.next.prev=h}h.next=f.next;h.prev=f;f.next=h}h.parent=g;return h},getAll:function(g){var f=this,h,i=[];for(h=f.firstChild;h;h=a(h,f)){if(h.name===g){i.push(h)}}return i},empty:function(){var g=this,f,h,j;if(g.firstChild){f=[];for(j=g.firstChild;j;j=a(j,g)){f.push(j)}h=f.length;while(h--){j=f[h];j.parent=j.firstChild=j.lastChild=j.next=j.prev=null}}g.firstChild=g.lastChild=null;return g},isEmpty:function(k){var f=this,j=f.firstChild,h,g;if(j){do{if(j.type===1){if(j.attributes.map["data-mce-bogus"]){continue}if(k[j.name]){return false}h=j.attributes.length;while(h--){g=j.attributes[h].name;if(g==="name"||g.indexOf("data-")===0){return false}}}if(j.type===8){return false}if((j.type===3&&!c.test(j.value))){return false}}while(j=a(j,f))}return true},walk:function(f){return a(this,null,f)}});d.extend(b,{create:function(g,f){var i,h;i=new b(g,e[g]||1);if(f){for(h in f){i.attr(h,f[h])}}return i}});d.html.Node=b})(tinymce);(function(b){var a=b.html.Node;b.html.DomParser=function(g,h){var f=this,e={},d=[],i={},c={};g=g||{};g.validate="validate" in g?g.validate:true;g.root_name=g.root_name||"body";f.schema=h=h||new b.html.Schema();function j(m){var o,p,x,v,z,n,q,l,t,u,k,s,y,r;s=b.makeMap("tr,td,th,tbody,thead,tfoot,table");k=h.getNonEmptyElements();for(o=0;o<m.length;o++){p=m[o];if(!p.parent){continue}v=[p];for(x=p.parent;x&&!h.isValidChild(x.name,p.name)&&!s[x.name];x=x.parent){v.push(x)}if(x&&v.length>1){v.reverse();z=n=f.filterNode(v[0].clone());for(t=0;t<v.length-1;t++){if(h.isValidChild(n.name,v[t].name)){q=f.filterNode(v[t].clone());n.append(q)}else{q=n}for(l=v[t].firstChild;l&&l!=v[t+1];){r=l.next;q.append(l);l=r}n=q}if(!z.isEmpty(k)){x.insert(z,v[0],true);x.insert(p,z)}else{x.insert(p,v[0],true)}x=v[0];if(x.isEmpty(k)||x.firstChild===x.lastChild&&x.firstChild.name==="br"){x.empty().remove()}}else{if(p.parent){if(p.name==="li"){y=p.prev;if(y&&(y.name==="ul"||y.name==="ul")){y.append(p);continue}y=p.next;if(y&&(y.name==="ul"||y.name==="ul")){y.insert(p,y.firstChild,true);continue}p.wrap(f.filterNode(new a("ul",1)));continue}if(h.isValidChild(p.parent.name,"div")&&h.isValidChild("div",p.name)){p.wrap(f.filterNode(new a("div",1)))}else{if(p.name==="style"||p.name==="script"){p.empty().remove()}else{p.unwrap()}}}}}}f.filterNode=function(m){var l,k,n;if(k in e){n=i[k];if(n){n.push(m)}else{i[k]=[m]}}l=d.length;while(l--){k=d[l].name;if(k in m.attributes.map){n=c[k];if(n){n.push(m)}else{c[k]=[m]}}}return m};f.addNodeFilter=function(k,l){b.each(b.explode(k),function(m){var n=e[m];if(!n){e[m]=n=[]}n.push(l)})};f.addAttributeFilter=function(k,l){b.each(b.explode(k),function(m){var n;for(n=0;n<d.length;n++){if(d[n].name===m){d[n].callbacks.push(l);return}}d.push({name:m,callbacks:[l]})})};f.parse=function(v,m){var n,J,B,A,D,C,x,r,F,N,z,o,E,M=[],L,t,k,y,s,p,u,q;m=m||{};i={};c={};o=b.extend(b.makeMap("script,style,head,html,body,title,meta,param"),h.getBlockElements());u=h.getNonEmptyElements();p=h.children;z=g.validate;q="forced_root_block" in m?m.forced_root_block:g.forced_root_block;s=h.getWhiteSpaceElements();E=/^[ \t\r\n]+/;t=/[ \t\r\n]+$/;k=/[ \t\r\n]+/g;y=/^[ \t\r\n]+$/;function G(){var O=J.firstChild,l,P;while(O){l=O.next;if(O.type==3||(O.type==1&&O.name!=="p"&&!o[O.name]&&!O.attr("data-mce-type"))){if(!P){P=K(q,1);J.insert(P,O);P.append(O)}else{P.append(O)}}else{P=null}O=l}}function K(l,O){var P=new a(l,O),Q;if(l in e){Q=i[l];if(Q){Q.push(P)}else{i[l]=[P]}}return P}function I(P){var Q,l,O;for(Q=P.prev;Q&&Q.type===3;){l=Q.value.replace(t,"");if(l.length>0){Q.value=l;Q=Q.prev}else{O=Q.prev;Q.remove();Q=O}}}function H(O){var P,l={};for(P in O){if(P!=="li"&&P!="p"){l[P]=O[P]}}return l}n=new b.html.SaxParser({validate:z,self_closing_elements:H(h.getSelfClosingElements()),cdata:function(l){B.append(K("#cdata",4)).value=l},text:function(P,l){var O;if(!L){P=P.replace(k," ");if(B.lastChild&&o[B.lastChild.name]){P=P.replace(E,"")}}if(P.length!==0){O=K("#text",3);O.raw=!!l;B.append(O).value=P}},comment:function(l){B.append(K("#comment",8)).value=l},pi:function(l,O){B.append(K(l,7)).value=O;I(B)},doctype:function(O){var l;l=B.append(K("#doctype",10));l.value=O;I(B)},start:function(l,W,P){var U,R,Q,O,S,X,V,T;Q=z?h.getElementRule(l):{};if(Q){U=K(Q.outputName||l,1);U.attributes=W;U.shortEnded=P;B.append(U);T=p[B.name];if(T&&p[U.name]&&!T[U.name]){M.push(U)}R=d.length;while(R--){S=d[R].name;if(S in W.map){F=c[S];if(F){F.push(U)}else{c[S]=[U]}}}if(o[l]){I(U)}if(!P){B=U}if(!L&&s[l]){L=true}}},end:function(l){var S,P,R,O,Q;P=z?h.getElementRule(l):{};if(P){if(o[l]){if(!L){S=B.firstChild;if(S&&S.type===3){R=S.value.replace(E,"");if(R.length>0){S.value=R;S=S.next}else{O=S.next;S.remove();S=O}while(S&&S.type===3){R=S.value;O=S.next;if(R.length===0||y.test(R)){S.remove();S=O}S=O}}S=B.lastChild;if(S&&S.type===3){R=S.value.replace(t,"");if(R.length>0){S.value=R;S=S.prev}else{O=S.prev;S.remove();S=O}while(S&&S.type===3){R=S.value;O=S.prev;if(R.length===0||y.test(R)){S.remove();S=O}S=O}}}S=B.prev;if(S&&S.type===3){R=S.value.replace(E,"");if(R.length>0){S.value=R}else{S.remove()}}}if(L&&s[l]){L=false}if(P.removeEmpty||P.paddEmpty){if(B.isEmpty(u)){if(P.paddEmpty){B.empty().append(new a("#text","3")).value="\u00a0"}else{if(!B.attributes.map.name&&!B.attributes.map.id){Q=B.parent;B.empty().remove();B=Q;return}}}}B=B.parent}}},h);J=B=new a(m.context||g.root_name,11);n.parse(v);if(z&&M.length){if(!m.context){j(M)}else{m.invalid=true}}if(q&&J.name=="body"){G()}if(!m.invalid){for(N in i){F=e[N];A=i[N];x=A.length;while(x--){if(!A[x].parent){A.splice(x,1)}}for(D=0,C=F.length;D<C;D++){F[D](A,N,m)}}for(D=0,C=d.length;D<C;D++){F=d[D];if(F.name in c){A=c[F.name];x=A.length;while(x--){if(!A[x].parent){A.splice(x,1)}}for(x=0,r=F.callbacks.length;x<r;x++){F.callbacks[x](A,F.name,m)}}}}return J};if(g.remove_trailing_brs){f.addNodeFilter("br",function(n,m){var r,q=n.length,o,v=b.extend({},h.getBlockElements()),k=h.getNonEmptyElements(),t,s,p,u;v.body=1;for(r=0;r<q;r++){o=n[r];t=o.parent;if(v[o.parent.name]&&o===t.lastChild){p=o.prev;while(p){u=p.name;if(u!=="span"||p.attr("data-mce-type")!=="bookmark"){if(u!=="br"){break}if(u==="br"){o=null;break}}p=p.prev}if(o){o.remove();if(t.isEmpty(k)){elementRule=h.getElementRule(t.name);if(elementRule){if(elementRule.removeEmpty){t.remove()}else{if(elementRule.paddEmpty){t.empty().append(new b.html.Node("#text",3)).value="\u00a0"}}}}}}else{s=o;while(t.firstChild===s&&t.lastChild===s){s=t;if(v[t.name]){break}t=t.parent}if(s===t){textNode=new b.html.Node("#text",3);textNode.value="\u00a0";o.replace(textNode)}}}})}if(!g.allow_html_in_named_anchor){f.addAttributeFilter("id,name",function(k,l){var n=k.length,p,m,o,q;while(n--){q=k[n];if(q.name==="a"&&q.firstChild&&!q.attr("href")){o=q.parent;p=q.lastChild;do{m=p.prev;o.insert(p,q);p=m}while(p)}}})}}})(tinymce);tinymce.html.Writer=function(e){var c=[],a,b,d,f,g;e=e||{};a=e.indent;b=tinymce.makeMap(e.indent_before||"");d=tinymce.makeMap(e.indent_after||"");f=tinymce.html.Entities.getEncodeFunc(e.entity_encoding||"raw",e.entities);g=e.element_format=="html";return{start:function(m,k,p){var n,j,h,o;if(a&&b[m]&&c.length>0){o=c[c.length-1];if(o.length>0&&o!=="\n"){c.push("\n")}}c.push("<",m);if(k){for(n=0,j=k.length;n<j;n++){h=k[n];c.push(" ",h.name,'="',f(h.value,true),'"')}}if(!p||g){c[c.length]=">"}else{c[c.length]=" />"}if(p&&a&&d[m]&&c.length>0){o=c[c.length-1];if(o.length>0&&o!=="\n"){c.push("\n")}}},end:function(h){var i;c.push("</",h,">");if(a&&d[h]&&c.length>0){i=c[c.length-1];if(i.length>0&&i!=="\n"){c.push("\n")}}},text:function(i,h){if(i.length>0){c[c.length]=h?i:f(i)}},cdata:function(h){c.push("<![CDATA[",h,"]]>")},comment:function(h){c.push("<!--",h,"-->")},pi:function(h,i){if(i){c.push("<?",h," ",i,"?>")}else{c.push("<?",h,"?>")}if(a){c.push("\n")}},doctype:function(h){c.push("<!DOCTYPE",h,">",a?"\n":"")},reset:function(){c.length=0},getContent:function(){return c.join("").replace(/\n$/,"")}}};(function(a){a.html.Serializer=function(c,d){var b=this,e=new a.html.Writer(c);c=c||{};c.validate="validate" in c?c.validate:true;b.schema=d=d||new a.html.Schema();b.writer=e;b.serialize=function(h){var g,i;i=c.validate;g={3:function(k,j){e.text(k.value,k.raw)},8:function(j){e.comment(j.value)},7:function(j){e.pi(j.name,j.value)},10:function(j){e.doctype(j.value)},4:function(j){e.cdata(j.value)},11:function(j){if((j=j.firstChild)){do{f(j)}while(j=j.next)}}};e.reset();function f(k){var t=g[k.type],j,o,s,r,p,u,n,m,q;if(!t){j=k.name;o=k.shortEnded;s=k.attributes;if(i&&s&&s.length>1){u=[];u.map={};q=d.getElementRule(k.name);for(n=0,m=q.attributesOrder.length;n<m;n++){r=q.attributesOrder[n];if(r in s.map){p=s.map[r];u.map[r]=p;u.push({name:r,value:p})}}for(n=0,m=s.length;n<m;n++){r=s[n].name;if(!(r in u.map)){p=s.map[r];u.map[r]=p;u.push({name:r,value:p})}}s=u}e.start(k.name,s,o);if(!o){if((k=k.firstChild)){do{f(k)}while(k=k.next)}e.end(j)}}else{t(k)}}if(h.type==1&&!c.inner){f(h)}else{g[11](h)}return e.getContent()}}})(tinymce);tinymce.dom={};(function(b,h){var g=!!document.addEventListener;function c(k,j,l,i){if(k.addEventListener){k.addEventListener(j,l,i||false)}else{if(k.attachEvent){k.attachEvent("on"+j,l)}}}function e(k,j,l,i){if(k.removeEventListener){k.removeEventListener(j,l,i||false)}else{if(k.detachEvent){k.detachEvent("on"+j,l)}}}function a(n,l){var i,k=l||{};function j(){return false}function m(){return true}for(i in n){if(i!=="layerX"&&i!=="layerY"){k[i]=n[i]}}if(!k.target){k.target=k.srcElement||document}k.preventDefault=function(){k.isDefaultPrevented=m;if(n){if(n.preventDefault){n.preventDefault()}else{n.returnValue=false}}};k.stopPropagation=function(){k.isPropagationStopped=m;if(n){if(n.stopPropagation){n.stopPropagation()}else{n.cancelBubble=true}}};k.stopImmediatePropagation=function(){k.isImmediatePropagationStopped=m;k.stopPropagation()};if(!k.isDefaultPrevented){k.isDefaultPrevented=j;k.isPropagationStopped=j;k.isImmediatePropagationStopped=j}return k}function d(m,n,l){var k=m.document,j={type:"ready"};function i(){if(!l.domLoaded){l.domLoaded=true;n(j)}}if(g){c(m,"DOMContentLoaded",i)}else{c(k,"readystatechange",function(){if(k.readyState==="complete"){e(k,"readystatechange",arguments.callee);i()}});if(k.documentElement.doScroll&&m===m.top){(function(){try{k.documentElement.doScroll("left")}catch(o){setTimeout(arguments.callee,0);return}i()})()}}c(m,"load",i)}function f(k){var q=this,p={},i,o,n,m,l;m="onmouseenter" in document.documentElement;n="onfocusin" in document.documentElement;l={mouseenter:"mouseover",mouseleave:"mouseout"};i=1;q.domLoaded=false;q.events=p;function j(t,x){var s,u,r,v;s=p[x][t.type];if(s){for(u=0,r=s.length;u<r;u++){v=s[u];if(v&&v.func.call(v.scope,t)===false){t.preventDefault()}if(t.isImmediatePropagationStopped()){return}}}}q.bind=function(x,A,D,E){var s,t,u,r,B,z,C,v=window;function y(F){j(a(F||v.event),s)}if(!x||x.nodeType===3||x.nodeType===8){return}if(!x[h]){s=i++;x[h]=s;p[s]={}}else{s=x[h];if(!p[s]){p[s]={}}}E=E||x;A=A.split(" ");u=A.length;while(u--){r=A[u];z=y;B=C=false;if(r==="DOMContentLoaded"){r="ready"}if((q.domLoaded||x.readyState=="complete")&&r==="ready"){q.domLoaded=true;D.call(E,a({type:r}));continue}if(!m){B=l[r];if(B){z=function(F){var H,G;H=F.currentTarget;G=F.relatedTarget;if(G&&H.contains){G=H.contains(G)}else{while(G&&G!==H){G=G.parentNode}}if(!G){F=a(F||v.event);F.type=F.type==="mouseout"?"mouseleave":"mouseenter";F.target=H;j(F,s)}}}}if(!n&&(r==="focusin"||r==="focusout")){C=true;B=r==="focusin"?"focus":"blur";z=function(F){F=a(F||v.event);F.type=F.type==="focus"?"focusin":"focusout";j(F,s)}}t=p[s][r];if(!t){p[s][r]=t=[{func:D,scope:E}];t.fakeName=B;t.capture=C;t.nativeHandler=z;if(!g){t.proxyHandler=k(s)}if(r==="ready"){d(x,z,q)}else{c(x,B||r,g?z:t.proxyHandler,C)}}else{t.push({func:D,scope:E})}}x=t=0;return D};q.unbind=function(x,z,A){var s,u,v,B,r,t;if(!x||x.nodeType===3||x.nodeType===8){return q}s=x[h];if(s){t=p[s];if(z){z=z.split(" ");v=z.length;while(v--){r=z[v];u=t[r];if(u){if(A){B=u.length;while(B--){if(u[B].func===A){u.splice(B,1)}}}if(!A||u.length===0){delete t[r];e(x,u.fakeName||r,g?u.nativeHandler:u.proxyHandler,u.capture)}}}}else{for(r in t){u=t[r];e(x,u.fakeName||r,g?u.nativeHandler:u.proxyHandler,u.capture)}t={}}for(r in t){return q}delete p[s];try{delete x[h]}catch(y){x[h]=null}}return q};q.fire=function(u,s,r){var v,t;if(!u||u.nodeType===3||u.nodeType===8){return q}t=a(null,r);t.type=s;do{v=u[h];if(v){j(t,v)}u=u.parentNode||u.ownerDocument||u.defaultView||u.parentWindow}while(u&&!t.isPropagationStopped());return q};q.clean=function(u){var s,r,t=q.unbind;if(!u||u.nodeType===3||u.nodeType===8){return q}if(u[h]){t(u)}if(!u.getElementsByTagName){u=u.document}if(u&&u.getElementsByTagName){t(u);r=u.getElementsByTagName("*");s=r.length;while(s--){u=r[s];if(u[h]){t(u)}}}return q};q.callNativeHandler=function(s,r){if(p){p[s][r.type].nativeHandler(r)}};q.destory=function(){p={}};q.add=function(v,s,u,t){if(typeof(v)==="string"){v=document.getElementById(v)}if(v&&v instanceof Array){var r=v.length;while(r--){q.add(v[r],s,u,t)}return}if(s==="init"){s="ready"}return q.bind(v,s instanceof Array?s.join(" "):s,u,t)};q.remove=function(v,s,u,t){if(!v){return q}if(typeof(v)==="string"){v=document.getElementById(v)}if(v instanceof Array){var r=v.length;while(r--){q.remove(v[r],s,u,t)}return q}return q.unbind(v,s instanceof Array?s.join(" "):s,u)};q.clear=function(r){if(typeof(r)==="string"){r=document.getElementById(r)}return q.clean(r)};q.cancel=function(r){if(r){q.prevent(r);q.stop(r)}return false};q.prevent=function(r){if(!r.preventDefault){r=a(r)}r.preventDefault();return false};q.stop=function(r){if(!r.stopPropagation){r=a(r)}r.stopPropagation();return false}}b.EventUtils=f;b.Event=new f(function(i){return function(j){tinymce.dom.Event.callNativeHandler(i,j)}});b.Event.bind(window,"ready",function(){});b=0})(tinymce.dom,"data-mce-expando");tinymce.dom.TreeWalker=function(a,c){var b=a;function d(i,f,e,j){var h,g;if(i){if(!j&&i[f]){return i[f]}if(i!=c){h=i[e];if(h){return h}for(g=i.parentNode;g&&g!=c;g=g.parentNode){h=g[e];if(h){return h}}}}}this.current=function(){return b};this.next=function(e){return(b=d(b,"firstChild","nextSibling",e))};this.prev=function(e){return(b=d(b,"lastChild","previousSibling",e))}};(function(e){var g=e.each,d=e.is,f=e.isWebKit,b=e.isIE,h=e.html.Entities,c=/^([a-z0-9],?)+$/i,a=/^[ \t\r\n]*$/;e.create("tinymce.dom.DOMUtils",{doc:null,root:null,files:null,pixelStyles:/^(top|left|bottom|right|width|height|borderWidth)$/,props:{"for":"htmlFor","class":"className",className:"className",checked:"checked",disabled:"disabled",maxlength:"maxLength",readonly:"readOnly",selected:"selected",value:"value",id:"id",name:"name",type:"type"},DOMUtils:function(o,l){var k=this,i,j,n;k.doc=o;k.win=window;k.files={};k.cssFlicker=false;k.counter=0;k.stdMode=!e.isIE||o.documentMode>=8;k.boxModel=!e.isIE||o.compatMode=="CSS1Compat"||k.stdMode;k.hasOuterHTML="outerHTML" in o.createElement("a");k.settings=l=e.extend({keep_values:false,hex_colors:1},l);k.schema=l.schema;k.styles=new e.html.Styles({url_converter:l.url_converter,url_converter_scope:l.url_converter_scope},l.schema);if(e.isIE6){try{o.execCommand("BackgroundImageCache",false,true)}catch(m){k.cssFlicker=true}}k.fixDoc(o);k.events=l.ownEvents?new e.dom.EventUtils(l.proxy):e.dom.Event;e.addUnload(k.destroy,k);n=l.schema?l.schema.getBlockElements():{};k.isBlock=function(q){var p=q.nodeType;if(p){return !!(p===1&&n[q.nodeName])}return !!n[q]}},fixDoc:function(k){var j=this.settings,i;if(b&&j.schema){("abbr article aside audio canvas details figcaption figure footer header hgroup mark menu meter nav output progress section summary time video").replace(/\w+/g,function(l){k.createElement(l)});for(i in j.schema.getCustomElements()){k.createElement(i)}}},clone:function(k,i){var j=this,m,l;if(!b||k.nodeType!==1||i){return k.cloneNode(i)}l=j.doc;if(!i){m=l.createElement(k.nodeName);g(j.getAttribs(k),function(n){j.setAttrib(m,n.nodeName,j.getAttrib(k,n.nodeName))});return m}return m.firstChild},getRoot:function(){var i=this,j=i.settings;return(j&&i.get(j.root_element))||i.doc.body},getViewPort:function(j){var k,i;j=!j?this.win:j;k=j.document;i=this.boxModel?k.documentElement:k.body;return{x:j.pageXOffset||i.scrollLeft,y:j.pageYOffset||i.scrollTop,w:j.innerWidth||i.clientWidth,h:j.innerHeight||i.clientHeight}},getRect:function(l){var k,i=this,j;l=i.get(l);k=i.getPos(l);j=i.getSize(l);return{x:k.x,y:k.y,w:j.w,h:j.h}},getSize:function(l){var j=this,i,k;l=j.get(l);i=j.getStyle(l,"width");k=j.getStyle(l,"height");if(i.indexOf("px")===-1){i=0}if(k.indexOf("px")===-1){k=0}return{w:parseInt(i,10)||l.offsetWidth||l.clientWidth,h:parseInt(k,10)||l.offsetHeight||l.clientHeight}},getParent:function(k,j,i){return this.getParents(k,j,i,false)},getParents:function(s,m,k,q){var j=this,i,l=j.settings,p=[];s=j.get(s);q=q===undefined;if(l.strict_root){k=k||j.getRoot()}if(d(m,"string")){i=m;if(m==="*"){m=function(o){return o.nodeType==1}}else{m=function(o){return j.is(o,i)}}}while(s){if(s==k||!s.nodeType||s.nodeType===9){break}if(!m||m(s)){if(q){p.push(s)}else{return s}}s=s.parentNode}return q?p:null},get:function(i){var j;if(i&&this.doc&&typeof(i)=="string"){j=i;i=this.doc.getElementById(i);if(i&&i.id!==j){return this.doc.getElementsByName(j)[1]}}return i},getNext:function(j,i){return this._findSib(j,i,"nextSibling")},getPrev:function(j,i){return this._findSib(j,i,"previousSibling")},select:function(k,j){var i=this;return e.dom.Sizzle(k,i.get(j)||i.get(i.settings.root_element)||i.doc,[])},is:function(l,j){var k;if(l.length===undefined){if(j==="*"){return l.nodeType==1}if(c.test(j)){j=j.toLowerCase().split(/,/);l=l.nodeName.toLowerCase();for(k=j.length-1;k>=0;k--){if(j[k]==l){return true}}return false}}return e.dom.Sizzle.matches(j,l.nodeType?[l]:l).length>0},add:function(l,o,i,k,m){var j=this;return this.run(l,function(r){var q,n;q=d(o,"string")?j.doc.createElement(o):o;j.setAttribs(q,i);if(k){if(k.nodeType){q.appendChild(k)}else{j.setHTML(q,k)}}return !m?r.appendChild(q):q})},create:function(k,i,j){return this.add(this.doc.createElement(k),k,i,j,1)},createHTML:function(q,i,m){var p="",l=this,j;p+="<"+q;for(j in i){if(i.hasOwnProperty(j)){p+=" "+j+'="'+l.encode(i[j])+'"'}}if(typeof(m)!="undefined"){return p+">"+m+"</"+q+">"}return p+" />"},remove:function(i,j){return this.run(i,function(l){var m,k=l.parentNode;if(!k){return null}if(j){while(m=l.firstChild){if(!e.isIE||m.nodeType!==3||m.nodeValue){k.insertBefore(m,l)}else{l.removeChild(m)}}}return k.removeChild(l)})},setStyle:function(l,i,j){var k=this;return k.run(l,function(o){var n,m;n=o.style;i=i.replace(/-(\D)/g,function(q,p){return p.toUpperCase()});if(k.pixelStyles.test(i)&&(e.is(j,"number")||/^[\-0-9\.]+$/.test(j))){j+="px"}switch(i){case"opacity":if(b){n.filter=j===""?"":"alpha(opacity="+(j*100)+")";if(!l.currentStyle||!l.currentStyle.hasLayout){n.display="inline-block"}}n[i]=n["-moz-opacity"]=n["-khtml-opacity"]=j||"";break;case"float":b?n.styleFloat=j:n.cssFloat=j;break;default:n[i]=j||""}if(k.settings.update_styles){k.setAttrib(o,"data-mce-style")}})},getStyle:function(l,i,k){l=this.get(l);if(!l){return}if(this.doc.defaultView&&k){i=i.replace(/[A-Z]/g,function(m){return"-"+m});try{return this.doc.defaultView.getComputedStyle(l,null).getPropertyValue(i)}catch(j){return null}}i=i.replace(/-(\D)/g,function(n,m){return m.toUpperCase()});if(i=="float"){i=b?"styleFloat":"cssFloat"}if(l.currentStyle&&k){return l.currentStyle[i]}return l.style?l.style[i]:undefined},setStyles:function(l,m){var j=this,k=j.settings,i;i=k.update_styles;k.update_styles=0;g(m,function(o,p){j.setStyle(l,p,o)});k.update_styles=i;if(k.update_styles){j.setAttrib(l,k.cssText)}},removeAllAttribs:function(i){return this.run(i,function(l){var k,j=l.attributes;for(k=j.length-1;k>=0;k--){l.removeAttributeNode(j.item(k))}})},setAttrib:function(k,l,i){var j=this;if(!k||!l){return}if(j.settings.strict){l=l.toLowerCase()}return this.run(k,function(p){var o=j.settings;var m=p.getAttribute(l);if(i!==null){switch(l){case"style":if(!d(i,"string")){g(i,function(q,r){j.setStyle(p,r,q)});return}if(o.keep_values){if(i&&!j._isRes(i)){p.setAttribute("data-mce-style",i,2)}else{p.removeAttribute("data-mce-style",2)}}p.style.cssText=i;break;case"class":p.className=i||"";break;case"src":case"href":if(o.keep_values){if(o.url_converter){i=o.url_converter.call(o.url_converter_scope||j,i,l,p)}j.setAttrib(p,"data-mce-"+l,i,2)}break;case"shape":p.setAttribute("data-mce-style",i);break}}if(d(i)&&i!==null&&i.length!==0){p.setAttribute(l,""+i,2)}else{p.removeAttribute(l,2)}if(tinyMCE.activeEditor&&m!=i){var n=tinyMCE.activeEditor;n.onSetAttrib.dispatch(n,p,l,i)}})},setAttribs:function(j,k){var i=this;return this.run(j,function(l){g(k,function(m,o){i.setAttrib(l,o,m)})})},getAttrib:function(m,o,k){var i,j=this,l;m=j.get(m);if(!m||m.nodeType!==1){return k===l?false:k}if(!d(k)){k=""}if(/^(src|href|style|coords|shape)$/.test(o)){i=m.getAttribute("data-mce-"+o);if(i){return i}}if(b&&j.props[o]){i=m[j.props[o]];i=i&&i.nodeValue?i.nodeValue:i}if(!i){i=m.getAttribute(o,2)}if(/^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)$/.test(o)){if(m[j.props[o]]===true&&i===""){return o}return i?o:""}if(m.nodeName==="FORM"&&m.getAttributeNode(o)){return m.getAttributeNode(o).nodeValue}if(o==="style"){i=i||m.style.cssText;if(i){i=j.serializeStyle(j.parseStyle(i),m.nodeName);if(j.settings.keep_values&&!j._isRes(i)){m.setAttribute("data-mce-style",i)}}}if(f&&o==="class"&&i){i=i.replace(/(apple|webkit)\-[a-z\-]+/gi,"")}if(b){switch(o){case"rowspan":case"colspan":if(i===1){i=""}break;case"size":if(i==="+0"||i===20||i===0){i=""}break;case"width":case"height":case"vspace":case"checked":case"disabled":case"readonly":if(i===0){i=""}break;case"hspace":if(i===-1){i=""}break;case"maxlength":case"tabindex":if(i===32768||i===2147483647||i==="32768"){i=""}break;case"multiple":case"compact":case"noshade":case"nowrap":if(i===65535){return o}return k;case"shape":i=i.toLowerCase();break;default:if(o.indexOf("on")===0&&i){i=e._replace(/^function\s+\w+\(\)\s+\{\s+(.*)\s+\}$/,"$1",""+i)}}}return(i!==l&&i!==null&&i!=="")?""+i:k},getPos:function(q,l){var j=this,i=0,p=0,m,o=j.doc,k;q=j.get(q);l=l||o.body;if(q){if(q.getBoundingClientRect){q=q.getBoundingClientRect();m=j.boxModel?o.documentElement:o.body;i=q.left+(o.documentElement.scrollLeft||o.body.scrollLeft)-m.clientTop;p=q.top+(o.documentElement.scrollTop||o.body.scrollTop)-m.clientLeft;return{x:i,y:p}}k=q;while(k&&k!=l&&k.nodeType){i+=k.offsetLeft||0;p+=k.offsetTop||0;k=k.offsetParent}k=q.parentNode;while(k&&k!=l&&k.nodeType){i-=k.scrollLeft||0;p-=k.scrollTop||0;k=k.parentNode}}return{x:i,y:p}},parseStyle:function(i){return this.styles.parse(i)},serializeStyle:function(j,i){return this.styles.serialize(j,i)},addStyle:function(j){var k=this.doc,i;styleElm=k.getElementById("mceDefaultStyles");if(!styleElm){styleElm=k.createElement("style"),styleElm.id="mceDefaultStyles";styleElm.type="text/css";i=k.getElementsByTagName("head")[0];if(i.firstChild){i.insertBefore(styleElm,i.firstChild)}else{i.appendChild(styleElm)}}if(styleElm.styleSheet){styleElm.styleSheet.cssText+=j}else{styleElm.appendChild(k.createTextNode(j))}},loadCSS:function(i){var k=this,l=k.doc,j;if(!i){i=""}j=l.getElementsByTagName("head")[0];g(i.split(","),function(m){var n;if(k.files[m]){return}k.files[m]=true;n=k.create("link",{rel:"stylesheet",href:e._addVer(m)});if(b&&l.documentMode&&l.recalc){n.onload=function(){if(l.recalc){l.recalc()}n.onload=null}}j.appendChild(n)})},addClass:function(i,j){return this.run(i,function(k){var l;if(!j){return 0}if(this.hasClass(k,j)){return k.className}l=this.removeClass(k,j);return k.className=(l!=""?(l+" "):"")+j})},removeClass:function(k,l){var i=this,j;return i.run(k,function(n){var m;if(i.hasClass(n,l)){if(!j){j=new RegExp("(^|\\s+)"+l+"(\\s+|$)","g")}m=n.className.replace(j," ");m=e.trim(m!=" "?m:"");n.className=m;if(!m){n.removeAttribute("class");n.removeAttribute("className")}return m}return n.className})},hasClass:function(j,i){j=this.get(j);if(!j||!i){return false}return(" "+j.className+" ").indexOf(" "+i+" ")!==-1},show:function(i){return this.setStyle(i,"display","block")},hide:function(i){return this.setStyle(i,"display","none")},isHidden:function(i){i=this.get(i);return !i||i.style.display=="none"||this.getStyle(i,"display")=="none"},uniqueId:function(i){return(!i?"mce_":i)+(this.counter++)},setHTML:function(k,j){var i=this;return i.run(k,function(m){if(b){while(m.firstChild){m.removeChild(m.firstChild)}try{m.innerHTML="<br />"+j;m.removeChild(m.firstChild)}catch(l){var n=i.create("div");n.innerHTML="<br />"+j;g(e.grep(n.childNodes),function(p,o){if(o&&m.canHaveHTML){m.appendChild(p)}})}}else{m.innerHTML=j}return j})},getOuterHTML:function(k){var j,i=this;k=i.get(k);if(!k){return null}if(k.nodeType===1&&i.hasOuterHTML){return k.outerHTML}j=(k.ownerDocument||i.doc).createElement("body");j.appendChild(k.cloneNode(true));return j.innerHTML},setOuterHTML:function(l,j,m){var i=this;function k(p,o,r){var s,q;q=r.createElement("body");q.innerHTML=o;s=q.lastChild;while(s){i.insertAfter(s.cloneNode(true),p);s=s.previousSibling}i.remove(p)}return this.run(l,function(o){o=i.get(o);if(o.nodeType==1){m=m||o.ownerDocument||i.doc;if(b){try{if(b&&o.nodeType==1){o.outerHTML=j}else{k(o,j,m)}}catch(n){k(o,j,m)}}else{k(o,j,m)}}})},decode:h.decode,encode:h.encodeAllRaw,insertAfter:function(i,j){j=this.get(j);return this.run(i,function(l){var k,m;k=j.parentNode;m=j.nextSibling;if(m){k.insertBefore(l,m)}else{k.appendChild(l)}return l})},replace:function(m,l,i){var j=this;if(d(l,"array")){m=m.cloneNode(true)}return j.run(l,function(k){if(i){g(e.grep(k.childNodes),function(n){m.appendChild(n)})}return k.parentNode.replaceChild(m,k)})},rename:function(l,i){var k=this,j;if(l.nodeName!=i.toUpperCase()){j=k.create(i);g(k.getAttribs(l),function(m){k.setAttrib(j,m.nodeName,k.getAttrib(l,m.nodeName))});k.replace(j,l,1)}return j||l},findCommonAncestor:function(k,i){var l=k,j;while(l){j=i;while(j&&l!=j){j=j.parentNode}if(l==j){break}l=l.parentNode}if(!l&&k.ownerDocument){return k.ownerDocument.documentElement}return l},toHex:function(i){var k=/^\s*rgb\s*?\(\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?\)\s*$/i.exec(i);function j(l){l=parseInt(l,10).toString(16);return l.length>1?l:"0"+l}if(k){i="#"+j(k[1])+j(k[2])+j(k[3]);return i}return i},getClasses:function(){var n=this,j=[],m,o={},p=n.settings.class_filter,l;if(n.classes){return n.classes}function q(i){g(i.imports,function(s){q(s)});g(i.cssRules||i.rules,function(s){switch(s.type||1){case 1:if(s.selectorText){g(s.selectorText.split(","),function(r){r=r.replace(/^\s*|\s*$|^\s\./g,"");if(/\.mce/.test(r)||!/\.[\w\-]+$/.test(r)){return}l=r;r=e._replace(/.*\.([a-z0-9_\-]+).*/i,"$1",r);if(p&&!(r=p(r,l))){return}if(!o[r]){j.push({"class":r});o[r]=1}})}break;case 3:q(s.styleSheet);break}})}try{g(n.doc.styleSheets,q)}catch(k){}if(j.length>0){n.classes=j}return j},run:function(l,k,j){var i=this,m;if(i.doc&&typeof(l)==="string"){l=i.get(l)}if(!l){return false}j=j||this;if(!l.nodeType&&(l.length||l.length===0)){m=[];g(l,function(o,n){if(o){if(typeof(o)=="string"){o=i.doc.getElementById(o)}m.push(k.call(j,o,n))}});return m}return k.call(j,l)},getAttribs:function(j){var i;j=this.get(j);if(!j){return[]}if(b){i=[];if(j.nodeName=="OBJECT"){return j.attributes}if(j.nodeName==="OPTION"&&this.getAttrib(j,"selected")){i.push({specified:1,nodeName:"selected"})}j.cloneNode(false).outerHTML.replace(/<\/?[\w:\-]+ ?|=[\"][^\"]+\"|=\'[^\']+\'|=[\w\-]+|>/gi,"").replace(/[\w:\-]+/gi,function(k){i.push({specified:1,nodeName:k})});return i}return j.attributes},isEmpty:function(m,k){var r=this,o,n,q,j,l,p=0;m=m.firstChild;if(m){j=new e.dom.TreeWalker(m,m.parentNode);k=k||r.schema?r.schema.getNonEmptyElements():null;do{q=m.nodeType;if(q===1){if(m.getAttribute("data-mce-bogus")){continue}l=m.nodeName.toLowerCase();if(k&&k[l]){if(l==="br"){p++;continue}return false}n=r.getAttribs(m);o=m.attributes.length;while(o--){l=m.attributes[o].nodeName;if(l==="name"||l==="data-mce-bookmark"){return false}}}if(q==8){return false}if((q===3&&!a.test(m.nodeValue))){return false}}while(m=j.next())}return p<=1},destroy:function(j){var i=this;i.win=i.doc=i.root=i.events=i.frag=null;if(!j){e.removeUnload(i.destroy)}},createRng:function(){var i=this.doc;return i.createRange?i.createRange():new e.dom.Range(this)},nodeIndex:function(m,n){var i=0,k,l,j;if(m){for(k=m.nodeType,m=m.previousSibling,l=m;m;m=m.previousSibling){j=m.nodeType;if(n&&j==3){if(j==k||!m.nodeValue.length){continue}}i++;k=j}}return i},split:function(m,l,p){var q=this,i=q.createRng(),n,k,o;function j(v){var t,s=v.childNodes,u=v.nodeType;function x(A){var z=A.previousSibling&&A.previousSibling.nodeName=="SPAN";var y=A.nextSibling&&A.nextSibling.nodeName=="SPAN";return z&&y}if(u==1&&v.getAttribute("data-mce-type")=="bookmark"){return}for(t=s.length-1;t>=0;t--){j(s[t])}if(u!=9){if(u==3&&v.nodeValue.length>0){var r=e.trim(v.nodeValue).length;if(!q.isBlock(v.parentNode)||r>0||r===0&&x(v)){return}}else{if(u==1){s=v.childNodes;if(s.length==1&&s[0]&&s[0].nodeType==1&&s[0].getAttribute("data-mce-type")=="bookmark"){v.parentNode.insertBefore(s[0],v)}if(s.length||/^(br|hr|input|img)$/i.test(v.nodeName)){return}}}q.remove(v)}return v}if(m&&l){i.setStart(m.parentNode,q.nodeIndex(m));i.setEnd(l.parentNode,q.nodeIndex(l));n=i.extractContents();i=q.createRng();i.setStart(l.parentNode,q.nodeIndex(l)+1);i.setEnd(m.parentNode,q.nodeIndex(m)+1);k=i.extractContents();o=m.parentNode;o.insertBefore(j(n),m);if(p){o.replaceChild(p,l)}else{o.insertBefore(l,m)}o.insertBefore(j(k),m);q.remove(m);return p||l}},bind:function(l,i,k,j){return this.events.add(l,i,k,j||this)},unbind:function(k,i,j){return this.events.remove(k,i,j)},fire:function(k,j,i){return this.events.fire(k,j,i)},getContentEditable:function(j){var i;if(j.nodeType!=1){return null}i=j.getAttribute("data-mce-contenteditable");if(i&&i!=="inherit"){return i}return j.contentEditable!=="inherit"?j.contentEditable:null},_findSib:function(l,i,j){var k=this,m=i;if(l){if(d(m,"string")){m=function(n){return k.is(n,i)}}for(l=l[j];l;l=l[j]){if(m(l)){return l}}}return null},_isRes:function(i){return/^(top|left|bottom|right|width|height)/i.test(i)||/;\s*(top|left|bottom|right|width|height)/i.test(i)}});e.DOM=new e.dom.DOMUtils(document,{process_html:0})})(tinymce);(function(a){function b(c){var O=this,e=c.doc,U=0,F=1,j=2,E=true,S=false,W="startOffset",h="startContainer",Q="endContainer",A="endOffset",k=tinymce.extend,n=c.nodeIndex;k(O,{startContainer:e,startOffset:0,endContainer:e,endOffset:0,collapsed:E,commonAncestorContainer:e,START_TO_START:0,START_TO_END:1,END_TO_END:2,END_TO_START:3,setStart:q,setEnd:s,setStartBefore:g,setStartAfter:J,setEndBefore:K,setEndAfter:u,collapse:B,selectNode:y,selectNodeContents:G,compareBoundaryPoints:v,deleteContents:p,extractContents:I,cloneContents:d,insertNode:D,surroundContents:N,cloneRange:L,toStringIE:T});function x(){return e.createDocumentFragment()}function q(X,t){C(E,X,t)}function s(X,t){C(S,X,t)}function g(t){q(t.parentNode,n(t))}function J(t){q(t.parentNode,n(t)+1)}function K(t){s(t.parentNode,n(t))}function u(t){s(t.parentNode,n(t)+1)}function B(t){if(t){O[Q]=O[h];O[A]=O[W]}else{O[h]=O[Q];O[W]=O[A]}O.collapsed=E}function y(t){g(t);u(t)}function G(t){q(t,0);s(t,t.nodeType===1?t.childNodes.length:t.nodeValue.length)}function v(aa,t){var ad=O[h],Y=O[W],ac=O[Q],X=O[A],ab=t.startContainer,af=t.startOffset,Z=t.endContainer,ae=t.endOffset;if(aa===0){return H(ad,Y,ab,af)}if(aa===1){return H(ac,X,ab,af)}if(aa===2){return H(ac,X,Z,ae)}if(aa===3){return H(ad,Y,Z,ae)}}function p(){l(j)}function I(){return l(U)}function d(){return l(F)}function D(aa){var X=this[h],t=this[W],Z,Y;if((X.nodeType===3||X.nodeType===4)&&X.nodeValue){if(!t){X.parentNode.insertBefore(aa,X)}else{if(t>=X.nodeValue.length){c.insertAfter(aa,X)}else{Z=X.splitText(t);X.parentNode.insertBefore(aa,Z)}}}else{if(X.childNodes.length>0){Y=X.childNodes[t]}if(Y){X.insertBefore(aa,Y)}else{X.appendChild(aa)}}}function N(X){var t=O.extractContents();O.insertNode(X);X.appendChild(t);O.selectNode(X)}function L(){return k(new b(c),{startContainer:O[h],startOffset:O[W],endContainer:O[Q],endOffset:O[A],collapsed:O.collapsed,commonAncestorContainer:O.commonAncestorContainer})}function P(t,X){var Y;if(t.nodeType==3){return t}if(X<0){return t}Y=t.firstChild;while(Y&&X>0){--X;Y=Y.nextSibling}if(Y){return Y}return t}function m(){return(O[h]==O[Q]&&O[W]==O[A])}function H(Z,ab,X,aa){var ac,Y,t,ad,af,ae;if(Z==X){if(ab==aa){return 0}if(ab<aa){return -1}return 1}ac=X;while(ac&&ac.parentNode!=Z){ac=ac.parentNode}if(ac){Y=0;t=Z.firstChild;while(t!=ac&&Y<ab){Y++;t=t.nextSibling}if(ab<=Y){return -1}return 1}ac=Z;while(ac&&ac.parentNode!=X){ac=ac.parentNode}if(ac){Y=0;t=X.firstChild;while(t!=ac&&Y<aa){Y++;t=t.nextSibling}if(Y<aa){return -1}return 1}ad=c.findCommonAncestor(Z,X);af=Z;while(af&&af.parentNode!=ad){af=af.parentNode}if(!af){af=ad}ae=X;while(ae&&ae.parentNode!=ad){ae=ae.parentNode}if(!ae){ae=ad}if(af==ae){return 0}t=ad.firstChild;while(t){if(t==af){return -1}if(t==ae){return 1}t=t.nextSibling}}function C(X,aa,Z){var t,Y;if(X){O[h]=aa;O[W]=Z}else{O[Q]=aa;O[A]=Z}t=O[Q];while(t.parentNode){t=t.parentNode}Y=O[h];while(Y.parentNode){Y=Y.parentNode}if(Y==t){if(H(O[h],O[W],O[Q],O[A])>0){O.collapse(X)}}else{O.collapse(X)}O.collapsed=m();O.commonAncestorContainer=c.findCommonAncestor(O[h],O[Q])}function l(ad){var ac,Z=0,af=0,X,ab,Y,aa,t,ae;if(O[h]==O[Q]){return f(ad)}for(ac=O[Q],X=ac.parentNode;X;ac=X,X=X.parentNode){if(X==O[h]){return r(ac,ad)}++Z}for(ac=O[h],X=ac.parentNode;X;ac=X,X=X.parentNode){if(X==O[Q]){return V(ac,ad)}++af}ab=af-Z;Y=O[h];while(ab>0){Y=Y.parentNode;ab--}aa=O[Q];while(ab<0){aa=aa.parentNode;ab++}for(t=Y.parentNode,ae=aa.parentNode;t!=ae;t=t.parentNode,ae=ae.parentNode){Y=t;aa=ae}return o(Y,aa,ad)}function f(ac){var ae,af,t,Y,Z,ad,aa,X,ab;if(ac!=j){ae=x()}if(O[W]==O[A]){return ae}if(O[h].nodeType==3){af=O[h].nodeValue;t=af.substring(O[W],O[A]);if(ac!=F){Y=O[h];X=O[W];ab=O[A]-O[W];if(X===0&&ab>=Y.nodeValue.length-1){Y.parentNode.removeChild(Y)}else{Y.deleteData(X,ab)}O.collapse(E)}if(ac==j){return}if(t.length>0){ae.appendChild(e.createTextNode(t))}return ae}Y=P(O[h],O[W]);Z=O[A]-O[W];while(Y&&Z>0){ad=Y.nextSibling;aa=z(Y,ac);if(ae){ae.appendChild(aa)}--Z;Y=ad}if(ac!=F){O.collapse(E)}return ae}function r(ad,aa){var ac,ab,X,t,Z,Y;if(aa!=j){ac=x()}ab=i(ad,aa);if(ac){ac.appendChild(ab)}X=n(ad);t=X-O[W];if(t<=0){if(aa!=F){O.setEndBefore(ad);O.collapse(S)}return ac}ab=ad.previousSibling;while(t>0){Z=ab.previousSibling;Y=z(ab,aa);if(ac){ac.insertBefore(Y,ac.firstChild)}--t;ab=Z}if(aa!=F){O.setEndBefore(ad);O.collapse(S)}return ac}function V(ab,aa){var ad,X,ac,t,Z,Y;if(aa!=j){ad=x()}ac=R(ab,aa);if(ad){ad.appendChild(ac)}X=n(ab);++X;t=O[A]-X;ac=ab.nextSibling;while(ac&&t>0){Z=ac.nextSibling;Y=z(ac,aa);if(ad){ad.appendChild(Y)}--t;ac=Z}if(aa!=F){O.setStartAfter(ab);O.collapse(E)}return ad}function o(ab,t,ae){var Y,ag,aa,ac,ad,X,af,Z;if(ae!=j){ag=x()}Y=R(ab,ae);if(ag){ag.appendChild(Y)}aa=ab.parentNode;ac=n(ab);ad=n(t);++ac;X=ad-ac;af=ab.nextSibling;while(X>0){Z=af.nextSibling;Y=z(af,ae);if(ag){ag.appendChild(Y)}af=Z;--X}Y=i(t,ae);if(ag){ag.appendChild(Y)}if(ae!=F){O.setStartAfter(ab);O.collapse(E)}return ag}function i(ac,ad){var Y=P(O[Q],O[A]-1),ae,ab,aa,t,X,Z=Y!=O[Q];if(Y==ac){return M(Y,Z,S,ad)}ae=Y.parentNode;ab=M(ae,S,S,ad);while(ae){while(Y){aa=Y.previousSibling;t=M(Y,Z,S,ad);if(ad!=j){ab.insertBefore(t,ab.firstChild)}Z=E;Y=aa}if(ae==ac){return ab}Y=ae.previousSibling;ae=ae.parentNode;X=M(ae,S,S,ad);if(ad!=j){X.appendChild(ab)}ab=X}}function R(ac,ad){var Z=P(O[h],O[W]),aa=Z!=O[h],ae,ab,Y,t,X;if(Z==ac){return M(Z,aa,E,ad)}ae=Z.parentNode;ab=M(ae,S,E,ad);while(ae){while(Z){Y=Z.nextSibling;t=M(Z,aa,E,ad);if(ad!=j){ab.appendChild(t)}aa=E;Z=Y}if(ae==ac){return ab}Z=ae.nextSibling;ae=ae.parentNode;X=M(ae,S,E,ad);if(ad!=j){X.appendChild(ab)}ab=X}}function M(t,aa,ad,ae){var Z,Y,ab,X,ac;if(aa){return z(t,ae)}if(t.nodeType==3){Z=t.nodeValue;if(ad){X=O[W];Y=Z.substring(X);ab=Z.substring(0,X)}else{X=O[A];Y=Z.substring(0,X);ab=Z.substring(X)}if(ae!=F){t.nodeValue=ab}if(ae==j){return}ac=c.clone(t,S);ac.nodeValue=Y;return ac}if(ae==j){return}return c.clone(t,S)}function z(X,t){if(t!=j){return t==F?c.clone(X,E):X}X.parentNode.removeChild(X)}function T(){return c.create("body",null,d()).outerText}return O}a.Range=b;b.prototype.toString=function(){return this.toStringIE()}})(tinymce.dom);(function(){function a(d){var b=this,h=d.dom,c=true,f=false;function e(i,j){var k,t=0,q,n,m,l,o,r,p=-1,s;k=i.duplicate();k.collapse(j);s=k.parentElement();if(s.ownerDocument!==d.dom.doc){return}while(s.contentEditable==="false"){s=s.parentNode}if(!s.hasChildNodes()){return{node:s,inside:1}}m=s.children;q=m.length-1;while(t<=q){r=Math.floor((t+q)/2);l=m[r];k.moveToElementText(l);p=k.compareEndPoints(j?"StartToStart":"EndToEnd",i);if(p>0){q=r-1}else{if(p<0){t=r+1}else{return{node:l}}}}if(p<0){if(!l){k.moveToElementText(s);k.collapse(true);l=s;n=true}else{k.collapse(false)}o=0;while(k.compareEndPoints(j?"StartToStart":"StartToEnd",i)!==0){if(k.move("character",1)===0||s!=k.parentElement()){break}o++}}else{k.collapse(true);o=0;while(k.compareEndPoints(j?"StartToStart":"StartToEnd",i)!==0){if(k.move("character",-1)===0||s!=k.parentElement()){break}o++}}return{node:l,position:p,offset:o,inside:n}}function g(){var i=d.getRng(),r=h.createRng(),l,k,p,q,m,j;l=i.item?i.item(0):i.parentElement();if(l.ownerDocument!=h.doc){return r}k=d.isCollapsed();if(i.item){r.setStart(l.parentNode,h.nodeIndex(l));r.setEnd(r.startContainer,r.startOffset+1);return r}function o(A){var u=e(i,A),s,y,z=0,x,v,t;s=u.node;y=u.offset;if(u.inside&&!s.hasChildNodes()){r[A?"setStart":"setEnd"](s,0);return}if(y===v){r[A?"setStartBefore":"setEndAfter"](s);return}if(u.position<0){x=u.inside?s.firstChild:s.nextSibling;if(!x){r[A?"setStartAfter":"setEndAfter"](s);return}if(!y){if(x.nodeType==3){r[A?"setStart":"setEnd"](x,0)}else{r[A?"setStartBefore":"setEndBefore"](x)}return}while(x){t=x.nodeValue;z+=t.length;if(z>=y){s=x;z-=y;z=t.length-z;break}x=x.nextSibling}}else{x=s.previousSibling;if(!x){return r[A?"setStartBefore":"setEndBefore"](s)}if(!y){if(s.nodeType==3){r[A?"setStart":"setEnd"](x,s.nodeValue.length)}else{r[A?"setStartAfter":"setEndAfter"](x)}return}while(x){z+=x.nodeValue.length;if(z>=y){s=x;z-=y;break}x=x.previousSibling}}r[A?"setStart":"setEnd"](s,z)}try{o(true);if(!k){o()}}catch(n){if(n.number==-2147024809){m=b.getBookmark(2);p=i.duplicate();p.collapse(true);l=p.parentElement();if(!k){p=i.duplicate();p.collapse(false);q=p.parentElement();q.innerHTML=q.innerHTML}l.innerHTML=l.innerHTML;b.moveToBookmark(m);i=d.getRng();o(true);if(!k){o()}}else{throw n}}return r}this.getBookmark=function(m){var j=d.getRng(),o,i,l={};function n(u){var t,p,s,r,q=[];t=u.parentNode;p=h.getRoot().parentNode;while(t!=p&&t.nodeType!==9){s=t.children;r=s.length;while(r--){if(u===s[r]){q.push(r);break}}u=t;t=t.parentNode}return q}function k(q){var p;p=e(j,q);if(p){return{position:p.position,offset:p.offset,indexes:n(p.node),inside:p.inside}}}if(m===2){if(!j.item){l.start=k(true);if(!d.isCollapsed()){l.end=k()}}else{l.start={ctrl:true,indexes:n(j.item(0))}}}return l};this.moveToBookmark=function(k){var j,i=h.doc.body;function m(o){var r,q,n,p;r=h.getRoot();for(q=o.length-1;q>=0;q--){p=r.children;n=o[q];if(n<=p.length-1){r=p[n]}}return r}function l(r){var n=k[r?"start":"end"],q,p,o;if(n){q=n.position>0;p=i.createTextRange();p.moveToElementText(m(n.indexes));offset=n.offset;if(offset!==o){p.collapse(n.inside||q);p.moveStart("character",q?-offset:offset)}else{p.collapse(r)}j.setEndPoint(r?"StartToStart":"EndToStart",p);if(r){j.collapse(true)}}}if(k.start){if(k.start.ctrl){j=i.createControlRange();j.addElement(m(k.start.indexes));j.select()}else{j=i.createTextRange();l(true);l();j.select()}}};this.addRange=function(i){var n,l,k,p,t,q,s,r=d.dom.doc,m=r.body;function j(A){var v,z,u,y,x;u=h.create("a");v=A?k:t;z=A?p:q;y=n.duplicate();if(v==r||v==r.documentElement){v=m;z=0}if(v.nodeType==3){v.parentNode.insertBefore(u,v);y.moveToElementText(u);y.moveStart("character",z);h.remove(u);n.setEndPoint(A?"StartToStart":"EndToEnd",y)}else{x=v.childNodes;if(x.length){if(z>=x.length){h.insertAfter(u,x[x.length-1])}else{v.insertBefore(u,x[z])}y.moveToElementText(u)}else{if(v.canHaveHTML){v.innerHTML="<span>\uFEFF</span>";u=v.firstChild;y.moveToElementText(u);y.collapse(f)}}n.setEndPoint(A?"StartToStart":"EndToEnd",y);h.remove(u)}}k=i.startContainer;p=i.startOffset;t=i.endContainer;q=i.endOffset;n=m.createTextRange();if(k==t&&k.nodeType==1){if(p==q&&!k.hasChildNodes()){if(k.canHaveHTML){s=k.previousSibling;if(s&&!s.hasChildNodes()&&h.isBlock(s)){s.innerHTML="\uFEFF"}else{s=null}k.innerHTML="<span>\uFEFF</span><span>\uFEFF</span>";n.moveToElementText(k.lastChild);n.select();h.doc.selection.clear();k.innerHTML="";if(s){s.innerHTML=""}return}else{p=h.nodeIndex(k);k=k.parentNode}}if(p==q-1){try{l=m.createControlRange();l.addElement(k.childNodes[p]);l.select();return}catch(o){}}}j(true);j();n.select()};this.getRangeAt=g}tinymce.dom.TridentSelection=a})();(function(){var n=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,i="sizcache",o=0,r=Object.prototype.toString,h=false,g=true,q=/\\/g,u=/\r\n/g,x=/\W/;[0,0].sort(function(){g=false;return 0});var d=function(C,e,F,G){F=F||[];e=e||document;var I=e;if(e.nodeType!==1&&e.nodeType!==9){return[]}if(!C||typeof C!=="string"){return F}var z,K,N,y,J,M,L,E,B=true,A=d.isXML(e),D=[],H=C;do{n.exec("");z=n.exec(H);if(z){H=z[3];D.push(z[1]);if(z[2]){y=z[3];break}}}while(z);if(D.length>1&&j.exec(C)){if(D.length===2&&k.relative[D[0]]){K=s(D[0]+D[1],e,G)}else{K=k.relative[D[0]]?[e]:d(D.shift(),e);while(D.length){C=D.shift();if(k.relative[C]){C+=D.shift()}K=s(C,K,G)}}}else{if(!G&&D.length>1&&e.nodeType===9&&!A&&k.match.ID.test(D[0])&&!k.match.ID.test(D[D.length-1])){J=d.find(D.shift(),e,A);e=J.expr?d.filter(J.expr,J.set)[0]:J.set[0]}if(e){J=G?{expr:D.pop(),set:l(G)}:d.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&e.parentNode?e.parentNode:e,A);K=J.expr?d.filter(J.expr,J.set):J.set;if(D.length>0){N=l(K)}else{B=false}while(D.length){M=D.pop();L=M;if(!k.relative[M]){M=""}else{L=D.pop()}if(L==null){L=e}k.relative[M](N,L,A)}}else{N=D=[]}}if(!N){N=K}if(!N){d.error(M||C)}if(r.call(N)==="[object Array]"){if(!B){F.push.apply(F,N)}else{if(e&&e.nodeType===1){for(E=0;N[E]!=null;E++){if(N[E]&&(N[E]===true||N[E].nodeType===1&&d.contains(e,N[E]))){F.push(K[E])}}}else{for(E=0;N[E]!=null;E++){if(N[E]&&N[E].nodeType===1){F.push(K[E])}}}}}else{l(N,F)}if(y){d(y,I,F,G);d.uniqueSort(F)}return F};d.uniqueSort=function(y){if(p){h=g;y.sort(p);if(h){for(var e=1;e<y.length;e++){if(y[e]===y[e-1]){y.splice(e--,1)}}}}return y};d.matches=function(e,y){return d(e,null,null,y)};d.matchesSelector=function(e,y){return d(y,null,null,[e]).length>0};d.find=function(E,e,F){var D,z,B,A,C,y;if(!E){return[]}for(z=0,B=k.order.length;z<B;z++){C=k.order[z];if((A=k.leftMatch[C].exec(E))){y=A[1];A.splice(1,1);if(y.substr(y.length-1)!=="\\"){A[1]=(A[1]||"").replace(q,"");D=k.find[C](A,e,F);if(D!=null){E=E.replace(k.match[C],"");break}}}}if(!D){D=typeof e.getElementsByTagName!=="undefined"?e.getElementsByTagName("*"):[]}return{set:D,expr:E}};d.filter=function(I,H,L,B){var D,e,G,N,K,y,A,C,J,z=I,M=[],F=H,E=H&&H[0]&&d.isXML(H[0]);while(I&&H.length){for(G in k.filter){if((D=k.leftMatch[G].exec(I))!=null&&D[2]){y=k.filter[G];A=D[1];e=false;D.splice(1,1);if(A.substr(A.length-1)==="\\"){continue}if(F===M){M=[]}if(k.preFilter[G]){D=k.preFilter[G](D,F,L,M,B,E);if(!D){e=N=true}else{if(D===true){continue}}}if(D){for(C=0;(K=F[C])!=null;C++){if(K){N=y(K,D,C,F);J=B^N;if(L&&N!=null){if(J){e=true}else{F[C]=false}}else{if(J){M.push(K);e=true}}}}}if(N!==undefined){if(!L){F=M}I=I.replace(k.match[G],"");if(!e){return[]}break}}}if(I===z){if(e==null){d.error(I)}else{break}}z=I}return F};d.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)};var b=d.getText=function(B){var z,A,e=B.nodeType,y="";if(e){if(e===1||e===9||e===11){if(typeof B.textContent==="string"){return B.textContent}else{if(typeof B.innerText==="string"){return B.innerText.replace(u,"")}else{for(B=B.firstChild;B;B=B.nextSibling){y+=b(B)}}}}else{if(e===3||e===4){return B.nodeValue}}}else{for(z=0;(A=B[z]);z++){if(A.nodeType!==8){y+=b(A)}}}return y};var k=d.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|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(e){return e.getAttribute("href")},type:function(e){return e.getAttribute("type")}},relative:{"+":function(D,y){var A=typeof y==="string",C=A&&!x.test(y),E=A&&!C;if(C){y=y.toLowerCase()}for(var z=0,e=D.length,B;z<e;z++){if((B=D[z])){while((B=B.previousSibling)&&B.nodeType!==1){}D[z]=E||B&&B.nodeName.toLowerCase()===y?B||false:B===y}}if(E){d.filter(y,D,true)}},">":function(D,y){var C,B=typeof y==="string",z=0,e=D.length;if(B&&!x.test(y)){y=y.toLowerCase();for(;z<e;z++){C=D[z];if(C){var A=C.parentNode;D[z]=A.nodeName.toLowerCase()===y?A:false}}}else{for(;z<e;z++){C=D[z];if(C){D[z]=B?C.parentNode:C.parentNode===y}}if(B){d.filter(y,D,true)}}},"":function(A,y,C){var B,z=o++,e=t;if(typeof y==="string"&&!x.test(y)){y=y.toLowerCase();B=y;e=a}e("parentNode",y,z,A,B,C)},"~":function(A,y,C){var B,z=o++,e=t;if(typeof y==="string"&&!x.test(y)){y=y.toLowerCase();B=y;e=a}e("previousSibling",y,z,A,B,C)}},find:{ID:function(y,z,A){if(typeof z.getElementById!=="undefined"&&!A){var e=z.getElementById(y[1]);return e&&e.parentNode?[e]:[]}},NAME:function(z,C){if(typeof C.getElementsByName!=="undefined"){var y=[],B=C.getElementsByName(z[1]);for(var A=0,e=B.length;A<e;A++){if(B[A].getAttribute("name")===z[1]){y.push(B[A])}}return y.length===0?null:y}},TAG:function(e,y){if(typeof y.getElementsByTagName!=="undefined"){return y.getElementsByTagName(e[1])}}},preFilter:{CLASS:function(A,y,z,e,D,E){A=" "+A[1].replace(q,"")+" ";if(E){return A}for(var B=0,C;(C=y[B])!=null;B++){if(C){if(D^(C.className&&(" "+C.className+" ").replace(/[\t\n\r]/g," ").indexOf(A)>=0)){if(!z){e.push(C)}}else{if(z){y[B]=false}}}}return false},ID:function(e){return e[1].replace(q,"")},TAG:function(y,e){return y[1].replace(q,"").toLowerCase()},CHILD:function(e){if(e[1]==="nth"){if(!e[2]){d.error(e[0])}e[2]=e[2].replace(/^\+|\s*/g,"");var y=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(e[2]==="even"&&"2n"||e[2]==="odd"&&"2n+1"||!/\D/.test(e[2])&&"0n+"+e[2]||e[2]);e[2]=(y[1]+(y[2]||1))-0;e[3]=y[3]-0}else{if(e[2]){d.error(e[0])}}e[0]=o++;return e},ATTR:function(B,y,z,e,C,D){var A=B[1]=B[1].replace(q,"");if(!D&&k.attrMap[A]){B[1]=k.attrMap[A]}B[4]=(B[4]||B[5]||"").replace(q,"");if(B[2]==="~="){B[4]=" "+B[4]+" "}return B},PSEUDO:function(B,y,z,e,C){if(B[1]==="not"){if((n.exec(B[3])||"").length>1||/^\w/.test(B[3])){B[3]=d(B[3],null,null,y)}else{var A=d.filter(B[3],y,z,true^C);if(!z){e.push.apply(e,A)}return false}}else{if(k.match.POS.test(B[0])||k.match.CHILD.test(B[0])){return true}}return B},POS:function(e){e.unshift(true);return e}},filters:{enabled:function(e){return e.disabled===false&&e.type!=="hidden"},disabled:function(e){return e.disabled===true},checked:function(e){return e.checked===true},selected:function(e){if(e.parentNode){e.parentNode.selectedIndex}return e.selected===true},parent:function(e){return !!e.firstChild},empty:function(e){return !e.firstChild},has:function(z,y,e){return !!d(e[3],z).length},header:function(e){return(/h\d/i).test(e.nodeName)},text:function(z){var e=z.getAttribute("type"),y=z.type;return z.nodeName.toLowerCase()==="input"&&"text"===y&&(e===y||e===null)},radio:function(e){return e.nodeName.toLowerCase()==="input"&&"radio"===e.type},checkbox:function(e){return e.nodeName.toLowerCase()==="input"&&"checkbox"===e.type},file:function(e){return e.nodeName.toLowerCase()==="input"&&"file"===e.type},password:function(e){return e.nodeName.toLowerCase()==="input"&&"password"===e.type},submit:function(y){var e=y.nodeName.toLowerCase();return(e==="input"||e==="button")&&"submit"===y.type},image:function(e){return e.nodeName.toLowerCase()==="input"&&"image"===e.type},reset:function(y){var e=y.nodeName.toLowerCase();return(e==="input"||e==="button")&&"reset"===y.type},button:function(y){var e=y.nodeName.toLowerCase();return e==="input"&&"button"===y.type||e==="button"},input:function(e){return(/input|select|textarea|button/i).test(e.nodeName)},focus:function(e){return e===e.ownerDocument.activeElement}},setFilters:{first:function(y,e){return e===0},last:function(z,y,e,A){return y===A.length-1},even:function(y,e){return e%2===0},odd:function(y,e){return e%2===1},lt:function(z,y,e){return y<e[3]-0},gt:function(z,y,e){return y>e[3]-0},nth:function(z,y,e){return e[3]-0===y},eq:function(z,y,e){return e[3]-0===y}},filter:{PSEUDO:function(z,E,D,F){var e=E[1],y=k.filters[e];if(y){return y(z,D,E,F)}else{if(e==="contains"){return(z.textContent||z.innerText||b([z])||"").indexOf(E[3])>=0}else{if(e==="not"){var A=E[3];for(var C=0,B=A.length;C<B;C++){if(A[C]===z){return false}}return true}else{d.error(e)}}}},CHILD:function(z,B){var A,H,D,G,e,C,F,E=B[1],y=z;switch(E){case"only":case"first":while((y=y.previousSibling)){if(y.nodeType===1){return false}}if(E==="first"){return true}y=z;case"last":while((y=y.nextSibling)){if(y.nodeType===1){return false}}return true;case"nth":A=B[2];H=B[3];if(A===1&&H===0){return true}D=B[0];G=z.parentNode;if(G&&(G[i]!==D||!z.nodeIndex)){C=0;for(y=G.firstChild;y;y=y.nextSibling){if(y.nodeType===1){y.nodeIndex=++C}}G[i]=D}F=z.nodeIndex-H;if(A===0){return F===0}else{return(F%A===0&&F/A>=0)}}},ID:function(y,e){return y.nodeType===1&&y.getAttribute("id")===e},TAG:function(y,e){return(e==="*"&&y.nodeType===1)||!!y.nodeName&&y.nodeName.toLowerCase()===e},CLASS:function(y,e){return(" "+(y.className||y.getAttribute("class"))+" ").indexOf(e)>-1},ATTR:function(C,A){var z=A[1],e=d.attr?d.attr(C,z):k.attrHandle[z]?k.attrHandle[z](C):C[z]!=null?C[z]:C.getAttribute(z),D=e+"",B=A[2],y=A[4];return e==null?B==="!=":!B&&d.attr?e!=null:B==="="?D===y:B==="*="?D.indexOf(y)>=0:B==="~="?(" "+D+" ").indexOf(y)>=0:!y?D&&e!==false:B==="!="?D!==y:B==="^="?D.indexOf(y)===0:B==="$="?D.substr(D.length-y.length)===y:B==="|="?D===y||D.substr(0,y.length+1)===y+"-":false},POS:function(B,y,z,C){var e=y[2],A=k.setFilters[e];if(A){return A(B,z,y,C)}}}};var j=k.match.POS,c=function(y,e){return"\\"+(e-0+1)};for(var f in k.match){k.match[f]=new RegExp(k.match[f].source+(/(?![^\[]*\])(?![^\(]*\))/.source));k.leftMatch[f]=new RegExp(/(^(?:.|\r|\n)*?)/.source+k.match[f].source.replace(/\\(\d+)/g,c))}k.match.globalPOS=j;var l=function(y,e){y=Array.prototype.slice.call(y,0);if(e){e.push.apply(e,y);return e}return y};try{Array.prototype.slice.call(document.documentElement.childNodes,0)[0].nodeType}catch(v){l=function(B,A){var z=0,y=A||[];if(r.call(B)==="[object Array]"){Array.prototype.push.apply(y,B)}else{if(typeof B.length==="number"){for(var e=B.length;z<e;z++){y.push(B[z])}}else{for(;B[z];z++){y.push(B[z])}}}return y}}var p,m;if(document.documentElement.compareDocumentPosition){p=function(y,e){if(y===e){h=true;return 0}if(!y.compareDocumentPosition||!e.compareDocumentPosition){return y.compareDocumentPosition?-1:1}return y.compareDocumentPosition(e)&4?-1:1}}else{p=function(F,E){if(F===E){h=true;return 0}else{if(F.sourceIndex&&E.sourceIndex){return F.sourceIndex-E.sourceIndex}}var C,y,z=[],e=[],B=F.parentNode,D=E.parentNode,G=B;if(B===D){return m(F,E)}else{if(!B){return -1}else{if(!D){return 1}}}while(G){z.unshift(G);G=G.parentNode}G=D;while(G){e.unshift(G);G=G.parentNode}C=z.length;y=e.length;for(var A=0;A<C&&A<y;A++){if(z[A]!==e[A]){return m(z[A],e[A])}}return A===C?m(F,e[A],-1):m(z[A],E,1)};m=function(y,e,z){if(y===e){return z}var A=y.nextSibling;while(A){if(A===e){return -1}A=A.nextSibling}return 1}}(function(){var y=document.createElement("div"),z="script"+(new Date()).getTime(),e=document.documentElement;y.innerHTML="<a name='"+z+"'/>";e.insertBefore(y,e.firstChild);if(document.getElementById(z)){k.find.ID=function(B,C,D){if(typeof C.getElementById!=="undefined"&&!D){var A=C.getElementById(B[1]);return A?A.id===B[1]||typeof A.getAttributeNode!=="undefined"&&A.getAttributeNode("id").nodeValue===B[1]?[A]:undefined:[]}};k.filter.ID=function(C,A){var B=typeof C.getAttributeNode!=="undefined"&&C.getAttributeNode("id");return C.nodeType===1&&B&&B.nodeValue===A}}e.removeChild(y);e=y=null})();(function(){var e=document.createElement("div");e.appendChild(document.createComment(""));if(e.getElementsByTagName("*").length>0){k.find.TAG=function(y,C){var B=C.getElementsByTagName(y[1]);if(y[1]==="*"){var A=[];for(var z=0;B[z];z++){if(B[z].nodeType===1){A.push(B[z])}}B=A}return B}}e.innerHTML="<a href='#'></a>";if(e.firstChild&&typeof e.firstChild.getAttribute!=="undefined"&&e.firstChild.getAttribute("href")!=="#"){k.attrHandle.href=function(y){return y.getAttribute("href",2)}}e=null})();if(document.querySelectorAll){(function(){var e=d,A=document.createElement("div"),z="__sizzle__";A.innerHTML="<p class='TEST'></p>";if(A.querySelectorAll&&A.querySelectorAll(".TEST").length===0){return}d=function(L,C,G,K){C=C||document;if(!K&&!d.isXML(C)){var J=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(L);if(J&&(C.nodeType===1||C.nodeType===9)){if(J[1]){return l(C.getElementsByTagName(L),G)}else{if(J[2]&&k.find.CLASS&&C.getElementsByClassName){return l(C.getElementsByClassName(J[2]),G)}}}if(C.nodeType===9){if(L==="body"&&C.body){return l([C.body],G)}else{if(J&&J[3]){var F=C.getElementById(J[3]);if(F&&F.parentNode){if(F.id===J[3]){return l([F],G)}}else{return l([],G)}}}try{return l(C.querySelectorAll(L),G)}catch(H){}}else{if(C.nodeType===1&&C.nodeName.toLowerCase()!=="object"){var D=C,E=C.getAttribute("id"),B=E||z,N=C.parentNode,M=/^\s*[+~]/.test(L);if(!E){C.setAttribute("id",B)}else{B=B.replace(/'/g,"\\$&")}if(M&&N){C=C.parentNode}try{if(!M||N){return l(C.querySelectorAll("[id='"+B+"'] "+L),G)}}catch(I){}finally{if(!E){D.removeAttribute("id")}}}}}return e(L,C,G,K)};for(var y in e){d[y]=e[y]}A=null})()}(function(){var e=document.documentElement,z=e.matchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.msMatchesSelector;if(z){var B=!z.call(document.createElement("div"),"div"),y=false;try{z.call(document.documentElement,"[test!='']:sizzle")}catch(A){y=true}d.matchesSelector=function(D,F){F=F.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!d.isXML(D)){try{if(y||!k.match.PSEUDO.test(F)&&!/!=/.test(F)){var C=z.call(D,F);if(C||!B||D.document&&D.document.nodeType!==11){return C}}}catch(E){}}return d(F,null,null,[D]).length>0}}})();(function(){var e=document.createElement("div");e.innerHTML="<div class='test e'></div><div class='test'></div>";if(!e.getElementsByClassName||e.getElementsByClassName("e").length===0){return}e.lastChild.className="e";if(e.getElementsByClassName("e").length===1){return}k.order.splice(1,0,"CLASS");k.find.CLASS=function(y,z,A){if(typeof z.getElementsByClassName!=="undefined"&&!A){return z.getElementsByClassName(y[1])}};e=null})();function a(y,D,C,G,E,F){for(var A=0,z=G.length;A<z;A++){var e=G[A];if(e){var B=false;e=e[y];while(e){if(e[i]===C){B=G[e.sizset];break}if(e.nodeType===1&&!F){e[i]=C;e.sizset=A}if(e.nodeName.toLowerCase()===D){B=e;break}e=e[y]}G[A]=B}}}function t(y,D,C,G,E,F){for(var A=0,z=G.length;A<z;A++){var e=G[A];if(e){var B=false;e=e[y];while(e){if(e[i]===C){B=G[e.sizset];break}if(e.nodeType===1){if(!F){e[i]=C;e.sizset=A}if(typeof D!=="string"){if(e===D){B=true;break}}else{if(d.filter(D,[e]).length>0){B=e;break}}}e=e[y]}G[A]=B}}}if(document.documentElement.contains){d.contains=function(y,e){return y!==e&&(y.contains?y.contains(e):true)}}else{if(document.documentElement.compareDocumentPosition){d.contains=function(y,e){return !!(y.compareDocumentPosition(e)&16)}}else{d.contains=function(){return false}}}d.isXML=function(e){var y=(e?e.ownerDocument||e:0).documentElement;return y?y.nodeName!=="HTML":false};var s=function(z,e,D){var C,E=[],B="",F=e.nodeType?[e]:e;while((C=k.match.PSEUDO.exec(z))){B+=C[0];z=z.replace(k.match.PSEUDO,"")}z=k.relative[z]?z+"*":z;for(var A=0,y=F.length;A<y;A++){d(z,F[A],E,D)}return d.filter(B,E)};window.tinymce.dom.Sizzle=d})();(function(a){a.dom.Element=function(f,d){var b=this,e,c;b.settings=d=d||{};b.id=f;b.dom=e=d.dom||a.DOM;if(!a.isIE){c=e.get(b.id)}a.each(("getPos,getRect,getParent,add,setStyle,getStyle,setStyles,setAttrib,setAttribs,getAttrib,addClass,removeClass,hasClass,getOuterHTML,setOuterHTML,remove,show,hide,isHidden,setHTML,get").split(/,/),function(g){b[g]=function(){var h=[f],j;for(j=0;j<arguments.length;j++){h.push(arguments[j])}h=e[g].apply(e,h);b.update(g);return h}});a.extend(b,{on:function(i,h,g){return a.dom.Event.add(b.id,i,h,g)},getXY:function(){return{x:parseInt(b.getStyle("left")),y:parseInt(b.getStyle("top"))}},getSize:function(){var g=e.get(b.id);return{w:parseInt(b.getStyle("width")||g.clientWidth),h:parseInt(b.getStyle("height")||g.clientHeight)}},moveTo:function(g,h){b.setStyles({left:g,top:h})},moveBy:function(g,i){var h=b.getXY();b.moveTo(h.x+g,h.y+i)},resizeTo:function(g,i){b.setStyles({width:g,height:i})},resizeBy:function(g,j){var i=b.getSize();b.resizeTo(i.w+g,i.h+j)},update:function(h){var g;if(a.isIE6&&d.blocker){h=h||"";if(h.indexOf("get")===0||h.indexOf("has")===0||h.indexOf("is")===0){return}if(h=="remove"){e.remove(b.blocker);return}if(!b.blocker){b.blocker=e.uniqueId();g=e.add(d.container||e.getRoot(),"iframe",{id:b.blocker,style:"position:absolute;",frameBorder:0,src:'javascript:""'});e.setStyle(g,"opacity",0)}else{g=e.get(b.blocker)}e.setStyles(g,{left:b.getStyle("left",1),top:b.getStyle("top",1),width:b.getStyle("width",1),height:b.getStyle("height",1),display:b.getStyle("display",1),zIndex:parseInt(b.getStyle("zIndex",1)||0)-1})}}})}})(tinymce);(function(d){function f(g){return g.replace(/[\n\r]+/g,"")}var c=d.is,b=d.isIE,e=d.each,a=d.dom.TreeWalker;d.create("tinymce.dom.Selection",{Selection:function(k,j,i,h){var g=this;g.dom=k;g.win=j;g.serializer=i;g.editor=h;e(["onBeforeSetContent","onBeforeGetContent","onSetContent","onGetContent"],function(l){g[l]=new d.util.Dispatcher(g)});if(!g.win.getSelection){g.tridentSel=new d.dom.TridentSelection(g)}if(d.isIE&&k.boxModel){this._fixIESelection()}d.addUnload(g.destroy,g)},setCursorLocation:function(i,j){var g=this;var h=g.dom.createRng();h.setStart(i,j);h.setEnd(i,j);g.setRng(h);g.collapse(false)},getContent:function(h){var g=this,i=g.getRng(),m=g.dom.create("body"),k=g.getSel(),j,l,o;h=h||{};j=l="";h.get=true;h.format=h.format||"html";h.forced_root_block="";g.onBeforeGetContent.dispatch(g,h);if(h.format=="text"){return g.isCollapsed()?"":(i.text||(k.toString?k.toString():""))}if(i.cloneContents){o=i.cloneContents();if(o){m.appendChild(o)}}else{if(c(i.item)||c(i.htmlText)){m.innerHTML="<br>"+(i.item?i.item(0).outerHTML:i.htmlText);m.removeChild(m.firstChild)}else{m.innerHTML=i.toString()}}if(/^\s/.test(m.innerHTML)){j=" "}if(/\s+$/.test(m.innerHTML)){l=" "}h.getInner=true;h.content=g.isCollapsed()?"":j+g.serializer.serialize(m,h)+l;g.onGetContent.dispatch(g,h);return h.content},setContent:function(h,j){var o=this,g=o.getRng(),k,l=o.win.document,n,m;j=j||{format:"html"};j.set=true;h=j.content=h;if(!j.no_events){o.onBeforeSetContent.dispatch(o,j)}h=j.content;if(g.insertNode){h+='<span id="__caret">_</span>';if(g.startContainer==l&&g.endContainer==l){l.body.innerHTML=h}else{g.deleteContents();if(l.body.childNodes.length===0){l.body.innerHTML=h}else{if(g.createContextualFragment){g.insertNode(g.createContextualFragment(h))}else{n=l.createDocumentFragment();m=l.createElement("div");n.appendChild(m);m.outerHTML=h;g.insertNode(n)}}}k=o.dom.get("__caret");g=l.createRange();g.setStartBefore(k);g.setEndBefore(k);o.setRng(g);o.dom.remove("__caret");try{o.setRng(g)}catch(i){}}else{if(g.item){l.execCommand("Delete",false,null);g=o.getRng()}if(/^\s+/.test(h)){g.pasteHTML('<span id="__mce_tmp">_</span>'+h);o.dom.remove("__mce_tmp")}else{g.pasteHTML(h)}}if(!j.no_events){o.onSetContent.dispatch(o,j)}},getStart:function(){var i=this,h=i.getRng(),j,g,l,k;if(h.duplicate||h.item){if(h.item){return h.item(0)}l=h.duplicate();l.collapse(1);j=l.parentElement();if(j.ownerDocument!==i.dom.doc){j=i.dom.getRoot()}g=k=h.parentElement();while(k=k.parentNode){if(k==j){j=g;break}}return j}else{j=h.startContainer;if(j.nodeType==1&&j.hasChildNodes()){j=j.childNodes[Math.min(j.childNodes.length-1,h.startOffset)]}if(j&&j.nodeType==3){return j.parentNode}return j}},getEnd:function(){var h=this,g=h.getRng(),j,i;if(g.duplicate||g.item){if(g.item){return g.item(0)}g=g.duplicate();g.collapse(0);j=g.parentElement();if(j.ownerDocument!==h.dom.doc){j=h.dom.getRoot()}if(j&&j.nodeName=="BODY"){return j.lastChild||j}return j}else{j=g.endContainer;i=g.endOffset;if(j.nodeType==1&&j.hasChildNodes()){j=j.childNodes[i>0?i-1:i]}if(j&&j.nodeType==3){return j.parentNode}return j}},getBookmark:function(s,v){var y=this,n=y.dom,h,k,j,o,i,p,q,m="\uFEFF",x;function g(z,A){var t=0;e(n.select(z),function(C,B){if(C==A){t=B}});return t}function u(t){function z(E){var A,D,C,B=E?"start":"end";A=t[B+"Container"];D=t[B+"Offset"];if(A.nodeType==1&&A.nodeName=="TR"){C=A.childNodes;A=C[Math.min(E?D:D-1,C.length-1)];if(A){D=E?0:A.childNodes.length;t["set"+(E?"Start":"End")](A,D)}}}z(true);z();return t}function l(){var z=y.getRng(true),t=n.getRoot(),A={};function B(E,J){var D=E[J?"startContainer":"endContainer"],I=E[J?"startOffset":"endOffset"],C=[],F,H,G=0;if(D.nodeType==3){if(v){for(F=D.previousSibling;F&&F.nodeType==3;F=F.previousSibling){I+=F.nodeValue.length}}C.push(I)}else{H=D.childNodes;if(I>=H.length&&H.length){G=1;I=Math.max(0,H.length-1)}C.push(y.dom.nodeIndex(H[I],v)+G)}for(;D&&D!=t;D=D.parentNode){C.push(y.dom.nodeIndex(D,v))}return C}A.start=B(z,true);if(!y.isCollapsed()){A.end=B(z)}return A}if(s==2){if(y.tridentSel){return y.tridentSel.getBookmark(s)}return l()}if(s){return{rng:y.getRng()}}h=y.getRng();j=n.uniqueId();o=tinyMCE.activeEditor.selection.isCollapsed();x="overflow:hidden;line-height:0px";if(h.duplicate||h.item){if(!h.item){k=h.duplicate();try{h.collapse();h.pasteHTML('<span data-mce-type="bookmark" id="'+j+'_start" style="'+x+'">'+m+"</span>");if(!o){k.collapse(false);h.moveToElementText(k.parentElement());if(h.compareEndPoints("StartToEnd",k)===0){k.move("character",-1)}k.pasteHTML('<span data-mce-type="bookmark" id="'+j+'_end" style="'+x+'">'+m+"</span>")}}catch(r){return null}}else{p=h.item(0);i=p.nodeName;return{name:i,index:g(i,p)}}}else{p=y.getNode();i=p.nodeName;if(i=="IMG"){return{name:i,index:g(i,p)}}k=u(h.cloneRange());if(!o){k.collapse(false);k.insertNode(n.create("span",{"data-mce-type":"bookmark",id:j+"_end",style:x},m))}h=u(h);h.collapse(true);h.insertNode(n.create("span",{"data-mce-type":"bookmark",id:j+"_start",style:x},m))}y.moveToBookmark({id:j,keep:1});return{id:j}},moveToBookmark:function(o){var s=this,m=s.dom,j,i,g,r,k,u,p,q;function h(A){var t=o[A?"start":"end"],x,y,z,v;if(t){z=t[0];for(y=r,x=t.length-1;x>=1;x--){v=y.childNodes;if(t[x]>v.length-1){return}y=v[t[x]]}if(y.nodeType===3){z=Math.min(t[0],y.nodeValue.length)}if(y.nodeType===1){z=Math.min(t[0],y.childNodes.length)}if(A){g.setStart(y,z)}else{g.setEnd(y,z)}}return true}function l(B){var v=m.get(o.id+"_"+B),A,t,y,z,x=o.keep;if(v){A=v.parentNode;if(B=="start"){if(!x){t=m.nodeIndex(v)}else{A=v.firstChild;t=1}k=u=A;p=q=t}else{if(!x){t=m.nodeIndex(v)}else{A=v.firstChild;t=1}u=A;q=t}if(!x){z=v.previousSibling;y=v.nextSibling;e(d.grep(v.childNodes),function(C){if(C.nodeType==3){C.nodeValue=C.nodeValue.replace(/\uFEFF/g,"")}});while(v=m.get(o.id+"_"+B)){m.remove(v,1)}if(z&&y&&z.nodeType==y.nodeType&&z.nodeType==3&&!d.isOpera){t=z.nodeValue.length;z.appendData(y.nodeValue);m.remove(y);if(B=="start"){k=u=z;p=q=t}else{u=z;q=t}}}}}function n(t){if(m.isBlock(t)&&!t.innerHTML&&!b){t.innerHTML='<br data-mce-bogus="1" />'}return t}if(o){if(o.start){g=m.createRng();r=m.getRoot();if(s.tridentSel){return s.tridentSel.moveToBookmark(o)}if(h(true)&&h()){s.setRng(g)}}else{if(o.id){l("start");l("end");if(k){g=m.createRng();g.setStart(n(k),p);g.setEnd(n(u),q);s.setRng(g)}}else{if(o.name){s.select(m.select(o.name)[o.index])}else{if(o.rng){s.setRng(o.rng)}}}}}},select:function(l,k){var j=this,m=j.dom,h=m.createRng(),g;function i(n,p){var o=new a(n,n);do{if(n.nodeType==3&&d.trim(n.nodeValue).length!==0){if(p){h.setStart(n,0)}else{h.setEnd(n,n.nodeValue.length)}return}if(n.nodeName=="BR"){if(p){h.setStartBefore(n)}else{h.setEndBefore(n)}return}}while(n=(p?o.next():o.prev()))}if(l){g=m.nodeIndex(l);h.setStart(l.parentNode,g);h.setEnd(l.parentNode,g+1);if(k){i(l,1);i(l)}j.setRng(h)}return l},isCollapsed:function(){var g=this,i=g.getRng(),h=g.getSel();if(!i||i.item){return false}if(i.compareEndPoints){return i.compareEndPoints("StartToEnd",i)===0}return !h||i.collapsed},collapse:function(g){var i=this,h=i.getRng(),j;if(h.item){j=h.item(0);h=i.win.document.body.createTextRange();h.moveToElementText(j)}h.collapse(!!g);i.setRng(h)},getSel:function(){var h=this,g=this.win;return g.getSelection?g.getSelection():g.document.selection},getRng:function(m){var h=this,j,g,l,k=h.win.document;if(m&&h.tridentSel){return h.tridentSel.getRangeAt(0)}try{if(j=h.getSel()){g=j.rangeCount>0?j.getRangeAt(0):(j.createRange?j.createRange():k.createRange())}}catch(i){}if(d.isIE&&g&&g.setStart&&k.selection.createRange().item){l=k.selection.createRange().item(0);g=k.createRange();g.setStartBefore(l);g.setEndAfter(l)}if(!g){g=k.createRange?k.createRange():k.body.createTextRange()}if(g.setStart&&g.startContainer.nodeType===9&&g.collapsed){l=h.dom.getRoot();g.setStart(l,0);g.setEnd(l,0)}if(h.selectedRange&&h.explicitRange){if(g.compareBoundaryPoints(g.START_TO_START,h.selectedRange)===0&&g.compareBoundaryPoints(g.END_TO_END,h.selectedRange)===0){g=h.explicitRange}else{h.selectedRange=null;h.explicitRange=null}}return g},setRng:function(k,g){var j,i=this;if(!i.tridentSel){j=i.getSel();if(j){i.explicitRange=k;try{j.removeAllRanges()}catch(h){}j.addRange(k);if(g===false&&j.extend){j.collapse(k.endContainer,k.endOffset);j.extend(k.startContainer,k.startOffset)}i.selectedRange=j.rangeCount>0?j.getRangeAt(0):null}}else{if(k.cloneRange){try{i.tridentSel.addRange(k);return}catch(h){}}try{k.select()}catch(h){}}},setNode:function(h){var g=this;g.setContent(g.dom.getOuterHTML(h));return h},getNode:function(){var i=this,h=i.getRng(),j=i.getSel(),m,l=h.startContainer,g=h.endContainer;function k(q,o){var p=q;while(q&&q.nodeType===3&&q.length===0){q=o?q.nextSibling:q.previousSibling}return q||p}if(!h){return i.dom.getRoot()}if(h.setStart){m=h.commonAncestorContainer;if(!h.collapsed){if(h.startContainer==h.endContainer){if(h.endOffset-h.startOffset<2){if(h.startContainer.hasChildNodes()){m=h.startContainer.childNodes[h.startOffset]}}}if(l.nodeType===3&&g.nodeType===3){if(l.length===h.startOffset){l=k(l.nextSibling,true)}else{l=l.parentNode}if(h.endOffset===0){g=k(g.previousSibling,false)}else{g=g.parentNode}if(l&&l===g){return l}}}if(m&&m.nodeType==3){return m.parentNode}return m}return h.item?h.item(0):h.parentElement()},getSelectedBlocks:function(p,h){var o=this,k=o.dom,m,l,i,j=[];m=k.getParent(p||o.getStart(),k.isBlock);l=k.getParent(h||o.getEnd(),k.isBlock);if(m){j.push(m)}if(m&&l&&m!=l){i=m;var g=new a(m,k.getRoot());while((i=g.next())&&i!=l){if(k.isBlock(i)){j.push(i)}}}if(l&&m!=l){j.push(l)}return j},isForward:function(){var i=this.dom,g=this.getSel(),j,h;if(!g||g.anchorNode==null||g.focusNode==null){return true}j=i.createRng();j.setStart(g.anchorNode,g.anchorOffset);j.collapse(true);h=i.createRng();h.setStart(g.focusNode,g.focusOffset);h.collapse(true);return j.compareBoundaryPoints(j.START_TO_START,h)<=0},normalize:function(){var h=this,g,m,l,j,i;function k(p){var o,r,n,s=h.dom,u=s.getRoot(),q,t,v;function y(z,A){var B=new a(z,s.getParent(z.parentNode,s.isBlock)||u);while(z=B[A?"prev":"next"]()){if(z.nodeName==="BR"){return true}}}function x(B,z){var C,A;z=z||o;C=new a(z,s.getParent(z.parentNode,s.isBlock)||u);while(q=C[B?"prev":"next"]()){if(q.nodeType===3&&q.nodeValue.length>0){o=q;r=B?q.nodeValue.length:0;m=true;return}if(s.isBlock(q)||t[q.nodeName.toLowerCase()]){return}A=q}if(l&&A){o=A;m=true;r=0}}o=g[(p?"start":"end")+"Container"];r=g[(p?"start":"end")+"Offset"];t=s.schema.getNonEmptyElements();if(o.nodeType===9){o=s.getRoot();r=0}if(o===u){if(p){q=o.childNodes[r>0?r-1:0];if(q){v=q.nodeName.toLowerCase();if(t[q.nodeName]||q.nodeName=="TABLE"){return}}}if(o.hasChildNodes()){o=o.childNodes[Math.min(!p&&r>0?r-1:r,o.childNodes.length-1)];r=0;if(o.hasChildNodes()&&!/TABLE/.test(o.nodeName)){q=o;n=new a(o,u);do{if(q.nodeType===3&&q.nodeValue.length>0){r=p?0:q.nodeValue.length;o=q;m=true;break}if(t[q.nodeName.toLowerCase()]){r=s.nodeIndex(q);o=q.parentNode;if(q.nodeName=="IMG"&&!p){r++}m=true;break}}while(q=(p?n.next():n.prev()))}}}if(l){if(o.nodeType===3&&r===0){x(true)}if(o.nodeType===1){q=o.childNodes[r];if(q&&q.nodeName==="BR"&&!y(q)&&!y(q,true)){x(true,o.childNodes[r])}}}if(p&&!l&&o.nodeType===3&&r===o.nodeValue.length){x(false)}if(m){g["set"+(p?"Start":"End")](o,r)}}if(d.isIE){return}g=h.getRng();l=g.collapsed;k(true);if(!l){k()}if(m){if(l){g.collapse(true)}h.setRng(g,h.isForward())}},selectorChanged:function(g,j){var h=this,i;if(!h.selectorChangedData){h.selectorChangedData={};i={};h.editor.onNodeChange.addToTop(function(l,k,o){var p=h.dom,m=p.getParents(o,null,p.getRoot()),n={};e(h.selectorChangedData,function(r,q){e(m,function(s){if(p.is(s,q)){if(!i[q]){e(r,function(t){t(true,{node:s,selector:q,parents:m})});i[q]=r}n[q]=r;return false}})});e(i,function(r,q){if(!n[q]){delete i[q];e(r,function(s){s(false,{node:o,selector:q,parents:m})})}})})}if(!h.selectorChangedData[g]){h.selectorChangedData[g]=[]}h.selectorChangedData[g].push(j);return h},destroy:function(h){var g=this;g.win=null;if(!h){d.removeUnload(g.destroy)}},_fixIESelection:function(){var h=this.dom,n=h.doc,i=n.body,k,o,g;function j(p,s){var q=i.createTextRange();try{q.moveToPoint(p,s)}catch(r){q=null}return q}function m(q){var p;if(q.button){p=j(q.x,q.y);if(p){if(p.compareEndPoints("StartToStart",o)>0){p.setEndPoint("StartToStart",o)}else{p.setEndPoint("EndToEnd",o)}p.select()}}else{l()}}function l(){var p=n.selection.createRange();if(o&&!p.item&&p.compareEndPoints("StartToEnd",p)===0){o.select()}h.unbind(n,"mouseup",l);h.unbind(n,"mousemove",m);o=k=0}n.documentElement.unselectable=true;h.bind(n,["mousedown","contextmenu"],function(p){if(p.target.nodeName==="HTML"){if(k){l()}g=n.documentElement;if(g.scrollHeight>g.clientHeight){return}k=1;o=j(p.x,p.y);if(o){h.bind(n,"mouseup",l);h.bind(n,"mousemove",m);h.win.focus();o.select()}}})}})})(tinymce);(function(a){a.dom.Serializer=function(e,i,f){var h,b,d=a.isIE,g=a.each,c;if(!e.apply_source_formatting){e.indent=false}i=i||a.DOM;f=f||new a.html.Schema(e);e.entity_encoding=e.entity_encoding||"named";e.remove_trailing_brs="remove_trailing_brs" in e?e.remove_trailing_brs:true;h=new a.util.Dispatcher(self);b=new a.util.Dispatcher(self);c=new a.html.DomParser(e,f);c.addAttributeFilter("src,href,style",function(k,j){var o=k.length,l,q,n="data-mce-"+j,p=e.url_converter,r=e.url_converter_scope,m;while(o--){l=k[o];q=l.attributes.map[n];if(q!==m){l.attr(j,q.length>0?q:null);l.attr(n,null)}else{q=l.attributes.map[j];if(j==="style"){q=i.serializeStyle(i.parseStyle(q),l.name)}else{if(p){q=p.call(r,q,j,l.name)}}l.attr(j,q.length>0?q:null)}}});c.addAttributeFilter("class",function(j,k){var l=j.length,m,n;while(l--){m=j[l];n=m.attr("class").replace(/(?:^|\s)mce(Item\w+|Selected)(?!\S)/g,"");m.attr("class",n.length>0?n:null)}});c.addAttributeFilter("data-mce-type",function(j,l,k){var m=j.length,n;while(m--){n=j[m];if(n.attributes.map["data-mce-type"]==="bookmark"&&!k.cleanup){n.remove()}}});c.addAttributeFilter("data-mce-expando",function(j,l,k){var m=j.length;while(m--){j[m].attr(l,null)}});c.addNodeFilter("script,style",function(k,l){var m=k.length,n,o;function j(p){return p.replace(/(<!--\[CDATA\[|\]\]-->)/g,"\n").replace(/^[\r\n]*|[\r\n]*$/g,"").replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi,"").replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g,"")}while(m--){n=k[m];o=n.firstChild?n.firstChild.value:"";if(l==="script"){n.attr("type",(n.attr("type")||"text/javascript").replace(/^mce\-/,""));if(o.length>0){n.firstChild.value="// <![CDATA[\n"+j(o)+"\n// ]]>"}}else{if(o.length>0){n.firstChild.value="<!--\n"+j(o)+"\n-->"}}}});c.addNodeFilter("#comment",function(j,k){var l=j.length,m;while(l--){m=j[l];if(m.value.indexOf("[CDATA[")===0){m.name="#cdata";m.type=4;m.value=m.value.replace(/^\[CDATA\[|\]\]$/g,"")}else{if(m.value.indexOf("mce:protected ")===0){m.name="#text";m.type=3;m.raw=true;m.value=unescape(m.value).substr(14)}}}});c.addNodeFilter("xml:namespace,input",function(j,k){var l=j.length,m;while(l--){m=j[l];if(m.type===7){m.remove()}else{if(m.type===1){if(k==="input"&&!("type" in m.attributes.map)){m.attr("type","text")}}}}});if(e.fix_list_elements){c.addNodeFilter("ul,ol",function(k,l){var m=k.length,n,j;while(m--){n=k[m];j=n.parent;if(j.name==="ul"||j.name==="ol"){if(n.prev&&n.prev.name==="li"){n.prev.append(n)}}}})}c.addAttributeFilter("data-mce-src,data-mce-href,data-mce-style",function(j,k){var l=j.length;while(l--){j[l].attr(k,null)}});return{schema:f,addNodeFilter:c.addNodeFilter,addAttributeFilter:c.addAttributeFilter,onPreProcess:h,onPostProcess:b,serialize:function(o,m){var l,p,k,j,n;if(d&&i.select("script,style,select,map").length>0){n=o.innerHTML;o=o.cloneNode(false);i.setHTML(o,n)}else{o=o.cloneNode(true)}l=o.ownerDocument.implementation;if(l.createHTMLDocument){p=l.createHTMLDocument("");g(o.nodeName=="BODY"?o.childNodes:[o],function(q){p.body.appendChild(p.importNode(q,true))});if(o.nodeName!="BODY"){o=p.body.firstChild}else{o=p.body}k=i.doc;i.doc=p}m=m||{};m.format=m.format||"html";if(!m.no_events){m.node=o;h.dispatch(self,m)}j=new a.html.Serializer(e,f);m.content=j.serialize(c.parse(a.trim(m.getInner?o.innerHTML:i.getOuterHTML(o)),m));if(!m.cleanup){m.content=m.content.replace(/\uFEFF|\u200B/g,"")}if(!m.no_events){b.dispatch(self,m)}if(k){i.doc=k}m.node=null;return m.content},addRules:function(j){f.addValidElements(j)},setRules:function(j){f.setValidElements(j)}}}})(tinymce);(function(a){a.dom.ScriptLoader=function(h){var c=0,k=1,i=2,l={},j=[],e={},d=[],g=0,f;function b(m,v){var x=this,q=a.DOM,s,o,r,n;function p(){q.remove(n);if(s){s.onreadystatechange=s.onload=s=null}v()}function u(){if(typeof(console)!=="undefined"&&console.log){console.log("Failed to load: "+m)}}n=q.uniqueId();if(a.isIE6){o=new a.util.URI(m);r=location;if(o.host==r.hostname&&o.port==r.port&&(o.protocol+":")==r.protocol&&o.protocol.toLowerCase()!="file"){a.util.XHR.send({url:a._addVer(o.getURI()),success:function(y){var t=q.create("script",{type:"text/javascript"});t.text=y;document.getElementsByTagName("head")[0].appendChild(t);q.remove(t);p()},error:u});return}}s=document.createElement("script");s.id=n;s.type="text/javascript";s.src=a._addVer(m);if(!a.isIE){s.onload=p}s.onerror=u;if(!a.isOpera){s.onreadystatechange=function(){var t=s.readyState;if(t=="complete"||t=="loaded"){p()}}}(document.getElementsByTagName("head")[0]||document.body).appendChild(s)}this.isDone=function(m){return l[m]==i};this.markDone=function(m){l[m]=i};this.add=this.load=function(m,q,n){var o,p=l[m];if(p==f){j.push(m);l[m]=c}if(q){if(!e[m]){e[m]=[]}e[m].push({func:q,scope:n||this})}};this.loadQueue=function(n,m){this.loadScripts(j,n,m)};this.loadScripts=function(m,q,p){var o;function n(r){a.each(e[r],function(s){s.func.call(s.scope)});e[r]=f}d.push({func:q,scope:p||this});o=function(){var r=a.grep(m);m.length=0;a.each(r,function(s){if(l[s]==i){n(s);return}if(l[s]!=k){l[s]=k;g++;b(s,function(){l[s]=i;g--;n(s);o()})}});if(!g){a.each(d,function(s){s.func.call(s.scope)});d.length=0}};o()}};a.ScriptLoader=new a.dom.ScriptLoader()})(tinymce);(function(a){a.dom.RangeUtils=function(c){var b="\uFEFF";this.walk=function(d,s){var i=d.startContainer,l=d.startOffset,t=d.endContainer,m=d.endOffset,j,g,o,h,r,q,e;e=c.select("td.mceSelected,th.mceSelected");if(e.length>0){a.each(e,function(u){s([u])});return}function f(u){var v;v=u[0];if(v.nodeType===3&&v===i&&l>=v.nodeValue.length){u.splice(0,1)}v=u[u.length-1];if(m===0&&u.length>0&&v===t&&v.nodeType===3){u.splice(u.length-1,1)}return u}function p(x,v,u){var y=[];for(;x&&x!=u;x=x[v]){y.push(x)}return y}function n(v,u){do{if(v.parentNode==u){return v}v=v.parentNode}while(v)}function k(x,v,y){var u=y?"nextSibling":"previousSibling";for(h=x,r=h.parentNode;h&&h!=v;h=r){r=h.parentNode;q=p(h==x?h:h[u],u);if(q.length){if(!y){q.reverse()}s(f(q))}}}if(i.nodeType==1&&i.hasChildNodes()){i=i.childNodes[l]}if(t.nodeType==1&&t.hasChildNodes()){t=t.childNodes[Math.min(m-1,t.childNodes.length-1)]}if(i==t){return s(f([i]))}j=c.findCommonAncestor(i,t);for(h=i;h;h=h.parentNode){if(h===t){return k(i,j,true)}if(h===j){break}}for(h=t;h;h=h.parentNode){if(h===i){return k(t,j)}if(h===j){break}}g=n(i,j)||i;o=n(t,j)||t;k(i,g,true);q=p(g==i?g:g.nextSibling,"nextSibling",o==t?o.nextSibling:o);if(q.length){s(f(q))}k(t,o)};this.split=function(e){var h=e.startContainer,d=e.startOffset,i=e.endContainer,g=e.endOffset;function f(j,k){return j.splitText(k)}if(h==i&&h.nodeType==3){if(d>0&&d<h.nodeValue.length){i=f(h,d);h=i.previousSibling;if(g>d){g=g-d;h=i=f(i,g).previousSibling;g=i.nodeValue.length;d=0}else{g=0}}}else{if(h.nodeType==3&&d>0&&d<h.nodeValue.length){h=f(h,d);d=0}if(i.nodeType==3&&g>0&&g<i.nodeValue.length){i=f(i,g).previousSibling;g=i.nodeValue.length}}return{startContainer:h,startOffset:d,endContainer:i,endOffset:g}}};a.dom.RangeUtils.compareRanges=function(c,b){if(c&&b){if(c.item||c.duplicate){if(c.item&&b.item&&c.item(0)===b.item(0)){return true}if(c.isEqual&&b.isEqual&&b.isEqual(c)){return true}}else{return c.startContainer==b.startContainer&&c.startOffset==b.startOffset}}return false}})(tinymce);(function(b){var a=b.dom.Event,c=b.each;b.create("tinymce.ui.KeyboardNavigation",{KeyboardNavigation:function(e,f){var q=this,n=e.root,m=e.items,o=e.enableUpDown,i=e.enableLeftRight||!e.enableUpDown,l=e.excludeFromTabOrder,k,h,p,d,g;f=f||b.DOM;k=function(r){g=r.target.id};h=function(r){f.setAttrib(r.target.id,"tabindex","-1")};d=function(r){var s=f.get(g);f.setAttrib(s,"tabindex","0");s.focus()};q.focus=function(){f.get(g).focus()};q.destroy=function(){c(m,function(s){var t=f.get(s.id);f.unbind(t,"focus",k);f.unbind(t,"blur",h)});var r=f.get(n);f.unbind(r,"focus",d);f.unbind(r,"keydown",p);m=f=n=q.focus=k=h=p=d=null;q.destroy=function(){}};q.moveFocus=function(v,s){var r=-1,u=q.controls,t;if(!g){return}c(m,function(y,x){if(y.id===g){r=x;return false}});r+=v;if(r<0){r=m.length-1}else{if(r>=m.length){r=0}}t=m[r];f.setAttrib(g,"tabindex","-1");f.setAttrib(t.id,"tabindex","0");f.get(t.id).focus();if(e.actOnFocus){e.onAction(t.id)}if(s){a.cancel(s)}};p=function(z){var v=37,u=39,y=38,A=40,r=27,t=14,s=13,x=32;switch(z.keyCode){case v:if(i){q.moveFocus(-1)}break;case u:if(i){q.moveFocus(1)}break;case y:if(o){q.moveFocus(-1)}break;case A:if(o){q.moveFocus(1)}break;case r:if(e.onCancel){e.onCancel();a.cancel(z)}break;case t:case s:case x:if(e.onAction){e.onAction(g);a.cancel(z)}break}};c(m,function(t,r){var s,u;if(!t.id){t.id=f.uniqueId("_mce_item_")}u=f.get(t.id);if(l){f.bind(u,"blur",h);s="-1"}else{s=(r===0?"0":"-1")}u.setAttribute("tabindex",s);f.bind(u,"focus",k)});if(m[0]){g=m[0].id}f.setAttrib(n,"tabindex","-1");var j=f.get(n);f.bind(j,"focus",d);f.bind(j,"keydown",p)}})})(tinymce);(function(c){var b=c.DOM,a=c.is;c.create("tinymce.ui.Control",{Control:function(f,e,d){this.id=f;this.settings=e=e||{};this.rendered=false;this.onRender=new c.util.Dispatcher(this);this.classPrefix="";this.scope=e.scope||this;this.disabled=0;this.active=0;this.editor=d},setAriaProperty:function(f,e){var d=b.get(this.id+"_aria")||b.get(this.id);if(d){b.setAttrib(d,"aria-"+f,!!e)}},focus:function(){b.get(this.id).focus()},setDisabled:function(d){if(d!=this.disabled){this.setAriaProperty("disabled",d);this.setState("Disabled",d);this.setState("Enabled",!d);this.disabled=d}},isDisabled:function(){return this.disabled},setActive:function(d){if(d!=this.active){this.setState("Active",d);this.active=d;this.setAriaProperty("pressed",d)}},isActive:function(){return this.active},setState:function(f,d){var e=b.get(this.id);f=this.classPrefix+f;if(d){b.addClass(e,f)}else{b.removeClass(e,f)}},isRendered:function(){return this.rendered},renderHTML:function(){},renderTo:function(d){b.setHTML(d,this.renderHTML())},postRender:function(){var e=this,d;if(a(e.disabled)){d=e.disabled;e.disabled=-1;e.setDisabled(d)}if(a(e.active)){d=e.active;e.active=-1;e.setActive(d)}},remove:function(){b.remove(this.id);this.destroy()},destroy:function(){c.dom.Event.clear(this.id)}})})(tinymce);tinymce.create("tinymce.ui.Container:tinymce.ui.Control",{Container:function(c,b,a){this.parent(c,b,a);this.controls=[];this.lookup={}},add:function(a){this.lookup[a.id]=a;this.controls.push(a);return a},get:function(a){return this.lookup[a]}});tinymce.create("tinymce.ui.Separator:tinymce.ui.Control",{Separator:function(b,a){this.parent(b,a);this.classPrefix="mceSeparator";this.setDisabled(true)},renderHTML:function(){return tinymce.DOM.createHTML("span",{"class":this.classPrefix,role:"separator","aria-orientation":"vertical",tabindex:"-1"})}});(function(d){var c=d.is,b=d.DOM,e=d.each,a=d.walk;d.create("tinymce.ui.MenuItem:tinymce.ui.Control",{MenuItem:function(g,f){this.parent(g,f);this.classPrefix="mceMenuItem"},setSelected:function(f){this.setState("Selected",f);this.setAriaProperty("checked",!!f);this.selected=f},isSelected:function(){return this.selected},postRender:function(){var f=this;f.parent();if(c(f.selected)){f.setSelected(f.selected)}}})})(tinymce);(function(d){var c=d.is,b=d.DOM,e=d.each,a=d.walk;d.create("tinymce.ui.Menu:tinymce.ui.MenuItem",{Menu:function(h,g){var f=this;f.parent(h,g);f.items={};f.collapsed=false;f.menuCount=0;f.onAddItem=new d.util.Dispatcher(this)},expand:function(g){var f=this;if(g){a(f,function(h){if(h.expand){h.expand()}},"items",f)}f.collapsed=false},collapse:function(g){var f=this;if(g){a(f,function(h){if(h.collapse){h.collapse()}},"items",f)}f.collapsed=true},isCollapsed:function(){return this.collapsed},add:function(f){if(!f.settings){f=new d.ui.MenuItem(f.id||b.uniqueId(),f)}this.onAddItem.dispatch(this,f);return this.items[f.id]=f},addSeparator:function(){return this.add({separator:true})},addMenu:function(f){if(!f.collapse){f=this.createMenu(f)}this.menuCount++;return this.add(f)},hasMenus:function(){return this.menuCount!==0},remove:function(f){delete this.items[f.id]},removeAll:function(){var f=this;a(f,function(g){if(g.removeAll){g.removeAll()}else{g.remove()}g.destroy()},"items",f);f.items={}},createMenu:function(g){var f=new d.ui.Menu(g.id||b.uniqueId(),g);f.onAddItem.add(this.onAddItem.dispatch,this.onAddItem);return f}})})(tinymce);(function(e){var d=e.is,c=e.DOM,f=e.each,a=e.dom.Event,b=e.dom.Element;e.create("tinymce.ui.DropMenu:tinymce.ui.Menu",{DropMenu:function(h,g){g=g||{};g.container=g.container||c.doc.body;g.offset_x=g.offset_x||0;g.offset_y=g.offset_y||0;g.vp_offset_x=g.vp_offset_x||0;g.vp_offset_y=g.vp_offset_y||0;if(d(g.icons)&&!g.icons){g["class"]+=" mceNoIcons"}this.parent(h,g);this.onShowMenu=new e.util.Dispatcher(this);this.onHideMenu=new e.util.Dispatcher(this);this.classPrefix="mceMenu"},createMenu:function(j){var h=this,i=h.settings,g;j.container=j.container||i.container;j.parent=h;j.constrain=j.constrain||i.constrain;j["class"]=j["class"]||i["class"];j.vp_offset_x=j.vp_offset_x||i.vp_offset_x;j.vp_offset_y=j.vp_offset_y||i.vp_offset_y;j.keyboard_focus=i.keyboard_focus;g=new e.ui.DropMenu(j.id||c.uniqueId(),j);g.onAddItem.add(h.onAddItem.dispatch,h.onAddItem);return g},focus:function(){var g=this;if(g.keyboardNav){g.keyboardNav.focus()}},update:function(){var i=this,j=i.settings,g=c.get("menu_"+i.id+"_tbl"),l=c.get("menu_"+i.id+"_co"),h,k;h=j.max_width?Math.min(g.offsetWidth,j.max_width):g.offsetWidth;k=j.max_height?Math.min(g.offsetHeight,j.max_height):g.offsetHeight;if(!c.boxModel){i.element.setStyles({width:h+2,height:k+2})}else{i.element.setStyles({width:h,height:k})}if(j.max_width){c.setStyle(l,"width",h)}if(j.max_height){c.setStyle(l,"height",k);if(g.clientHeight<j.max_height){c.setStyle(l,"overflow","hidden")}}},showMenu:function(p,n,r){var z=this,A=z.settings,o,g=c.getViewPort(),u,l,v,q,i=2,k,j,m=z.classPrefix;z.collapse(1);if(z.isMenuVisible){return}if(!z.rendered){o=c.add(z.settings.container,z.renderNode());f(z.items,function(h){h.postRender()});z.element=new b("menu_"+z.id,{blocker:1,container:A.container})}else{o=c.get("menu_"+z.id)}if(!e.isOpera){c.setStyles(o,{left:-65535,top:-65535})}c.show(o);z.update();p+=A.offset_x||0;n+=A.offset_y||0;g.w-=4;g.h-=4;if(A.constrain){u=o.clientWidth-i;l=o.clientHeight-i;v=g.x+g.w;q=g.y+g.h;if((p+A.vp_offset_x+u)>v){p=r?r-u:Math.max(0,(v-A.vp_offset_x)-u)}if((n+A.vp_offset_y+l)>q){n=Math.max(0,(q-A.vp_offset_y)-l)}}c.setStyles(o,{left:p,top:n});z.element.update();z.isMenuVisible=1;z.mouseClickFunc=a.add(o,"click",function(s){var h;s=s.target;if(s&&(s=c.getParent(s,"tr"))&&!c.hasClass(s,m+"ItemSub")){h=z.items[s.id];if(h.isDisabled()){return}k=z;while(k){if(k.hideMenu){k.hideMenu()}k=k.settings.parent}if(h.settings.onclick){h.settings.onclick(s)}return false}});if(z.hasMenus()){z.mouseOverFunc=a.add(o,"mouseover",function(x){var h,t,s;x=x.target;if(x&&(x=c.getParent(x,"tr"))){h=z.items[x.id];if(z.lastMenu){z.lastMenu.collapse(1)}if(h.isDisabled()){return}if(x&&c.hasClass(x,m+"ItemSub")){t=c.getRect(x);h.showMenu((t.x+t.w-i),t.y-i,t.x);z.lastMenu=h;c.addClass(c.get(h.id).firstChild,m+"ItemActive")}}})}a.add(o,"keydown",z._keyHandler,z);z.onShowMenu.dispatch(z);if(A.keyboard_focus){z._setupKeyboardNav()}},hideMenu:function(j){var g=this,i=c.get("menu_"+g.id),h;if(!g.isMenuVisible){return}if(g.keyboardNav){g.keyboardNav.destroy()}a.remove(i,"mouseover",g.mouseOverFunc);a.remove(i,"click",g.mouseClickFunc);a.remove(i,"keydown",g._keyHandler);c.hide(i);g.isMenuVisible=0;if(!j){g.collapse(1)}if(g.element){g.element.hide()}if(h=c.get(g.id)){c.removeClass(h.firstChild,g.classPrefix+"ItemActive")}g.onHideMenu.dispatch(g)},add:function(i){var g=this,h;i=g.parent(i);if(g.isRendered&&(h=c.get("menu_"+g.id))){g._add(c.select("tbody",h)[0],i)}return i},collapse:function(g){this.parent(g);this.hideMenu(1)},remove:function(g){c.remove(g.id);this.destroy();return this.parent(g)},destroy:function(){var g=this,h=c.get("menu_"+g.id);if(g.keyboardNav){g.keyboardNav.destroy()}a.remove(h,"mouseover",g.mouseOverFunc);a.remove(c.select("a",h),"focus",g.mouseOverFunc);a.remove(h,"click",g.mouseClickFunc);a.remove(h,"keydown",g._keyHandler);if(g.element){g.element.remove()}c.remove(h)},renderNode:function(){var i=this,j=i.settings,l,h,k,g;g=c.create("div",{role:"listbox",id:"menu_"+i.id,"class":j["class"],style:"position:absolute;left:0;top:0;z-index:200000;outline:0"});if(i.settings.parent){c.setAttrib(g,"aria-parent","menu_"+i.settings.parent.id)}k=c.add(g,"div",{role:"presentation",id:"menu_"+i.id+"_co","class":i.classPrefix+(j["class"]?" "+j["class"]:"")});i.element=new b("menu_"+i.id,{blocker:1,container:j.container});if(j.menu_line){c.add(k,"span",{"class":i.classPrefix+"Line"})}l=c.add(k,"table",{role:"presentation",id:"menu_"+i.id+"_tbl",border:0,cellPadding:0,cellSpacing:0});h=c.add(l,"tbody");f(i.items,function(m){i._add(h,m)});i.rendered=true;return g},_setupKeyboardNav:function(){var i,h,g=this;i=c.get("menu_"+g.id);h=c.select("a[role=option]","menu_"+g.id);h.splice(0,0,i);g.keyboardNav=new e.ui.KeyboardNavigation({root:"menu_"+g.id,items:h,onCancel:function(){g.hideMenu()},enableUpDown:true});i.focus()},_keyHandler:function(g){var h=this,i;switch(g.keyCode){case 37:if(h.settings.parent){h.hideMenu();h.settings.parent.focus();a.cancel(g)}break;case 39:if(h.mouseOverFunc){h.mouseOverFunc(g)}break}},_add:function(j,h){var i,q=h.settings,p,l,k,m=this.classPrefix,g;if(q.separator){l=c.add(j,"tr",{id:h.id,"class":m+"ItemSeparator"});c.add(l,"td",{"class":m+"ItemSeparator"});if(i=l.previousSibling){c.addClass(i,"mceLast")}return}i=l=c.add(j,"tr",{id:h.id,"class":m+"Item "+m+"ItemEnabled"});i=k=c.add(i,q.titleItem?"th":"td");i=p=c.add(i,"a",{id:h.id+"_aria",role:q.titleItem?"presentation":"option",href:"javascript:;",onclick:"return false;",onmousedown:"return false;"});if(q.parent){c.setAttrib(p,"aria-haspopup","true");c.setAttrib(p,"aria-owns","menu_"+h.id)}c.addClass(k,q["class"]);g=c.add(i,"span",{"class":"mceIcon"+(q.icon?" mce_"+q.icon:"")});if(q.icon_src){c.add(g,"img",{src:q.icon_src})}i=c.add(i,q.element||"span",{"class":"mceText",title:h.settings.title},h.settings.title);if(h.settings.style){if(typeof h.settings.style=="function"){h.settings.style=h.settings.style()}c.setAttrib(i,"style",h.settings.style)}if(j.childNodes.length==1){c.addClass(l,"mceFirst")}if((i=l.previousSibling)&&c.hasClass(i,m+"ItemSeparator")){c.addClass(l,"mceFirst")}if(h.collapse){c.addClass(l,m+"ItemSub")}if(i=l.previousSibling){c.removeClass(i,"mceLast")}c.addClass(l,"mceLast")}})})(tinymce);(function(b){var a=b.DOM;b.create("tinymce.ui.Button:tinymce.ui.Control",{Button:function(e,d,c){this.parent(e,d,c);this.classPrefix="mceButton"},renderHTML:function(){var f=this.classPrefix,e=this.settings,d,c;c=a.encode(e.label||"");d='<a role="button" id="'+this.id+'" href="javascript:;" class="'+f+" "+f+"Enabled "+e["class"]+(c?" "+f+"Labeled":"")+'" onmousedown="return false;" onclick="return false;" aria-labelledby="'+this.id+'_voice" title="'+a.encode(e.title)+'">';if(e.image&&!(this.editor&&this.editor.forcedHighContrastMode)){d+='<span class="mceIcon '+e["class"]+'"><img class="mceIcon" src="'+e.image+'" alt="'+a.encode(e.title)+'" /></span>'+(c?'<span class="'+f+'Label">'+c+"</span>":"")}else{d+='<span class="mceIcon '+e["class"]+'"></span>'+(c?'<span class="'+f+'Label">'+c+"</span>":"")}d+='<span class="mceVoiceLabel mceIconOnly" style="display: none;" id="'+this.id+'_voice">'+e.title+"</span>";d+="</a>";return d},postRender:function(){var d=this,e=d.settings,c;if(b.isIE&&d.editor){b.dom.Event.add(d.id,"mousedown",function(f){var g=d.editor.selection.getNode().nodeName;c=g==="IMG"?d.editor.selection.getBookmark():null})}b.dom.Event.add(d.id,"click",function(f){if(!d.isDisabled()){if(b.isIE&&d.editor&&c!==null){d.editor.selection.moveToBookmark(c)}return e.onclick.call(e.scope,f)}});b.dom.Event.add(d.id,"keyup",function(f){if(!d.isDisabled()&&f.keyCode==b.VK.SPACEBAR){return e.onclick.call(e.scope,f)}})}})})(tinymce);(function(e){var d=e.DOM,b=e.dom.Event,f=e.each,a=e.util.Dispatcher,c;e.create("tinymce.ui.ListBox:tinymce.ui.Control",{ListBox:function(j,i,g){var h=this;h.parent(j,i,g);h.items=[];h.onChange=new a(h);h.onPostRender=new a(h);h.onAdd=new a(h);h.onRenderMenu=new e.util.Dispatcher(this);h.classPrefix="mceListBox";h.marked={}},select:function(h){var g=this,j,i;g.marked={};if(h==c){return g.selectByIndex(-1)}if(h&&typeof(h)=="function"){i=h}else{i=function(k){return k==h}}if(h!=g.selectedValue){f(g.items,function(l,k){if(i(l.value)){j=1;g.selectByIndex(k);return false}});if(!j){g.selectByIndex(-1)}}},selectByIndex:function(g){var i=this,j,k,h;i.marked={};if(g!=i.selectedIndex){j=d.get(i.id+"_text");h=d.get(i.id+"_voiceDesc");k=i.items[g];if(k){i.selectedValue=k.value;i.selectedIndex=g;d.setHTML(j,d.encode(k.title));d.setHTML(h,i.settings.title+" - "+k.title);d.removeClass(j,"mceTitle");d.setAttrib(i.id,"aria-valuenow",k.title)}else{d.setHTML(j,d.encode(i.settings.title));d.setHTML(h,d.encode(i.settings.title));d.addClass(j,"mceTitle");i.selectedValue=i.selectedIndex=null;d.setAttrib(i.id,"aria-valuenow",i.settings.title)}j=0}},mark:function(g){this.marked[g]=true},add:function(j,g,i){var h=this;i=i||{};i=e.extend(i,{title:j,value:g});h.items.push(i);h.onAdd.dispatch(h,i)},getLength:function(){return this.items.length},renderHTML:function(){var j="",g=this,i=g.settings,k=g.classPrefix;j='<span role="listbox" aria-haspopup="true" aria-labelledby="'+g.id+'_voiceDesc" aria-describedby="'+g.id+'_voiceDesc"><table role="presentation" tabindex="0" id="'+g.id+'" cellpadding="0" cellspacing="0" class="'+k+" "+k+"Enabled"+(i["class"]?(" "+i["class"]):"")+'"><tbody><tr>';j+="<td>"+d.createHTML("span",{id:g.id+"_voiceDesc","class":"voiceLabel",style:"display:none;"},g.settings.title);j+=d.createHTML("a",{id:g.id+"_text",tabindex:-1,href:"javascript:;","class":"mceText",onclick:"return false;",onmousedown:"return false;"},d.encode(g.settings.title))+"</td>";j+="<td>"+d.createHTML("a",{id:g.id+"_open",tabindex:-1,href:"javascript:;","class":"mceOpen",onclick:"return false;",onmousedown:"return false;"},'<span><span style="display:none;" class="mceIconOnly" aria-hidden="true">\u25BC</span></span>')+"</td>";j+="</tr></tbody></table></span>";return j},showMenu:function(){var h=this,j,i=d.get(this.id),g;if(h.isDisabled()||h.items.length===0){return}if(h.menu&&h.menu.isMenuVisible){return h.hideMenu()}if(!h.isMenuRendered){h.renderMenu();h.isMenuRendered=true}j=d.getPos(i);g=h.menu;g.settings.offset_x=j.x;g.settings.offset_y=j.y;g.settings.keyboard_focus=!e.isOpera;f(h.items,function(k){if(g.items[k.id]){g.items[k.id].setSelected(0)}});f(h.items,function(k){if(g.items[k.id]&&h.marked[k.value]){g.items[k.id].setSelected(1)}if(k.value===h.selectedValue){g.items[k.id].setSelected(1)}});g.showMenu(0,i.clientHeight);b.add(d.doc,"mousedown",h.hideMenu,h);d.addClass(h.id,h.classPrefix+"Selected")},hideMenu:function(h){var g=this;if(g.menu&&g.menu.isMenuVisible){d.removeClass(g.id,g.classPrefix+"Selected");if(h&&h.type=="mousedown"&&(h.target.id==g.id+"_text"||h.target.id==g.id+"_open")){return}if(!h||!d.getParent(h.target,".mceMenu")){d.removeClass(g.id,g.classPrefix+"Selected");b.remove(d.doc,"mousedown",g.hideMenu,g);g.menu.hideMenu()}}},renderMenu:function(){var h=this,g;g=h.settings.control_manager.createDropMenu(h.id+"_menu",{menu_line:1,"class":h.classPrefix+"Menu mceNoIcons",max_width:250,max_height:150});g.onHideMenu.add(function(){h.hideMenu();h.focus()});g.add({title:h.settings.title,"class":"mceMenuItemTitle",onclick:function(){if(h.settings.onselect("")!==false){h.select("")}}});f(h.items,function(i){if(i.value===c){g.add({title:i.title,role:"option","class":"mceMenuItemTitle",onclick:function(){if(h.settings.onselect("")!==false){h.select("")}}})}else{i.id=d.uniqueId();i.role="option";i.onclick=function(){if(h.settings.onselect(i.value)!==false){h.select(i.value)}};g.add(i)}});h.onRenderMenu.dispatch(h,g);h.menu=g},postRender:function(){var g=this,h=g.classPrefix;b.add(g.id,"click",g.showMenu,g);b.add(g.id,"keydown",function(i){if(i.keyCode==32){g.showMenu(i);b.cancel(i)}});b.add(g.id,"focus",function(){if(!g._focused){g.keyDownHandler=b.add(g.id,"keydown",function(i){if(i.keyCode==40){g.showMenu();b.cancel(i)}});g.keyPressHandler=b.add(g.id,"keypress",function(j){var i;if(j.keyCode==13){i=g.selectedValue;g.selectedValue=null;b.cancel(j);g.settings.onselect(i)}})}g._focused=1});b.add(g.id,"blur",function(){b.remove(g.id,"keydown",g.keyDownHandler);b.remove(g.id,"keypress",g.keyPressHandler);g._focused=0});if(e.isIE6||!d.boxModel){b.add(g.id,"mouseover",function(){if(!d.hasClass(g.id,h+"Disabled")){d.addClass(g.id,h+"Hover")}});b.add(g.id,"mouseout",function(){if(!d.hasClass(g.id,h+"Disabled")){d.removeClass(g.id,h+"Hover")}})}g.onPostRender.dispatch(g,d.get(g.id))},destroy:function(){this.parent();b.clear(this.id+"_text");b.clear(this.id+"_open")}})})(tinymce);(function(e){var d=e.DOM,b=e.dom.Event,f=e.each,a=e.util.Dispatcher,c;e.create("tinymce.ui.NativeListBox:tinymce.ui.ListBox",{NativeListBox:function(h,g){this.parent(h,g);this.classPrefix="mceNativeListBox"},setDisabled:function(g){d.get(this.id).disabled=g;this.setAriaProperty("disabled",g)},isDisabled:function(){return d.get(this.id).disabled},select:function(h){var g=this,j,i;if(h==c){return g.selectByIndex(-1)}if(h&&typeof(h)=="function"){i=h}else{i=function(k){return k==h}}if(h!=g.selectedValue){f(g.items,function(l,k){if(i(l.value)){j=1;g.selectByIndex(k);return false}});if(!j){g.selectByIndex(-1)}}},selectByIndex:function(g){d.get(this.id).selectedIndex=g+1;this.selectedValue=this.items[g]?this.items[g].value:null},add:function(k,h,g){var j,i=this;g=g||{};g.value=h;if(i.isRendered()){d.add(d.get(this.id),"option",g,k)}j={title:k,value:h,attribs:g};i.items.push(j);i.onAdd.dispatch(i,j)},getLength:function(){return this.items.length},renderHTML:function(){var i,g=this;i=d.createHTML("option",{value:""},"-- "+g.settings.title+" --");f(g.items,function(h){i+=d.createHTML("option",{value:h.value},h.title)});i=d.createHTML("select",{id:g.id,"class":"mceNativeListBox","aria-labelledby":g.id+"_aria"},i);i+=d.createHTML("span",{id:g.id+"_aria",style:"display: none"},g.settings.title);return i},postRender:function(){var h=this,i,j=true;h.rendered=true;function g(l){var k=h.items[l.target.selectedIndex-1];if(k&&(k=k.value)){h.onChange.dispatch(h,k);if(h.settings.onselect){h.settings.onselect(k)}}}b.add(h.id,"change",g);b.add(h.id,"keydown",function(l){var k;b.remove(h.id,"change",i);j=false;k=b.add(h.id,"blur",function(){if(j){return}j=true;b.add(h.id,"change",g);b.remove(h.id,"blur",k)});if(e.isWebKit&&(l.keyCode==37||l.keyCode==39)){return b.prevent(l)}if(l.keyCode==13||l.keyCode==32){g(l);return b.cancel(l)}});h.onPostRender.dispatch(h,d.get(h.id))}})})(tinymce);(function(c){var b=c.DOM,a=c.dom.Event,d=c.each;c.create("tinymce.ui.MenuButton:tinymce.ui.Button",{MenuButton:function(g,f,e){this.parent(g,f,e);this.onRenderMenu=new c.util.Dispatcher(this);f.menu_container=f.menu_container||b.doc.body},showMenu:function(){var g=this,j,i,h=b.get(g.id),f;if(g.isDisabled()){return}if(!g.isMenuRendered){g.renderMenu();g.isMenuRendered=true}if(g.isMenuVisible){return g.hideMenu()}j=b.getPos(g.settings.menu_container);i=b.getPos(h);f=g.menu;f.settings.offset_x=i.x;f.settings.offset_y=i.y;f.settings.vp_offset_x=i.x;f.settings.vp_offset_y=i.y;f.settings.keyboard_focus=g._focused;f.showMenu(0,h.firstChild.clientHeight);a.add(b.doc,"mousedown",g.hideMenu,g);g.setState("Selected",1);g.isMenuVisible=1},renderMenu:function(){var f=this,e;e=f.settings.control_manager.createDropMenu(f.id+"_menu",{menu_line:1,"class":this.classPrefix+"Menu",icons:f.settings.icons});e.onHideMenu.add(function(){f.hideMenu();f.focus()});f.onRenderMenu.dispatch(f,e);f.menu=e},hideMenu:function(g){var f=this;if(g&&g.type=="mousedown"&&b.getParent(g.target,function(h){return h.id===f.id||h.id===f.id+"_open"})){return}if(!g||!b.getParent(g.target,".mceMenu")){f.setState("Selected",0);a.remove(b.doc,"mousedown",f.hideMenu,f);if(f.menu){f.menu.hideMenu()}}f.isMenuVisible=0},postRender:function(){var e=this,f=e.settings;a.add(e.id,"click",function(){if(!e.isDisabled()){if(f.onclick){f.onclick(e.value)}e.showMenu()}})}})})(tinymce);(function(c){var b=c.DOM,a=c.dom.Event,d=c.each;c.create("tinymce.ui.SplitButton:tinymce.ui.MenuButton",{SplitButton:function(g,f,e){this.parent(g,f,e);this.classPrefix="mceSplitButton"},renderHTML:function(){var i,f=this,g=f.settings,e;i="<tbody><tr>";if(g.image){e=b.createHTML("img ",{src:g.image,role:"presentation","class":"mceAction "+g["class"]})}else{e=b.createHTML("span",{"class":"mceAction "+g["class"]},"")}e+=b.createHTML("span",{"class":"mceVoiceLabel mceIconOnly",id:f.id+"_voice",style:"display:none;"},g.title);i+="<td >"+b.createHTML("a",{role:"button",id:f.id+"_action",tabindex:"-1",href:"javascript:;","class":"mceAction "+g["class"],onclick:"return false;",onmousedown:"return false;",title:g.title},e)+"</td>";e=b.createHTML("span",{"class":"mceOpen "+g["class"]},'<span style="display:none;" class="mceIconOnly" aria-hidden="true">\u25BC</span>');i+="<td >"+b.createHTML("a",{role:"button",id:f.id+"_open",tabindex:"-1",href:"javascript:;","class":"mceOpen "+g["class"],onclick:"return false;",onmousedown:"return false;",title:g.title},e)+"</td>";i+="</tr></tbody>";i=b.createHTML("table",{role:"presentation","class":"mceSplitButton mceSplitButtonEnabled "+g["class"],cellpadding:"0",cellspacing:"0",title:g.title},i);return b.createHTML("div",{id:f.id,role:"button",tabindex:"0","aria-labelledby":f.id+"_voice","aria-haspopup":"true"},i)},postRender:function(){var e=this,g=e.settings,f;if(g.onclick){f=function(h){if(!e.isDisabled()){g.onclick(e.value);a.cancel(h)}};a.add(e.id+"_action","click",f);a.add(e.id,["click","keydown"],function(h){var k=32,m=14,i=13,j=38,l=40;if((h.keyCode===32||h.keyCode===13||h.keyCode===14)&&!h.altKey&&!h.ctrlKey&&!h.metaKey){f();a.cancel(h)}else{if(h.type==="click"||h.keyCode===l){e.showMenu();a.cancel(h)}}})}a.add(e.id+"_open","click",function(h){e.showMenu();a.cancel(h)});a.add([e.id,e.id+"_open"],"focus",function(){e._focused=1});a.add([e.id,e.id+"_open"],"blur",function(){e._focused=0});if(c.isIE6||!b.boxModel){a.add(e.id,"mouseover",function(){if(!b.hasClass(e.id,"mceSplitButtonDisabled")){b.addClass(e.id,"mceSplitButtonHover")}});a.add(e.id,"mouseout",function(){if(!b.hasClass(e.id,"mceSplitButtonDisabled")){b.removeClass(e.id,"mceSplitButtonHover")}})}},destroy:function(){this.parent();a.clear(this.id+"_action");a.clear(this.id+"_open");a.clear(this.id)}})})(tinymce);(function(d){var c=d.DOM,a=d.dom.Event,b=d.is,e=d.each;d.create("tinymce.ui.ColorSplitButton:tinymce.ui.SplitButton",{ColorSplitButton:function(i,h,f){var g=this;g.parent(i,h,f);g.settings=h=d.extend({colors:"000000,993300,333300,003300,003366,000080,333399,333333,800000,FF6600,808000,008000,008080,0000FF,666699,808080,FF0000,FF9900,99CC00,339966,33CCCC,3366FF,800080,999999,FF00FF,FFCC00,FFFF00,00FF00,00FFFF,00CCFF,993366,C0C0C0,FF99CC,FFCC99,FFFF99,CCFFCC,CCFFFF,99CCFF,CC99FF,FFFFFF",grid_width:8,default_color:"#888888"},g.settings);g.onShowMenu=new d.util.Dispatcher(g);g.onHideMenu=new d.util.Dispatcher(g);g.value=h.default_color},showMenu:function(){var f=this,g,j,i,h;if(f.isDisabled()){return}if(!f.isMenuRendered){f.renderMenu();f.isMenuRendered=true}if(f.isMenuVisible){return f.hideMenu()}i=c.get(f.id);c.show(f.id+"_menu");c.addClass(i,"mceSplitButtonSelected");h=c.getPos(i);c.setStyles(f.id+"_menu",{left:h.x,top:h.y+i.firstChild.clientHeight,zIndex:200000});i=0;a.add(c.doc,"mousedown",f.hideMenu,f);f.onShowMenu.dispatch(f);if(f._focused){f._keyHandler=a.add(f.id+"_menu","keydown",function(k){if(k.keyCode==27){f.hideMenu()}});c.select("a",f.id+"_menu")[0].focus()}f.keyboardNav=new d.ui.KeyboardNavigation({root:f.id+"_menu",items:c.select("a",f.id+"_menu"),onCancel:function(){f.hideMenu();f.focus()}});f.keyboardNav.focus();f.isMenuVisible=1},hideMenu:function(g){var f=this;if(f.isMenuVisible){if(g&&g.type=="mousedown"&&c.getParent(g.target,function(h){return h.id===f.id+"_open"})){return}if(!g||!c.getParent(g.target,".mceSplitButtonMenu")){c.removeClass(f.id,"mceSplitButtonSelected");a.remove(c.doc,"mousedown",f.hideMenu,f);a.remove(f.id+"_menu","keydown",f._keyHandler);c.hide(f.id+"_menu")}f.isMenuVisible=0;f.onHideMenu.dispatch();f.keyboardNav.destroy()}},renderMenu:function(){var p=this,h,k=0,q=p.settings,g,j,l,o,f;o=c.add(q.menu_container,"div",{role:"listbox",id:p.id+"_menu","class":q.menu_class+" "+q["class"],style:"position:absolute;left:0;top:-1000px;"});h=c.add(o,"div",{"class":q["class"]+" mceSplitButtonMenu"});c.add(h,"span",{"class":"mceMenuLine"});g=c.add(h,"table",{role:"presentation","class":"mceColorSplitMenu"});j=c.add(g,"tbody");k=0;e(b(q.colors,"array")?q.colors:q.colors.split(","),function(m){m=m.replace(/^#/,"");if(!k--){l=c.add(j,"tr");k=q.grid_width-1}g=c.add(l,"td");var i={href:"javascript:;",style:{backgroundColor:"#"+m},title:p.editor.getLang("colors."+m,m),"data-mce-color":"#"+m};if(!d.isIE){i.role="option"}g=c.add(g,"a",i);if(p.editor.forcedHighContrastMode){g=c.add(g,"canvas",{width:16,height:16,"aria-hidden":"true"});if(g.getContext&&(f=g.getContext("2d"))){f.fillStyle="#"+m;f.fillRect(0,0,16,16)}else{c.remove(g)}}});if(q.more_colors_func){g=c.add(j,"tr");g=c.add(g,"td",{colspan:q.grid_width,"class":"mceMoreColors"});g=c.add(g,"a",{role:"option",id:p.id+"_more",href:"javascript:;",onclick:"return false;","class":"mceMoreColors"},q.more_colors_title);a.add(g,"click",function(i){q.more_colors_func.call(q.more_colors_scope||this);return a.cancel(i)})}c.addClass(h,"mceColorSplitMenu");a.add(p.id+"_menu","mousedown",function(i){return a.cancel(i)});a.add(p.id+"_menu","click",function(i){var m;i=c.getParent(i.target,"a",j);if(i&&i.nodeName.toLowerCase()=="a"&&(m=i.getAttribute("data-mce-color"))){p.setColor(m)}return false});return o},setColor:function(f){this.displayColor(f);this.hideMenu();this.settings.onselect(f)},displayColor:function(g){var f=this;c.setStyle(f.id+"_preview","backgroundColor",g);f.value=g},postRender:function(){var f=this,g=f.id;f.parent();c.add(g+"_action","div",{id:g+"_preview","class":"mceColorPreview"});c.setStyle(f.id+"_preview","backgroundColor",f.value)},destroy:function(){var f=this;f.parent();a.clear(f.id+"_menu");a.clear(f.id+"_more");c.remove(f.id+"_menu");if(f.keyboardNav){f.keyboardNav.destroy()}}})})(tinymce);(function(b){var d=b.DOM,c=b.each,a=b.dom.Event;b.create("tinymce.ui.ToolbarGroup:tinymce.ui.Container",{renderHTML:function(){var f=this,i=[],e=f.controls,j=b.each,g=f.settings;i.push('<div id="'+f.id+'" role="group" aria-labelledby="'+f.id+'_voice">');i.push("<span role='application'>");i.push('<span id="'+f.id+'_voice" class="mceVoiceLabel" style="display:none;">'+d.encode(g.name)+"</span>");j(e,function(h){i.push(h.renderHTML())});i.push("</span>");i.push("</div>");return i.join("")},focus:function(){var e=this;d.get(e.id).focus()},postRender:function(){var f=this,e=[];c(f.controls,function(g){c(g.controls,function(h){if(h.id){e.push(h)}})});f.keyNav=new b.ui.KeyboardNavigation({root:f.id,items:e,onCancel:function(){if(b.isWebKit){d.get(f.editor.id+"_ifr").focus()}f.editor.focus()},excludeFromTabOrder:!f.settings.tab_focus_toolbar})},destroy:function(){var e=this;e.parent();e.keyNav.destroy();a.clear(e.id)}})})(tinymce);(function(a){var c=a.DOM,b=a.each;a.create("tinymce.ui.Toolbar:tinymce.ui.Container",{renderHTML:function(){var m=this,f="",j,k,n=m.settings,e,d,g,l;l=m.controls;for(e=0;e<l.length;e++){k=l[e];d=l[e-1];g=l[e+1];if(e===0){j="mceToolbarStart";if(k.Button){j+=" mceToolbarStartButton"}else{if(k.SplitButton){j+=" mceToolbarStartSplitButton"}else{if(k.ListBox){j+=" mceToolbarStartListBox"}}}f+=c.createHTML("td",{"class":j},c.createHTML("span",null,"<!-- IE -->"))}if(d&&k.ListBox){if(d.Button||d.SplitButton){f+=c.createHTML("td",{"class":"mceToolbarEnd"},c.createHTML("span",null,"<!-- IE -->"))}}if(c.stdMode){f+='<td style="position: relative">'+k.renderHTML()+"</td>"}else{f+="<td>"+k.renderHTML()+"</td>"}if(g&&k.ListBox){if(g.Button||g.SplitButton){f+=c.createHTML("td",{"class":"mceToolbarStart"},c.createHTML("span",null,"<!-- IE -->"))}}}j="mceToolbarEnd";if(k.Button){j+=" mceToolbarEndButton"}else{if(k.SplitButton){j+=" mceToolbarEndSplitButton"}else{if(k.ListBox){j+=" mceToolbarEndListBox"}}}f+=c.createHTML("td",{"class":j},c.createHTML("span",null,"<!-- IE -->"));return c.createHTML("table",{id:m.id,"class":"mceToolbar"+(n["class"]?" "+n["class"]:""),cellpadding:"0",cellspacing:"0",align:m.settings.align||"",role:"presentation",tabindex:"-1"},"<tbody><tr>"+f+"</tr></tbody>")}})})(tinymce);(function(b){var a=b.util.Dispatcher,c=b.each;b.create("tinymce.AddOnManager",{AddOnManager:function(){var d=this;d.items=[];d.urls={};d.lookup={};d.onAdd=new a(d)},get:function(d){if(this.lookup[d]){return this.lookup[d].instance}else{return undefined}},dependencies:function(e){var d;if(this.lookup[e]){d=this.lookup[e].dependencies}return d||[]},requireLangPack:function(e){var d=b.settings;if(d&&d.language&&d.language_load!==false){b.ScriptLoader.add(this.urls[e]+"/langs/"+d.language+".js")}},add:function(f,e,d){this.items.push(e);this.lookup[f]={instance:e,dependencies:d};this.onAdd.dispatch(this,f,e);return e},createUrl:function(d,e){if(typeof e==="object"){return e}else{return{prefix:d.prefix,resource:e,suffix:d.suffix}}},addComponents:function(f,d){var e=this.urls[f];b.each(d,function(g){b.ScriptLoader.add(e+"/"+g)})},load:function(j,f,d,h){var g=this,e=f;function i(){var k=g.dependencies(j);b.each(k,function(m){var l=g.createUrl(f,m);g.load(l.resource,l,undefined,undefined)});if(d){if(h){d.call(h)}else{d.call(b.ScriptLoader)}}}if(g.urls[j]){return}if(typeof f==="object"){e=f.prefix+f.resource+f.suffix}if(e.indexOf("/")!==0&&e.indexOf("://")==-1){e=b.baseURL+"/"+e}g.urls[j]=e.substring(0,e.lastIndexOf("/"));if(g.lookup[j]){i()}else{b.ScriptLoader.add(e,i,h)}}});b.PluginManager=new b.AddOnManager();b.ThemeManager=new b.AddOnManager()}(tinymce));(function(j){var g=j.each,d=j.extend,k=j.DOM,i=j.dom.Event,f=j.ThemeManager,b=j.PluginManager,e=j.explode,h=j.util.Dispatcher,a,c=0;j.documentBaseURL=window.location.href.replace(/[\?#].*$/,"").replace(/[\/\\][^\/]+$/,"");if(!/[\/\\]$/.test(j.documentBaseURL)){j.documentBaseURL+="/"}j.baseURL=new j.util.URI(j.documentBaseURL).toAbsolute(j.baseURL);j.baseURI=new j.util.URI(j.baseURL);j.onBeforeUnload=new h(j);i.add(window,"beforeunload",function(l){j.onBeforeUnload.dispatch(j,l)});j.onAddEditor=new h(j);j.onRemoveEditor=new h(j);j.EditorManager=d(j,{editors:[],i18n:{},activeEditor:null,init:function(x){var v=this,o,n=j.ScriptLoader,u,l=[],r;function q(t){var s=t.id;if(!s){s=t.name;if(s&&!k.get(s)){s=t.name}else{s=k.uniqueId()}t.setAttribute("id",s)}return s}function m(z,A,t){var y=z[A];if(!y){return}if(j.is(y,"string")){t=y.replace(/\.\w+$/,"");t=t?j.resolve(t):0;y=j.resolve(y)}return y.apply(t||this,Array.prototype.slice.call(arguments,2))}function p(t,s){return s.constructor===RegExp?s.test(t.className):k.hasClass(t,s)}v.settings=x;i.bind(window,"ready",function(){var s,t;m(x,"onpageload");switch(x.mode){case"exact":s=x.elements||"";if(s.length>0){g(e(s),function(y){if(k.get(y)){r=new j.Editor(y,x);l.push(r);r.render(1)}else{g(document.forms,function(z){g(z.elements,function(A){if(A.name===y){y="mce_editor_"+c++;k.setAttrib(A,"id",y);r=new j.Editor(y,x);l.push(r);r.render(1)}})})}})}break;case"textareas":case"specific_textareas":g(k.select("textarea"),function(y){if(x.editor_deselector&&p(y,x.editor_deselector)){return}if(!x.editor_selector||p(y,x.editor_selector)){r=new j.Editor(q(y),x);l.push(r);r.render(1)}});break;default:if(x.types){g(x.types,function(y){g(k.select(y.selector),function(A){var z=new j.Editor(q(A),j.extend({},x,y));l.push(z);z.render(1)})})}else{if(x.selector){g(k.select(x.selector),function(z){var y=new j.Editor(q(z),x);l.push(y);y.render(1)})}}}if(x.oninit){s=t=0;g(l,function(y){t++;if(!y.initialized){y.onInit.add(function(){s++;if(s==t){m(x,"oninit")}})}else{s++}if(s==t){m(x,"oninit")}})}})},get:function(l){if(l===a){return this.editors}return this.editors[l]},getInstanceById:function(l){return this.get(l)},add:function(m){var l=this,n=l.editors;n[m.id]=m;n.push(m);l._setActive(m);l.onAddEditor.dispatch(l,m);return m},remove:function(n){var m=this,l,o=m.editors;if(!o[n.id]){return null}delete o[n.id];for(l=0;l<o.length;l++){if(o[l]==n){o.splice(l,1);break}}if(m.activeEditor==n){m._setActive(o[0])}n.destroy();m.onRemoveEditor.dispatch(m,n);return n},execCommand:function(r,p,o){var q=this,n=q.get(o),l;function m(){n.destroy();l.detachEvent("onunload",m);l=l.tinyMCE=l.tinymce=null}switch(r){case"mceFocus":n.focus();return true;case"mceAddEditor":case"mceAddControl":if(!q.get(o)){new j.Editor(o,q.settings).render()}return true;case"mceAddFrameControl":l=o.window;l.tinyMCE=tinyMCE;l.tinymce=j;j.DOM.doc=l.document;j.DOM.win=l;n=new j.Editor(o.element_id,o);n.render();if(j.isIE){l.attachEvent("onunload",m)}o.page_window=null;return true;case"mceRemoveEditor":case"mceRemoveControl":if(n){n.remove()}return true;case"mceToggleEditor":if(!n){q.execCommand("mceAddControl",0,o);return true}if(n.isHidden()){n.show()}else{n.hide()}return true}if(q.activeEditor){return q.activeEditor.execCommand(r,p,o)}return false},execInstanceCommand:function(p,o,n,m){var l=this.get(p);if(l){return l.execCommand(o,n,m)}return false},triggerSave:function(){g(this.editors,function(l){l.save()})},addI18n:function(n,q){var l,m=this.i18n;if(!j.is(n,"string")){g(n,function(r,p){g(r,function(t,s){g(t,function(v,u){if(s==="common"){m[p+"."+u]=v}else{m[p+"."+s+"."+u]=v}})})})}else{g(q,function(r,p){m[n+"."+p]=r})}},_setActive:function(l){this.selectedInstance=this.activeEditor=l}})})(tinymce);(function(k){var l=k.DOM,j=k.dom.Event,f=k.extend,i=k.each,a=k.isGecko,b=k.isIE,e=k.isWebKit,d=k.is,h=k.ThemeManager,c=k.PluginManager,g=k.explode;k.create("tinymce.Editor",{Editor:function(p,o){var m=this,n=true;m.settings=o=f({id:p,language:"en",theme:"advanced",skin:"default",delta_width:0,delta_height:0,popup_css:"",plugins:"",document_base_url:k.documentBaseURL,add_form_submit_trigger:n,submit_patch:n,add_unload_trigger:n,convert_urls:n,relative_urls:n,remove_script_host:n,table_inline_editing:false,object_resizing:n,accessibility_focus:n,doctype:k.isIE6?'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">':"<!DOCTYPE>",visual:n,font_size_style_values:"xx-small,x-small,small,medium,large,x-large,xx-large",font_size_legacy_values:"xx-small,small,medium,large,x-large,xx-large,300%",apply_source_formatting:n,directionality:"ltr",forced_root_block:"p",hidden_input:n,padd_empty_editor:n,render_ui:n,indentation:"30px",fix_table_elements:n,inline_styles:n,convert_fonts_to_spans:n,indent:"simple",indent_before:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,li,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure,option,optgroup,datalist",indent_after:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,li,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure,option,optgroup,datalist",validate:n,entity_encoding:"named",url_converter:m.convertURL,url_converter_scope:m,ie7_compat:n},o);m.id=m.editorId=p;m.isNotDirty=false;m.plugins={};m.documentBaseURI=new k.util.URI(o.document_base_url||k.documentBaseURL,{base_uri:tinyMCE.baseURI});m.baseURI=k.baseURI;m.contentCSS=[];m.contentStyles=[];m.setupEvents();m.execCommands={};m.queryStateCommands={};m.queryValueCommands={};m.execCallback("setup",m)},render:function(o){var p=this,q=p.settings,r=p.id,m=k.ScriptLoader;if(!j.domLoaded){j.add(window,"ready",function(){p.render()});return}tinyMCE.settings=q;if(!p.getElement()){return}if(k.isIDevice&&!k.isIOS5){return}if(!/TEXTAREA|INPUT/i.test(p.getElement().nodeName)&&q.hidden_input&&l.getParent(r,"form")){l.insertAfter(l.create("input",{type:"hidden",name:r}),r)}if(!q.content_editable){p.orgVisibility=p.getElement().style.visibility;p.getElement().style.visibility="hidden"}if(k.WindowManager){p.windowManager=new k.WindowManager(p)}if(q.encoding=="xml"){p.onGetContent.add(function(s,t){if(t.save){t.content=l.encode(t.content)}})}if(q.add_form_submit_trigger){p.onSubmit.addToTop(function(){if(p.initialized){p.save();p.isNotDirty=1}})}if(q.add_unload_trigger){p._beforeUnload=tinyMCE.onBeforeUnload.add(function(){if(p.initialized&&!p.destroyed&&!p.isHidden()){p.save({format:"raw",no_events:true})}})}k.addUnload(p.destroy,p);if(q.submit_patch){p.onBeforeRenderUI.add(function(){var s=p.getElement().form;if(!s){return}if(s._mceOldSubmit){return}if(!s.submit.nodeType&&!s.submit.length){p.formElement=s;s._mceOldSubmit=s.submit;s.submit=function(){k.triggerSave();p.isNotDirty=1;return p.formElement._mceOldSubmit(p.formElement)}}s=null})}function n(){if(q.language&&q.language_load!==false){m.add(k.baseURL+"/langs/"+q.language+".js")}if(q.theme&&typeof q.theme!="function"&&q.theme.charAt(0)!="-"&&!h.urls[q.theme]){h.load(q.theme,"themes/"+q.theme+"/editor_template"+k.suffix+".js")}i(g(q.plugins),function(t){if(t&&!c.urls[t]){if(t.charAt(0)=="-"){t=t.substr(1,t.length);var s=c.dependencies(t);i(s,function(v){var u={prefix:"plugins/",resource:v,suffix:"/editor_plugin"+k.suffix+".js"};v=c.createUrl(u,v);c.load(v.resource,v)})}else{if(t=="safari"){return}c.load(t,{prefix:"plugins/",resource:t,suffix:"/editor_plugin"+k.suffix+".js"})}}});m.loadQueue(function(){if(!p.removed){p.init()}})}n()},init:function(){var q,G=this,H=G.settings,D,y,z,C=G.getElement(),p,m,E,v,B,F,x,r=[];k.add(G);H.aria_label=H.aria_label||l.getAttrib(C,"aria-label",G.getLang("aria.rich_text_area"));if(H.theme){if(typeof H.theme!="function"){H.theme=H.theme.replace(/-/,"");p=h.get(H.theme);G.theme=new p();if(G.theme.init){G.theme.init(G,h.urls[H.theme]||k.documentBaseURL.replace(/\/$/,""))}}else{G.theme=H.theme}}function A(s){var t=c.get(s),o=c.urls[s]||k.documentBaseURL.replace(/\/$/,""),n;if(t&&k.inArray(r,s)===-1){i(c.dependencies(s),function(u){A(u)});n=new t(G,o);G.plugins[s]=n;if(n.init){n.init(G,o);r.push(s)}}}i(g(H.plugins.replace(/\-/g,"")),A);if(H.popup_css!==false){if(H.popup_css){H.popup_css=G.documentBaseURI.toAbsolute(H.popup_css)}else{H.popup_css=G.baseURI.toAbsolute("themes/"+H.theme+"/skins/"+H.skin+"/dialog.css")}}if(H.popup_css_add){H.popup_css+=","+G.documentBaseURI.toAbsolute(H.popup_css_add)}G.controlManager=new k.ControlManager(G);G.onBeforeRenderUI.dispatch(G,G.controlManager);if(H.render_ui&&G.theme){G.orgDisplay=C.style.display;if(typeof H.theme!="function"){D=H.width||C.style.width||C.offsetWidth;y=H.height||C.style.height||C.offsetHeight;z=H.min_height||100;F=/^[0-9\.]+(|px)$/i;if(F.test(""+D)){D=Math.max(parseInt(D,10)+(p.deltaWidth||0),100)}if(F.test(""+y)){y=Math.max(parseInt(y,10)+(p.deltaHeight||0),z)}p=G.theme.renderUI({targetNode:C,width:D,height:y,deltaWidth:H.delta_width,deltaHeight:H.delta_height});l.setStyles(p.sizeContainer||p.editorContainer,{width:D,height:y});y=(p.iframeHeight||y)+(typeof(y)=="number"?(p.deltaHeight||0):"");if(y<z){y=z}}else{p=H.theme(G,C);if(p.editorContainer.nodeType){p.editorContainer=p.editorContainer.id=p.editorContainer.id||G.id+"_parent"}if(p.iframeContainer.nodeType){p.iframeContainer=p.iframeContainer.id=p.iframeContainer.id||G.id+"_iframecontainer"}y=p.iframeHeight||C.offsetHeight;if(b){G.onInit.add(function(n){n.dom.bind(n.getBody(),"beforedeactivate keydown",function(){n.lastIERng=n.selection.getRng()})})}}G.editorContainer=p.editorContainer}if(H.content_css){i(g(H.content_css),function(n){G.contentCSS.push(G.documentBaseURI.toAbsolute(n))})}if(H.content_editable){C=q=p=null;return G.initContentBody()}if(document.domain&&location.hostname!=document.domain){k.relaxedDomain=document.domain}G.iframeHTML=H.doctype+'<html><head xmlns="http://www.w3.org/1999/xhtml">';if(H.document_base_url!=k.documentBaseURL){G.iframeHTML+='<base href="'+G.documentBaseURI.getURI()+'" />'}if(H.ie7_compat){G.iframeHTML+='<meta http-equiv="X-UA-Compatible" content="IE=7" />'}else{G.iframeHTML+='<meta http-equiv="X-UA-Compatible" content="IE=edge" />'}G.iframeHTML+='<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';for(x=0;x<G.contentCSS.length;x++){G.iframeHTML+='<link type="text/css" rel="stylesheet" href="'+G.contentCSS[x]+'" />'}G.contentCSS=[];v=H.body_id||"tinymce";if(v.indexOf("=")!=-1){v=G.getParam("body_id","","hash");v=v[G.id]||v}B=H.body_class||"";if(B.indexOf("=")!=-1){B=G.getParam("body_class","","hash");B=B[G.id]||""}G.iframeHTML+='</head><body id="'+v+'" class="mceContentBody '+B+'" onload="window.parent.tinyMCE.get(\''+G.id+"').onLoad.dispatch();\"><br></body></html>";if(k.relaxedDomain&&(b||(k.isOpera&&parseFloat(opera.version())<11))){E='javascript:(function(){document.open();document.domain="'+document.domain+'";var ed = window.parent.tinyMCE.get("'+G.id+'");document.write(ed.iframeHTML);document.close();ed.initContentBody();})()'}q=l.add(p.iframeContainer,"iframe",{id:G.id+"_ifr",src:E||'javascript:""',frameBorder:"0",allowTransparency:"true",title:H.aria_label,style:{width:"100%",height:y,display:"block"}});G.contentAreaContainer=p.iframeContainer;if(p.editorContainer){l.get(p.editorContainer).style.display=G.orgDisplay}C.style.visibility=G.orgVisibility;l.get(G.id).style.display="none";l.setAttrib(G.id,"aria-hidden",true);if(!k.relaxedDomain||!E){G.initContentBody()}C=q=p=null},initContentBody:function(){var n=this,p=n.settings,q=l.get(n.id),r=n.getDoc(),o,m,s;if((!b||!k.relaxedDomain)&&!p.content_editable){r.open();r.write(n.iframeHTML);r.close();if(k.relaxedDomain){r.domain=k.relaxedDomain}}if(p.content_editable){l.addClass(q,"mceContentBody");n.contentDocument=r=p.content_document||document;n.contentWindow=p.content_window||window;n.bodyElement=q;p.content_document=p.content_window=null}m=n.getBody();m.disabled=true;if(!p.readonly){m.contentEditable=n.getParam("content_editable_state",true)}m.disabled=false;n.schema=new k.html.Schema(p);n.dom=new k.dom.DOMUtils(r,{keep_values:true,url_converter:n.convertURL,url_converter_scope:n,hex_colors:p.force_hex_style_colors,class_filter:p.class_filter,update_styles:true,root_element:p.content_editable?n.id:null,schema:n.schema});n.parser=new k.html.DomParser(p,n.schema);n.parser.addAttributeFilter("src,href,style",function(t,u){var v=t.length,y,A=n.dom,z,x;while(v--){y=t[v];z=y.attr(u);x="data-mce-"+u;if(!y.attributes.map[x]){if(u==="style"){y.attr(x,A.serializeStyle(A.parseStyle(z),y.name))}else{y.attr(x,n.convertURL(z,u,y.name))}}}});n.parser.addNodeFilter("script",function(t,u){var v=t.length,x;while(v--){x=t[v];x.attr("type","mce-"+(x.attr("type")||"text/javascript"))}});n.parser.addNodeFilter("#cdata",function(t,u){var v=t.length,x;while(v--){x=t[v];x.type=8;x.name="#comment";x.value="[CDATA["+x.value+"]]"}});n.parser.addNodeFilter("p,h1,h2,h3,h4,h5,h6,div",function(u,v){var x=u.length,y,t=n.schema.getNonEmptyElements();while(x--){y=u[x];if(y.isEmpty(t)){y.empty().append(new k.html.Node("br",1)).shortEnded=true}}});n.serializer=new k.dom.Serializer(p,n.dom,n.schema);n.selection=new k.dom.Selection(n.dom,n.getWin(),n.serializer,n);n.formatter=new k.Formatter(n);n.undoManager=new k.UndoManager(n);n.forceBlocks=new k.ForceBlocks(n);n.enterKey=new k.EnterKey(n);n.editorCommands=new k.EditorCommands(n);n.onExecCommand.add(function(t,u){if(!/^(FontName|FontSize)$/.test(u)){n.nodeChanged()}});n.serializer.onPreProcess.add(function(t,u){return n.onPreProcess.dispatch(n,u,t)});n.serializer.onPostProcess.add(function(t,u){return n.onPostProcess.dispatch(n,u,t)});n.onPreInit.dispatch(n);if(!p.browser_spellcheck&&!p.gecko_spellcheck){r.body.spellcheck=false}if(!p.readonly){n.bindNativeEvents()}n.controlManager.onPostRender.dispatch(n,n.controlManager);n.onPostRender.dispatch(n);n.quirks=k.util.Quirks(n);if(p.directionality){m.dir=p.directionality}if(p.nowrap){m.style.whiteSpace="nowrap"}if(p.protect){n.onBeforeSetContent.add(function(t,u){i(p.protect,function(v){u.content=u.content.replace(v,function(x){return"<!--mce:protected "+escape(x)+"-->"})})})}n.onSetContent.add(function(){n.addVisual(n.getBody())});if(p.padd_empty_editor){n.onPostProcess.add(function(t,u){u.content=u.content.replace(/^(<p[^>]*>(&nbsp;|&#160;|\s|\u00a0|)<\/p>[\r\n]*|<br \/>[\r\n]*)$/,"")})}n.load({initial:true,format:"html"});n.startContent=n.getContent({format:"raw"});n.initialized=true;n.onInit.dispatch(n);n.execCallback("setupcontent_callback",n.id,m,r);n.execCallback("init_instance_callback",n);n.focus(true);n.nodeChanged({initial:true});if(n.contentStyles.length>0){s="";i(n.contentStyles,function(t){s+=t+"\r\n"});n.dom.addStyle(s)}i(n.contentCSS,function(t){n.dom.loadCSS(t)});if(p.auto_focus){setTimeout(function(){var t=k.get(p.auto_focus);t.selection.select(t.getBody(),1);t.selection.collapse(1);t.getBody().focus();t.getWin().focus()},100)}q=r=m=null},focus:function(p){var o,u=this,t=u.selection,q=u.settings.content_editable,n,r,s=u.getDoc(),m;if(!p){if(u.lastIERng){t.setRng(u.lastIERng)}n=t.getRng();if(n.item){r=n.item(0)}u._refreshContentEditable();if(!q){u.getWin().focus()}if(k.isGecko||q){m=u.getBody();if(m.setActive){m.setActive()}else{m.focus()}if(q){t.normalize()}}if(r&&r.ownerDocument==s){n=s.body.createControlRange();n.addElement(r);n.select()}}if(k.activeEditor!=u){if((o=k.activeEditor)!=null){o.onDeactivate.dispatch(o,u)}u.onActivate.dispatch(u,o)}k._setActive(u)},execCallback:function(q){var m=this,p=m.settings[q],o;if(!p){return}if(m.callbackLookup&&(o=m.callbackLookup[q])){p=o.func;o=o.scope}if(d(p,"string")){o=p.replace(/\.\w+$/,"");o=o?k.resolve(o):0;p=k.resolve(p);m.callbackLookup=m.callbackLookup||{};m.callbackLookup[q]={func:p,scope:o}}return p.apply(o||m,Array.prototype.slice.call(arguments,1))},translate:function(m){var o=this.settings.language||"en",n=k.i18n;if(!m){return""}return n[o+"."+m]||m.replace(/\{\#([^\}]+)\}/g,function(q,p){return n[o+"."+p]||"{#"+p+"}"})},getLang:function(o,m){return k.i18n[(this.settings.language||"en")+"."+o]||(d(m)?m:"{#"+o+"}")},getParam:function(t,q,m){var r=k.trim,p=d(this.settings[t])?this.settings[t]:q,s;if(m==="hash"){s={};if(d(p,"string")){i(p.indexOf("=")>0?p.split(/[;,](?![^=;,]*(?:[;,]|$))/):p.split(","),function(n){n=n.split("=");if(n.length>1){s[r(n[0])]=r(n[1])}else{s[r(n[0])]=r(n)}})}else{s=p}return s}return p},nodeChanged:function(q){var m=this,n=m.selection,p;if(m.initialized){q=q||{};p=n.getStart()||m.getBody();p=b&&p.ownerDocument!=m.getDoc()?m.getBody():p;q.parents=[];m.dom.getParent(p,function(o){if(o.nodeName=="BODY"){return true}q.parents.push(o)});m.onNodeChange.dispatch(m,q?q.controlManager||m.controlManager:m.controlManager,p,n.isCollapsed(),q)}},addButton:function(n,o){var m=this;m.buttons=m.buttons||{};m.buttons[n]=o},addCommand:function(m,o,n){this.execCommands[m]={func:o,scope:n||this}},addQueryStateHandler:function(m,o,n){this.queryStateCommands[m]={func:o,scope:n||this}},addQueryValueHandler:function(m,o,n){this.queryValueCommands[m]={func:o,scope:n||this}},addShortcut:function(o,q,m,p){var n=this,r;if(n.settings.custom_shortcuts===false){return false}n.shortcuts=n.shortcuts||{};if(d(m,"string")){r=m;m=function(){n.execCommand(r,false,null)}}if(d(m,"object")){r=m;m=function(){n.execCommand(r[0],r[1],r[2])}}i(g(o),function(s){var t={func:m,scope:p||this,desc:n.translate(q),alt:false,ctrl:false,shift:false};i(g(s,"+"),function(u){switch(u){case"alt":case"ctrl":case"shift":t[u]=true;break;default:t.charCode=u.charCodeAt(0);t.keyCode=u.toUpperCase().charCodeAt(0)}});n.shortcuts[(t.ctrl?"ctrl":"")+","+(t.alt?"alt":"")+","+(t.shift?"shift":"")+","+t.keyCode]=t});return true},execCommand:function(u,r,x,m){var p=this,q=0,v,n;if(!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint|SelectAll)$/.test(u)&&(!m||!m.skip_focus)){p.focus()}m=f({},m);p.onBeforeExecCommand.dispatch(p,u,r,x,m);if(m.terminate){return false}if(p.execCallback("execcommand_callback",p.id,p.selection.getNode(),u,r,x)){p.onExecCommand.dispatch(p,u,r,x,m);return true}if(v=p.execCommands[u]){n=v.func.call(v.scope,r,x);if(n!==true){p.onExecCommand.dispatch(p,u,r,x,m);return n}}i(p.plugins,function(o){if(o.execCommand&&o.execCommand(u,r,x)){p.onExecCommand.dispatch(p,u,r,x,m);q=1;return false}});if(q){return true}if(p.theme&&p.theme.execCommand&&p.theme.execCommand(u,r,x)){p.onExecCommand.dispatch(p,u,r,x,m);return true}if(p.editorCommands.execCommand(u,r,x)){p.onExecCommand.dispatch(p,u,r,x,m);return true}p.getDoc().execCommand(u,r,x);p.onExecCommand.dispatch(p,u,r,x,m)},queryCommandState:function(q){var n=this,r,p;if(n._isHidden()){return}if(r=n.queryStateCommands[q]){p=r.func.call(r.scope);if(p!==true){return p}}r=n.editorCommands.queryCommandState(q);if(r!==-1){return r}try{return this.getDoc().queryCommandState(q)}catch(m){}},queryCommandValue:function(r){var n=this,q,p;if(n._isHidden()){return}if(q=n.queryValueCommands[r]){p=q.func.call(q.scope);if(p!==true){return p}}q=n.editorCommands.queryCommandValue(r);if(d(q)){return q}try{return this.getDoc().queryCommandValue(r)}catch(m){}},show:function(){var m=this;l.show(m.getContainer());l.hide(m.id);m.load()},hide:function(){var m=this,n=m.getDoc();if(b&&n){n.execCommand("SelectAll")}m.save();l.hide(m.getContainer());l.setStyle(m.id,"display",m.orgDisplay)},isHidden:function(){return !l.isHidden(this.id)},setProgressState:function(m,n,p){this.onSetProgressState.dispatch(this,m,n,p);return m},load:function(q){var m=this,p=m.getElement(),n;if(p){q=q||{};q.load=true;n=m.setContent(d(p.value)?p.value:p.innerHTML,q);q.element=p;if(!q.no_events){m.onLoadContent.dispatch(m,q)}q.element=p=null;return n}},save:function(r){var m=this,q=m.getElement(),n,p;if(!q||!m.initialized){return}r=r||{};r.save=true;r.element=q;n=r.content=m.getContent(r);if(!r.no_events){m.onSaveContent.dispatch(m,r)}n=r.content;if(!/TEXTAREA|INPUT/i.test(q.nodeName)){q.innerHTML=n;if(p=l.getParent(m.id,"form")){i(p.elements,function(o){if(o.name==m.id){o.value=n;return false}})}}else{q.value=n}r.element=q=null;return n},setContent:function(r,p){var o=this,n,m=o.getBody(),q;p=p||{};p.format=p.format||"html";p.set=true;p.content=r;if(!p.no_events){o.onBeforeSetContent.dispatch(o,p)}r=p.content;if(!k.isIE&&(r.length===0||/^\s+$/.test(r))){q=o.settings.forced_root_block;if(q){r="<"+q+'><br data-mce-bogus="1"></'+q+">"}else{r='<br data-mce-bogus="1">'}m.innerHTML=r;o.selection.select(m,true);o.selection.collapse(true);return}if(p.format!=="raw"){r=new k.html.Serializer({},o.schema).serialize(o.parser.parse(r))}p.content=k.trim(r);o.dom.setHTML(m,p.content);if(!p.no_events){o.onSetContent.dispatch(o,p)}if(!o.settings.content_editable||document.activeElement===o.getBody()){o.selection.normalize()}return p.content},getContent:function(n){var m=this,o;n=n||{};n.format=n.format||"html";n.get=true;n.getInner=true;if(!n.no_events){m.onBeforeGetContent.dispatch(m,n)}if(n.format=="raw"){o=m.getBody().innerHTML}else{o=m.serializer.serialize(m.getBody(),n)}n.content=k.trim(o);if(!n.no_events){m.onGetContent.dispatch(m,n)}return n.content},isDirty:function(){var m=this;return k.trim(m.startContent)!=k.trim(m.getContent({format:"raw",no_events:1}))&&!m.isNotDirty},getContainer:function(){var m=this;if(!m.container){m.container=l.get(m.editorContainer||m.id+"_parent")}return m.container},getContentAreaContainer:function(){return this.contentAreaContainer},getElement:function(){return l.get(this.settings.content_element||this.id)},getWin:function(){var m=this,n;if(!m.contentWindow){n=l.get(m.id+"_ifr");if(n){m.contentWindow=n.contentWindow}}return m.contentWindow},getDoc:function(){var m=this,n;if(!m.contentDocument){n=m.getWin();if(n){m.contentDocument=n.document}}return m.contentDocument},getBody:function(){return this.bodyElement||this.getDoc().body},convertURL:function(o,n,q){var m=this,p=m.settings;if(p.urlconverter_callback){return m.execCallback("urlconverter_callback",o,q,true,n)}if(!p.convert_urls||(q&&q.nodeName=="LINK")||o.indexOf("file:")===0){return o}if(p.relative_urls){return m.documentBaseURI.toRelative(o)}o=m.documentBaseURI.toAbsolute(o,p.remove_script_host);return o},addVisual:function(q){var n=this,o=n.settings,p=n.dom,m;q=q||n.getBody();if(!d(n.hasVisual)){n.hasVisual=o.visual}i(p.select("table,a",q),function(s){var r;switch(s.nodeName){case"TABLE":m=o.visual_table_class||"mceItemTable";r=p.getAttrib(s,"border");if(!r||r=="0"){if(n.hasVisual){p.addClass(s,m)}else{p.removeClass(s,m)}}return;case"A":if(!p.getAttrib(s,"href",false)){r=p.getAttrib(s,"name")||s.id;m="mceItemAnchor";if(r){if(n.hasVisual){p.addClass(s,m)}else{p.removeClass(s,m)}}}return}});n.onVisualAid.dispatch(n,q,n.hasVisual)},remove:function(){var m=this,n=m.getContainer();if(!m.removed){m.removed=1;m.hide();if(!m.settings.content_editable){j.unbind(m.getWin());j.unbind(m.getDoc())}j.unbind(m.getBody());j.clear(n);m.execCallback("remove_instance_callback",m);m.onRemove.dispatch(m);m.onExecCommand.listeners=[];k.remove(m);l.remove(n)}},destroy:function(n){var m=this;if(m.destroyed){return}if(a){j.unbind(m.getDoc());j.unbind(m.getWin());j.unbind(m.getBody())}if(!n){k.removeUnload(m.destroy);tinyMCE.onBeforeUnload.remove(m._beforeUnload);if(m.theme&&m.theme.destroy){m.theme.destroy()}m.controlManager.destroy();m.selection.destroy();m.dom.destroy()}if(m.formElement){m.formElement.submit=m.formElement._mceOldSubmit;m.formElement._mceOldSubmit=null}m.contentAreaContainer=m.formElement=m.container=m.settings.content_element=m.bodyElement=m.contentDocument=m.contentWindow=null;if(m.selection){m.selection=m.selection.win=m.selection.dom=m.selection.dom.doc=null}m.destroyed=1},_refreshContentEditable:function(){var n=this,m,o;if(n._isHidden()){m=n.getBody();o=m.parentNode;o.removeChild(m);o.appendChild(m);m.focus()}},_isHidden:function(){var m;if(!a){return 0}m=this.selection.getSel();return(!m||!m.rangeCount||m.rangeCount===0)}})})(tinymce);(function(a){var b=a.each;a.Editor.prototype.setupEvents=function(){var c=this,d=c.settings;b(["onPreInit","onBeforeRenderUI","onPostRender","onLoad","onInit","onRemove","onActivate","onDeactivate","onClick","onEvent","onMouseUp","onMouseDown","onDblClick","onKeyDown","onKeyUp","onKeyPress","onContextMenu","onSubmit","onReset","onPaste","onPreProcess","onPostProcess","onBeforeSetContent","onBeforeGetContent","onSetContent","onGetContent","onLoadContent","onSaveContent","onNodeChange","onChange","onBeforeExecCommand","onExecCommand","onUndo","onRedo","onVisualAid","onSetProgressState","onSetAttrib"],function(e){c[e]=new a.util.Dispatcher(c)});if(d.cleanup_callback){c.onBeforeSetContent.add(function(e,f){f.content=e.execCallback("cleanup_callback","insert_to_editor",f.content,f)});c.onPreProcess.add(function(e,f){if(f.set){e.execCallback("cleanup_callback","insert_to_editor_dom",f.node,f)}if(f.get){e.execCallback("cleanup_callback","get_from_editor_dom",f.node,f)}});c.onPostProcess.add(function(e,f){if(f.set){f.content=e.execCallback("cleanup_callback","insert_to_editor",f.content,f)}if(f.get){f.content=e.execCallback("cleanup_callback","get_from_editor",f.content,f)}})}if(d.save_callback){c.onGetContent.add(function(e,f){if(f.save){f.content=e.execCallback("save_callback",e.id,f.content,e.getBody())}})}if(d.handle_event_callback){c.onEvent.add(function(f,g,h){if(c.execCallback("handle_event_callback",g,f,h)===false){g.preventDefault();g.stopPropagation()}})}if(d.handle_node_change_callback){c.onNodeChange.add(function(f,e,g){f.execCallback("handle_node_change_callback",f.id,g,-1,-1,true,f.selection.isCollapsed())})}if(d.save_callback){c.onSaveContent.add(function(e,g){var f=e.execCallback("save_callback",e.id,g.content,e.getBody());if(f){g.content=f}})}if(d.onchange_callback){c.onChange.add(function(f,e){f.execCallback("onchange_callback",f,e)})}};a.Editor.prototype.bindNativeEvents=function(){var l=this,f,d=l.settings,e=l.dom,h;h={mouseup:"onMouseUp",mousedown:"onMouseDown",click:"onClick",keyup:"onKeyUp",keydown:"onKeyDown",keypress:"onKeyPress",submit:"onSubmit",reset:"onReset",contextmenu:"onContextMenu",dblclick:"onDblClick",paste:"onPaste"};function c(i,m){var n=i.type;if(l.removed){return}if(l.onEvent.dispatch(l,i,m)!==false){l[h[i.fakeType||i.type]].dispatch(l,i,m)}}function j(i){l.focus(true)}function k(){l.selection.normalize();l.nodeChanged()}b(h,function(m,n){var i=d.content_editable?l.getBody():l.getDoc();switch(n){case"contextmenu":e.bind(i,n,c);break;case"paste":e.bind(l.getBody(),n,c);break;case"submit":case"reset":e.bind(l.getElement().form||a.DOM.getParent(l.id,"form"),n,c);break;default:e.bind(i,n,c)}});e.bind(d.content_editable?l.getBody():(a.isGecko?l.getDoc():l.getWin()),"focus",function(i){l.focus(true)});if(d.content_editable&&a.isOpera){e.bind(l.getBody(),"click",j);e.bind(l.getBody(),"keydown",j)}l.onMouseUp.add(k);l.onKeyUp.add(function(i,n){var m=n.keyCode;if((m>=33&&m<=36)||(m>=37&&m<=40)||m==13||m==45||m==46||m==8||(a.isMac&&(m==91||m==93))||n.ctrlKey){k()}});l.onReset.add(function(){l.setContent(l.startContent,{format:"raw"})});function g(m,i){if(m.altKey||m.ctrlKey||m.metaKey){b(l.shortcuts,function(n){var o=a.isMac?m.metaKey:m.ctrlKey;if(n.ctrl!=o||n.alt!=m.altKey||n.shift!=m.shiftKey){return}if(m.keyCode==n.keyCode||(m.charCode&&m.charCode==n.charCode)){m.preventDefault();if(i){n.func.call(n.scope)}return true}})}}l.onKeyUp.add(function(i,m){g(m)});l.onKeyPress.add(function(i,m){g(m)});l.onKeyDown.add(function(i,m){g(m,true)});if(a.isOpera){l.onClick.add(function(i,m){m.preventDefault()})}}})(tinymce);(function(d){var e=d.each,b,a=true,c=false;d.EditorCommands=function(n){var m=n.dom,p=n.selection,j={state:{},exec:{},value:{}},k=n.settings,q=n.formatter,o;function r(z,y,x){var v;z=z.toLowerCase();if(v=j.exec[z]){v(z,y,x);return a}return c}function l(x){var v;x=x.toLowerCase();if(v=j.state[x]){return v(x)}return -1}function h(x){var v;x=x.toLowerCase();if(v=j.value[x]){return v(x)}return c}function u(v,x){x=x||"exec";e(v,function(z,y){e(y.toLowerCase().split(","),function(A){j[x][A]=z})})}d.extend(this,{execCommand:r,queryCommandState:l,queryCommandValue:h,addCommands:u});function f(y,x,v){if(x===b){x=c}if(v===b){v=null}return n.getDoc().execCommand(y,x,v)}function t(v){return q.match(v)}function s(v,x){q.toggle(v,x?{value:x}:b)}function i(v){o=p.getBookmark(v)}function g(){p.moveToBookmark(o)}u({"mceResetDesignMode,mceBeginUndoLevel":function(){},"mceEndUndoLevel,mceAddUndoLevel":function(){n.undoManager.add()},"Cut,Copy,Paste":function(z){var y=n.getDoc(),v;try{f(z)}catch(x){v=a}if(v||!y.queryCommandSupported(z)){if(d.isGecko){n.windowManager.confirm(n.getLang("clipboard_msg"),function(A){if(A){open("http://www.mozilla.org/editor/midasdemo/securityprefs.html","_blank")}})}else{n.windowManager.alert(n.getLang("clipboard_no_support"))}}},unlink:function(v){if(p.isCollapsed()){p.select(p.getNode())}f(v);p.collapse(c)},"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull":function(v){var x=v.substring(7);e("left,center,right,full".split(","),function(y){if(x!=y){q.remove("align"+y)}});s("align"+x);r("mceRepaint")},"InsertUnorderedList,InsertOrderedList":function(y){var v,x;f(y);v=m.getParent(p.getNode(),"ol,ul");if(v){x=v.parentNode;if(/^(H[1-6]|P|ADDRESS|PRE)$/.test(x.nodeName)){i();m.split(x,v);g()}}},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(v){s(v)},"ForeColor,HiliteColor,FontName":function(y,x,v){s(y,v)},FontSize:function(z,y,x){var v,A;if(x>=1&&x<=7){A=d.explode(k.font_size_style_values);v=d.explode(k.font_size_classes);if(v){x=v[x-1]||x}else{x=A[x-1]||x}}s(z,x)},RemoveFormat:function(v){q.remove(v)},mceBlockQuote:function(v){s("blockquote")},FormatBlock:function(y,x,v){return s(v||"p")},mceCleanup:function(){var v=p.getBookmark();n.setContent(n.getContent({cleanup:a}),{cleanup:a});p.moveToBookmark(v)},mceRemoveNode:function(z,y,x){var v=x||p.getNode();if(v!=n.getBody()){i();n.dom.remove(v,a);g()}},mceSelectNodeDepth:function(z,y,x){var v=0;m.getParent(p.getNode(),function(A){if(A.nodeType==1&&v++==x){p.select(A);return c}},n.getBody())},mceSelectNode:function(y,x,v){p.select(v)},mceInsertContent:function(B,I,K){var y,J,E,z,F,G,D,C,L,x,A,M,v,H;y=n.parser;J=new d.html.Serializer({},n.schema);v='<span id="mce_marker" data-mce-type="bookmark">\uFEFF</span>';G={content:K,format:"html"};p.onBeforeSetContent.dispatch(p,G);K=G.content;if(K.indexOf("{$caret}")==-1){K+="{$caret}"}K=K.replace(/\{\$caret\}/,v);if(!p.isCollapsed()){n.getDoc().execCommand("Delete",false,null)}E=p.getNode();G={context:E.nodeName.toLowerCase()};F=y.parse(K,G);A=F.lastChild;if(A.attr("id")=="mce_marker"){D=A;for(A=A.prev;A;A=A.walk(true)){if(A.type==3||!m.isBlock(A.name)){A.parent.insert(D,A,A.name==="br");break}}}if(!G.invalid){K=J.serialize(F);A=E.firstChild;M=E.lastChild;if(!A||(A===M&&A.nodeName==="BR")){m.setHTML(E,K)}else{p.setContent(K)}}else{p.setContent(v);E=n.selection.getNode();z=n.getBody();if(E.nodeType==9){E=A=z}else{A=E}while(A!==z){E=A;A=A.parentNode}K=E==z?z.innerHTML:m.getOuterHTML(E);K=J.serialize(y.parse(K.replace(/<span (id="mce_marker"|id=mce_marker).+?<\/span>/i,function(){return J.serialize(F)})));if(E==z){m.setHTML(z,K)}else{m.setOuterHTML(E,K)}}D=m.get("mce_marker");C=m.getRect(D);L=m.getViewPort(n.getWin());if((C.y+C.h>L.y+L.h||C.y<L.y)||(C.x>L.x+L.w||C.x<L.x)){H=d.isIE?n.getDoc().documentElement:n.getBody();H.scrollLeft=C.x;H.scrollTop=C.y-L.h+25}x=m.createRng();A=D.previousSibling;if(A&&A.nodeType==3){x.setStart(A,A.nodeValue.length)}else{x.setStartBefore(D);x.setEndBefore(D)}m.remove(D);p.setRng(x);p.onSetContent.dispatch(p,G);n.addVisual()},mceInsertRawHTML:function(y,x,v){p.setContent("tiny_mce_marker");n.setContent(n.getContent().replace(/tiny_mce_marker/g,function(){return v}))},mceToggleFormat:function(y,x,v){s(v)},mceSetContent:function(y,x,v){n.setContent(v)},"Indent,Outdent":function(z){var x,v,y;x=k.indentation;v=/[a-z%]+$/i.exec(x);x=parseInt(x);if(!l("InsertUnorderedList")&&!l("InsertOrderedList")){if(!k.forced_root_block&&!m.getParent(p.getNode(),m.isBlock)){q.apply("div")}e(p.getSelectedBlocks(),function(A){if(z=="outdent"){y=Math.max(0,parseInt(A.style.paddingLeft||0)-x);m.setStyle(A,"paddingLeft",y?y+v:"")}else{m.setStyle(A,"paddingLeft",(parseInt(A.style.paddingLeft||0)+x)+v)}})}else{f(z)}},mceRepaint:function(){var x;if(d.isGecko){try{i(a);if(p.getSel()){p.getSel().selectAllChildren(n.getBody())}p.collapse(a);g()}catch(v){}}},mceToggleFormat:function(y,x,v){q.toggle(v)},InsertHorizontalRule:function(){n.execCommand("mceInsertContent",false,"<hr />")},mceToggleVisualAid:function(){n.hasVisual=!n.hasVisual;n.addVisual()},mceReplaceContent:function(y,x,v){n.execCommand("mceInsertContent",false,v.replace(/\{\$selection\}/g,p.getContent({format:"text"})))},mceInsertLink:function(z,y,x){var v;if(typeof(x)=="string"){x={href:x}}v=m.getParent(p.getNode(),"a");x.href=x.href.replace(" ","%20");if(!v||!x.href){q.remove("link")}if(x.href){q.apply("link",x,v)}},selectAll:function(){var x=m.getRoot(),v=m.createRng();v.setStart(x,0);v.setEnd(x,x.childNodes.length);n.selection.setRng(v)}});u({"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull":function(z){var x="align"+z.substring(7);var v=p.isCollapsed()?[m.getParent(p.getNode(),m.isBlock)]:p.getSelectedBlocks();var y=d.map(v,function(A){return !!q.matchNode(A,x)});return d.inArray(y,a)!==-1},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(v){return t(v)},mceBlockQuote:function(){return t("blockquote")},Outdent:function(){var v;if(k.inline_styles){if((v=m.getParent(p.getStart(),m.isBlock))&&parseInt(v.style.paddingLeft)>0){return a}if((v=m.getParent(p.getEnd(),m.isBlock))&&parseInt(v.style.paddingLeft)>0){return a}}return l("InsertUnorderedList")||l("InsertOrderedList")||(!k.inline_styles&&!!m.getParent(p.getNode(),"BLOCKQUOTE"))},"InsertUnorderedList,InsertOrderedList":function(v){return m.getParent(p.getNode(),v=="insertunorderedlist"?"UL":"OL")}},"state");u({"FontSize,FontName":function(y){var x=0,v;if(v=m.getParent(p.getNode(),"span")){if(y=="fontsize"){x=v.style.fontSize}else{x=v.style.fontFamily.replace(/, /g,",").replace(/[\'\"]/g,"").toLowerCase()}}return x}},"value");u({Undo:function(){n.undoManager.undo()},Redo:function(){n.undoManager.redo()}})}})(tinymce);(function(b){var a=b.util.Dispatcher;b.UndoManager=function(h){var l,i=0,e=[],g,k,j,f;function c(){return b.trim(h.getContent({format:"raw",no_events:1}).replace(/<span[^>]+data-mce-bogus[^>]+>[\u200B\uFEFF]+<\/span>/g,""))}function d(){l.typing=false;l.add()}onBeforeAdd=new a(l);k=new a(l);j=new a(l);f=new a(l);k.add(function(m,n){if(m.hasUndo()){return h.onChange.dispatch(h,n,m)}});j.add(function(m,n){return h.onUndo.dispatch(h,n,m)});f.add(function(m,n){return h.onRedo.dispatch(h,n,m)});h.onInit.add(function(){l.add()});h.onBeforeExecCommand.add(function(m,p,o,q,n){if(p!="Undo"&&p!="Redo"&&p!="mceRepaint"&&(!n||!n.skip_undo)){l.beforeChange()}});h.onExecCommand.add(function(m,p,o,q,n){if(p!="Undo"&&p!="Redo"&&p!="mceRepaint"&&(!n||!n.skip_undo)){l.add()}});h.onSaveContent.add(d);h.dom.bind(h.dom.getRoot(),"dragend",d);h.dom.bind(h.getDoc(),b.isGecko?"blur":"focusout",function(m){if(!h.removed&&l.typing){d()}});h.onKeyUp.add(function(m,o){var n=o.keyCode;if((n>=33&&n<=36)||(n>=37&&n<=40)||n==45||n==13||o.ctrlKey){d()}});h.onKeyDown.add(function(m,o){var n=o.keyCode;if((n>=33&&n<=36)||(n>=37&&n<=40)||n==45){if(l.typing){d()}return}if((n<16||n>20)&&n!=224&&n!=91&&!l.typing){l.beforeChange();l.typing=true;l.add()}});h.onMouseDown.add(function(m,n){if(l.typing){d()}});h.addShortcut("ctrl+z","undo_desc","Undo");h.addShortcut("ctrl+y","redo_desc","Redo");l={data:e,typing:false,onBeforeAdd:onBeforeAdd,onAdd:k,onUndo:j,onRedo:f,beforeChange:function(){g=h.selection.getBookmark(2,true)},add:function(p){var m,n=h.settings,o;p=p||{};p.content=c();l.onBeforeAdd.dispatch(l,p);o=e[i];if(o&&o.content==p.content){return null}if(e[i]){e[i].beforeBookmark=g}if(n.custom_undo_redo_levels){if(e.length>n.custom_undo_redo_levels){for(m=0;m<e.length-1;m++){e[m]=e[m+1]}e.length--;i=e.length}}p.bookmark=h.selection.getBookmark(2,true);if(i<e.length-1){e.length=i+1}e.push(p);i=e.length-1;l.onAdd.dispatch(l,p);h.isNotDirty=0;return p},undo:function(){var n,m;if(l.typing){l.add();l.typing=false}if(i>0){n=e[--i];h.setContent(n.content,{format:"raw"});h.selection.moveToBookmark(n.beforeBookmark);l.onUndo.dispatch(l,n)}return n},redo:function(){var m;if(i<e.length-1){m=e[++i];h.setContent(m.content,{format:"raw"});h.selection.moveToBookmark(m.bookmark);l.onRedo.dispatch(l,m)}return m},clear:function(){e=[];i=0;l.typing=false},hasUndo:function(){return i>0||this.typing},hasRedo:function(){return i<e.length-1&&!this.typing}};return l}})(tinymce);tinymce.ForceBlocks=function(c){var b=c.settings,e=c.dom,a=c.selection,d=c.schema.getBlockElements();function f(){var j=a.getStart(),h=c.getBody(),g,k,o,s,q,i,l,m=-16777215,p,r;if(!j||j.nodeType!==1||!b.forced_root_block){return}while(j&&j!=h){if(d[j.nodeName]){return}j=j.parentNode}g=a.getRng();if(g.setStart){k=g.startContainer;o=g.startOffset;s=g.endContainer;q=g.endOffset}else{if(g.item){j=g.item(0);g=c.getDoc().body.createTextRange();g.moveToElementText(j)}r=g.parentElement().ownerDocument===c.getDoc();tmpRng=g.duplicate();tmpRng.collapse(true);o=tmpRng.move("character",m)*-1;if(!tmpRng.collapsed){tmpRng=g.duplicate();tmpRng.collapse(false);q=(tmpRng.move("character",m)*-1)-o}}j=h.firstChild;while(j){if(j.nodeType===3||(j.nodeType==1&&!d[j.nodeName])){if(!i){i=e.create(b.forced_root_block);j.parentNode.insertBefore(i,j);p=true}l=j;j=j.nextSibling;i.appendChild(l)}else{i=null;j=j.nextSibling}}if(p){if(g.setStart){g.setStart(k,o);g.setEnd(s,q);a.setRng(g)}else{if(r){try{g=c.getDoc().body.createTextRange();g.moveToElementText(h);g.collapse(true);g.moveStart("character",o);if(q>0){g.moveEnd("character",q)}g.select()}catch(n){}}}c.nodeChanged()}}if(b.forced_root_block){c.onKeyUp.add(f);c.onNodeChange.add(f)}};(function(c){var b=c.DOM,a=c.dom.Event,d=c.each,e=c.extend;c.create("tinymce.ControlManager",{ControlManager:function(f,j){var h=this,g;j=j||{};h.editor=f;h.controls={};h.onAdd=new c.util.Dispatcher(h);h.onPostRender=new c.util.Dispatcher(h);h.prefix=j.prefix||f.id+"_";h._cls={};h.onPostRender.add(function(){d(h.controls,function(i){i.postRender()})})},get:function(f){return this.controls[this.prefix+f]||this.controls[f]},setActive:function(h,f){var g=null;if(g=this.get(h)){g.setActive(f)}return g},setDisabled:function(h,f){var g=null;if(g=this.get(h)){g.setDisabled(f)}return g},add:function(g){var f=this;if(g){f.controls[g.id]=g;f.onAdd.dispatch(g,f)}return g},createControl:function(j){var o,k,g,h=this,m=h.editor,n,f;if(!h.controlFactories){h.controlFactories=[];d(m.plugins,function(i){if(i.createControl){h.controlFactories.push(i)}})}n=h.controlFactories;for(k=0,g=n.length;k<g;k++){o=n[k].createControl(j,h);if(o){return h.add(o)}}if(j==="|"||j==="separator"){return h.createSeparator()}if(m.buttons&&(o=m.buttons[j])){return h.createButton(j,o)}return h.add(o)},createDropMenu:function(f,n,h){var m=this,i=m.editor,j,g,k,l;n=e({"class":"mceDropDown",constrain:i.settings.constrain_menus},n);n["class"]=n["class"]+" "+i.getParam("skin")+"Skin";if(k=i.getParam("skin_variant")){n["class"]+=" "+i.getParam("skin")+"Skin"+k.substring(0,1).toUpperCase()+k.substring(1)}n["class"]+=i.settings.directionality=="rtl"?" mceRtl":"";f=m.prefix+f;l=h||m._cls.dropmenu||c.ui.DropMenu;j=m.controls[f]=new l(f,n);j.onAddItem.add(function(r,q){var p=q.settings;p.title=i.getLang(p.title,p.title);if(!p.onclick){p.onclick=function(o){if(p.cmd){i.execCommand(p.cmd,p.ui||false,p.value)}}}});i.onRemove.add(function(){j.destroy()});if(c.isIE){j.onShowMenu.add(function(){i.focus();g=i.selection.getBookmark(1)});j.onHideMenu.add(function(){if(g){i.selection.moveToBookmark(g);g=0}})}return m.add(j)},createListBox:function(f,n,h){var l=this,j=l.editor,i,k,m;if(l.get(f)){return null}n.title=j.translate(n.title);n.scope=n.scope||j;if(!n.onselect){n.onselect=function(o){j.execCommand(n.cmd,n.ui||false,o||n.value)}}n=e({title:n.title,"class":"mce_"+f,scope:n.scope,control_manager:l},n);f=l.prefix+f;function g(o){return o.settings.use_accessible_selects&&!c.isGecko}if(j.settings.use_native_selects||g(j)){k=new c.ui.NativeListBox(f,n)}else{m=h||l._cls.listbox||c.ui.ListBox;k=new m(f,n,j)}l.controls[f]=k;if(c.isWebKit){k.onPostRender.add(function(p,o){a.add(o,"mousedown",function(){j.bookmark=j.selection.getBookmark(1)});a.add(o,"focus",function(){j.selection.moveToBookmark(j.bookmark);j.bookmark=null})})}if(k.hideMenu){j.onMouseDown.add(k.hideMenu,k)}return l.add(k)},createButton:function(m,i,l){var h=this,g=h.editor,j,k,f;if(h.get(m)){return null}i.title=g.translate(i.title);i.label=g.translate(i.label);i.scope=i.scope||g;if(!i.onclick&&!i.menu_button){i.onclick=function(){g.execCommand(i.cmd,i.ui||false,i.value)}}i=e({title:i.title,"class":"mce_"+m,unavailable_prefix:g.getLang("unavailable",""),scope:i.scope,control_manager:h},i);m=h.prefix+m;if(i.menu_button){f=l||h._cls.menubutton||c.ui.MenuButton;k=new f(m,i,g);g.onMouseDown.add(k.hideMenu,k)}else{f=h._cls.button||c.ui.Button;k=new f(m,i,g)}return h.add(k)},createMenuButton:function(h,f,g){f=f||{};f.menu_button=1;return this.createButton(h,f,g)},createSplitButton:function(m,i,l){var h=this,g=h.editor,j,k,f;if(h.get(m)){return null}i.title=g.translate(i.title);i.scope=i.scope||g;if(!i.onclick){i.onclick=function(n){g.execCommand(i.cmd,i.ui||false,n||i.value)}}if(!i.onselect){i.onselect=function(n){g.execCommand(i.cmd,i.ui||false,n||i.value)}}i=e({title:i.title,"class":"mce_"+m,scope:i.scope,control_manager:h},i);m=h.prefix+m;f=l||h._cls.splitbutton||c.ui.SplitButton;k=h.add(new f(m,i,g));g.onMouseDown.add(k.hideMenu,k);return k},createColorSplitButton:function(f,n,h){var l=this,j=l.editor,i,k,m,g;if(l.get(f)){return null}n.title=j.translate(n.title);n.scope=n.scope||j;if(!n.onclick){n.onclick=function(o){if(c.isIE){g=j.selection.getBookmark(1)}j.execCommand(n.cmd,n.ui||false,o||n.value)}}if(!n.onselect){n.onselect=function(o){j.execCommand(n.cmd,n.ui||false,o||n.value)}}n=e({title:n.title,"class":"mce_"+f,menu_class:j.getParam("skin")+"Skin",scope:n.scope,more_colors_title:j.getLang("more_colors")},n);f=l.prefix+f;m=h||l._cls.colorsplitbutton||c.ui.ColorSplitButton;k=new m(f,n,j);j.onMouseDown.add(k.hideMenu,k);j.onRemove.add(function(){k.destroy()});if(c.isIE){k.onShowMenu.add(function(){j.focus();g=j.selection.getBookmark(1)});k.onHideMenu.add(function(){if(g){j.selection.moveToBookmark(g);g=0}})}return l.add(k)},createToolbar:function(k,h,j){var i,g=this,f;k=g.prefix+k;f=j||g._cls.toolbar||c.ui.Toolbar;i=new f(k,h,g.editor);if(g.get(k)){return null}return g.add(i)},createToolbarGroup:function(k,h,j){var i,g=this,f;k=g.prefix+k;f=j||this._cls.toolbarGroup||c.ui.ToolbarGroup;i=new f(k,h,g.editor);if(g.get(k)){return null}return g.add(i)},createSeparator:function(g){var f=g||this._cls.separator||c.ui.Separator;return new f()},setControlType:function(g,f){return this._cls[g.toLowerCase()]=f},destroy:function(){d(this.controls,function(f){f.destroy()});this.controls=null}})})(tinymce);(function(d){var a=d.util.Dispatcher,e=d.each,c=d.isIE,b=d.isOpera;d.create("tinymce.WindowManager",{WindowManager:function(f){var g=this;g.editor=f;g.onOpen=new a(g);g.onClose=new a(g);g.params={};g.features={}},open:function(z,h){var v=this,k="",n,m,i=v.editor.settings.dialog_type=="modal",q,o,j,g=d.DOM.getViewPort(),r;z=z||{};h=h||{};o=b?g.w:screen.width;j=b?g.h:screen.height;z.name=z.name||"mc_"+new Date().getTime();z.width=parseInt(z.width||320);z.height=parseInt(z.height||240);z.resizable=true;z.left=z.left||parseInt(o/2)-(z.width/2);z.top=z.top||parseInt(j/2)-(z.height/2);h.inline=false;h.mce_width=z.width;h.mce_height=z.height;h.mce_auto_focus=z.auto_focus;if(i){if(c){z.center=true;z.help=false;z.dialogWidth=z.width+"px";z.dialogHeight=z.height+"px";z.scroll=z.scrollbars||false}}e(z,function(p,f){if(d.is(p,"boolean")){p=p?"yes":"no"}if(!/^(name|url)$/.test(f)){if(c&&i){k+=(k?";":"")+f+":"+p}else{k+=(k?",":"")+f+"="+p}}});v.features=z;v.params=h;v.onOpen.dispatch(v,z,h);r=z.url||z.file;r=d._addVer(r);try{if(c&&i){q=1;window.showModalDialog(r,window,k)}else{q=window.open(r,z.name,k)}}catch(l){}if(!q){alert(v.editor.getLang("popup_blocked"))}},close:function(f){f.close();this.onClose.dispatch(this)},createInstance:function(i,h,g,m,l,k){var j=d.resolve(i);return new j(h,g,m,l,k)},confirm:function(h,f,i,g){g=g||window;f.call(i||this,g.confirm(this._decode(this.editor.getLang(h,h))))},alert:function(h,f,j,g){var i=this;g=g||window;g.alert(i._decode(i.editor.getLang(h,h)));if(f){f.call(j||i)}},resizeBy:function(f,g,h){h.resizeBy(f,g)},_decode:function(f){return d.DOM.decode(f).replace(/\\n/g,"\n")}})}(tinymce));(function(a){a.Formatter=function(aa){var Q={},T=a.each,c=aa.dom,r=aa.selection,t=a.dom.TreeWalker,N=new a.dom.RangeUtils(c),d=aa.schema.isValidChild,H=c.isBlock,m=aa.settings.forced_root_block,s=c.nodeIndex,G=a.isGecko?"\u200B":"\uFEFF",e=/^(src|href|style)$/,X=false,C=true,P,D,x=c.getContentEditable;function A(ab){return ab instanceof Array}function n(ac,ab){return c.getParents(ac,ab,c.getRoot())}function b(ab){return ab.nodeType===1&&ab.id==="_mce_caret"}function j(){l({alignleft:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",styles:{textAlign:"left"},defaultBlock:"div"},{selector:"img,table",collapsed:false,styles:{"float":"left"}}],aligncenter:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",styles:{textAlign:"center"},defaultBlock:"div"},{selector:"img",collapsed:false,styles:{display:"block",marginLeft:"auto",marginRight:"auto"}},{selector:"table",collapsed:false,styles:{marginLeft:"auto",marginRight:"auto"}}],alignright:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",styles:{textAlign:"right"},defaultBlock:"div"},{selector:"img,table",collapsed:false,styles:{"float":"right"}}],alignfull:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",styles:{textAlign:"justify"},defaultBlock:"div"}],bold:[{inline:"strong",remove:"all"},{inline:"span",styles:{fontWeight:"bold"}},{inline:"b",remove:"all"}],italic:[{inline:"em",remove:"all"},{inline:"span",styles:{fontStyle:"italic"}},{inline:"i",remove:"all"}],underline:[{inline:"span",styles:{textDecoration:"underline"},exact:true},{inline:"u",remove:"all"}],strikethrough:[{inline:"span",styles:{textDecoration:"line-through"},exact:true},{inline:"strike",remove:"all"}],forecolor:{inline:"span",styles:{color:"%value"},wrap_links:false},hilitecolor:{inline:"span",styles:{backgroundColor:"%value"},wrap_links:false},fontname:{inline:"span",styles:{fontFamily:"%value"}},fontsize:{inline:"span",styles:{fontSize:"%value"}},fontsize_class:{inline:"span",attributes:{"class":"%value"}},blockquote:{block:"blockquote",wrapper:1,remove:"all"},subscript:{inline:"sub"},superscript:{inline:"sup"},link:{inline:"a",selector:"a",remove:"all",split:true,deep:true,onmatch:function(ab){return true},onformat:function(ad,ab,ac){T(ac,function(af,ae){c.setAttrib(ad,ae,af)})}},removeformat:[{selector:"b,strong,em,i,font,u,strike",remove:"all",split:true,expand:false,block_expand:true,deep:true},{selector:"span",attributes:["style","class"],remove:"empty",split:true,expand:false,deep:true},{selector:"*",attributes:["style","class"],split:false,expand:false,deep:true}]});T("p h1 h2 h3 h4 h5 h6 div address pre div code dt dd samp".split(/\s/),function(ab){l(ab,{block:ab,remove:"all"})});l(aa.settings.formats)}function W(){aa.addShortcut("ctrl+b","bold_desc","Bold");aa.addShortcut("ctrl+i","italic_desc","Italic");aa.addShortcut("ctrl+u","underline_desc","Underline");for(var ab=1;ab<=6;ab++){aa.addShortcut("ctrl+"+ab,"",["FormatBlock",false,"h"+ab])}aa.addShortcut("ctrl+7","",["FormatBlock",false,"p"]);aa.addShortcut("ctrl+8","",["FormatBlock",false,"div"]);aa.addShortcut("ctrl+9","",["FormatBlock",false,"address"])}function V(ab){return ab?Q[ab]:Q}function l(ab,ac){if(ab){if(typeof(ab)!=="string"){T(ab,function(ae,ad){l(ad,ae)})}else{ac=ac.length?ac:[ac];T(ac,function(ad){if(ad.deep===D){ad.deep=!ad.selector}if(ad.split===D){ad.split=!ad.selector||ad.inline}if(ad.remove===D&&ad.selector&&!ad.inline){ad.remove="none"}if(ad.selector&&ad.inline){ad.mixed=true;ad.block_expand=true}if(typeof(ad.classes)==="string"){ad.classes=ad.classes.split(/\s+/)}});Q[ab]=ac}}}var i=function(ac){var ab;aa.dom.getParent(ac,function(ad){ab=aa.dom.getStyle(ad,"text-decoration");return ab&&ab!=="none"});return ab};var L=function(ab){var ac;if(ab.nodeType===1&&ab.parentNode&&ab.parentNode.nodeType===1){ac=i(ab.parentNode);if(aa.dom.getStyle(ab,"color")&&ac){aa.dom.setStyle(ab,"text-decoration",ac)}else{if(aa.dom.getStyle(ab,"textdecoration")===ac){aa.dom.setStyle(ab,"text-decoration",null)}}}};function Y(ae,al,ag){var ah=V(ae),am=ah[0],ak,ac,aj,ai=r.isCollapsed();function ab(aq,ap){ap=ap||am;if(aq){if(ap.onformat){ap.onformat(aq,ap,al,ag)}T(ap.styles,function(at,ar){c.setStyle(aq,ar,q(at,al))});T(ap.attributes,function(at,ar){c.setAttrib(aq,ar,q(at,al))});T(ap.classes,function(ar){ar=q(ar,al);if(!c.hasClass(aq,ar)){c.addClass(aq,ar)}})}}function af(){function ar(ay,aw){var ax=new t(aw);for(ag=ax.current();ag;ag=ax.prev()){if(ag.childNodes.length>1||ag==ay||ag.tagName=="BR"){return ag}}}var aq=aa.selection.getRng();var av=aq.startContainer;var ap=aq.endContainer;if(av!=ap&&aq.endOffset===0){var au=ar(av,ap);var at=au.nodeType==3?au.length:au.childNodes.length;aq.setEnd(au,at)}return aq}function ad(at,ay,aw,av,aq){var ap=[],ar=-1,ax,aA=-1,au=-1,az;T(at.childNodes,function(aC,aB){if(aC.nodeName==="UL"||aC.nodeName==="OL"){ar=aB;ax=aC;return false}});T(at.childNodes,function(aC,aB){if(aC.nodeName==="SPAN"&&c.getAttrib(aC,"data-mce-type")=="bookmark"){if(aC.id==ay.id+"_start"){aA=aB}else{if(aC.id==ay.id+"_end"){au=aB}}}});if(ar<=0||(aA<ar&&au>ar)){T(a.grep(at.childNodes),aq);return 0}else{az=c.clone(aw,X);T(a.grep(at.childNodes),function(aC,aB){if((aA<ar&&aB<ar)||(aA>ar&&aB>ar)){ap.push(aC);aC.parentNode.removeChild(aC)}});if(aA<ar){at.insertBefore(az,ax)}else{if(aA>ar){at.insertBefore(az,ax.nextSibling)}}av.push(az);T(ap,function(aB){az.appendChild(aB)});return az}}function an(aq,at,aw){var ap=[],av,ar,au=true;av=am.inline||am.block;ar=c.create(av);ab(ar);N.walk(aq,function(ax){var ay;function az(aA){var aF,aD,aB,aC,aE;aE=au;aF=aA.nodeName.toLowerCase();aD=aA.parentNode.nodeName.toLowerCase();if(aA.nodeType===1&&x(aA)){aE=au;au=x(aA)==="true";aC=true}if(g(aF,"br")){ay=0;if(am.block){c.remove(aA)}return}if(am.wrapper&&y(aA,ae,al)){ay=0;return}if(au&&!aC&&am.block&&!am.wrapper&&I(aF)){aA=c.rename(aA,av);ab(aA);ap.push(aA);ay=0;return}if(am.selector){T(ah,function(aG){if("collapsed" in aG&&aG.collapsed!==ai){return}if(c.is(aA,aG.selector)&&!b(aA)){ab(aA,aG);aB=true}});if(!am.inline||aB){ay=0;return}}if(au&&!aC&&d(av,aF)&&d(aD,av)&&!(!aw&&aA.nodeType===3&&aA.nodeValue.length===1&&aA.nodeValue.charCodeAt(0)===65279)&&!b(aA)){if(!ay){ay=c.clone(ar,X);aA.parentNode.insertBefore(ay,aA);ap.push(ay)}ay.appendChild(aA)}else{if(aF=="li"&&at){ay=ad(aA,at,ar,ap,az)}else{ay=0;T(a.grep(aA.childNodes),az);if(aC){au=aE}ay=0}}}T(ax,az)});if(am.wrap_links===false){T(ap,function(ax){function ay(aC){var aB,aA,az;if(aC.nodeName==="A"){aA=c.clone(ar,X);ap.push(aA);az=a.grep(aC.childNodes);for(aB=0;aB<az.length;aB++){aA.appendChild(az[aB])}aC.appendChild(aA)}T(a.grep(aC.childNodes),ay)}ay(ax)})}T(ap,function(az){var ax;function aA(aC){var aB=0;T(aC.childNodes,function(aD){if(!f(aD)&&!K(aD)){aB++}});return aB}function ay(aB){var aD,aC;T(aB.childNodes,function(aE){if(aE.nodeType==1&&!K(aE)&&!b(aE)){aD=aE;return X}});if(aD&&h(aD,am)){aC=c.clone(aD,X);ab(aC);c.replace(aC,aB,C);c.remove(aD,1)}return aC||aB}ax=aA(az);if((ap.length>1||!H(az))&&ax===0){c.remove(az,1);return}if(am.inline||am.wrapper){if(!am.exact&&ax===1){az=ay(az)}T(ah,function(aB){T(c.select(aB.inline,az),function(aD){var aC;if(aB.wrap_links===false){aC=aD.parentNode;do{if(aC.nodeName==="A"){return}}while(aC=aC.parentNode)}Z(aB,al,aD,aB.exact?aD:null)})});if(y(az.parentNode,ae,al)){c.remove(az,1);az=0;return C}if(am.merge_with_parents){c.getParent(az.parentNode,function(aB){if(y(aB,ae,al)){c.remove(az,1);az=0;return C}})}if(az&&am.merge_siblings!==false){az=u(E(az),az);az=u(az,E(az,C))}}})}if(am){if(ag){if(ag.nodeType){ac=c.createRng();ac.setStartBefore(ag);ac.setEndAfter(ag);an(p(ac,ah),null,true)}else{an(ag,null,true)}}else{if(!ai||!am.inline||c.select("td.mceSelected,th.mceSelected").length){var ao=aa.selection.getNode();if(!m&&ah[0].defaultBlock&&!c.getParent(ao,c.isBlock)){Y(ah[0].defaultBlock)}aa.selection.setRng(af());ak=r.getBookmark();an(p(r.getRng(C),ah),ak);if(am.styles&&(am.styles.color||am.styles.textDecoration)){a.walk(ao,L,"childNodes");L(ao)}r.moveToBookmark(ak);R(r.getRng(C));aa.nodeChanged()}else{U("apply",ae,al)}}}}function B(ad,am,af){var ag=V(ad),ao=ag[0],ak,aj,ac,al=true;function ae(av){var au,at,ar,aq,ax,aw;if(av.nodeType===1&&x(av)){ax=al;al=x(av)==="true";aw=true}au=a.grep(av.childNodes);if(al&&!aw){for(at=0,ar=ag.length;at<ar;at++){if(Z(ag[at],am,av,av)){break}}}if(ao.deep){if(au.length){for(at=0,ar=au.length;at<ar;at++){ae(au[at])}if(aw){al=ax}}}}function ah(aq){var ar;T(n(aq.parentNode).reverse(),function(at){var au;if(!ar&&at.id!="_start"&&at.id!="_end"){au=y(at,ad,am);if(au&&au.split!==false){ar=at}}});return ar}function ab(au,aq,aw,az){var aA,ay,ax,at,av,ar;if(au){ar=au.parentNode;for(aA=aq.parentNode;aA&&aA!=ar;aA=aA.parentNode){ay=c.clone(aA,X);for(av=0;av<ag.length;av++){if(Z(ag[av],am,ay,ay)){ay=0;break}}if(ay){if(ax){ay.appendChild(ax)}if(!at){at=ay}ax=ay}}if(az&&(!ao.mixed||!H(au))){aq=c.split(au,aq)}if(ax){aw.parentNode.insertBefore(ax,aw);at.appendChild(aw)}}return aq}function an(aq){return ab(ah(aq),aq,aq,true)}function ai(at){var ar=c.get(at?"_start":"_end"),aq=ar[at?"firstChild":"lastChild"];if(K(aq)){aq=aq[at?"firstChild":"lastChild"]}c.remove(ar,true);return aq}function ap(aq){var at,au,ar;aq=p(aq,ag,C);if(ao.split){at=M(aq,C);au=M(aq);if(at!=au){if(/^(TR|TD)$/.test(at.nodeName)&&at.firstChild){at=(at.nodeName=="TD"?at.firstChild:at.firstChild.firstChild)||at}at=S(at,"span",{id:"_start","data-mce-type":"bookmark"});au=S(au,"span",{id:"_end","data-mce-type":"bookmark"});an(at);an(au);at=ai(C);au=ai()}else{at=au=an(at)}aq.startContainer=at.parentNode;aq.startOffset=s(at);aq.endContainer=au.parentNode;aq.endOffset=s(au)+1}N.walk(aq,function(av){T(av,function(aw){ae(aw);if(aw.nodeType===1&&aa.dom.getStyle(aw,"text-decoration")==="underline"&&aw.parentNode&&i(aw.parentNode)==="underline"){Z({deep:false,exact:true,inline:"span",styles:{textDecoration:"underline"}},null,aw)}})})}if(af){if(af.nodeType){ac=c.createRng();ac.setStartBefore(af);ac.setEndAfter(af);ap(ac)}else{ap(af)}return}if(!r.isCollapsed()||!ao.inline||c.select("td.mceSelected,th.mceSelected").length){ak=r.getBookmark();ap(r.getRng(C));r.moveToBookmark(ak);if(ao.inline&&k(ad,am,r.getStart())){R(r.getRng(true))}aa.nodeChanged()}else{U("remove",ad,am)}}function F(ac,ae,ad){var ab=V(ac);if(k(ac,ae,ad)&&(!("toggle" in ab[0])||ab[0].toggle)){B(ac,ae,ad)}else{Y(ac,ae,ad)}}function y(ac,ab,ah,af){var ad=V(ab),ai,ag,ae;function aj(an,ap,aq){var am,ao,ak=ap[aq],al;if(ap.onmatch){return ap.onmatch(an,ap,aq)}if(ak){if(ak.length===D){for(am in ak){if(ak.hasOwnProperty(am)){if(aq==="attributes"){ao=c.getAttrib(an,am)}else{ao=O(an,am)}if(af&&!ao&&!ap.exact){return}if((!af||ap.exact)&&!g(ao,q(ak[am],ah))){return}}}}else{for(al=0;al<ak.length;al++){if(aq==="attributes"?c.getAttrib(an,ak[al]):O(an,ak[al])){return ap}}}}return ap}if(ad&&ac){for(ag=0;ag<ad.length;ag++){ai=ad[ag];if(h(ac,ai)&&aj(ac,ai,"attributes")&&aj(ac,ai,"styles")){if(ae=ai.classes){for(ag=0;ag<ae.length;ag++){if(!c.hasClass(ac,ae[ag])){return}}}return ai}}}}function k(ad,af,ae){var ac;function ab(ag){ag=c.getParent(ag,function(ah){return !!y(ah,ad,af,true)});return y(ag,ad,af)}if(ae){return ab(ae)}ae=r.getNode();if(ab(ae)){return C}ac=r.getStart();if(ac!=ae){if(ab(ac)){return C}}return X}function v(ai,ah){var af,ag=[],ae={},ad,ac,ab;af=r.getStart();c.getParent(af,function(al){var ak,aj;for(ak=0;ak<ai.length;ak++){aj=ai[ak];if(!ae[aj]&&y(al,aj,ah)){ae[aj]=true;ag.push(aj)}}},c.getRoot());return ag}function z(af){var ah=V(af),ae,ad,ag,ac,ab;if(ah){ae=r.getStart();ad=n(ae);for(ac=ah.length-1;ac>=0;ac--){ab=ah[ac].selector;if(!ab){return C}for(ag=ad.length-1;ag>=0;ag--){if(c.is(ad[ag],ab)){return C}}}}return X}function J(ab,ad){var ac;if(!P){P={};ac={};aa.onNodeChange.addToTop(function(af,ae,ah){var ag=n(ah),ai={};T(P,function(aj,ak){T(ag,function(al){if(y(al,ak,{},true)){if(!ac[ak]){T(aj,function(am){am(true,{node:al,format:ak,parents:ag})});ac[ak]=aj}ai[ak]=aj;return false}})});T(ac,function(aj,ak){if(!ai[ak]){delete ac[ak];T(aj,function(al){al(false,{node:ah,format:ak,parents:ag})})}})})}T(ab.split(","),function(ae){if(!P[ae]){P[ae]=[]}P[ae].push(ad)});return this}a.extend(this,{get:V,register:l,apply:Y,remove:B,toggle:F,match:k,matchAll:v,matchNode:y,canApply:z,formatChanged:J});j();W();function h(ab,ac){if(g(ab,ac.inline)){return C}if(g(ab,ac.block)){return C}if(ac.selector){return c.is(ab,ac.selector)}}function g(ac,ab){ac=ac||"";ab=ab||"";ac=""+(ac.nodeName||ac);ab=""+(ab.nodeName||ab);return ac.toLowerCase()==ab.toLowerCase()}function O(ac,ab){var ad=c.getStyle(ac,ab);if(ab=="color"||ab=="backgroundColor"){ad=c.toHex(ad)}if(ab=="fontWeight"&&ad==700){ad="bold"}return""+ad}function q(ab,ac){if(typeof(ab)!="string"){ab=ab(ac)}else{if(ac){ab=ab.replace(/%(\w+)/g,function(ae,ad){return ac[ad]||ae})}}return ab}function f(ab){return ab&&ab.nodeType===3&&/^([\t \r\n]+|)$/.test(ab.nodeValue)}function S(ad,ac,ab){var ae=c.create(ac,ab);ad.parentNode.insertBefore(ae,ad);ae.appendChild(ad);return ae}function p(ab,am,ae){var ap,an,ah,al,ad=ab.startContainer,ai=ab.startOffset,ar=ab.endContainer,ak=ab.endOffset;function ao(az){var au,ax,ay,aw,av,at;au=ax=az?ad:ar;av=az?"previousSibling":"nextSibling";at=c.getRoot();if(au.nodeType==3&&!f(au)){if(az?ai>0:ak<au.nodeValue.length){return au}}for(;;){if(!am[0].block_expand&&H(ax)){return ax}for(aw=ax[av];aw;aw=aw[av]){if(!K(aw)&&!f(aw)){return ax}}if(ax.parentNode==at){au=ax;break}ax=ax.parentNode}return au}function ag(at,au){if(au===D){au=at.nodeType===3?at.length:at.childNodes.length}while(at&&at.hasChildNodes()){at=at.childNodes[au];if(at){au=at.nodeType===3?at.length:at.childNodes.length}}return{node:at,offset:au}}if(ad.nodeType==1&&ad.hasChildNodes()){an=ad.childNodes.length-1;ad=ad.childNodes[ai>an?an:ai];if(ad.nodeType==3){ai=0}}if(ar.nodeType==1&&ar.hasChildNodes()){an=ar.childNodes.length-1;ar=ar.childNodes[ak>an?an:ak-1];if(ar.nodeType==3){ak=ar.nodeValue.length}}function aq(au){var at=au;while(at){if(at.nodeType===1&&x(at)){return x(at)==="false"?at:au}at=at.parentNode}return au}function aj(au,ay,aA){var ax,av,az,at;function aw(aC,aE){var aF,aB,aD=aC.nodeValue;if(typeof(aE)=="undefined"){aE=aA?aD.length:0}if(aA){aF=aD.lastIndexOf(" ",aE);aB=aD.lastIndexOf("\u00a0",aE);aF=aF>aB?aF:aB;if(aF!==-1&&!ae){aF++}}else{aF=aD.indexOf(" ",aE);aB=aD.indexOf("\u00a0",aE);aF=aF!==-1&&(aB===-1||aF<aB)?aF:aB}return aF}if(au.nodeType===3){az=aw(au,ay);if(az!==-1){return{container:au,offset:az}}at=au}ax=new t(au,c.getParent(au,H)||aa.getBody());while(av=ax[aA?"prev":"next"]()){if(av.nodeType===3){at=av;az=aw(av);if(az!==-1){return{container:av,offset:az}}}else{if(H(av)){break}}}if(at){if(aA){ay=0}else{ay=at.length}return{container:at,offset:ay}}}function af(au,at){var av,aw,ay,ax;if(au.nodeType==3&&au.nodeValue.length===0&&au[at]){au=au[at]}av=n(au);for(aw=0;aw<av.length;aw++){for(ay=0;ay<am.length;ay++){ax=am[ay];if("collapsed" in ax&&ax.collapsed!==ab.collapsed){continue}if(c.is(av[aw],ax.selector)){return av[aw]}}}return au}function ac(au,at,aw){var av;if(!am[0].wrapper){av=c.getParent(au,am[0].block)}if(!av){av=c.getParent(au.nodeType==3?au.parentNode:au,H)}if(av&&am[0].wrapper){av=n(av,"ul,ol").reverse()[0]||av}if(!av){av=au;while(av[at]&&!H(av[at])){av=av[at];if(g(av,"br")){break}}}return av||au}ad=aq(ad);ar=aq(ar);if(K(ad.parentNode)||K(ad)){ad=K(ad)?ad:ad.parentNode;ad=ad.nextSibling||ad;if(ad.nodeType==3){ai=0}}if(K(ar.parentNode)||K(ar)){ar=K(ar)?ar:ar.parentNode;ar=ar.previousSibling||ar;if(ar.nodeType==3){ak=ar.length}}if(am[0].inline){if(ab.collapsed){al=aj(ad,ai,true);if(al){ad=al.container;ai=al.offset}al=aj(ar,ak);if(al){ar=al.container;ak=al.offset}}ah=ag(ar,ak);if(ah.node){while(ah.node&&ah.offset===0&&ah.node.previousSibling){ah=ag(ah.node.previousSibling)}if(ah.node&&ah.offset>0&&ah.node.nodeType===3&&ah.node.nodeValue.charAt(ah.offset-1)===" "){if(ah.offset>1){ar=ah.node;ar.splitText(ah.offset-1)}}}}if(am[0].inline||am[0].block_expand){if(!am[0].inline||(ad.nodeType!=3||ai===0)){ad=ao(true)}if(!am[0].inline||(ar.nodeType!=3||ak===ar.nodeValue.length)){ar=ao()}}if(am[0].selector&&am[0].expand!==X&&!am[0].inline){ad=af(ad,"previousSibling");ar=af(ar,"nextSibling")}if(am[0].block||am[0].selector){ad=ac(ad,"previousSibling");ar=ac(ar,"nextSibling");if(am[0].block){if(!H(ad)){ad=ao(true)}if(!H(ar)){ar=ao()}}}if(ad.nodeType==1){ai=s(ad);ad=ad.parentNode}if(ar.nodeType==1){ak=s(ar)+1;ar=ar.parentNode}return{startContainer:ad,startOffset:ai,endContainer:ar,endOffset:ak}}function Z(ah,ag,ae,ab){var ad,ac,af;if(!h(ae,ah)){return X}if(ah.remove!="all"){T(ah.styles,function(aj,ai){aj=q(aj,ag);if(typeof(ai)==="number"){ai=aj;ab=0}if(!ab||g(O(ab,ai),aj)){c.setStyle(ae,ai,"")}af=1});if(af&&c.getAttrib(ae,"style")==""){ae.removeAttribute("style");ae.removeAttribute("data-mce-style")}T(ah.attributes,function(ak,ai){var aj;ak=q(ak,ag);if(typeof(ai)==="number"){ai=ak;ab=0}if(!ab||g(c.getAttrib(ab,ai),ak)){if(ai=="class"){ak=c.getAttrib(ae,ai);if(ak){aj="";T(ak.split(/\s+/),function(al){if(/mce\w+/.test(al)){aj+=(aj?" ":"")+al}});if(aj){c.setAttrib(ae,ai,aj);return}}}if(ai=="class"){ae.removeAttribute("className")}if(e.test(ai)){ae.removeAttribute("data-mce-"+ai)}ae.removeAttribute(ai)}});T(ah.classes,function(ai){ai=q(ai,ag);if(!ab||c.hasClass(ab,ai)){c.removeClass(ae,ai)}});ac=c.getAttribs(ae);for(ad=0;ad<ac.length;ad++){if(ac[ad].nodeName.indexOf("_")!==0){return X}}}if(ah.remove!="none"){o(ae,ah);return C}}function o(ad,ae){var ab=ad.parentNode,ac;function af(ah,ag,ai){ah=E(ah,ag,ai);return !ah||(ah.nodeName=="BR"||H(ah))}if(ae.block){if(!m){if(H(ad)&&!H(ab)){if(!af(ad,X)&&!af(ad.firstChild,C,1)){ad.insertBefore(c.create("br"),ad.firstChild)}if(!af(ad,C)&&!af(ad.lastChild,X,1)){ad.appendChild(c.create("br"))}}}else{if(ab==c.getRoot()){if(!ae.list_block||!g(ad,ae.list_block)){T(a.grep(ad.childNodes),function(ag){if(d(m,ag.nodeName.toLowerCase())){if(!ac){ac=S(ag,m)}else{ac.appendChild(ag)}}else{ac=0}})}}}}if(ae.selector&&ae.inline&&!g(ae.inline,ad)){return}c.remove(ad,1)}function E(ac,ab,ad){if(ac){ab=ab?"nextSibling":"previousSibling";for(ac=ad?ac:ac[ab];ac;ac=ac[ab]){if(ac.nodeType==1||!f(ac)){return ac}}}}function K(ab){return ab&&ab.nodeType==1&&ab.getAttribute("data-mce-type")=="bookmark"}function u(af,ae){var ab,ad,ac;function ah(ak,aj){if(ak.nodeName!=aj.nodeName){return X}function ai(am){var an={};T(c.getAttribs(am),function(ao){var ap=ao.nodeName.toLowerCase();if(ap.indexOf("_")!==0&&ap!=="style"){an[ap]=c.getAttrib(am,ap)}});return an}function al(ap,ao){var an,am;for(am in ap){if(ap.hasOwnProperty(am)){an=ao[am];if(an===D){return X}if(ap[am]!=an){return X}delete ao[am]}}for(am in ao){if(ao.hasOwnProperty(am)){return X}}return C}if(!al(ai(ak),ai(aj))){return X}if(!al(c.parseStyle(c.getAttrib(ak,"style")),c.parseStyle(c.getAttrib(aj,"style")))){return X}return C}function ag(aj,ai){for(ad=aj;ad;ad=ad[ai]){if(ad.nodeType==3&&ad.nodeValue.length!==0){return aj}if(ad.nodeType==1&&!K(ad)){return ad}}return aj}if(af&&ae){af=ag(af,"previousSibling");ae=ag(ae,"nextSibling");if(ah(af,ae)){for(ad=af.nextSibling;ad&&ad!=ae;){ac=ad;ad=ad.nextSibling;af.appendChild(ac)}c.remove(ae);T(a.grep(ae.childNodes),function(ai){af.appendChild(ai)});return af}}return ae}function I(ab){return/^(h[1-6]|p|div|pre|address|dl|dt|dd)$/.test(ab)}function M(ac,ag){var ab,af,ad,ae;ab=ac[ag?"startContainer":"endContainer"];af=ac[ag?"startOffset":"endOffset"];if(ab.nodeType==1){ad=ab.childNodes.length-1;if(!ag&&af){af--}ab=ab.childNodes[af>ad?ad:af]}if(ab.nodeType===3&&ag&&af>=ab.nodeValue.length){ab=new t(ab,aa.getBody()).next()||ab}if(ab.nodeType===3&&!ag&&af===0){ab=new t(ab,aa.getBody()).prev()||ab}return ab}function U(ak,ab,ai){var al="_mce_caret",ac=aa.settings.caret_debug;function ad(ap){var ao=c.create("span",{id:al,"data-mce-bogus":true,style:ac?"color:red":""});if(ap){ao.appendChild(aa.getDoc().createTextNode(G))}return ao}function aj(ap,ao){while(ap){if((ap.nodeType===3&&ap.nodeValue!==G)||ap.childNodes.length>1){return false}if(ao&&ap.nodeType===1){ao.push(ap)}ap=ap.firstChild}return true}function ag(ao){while(ao){if(ao.id===al){return ao}ao=ao.parentNode}}function af(ao){var ap;if(ao){ap=new t(ao,ao);for(ao=ap.current();ao;ao=ap.next()){if(ao.nodeType===3){return ao}}}}function ae(aq,ap){var ar,ao;if(!aq){aq=ag(r.getStart());if(!aq){while(aq=c.get(al)){ae(aq,false)}}}else{ao=r.getRng(true);if(aj(aq)){if(ap!==false){ao.setStartBefore(aq);ao.setEndBefore(aq)}c.remove(aq)}else{ar=af(aq);if(ar.nodeValue.charAt(0)===G){ar=ar.deleteData(0,1)}c.remove(aq,1)}r.setRng(ao)}}function ah(){var aq,ao,av,au,ar,ap,at;aq=r.getRng(true);au=aq.startOffset;ap=aq.startContainer;at=ap.nodeValue;ao=ag(r.getStart());if(ao){av=af(ao)}if(at&&au>0&&au<at.length&&/\w/.test(at.charAt(au))&&/\w/.test(at.charAt(au-1))){ar=r.getBookmark();aq.collapse(true);aq=p(aq,V(ab));aq=N.split(aq);Y(ab,ai,aq);r.moveToBookmark(ar)}else{if(!ao||av.nodeValue!==G){ao=ad(true);av=ao.firstChild;aq.insertNode(ao);au=1;Y(ab,ai,ao)}else{Y(ab,ai,ao)}r.setCursorLocation(av,au)}}function am(){var ao=r.getRng(true),ap,ar,av,au,aq,ay,ax=[],at,aw;ap=ao.startContainer;ar=ao.startOffset;aq=ap;if(ap.nodeType==3){if(ar!=ap.nodeValue.length||ap.nodeValue===G){au=true}aq=aq.parentNode}while(aq){if(y(aq,ab,ai)){ay=aq;break}if(aq.nextSibling){au=true}ax.push(aq);aq=aq.parentNode}if(!ay){return}if(au){av=r.getBookmark();ao.collapse(true);ao=p(ao,V(ab),true);ao=N.split(ao);B(ab,ai,ao);r.moveToBookmark(av)}else{aw=ad();aq=aw;for(at=ax.length-1;at>=0;at--){aq.appendChild(c.clone(ax[at],false));aq=aq.firstChild}aq.appendChild(c.doc.createTextNode(G));aq=aq.firstChild;c.insertAfter(aw,ay);r.setCursorLocation(aq,1)}}function an(){var ap,ao,aq;ao=ag(r.getStart());if(ao&&!c.isEmpty(ao)){a.walk(ao,function(ar){if(ar.nodeType==1&&ar.id!==al&&!c.isEmpty(ar)){c.setAttrib(ar,"data-mce-bogus",null)}},"childNodes")}}if(!self._hasCaretEvents){aa.onBeforeGetContent.addToTop(function(){var ao=[],ap;if(aj(ag(r.getStart()),ao)){ap=ao.length;while(ap--){c.setAttrib(ao[ap],"data-mce-bogus","1")}}});a.each("onMouseUp onKeyUp".split(" "),function(ao){aa[ao].addToTop(function(){ae();an()})});aa.onKeyDown.addToTop(function(ao,aq){var ap=aq.keyCode;if(ap==8||ap==37||ap==39){ae(ag(r.getStart()))}an()});r.onSetContent.add(an);self._hasCaretEvents=true}if(ak=="apply"){ah()}else{am()}}function R(ac){var ab=ac.startContainer,ai=ac.startOffset,ae,ah,ag,ad,af;if(ab.nodeType==3&&ai>=ab.nodeValue.length){ai=s(ab);ab=ab.parentNode;ae=true}if(ab.nodeType==1){ad=ab.childNodes;ab=ad[Math.min(ai,ad.length-1)];ah=new t(ab,c.getParent(ab,c.isBlock));if(ai>ad.length-1||ae){ah.next()}for(ag=ah.current();ag;ag=ah.next()){if(ag.nodeType==3&&!f(ag)){af=c.create("a",null,G);ag.parentNode.insertBefore(af,ag);ac.setStart(ag,0);r.setRng(ac);c.remove(af);return}}}}}})(tinymce);tinymce.onAddEditor.add(function(e,a){var d,h,g,c=a.settings;function b(j,i){e.each(i,function(l,k){if(l){g.setStyle(j,k,l)}});g.rename(j,"span")}function f(i,j){g=i.dom;if(c.convert_fonts_to_spans){e.each(g.select("font,u,strike",j.node),function(k){d[k.nodeName.toLowerCase()](a.dom,k)})}}if(c.inline_styles){h=e.explode(c.font_size_legacy_values);d={font:function(j,i){b(i,{backgroundColor:i.style.backgroundColor,color:i.color,fontFamily:i.face,fontSize:h[parseInt(i.size,10)-1]})},u:function(j,i){b(i,{textDecoration:"underline"})},strike:function(j,i){b(i,{textDecoration:"line-through"})}};a.onPreProcess.add(f);a.onSetContent.add(f);a.onInit.add(function(){a.selection.onSetContent.add(f)})}});(function(b){var a=b.dom.TreeWalker;b.EnterKey=function(f){var i=f.dom,e=f.selection,d=f.settings,h=f.undoManager,c=f.schema.getNonEmptyElements();function g(A){var v=e.getRng(true),E,j,z,u,p,L,o,k,n,t,I,x,B;function D(M){return M&&i.isBlock(M)&&!/^(TD|TH|CAPTION|FORM)$/.test(M.nodeName)&&!/^(fixed|absolute)/i.test(M.style.position)&&i.getContentEditable(M)!=="true"}function F(N){var M;if(b.isIE&&i.isBlock(N)){M=e.getRng();N.appendChild(i.create("span",null,"\u00a0"));e.select(N);N.lastChild.outerHTML="";e.setRng(M)}}function y(O){var N=O,P=[],M;while(N=N.firstChild){if(i.isBlock(N)){return}if(N.nodeType==1&&!c[N.nodeName.toLowerCase()]){P.push(N)}}M=P.length;while(M--){N=P[M];if(!N.hasChildNodes()||(N.firstChild==N.lastChild&&N.firstChild.nodeValue==="")){i.remove(N)}}}function m(N){var S,Q,M,T,R,P=N,O;M=i.createRng();if(N.hasChildNodes()){S=new a(N,N);while(Q=S.current()){if(Q.nodeType==3){M.setStart(Q,0);M.setEnd(Q,0);break}if(c[Q.nodeName.toLowerCase()]){M.setStartBefore(Q);M.setEndBefore(Q);break}P=Q;Q=S.next()}if(!Q){M.setStart(P,0);M.setEnd(P,0)}}else{if(N.nodeName=="BR"){if(N.nextSibling&&i.isBlock(N.nextSibling)){if(!L||L<9){O=i.create("br");N.parentNode.insertBefore(O,N)}M.setStartBefore(N);M.setEndBefore(N)}else{M.setStartAfter(N);M.setEndAfter(N)}}else{M.setStart(N,0);M.setEnd(N,0)}}e.setRng(M);i.remove(O);R=i.getViewPort(f.getWin());T=i.getPos(N).y;if(T<R.y||T+25>R.y+R.h){f.getWin().scrollTo(0,T<R.y?T:T-R.h+25)}}function r(N){var O=z,Q,P,M;Q=N||t=="TABLE"?i.create(N||x):p.cloneNode(false);M=Q;if(d.keep_styles!==false){do{if(/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(O.nodeName)){P=O.cloneNode(false);i.setAttrib(P,"id","");if(Q.hasChildNodes()){P.appendChild(Q.firstChild);Q.appendChild(P)}else{M=P;Q.appendChild(P)}}}while(O=O.parentNode)}if(!b.isIE){M.innerHTML="<br>"}return Q}function q(P){var O,N,M;if(z.nodeType==3&&(P?u>0:u<z.nodeValue.length)){return false}if(z.parentNode==p&&B&&!P){return true}if(P&&z.nodeType==1&&z==p.firstChild){return true}if(z.nodeName==="TABLE"||(z.previousSibling&&z.previousSibling.nodeName=="TABLE")){return(B&&!P)||(!B&&P)}O=new a(z,p);if(z.nodeType==3){if(P&&u==0){O.prev()}else{if(!P&&u==z.nodeValue.length){O.next()}}}while(N=O.current()){if(N.nodeType===1){if(!N.getAttribute("data-mce-bogus")){M=N.nodeName.toLowerCase();if(c[M]&&M!=="br"){return false}}}else{if(N.nodeType===3&&!/^[ \t\r\n]*$/.test(N.nodeValue)){return false}}if(P){O.prev()}else{O.next()}}return true}function l(M,S){var T,R,O,Q,P,N=x||"P";R=i.getParent(M,i.isBlock);if(!R||!D(R)){R=R||j;if(!R.hasChildNodes()){T=i.create(N);R.appendChild(T);v.setStart(T,0);v.setEnd(T,0);return T}Q=M;while(Q.parentNode!=R){Q=Q.parentNode}while(Q&&!i.isBlock(Q)){O=Q;Q=Q.previousSibling}if(O){T=i.create(N);O.parentNode.insertBefore(T,O);Q=O;while(Q&&!i.isBlock(Q)){P=Q.nextSibling;T.appendChild(Q);Q=P}v.setStart(M,S);v.setEnd(M,S)}}return M}function G(){function M(O){var N=n[O?"firstChild":"lastChild"];while(N){if(N.nodeType==1){break}N=N[O?"nextSibling":"previousSibling"]}return N===p}o=x?r(x):i.create("BR");if(M(true)&&M()){i.replace(o,n)}else{if(M(true)){n.parentNode.insertBefore(o,n)}else{if(M()){i.insertAfter(o,n);F(o)}else{E=v.cloneRange();E.setStartAfter(p);E.setEndAfter(n);k=E.extractContents();i.insertAfter(k,n);i.insertAfter(o,n)}}}i.remove(p);m(o);h.add()}function C(){var N=new a(z,p),M;while(M=N.current()){if(M.nodeName=="BR"){return true}M=N.next()}}function K(){var N,M;if(z&&z.nodeType==3&&u>=z.nodeValue.length){if(!b.isIE&&!C()){N=i.create("br");v.insertNode(N);v.setStartAfter(N);v.setEndAfter(N);M=true}}N=i.create("br");v.insertNode(N);if(b.isIE&&t=="PRE"&&(!L||L<8)){N.parentNode.insertBefore(i.doc.createTextNode("\r"),N)}if(!M){v.setStartAfter(N);v.setEndAfter(N)}else{v.setStartBefore(N);v.setEndBefore(N)}e.setRng(v);h.add()}function s(M){do{if(M.nodeType===3){M.nodeValue=M.nodeValue.replace(/^[\r\n]+/,"")}M=M.firstChild}while(M)}function J(O){var M=i.getRoot(),N,P;N=O;while(N!==M&&i.getContentEditable(N)!=="false"){if(i.getContentEditable(N)==="true"){P=N}N=N.parentNode}return N!==M?P:M}function H(N){var M;if(!b.isIE){N.normalize();M=N.lastChild;if(!M||(/^(left|right)$/gi.test(i.getStyle(M,"float",true)))){i.add(N,"br")}}}if(!v.collapsed){f.execCommand("Delete");return}if(A.isDefaultPrevented()){return}z=v.startContainer;u=v.startOffset;x=d.forced_root_block;x=x?x.toUpperCase():"";L=i.doc.documentMode;if(z.nodeType==1&&z.hasChildNodes()){B=u>z.childNodes.length-1;z=z.childNodes[Math.min(u,z.childNodes.length-1)]||z;if(B&&z.nodeType==3){u=z.nodeValue.length}else{u=0}}j=J(z);if(!j){return}h.beforeChange();if(!i.isBlock(j)&&j!=i.getRoot()){if(!x||A.shiftKey){K()}return}if((x&&!A.shiftKey)||(!x&&A.shiftKey)){z=l(z,u)}p=i.getParent(z,i.isBlock);n=p?i.getParent(p.parentNode,i.isBlock):null;t=p?p.nodeName.toUpperCase():"";I=n?n.nodeName.toUpperCase():"";if(t=="LI"&&i.isEmpty(p)){if(/^(UL|OL|LI)$/.test(n.parentNode.nodeName)){return false}G();return}if(t=="PRE"&&d.br_in_pre!==false){if(!A.shiftKey){K();return}}else{if((!x&&!A.shiftKey&&t!="LI")||(x&&A.shiftKey)){K();return}}x=x||"P";if(q()){if(/^(H[1-6]|PRE)$/.test(t)&&I!="HGROUP"){o=r(x)}else{o=r()}if(d.end_container_on_empty_block&&D(n)&&i.isEmpty(p)){o=i.split(n,p)}else{i.insertAfter(o,p)}m(o)}else{if(q(true)){o=p.parentNode.insertBefore(r(),p);F(o)}else{E=v.cloneRange();E.setEndAfter(p);k=E.extractContents();s(k);o=k.firstChild;i.insertAfter(k,p);y(o);H(p);m(o)}}i.setAttrib(o,"id","");h.add()}f.onKeyDown.add(function(k,j){if(j.keyCode==13){if(g(j)!==false){j.preventDefault()}}})}})(tinymce); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/tiny_mce_popup.js b/askbot/media/js/tinymce/tiny_mce_popup.js
new file mode 100644
index 00000000..bb8e58c8
--- /dev/null
+++ b/askbot/media/js/tinymce/tiny_mce_popup.js
@@ -0,0 +1,5 @@
+
+// Uncomment and change this document.domain value if you are loading the script cross subdomains
+// document.domain = 'moxiecode.com';
+
+var tinymce=null,tinyMCEPopup,tinyMCE;tinyMCEPopup={init:function(){var b=this,a,c;a=b.getWin();tinymce=a.tinymce;tinyMCE=a.tinyMCE;b.editor=tinymce.EditorManager.activeEditor;b.params=b.editor.windowManager.params;b.features=b.editor.windowManager.features;b.dom=b.editor.windowManager.createInstance("tinymce.dom.DOMUtils",document,{ownEvents:true,proxy:tinyMCEPopup._eventProxy});b.dom.bind(window,"ready",b._onDOMLoaded,b);if(b.features.popup_css!==false){b.dom.loadCSS(b.features.popup_css||b.editor.settings.popup_css)}b.listeners=[];b.onInit={add:function(e,d){b.listeners.push({func:e,scope:d})}};b.isWindow=!b.getWindowArg("mce_inline");b.id=b.getWindowArg("mce_window_id");b.editor.windowManager.onOpen.dispatch(b.editor.windowManager,window)},getWin:function(){return(!window.frameElement&&window.dialogArguments)||opener||parent||top},getWindowArg:function(c,b){var a=this.params[c];return tinymce.is(a)?a:b},getParam:function(b,a){return this.editor.getParam(b,a)},getLang:function(b,a){return this.editor.getLang(b,a)},execCommand:function(d,c,e,b){b=b||{};b.skip_focus=1;this.restoreSelection();return this.editor.execCommand(d,c,e,b)},resizeToInnerSize:function(){var a=this;setTimeout(function(){var b=a.dom.getViewPort(window);a.editor.windowManager.resizeBy(a.getWindowArg("mce_width")-b.w,a.getWindowArg("mce_height")-b.h,a.id||window)},10)},executeOnLoad:function(s){this.onInit.add(function(){eval(s)})},storeSelection:function(){this.editor.windowManager.bookmark=tinyMCEPopup.editor.selection.getBookmark(1)},restoreSelection:function(){var a=tinyMCEPopup;if(!a.isWindow&&tinymce.isIE){a.editor.selection.moveToBookmark(a.editor.windowManager.bookmark)}},requireLangPack:function(){var b=this,a=b.getWindowArg("plugin_url")||b.getWindowArg("theme_url");if(a&&b.editor.settings.language&&b.features.translate_i18n!==false&&b.editor.settings.language_load!==false){a+="/langs/"+b.editor.settings.language+"_dlg.js";if(!tinymce.ScriptLoader.isDone(a)){document.write('<script type="text/javascript" src="'+tinymce._addVer(a)+'"><\/script>');tinymce.ScriptLoader.markDone(a)}}},pickColor:function(b,a){this.execCommand("mceColorPicker",true,{color:document.getElementById(a).value,func:function(e){document.getElementById(a).value=e;try{document.getElementById(a).onchange()}catch(d){}}})},openBrowser:function(a,c,b){tinyMCEPopup.restoreSelection();this.editor.execCallback("file_browser_callback",a,document.getElementById(a).value,c,window)},confirm:function(b,a,c){this.editor.windowManager.confirm(b,a,c,window)},alert:function(b,a,c){this.editor.windowManager.alert(b,a,c,window)},close:function(){var a=this;function b(){a.editor.windowManager.close(window);tinymce=tinyMCE=a.editor=a.params=a.dom=a.dom.doc=null}if(tinymce.isOpera){a.getWin().setTimeout(b,0)}else{b()}},_restoreSelection:function(){var a=window.event.srcElement;if(a.nodeName=="INPUT"&&(a.type=="submit"||a.type=="button")){tinyMCEPopup.restoreSelection()}},_onDOMLoaded:function(){var b=tinyMCEPopup,d=document.title,e,c,a;if(b.features.translate_i18n!==false){c=document.body.innerHTML;if(tinymce.isIE){c=c.replace(/ (value|title|alt)=([^"][^\s>]+)/gi,' $1="$2"')}document.dir=b.editor.getParam("directionality","");if((a=b.editor.translate(c))&&a!=c){document.body.innerHTML=a}if((a=b.editor.translate(d))&&a!=d){document.title=d=a}}if(!b.editor.getParam("browser_preferred_colors",false)||!b.isWindow){b.dom.addClass(document.body,"forceColors")}document.body.style.display="";if(tinymce.isIE){document.attachEvent("onmouseup",tinyMCEPopup._restoreSelection);b.dom.add(b.dom.select("head")[0],"base",{target:"_self"})}b.restoreSelection();b.resizeToInnerSize();if(!b.isWindow){b.editor.windowManager.setTitle(window,d)}else{window.focus()}if(!tinymce.isIE&&!b.isWindow){b.dom.bind(document,"focus",function(){b.editor.windowManager.focus(b.id)})}tinymce.each(b.dom.select("select"),function(f){f.onkeydown=tinyMCEPopup._accessHandler});tinymce.each(b.listeners,function(f){f.func.call(f.scope,b.editor)});if(b.getWindowArg("mce_auto_focus",true)){window.focus();tinymce.each(document.forms,function(g){tinymce.each(g.elements,function(f){if(b.dom.hasClass(f,"mceFocus")&&!f.disabled){f.focus();return false}})})}document.onkeyup=tinyMCEPopup._closeWinKeyHandler},_accessHandler:function(a){a=a||window.event;if(a.keyCode==13||a.keyCode==32){var b=a.target||a.srcElement;if(b.onchange){b.onchange()}return tinymce.dom.Event.cancel(a)}},_closeWinKeyHandler:function(a){a=a||window.event;if(a.keyCode==27){tinyMCEPopup.close()}},_eventProxy:function(a){return function(b){tinyMCEPopup.dom.events.callNativeHandler(a,b)}}};tinyMCEPopup.init(); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/tiny_mce_src.js b/askbot/media/js/tinymce/tiny_mce_src.js
new file mode 100644
index 00000000..23bbe34a
--- /dev/null
+++ b/askbot/media/js/tinymce/tiny_mce_src.js
@@ -0,0 +1,18576 @@
+// FILE IS GENERATED BY COMBINING THE SOURCES IN THE "classes" DIRECTORY SO DON'T MODIFY THIS FILE DIRECTLY
+(function(win) {
+ var whiteSpaceRe = /^\s*|\s*$/g,
+ undef, isRegExpBroken = 'B'.replace(/A(.)|B/, '$1') === '$1';
+
+ var tinymce = {
+ majorVersion : '3',
+
+ minorVersion : '5.3',
+
+ releaseDate : '2012-06-19',
+
+ _init : function() {
+ var t = this, d = document, na = navigator, ua = na.userAgent, i, nl, n, base, p, v;
+
+ t.isOpera = win.opera && opera.buildNumber;
+
+ t.isWebKit = /WebKit/.test(ua);
+
+ t.isIE = !t.isWebKit && !t.isOpera && (/MSIE/gi).test(ua) && (/Explorer/gi).test(na.appName);
+
+ t.isIE6 = t.isIE && /MSIE [56]/.test(ua);
+
+ t.isIE7 = t.isIE && /MSIE [7]/.test(ua);
+
+ t.isIE8 = t.isIE && /MSIE [8]/.test(ua);
+
+ t.isIE9 = t.isIE && /MSIE [9]/.test(ua);
+
+ t.isGecko = !t.isWebKit && /Gecko/.test(ua);
+
+ t.isMac = ua.indexOf('Mac') != -1;
+
+ t.isAir = /adobeair/i.test(ua);
+
+ t.isIDevice = /(iPad|iPhone)/.test(ua);
+
+ t.isIOS5 = t.isIDevice && ua.match(/AppleWebKit\/(\d*)/)[1]>=534;
+
+ // TinyMCE .NET webcontrol might be setting the values for TinyMCE
+ if (win.tinyMCEPreInit) {
+ t.suffix = tinyMCEPreInit.suffix;
+ t.baseURL = tinyMCEPreInit.base;
+ t.query = tinyMCEPreInit.query;
+ return;
+ }
+
+ // Get suffix and base
+ t.suffix = '';
+
+ // If base element found, add that infront of baseURL
+ nl = d.getElementsByTagName('base');
+ for (i=0; i<nl.length; i++) {
+ v = nl[i].href;
+ if (v) {
+ // Host only value like http://site.com or http://site.com:8008
+ if (/^https?:\/\/[^\/]+$/.test(v))
+ v += '/';
+
+ base = v ? v.match(/.*\//)[0] : ''; // Get only directory
+ }
+ }
+
+ function getBase(n) {
+ if (n.src && /tiny_mce(|_gzip|_jquery|_prototype|_full)(_dev|_src)?.js/.test(n.src)) {
+ if (/_(src|dev)\.js/g.test(n.src))
+ t.suffix = '_src';
+
+ if ((p = n.src.indexOf('?')) != -1)
+ t.query = n.src.substring(p + 1);
+
+ t.baseURL = n.src.substring(0, n.src.lastIndexOf('/'));
+
+ // If path to script is relative and a base href was found add that one infront
+ // the src property will always be an absolute one on non IE browsers and IE 8
+ // so this logic will basically only be executed on older IE versions
+ if (base && t.baseURL.indexOf('://') == -1 && t.baseURL.indexOf('/') !== 0)
+ t.baseURL = base + t.baseURL;
+
+ return t.baseURL;
+ }
+
+ return null;
+ };
+
+ // Check document
+ nl = d.getElementsByTagName('script');
+ for (i=0; i<nl.length; i++) {
+ if (getBase(nl[i]))
+ return;
+ }
+
+ // Check head
+ n = d.getElementsByTagName('head')[0];
+ if (n) {
+ nl = n.getElementsByTagName('script');
+ for (i=0; i<nl.length; i++) {
+ if (getBase(nl[i]))
+ return;
+ }
+ }
+
+ return;
+ },
+
+ is : function(o, t) {
+ if (!t)
+ return o !== undef;
+
+ if (t == 'array' && (o.hasOwnProperty && o instanceof Array))
+ return true;
+
+ return typeof(o) == t;
+ },
+
+ makeMap : function(items, delim, map) {
+ var i;
+
+ items = items || [];
+ delim = delim || ',';
+
+ if (typeof(items) == "string")
+ items = items.split(delim);
+
+ map = map || {};
+
+ i = items.length;
+ while (i--)
+ map[items[i]] = {};
+
+ return map;
+ },
+
+ each : function(o, cb, s) {
+ var n, l;
+
+ if (!o)
+ return 0;
+
+ s = s || o;
+
+ if (o.length !== undef) {
+ // Indexed arrays, needed for Safari
+ for (n=0, l = o.length; n < l; n++) {
+ if (cb.call(s, o[n], n, o) === false)
+ return 0;
+ }
+ } else {
+ // Hashtables
+ for (n in o) {
+ if (o.hasOwnProperty(n)) {
+ if (cb.call(s, o[n], n, o) === false)
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+ },
+
+
+ map : function(a, f) {
+ var o = [];
+
+ tinymce.each(a, function(v) {
+ o.push(f(v));
+ });
+
+ return o;
+ },
+
+ grep : function(a, f) {
+ var o = [];
+
+ tinymce.each(a, function(v) {
+ if (!f || f(v))
+ o.push(v);
+ });
+
+ return o;
+ },
+
+ inArray : function(a, v) {
+ var i, l;
+
+ if (a) {
+ for (i = 0, l = a.length; i < l; i++) {
+ if (a[i] === v)
+ return i;
+ }
+ }
+
+ return -1;
+ },
+
+ extend : function(obj, ext) {
+ var i, l, name, args = arguments, value;
+
+ for (i = 1, l = args.length; i < l; i++) {
+ ext = args[i];
+ for (name in ext) {
+ if (ext.hasOwnProperty(name)) {
+ value = ext[name];
+
+ if (value !== undef) {
+ obj[name] = value;
+ }
+ }
+ }
+ }
+
+ return obj;
+ },
+
+
+ trim : function(s) {
+ return (s ? '' + s : '').replace(whiteSpaceRe, '');
+ },
+
+ create : function(s, p, root) {
+ var t = this, sp, ns, cn, scn, c, de = 0;
+
+ // Parse : <prefix> <class>:<super class>
+ s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s);
+ cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name
+
+ // Create namespace for new class
+ ns = t.createNS(s[3].replace(/\.\w+$/, ''), root);
+
+ // Class already exists
+ if (ns[cn])
+ return;
+
+ // Make pure static class
+ if (s[2] == 'static') {
+ ns[cn] = p;
+
+ if (this.onCreate)
+ this.onCreate(s[2], s[3], ns[cn]);
+
+ return;
+ }
+
+ // Create default constructor
+ if (!p[cn]) {
+ p[cn] = function() {};
+ de = 1;
+ }
+
+ // Add constructor and methods
+ ns[cn] = p[cn];
+ t.extend(ns[cn].prototype, p);
+
+ // Extend
+ if (s[5]) {
+ sp = t.resolve(s[5]).prototype;
+ scn = s[5].match(/\.(\w+)$/i)[1]; // Class name
+
+ // Extend constructor
+ c = ns[cn];
+ if (de) {
+ // Add passthrough constructor
+ ns[cn] = function() {
+ return sp[scn].apply(this, arguments);
+ };
+ } else {
+ // Add inherit constructor
+ ns[cn] = function() {
+ this.parent = sp[scn];
+ return c.apply(this, arguments);
+ };
+ }
+ ns[cn].prototype[cn] = ns[cn];
+
+ // Add super methods
+ t.each(sp, function(f, n) {
+ ns[cn].prototype[n] = sp[n];
+ });
+
+ // Add overridden methods
+ t.each(p, function(f, n) {
+ // Extend methods if needed
+ if (sp[n]) {
+ ns[cn].prototype[n] = function() {
+ this.parent = sp[n];
+ return f.apply(this, arguments);
+ };
+ } else {
+ if (n != cn)
+ ns[cn].prototype[n] = f;
+ }
+ });
+ }
+
+ // Add static methods
+ t.each(p['static'], function(f, n) {
+ ns[cn][n] = f;
+ });
+
+ if (this.onCreate)
+ this.onCreate(s[2], s[3], ns[cn].prototype);
+ },
+
+ walk : function(o, f, n, s) {
+ s = s || this;
+
+ if (o) {
+ if (n)
+ o = o[n];
+
+ tinymce.each(o, function(o, i) {
+ if (f.call(s, o, i, n) === false)
+ return false;
+
+ tinymce.walk(o, f, n, s);
+ });
+ }
+ },
+
+ createNS : function(n, o) {
+ var i, v;
+
+ o = o || win;
+
+ n = n.split('.');
+ for (i=0; i<n.length; i++) {
+ v = n[i];
+
+ if (!o[v])
+ o[v] = {};
+
+ o = o[v];
+ }
+
+ return o;
+ },
+
+ resolve : function(n, o) {
+ var i, l;
+
+ o = o || win;
+
+ n = n.split('.');
+ for (i = 0, l = n.length; i < l; i++) {
+ o = o[n[i]];
+
+ if (!o)
+ break;
+ }
+
+ return o;
+ },
+
+ addUnload : function(f, s) {
+ var t = this, unload;
+
+ unload = function() {
+ var li = t.unloads, o, n;
+
+ if (li) {
+ // Call unload handlers
+ for (n in li) {
+ o = li[n];
+
+ if (o && o.func)
+ o.func.call(o.scope, 1); // Send in one arg to distinct unload and user destroy
+ }
+
+ // Detach unload function
+ if (win.detachEvent) {
+ win.detachEvent('onbeforeunload', fakeUnload);
+ win.detachEvent('onunload', unload);
+ } else if (win.removeEventListener)
+ win.removeEventListener('unload', unload, false);
+
+ // Destroy references
+ t.unloads = o = li = w = unload = 0;
+
+ // Run garbarge collector on IE
+ if (win.CollectGarbage)
+ CollectGarbage();
+ }
+ };
+
+ function fakeUnload() {
+ var d = document;
+
+ function stop() {
+ // Prevent memory leak
+ d.detachEvent('onstop', stop);
+
+ // Call unload handler
+ if (unload)
+ unload();
+
+ d = 0;
+ };
+
+ // Is there things still loading, then do some magic
+ if (d.readyState == 'interactive') {
+ // Fire unload when the currently loading page is stopped
+ if (d)
+ d.attachEvent('onstop', stop);
+
+ // Remove onstop listener after a while to prevent the unload function
+ // to execute if the user presses cancel in an onbeforeunload
+ // confirm dialog and then presses the browser stop button
+ win.setTimeout(function() {
+ if (d)
+ d.detachEvent('onstop', stop);
+ }, 0);
+ }
+ };
+
+ f = {func : f, scope : s || this};
+
+ if (!t.unloads) {
+ // Attach unload handler
+ if (win.attachEvent) {
+ win.attachEvent('onunload', unload);
+ win.attachEvent('onbeforeunload', fakeUnload);
+ } else if (win.addEventListener)
+ win.addEventListener('unload', unload, false);
+
+ // Setup initial unload handler array
+ t.unloads = [f];
+ } else
+ t.unloads.push(f);
+
+ return f;
+ },
+
+ removeUnload : function(f) {
+ var u = this.unloads, r = null;
+
+ tinymce.each(u, function(o, i) {
+ if (o && o.func == f) {
+ u.splice(i, 1);
+ r = f;
+ return false;
+ }
+ });
+
+ return r;
+ },
+
+ explode : function(s, d) {
+ if (!s || tinymce.is(s, 'array')) {
+ return s;
+ }
+
+ return tinymce.map(s.split(d || ','), tinymce.trim);
+ },
+
+ _addVer : function(u) {
+ var v;
+
+ if (!this.query)
+ return u;
+
+ v = (u.indexOf('?') == -1 ? '?' : '&') + this.query;
+
+ if (u.indexOf('#') == -1)
+ return u + v;
+
+ return u.replace('#', v + '#');
+ },
+
+ // Fix function for IE 9 where regexps isn't working correctly
+ // Todo: remove me once MS fixes the bug
+ _replace : function(find, replace, str) {
+ // On IE9 we have to fake $x replacement
+ if (isRegExpBroken) {
+ return str.replace(find, function() {
+ var val = replace, args = arguments, i;
+
+ for (i = 0; i < args.length - 2; i++) {
+ if (args[i] === undef) {
+ val = val.replace(new RegExp('\\$' + i, 'g'), '');
+ } else {
+ val = val.replace(new RegExp('\\$' + i, 'g'), args[i]);
+ }
+ }
+
+ return val;
+ });
+ }
+
+ return str.replace(find, replace);
+ }
+
+ };
+
+ // Initialize the API
+ tinymce._init();
+
+ // Expose tinymce namespace to the global namespace (window)
+ win.tinymce = win.tinyMCE = tinymce;
+
+ // Describe the different namespaces
+
+ })(window);
+
+
+
+tinymce.create('tinymce.util.Dispatcher', {
+ scope : null,
+ listeners : null,
+ inDispatch: false,
+
+ Dispatcher : function(scope) {
+ this.scope = scope || this;
+ this.listeners = [];
+ },
+
+ add : function(callback, scope) {
+ this.listeners.push({cb : callback, scope : scope || this.scope});
+
+ return callback;
+ },
+
+ addToTop : function(callback, scope) {
+ var self = this, listener = {cb : callback, scope : scope || self.scope};
+
+ // Create new listeners if addToTop is executed in a dispatch loop
+ if (self.inDispatch) {
+ self.listeners = [listener].concat(self.listeners);
+ } else {
+ self.listeners.unshift(listener);
+ }
+
+ return callback;
+ },
+
+ remove : function(callback) {
+ var listeners = this.listeners, output = null;
+
+ tinymce.each(listeners, function(listener, i) {
+ if (callback == listener.cb) {
+ output = listener;
+ listeners.splice(i, 1);
+ return false;
+ }
+ });
+
+ return output;
+ },
+
+ dispatch : function() {
+ var self = this, returnValue, args = arguments, i, listeners = self.listeners, listener;
+
+ self.inDispatch = true;
+
+ // Needs to be a real loop since the listener count might change while looping
+ // And this is also more efficient
+ for (i = 0; i < listeners.length; i++) {
+ listener = listeners[i];
+ returnValue = listener.cb.apply(listener.scope, args.length > 0 ? args : [listener.scope]);
+
+ if (returnValue === false)
+ break;
+ }
+
+ self.inDispatch = false;
+
+ return returnValue;
+ }
+
+ });
+
+(function() {
+ var each = tinymce.each;
+
+ tinymce.create('tinymce.util.URI', {
+ URI : function(u, s) {
+ var t = this, o, a, b, base_url;
+
+ // Trim whitespace
+ u = tinymce.trim(u);
+
+ // Default settings
+ s = t.settings = s || {};
+
+ // Strange app protocol that isn't http/https or local anchor
+ // For example: mailto,skype,tel etc.
+ if (/^([\w\-]+):([^\/]{2})/i.test(u) || /^\s*#/.test(u)) {
+ t.source = u;
+ return;
+ }
+
+ // Absolute path with no host, fake host and protocol
+ if (u.indexOf('/') === 0 && u.indexOf('//') !== 0)
+ u = (s.base_uri ? s.base_uri.protocol || 'http' : 'http') + '://mce_host' + u;
+
+ // Relative path http:// or protocol relative //path
+ if (!/^[\w\-]*:?\/\//.test(u)) {
+ base_url = s.base_uri ? s.base_uri.path : new tinymce.util.URI(location.href).directory;
+ u = ((s.base_uri && s.base_uri.protocol) || 'http') + '://mce_host' + t.toAbsPath(base_url, u);
+ }
+
+ // Parse URL (Credits goes to Steave, http://blog.stevenlevithan.com/archives/parseuri)
+ u = u.replace(/@@/g, '(mce_at)'); // Zope 3 workaround, they use @@something
+ u = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(u);
+ each(["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], function(v, i) {
+ var s = u[i];
+
+ // Zope 3 workaround, they use @@something
+ if (s)
+ s = s.replace(/\(mce_at\)/g, '@@');
+
+ t[v] = s;
+ });
+
+ b = s.base_uri;
+ if (b) {
+ if (!t.protocol)
+ t.protocol = b.protocol;
+
+ if (!t.userInfo)
+ t.userInfo = b.userInfo;
+
+ if (!t.port && t.host === 'mce_host')
+ t.port = b.port;
+
+ if (!t.host || t.host === 'mce_host')
+ t.host = b.host;
+
+ t.source = '';
+ }
+
+ //t.path = t.path || '/';
+ },
+
+ setPath : function(p) {
+ var t = this;
+
+ p = /^(.*?)\/?(\w+)?$/.exec(p);
+
+ // Update path parts
+ t.path = p[0];
+ t.directory = p[1];
+ t.file = p[2];
+
+ // Rebuild source
+ t.source = '';
+ t.getURI();
+ },
+
+ toRelative : function(u) {
+ var t = this, o;
+
+ if (u === "./")
+ return u;
+
+ u = new tinymce.util.URI(u, {base_uri : t});
+
+ // Not on same domain/port or protocol
+ if ((u.host != 'mce_host' && t.host != u.host && u.host) || t.port != u.port || t.protocol != u.protocol)
+ return u.getURI();
+
+ var tu = t.getURI(), uu = u.getURI();
+
+ // Allow usage of the base_uri when relative_urls = true
+ if(tu == uu || (tu.charAt(tu.length - 1) == "/" && tu.substr(0, tu.length - 1) == uu))
+ return tu;
+
+ o = t.toRelPath(t.path, u.path);
+
+ // Add query
+ if (u.query)
+ o += '?' + u.query;
+
+ // Add anchor
+ if (u.anchor)
+ o += '#' + u.anchor;
+
+ return o;
+ },
+
+ toAbsolute : function(u, nh) {
+ u = new tinymce.util.URI(u, {base_uri : this});
+
+ return u.getURI(this.host == u.host && this.protocol == u.protocol ? nh : 0);
+ },
+
+ toRelPath : function(base, path) {
+ var items, bp = 0, out = '', i, l;
+
+ // Split the paths
+ base = base.substring(0, base.lastIndexOf('/'));
+ base = base.split('/');
+ items = path.split('/');
+
+ if (base.length >= items.length) {
+ for (i = 0, l = base.length; i < l; i++) {
+ if (i >= items.length || base[i] != items[i]) {
+ bp = i + 1;
+ break;
+ }
+ }
+ }
+
+ if (base.length < items.length) {
+ for (i = 0, l = items.length; i < l; i++) {
+ if (i >= base.length || base[i] != items[i]) {
+ bp = i + 1;
+ break;
+ }
+ }
+ }
+
+ if (bp === 1)
+ return path;
+
+ for (i = 0, l = base.length - (bp - 1); i < l; i++)
+ out += "../";
+
+ for (i = bp - 1, l = items.length; i < l; i++) {
+ if (i != bp - 1)
+ out += "/" + items[i];
+ else
+ out += items[i];
+ }
+
+ return out;
+ },
+
+ toAbsPath : function(base, path) {
+ var i, nb = 0, o = [], tr, outPath;
+
+ // Split paths
+ tr = /\/$/.test(path) ? '/' : '';
+ base = base.split('/');
+ path = path.split('/');
+
+ // Remove empty chunks
+ each(base, function(k) {
+ if (k)
+ o.push(k);
+ });
+
+ base = o;
+
+ // Merge relURLParts chunks
+ for (i = path.length - 1, o = []; i >= 0; i--) {
+ // Ignore empty or .
+ if (path[i].length === 0 || path[i] === ".")
+ continue;
+
+ // Is parent
+ if (path[i] === '..') {
+ nb++;
+ continue;
+ }
+
+ // Move up
+ if (nb > 0) {
+ nb--;
+ continue;
+ }
+
+ o.push(path[i]);
+ }
+
+ i = base.length - nb;
+
+ // If /a/b/c or /
+ if (i <= 0)
+ outPath = o.reverse().join('/');
+ else
+ outPath = base.slice(0, i).join('/') + '/' + o.reverse().join('/');
+
+ // Add front / if it's needed
+ if (outPath.indexOf('/') !== 0)
+ outPath = '/' + outPath;
+
+ // Add traling / if it's needed
+ if (tr && outPath.lastIndexOf('/') !== outPath.length - 1)
+ outPath += tr;
+
+ return outPath;
+ },
+
+ getURI : function(nh) {
+ var s, t = this;
+
+ // Rebuild source
+ if (!t.source || nh) {
+ s = '';
+
+ if (!nh) {
+ if (t.protocol)
+ s += t.protocol + '://';
+
+ if (t.userInfo)
+ s += t.userInfo + '@';
+
+ if (t.host)
+ s += t.host;
+
+ if (t.port)
+ s += ':' + t.port;
+ }
+
+ if (t.path)
+ s += t.path;
+
+ if (t.query)
+ s += '?' + t.query;
+
+ if (t.anchor)
+ s += '#' + t.anchor;
+
+ t.source = s;
+ }
+
+ return t.source;
+ }
+ });
+})();
+
+(function() {
+ var each = tinymce.each;
+
+ tinymce.create('static tinymce.util.Cookie', {
+ getHash : function(n) {
+ var v = this.get(n), h;
+
+ if (v) {
+ each(v.split('&'), function(v) {
+ v = v.split('=');
+ h = h || {};
+ h[unescape(v[0])] = unescape(v[1]);
+ });
+ }
+
+ return h;
+ },
+
+ setHash : function(n, v, e, p, d, s) {
+ var o = '';
+
+ each(v, function(v, k) {
+ o += (!o ? '' : '&') + escape(k) + '=' + escape(v);
+ });
+
+ this.set(n, o, e, p, d, s);
+ },
+
+ get : function(n) {
+ var c = document.cookie, e, p = n + "=", b;
+
+ // Strict mode
+ if (!c)
+ return;
+
+ b = c.indexOf("; " + p);
+
+ if (b == -1) {
+ b = c.indexOf(p);
+
+ if (b !== 0)
+ return null;
+ } else
+ b += 2;
+
+ e = c.indexOf(";", b);
+
+ if (e == -1)
+ e = c.length;
+
+ return unescape(c.substring(b + p.length, e));
+ },
+
+ set : function(n, v, e, p, d, s) {
+ document.cookie = n + "=" + escape(v) +
+ ((e) ? "; expires=" + e.toGMTString() : "") +
+ ((p) ? "; path=" + escape(p) : "") +
+ ((d) ? "; domain=" + d : "") +
+ ((s) ? "; secure" : "");
+ },
+
+ remove : function(name, path, domain) {
+ var date = new Date();
+
+ date.setTime(date.getTime() - 1000);
+
+ this.set(name, '', date, path, domain);
+ }
+ });
+})();
+
+(function() {
+ function serialize(o, quote) {
+ var i, v, t, name;
+
+ quote = quote || '"';
+
+ if (o == null)
+ return 'null';
+
+ t = typeof o;
+
+ if (t == 'string') {
+ v = '\bb\tt\nn\ff\rr\""\'\'\\\\';
+
+ return quote + o.replace(/([\u0080-\uFFFF\x00-\x1f\"\'\\])/g, function(a, b) {
+ // Make sure single quotes never get encoded inside double quotes for JSON compatibility
+ if (quote === '"' && a === "'")
+ return a;
+
+ i = v.indexOf(b);
+
+ if (i + 1)
+ return '\\' + v.charAt(i + 1);
+
+ a = b.charCodeAt().toString(16);
+
+ return '\\u' + '0000'.substring(a.length) + a;
+ }) + quote;
+ }
+
+ if (t == 'object') {
+ if (o.hasOwnProperty && o instanceof Array) {
+ for (i=0, v = '['; i<o.length; i++)
+ v += (i > 0 ? ',' : '') + serialize(o[i], quote);
+
+ return v + ']';
+ }
+
+ v = '{';
+
+ for (name in o) {
+ if (o.hasOwnProperty(name)) {
+ v += typeof o[name] != 'function' ? (v.length > 1 ? ',' + quote : quote) + name + quote +':' + serialize(o[name], quote) : '';
+ }
+ }
+
+ return v + '}';
+ }
+
+ return '' + o;
+ };
+
+ tinymce.util.JSON = {
+ serialize: serialize,
+
+ parse: function(s) {
+ try {
+ return eval('(' + s + ')');
+ } catch (ex) {
+ // Ignore
+ }
+ }
+
+ };
+})();
+
+tinymce.create('static tinymce.util.XHR', {
+ send : function(o) {
+ var x, t, w = window, c = 0;
+
+ function ready() {
+ if (!o.async || x.readyState == 4 || c++ > 10000) {
+ if (o.success && c < 10000 && x.status == 200)
+ o.success.call(o.success_scope, '' + x.responseText, x, o);
+ else if (o.error)
+ o.error.call(o.error_scope, c > 10000 ? 'TIMED_OUT' : 'GENERAL', x, o);
+
+ x = null;
+ } else
+ w.setTimeout(ready, 10);
+ };
+
+ // Default settings
+ o.scope = o.scope || this;
+ o.success_scope = o.success_scope || o.scope;
+ o.error_scope = o.error_scope || o.scope;
+ o.async = o.async === false ? false : true;
+ o.data = o.data || '';
+
+ function get(s) {
+ x = 0;
+
+ try {
+ x = new ActiveXObject(s);
+ } catch (ex) {
+ }
+
+ return x;
+ };
+
+ x = w.XMLHttpRequest ? new XMLHttpRequest() : get('Microsoft.XMLHTTP') || get('Msxml2.XMLHTTP');
+
+ if (x) {
+ if (x.overrideMimeType)
+ x.overrideMimeType(o.content_type);
+
+ x.open(o.type || (o.data ? 'POST' : 'GET'), o.url, o.async);
+
+ if (o.content_type)
+ x.setRequestHeader('Content-Type', o.content_type);
+
+ x.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+
+ x.send(o.data);
+
+ // Syncronous request
+ if (!o.async)
+ return ready();
+
+ // Wait for response, onReadyStateChange can not be used since it leaks memory in IE
+ t = w.setTimeout(ready, 10);
+ }
+ }
+});
+
+(function() {
+ var extend = tinymce.extend, JSON = tinymce.util.JSON, XHR = tinymce.util.XHR;
+
+ tinymce.create('tinymce.util.JSONRequest', {
+ JSONRequest : function(s) {
+ this.settings = extend({
+ }, s);
+ this.count = 0;
+ },
+
+ send : function(o) {
+ var ecb = o.error, scb = o.success;
+
+ o = extend(this.settings, o);
+
+ o.success = function(c, x) {
+ c = JSON.parse(c);
+
+ if (typeof(c) == 'undefined') {
+ c = {
+ error : 'JSON Parse error.'
+ };
+ }
+
+ if (c.error)
+ ecb.call(o.error_scope || o.scope, c.error, x);
+ else
+ scb.call(o.success_scope || o.scope, c.result);
+ };
+
+ o.error = function(ty, x) {
+ if (ecb)
+ ecb.call(o.error_scope || o.scope, ty, x);
+ };
+
+ o.data = JSON.serialize({
+ id : o.id || 'c' + (this.count++),
+ method : o.method,
+ params : o.params
+ });
+
+ // JSON content type for Ruby on rails. Bug: #1883287
+ o.content_type = 'application/json';
+
+ XHR.send(o);
+ },
+
+ 'static' : {
+ sendRPC : function(o) {
+ return new tinymce.util.JSONRequest().send(o);
+ }
+ }
+ });
+}());
+(function(tinymce){
+ tinymce.VK = {
+ BACKSPACE: 8,
+ DELETE: 46,
+ DOWN: 40,
+ ENTER: 13,
+ LEFT: 37,
+ RIGHT: 39,
+ SPACEBAR: 32,
+ TAB: 9,
+ UP: 38,
+
+ modifierPressed: function (e) {
+ return e.shiftKey || e.ctrlKey || e.altKey;
+ }
+ };
+})(tinymce);
+
+tinymce.util.Quirks = function(editor) {
+ var VK = tinymce.VK, BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE, dom = editor.dom, selection = editor.selection, settings = editor.settings;
+
+ function setEditorCommandState(cmd, state) {
+ try {
+ editor.getDoc().execCommand(cmd, false, state);
+ } catch (ex) {
+ // Ignore
+ }
+ }
+
+ function getDocumentMode() {
+ var documentMode = editor.getDoc().documentMode;
+
+ return documentMode ? documentMode : 6;
+ };
+
+ function cleanupStylesWhenDeleting() {
+ function removeMergedFormatSpans(isDelete) {
+ var rng, blockElm, node, clonedSpan;
+
+ rng = selection.getRng();
+
+ // Find root block
+ blockElm = dom.getParent(rng.startContainer, dom.isBlock);
+
+ // On delete clone the root span of the next block element
+ if (isDelete)
+ blockElm = dom.getNext(blockElm, dom.isBlock);
+
+ // Locate root span element and clone it since it would otherwise get merged by the "apple-style-span" on delete/backspace
+ if (blockElm) {
+ node = blockElm.firstChild;
+
+ // Ignore empty text nodes
+ while (node && node.nodeType == 3 && node.nodeValue.length === 0)
+ node = node.nextSibling;
+
+ if (node && node.nodeName === 'SPAN') {
+ clonedSpan = node.cloneNode(false);
+ }
+ }
+
+ // Do the backspace/delete action
+ editor.getDoc().execCommand(isDelete ? 'ForwardDelete' : 'Delete', false, null);
+
+ // Find all odd apple-style-spans
+ blockElm = dom.getParent(rng.startContainer, dom.isBlock);
+ tinymce.each(dom.select('span.Apple-style-span,font.Apple-style-span', blockElm), function(span) {
+ var bm = selection.getBookmark();
+
+ if (clonedSpan) {
+ dom.replace(clonedSpan.cloneNode(false), span, true);
+ } else {
+ dom.remove(span, true);
+ }
+
+ // Restore the selection
+ selection.moveToBookmark(bm);
+ });
+ };
+
+ editor.onKeyDown.add(function(editor, e) {
+ var isDelete;
+
+ isDelete = e.keyCode == DELETE;
+ if (!e.isDefaultPrevented() && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
+ e.preventDefault();
+ removeMergedFormatSpans(isDelete);
+ }
+ });
+
+ editor.addCommand('Delete', function() {removeMergedFormatSpans();});
+ };
+
+ function emptyEditorWhenDeleting() {
+ function getEndPointNode(rng, start) {
+ var container, offset, prefix = start ? 'start' : 'end';
+
+ container = rng[prefix + 'Container'];
+ offset = rng[prefix + 'Offset'];
+
+ // Resolve indexed container
+ if (container.nodeType == 1 && container.hasChildNodes()) {
+ container = container.childNodes[Math.min(start ? offset : (offset > 0 ? offset - 1 : 0), container.childNodes.length - 1)]
+ }
+
+ return container;
+ };
+
+ function isAtStartEndOfBody(rng, start) {
+ var container, offset, root, childNode, prefix = start ? 'start' : 'end', isAfter;
+
+ container = rng[prefix + 'Container'];
+ offset = rng[prefix + 'Offset'];
+ root = dom.getRoot();
+
+ // Resolve indexed container
+ if (container.nodeType == 1) {
+ isAfter = offset >= container.childNodes.length;
+ container = getEndPointNode(rng, start);
+
+ if (container.nodeType == 3) {
+ offset = start && !isAfter ? 0 : container.nodeValue.length;
+ }
+ }
+
+ // Check if start/end is in the middle of text
+ if (container.nodeType == 3 && ((start && offset > 0) || (!start && offset < container.nodeValue.length))) {
+ return false;
+ }
+
+ // Walk up the DOM tree to see if the endpoint is at the beginning/end of body
+ while (container !== root) {
+ childNode = container.parentNode[start ? 'firstChild' : 'lastChild'];
+
+ // If first/last element is a BR then jump to it's sibling in case: <p>x<br></p>
+ if (childNode.nodeName == "BR") {
+ childNode = childNode[start ? 'nextSibling' : 'previousSibling'] || childNode;
+ }
+
+ // If the childNode isn't the container node then break in case <p><span>A</span>[X]</p>
+ if (childNode !== container) {
+ return false;
+ }
+
+ container = container.parentNode;
+ }
+
+ return true;
+ };
+
+ editor.onKeyDown.addToTop(function(editor, e) {
+ var rng, keyCode = e.keyCode;
+
+ if (!e.isDefaultPrevented() && (keyCode == DELETE || keyCode == BACKSPACE)) {
+ rng = selection.getRng(true);
+
+ if (isAtStartEndOfBody(rng, true) && isAtStartEndOfBody(rng, false) &&
+ (rng.collapsed || dom.findCommonAncestor(getEndPointNode(rng, true), getEndPointNode(rng)) === dom.getRoot())) {
+ editor.setContent('');
+ editor.selection.setCursorLocation(editor.getBody(), 0);
+ editor.nodeChanged();
+ e.preventDefault();
+ }
+ }
+ });
+ };
+
+ function inputMethodFocus() {
+ if (!editor.settings.content_editable) {
+ // Case 1 IME doesn't initialize if you focus the document
+ dom.bind(editor.getDoc(), 'focusin', function(e) {
+ selection.setRng(selection.getRng());
+ });
+
+ // Case 2 IME doesn't initialize if you click the documentElement it also doesn't properly fire the focusin event
+ dom.bind(editor.getDoc(), 'mousedown', function(e) {
+ if (e.target == editor.getDoc().documentElement) {
+ editor.getWin().focus();
+ selection.setRng(selection.getRng());
+ }
+ });
+ }
+ };
+
+ function removeHrOnBackspace() {
+ editor.onKeyDown.add(function(editor, e) {
+ if (!e.isDefaultPrevented() && e.keyCode === BACKSPACE) {
+ if (selection.isCollapsed() && selection.getRng(true).startOffset === 0) {
+ var node = selection.getNode();
+ var previousSibling = node.previousSibling;
+
+ if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === "hr") {
+ dom.remove(previousSibling);
+ tinymce.dom.Event.cancel(e);
+ }
+ }
+ }
+ })
+ }
+
+ function focusBody() {
+ // Fix for a focus bug in FF 3.x where the body element
+ // wouldn't get proper focus if the user clicked on the HTML element
+ if (!Range.prototype.getClientRects) { // Detect getClientRects got introduced in FF 4
+ editor.onMouseDown.add(function(editor, e) {
+ if (e.target.nodeName === "HTML") {
+ var body = editor.getBody();
+
+ // Blur the body it's focused but not correctly focused
+ body.blur();
+
+ // Refocus the body after a little while
+ setTimeout(function() {
+ body.focus();
+ }, 0);
+ }
+ });
+ }
+ };
+
+ function selectControlElements() {
+ editor.onClick.add(function(editor, e) {
+ e = e.target;
+
+ // Workaround for bug, http://bugs.webkit.org/show_bug.cgi?id=12250
+ // WebKit can't even do simple things like selecting an image
+ // Needs tobe the setBaseAndExtend or it will fail to select floated images
+ if (/^(IMG|HR)$/.test(e.nodeName)) {
+ selection.getSel().setBaseAndExtent(e, 0, e, 1);
+ }
+
+ if (e.nodeName == 'A' && dom.hasClass(e, 'mceItemAnchor')) {
+ selection.select(e);
+ }
+
+ editor.nodeChanged();
+ });
+ };
+
+ function removeStylesWhenDeletingAccrossBlockElements() {
+ function getAttributeApplyFunction() {
+ var template = dom.getAttribs(selection.getStart().cloneNode(false));
+
+ return function() {
+ var target = selection.getStart();
+
+ if (target !== editor.getBody()) {
+ dom.setAttrib(target, "style", null);
+
+ tinymce.each(template, function(attr) {
+ target.setAttributeNode(attr.cloneNode(true));
+ });
+ }
+ };
+ }
+
+ function isSelectionAcrossElements() {
+ return !selection.isCollapsed() && selection.getStart() != selection.getEnd();
+ }
+
+ function blockEvent(editor, e) {
+ e.preventDefault();
+ return false;
+ }
+
+ editor.onKeyPress.add(function(editor, e) {
+ var applyAttributes;
+
+ if ((e.keyCode == 8 || e.keyCode == 46) && isSelectionAcrossElements()) {
+ applyAttributes = getAttributeApplyFunction();
+ editor.getDoc().execCommand('delete', false, null);
+ applyAttributes();
+ e.preventDefault();
+ return false;
+ }
+ });
+
+ dom.bind(editor.getDoc(), 'cut', function(e) {
+ var applyAttributes;
+
+ if (isSelectionAcrossElements()) {
+ applyAttributes = getAttributeApplyFunction();
+ editor.onKeyUp.addToTop(blockEvent);
+
+ setTimeout(function() {
+ applyAttributes();
+ editor.onKeyUp.remove(blockEvent);
+ }, 0);
+ }
+ });
+ }
+
+ function selectionChangeNodeChanged() {
+ var lastRng, selectionTimer;
+
+ dom.bind(editor.getDoc(), 'selectionchange', function() {
+ if (selectionTimer) {
+ clearTimeout(selectionTimer);
+ selectionTimer = 0;
+ }
+
+ selectionTimer = window.setTimeout(function() {
+ var rng = selection.getRng();
+
+ // Compare the ranges to see if it was a real change or not
+ if (!lastRng || !tinymce.dom.RangeUtils.compareRanges(rng, lastRng)) {
+ editor.nodeChanged();
+ lastRng = rng;
+ }
+ }, 50);
+ });
+ }
+
+ function ensureBodyHasRoleApplication() {
+ document.body.setAttribute("role", "application");
+ }
+
+ function disableBackspaceIntoATable() {
+ editor.onKeyDown.add(function(editor, e) {
+ if (!e.isDefaultPrevented() && e.keyCode === BACKSPACE) {
+ if (selection.isCollapsed() && selection.getRng(true).startOffset === 0) {
+ var previousSibling = selection.getNode().previousSibling;
+ if (previousSibling && previousSibling.nodeName && previousSibling.nodeName.toLowerCase() === "table") {
+ return tinymce.dom.Event.cancel(e);
+ }
+ }
+ }
+ })
+ }
+
+ function addNewLinesBeforeBrInPre() {
+ // IE8+ rendering mode does the right thing with BR in PRE
+ if (getDocumentMode() > 7) {
+ return;
+ }
+
+ // Enable display: none in area and add a specific class that hides all BR elements in PRE to
+ // avoid the caret from getting stuck at the BR elements while pressing the right arrow key
+ setEditorCommandState('RespectVisibilityInDesign', true);
+ editor.contentStyles.push('.mceHideBrInPre pre br {display: none}');
+ dom.addClass(editor.getBody(), 'mceHideBrInPre');
+
+ // Adds a \n before all BR elements in PRE to get them visual
+ editor.parser.addNodeFilter('pre', function(nodes, name) {
+ var i = nodes.length, brNodes, j, brElm, sibling;
+
+ while (i--) {
+ brNodes = nodes[i].getAll('br');
+ j = brNodes.length;
+ while (j--) {
+ brElm = brNodes[j];
+
+ // Add \n before BR in PRE elements on older IE:s so the new lines get rendered
+ sibling = brElm.prev;
+ if (sibling && sibling.type === 3 && sibling.value.charAt(sibling.value - 1) != '\n') {
+ sibling.value += '\n';
+ } else {
+ brElm.parent.insert(new tinymce.html.Node('#text', 3), brElm, true).value = '\n';
+ }
+ }
+ }
+ });
+
+ // Removes any \n before BR elements in PRE since other browsers and in contentEditable=false mode they will be visible
+ editor.serializer.addNodeFilter('pre', function(nodes, name) {
+ var i = nodes.length, brNodes, j, brElm, sibling;
+
+ while (i--) {
+ brNodes = nodes[i].getAll('br');
+ j = brNodes.length;
+ while (j--) {
+ brElm = brNodes[j];
+ sibling = brElm.prev;
+ if (sibling && sibling.type == 3) {
+ sibling.value = sibling.value.replace(/\r?\n$/, '');
+ }
+ }
+ }
+ });
+ }
+
+ function removePreSerializedStylesWhenSelectingControls() {
+ dom.bind(editor.getBody(), 'mouseup', function(e) {
+ var value, node = selection.getNode();
+
+ // Moved styles to attributes on IMG eements
+ if (node.nodeName == 'IMG') {
+ // Convert style width to width attribute
+ if (value = dom.getStyle(node, 'width')) {
+ dom.setAttrib(node, 'width', value.replace(/[^0-9%]+/g, ''));
+ dom.setStyle(node, 'width', '');
+ }
+
+ // Convert style height to height attribute
+ if (value = dom.getStyle(node, 'height')) {
+ dom.setAttrib(node, 'height', value.replace(/[^0-9%]+/g, ''));
+ dom.setStyle(node, 'height', '');
+ }
+ }
+ });
+ }
+
+ function keepInlineElementOnDeleteBackspace() {
+ editor.onKeyDown.add(function(editor, e) {
+ var isDelete, rng, container, offset, brElm, sibling, collapsed;
+
+ isDelete = e.keyCode == DELETE;
+ if (!e.isDefaultPrevented() && (isDelete || e.keyCode == BACKSPACE) && !VK.modifierPressed(e)) {
+ rng = selection.getRng();
+ container = rng.startContainer;
+ offset = rng.startOffset;
+ collapsed = rng.collapsed;
+
+ // Override delete if the start container is a text node and is at the beginning of text or
+ // just before/after the last character to be deleted in collapsed mode
+ if (container.nodeType == 3 && container.nodeValue.length > 0 && ((offset === 0 && !collapsed) || (collapsed && offset === (isDelete ? 0 : 1)))) {
+ nonEmptyElements = editor.schema.getNonEmptyElements();
+
+ // Prevent default logic since it's broken
+ e.preventDefault();
+
+ // Insert a BR before the text node this will prevent the containing element from being deleted/converted
+ brElm = dom.create('br', {id: '__tmp'});
+ container.parentNode.insertBefore(brElm, container);
+
+ // Do the browser delete
+ editor.getDoc().execCommand(isDelete ? 'ForwardDelete' : 'Delete', false, null);
+
+ // Check if the previous sibling is empty after deleting for example: <p><b></b>|</p>
+ container = selection.getRng().startContainer;
+ sibling = container.previousSibling;
+ if (sibling && sibling.nodeType == 1 && !dom.isBlock(sibling) && dom.isEmpty(sibling) && !nonEmptyElements[sibling.nodeName.toLowerCase()]) {
+ dom.remove(sibling);
+ }
+
+ // Remove the temp element we inserted
+ dom.remove('__tmp');
+ }
+ }
+ });
+ }
+
+ function removeBlockQuoteOnBackSpace() {
+ // Add block quote deletion handler
+ editor.onKeyDown.add(function(editor, e) {
+ var rng, container, offset, root, parent;
+
+ if (e.isDefaultPrevented() || e.keyCode != VK.BACKSPACE) {
+ return;
+ }
+
+ rng = selection.getRng();
+ container = rng.startContainer;
+ offset = rng.startOffset;
+ root = dom.getRoot();
+ parent = container;
+
+ if (!rng.collapsed || offset !== 0) {
+ return;
+ }
+
+ while (parent && parent.parentNode && parent.parentNode.firstChild == parent && parent.parentNode != root) {
+ parent = parent.parentNode;
+ }
+
+ // Is the cursor at the beginning of a blockquote?
+ if (parent.tagName === 'BLOCKQUOTE') {
+ // Remove the blockquote
+ editor.formatter.toggle('blockquote', null, parent);
+
+ // Move the caret to the beginning of container
+ rng.setStart(container, 0);
+ rng.setEnd(container, 0);
+ selection.setRng(rng);
+ selection.collapse(false);
+ }
+ });
+ };
+
+ function setGeckoEditingOptions() {
+ function setOpts() {
+ editor._refreshContentEditable();
+
+ setEditorCommandState("StyleWithCSS", false);
+ setEditorCommandState("enableInlineTableEditing", false);
+
+ if (!settings.object_resizing) {
+ setEditorCommandState("enableObjectResizing", false);
+ }
+ };
+
+ if (!settings.readonly) {
+ editor.onBeforeExecCommand.add(setOpts);
+ editor.onMouseDown.add(setOpts);
+ }
+ };
+
+ function addBrAfterLastLinks() {
+ function fixLinks(editor, o) {
+ tinymce.each(dom.select('a'), function(node) {
+ var parentNode = node.parentNode, root = dom.getRoot();
+
+ if (parentNode.lastChild === node) {
+ while (parentNode && !dom.isBlock(parentNode)) {
+ if (parentNode.parentNode.lastChild !== parentNode || parentNode === root) {
+ return;
+ }
+
+ parentNode = parentNode.parentNode;
+ }
+
+ dom.add(parentNode, 'br', {'data-mce-bogus' : 1});
+ }
+ });
+ };
+
+ editor.onExecCommand.add(function(editor, cmd) {
+ if (cmd === 'CreateLink') {
+ fixLinks(editor);
+ }
+ });
+
+ editor.onSetContent.add(selection.onSetContent.add(fixLinks));
+ };
+
+ function setDefaultBlockType() {
+ if (settings.forced_root_block) {
+ editor.onInit.add(function() {
+ setEditorCommandState('DefaultParagraphSeparator', settings.forced_root_block);
+ });
+ }
+ }
+
+ function removeGhostSelection() {
+ function repaint(sender, args) {
+ if (!sender || !args.initial) {
+ editor.execCommand('mceRepaint');
+ }
+ };
+
+ editor.onUndo.add(repaint);
+ editor.onRedo.add(repaint);
+ editor.onSetContent.add(repaint);
+ };
+
+ function deleteControlItemOnBackSpace() {
+ editor.onKeyDown.add(function(editor, e) {
+ var rng;
+
+ if (!e.isDefaultPrevented() && e.keyCode == BACKSPACE) {
+ rng = editor.getDoc().selection.createRange();
+ if (rng && rng.item) {
+ e.preventDefault();
+ editor.undoManager.beforeChange();
+ dom.remove(rng.item(0));
+ editor.undoManager.add();
+ }
+ }
+ });
+ };
+
+ function renderEmptyBlocksFix() {
+ var emptyBlocksCSS;
+
+ // IE10+
+ if (getDocumentMode() >= 10) {
+ emptyBlocksCSS = '';
+ tinymce.each('p div h1 h2 h3 h4 h5 h6'.split(' '), function(name, i) {
+ emptyBlocksCSS += (i > 0 ? ',' : '') + name + ':empty';
+ });
+
+ editor.contentStyles.push(emptyBlocksCSS + '{padding-right: 1px !important}');
+ }
+ };
+
+ // All browsers
+ disableBackspaceIntoATable();
+ removeBlockQuoteOnBackSpace();
+ emptyEditorWhenDeleting();
+
+ // WebKit
+ if (tinymce.isWebKit) {
+ keepInlineElementOnDeleteBackspace();
+ cleanupStylesWhenDeleting();
+ inputMethodFocus();
+ selectControlElements();
+ setDefaultBlockType();
+
+ // iOS
+ if (tinymce.isIDevice) {
+ selectionChangeNodeChanged();
+ }
+ }
+
+ // IE
+ if (tinymce.isIE) {
+ removeHrOnBackspace();
+ ensureBodyHasRoleApplication();
+ addNewLinesBeforeBrInPre();
+ removePreSerializedStylesWhenSelectingControls();
+ deleteControlItemOnBackSpace();
+ renderEmptyBlocksFix();
+ }
+
+ // Gecko
+ if (tinymce.isGecko) {
+ removeHrOnBackspace();
+ focusBody();
+ removeStylesWhenDeletingAccrossBlockElements();
+ setGeckoEditingOptions();
+ addBrAfterLastLinks();
+ removeGhostSelection();
+ }
+};
+(function(tinymce) {
+ var namedEntities, baseEntities, reverseEntities,
+ attrsCharsRegExp = /[&<>\"\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
+ textCharsRegExp = /[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
+ rawCharsRegExp = /[<>&\"\']/g,
+ entityRegExp = /&(#x|#)?([\w]+);/g,
+ asciiMap = {
+ 128 : "\u20AC", 130 : "\u201A", 131 : "\u0192", 132 : "\u201E", 133 : "\u2026", 134 : "\u2020",
+ 135 : "\u2021", 136 : "\u02C6", 137 : "\u2030", 138 : "\u0160", 139 : "\u2039", 140 : "\u0152",
+ 142 : "\u017D", 145 : "\u2018", 146 : "\u2019", 147 : "\u201C", 148 : "\u201D", 149 : "\u2022",
+ 150 : "\u2013", 151 : "\u2014", 152 : "\u02DC", 153 : "\u2122", 154 : "\u0161", 155 : "\u203A",
+ 156 : "\u0153", 158 : "\u017E", 159 : "\u0178"
+ };
+
+ // Raw entities
+ baseEntities = {
+ '\"' : '&quot;', // Needs to be escaped since the YUI compressor would otherwise break the code
+ "'" : '&#39;',
+ '<' : '&lt;',
+ '>' : '&gt;',
+ '&' : '&amp;'
+ };
+
+ // Reverse lookup table for raw entities
+ reverseEntities = {
+ '&lt;' : '<',
+ '&gt;' : '>',
+ '&amp;' : '&',
+ '&quot;' : '"',
+ '&apos;' : "'"
+ };
+
+ // Decodes text by using the browser
+ function nativeDecode(text) {
+ var elm;
+
+ elm = document.createElement("div");
+ elm.innerHTML = text;
+
+ return elm.textContent || elm.innerText || text;
+ };
+
+ // Build a two way lookup table for the entities
+ function buildEntitiesLookup(items, radix) {
+ var i, chr, entity, lookup = {};
+
+ if (items) {
+ items = items.split(',');
+ radix = radix || 10;
+
+ // Build entities lookup table
+ for (i = 0; i < items.length; i += 2) {
+ chr = String.fromCharCode(parseInt(items[i], radix));
+
+ // Only add non base entities
+ if (!baseEntities[chr]) {
+ entity = '&' + items[i + 1] + ';';
+ lookup[chr] = entity;
+ lookup[entity] = chr;
+ }
+ }
+
+ return lookup;
+ }
+ };
+
+ // Unpack entities lookup where the numbers are in radix 32 to reduce the size
+ namedEntities = buildEntitiesLookup(
+ '50,nbsp,51,iexcl,52,cent,53,pound,54,curren,55,yen,56,brvbar,57,sect,58,uml,59,copy,' +
+ '5a,ordf,5b,laquo,5c,not,5d,shy,5e,reg,5f,macr,5g,deg,5h,plusmn,5i,sup2,5j,sup3,5k,acute,' +
+ '5l,micro,5m,para,5n,middot,5o,cedil,5p,sup1,5q,ordm,5r,raquo,5s,frac14,5t,frac12,5u,frac34,' +
+ '5v,iquest,60,Agrave,61,Aacute,62,Acirc,63,Atilde,64,Auml,65,Aring,66,AElig,67,Ccedil,' +
+ '68,Egrave,69,Eacute,6a,Ecirc,6b,Euml,6c,Igrave,6d,Iacute,6e,Icirc,6f,Iuml,6g,ETH,6h,Ntilde,' +
+ '6i,Ograve,6j,Oacute,6k,Ocirc,6l,Otilde,6m,Ouml,6n,times,6o,Oslash,6p,Ugrave,6q,Uacute,' +
+ '6r,Ucirc,6s,Uuml,6t,Yacute,6u,THORN,6v,szlig,70,agrave,71,aacute,72,acirc,73,atilde,74,auml,' +
+ '75,aring,76,aelig,77,ccedil,78,egrave,79,eacute,7a,ecirc,7b,euml,7c,igrave,7d,iacute,7e,icirc,' +
+ '7f,iuml,7g,eth,7h,ntilde,7i,ograve,7j,oacute,7k,ocirc,7l,otilde,7m,ouml,7n,divide,7o,oslash,' +
+ '7p,ugrave,7q,uacute,7r,ucirc,7s,uuml,7t,yacute,7u,thorn,7v,yuml,ci,fnof,sh,Alpha,si,Beta,' +
+ 'sj,Gamma,sk,Delta,sl,Epsilon,sm,Zeta,sn,Eta,so,Theta,sp,Iota,sq,Kappa,sr,Lambda,ss,Mu,' +
+ 'st,Nu,su,Xi,sv,Omicron,t0,Pi,t1,Rho,t3,Sigma,t4,Tau,t5,Upsilon,t6,Phi,t7,Chi,t8,Psi,' +
+ 't9,Omega,th,alpha,ti,beta,tj,gamma,tk,delta,tl,epsilon,tm,zeta,tn,eta,to,theta,tp,iota,' +
+ 'tq,kappa,tr,lambda,ts,mu,tt,nu,tu,xi,tv,omicron,u0,pi,u1,rho,u2,sigmaf,u3,sigma,u4,tau,' +
+ 'u5,upsilon,u6,phi,u7,chi,u8,psi,u9,omega,uh,thetasym,ui,upsih,um,piv,812,bull,816,hellip,' +
+ '81i,prime,81j,Prime,81u,oline,824,frasl,88o,weierp,88h,image,88s,real,892,trade,89l,alefsym,' +
+ '8cg,larr,8ch,uarr,8ci,rarr,8cj,darr,8ck,harr,8dl,crarr,8eg,lArr,8eh,uArr,8ei,rArr,8ej,dArr,' +
+ '8ek,hArr,8g0,forall,8g2,part,8g3,exist,8g5,empty,8g7,nabla,8g8,isin,8g9,notin,8gb,ni,8gf,prod,' +
+ '8gh,sum,8gi,minus,8gn,lowast,8gq,radic,8gt,prop,8gu,infin,8h0,ang,8h7,and,8h8,or,8h9,cap,8ha,cup,' +
+ '8hb,int,8hk,there4,8hs,sim,8i5,cong,8i8,asymp,8j0,ne,8j1,equiv,8j4,le,8j5,ge,8k2,sub,8k3,sup,8k4,' +
+ 'nsub,8k6,sube,8k7,supe,8kl,oplus,8kn,otimes,8l5,perp,8m5,sdot,8o8,lceil,8o9,rceil,8oa,lfloor,8ob,' +
+ 'rfloor,8p9,lang,8pa,rang,9ea,loz,9j0,spades,9j3,clubs,9j5,hearts,9j6,diams,ai,OElig,aj,oelig,b0,' +
+ 'Scaron,b1,scaron,bo,Yuml,m6,circ,ms,tilde,802,ensp,803,emsp,809,thinsp,80c,zwnj,80d,zwj,80e,lrm,' +
+ '80f,rlm,80j,ndash,80k,mdash,80o,lsquo,80p,rsquo,80q,sbquo,80s,ldquo,80t,rdquo,80u,bdquo,810,dagger,' +
+ '811,Dagger,81g,permil,81p,lsaquo,81q,rsaquo,85c,euro', 32);
+
+ tinymce.html = tinymce.html || {};
+
+ tinymce.html.Entities = {
+ encodeRaw : function(text, attr) {
+ return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(chr) {
+ return baseEntities[chr] || chr;
+ });
+ },
+
+ encodeAllRaw : function(text) {
+ return ('' + text).replace(rawCharsRegExp, function(chr) {
+ return baseEntities[chr] || chr;
+ });
+ },
+
+ encodeNumeric : function(text, attr) {
+ return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(chr) {
+ // Multi byte sequence convert it to a single entity
+ if (chr.length > 1)
+ return '&#' + (((chr.charCodeAt(0) - 0xD800) * 0x400) + (chr.charCodeAt(1) - 0xDC00) + 0x10000) + ';';
+
+ return baseEntities[chr] || '&#' + chr.charCodeAt(0) + ';';
+ });
+ },
+
+ encodeNamed : function(text, attr, entities) {
+ entities = entities || namedEntities;
+
+ return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(chr) {
+ return baseEntities[chr] || entities[chr] || chr;
+ });
+ },
+
+ getEncodeFunc : function(name, entities) {
+ var Entities = tinymce.html.Entities;
+
+ entities = buildEntitiesLookup(entities) || namedEntities;
+
+ function encodeNamedAndNumeric(text, attr) {
+ return text.replace(attr ? attrsCharsRegExp : textCharsRegExp, function(chr) {
+ return baseEntities[chr] || entities[chr] || '&#' + chr.charCodeAt(0) + ';' || chr;
+ });
+ };
+
+ function encodeCustomNamed(text, attr) {
+ return Entities.encodeNamed(text, attr, entities);
+ };
+
+ // Replace + with , to be compatible with previous TinyMCE versions
+ name = tinymce.makeMap(name.replace(/\+/g, ','));
+
+ // Named and numeric encoder
+ if (name.named && name.numeric)
+ return encodeNamedAndNumeric;
+
+ // Named encoder
+ if (name.named) {
+ // Custom names
+ if (entities)
+ return encodeCustomNamed;
+
+ return Entities.encodeNamed;
+ }
+
+ // Numeric
+ if (name.numeric)
+ return Entities.encodeNumeric;
+
+ // Raw encoder
+ return Entities.encodeRaw;
+ },
+
+ decode : function(text) {
+ return text.replace(entityRegExp, function(all, numeric, value) {
+ if (numeric) {
+ value = parseInt(value, numeric.length === 2 ? 16 : 10);
+
+ // Support upper UTF
+ if (value > 0xFFFF) {
+ value -= 0x10000;
+
+ return String.fromCharCode(0xD800 + (value >> 10), 0xDC00 + (value & 0x3FF));
+ } else
+ return asciiMap[value] || String.fromCharCode(value);
+ }
+
+ return reverseEntities[all] || namedEntities[all] || nativeDecode(all);
+ });
+ }
+ };
+})(tinymce);
+
+tinymce.html.Styles = function(settings, schema) {
+ var rgbRegExp = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi,
+ urlOrStrRegExp = /(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi,
+ styleRegExp = /\s*([^:]+):\s*([^;]+);?/g,
+ trimRightRegExp = /\s+$/,
+ urlColorRegExp = /rgb/,
+ undef, i, encodingLookup = {}, encodingItems;
+
+ settings = settings || {};
+
+ encodingItems = '\\" \\\' \\; \\: ; : \uFEFF'.split(' ');
+ for (i = 0; i < encodingItems.length; i++) {
+ encodingLookup[encodingItems[i]] = '\uFEFF' + i;
+ encodingLookup['\uFEFF' + i] = encodingItems[i];
+ }
+
+ function toHex(match, r, g, b) {
+ function hex(val) {
+ val = parseInt(val).toString(16);
+
+ return val.length > 1 ? val : '0' + val; // 0 -> 00
+ };
+
+ return '#' + hex(r) + hex(g) + hex(b);
+ };
+
+ return {
+ toHex : function(color) {
+ return color.replace(rgbRegExp, toHex);
+ },
+
+ parse : function(css) {
+ var styles = {}, matches, name, value, isEncoded, urlConverter = settings.url_converter, urlConverterScope = settings.url_converter_scope || this;
+
+ function compress(prefix, suffix) {
+ var top, right, bottom, left;
+
+ // Get values and check it it needs compressing
+ top = styles[prefix + '-top' + suffix];
+ if (!top)
+ return;
+
+ right = styles[prefix + '-right' + suffix];
+ if (top != right)
+ return;
+
+ bottom = styles[prefix + '-bottom' + suffix];
+ if (right != bottom)
+ return;
+
+ left = styles[prefix + '-left' + suffix];
+ if (bottom != left)
+ return;
+
+ // Compress
+ styles[prefix + suffix] = left;
+ delete styles[prefix + '-top' + suffix];
+ delete styles[prefix + '-right' + suffix];
+ delete styles[prefix + '-bottom' + suffix];
+ delete styles[prefix + '-left' + suffix];
+ };
+
+ function canCompress(key) {
+ var value = styles[key], i;
+
+ if (!value || value.indexOf(' ') < 0)
+ return;
+
+ value = value.split(' ');
+ i = value.length;
+ while (i--) {
+ if (value[i] !== value[0])
+ return false;
+ }
+
+ styles[key] = value[0];
+
+ return true;
+ };
+
+ function compress2(target, a, b, c) {
+ if (!canCompress(a))
+ return;
+
+ if (!canCompress(b))
+ return;
+
+ if (!canCompress(c))
+ return;
+
+ // Compress
+ styles[target] = styles[a] + ' ' + styles[b] + ' ' + styles[c];
+ delete styles[a];
+ delete styles[b];
+ delete styles[c];
+ };
+
+ // Encodes the specified string by replacing all \" \' ; : with _<num>
+ function encode(str) {
+ isEncoded = true;
+
+ return encodingLookup[str];
+ };
+
+ // Decodes the specified string by replacing all _<num> with it's original value \" \' etc
+ // It will also decode the \" \' if keep_slashes is set to fale or omitted
+ function decode(str, keep_slashes) {
+ if (isEncoded) {
+ str = str.replace(/\uFEFF[0-9]/g, function(str) {
+ return encodingLookup[str];
+ });
+ }
+
+ if (!keep_slashes)
+ str = str.replace(/\\([\'\";:])/g, "$1");
+
+ return str;
+ };
+
+ function processUrl(match, url, url2, url3, str, str2) {
+ str = str || str2;
+
+ if (str) {
+ str = decode(str);
+
+ // Force strings into single quote format
+ return "'" + str.replace(/\'/g, "\\'") + "'";
+ }
+
+ url = decode(url || url2 || url3);
+
+ // Convert the URL to relative/absolute depending on config
+ if (urlConverter)
+ url = urlConverter.call(urlConverterScope, url, 'style');
+
+ // Output new URL format
+ return "url('" + url.replace(/\'/g, "\\'") + "')";
+ };
+
+ if (css) {
+ // Encode \" \' % and ; and : inside strings so they don't interfere with the style parsing
+ css = css.replace(/\\[\"\';:\uFEFF]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, function(str) {
+ return str.replace(/[;:]/g, encode);
+ });
+
+ // Parse styles
+ while (matches = styleRegExp.exec(css)) {
+ name = matches[1].replace(trimRightRegExp, '').toLowerCase();
+ value = matches[2].replace(trimRightRegExp, '');
+
+ if (name && value.length > 0) {
+ // Opera will produce 700 instead of bold in their style values
+ if (name === 'font-weight' && value === '700')
+ value = 'bold';
+ else if (name === 'color' || name === 'background-color') // Lowercase colors like RED
+ value = value.toLowerCase();
+
+ // Convert RGB colors to HEX
+ value = value.replace(rgbRegExp, toHex);
+
+ // Convert URLs and force them into url('value') format
+ value = value.replace(urlOrStrRegExp, processUrl);
+ styles[name] = isEncoded ? decode(value, true) : value;
+ }
+
+ styleRegExp.lastIndex = matches.index + matches[0].length;
+ }
+
+ // Compress the styles to reduce it's size for example IE will expand styles
+ compress("border", "");
+ compress("border", "-width");
+ compress("border", "-color");
+ compress("border", "-style");
+ compress("padding", "");
+ compress("margin", "");
+ compress2('border', 'border-width', 'border-style', 'border-color');
+
+ // Remove pointless border, IE produces these
+ if (styles.border === 'medium none')
+ delete styles.border;
+ }
+
+ return styles;
+ },
+
+ serialize : function(styles, element_name) {
+ var css = '', name, value;
+
+ function serializeStyles(name) {
+ var styleList, i, l, value;
+
+ styleList = schema.styles[name];
+ if (styleList) {
+ for (i = 0, l = styleList.length; i < l; i++) {
+ name = styleList[i];
+ value = styles[name];
+
+ if (value !== undef && value.length > 0)
+ css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
+ }
+ }
+ };
+
+ // Serialize styles according to schema
+ if (element_name && schema && schema.styles) {
+ // Serialize global styles and element specific styles
+ serializeStyles('*');
+ serializeStyles(element_name);
+ } else {
+ // Output the styles in the order they are inside the object
+ for (name in styles) {
+ value = styles[name];
+
+ if (value !== undef && value.length > 0)
+ css += (css.length > 0 ? ' ' : '') + name + ': ' + value + ';';
+ }
+ }
+
+ return css;
+ }
+ };
+};
+
+(function(tinymce) {
+ var mapCache = {}, makeMap = tinymce.makeMap, each = tinymce.each;
+
+ function split(str, delim) {
+ return str.split(delim || ',');
+ };
+
+ function unpack(lookup, data) {
+ var key, elements = {};
+
+ function replace(value) {
+ return value.replace(/[A-Z]+/g, function(key) {
+ return replace(lookup[key]);
+ });
+ };
+
+ // Unpack lookup
+ for (key in lookup) {
+ if (lookup.hasOwnProperty(key))
+ lookup[key] = replace(lookup[key]);
+ }
+
+ // Unpack and parse data into object map
+ replace(data).replace(/#/g, '#text').replace(/(\w+)\[([^\]]+)\]\[([^\]]*)\]/g, function(str, name, attributes, children) {
+ attributes = split(attributes, '|');
+
+ elements[name] = {
+ attributes : makeMap(attributes),
+ attributesOrder : attributes,
+ children : makeMap(children, '|', {'#comment' : {}})
+ }
+ });
+
+ return elements;
+ };
+
+ function getHTML5() {
+ var html5 = mapCache.html5;
+
+ if (!html5) {
+ html5 = mapCache.html5 = unpack({
+ A : 'id|accesskey|class|dir|draggable|item|hidden|itemprop|role|spellcheck|style|subject|title',
+ B : '#|a|abbr|area|audio|b|bdo|br|button|canvas|cite|code|command|datalist|del|dfn|em|embed|i|iframe|img|input|ins|kbd|keygen|label|link|map|mark|meta|' +
+ 'meter|noscript|object|output|progress|q|ruby|samp|script|select|small|span|strong|sub|sup|svg|textarea|time|var|video|wbr',
+ C : '#|a|abbr|area|address|article|aside|audio|b|bdo|blockquote|br|button|canvas|cite|code|command|datalist|del|details|dfn|dialog|div|dl|em|embed|fieldset|' +
+ 'figure|footer|form|h1|h2|h3|h4|h5|h6|header|hgroup|hr|i|iframe|img|input|ins|kbd|keygen|label|link|map|mark|menu|meta|meter|nav|noscript|ol|object|output|' +
+ 'p|pre|progress|q|ruby|samp|script|section|select|small|span|strong|style|sub|sup|svg|table|textarea|time|ul|var|video'
+ }, 'html[A|manifest][body|head]' +
+ 'head[A][base|command|link|meta|noscript|script|style|title]' +
+ 'title[A][#]' +
+ 'base[A|href|target][]' +
+ 'link[A|href|rel|media|type|sizes][]' +
+ 'meta[A|http-equiv|name|content|charset][]' +
+ 'style[A|type|media|scoped][#]' +
+ 'script[A|charset|type|src|defer|async][#]' +
+ 'noscript[A][C]' +
+ 'body[A][C]' +
+ 'section[A][C]' +
+ 'nav[A][C]' +
+ 'article[A][C]' +
+ 'aside[A][C]' +
+ 'h1[A][B]' +
+ 'h2[A][B]' +
+ 'h3[A][B]' +
+ 'h4[A][B]' +
+ 'h5[A][B]' +
+ 'h6[A][B]' +
+ 'hgroup[A][h1|h2|h3|h4|h5|h6]' +
+ 'header[A][C]' +
+ 'footer[A][C]' +
+ 'address[A][C]' +
+ 'p[A][B]' +
+ 'br[A][]' +
+ 'pre[A][B]' +
+ 'dialog[A][dd|dt]' +
+ 'blockquote[A|cite][C]' +
+ 'ol[A|start|reversed][li]' +
+ 'ul[A][li]' +
+ 'li[A|value][C]' +
+ 'dl[A][dd|dt]' +
+ 'dt[A][B]' +
+ 'dd[A][C]' +
+ 'a[A|href|target|ping|rel|media|type][B]' +
+ 'em[A][B]' +
+ 'strong[A][B]' +
+ 'small[A][B]' +
+ 'cite[A][B]' +
+ 'q[A|cite][B]' +
+ 'dfn[A][B]' +
+ 'abbr[A][B]' +
+ 'code[A][B]' +
+ 'var[A][B]' +
+ 'samp[A][B]' +
+ 'kbd[A][B]' +
+ 'sub[A][B]' +
+ 'sup[A][B]' +
+ 'i[A][B]' +
+ 'b[A][B]' +
+ 'mark[A][B]' +
+ 'progress[A|value|max][B]' +
+ 'meter[A|value|min|max|low|high|optimum][B]' +
+ 'time[A|datetime][B]' +
+ 'ruby[A][B|rt|rp]' +
+ 'rt[A][B]' +
+ 'rp[A][B]' +
+ 'bdo[A][B]' +
+ 'span[A][B]' +
+ 'ins[A|cite|datetime][B]' +
+ 'del[A|cite|datetime][B]' +
+ 'figure[A][C|legend|figcaption]' +
+ 'figcaption[A][C]' +
+ 'img[A|alt|src|height|width|usemap|ismap][]' +
+ 'iframe[A|name|src|height|width|sandbox|seamless][]' +
+ 'embed[A|src|height|width|type][]' +
+ 'object[A|data|type|height|width|usemap|name|form|classid][param]' +
+ 'param[A|name|value][]' +
+ 'details[A|open][C|legend]' +
+ 'command[A|type|label|icon|disabled|checked|radiogroup][]' +
+ 'menu[A|type|label][C|li]' +
+ 'legend[A][C|B]' +
+ 'div[A][C]' +
+ 'source[A|src|type|media][]' +
+ 'audio[A|src|autobuffer|autoplay|loop|controls][source]' +
+ 'video[A|src|autobuffer|autoplay|loop|controls|width|height|poster][source]' +
+ 'hr[A][]' +
+ 'form[A|accept-charset|action|autocomplete|enctype|method|name|novalidate|target][C]' +
+ 'fieldset[A|disabled|form|name][C|legend]' +
+ 'label[A|form|for][B]' +
+ 'input[A|type|accept|alt|autocomplete|checked|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|height|list|max|maxlength|min|' +
+ 'multiple|pattern|placeholder|readonly|required|size|src|step|width|files|value|name][]' +
+ 'button[A|autofocus|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|name|value|type][B]' +
+ 'select[A|autofocus|disabled|form|multiple|name|size][option|optgroup]' +
+ 'datalist[A][B|option]' +
+ 'optgroup[A|disabled|label][option]' +
+ 'option[A|disabled|selected|label|value][]' +
+ 'textarea[A|autofocus|disabled|form|maxlength|name|placeholder|readonly|required|rows|cols|wrap][]' +
+ 'keygen[A|autofocus|challenge|disabled|form|keytype|name][]' +
+ 'output[A|for|form|name][B]' +
+ 'canvas[A|width|height][]' +
+ 'map[A|name][B|C]' +
+ 'area[A|shape|coords|href|alt|target|media|rel|ping|type][]' +
+ 'mathml[A][]' +
+ 'svg[A][]' +
+ 'table[A|border][caption|colgroup|thead|tfoot|tbody|tr]' +
+ 'caption[A][C]' +
+ 'colgroup[A|span][col]' +
+ 'col[A|span][]' +
+ 'thead[A][tr]' +
+ 'tfoot[A][tr]' +
+ 'tbody[A][tr]' +
+ 'tr[A][th|td]' +
+ 'th[A|headers|rowspan|colspan|scope][B]' +
+ 'td[A|headers|rowspan|colspan][C]' +
+ 'wbr[A][]'
+ );
+ }
+
+ return html5;
+ };
+
+ function getHTML4() {
+ var html4 = mapCache.html4;
+
+ if (!html4) {
+ // This is the XHTML 1.0 transitional elements with it's attributes and children packed to reduce it's size
+ html4 = mapCache.html4 = unpack({
+ Z : 'H|K|N|O|P',
+ Y : 'X|form|R|Q',
+ ZG : 'E|span|width|align|char|charoff|valign',
+ X : 'p|T|div|U|W|isindex|fieldset|table',
+ ZF : 'E|align|char|charoff|valign',
+ W : 'pre|hr|blockquote|address|center|noframes',
+ ZE : 'abbr|axis|headers|scope|rowspan|colspan|align|char|charoff|valign|nowrap|bgcolor|width|height',
+ ZD : '[E][S]',
+ U : 'ul|ol|dl|menu|dir',
+ ZC : 'p|Y|div|U|W|table|br|span|bdo|object|applet|img|map|K|N|Q',
+ T : 'h1|h2|h3|h4|h5|h6',
+ ZB : 'X|S|Q',
+ S : 'R|P',
+ ZA : 'a|G|J|M|O|P',
+ R : 'a|H|K|N|O',
+ Q : 'noscript|P',
+ P : 'ins|del|script',
+ O : 'input|select|textarea|label|button',
+ N : 'M|L',
+ M : 'em|strong|dfn|code|q|samp|kbd|var|cite|abbr|acronym',
+ L : 'sub|sup',
+ K : 'J|I',
+ J : 'tt|i|b|u|s|strike',
+ I : 'big|small|font|basefont',
+ H : 'G|F',
+ G : 'br|span|bdo',
+ F : 'object|applet|img|map|iframe',
+ E : 'A|B|C',
+ D : 'accesskey|tabindex|onfocus|onblur',
+ C : 'onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup',
+ B : 'lang|xml:lang|dir',
+ A : 'id|class|style|title'
+ }, 'script[id|charset|type|language|src|defer|xml:space][]' +
+ 'style[B|id|type|media|title|xml:space][]' +
+ 'object[E|declare|classid|codebase|data|type|codetype|archive|standby|width|height|usemap|name|tabindex|align|border|hspace|vspace][#|param|Y]' +
+ 'param[id|name|value|valuetype|type][]' +
+ 'p[E|align][#|S]' +
+ 'a[E|D|charset|type|name|href|hreflang|rel|rev|shape|coords|target][#|Z]' +
+ 'br[A|clear][]' +
+ 'span[E][#|S]' +
+ 'bdo[A|C|B][#|S]' +
+ 'applet[A|codebase|archive|code|object|alt|name|width|height|align|hspace|vspace][#|param|Y]' +
+ 'h1[E|align][#|S]' +
+ 'img[E|src|alt|name|longdesc|width|height|usemap|ismap|align|border|hspace|vspace][]' +
+ 'map[B|C|A|name][X|form|Q|area]' +
+ 'h2[E|align][#|S]' +
+ 'iframe[A|longdesc|name|src|frameborder|marginwidth|marginheight|scrolling|align|width|height][#|Y]' +
+ 'h3[E|align][#|S]' +
+ 'tt[E][#|S]' +
+ 'i[E][#|S]' +
+ 'b[E][#|S]' +
+ 'u[E][#|S]' +
+ 's[E][#|S]' +
+ 'strike[E][#|S]' +
+ 'big[E][#|S]' +
+ 'small[E][#|S]' +
+ 'font[A|B|size|color|face][#|S]' +
+ 'basefont[id|size|color|face][]' +
+ 'em[E][#|S]' +
+ 'strong[E][#|S]' +
+ 'dfn[E][#|S]' +
+ 'code[E][#|S]' +
+ 'q[E|cite][#|S]' +
+ 'samp[E][#|S]' +
+ 'kbd[E][#|S]' +
+ 'var[E][#|S]' +
+ 'cite[E][#|S]' +
+ 'abbr[E][#|S]' +
+ 'acronym[E][#|S]' +
+ 'sub[E][#|S]' +
+ 'sup[E][#|S]' +
+ 'input[E|D|type|name|value|checked|disabled|readonly|size|maxlength|src|alt|usemap|onselect|onchange|accept|align][]' +
+ 'select[E|name|size|multiple|disabled|tabindex|onfocus|onblur|onchange][optgroup|option]' +
+ 'optgroup[E|disabled|label][option]' +
+ 'option[E|selected|disabled|label|value][]' +
+ 'textarea[E|D|name|rows|cols|disabled|readonly|onselect|onchange][]' +
+ 'label[E|for|accesskey|onfocus|onblur][#|S]' +
+ 'button[E|D|name|value|type|disabled][#|p|T|div|U|W|table|G|object|applet|img|map|K|N|Q]' +
+ 'h4[E|align][#|S]' +
+ 'ins[E|cite|datetime][#|Y]' +
+ 'h5[E|align][#|S]' +
+ 'del[E|cite|datetime][#|Y]' +
+ 'h6[E|align][#|S]' +
+ 'div[E|align][#|Y]' +
+ 'ul[E|type|compact][li]' +
+ 'li[E|type|value][#|Y]' +
+ 'ol[E|type|compact|start][li]' +
+ 'dl[E|compact][dt|dd]' +
+ 'dt[E][#|S]' +
+ 'dd[E][#|Y]' +
+ 'menu[E|compact][li]' +
+ 'dir[E|compact][li]' +
+ 'pre[E|width|xml:space][#|ZA]' +
+ 'hr[E|align|noshade|size|width][]' +
+ 'blockquote[E|cite][#|Y]' +
+ 'address[E][#|S|p]' +
+ 'center[E][#|Y]' +
+ 'noframes[E][#|Y]' +
+ 'isindex[A|B|prompt][]' +
+ 'fieldset[E][#|legend|Y]' +
+ 'legend[E|accesskey|align][#|S]' +
+ 'table[E|summary|width|border|frame|rules|cellspacing|cellpadding|align|bgcolor][caption|col|colgroup|thead|tfoot|tbody|tr]' +
+ 'caption[E|align][#|S]' +
+ 'col[ZG][]' +
+ 'colgroup[ZG][col]' +
+ 'thead[ZF][tr]' +
+ 'tr[ZF|bgcolor][th|td]' +
+ 'th[E|ZE][#|Y]' +
+ 'form[E|action|method|name|enctype|onsubmit|onreset|accept|accept-charset|target][#|X|R|Q]' +
+ 'noscript[E][#|Y]' +
+ 'td[E|ZE][#|Y]' +
+ 'tfoot[ZF][tr]' +
+ 'tbody[ZF][tr]' +
+ 'area[E|D|shape|coords|href|nohref|alt|target][]' +
+ 'base[id|href|target][]' +
+ 'body[E|onload|onunload|background|bgcolor|text|link|vlink|alink][#|Y]'
+ );
+ }
+
+ return html4;
+ };
+
+ tinymce.html.Schema = function(settings) {
+ var self = this, elements = {}, children = {}, patternElements = [], validStyles, schemaItems;
+ var whiteSpaceElementsMap, selfClosingElementsMap, shortEndedElementsMap, boolAttrMap, blockElementsMap, nonEmptyElementsMap, customElementsMap = {};
+
+ // Creates an lookup table map object for the specified option or the default value
+ function createLookupTable(option, default_value, extend) {
+ var value = settings[option];
+
+ if (!value) {
+ // Get cached default map or make it if needed
+ value = mapCache[option];
+
+ if (!value) {
+ value = makeMap(default_value, ' ', makeMap(default_value.toUpperCase(), ' '));
+ value = tinymce.extend(value, extend);
+
+ mapCache[option] = value;
+ }
+ } else {
+ // Create custom map
+ value = makeMap(value, ',', makeMap(value.toUpperCase(), ' '));
+ }
+
+ return value;
+ };
+
+ settings = settings || {};
+ schemaItems = settings.schema == "html5" ? getHTML5() : getHTML4();
+
+ // Allow all elements and attributes if verify_html is set to false
+ if (settings.verify_html === false)
+ settings.valid_elements = '*[*]';
+
+ // Build styles list
+ if (settings.valid_styles) {
+ validStyles = {};
+
+ // Convert styles into a rule list
+ each(settings.valid_styles, function(value, key) {
+ validStyles[key] = tinymce.explode(value);
+ });
+ }
+
+ // Setup map objects
+ whiteSpaceElementsMap = createLookupTable('whitespace_elements', 'pre script style textarea');
+ selfClosingElementsMap = createLookupTable('self_closing_elements', 'colgroup dd dt li option p td tfoot th thead tr');
+ shortEndedElementsMap = createLookupTable('short_ended_elements', 'area base basefont br col frame hr img input isindex link meta param embed source wbr');
+ boolAttrMap = createLookupTable('boolean_attributes', 'checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected autoplay loop controls');
+ nonEmptyElementsMap = createLookupTable('non_empty_elements', 'td th iframe video audio object', shortEndedElementsMap);
+ blockElementsMap = createLookupTable('block_elements', 'h1 h2 h3 h4 h5 h6 hr p div address pre form table tbody thead tfoot ' +
+ 'th tr td li ol ul caption blockquote center dl dt dd dir fieldset ' +
+ 'noscript menu isindex samp header footer article section hgroup aside nav figure option datalist select optgroup');
+
+ // Converts a wildcard expression string to a regexp for example *a will become /.*a/.
+ function patternToRegExp(str) {
+ return new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$');
+ };
+
+ // Parses the specified valid_elements string and adds to the current rules
+ // This function is a bit hard to read since it's heavily optimized for speed
+ function addValidElements(valid_elements) {
+ var ei, el, ai, al, yl, matches, element, attr, attrData, elementName, attrName, attrType, attributes, attributesOrder,
+ prefix, outputName, globalAttributes, globalAttributesOrder, transElement, key, childKey, value,
+ elementRuleRegExp = /^([#+\-])?([^\[\/]+)(?:\/([^\[]+))?(?:\[([^\]]+)\])?$/,
+ attrRuleRegExp = /^([!\-])?(\w+::\w+|[^=:<]+)?(?:([=:<])(.*))?$/,
+ hasPatternsRegExp = /[*?+]/;
+
+ if (valid_elements) {
+ // Split valid elements into an array with rules
+ valid_elements = split(valid_elements);
+
+ if (elements['@']) {
+ globalAttributes = elements['@'].attributes;
+ globalAttributesOrder = elements['@'].attributesOrder;
+ }
+
+ // Loop all rules
+ for (ei = 0, el = valid_elements.length; ei < el; ei++) {
+ // Parse element rule
+ matches = elementRuleRegExp.exec(valid_elements[ei]);
+ if (matches) {
+ // Setup local names for matches
+ prefix = matches[1];
+ elementName = matches[2];
+ outputName = matches[3];
+ attrData = matches[4];
+
+ // Create new attributes and attributesOrder
+ attributes = {};
+ attributesOrder = [];
+
+ // Create the new element
+ element = {
+ attributes : attributes,
+ attributesOrder : attributesOrder
+ };
+
+ // Padd empty elements prefix
+ if (prefix === '#')
+ element.paddEmpty = true;
+
+ // Remove empty elements prefix
+ if (prefix === '-')
+ element.removeEmpty = true;
+
+ // Copy attributes from global rule into current rule
+ if (globalAttributes) {
+ for (key in globalAttributes)
+ attributes[key] = globalAttributes[key];
+
+ attributesOrder.push.apply(attributesOrder, globalAttributesOrder);
+ }
+
+ // Attributes defined
+ if (attrData) {
+ attrData = split(attrData, '|');
+ for (ai = 0, al = attrData.length; ai < al; ai++) {
+ matches = attrRuleRegExp.exec(attrData[ai]);
+ if (matches) {
+ attr = {};
+ attrType = matches[1];
+ attrName = matches[2].replace(/::/g, ':');
+ prefix = matches[3];
+ value = matches[4];
+
+ // Required
+ if (attrType === '!') {
+ element.attributesRequired = element.attributesRequired || [];
+ element.attributesRequired.push(attrName);
+ attr.required = true;
+ }
+
+ // Denied from global
+ if (attrType === '-') {
+ delete attributes[attrName];
+ attributesOrder.splice(tinymce.inArray(attributesOrder, attrName), 1);
+ continue;
+ }
+
+ // Default value
+ if (prefix) {
+ // Default value
+ if (prefix === '=') {
+ element.attributesDefault = element.attributesDefault || [];
+ element.attributesDefault.push({name: attrName, value: value});
+ attr.defaultValue = value;
+ }
+
+ // Forced value
+ if (prefix === ':') {
+ element.attributesForced = element.attributesForced || [];
+ element.attributesForced.push({name: attrName, value: value});
+ attr.forcedValue = value;
+ }
+
+ // Required values
+ if (prefix === '<')
+ attr.validValues = makeMap(value, '?');
+ }
+
+ // Check for attribute patterns
+ if (hasPatternsRegExp.test(attrName)) {
+ element.attributePatterns = element.attributePatterns || [];
+ attr.pattern = patternToRegExp(attrName);
+ element.attributePatterns.push(attr);
+ } else {
+ // Add attribute to order list if it doesn't already exist
+ if (!attributes[attrName])
+ attributesOrder.push(attrName);
+
+ attributes[attrName] = attr;
+ }
+ }
+ }
+ }
+
+ // Global rule, store away these for later usage
+ if (!globalAttributes && elementName == '@') {
+ globalAttributes = attributes;
+ globalAttributesOrder = attributesOrder;
+ }
+
+ // Handle substitute elements such as b/strong
+ if (outputName) {
+ element.outputName = elementName;
+ elements[outputName] = element;
+ }
+
+ // Add pattern or exact element
+ if (hasPatternsRegExp.test(elementName)) {
+ element.pattern = patternToRegExp(elementName);
+ patternElements.push(element);
+ } else
+ elements[elementName] = element;
+ }
+ }
+ }
+ };
+
+ function setValidElements(valid_elements) {
+ elements = {};
+ patternElements = [];
+
+ addValidElements(valid_elements);
+
+ each(schemaItems, function(element, name) {
+ children[name] = element.children;
+ });
+ };
+
+ // Adds custom non HTML elements to the schema
+ function addCustomElements(custom_elements) {
+ var customElementRegExp = /^(~)?(.+)$/;
+
+ if (custom_elements) {
+ each(split(custom_elements), function(rule) {
+ var matches = customElementRegExp.exec(rule),
+ inline = matches[1] === '~',
+ cloneName = inline ? 'span' : 'div',
+ name = matches[2];
+
+ children[name] = children[cloneName];
+ customElementsMap[name] = cloneName;
+
+ // If it's not marked as inline then add it to valid block elements
+ if (!inline)
+ blockElementsMap[name] = {};
+
+ // Add custom elements at span/div positions
+ each(children, function(element, child) {
+ if (element[cloneName])
+ element[name] = element[cloneName];
+ });
+ });
+ }
+ };
+
+ // Adds valid children to the schema object
+ function addValidChildren(valid_children) {
+ var childRuleRegExp = /^([+\-]?)(\w+)\[([^\]]+)\]$/;
+
+ if (valid_children) {
+ each(split(valid_children), function(rule) {
+ var matches = childRuleRegExp.exec(rule), parent, prefix;
+
+ if (matches) {
+ prefix = matches[1];
+
+ // Add/remove items from default
+ if (prefix)
+ parent = children[matches[2]];
+ else
+ parent = children[matches[2]] = {'#comment' : {}};
+
+ parent = children[matches[2]];
+
+ each(split(matches[3], '|'), function(child) {
+ if (prefix === '-')
+ delete parent[child];
+ else
+ parent[child] = {};
+ });
+ }
+ });
+ }
+ };
+
+ function getElementRule(name) {
+ var element = elements[name], i;
+
+ // Exact match found
+ if (element)
+ return element;
+
+ // No exact match then try the patterns
+ i = patternElements.length;
+ while (i--) {
+ element = patternElements[i];
+
+ if (element.pattern.test(name))
+ return element;
+ }
+ };
+
+ if (!settings.valid_elements) {
+ // No valid elements defined then clone the elements from the schema spec
+ each(schemaItems, function(element, name) {
+ elements[name] = {
+ attributes : element.attributes,
+ attributesOrder : element.attributesOrder
+ };
+
+ children[name] = element.children;
+ });
+
+ // Switch these on HTML4
+ if (settings.schema != "html5") {
+ each(split('strong/b,em/i'), function(item) {
+ item = split(item, '/');
+ elements[item[1]].outputName = item[0];
+ });
+ }
+
+ // Add default alt attribute for images
+ elements.img.attributesDefault = [{name: 'alt', value: ''}];
+
+ // Remove these if they are empty by default
+ each(split('ol,ul,sub,sup,blockquote,span,font,a,table,tbody,tr,strong,em,b,i'), function(name) {
+ if (elements[name]) {
+ elements[name].removeEmpty = true;
+ }
+ });
+
+ // Padd these by default
+ each(split('p,h1,h2,h3,h4,h5,h6,th,td,pre,div,address,caption'), function(name) {
+ elements[name].paddEmpty = true;
+ });
+ } else
+ setValidElements(settings.valid_elements);
+
+ addCustomElements(settings.custom_elements);
+ addValidChildren(settings.valid_children);
+ addValidElements(settings.extended_valid_elements);
+
+ // Todo: Remove this when we fix list handling to be valid
+ addValidChildren('+ol[ul|ol],+ul[ul|ol]');
+
+ // Delete invalid elements
+ if (settings.invalid_elements) {
+ tinymce.each(tinymce.explode(settings.invalid_elements), function(item) {
+ if (elements[item])
+ delete elements[item];
+ });
+ }
+
+ // If the user didn't allow span only allow internal spans
+ if (!getElementRule('span'))
+ addValidElements('span[!data-mce-type|*]');
+
+ self.children = children;
+
+ self.styles = validStyles;
+
+ self.getBoolAttrs = function() {
+ return boolAttrMap;
+ };
+
+ self.getBlockElements = function() {
+ return blockElementsMap;
+ };
+
+ self.getShortEndedElements = function() {
+ return shortEndedElementsMap;
+ };
+
+ self.getSelfClosingElements = function() {
+ return selfClosingElementsMap;
+ };
+
+ self.getNonEmptyElements = function() {
+ return nonEmptyElementsMap;
+ };
+
+ self.getWhiteSpaceElements = function() {
+ return whiteSpaceElementsMap;
+ };
+
+ self.isValidChild = function(name, child) {
+ var parent = children[name];
+
+ return !!(parent && parent[child]);
+ };
+
+ self.isValid = function(name, attr) {
+ var attrPatterns, i, rule = getElementRule(name);
+
+ // Check if it's a valid element
+ if (rule) {
+ if (attr) {
+ // Check if attribute name exists
+ if (rule.attributes[attr]) {
+ return true;
+ }
+
+ // Check if attribute matches a regexp pattern
+ attrPatterns = rule.attributePatterns;
+ if (attrPatterns) {
+ i = attrPatterns.length;
+ while (i--) {
+ if (attrPatterns[i].pattern.test(name)) {
+ return true;
+ }
+ }
+ }
+ } else {
+ return true;
+ }
+ }
+
+ // No match
+ return false;
+ };
+
+ self.getElementRule = getElementRule;
+
+ self.getCustomElements = function() {
+ return customElementsMap;
+ };
+
+ self.addValidElements = addValidElements;
+
+ self.setValidElements = setValidElements;
+
+ self.addCustomElements = addCustomElements;
+
+ self.addValidChildren = addValidChildren;
+ };
+})(tinymce);
+
+(function(tinymce) {
+ tinymce.html.SaxParser = function(settings, schema) {
+ var self = this, noop = function() {};
+
+ settings = settings || {};
+ self.schema = schema = schema || new tinymce.html.Schema();
+
+ if (settings.fix_self_closing !== false)
+ settings.fix_self_closing = true;
+
+ // Add handler functions from settings and setup default handlers
+ tinymce.each('comment cdata text start end pi doctype'.split(' '), function(name) {
+ if (name)
+ self[name] = settings[name] || noop;
+ });
+
+ self.parse = function(html) {
+ var self = this, matches, index = 0, value, endRegExp, stack = [], attrList, i, text, name, isInternalElement, removeInternalElements,
+ shortEndedElements, fillAttrsMap, isShortEnded, validate, elementRule, isValidElement, attr, attribsValue, invalidPrefixRegExp,
+ validAttributesMap, validAttributePatterns, attributesRequired, attributesDefault, attributesForced, selfClosing,
+ tokenRegExp, attrRegExp, specialElements, attrValue, idCount = 0, decode = tinymce.html.Entities.decode, fixSelfClosing, isIE;
+
+ function processEndTag(name) {
+ var pos, i;
+
+ // Find position of parent of the same type
+ pos = stack.length;
+ while (pos--) {
+ if (stack[pos].name === name)
+ break;
+ }
+
+ // Found parent
+ if (pos >= 0) {
+ // Close all the open elements
+ for (i = stack.length - 1; i >= pos; i--) {
+ name = stack[i];
+
+ if (name.valid)
+ self.end(name.name);
+ }
+
+ // Remove the open elements from the stack
+ stack.length = pos;
+ }
+ };
+
+ function parseAttribute(match, name, value, val2, val3) {
+ var attrRule, i;
+
+ name = name.toLowerCase();
+ value = name in fillAttrsMap ? name : decode(value || val2 || val3 || ''); // Handle boolean attribute than value attribute
+
+ // Validate name and value
+ if (validate && !isInternalElement && name.indexOf('data-') !== 0) {
+ attrRule = validAttributesMap[name];
+
+ // Find rule by pattern matching
+ if (!attrRule && validAttributePatterns) {
+ i = validAttributePatterns.length;
+ while (i--) {
+ attrRule = validAttributePatterns[i];
+ if (attrRule.pattern.test(name))
+ break;
+ }
+
+ // No rule matched
+ if (i === -1)
+ attrRule = null;
+ }
+
+ // No attribute rule found
+ if (!attrRule)
+ return;
+
+ // Validate value
+ if (attrRule.validValues && !(value in attrRule.validValues))
+ return;
+ }
+
+ // Add attribute to list and map
+ attrList.map[name] = value;
+ attrList.push({
+ name: name,
+ value: value
+ });
+ };
+
+ // Precompile RegExps and map objects
+ tokenRegExp = new RegExp('<(?:' +
+ '(?:!--([\\w\\W]*?)-->)|' + // Comment
+ '(?:!\\[CDATA\\[([\\w\\W]*?)\\]\\]>)|' + // CDATA
+ '(?:!DOCTYPE([\\w\\W]*?)>)|' + // DOCTYPE
+ '(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)|' + // PI
+ '(?:\\/([^>]+)>)|' + // End element
+ '(?:([A-Za-z0-9\\-\\:]+)((?:\\s+[^"\'>]+(?:(?:"[^"]*")|(?:\'[^\']*\')|[^>]*))*|\\/|\\s+)>)' + // Start element
+ ')', 'g');
+
+ attrRegExp = /([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:\\.|[^\"])*)\")|(?:\'((?:\\.|[^\'])*)\')|([^>\s]+)))?/g;
+ specialElements = {
+ 'script' : /<\/script[^>]*>/gi,
+ 'style' : /<\/style[^>]*>/gi,
+ 'noscript' : /<\/noscript[^>]*>/gi
+ };
+
+ // Setup lookup tables for empty elements and boolean attributes
+ shortEndedElements = schema.getShortEndedElements();
+ selfClosing = settings.self_closing_elements || schema.getSelfClosingElements();
+ fillAttrsMap = schema.getBoolAttrs();
+ validate = settings.validate;
+ removeInternalElements = settings.remove_internals;
+ fixSelfClosing = settings.fix_self_closing;
+ isIE = tinymce.isIE;
+ invalidPrefixRegExp = /^:/;
+
+ while (matches = tokenRegExp.exec(html)) {
+ // Text
+ if (index < matches.index)
+ self.text(decode(html.substr(index, matches.index - index)));
+
+ if (value = matches[6]) { // End element
+ value = value.toLowerCase();
+
+ // IE will add a ":" in front of elements it doesn't understand like custom elements or HTML5 elements
+ if (isIE && invalidPrefixRegExp.test(value))
+ value = value.substr(1);
+
+ processEndTag(value);
+ } else if (value = matches[7]) { // Start element
+ value = value.toLowerCase();
+
+ // IE will add a ":" in front of elements it doesn't understand like custom elements or HTML5 elements
+ if (isIE && invalidPrefixRegExp.test(value))
+ value = value.substr(1);
+
+ isShortEnded = value in shortEndedElements;
+
+ // Is self closing tag for example an <li> after an open <li>
+ if (fixSelfClosing && selfClosing[value] && stack.length > 0 && stack[stack.length - 1].name === value)
+ processEndTag(value);
+
+ // Validate element
+ if (!validate || (elementRule = schema.getElementRule(value))) {
+ isValidElement = true;
+
+ // Grab attributes map and patters when validation is enabled
+ if (validate) {
+ validAttributesMap = elementRule.attributes;
+ validAttributePatterns = elementRule.attributePatterns;
+ }
+
+ // Parse attributes
+ if (attribsValue = matches[8]) {
+ isInternalElement = attribsValue.indexOf('data-mce-type') !== -1; // Check if the element is an internal element
+
+ // If the element has internal attributes then remove it if we are told to do so
+ if (isInternalElement && removeInternalElements)
+ isValidElement = false;
+
+ attrList = [];
+ attrList.map = {};
+
+ attribsValue.replace(attrRegExp, parseAttribute);
+ } else {
+ attrList = [];
+ attrList.map = {};
+ }
+
+ // Process attributes if validation is enabled
+ if (validate && !isInternalElement) {
+ attributesRequired = elementRule.attributesRequired;
+ attributesDefault = elementRule.attributesDefault;
+ attributesForced = elementRule.attributesForced;
+
+ // Handle forced attributes
+ if (attributesForced) {
+ i = attributesForced.length;
+ while (i--) {
+ attr = attributesForced[i];
+ name = attr.name;
+ attrValue = attr.value;
+
+ if (attrValue === '{$uid}')
+ attrValue = 'mce_' + idCount++;
+
+ attrList.map[name] = attrValue;
+ attrList.push({name: name, value: attrValue});
+ }
+ }
+
+ // Handle default attributes
+ if (attributesDefault) {
+ i = attributesDefault.length;
+ while (i--) {
+ attr = attributesDefault[i];
+ name = attr.name;
+
+ if (!(name in attrList.map)) {
+ attrValue = attr.value;
+
+ if (attrValue === '{$uid}')
+ attrValue = 'mce_' + idCount++;
+
+ attrList.map[name] = attrValue;
+ attrList.push({name: name, value: attrValue});
+ }
+ }
+ }
+
+ // Handle required attributes
+ if (attributesRequired) {
+ i = attributesRequired.length;
+ while (i--) {
+ if (attributesRequired[i] in attrList.map)
+ break;
+ }
+
+ // None of the required attributes where found
+ if (i === -1)
+ isValidElement = false;
+ }
+
+ // Invalidate element if it's marked as bogus
+ if (attrList.map['data-mce-bogus'])
+ isValidElement = false;
+ }
+
+ if (isValidElement)
+ self.start(value, attrList, isShortEnded);
+ } else
+ isValidElement = false;
+
+ // Treat script, noscript and style a bit different since they may include code that looks like elements
+ if (endRegExp = specialElements[value]) {
+ endRegExp.lastIndex = index = matches.index + matches[0].length;
+
+ if (matches = endRegExp.exec(html)) {
+ if (isValidElement)
+ text = html.substr(index, matches.index - index);
+
+ index = matches.index + matches[0].length;
+ } else {
+ text = html.substr(index);
+ index = html.length;
+ }
+
+ if (isValidElement && text.length > 0)
+ self.text(text, true);
+
+ if (isValidElement)
+ self.end(value);
+
+ tokenRegExp.lastIndex = index;
+ continue;
+ }
+
+ // Push value on to stack
+ if (!isShortEnded) {
+ if (!attribsValue || attribsValue.indexOf('/') != attribsValue.length - 1)
+ stack.push({name: value, valid: isValidElement});
+ else if (isValidElement)
+ self.end(value);
+ }
+ } else if (value = matches[1]) { // Comment
+ self.comment(value);
+ } else if (value = matches[2]) { // CDATA
+ self.cdata(value);
+ } else if (value = matches[3]) { // DOCTYPE
+ self.doctype(value);
+ } else if (value = matches[4]) { // PI
+ self.pi(value, matches[5]);
+ }
+
+ index = matches.index + matches[0].length;
+ }
+
+ // Text
+ if (index < html.length)
+ self.text(decode(html.substr(index)));
+
+ // Close any open elements
+ for (i = stack.length - 1; i >= 0; i--) {
+ value = stack[i];
+
+ if (value.valid)
+ self.end(value.name);
+ }
+ };
+ }
+})(tinymce);
+
+(function(tinymce) {
+ var whiteSpaceRegExp = /^[ \t\r\n]*$/, typeLookup = {
+ '#text' : 3,
+ '#comment' : 8,
+ '#cdata' : 4,
+ '#pi' : 7,
+ '#doctype' : 10,
+ '#document-fragment' : 11
+ };
+
+ // Walks the tree left/right
+ function walk(node, root_node, prev) {
+ var sibling, parent, startName = prev ? 'lastChild' : 'firstChild', siblingName = prev ? 'prev' : 'next';
+
+ // Walk into nodes if it has a start
+ if (node[startName])
+ return node[startName];
+
+ // Return the sibling if it has one
+ if (node !== root_node) {
+ sibling = node[siblingName];
+
+ if (sibling)
+ return sibling;
+
+ // Walk up the parents to look for siblings
+ for (parent = node.parent; parent && parent !== root_node; parent = parent.parent) {
+ sibling = parent[siblingName];
+
+ if (sibling)
+ return sibling;
+ }
+ }
+ };
+
+ function Node(name, type) {
+ this.name = name;
+ this.type = type;
+
+ if (type === 1) {
+ this.attributes = [];
+ this.attributes.map = {};
+ }
+ }
+
+ tinymce.extend(Node.prototype, {
+ replace : function(node) {
+ var self = this;
+
+ if (node.parent)
+ node.remove();
+
+ self.insert(node, self);
+ self.remove();
+
+ return self;
+ },
+
+ attr : function(name, value) {
+ var self = this, attrs, i, undef;
+
+ if (typeof name !== "string") {
+ for (i in name)
+ self.attr(i, name[i]);
+
+ return self;
+ }
+
+ if (attrs = self.attributes) {
+ if (value !== undef) {
+ // Remove attribute
+ if (value === null) {
+ if (name in attrs.map) {
+ delete attrs.map[name];
+
+ i = attrs.length;
+ while (i--) {
+ if (attrs[i].name === name) {
+ attrs = attrs.splice(i, 1);
+ return self;
+ }
+ }
+ }
+
+ return self;
+ }
+
+ // Set attribute
+ if (name in attrs.map) {
+ // Set attribute
+ i = attrs.length;
+ while (i--) {
+ if (attrs[i].name === name) {
+ attrs[i].value = value;
+ break;
+ }
+ }
+ } else
+ attrs.push({name: name, value: value});
+
+ attrs.map[name] = value;
+
+ return self;
+ } else {
+ return attrs.map[name];
+ }
+ }
+ },
+
+ clone : function() {
+ var self = this, clone = new Node(self.name, self.type), i, l, selfAttrs, selfAttr, cloneAttrs;
+
+ // Clone element attributes
+ if (selfAttrs = self.attributes) {
+ cloneAttrs = [];
+ cloneAttrs.map = {};
+
+ for (i = 0, l = selfAttrs.length; i < l; i++) {
+ selfAttr = selfAttrs[i];
+
+ // Clone everything except id
+ if (selfAttr.name !== 'id') {
+ cloneAttrs[cloneAttrs.length] = {name: selfAttr.name, value: selfAttr.value};
+ cloneAttrs.map[selfAttr.name] = selfAttr.value;
+ }
+ }
+
+ clone.attributes = cloneAttrs;
+ }
+
+ clone.value = self.value;
+ clone.shortEnded = self.shortEnded;
+
+ return clone;
+ },
+
+ wrap : function(wrapper) {
+ var self = this;
+
+ self.parent.insert(wrapper, self);
+ wrapper.append(self);
+
+ return self;
+ },
+
+ unwrap : function() {
+ var self = this, node, next;
+
+ for (node = self.firstChild; node; ) {
+ next = node.next;
+ self.insert(node, self, true);
+ node = next;
+ }
+
+ self.remove();
+ },
+
+ remove : function() {
+ var self = this, parent = self.parent, next = self.next, prev = self.prev;
+
+ if (parent) {
+ if (parent.firstChild === self) {
+ parent.firstChild = next;
+
+ if (next)
+ next.prev = null;
+ } else {
+ prev.next = next;
+ }
+
+ if (parent.lastChild === self) {
+ parent.lastChild = prev;
+
+ if (prev)
+ prev.next = null;
+ } else {
+ next.prev = prev;
+ }
+
+ self.parent = self.next = self.prev = null;
+ }
+
+ return self;
+ },
+
+ append : function(node) {
+ var self = this, last;
+
+ if (node.parent)
+ node.remove();
+
+ last = self.lastChild;
+ if (last) {
+ last.next = node;
+ node.prev = last;
+ self.lastChild = node;
+ } else
+ self.lastChild = self.firstChild = node;
+
+ node.parent = self;
+
+ return node;
+ },
+
+ insert : function(node, ref_node, before) {
+ var parent;
+
+ if (node.parent)
+ node.remove();
+
+ parent = ref_node.parent || this;
+
+ if (before) {
+ if (ref_node === parent.firstChild)
+ parent.firstChild = node;
+ else
+ ref_node.prev.next = node;
+
+ node.prev = ref_node.prev;
+ node.next = ref_node;
+ ref_node.prev = node;
+ } else {
+ if (ref_node === parent.lastChild)
+ parent.lastChild = node;
+ else
+ ref_node.next.prev = node;
+
+ node.next = ref_node.next;
+ node.prev = ref_node;
+ ref_node.next = node;
+ }
+
+ node.parent = parent;
+
+ return node;
+ },
+
+ getAll : function(name) {
+ var self = this, node, collection = [];
+
+ for (node = self.firstChild; node; node = walk(node, self)) {
+ if (node.name === name)
+ collection.push(node);
+ }
+
+ return collection;
+ },
+
+ empty : function() {
+ var self = this, nodes, i, node;
+
+ // Remove all children
+ if (self.firstChild) {
+ nodes = [];
+
+ // Collect the children
+ for (node = self.firstChild; node; node = walk(node, self))
+ nodes.push(node);
+
+ // Remove the children
+ i = nodes.length;
+ while (i--) {
+ node = nodes[i];
+ node.parent = node.firstChild = node.lastChild = node.next = node.prev = null;
+ }
+ }
+
+ self.firstChild = self.lastChild = null;
+
+ return self;
+ },
+
+ isEmpty : function(elements) {
+ var self = this, node = self.firstChild, i, name;
+
+ if (node) {
+ do {
+ if (node.type === 1) {
+ // Ignore bogus elements
+ if (node.attributes.map['data-mce-bogus'])
+ continue;
+
+ // Keep empty elements like <img />
+ if (elements[node.name])
+ return false;
+
+ // Keep elements with data attributes or name attribute like <a name="1"></a>
+ i = node.attributes.length;
+ while (i--) {
+ name = node.attributes[i].name;
+ if (name === "name" || name.indexOf('data-') === 0)
+ return false;
+ }
+ }
+
+ // Keep comments
+ if (node.type === 8)
+ return false;
+
+ // Keep non whitespace text nodes
+ if ((node.type === 3 && !whiteSpaceRegExp.test(node.value)))
+ return false;
+ } while (node = walk(node, self));
+ }
+
+ return true;
+ },
+
+ walk : function(prev) {
+ return walk(this, null, prev);
+ }
+ });
+
+ tinymce.extend(Node, {
+ create : function(name, attrs) {
+ var node, attrName;
+
+ // Create node
+ node = new Node(name, typeLookup[name] || 1);
+
+ // Add attributes if needed
+ if (attrs) {
+ for (attrName in attrs)
+ node.attr(attrName, attrs[attrName]);
+ }
+
+ return node;
+ }
+ });
+
+ tinymce.html.Node = Node;
+})(tinymce);
+
+(function(tinymce) {
+ var Node = tinymce.html.Node;
+
+ tinymce.html.DomParser = function(settings, schema) {
+ var self = this, nodeFilters = {}, attributeFilters = [], matchedNodes = {}, matchedAttributes = {};
+
+ settings = settings || {};
+ settings.validate = "validate" in settings ? settings.validate : true;
+ settings.root_name = settings.root_name || 'body';
+ self.schema = schema = schema || new tinymce.html.Schema();
+
+ function fixInvalidChildren(nodes) {
+ var ni, node, parent, parents, newParent, currentNode, tempNode, childNode, i,
+ childClone, nonEmptyElements, nonSplitableElements, sibling, nextNode;
+
+ nonSplitableElements = tinymce.makeMap('tr,td,th,tbody,thead,tfoot,table');
+ nonEmptyElements = schema.getNonEmptyElements();
+
+ for (ni = 0; ni < nodes.length; ni++) {
+ node = nodes[ni];
+
+ // Already removed
+ if (!node.parent)
+ continue;
+
+ // Get list of all parent nodes until we find a valid parent to stick the child into
+ parents = [node];
+ for (parent = node.parent; parent && !schema.isValidChild(parent.name, node.name) && !nonSplitableElements[parent.name]; parent = parent.parent)
+ parents.push(parent);
+
+ // Found a suitable parent
+ if (parent && parents.length > 1) {
+ // Reverse the array since it makes looping easier
+ parents.reverse();
+
+ // Clone the related parent and insert that after the moved node
+ newParent = currentNode = self.filterNode(parents[0].clone());
+
+ // Start cloning and moving children on the left side of the target node
+ for (i = 0; i < parents.length - 1; i++) {
+ if (schema.isValidChild(currentNode.name, parents[i].name)) {
+ tempNode = self.filterNode(parents[i].clone());
+ currentNode.append(tempNode);
+ } else
+ tempNode = currentNode;
+
+ for (childNode = parents[i].firstChild; childNode && childNode != parents[i + 1]; ) {
+ nextNode = childNode.next;
+ tempNode.append(childNode);
+ childNode = nextNode;
+ }
+
+ currentNode = tempNode;
+ }
+
+ if (!newParent.isEmpty(nonEmptyElements)) {
+ parent.insert(newParent, parents[0], true);
+ parent.insert(node, newParent);
+ } else {
+ parent.insert(node, parents[0], true);
+ }
+
+ // Check if the element is empty by looking through it's contents and special treatment for <p><br /></p>
+ parent = parents[0];
+ if (parent.isEmpty(nonEmptyElements) || parent.firstChild === parent.lastChild && parent.firstChild.name === 'br') {
+ parent.empty().remove();
+ }
+ } else if (node.parent) {
+ // If it's an LI try to find a UL/OL for it or wrap it
+ if (node.name === 'li') {
+ sibling = node.prev;
+ if (sibling && (sibling.name === 'ul' || sibling.name === 'ul')) {
+ sibling.append(node);
+ continue;
+ }
+
+ sibling = node.next;
+ if (sibling && (sibling.name === 'ul' || sibling.name === 'ul')) {
+ sibling.insert(node, sibling.firstChild, true);
+ continue;
+ }
+
+ node.wrap(self.filterNode(new Node('ul', 1)));
+ continue;
+ }
+
+ // Try wrapping the element in a DIV
+ if (schema.isValidChild(node.parent.name, 'div') && schema.isValidChild('div', node.name)) {
+ node.wrap(self.filterNode(new Node('div', 1)));
+ } else {
+ // We failed wrapping it, then remove or unwrap it
+ if (node.name === 'style' || node.name === 'script')
+ node.empty().remove();
+ else
+ node.unwrap();
+ }
+ }
+ }
+ };
+
+ self.filterNode = function(node) {
+ var i, name, list;
+
+ // Run element filters
+ if (name in nodeFilters) {
+ list = matchedNodes[name];
+
+ if (list)
+ list.push(node);
+ else
+ matchedNodes[name] = [node];
+ }
+
+ // Run attribute filters
+ i = attributeFilters.length;
+ while (i--) {
+ name = attributeFilters[i].name;
+
+ if (name in node.attributes.map) {
+ list = matchedAttributes[name];
+
+ if (list)
+ list.push(node);
+ else
+ matchedAttributes[name] = [node];
+ }
+ }
+
+ return node;
+ };
+
+ self.addNodeFilter = function(name, callback) {
+ tinymce.each(tinymce.explode(name), function(name) {
+ var list = nodeFilters[name];
+
+ if (!list)
+ nodeFilters[name] = list = [];
+
+ list.push(callback);
+ });
+ };
+
+ self.addAttributeFilter = function(name, callback) {
+ tinymce.each(tinymce.explode(name), function(name) {
+ var i;
+
+ for (i = 0; i < attributeFilters.length; i++) {
+ if (attributeFilters[i].name === name) {
+ attributeFilters[i].callbacks.push(callback);
+ return;
+ }
+ }
+
+ attributeFilters.push({name: name, callbacks: [callback]});
+ });
+ };
+
+ self.parse = function(html, args) {
+ var parser, rootNode, node, nodes, i, l, fi, fl, list, name, validate,
+ blockElements, startWhiteSpaceRegExp, invalidChildren = [], isInWhiteSpacePreservedElement,
+ endWhiteSpaceRegExp, allWhiteSpaceRegExp, isAllWhiteSpaceRegExp, whiteSpaceElements, children, nonEmptyElements, rootBlockName;
+
+ args = args || {};
+ matchedNodes = {};
+ matchedAttributes = {};
+ blockElements = tinymce.extend(tinymce.makeMap('script,style,head,html,body,title,meta,param'), schema.getBlockElements());
+ nonEmptyElements = schema.getNonEmptyElements();
+ children = schema.children;
+ validate = settings.validate;
+ rootBlockName = "forced_root_block" in args ? args.forced_root_block : settings.forced_root_block;
+
+ whiteSpaceElements = schema.getWhiteSpaceElements();
+ startWhiteSpaceRegExp = /^[ \t\r\n]+/;
+ endWhiteSpaceRegExp = /[ \t\r\n]+$/;
+ allWhiteSpaceRegExp = /[ \t\r\n]+/g;
+ isAllWhiteSpaceRegExp = /^[ \t\r\n]+$/;
+
+ function addRootBlocks() {
+ var node = rootNode.firstChild, next, rootBlockNode;
+
+ while (node) {
+ next = node.next;
+
+ if (node.type == 3 || (node.type == 1 && node.name !== 'p' && !blockElements[node.name] && !node.attr('data-mce-type'))) {
+ if (!rootBlockNode) {
+ // Create a new root block element
+ rootBlockNode = createNode(rootBlockName, 1);
+ rootNode.insert(rootBlockNode, node);
+ rootBlockNode.append(node);
+ } else
+ rootBlockNode.append(node);
+ } else {
+ rootBlockNode = null;
+ }
+
+ node = next;
+ };
+ };
+
+ function createNode(name, type) {
+ var node = new Node(name, type), list;
+
+ if (name in nodeFilters) {
+ list = matchedNodes[name];
+
+ if (list)
+ list.push(node);
+ else
+ matchedNodes[name] = [node];
+ }
+
+ return node;
+ };
+
+ function removeWhitespaceBefore(node) {
+ var textNode, textVal, sibling;
+
+ for (textNode = node.prev; textNode && textNode.type === 3; ) {
+ textVal = textNode.value.replace(endWhiteSpaceRegExp, '');
+
+ if (textVal.length > 0) {
+ textNode.value = textVal;
+ textNode = textNode.prev;
+ } else {
+ sibling = textNode.prev;
+ textNode.remove();
+ textNode = sibling;
+ }
+ }
+ };
+
+ function cloneAndExcludeBlocks(input) {
+ var name, output = {};
+
+ for (name in input) {
+ if (name !== 'li' && name != 'p') {
+ output[name] = input[name];
+ }
+ }
+
+ return output;
+ };
+
+ parser = new tinymce.html.SaxParser({
+ validate : validate,
+
+ // Exclude P and LI from DOM parsing since it's treated better by the DOM parser
+ self_closing_elements: cloneAndExcludeBlocks(schema.getSelfClosingElements()),
+
+ cdata: function(text) {
+ node.append(createNode('#cdata', 4)).value = text;
+ },
+
+ text: function(text, raw) {
+ var textNode;
+
+ // Trim all redundant whitespace on non white space elements
+ if (!isInWhiteSpacePreservedElement) {
+ text = text.replace(allWhiteSpaceRegExp, ' ');
+
+ if (node.lastChild && blockElements[node.lastChild.name])
+ text = text.replace(startWhiteSpaceRegExp, '');
+ }
+
+ // Do we need to create the node
+ if (text.length !== 0) {
+ textNode = createNode('#text', 3);
+ textNode.raw = !!raw;
+ node.append(textNode).value = text;
+ }
+ },
+
+ comment: function(text) {
+ node.append(createNode('#comment', 8)).value = text;
+ },
+
+ pi: function(name, text) {
+ node.append(createNode(name, 7)).value = text;
+ removeWhitespaceBefore(node);
+ },
+
+ doctype: function(text) {
+ var newNode;
+
+ newNode = node.append(createNode('#doctype', 10));
+ newNode.value = text;
+ removeWhitespaceBefore(node);
+ },
+
+ start: function(name, attrs, empty) {
+ var newNode, attrFiltersLen, elementRule, textNode, attrName, text, sibling, parent;
+
+ elementRule = validate ? schema.getElementRule(name) : {};
+ if (elementRule) {
+ newNode = createNode(elementRule.outputName || name, 1);
+ newNode.attributes = attrs;
+ newNode.shortEnded = empty;
+
+ node.append(newNode);
+
+ // Check if node is valid child of the parent node is the child is
+ // unknown we don't collect it since it's probably a custom element
+ parent = children[node.name];
+ if (parent && children[newNode.name] && !parent[newNode.name])
+ invalidChildren.push(newNode);
+
+ attrFiltersLen = attributeFilters.length;
+ while (attrFiltersLen--) {
+ attrName = attributeFilters[attrFiltersLen].name;
+
+ if (attrName in attrs.map) {
+ list = matchedAttributes[attrName];
+
+ if (list)
+ list.push(newNode);
+ else
+ matchedAttributes[attrName] = [newNode];
+ }
+ }
+
+ // Trim whitespace before block
+ if (blockElements[name])
+ removeWhitespaceBefore(newNode);
+
+ // Change current node if the element wasn't empty i.e not <br /> or <img />
+ if (!empty)
+ node = newNode;
+
+ // Check if we are inside a whitespace preserved element
+ if (!isInWhiteSpacePreservedElement && whiteSpaceElements[name]) {
+ isInWhiteSpacePreservedElement = true;
+ }
+ }
+ },
+
+ end: function(name) {
+ var textNode, elementRule, text, sibling, tempNode;
+
+ elementRule = validate ? schema.getElementRule(name) : {};
+ if (elementRule) {
+ if (blockElements[name]) {
+ if (!isInWhiteSpacePreservedElement) {
+ // Trim whitespace of the first node in a block
+ textNode = node.firstChild;
+ if (textNode && textNode.type === 3) {
+ text = textNode.value.replace(startWhiteSpaceRegExp, '');
+
+ // Any characters left after trim or should we remove it
+ if (text.length > 0) {
+ textNode.value = text;
+ textNode = textNode.next;
+ } else {
+ sibling = textNode.next;
+ textNode.remove();
+ textNode = sibling;
+ }
+
+ // Remove any pure whitespace siblings
+ while (textNode && textNode.type === 3) {
+ text = textNode.value;
+ sibling = textNode.next;
+
+ if (text.length === 0 || isAllWhiteSpaceRegExp.test(text)) {
+ textNode.remove();
+ textNode = sibling;
+ }
+
+ textNode = sibling;
+ }
+ }
+
+ // Trim whitespace of the last node in a block
+ textNode = node.lastChild;
+ if (textNode && textNode.type === 3) {
+ text = textNode.value.replace(endWhiteSpaceRegExp, '');
+
+ // Any characters left after trim or should we remove it
+ if (text.length > 0) {
+ textNode.value = text;
+ textNode = textNode.prev;
+ } else {
+ sibling = textNode.prev;
+ textNode.remove();
+ textNode = sibling;
+ }
+
+ // Remove any pure whitespace siblings
+ while (textNode && textNode.type === 3) {
+ text = textNode.value;
+ sibling = textNode.prev;
+
+ if (text.length === 0 || isAllWhiteSpaceRegExp.test(text)) {
+ textNode.remove();
+ textNode = sibling;
+ }
+
+ textNode = sibling;
+ }
+ }
+ }
+
+ // Trim start white space
+ textNode = node.prev;
+ if (textNode && textNode.type === 3) {
+ text = textNode.value.replace(startWhiteSpaceRegExp, '');
+
+ if (text.length > 0)
+ textNode.value = text;
+ else
+ textNode.remove();
+ }
+ }
+
+ // Check if we exited a whitespace preserved element
+ if (isInWhiteSpacePreservedElement && whiteSpaceElements[name]) {
+ isInWhiteSpacePreservedElement = false;
+ }
+
+ // Handle empty nodes
+ if (elementRule.removeEmpty || elementRule.paddEmpty) {
+ if (node.isEmpty(nonEmptyElements)) {
+ if (elementRule.paddEmpty)
+ node.empty().append(new Node('#text', '3')).value = '\u00a0';
+ else {
+ // Leave nodes that have a name like <a name="name">
+ if (!node.attributes.map.name && !node.attributes.map.id) {
+ tempNode = node.parent;
+ node.empty().remove();
+ node = tempNode;
+ return;
+ }
+ }
+ }
+ }
+
+ node = node.parent;
+ }
+ }
+ }, schema);
+
+ rootNode = node = new Node(args.context || settings.root_name, 11);
+
+ parser.parse(html);
+
+ // Fix invalid children or report invalid children in a contextual parsing
+ if (validate && invalidChildren.length) {
+ if (!args.context)
+ fixInvalidChildren(invalidChildren);
+ else
+ args.invalid = true;
+ }
+
+ // Wrap nodes in the root into block elements if the root is body
+ if (rootBlockName && rootNode.name == 'body')
+ addRootBlocks();
+
+ // Run filters only when the contents is valid
+ if (!args.invalid) {
+ // Run node filters
+ for (name in matchedNodes) {
+ list = nodeFilters[name];
+ nodes = matchedNodes[name];
+
+ // Remove already removed children
+ fi = nodes.length;
+ while (fi--) {
+ if (!nodes[fi].parent)
+ nodes.splice(fi, 1);
+ }
+
+ for (i = 0, l = list.length; i < l; i++)
+ list[i](nodes, name, args);
+ }
+
+ // Run attribute filters
+ for (i = 0, l = attributeFilters.length; i < l; i++) {
+ list = attributeFilters[i];
+
+ if (list.name in matchedAttributes) {
+ nodes = matchedAttributes[list.name];
+
+ // Remove already removed children
+ fi = nodes.length;
+ while (fi--) {
+ if (!nodes[fi].parent)
+ nodes.splice(fi, 1);
+ }
+
+ for (fi = 0, fl = list.callbacks.length; fi < fl; fi++)
+ list.callbacks[fi](nodes, list.name, args);
+ }
+ }
+ }
+
+ return rootNode;
+ };
+
+ // Remove <br> at end of block elements Gecko and WebKit injects BR elements to
+ // make it possible to place the caret inside empty blocks. This logic tries to remove
+ // these elements and keep br elements that where intended to be there intact
+ if (settings.remove_trailing_brs) {
+ self.addNodeFilter('br', function(nodes, name) {
+ var i, l = nodes.length, node, blockElements = tinymce.extend({}, schema.getBlockElements()),
+ nonEmptyElements = schema.getNonEmptyElements(), parent, lastParent, prev, prevName;
+
+ // Remove brs from body element as well
+ blockElements.body = 1;
+
+ // Must loop forwards since it will otherwise remove all brs in <p>a<br><br><br></p>
+ for (i = 0; i < l; i++) {
+ node = nodes[i];
+ parent = node.parent;
+
+ if (blockElements[node.parent.name] && node === parent.lastChild) {
+ // Loop all nodes to the left of the current node and check for other BR elements
+ // excluding bookmarks since they are invisible
+ prev = node.prev;
+ while (prev) {
+ prevName = prev.name;
+
+ // Ignore bookmarks
+ if (prevName !== "span" || prev.attr('data-mce-type') !== 'bookmark') {
+ // Found a non BR element
+ if (prevName !== "br")
+ break;
+
+ // Found another br it's a <br><br> structure then don't remove anything
+ if (prevName === 'br') {
+ node = null;
+ break;
+ }
+ }
+
+ prev = prev.prev;
+ }
+
+ if (node) {
+ node.remove();
+
+ // Is the parent to be considered empty after we removed the BR
+ if (parent.isEmpty(nonEmptyElements)) {
+ elementRule = schema.getElementRule(parent.name);
+
+ // Remove or padd the element depending on schema rule
+ if (elementRule) {
+ if (elementRule.removeEmpty)
+ parent.remove();
+ else if (elementRule.paddEmpty)
+ parent.empty().append(new tinymce.html.Node('#text', 3)).value = '\u00a0';
+ }
+ }
+ }
+ } else {
+ // Replaces BR elements inside inline elements like <p><b><i><br></i></b></p> so they become <p><b><i>&nbsp;</i></b></p>
+ lastParent = node;
+ while (parent.firstChild === lastParent && parent.lastChild === lastParent) {
+ lastParent = parent;
+
+ if (blockElements[parent.name]) {
+ break;
+ }
+
+ parent = parent.parent;
+ }
+
+ if (lastParent === parent) {
+ textNode = new tinymce.html.Node('#text', 3);
+ textNode.value = '\u00a0';
+ node.replace(textNode);
+ }
+ }
+ }
+ });
+ }
+
+ // Force anchor names closed, unless the setting "allow_html_in_named_anchor" is explicitly included.
+ if (!settings.allow_html_in_named_anchor) {
+ self.addAttributeFilter('id,name', function(nodes, name) {
+ var i = nodes.length, sibling, prevSibling, parent, node;
+
+ while (i--) {
+ node = nodes[i];
+ if (node.name === 'a' && node.firstChild && !node.attr('href')) {
+ parent = node.parent;
+
+ // Move children after current node
+ sibling = node.lastChild;
+ do {
+ prevSibling = sibling.prev;
+ parent.insert(sibling, node);
+ sibling = prevSibling;
+ } while (sibling);
+ }
+ }
+ });
+ }
+ }
+})(tinymce);
+
+tinymce.html.Writer = function(settings) {
+ var html = [], indent, indentBefore, indentAfter, encode, htmlOutput;
+
+ settings = settings || {};
+ indent = settings.indent;
+ indentBefore = tinymce.makeMap(settings.indent_before || '');
+ indentAfter = tinymce.makeMap(settings.indent_after || '');
+ encode = tinymce.html.Entities.getEncodeFunc(settings.entity_encoding || 'raw', settings.entities);
+ htmlOutput = settings.element_format == "html";
+
+ return {
+ start: function(name, attrs, empty) {
+ var i, l, attr, value;
+
+ if (indent && indentBefore[name] && html.length > 0) {
+ value = html[html.length - 1];
+
+ if (value.length > 0 && value !== '\n')
+ html.push('\n');
+ }
+
+ html.push('<', name);
+
+ if (attrs) {
+ for (i = 0, l = attrs.length; i < l; i++) {
+ attr = attrs[i];
+ html.push(' ', attr.name, '="', encode(attr.value, true), '"');
+ }
+ }
+
+ if (!empty || htmlOutput)
+ html[html.length] = '>';
+ else
+ html[html.length] = ' />';
+
+ if (empty && indent && indentAfter[name] && html.length > 0) {
+ value = html[html.length - 1];
+
+ if (value.length > 0 && value !== '\n')
+ html.push('\n');
+ }
+ },
+
+ end: function(name) {
+ var value;
+
+ /*if (indent && indentBefore[name] && html.length > 0) {
+ value = html[html.length - 1];
+
+ if (value.length > 0 && value !== '\n')
+ html.push('\n');
+ }*/
+
+ html.push('</', name, '>');
+
+ if (indent && indentAfter[name] && html.length > 0) {
+ value = html[html.length - 1];
+
+ if (value.length > 0 && value !== '\n')
+ html.push('\n');
+ }
+ },
+
+ text: function(text, raw) {
+ if (text.length > 0)
+ html[html.length] = raw ? text : encode(text);
+ },
+
+ cdata: function(text) {
+ html.push('<![CDATA[', text, ']]>');
+ },
+
+ comment: function(text) {
+ html.push('<!--', text, '-->');
+ },
+
+ pi: function(name, text) {
+ if (text)
+ html.push('<?', name, ' ', text, '?>');
+ else
+ html.push('<?', name, '?>');
+
+ if (indent)
+ html.push('\n');
+ },
+
+ doctype: function(text) {
+ html.push('<!DOCTYPE', text, '>', indent ? '\n' : '');
+ },
+
+ reset: function() {
+ html.length = 0;
+ },
+
+ getContent: function() {
+ return html.join('').replace(/\n$/, '');
+ }
+ };
+};
+
+(function(tinymce) {
+ tinymce.html.Serializer = function(settings, schema) {
+ var self = this, writer = new tinymce.html.Writer(settings);
+
+ settings = settings || {};
+ settings.validate = "validate" in settings ? settings.validate : true;
+
+ self.schema = schema = schema || new tinymce.html.Schema();
+ self.writer = writer;
+
+ self.serialize = function(node) {
+ var handlers, validate;
+
+ validate = settings.validate;
+
+ handlers = {
+ // #text
+ 3: function(node, raw) {
+ writer.text(node.value, node.raw);
+ },
+
+ // #comment
+ 8: function(node) {
+ writer.comment(node.value);
+ },
+
+ // Processing instruction
+ 7: function(node) {
+ writer.pi(node.name, node.value);
+ },
+
+ // Doctype
+ 10: function(node) {
+ writer.doctype(node.value);
+ },
+
+ // CDATA
+ 4: function(node) {
+ writer.cdata(node.value);
+ },
+
+ // Document fragment
+ 11: function(node) {
+ if ((node = node.firstChild)) {
+ do {
+ walk(node);
+ } while (node = node.next);
+ }
+ }
+ };
+
+ writer.reset();
+
+ function walk(node) {
+ var handler = handlers[node.type], name, isEmpty, attrs, attrName, attrValue, sortedAttrs, i, l, elementRule;
+
+ if (!handler) {
+ name = node.name;
+ isEmpty = node.shortEnded;
+ attrs = node.attributes;
+
+ // Sort attributes
+ if (validate && attrs && attrs.length > 1) {
+ sortedAttrs = [];
+ sortedAttrs.map = {};
+
+ elementRule = schema.getElementRule(node.name);
+ for (i = 0, l = elementRule.attributesOrder.length; i < l; i++) {
+ attrName = elementRule.attributesOrder[i];
+
+ if (attrName in attrs.map) {
+ attrValue = attrs.map[attrName];
+ sortedAttrs.map[attrName] = attrValue;
+ sortedAttrs.push({name: attrName, value: attrValue});
+ }
+ }
+
+ for (i = 0, l = attrs.length; i < l; i++) {
+ attrName = attrs[i].name;
+
+ if (!(attrName in sortedAttrs.map)) {
+ attrValue = attrs.map[attrName];
+ sortedAttrs.map[attrName] = attrValue;
+ sortedAttrs.push({name: attrName, value: attrValue});
+ }
+ }
+
+ attrs = sortedAttrs;
+ }
+
+ writer.start(node.name, attrs, isEmpty);
+
+ if (!isEmpty) {
+ if ((node = node.firstChild)) {
+ do {
+ walk(node);
+ } while (node = node.next);
+ }
+
+ writer.end(name);
+ }
+ } else
+ handler(node);
+ }
+
+ // Serialize element and treat all non elements as fragments
+ if (node.type == 1 && !settings.inner)
+ walk(node);
+ else
+ handlers[11](node);
+
+ return writer.getContent();
+ };
+ }
+})(tinymce);
+
+// JSLint defined globals
+/*global tinymce:false, window:false */
+
+tinymce.dom = {};
+
+(function(namespace, expando) {
+ var w3cEventModel = !!document.addEventListener;
+
+ function addEvent(target, name, callback, capture) {
+ if (target.addEventListener) {
+ target.addEventListener(name, callback, capture || false);
+ } else if (target.attachEvent) {
+ target.attachEvent('on' + name, callback);
+ }
+ }
+
+ function removeEvent(target, name, callback, capture) {
+ if (target.removeEventListener) {
+ target.removeEventListener(name, callback, capture || false);
+ } else if (target.detachEvent) {
+ target.detachEvent('on' + name, callback);
+ }
+ }
+
+ function fix(original_event, data) {
+ var name, event = data || {};
+
+ // Dummy function that gets replaced on the delegation state functions
+ function returnFalse() {
+ return false;
+ }
+
+ // Dummy function that gets replaced on the delegation state functions
+ function returnTrue() {
+ return true;
+ }
+
+ // Copy all properties from the original event
+ for (name in original_event) {
+ // layerX/layerY is deprecated in Chrome and produces a warning
+ if (name !== "layerX" && name !== "layerY") {
+ event[name] = original_event[name];
+ }
+ }
+
+ // Normalize target IE uses srcElement
+ if (!event.target) {
+ event.target = event.srcElement || document;
+ }
+
+ // Add preventDefault method
+ event.preventDefault = function() {
+ event.isDefaultPrevented = returnTrue;
+
+ // Execute preventDefault on the original event object
+ if (original_event) {
+ if (original_event.preventDefault) {
+ original_event.preventDefault();
+ } else {
+ original_event.returnValue = false; // IE
+ }
+ }
+ };
+
+ // Add stopPropagation
+ event.stopPropagation = function() {
+ event.isPropagationStopped = returnTrue;
+
+ // Execute stopPropagation on the original event object
+ if (original_event) {
+ if (original_event.stopPropagation) {
+ original_event.stopPropagation();
+ } else {
+ original_event.cancelBubble = true; // IE
+ }
+ }
+ };
+
+ // Add stopImmediatePropagation
+ event.stopImmediatePropagation = function() {
+ event.isImmediatePropagationStopped = returnTrue;
+ event.stopPropagation();
+ };
+
+ // Add event delegation states
+ if (!event.isDefaultPrevented) {
+ event.isDefaultPrevented = returnFalse;
+ event.isPropagationStopped = returnFalse;
+ event.isImmediatePropagationStopped = returnFalse;
+ }
+
+ return event;
+ }
+
+ function bindOnReady(win, callback, event_utils) {
+ var doc = win.document, event = {type: 'ready'};
+
+ // Gets called when the DOM is ready
+ function readyHandler() {
+ if (!event_utils.domLoaded) {
+ event_utils.domLoaded = true;
+ callback(event);
+ }
+ }
+
+ // Use W3C method
+ if (w3cEventModel) {
+ addEvent(win, 'DOMContentLoaded', readyHandler);
+ } else {
+ // Use IE method
+ addEvent(doc, "readystatechange", function() {
+ if (doc.readyState === "complete") {
+ removeEvent(doc, "readystatechange", arguments.callee);
+ readyHandler();
+ }
+ });
+
+ // Wait until we can scroll, when we can the DOM is initialized
+ if (doc.documentElement.doScroll && win === win.top) {
+ (function() {
+ try {
+ // If IE is used, use the trick by Diego Perini licensed under MIT by request to the author.
+ // http://javascript.nwbox.com/IEContentLoaded/
+ doc.documentElement.doScroll("left");
+ } catch (ex) {
+ setTimeout(arguments.callee, 0);
+ return;
+ }
+
+ readyHandler();
+ })();
+ }
+ }
+
+ // Fallback if any of the above methods should fail for some odd reason
+ addEvent(win, 'load', readyHandler);
+ }
+
+ function EventUtils(proxy) {
+ var self = this, events = {}, count, isFocusBlurBound, hasFocusIn, hasMouseEnterLeave, mouseEnterLeave;
+
+ hasMouseEnterLeave = "onmouseenter" in document.documentElement;
+ hasFocusIn = "onfocusin" in document.documentElement;
+ mouseEnterLeave = {mouseenter: 'mouseover', mouseleave: 'mouseout'};
+ count = 1;
+
+ // State if the DOMContentLoaded was executed or not
+ self.domLoaded = false;
+ self.events = events;
+
+ function executeHandlers(evt, id) {
+ var callbackList, i, l, callback;
+
+ callbackList = events[id][evt.type];
+ if (callbackList) {
+ for (i = 0, l = callbackList.length; i < l; i++) {
+ callback = callbackList[i];
+
+ // Check if callback exists might be removed if a unbind is called inside the callback
+ if (callback && callback.func.call(callback.scope, evt) === false) {
+ evt.preventDefault();
+ }
+
+ // Should we stop propagation to immediate listeners
+ if (evt.isImmediatePropagationStopped()) {
+ return;
+ }
+ }
+ }
+ }
+
+ self.bind = function(target, names, callback, scope) {
+ var id, callbackList, i, name, fakeName, nativeHandler, capture, win = window;
+
+ // Native event handler function patches the event and executes the callbacks for the expando
+ function defaultNativeHandler(evt) {
+ executeHandlers(fix(evt || win.event), id);
+ }
+
+ // Don't bind to text nodes or comments
+ if (!target || target.nodeType === 3 || target.nodeType === 8) {
+ return;
+ }
+
+ // Create or get events id for the target
+ if (!target[expando]) {
+ id = count++;
+ target[expando] = id;
+ events[id] = {};
+ } else {
+ id = target[expando];
+
+ if (!events[id]) {
+ events[id] = {};
+ }
+ }
+
+ // Setup the specified scope or use the target as a default
+ scope = scope || target;
+
+ // Split names and bind each event, enables you to bind multiple events with one call
+ names = names.split(' ');
+ i = names.length;
+ while (i--) {
+ name = names[i];
+ nativeHandler = defaultNativeHandler;
+ fakeName = capture = false;
+
+ // Use ready instead of DOMContentLoaded
+ if (name === "DOMContentLoaded") {
+ name = "ready";
+ }
+
+ // DOM is already ready
+ if ((self.domLoaded || target.readyState == 'complete') && name === "ready") {
+ self.domLoaded = true;
+ callback.call(scope, fix({type: name}));
+ continue;
+ }
+
+ // Handle mouseenter/mouseleaver
+ if (!hasMouseEnterLeave) {
+ fakeName = mouseEnterLeave[name];
+
+ if (fakeName) {
+ nativeHandler = function(evt) {
+ var current, related;
+
+ current = evt.currentTarget;
+ related = evt.relatedTarget;
+
+ // Check if related is inside the current target if it's not then the event should be ignored since it's a mouseover/mouseout inside the element
+ if (related && current.contains) {
+ // Use contains for performance
+ related = current.contains(related);
+ } else {
+ while (related && related !== current) {
+ related = related.parentNode;
+ }
+ }
+
+ // Fire fake event
+ if (!related) {
+ evt = fix(evt || win.event);
+ evt.type = evt.type === 'mouseout' ? 'mouseleave' : 'mouseenter';
+ evt.target = current;
+ executeHandlers(evt, id);
+ }
+ };
+ }
+ }
+
+ // Fake bubbeling of focusin/focusout
+ if (!hasFocusIn && (name === "focusin" || name === "focusout")) {
+ capture = true;
+ fakeName = name === "focusin" ? "focus" : "blur";
+ nativeHandler = function(evt) {
+ evt = fix(evt || win.event);
+ evt.type = evt.type === 'focus' ? 'focusin' : 'focusout';
+ executeHandlers(evt, id);
+ };
+ }
+
+ // Setup callback list and bind native event
+ callbackList = events[id][name];
+ if (!callbackList) {
+ events[id][name] = callbackList = [{func: callback, scope: scope}];
+ callbackList.fakeName = fakeName;
+ callbackList.capture = capture;
+
+ // Add the nativeHandler to the callback list so that we can later unbind it
+ callbackList.nativeHandler = nativeHandler;
+ if (!w3cEventModel) {
+ callbackList.proxyHandler = proxy(id);
+ }
+
+ // Check if the target has native events support
+ if (name === "ready") {
+ bindOnReady(target, nativeHandler, self);
+ } else {
+ addEvent(target, fakeName || name, w3cEventModel ? nativeHandler : callbackList.proxyHandler, capture);
+ }
+ } else {
+ // If it already has an native handler then just push the callback
+ callbackList.push({func: callback, scope: scope});
+ }
+ }
+
+ target = callbackList = 0; // Clean memory for IE
+
+ return callback;
+ };
+
+ self.unbind = function(target, names, callback) {
+ var id, callbackList, i, ci, name, eventMap;
+
+ // Don't bind to text nodes or comments
+ if (!target || target.nodeType === 3 || target.nodeType === 8) {
+ return self;
+ }
+
+ // Unbind event or events if the target has the expando
+ id = target[expando];
+ if (id) {
+ eventMap = events[id];
+
+ // Specific callback
+ if (names) {
+ names = names.split(' ');
+ i = names.length;
+ while (i--) {
+ name = names[i];
+ callbackList = eventMap[name];
+
+ // Unbind the event if it exists in the map
+ if (callbackList) {
+ // Remove specified callback
+ if (callback) {
+ ci = callbackList.length;
+ while (ci--) {
+ if (callbackList[ci].func === callback) {
+ callbackList.splice(ci, 1);
+ }
+ }
+ }
+
+ // Remove all callbacks if there isn't a specified callback or there is no callbacks left
+ if (!callback || callbackList.length === 0) {
+ delete eventMap[name];
+ removeEvent(target, callbackList.fakeName || name, w3cEventModel ? callbackList.nativeHandler : callbackList.proxyHandler, callbackList.capture);
+ }
+ }
+ }
+ } else {
+ // All events for a specific element
+ for (name in eventMap) {
+ callbackList = eventMap[name];
+ removeEvent(target, callbackList.fakeName || name, w3cEventModel ? callbackList.nativeHandler : callbackList.proxyHandler, callbackList.capture);
+ }
+
+ eventMap = {};
+ }
+
+ // Check if object is empty, if it isn't then we won't remove the expando map
+ for (name in eventMap) {
+ return self;
+ }
+
+ // Delete event object
+ delete events[id];
+
+ // Remove expando from target
+ try {
+ // IE will fail here since it can't delete properties from window
+ delete target[expando];
+ } catch (ex) {
+ // IE will set it to null
+ target[expando] = null;
+ }
+ }
+
+ return self;
+ };
+
+ self.fire = function(target, name, args) {
+ var id, event;
+
+ // Don't bind to text nodes or comments
+ if (!target || target.nodeType === 3 || target.nodeType === 8) {
+ return self;
+ }
+
+ // Build event object by patching the args
+ event = fix(null, args);
+ event.type = name;
+
+ do {
+ // Found an expando that means there is listeners to execute
+ id = target[expando];
+ if (id) {
+ executeHandlers(event, id);
+ }
+
+ // Walk up the DOM
+ target = target.parentNode || target.ownerDocument || target.defaultView || target.parentWindow;
+ } while (target && !event.isPropagationStopped());
+
+ return self;
+ };
+
+ self.clean = function(target) {
+ var i, children, unbind = self.unbind;
+
+ // Don't bind to text nodes or comments
+ if (!target || target.nodeType === 3 || target.nodeType === 8) {
+ return self;
+ }
+
+ // Unbind any element on the specificed target
+ if (target[expando]) {
+ unbind(target);
+ }
+
+ // Target doesn't have getElementsByTagName it's probably a window object then use it's document to find the children
+ if (!target.getElementsByTagName) {
+ target = target.document;
+ }
+
+ // Remove events from each child element
+ if (target && target.getElementsByTagName) {
+ unbind(target);
+
+ children = target.getElementsByTagName('*');
+ i = children.length;
+ while (i--) {
+ target = children[i];
+
+ if (target[expando]) {
+ unbind(target);
+ }
+ }
+ }
+
+ return self;
+ };
+
+ self.callNativeHandler = function(id, evt) {
+ if (events) {
+ events[id][evt.type].nativeHandler(evt);
+ }
+ };
+
+ self.destory = function() {
+ events = {};
+ };
+
+ // Legacy function calls
+
+ self.add = function(target, events, func, scope) {
+ // Old API supported direct ID assignment
+ if (typeof(target) === "string") {
+ target = document.getElementById(target);
+ }
+
+ // Old API supported multiple targets
+ if (target && target instanceof Array) {
+ var i = target.length;
+
+ while (i--) {
+ self.add(target[i], events, func, scope);
+ }
+
+ return;
+ }
+
+ // Old API called ready init
+ if (events === "init") {
+ events = "ready";
+ }
+
+ return self.bind(target, events instanceof Array ? events.join(' ') : events, func, scope);
+ };
+
+ self.remove = function(target, events, func, scope) {
+ if (!target) {
+ return self;
+ }
+
+ // Old API supported direct ID assignment
+ if (typeof(target) === "string") {
+ target = document.getElementById(target);
+ }
+
+ // Old API supported multiple targets
+ if (target instanceof Array) {
+ var i = target.length;
+
+ while (i--) {
+ self.remove(target[i], events, func, scope);
+ }
+
+ return self;
+ }
+
+ return self.unbind(target, events instanceof Array ? events.join(' ') : events, func);
+ };
+
+ self.clear = function(target) {
+ // Old API supported direct ID assignment
+ if (typeof(target) === "string") {
+ target = document.getElementById(target);
+ }
+
+ return self.clean(target);
+ };
+
+ self.cancel = function(e) {
+ if (e) {
+ self.prevent(e);
+ self.stop(e);
+ }
+
+ return false;
+ };
+
+ self.prevent = function(e) {
+ if (!e.preventDefault) {
+ e = fix(e);
+ }
+
+ e.preventDefault();
+
+ return false;
+ };
+
+ self.stop = function(e) {
+ if (!e.stopPropagation) {
+ e = fix(e);
+ }
+
+ e.stopPropagation();
+
+ return false;
+ };
+ }
+
+ namespace.EventUtils = EventUtils;
+
+ namespace.Event = new EventUtils(function(id) {
+ return function(evt) {
+ tinymce.dom.Event.callNativeHandler(id, evt);
+ };
+ });
+
+ // Bind ready event when tinymce script is loaded
+ namespace.Event.bind(window, 'ready', function() {});
+
+ namespace = 0;
+})(tinymce.dom, 'data-mce-expando'); // Namespace and expando
+
+tinymce.dom.TreeWalker = function(start_node, root_node) {
+ var node = start_node;
+
+ function findSibling(node, start_name, sibling_name, shallow) {
+ var sibling, parent;
+
+ if (node) {
+ // Walk into nodes if it has a start
+ if (!shallow && node[start_name])
+ return node[start_name];
+
+ // Return the sibling if it has one
+ if (node != root_node) {
+ sibling = node[sibling_name];
+ if (sibling)
+ return sibling;
+
+ // Walk up the parents to look for siblings
+ for (parent = node.parentNode; parent && parent != root_node; parent = parent.parentNode) {
+ sibling = parent[sibling_name];
+ if (sibling)
+ return sibling;
+ }
+ }
+ }
+ };
+
+ this.current = function() {
+ return node;
+ };
+
+ this.next = function(shallow) {
+ return (node = findSibling(node, 'firstChild', 'nextSibling', shallow));
+ };
+
+ this.prev = function(shallow) {
+ return (node = findSibling(node, 'lastChild', 'previousSibling', shallow));
+ };
+};
+
+(function(tinymce) {
+ // Shorten names
+ var each = tinymce.each,
+ is = tinymce.is,
+ isWebKit = tinymce.isWebKit,
+ isIE = tinymce.isIE,
+ Entities = tinymce.html.Entities,
+ simpleSelectorRe = /^([a-z0-9],?)+$/i,
+ whiteSpaceRegExp = /^[ \t\r\n]*$/;
+
+ tinymce.create('tinymce.dom.DOMUtils', {
+ doc : null,
+ root : null,
+ files : null,
+ pixelStyles : /^(top|left|bottom|right|width|height|borderWidth)$/,
+ props : {
+ "for" : "htmlFor",
+ "class" : "className",
+ className : "className",
+ checked : "checked",
+ disabled : "disabled",
+ maxlength : "maxLength",
+ readonly : "readOnly",
+ selected : "selected",
+ value : "value",
+ id : "id",
+ name : "name",
+ type : "type"
+ },
+
+ DOMUtils : function(d, s) {
+ var t = this, globalStyle, name, blockElementsMap;
+
+ t.doc = d;
+ t.win = window;
+ t.files = {};
+ t.cssFlicker = false;
+ t.counter = 0;
+ t.stdMode = !tinymce.isIE || d.documentMode >= 8;
+ t.boxModel = !tinymce.isIE || d.compatMode == "CSS1Compat" || t.stdMode;
+ t.hasOuterHTML = "outerHTML" in d.createElement("a");
+
+ t.settings = s = tinymce.extend({
+ keep_values : false,
+ hex_colors : 1
+ }, s);
+
+ t.schema = s.schema;
+ t.styles = new tinymce.html.Styles({
+ url_converter : s.url_converter,
+ url_converter_scope : s.url_converter_scope
+ }, s.schema);
+
+ // Fix IE6SP2 flicker and check it failed for pre SP2
+ if (tinymce.isIE6) {
+ try {
+ d.execCommand('BackgroundImageCache', false, true);
+ } catch (e) {
+ t.cssFlicker = true;
+ }
+ }
+
+ t.fixDoc(d);
+ t.events = s.ownEvents ? new tinymce.dom.EventUtils(s.proxy) : tinymce.dom.Event;
+ tinymce.addUnload(t.destroy, t);
+ blockElementsMap = s.schema ? s.schema.getBlockElements() : {};
+
+ t.isBlock = function(node) {
+ // This function is called in module pattern style since it might be executed with the wrong this scope
+ var type = node.nodeType;
+
+ // If it's a node then check the type and use the nodeName
+ if (type)
+ return !!(type === 1 && blockElementsMap[node.nodeName]);
+
+ return !!blockElementsMap[node];
+ };
+ },
+
+ fixDoc: function(doc) {
+ var settings = this.settings, name;
+
+ if (isIE && settings.schema) {
+ // Add missing HTML 4/5 elements to IE
+ ('abbr article aside audio canvas ' +
+ 'details figcaption figure footer ' +
+ 'header hgroup mark menu meter nav ' +
+ 'output progress section summary ' +
+ 'time video').replace(/\w+/g, function(name) {
+ doc.createElement(name);
+ });
+
+ // Create all custom elements
+ for (name in settings.schema.getCustomElements()) {
+ doc.createElement(name);
+ }
+ }
+ },
+
+ clone: function(node, deep) {
+ var self = this, clone, doc;
+
+ // TODO: Add feature detection here in the future
+ if (!isIE || node.nodeType !== 1 || deep) {
+ return node.cloneNode(deep);
+ }
+
+ doc = self.doc;
+
+ // Make a HTML5 safe shallow copy
+ if (!deep) {
+ clone = doc.createElement(node.nodeName);
+
+ // Copy attribs
+ each(self.getAttribs(node), function(attr) {
+ self.setAttrib(clone, attr.nodeName, self.getAttrib(node, attr.nodeName));
+ });
+
+ return clone;
+ }
+/*
+ // Setup HTML5 patched document fragment
+ if (!self.frag) {
+ self.frag = doc.createDocumentFragment();
+ self.fixDoc(self.frag);
+ }
+
+ // Make a deep copy by adding it to the document fragment then removing it this removed the :section
+ clone = doc.createElement('div');
+ self.frag.appendChild(clone);
+ clone.innerHTML = node.outerHTML;
+ self.frag.removeChild(clone);
+*/
+ return clone.firstChild;
+ },
+
+ getRoot : function() {
+ var t = this, s = t.settings;
+
+ return (s && t.get(s.root_element)) || t.doc.body;
+ },
+
+ getViewPort : function(w) {
+ var d, b;
+
+ w = !w ? this.win : w;
+ d = w.document;
+ b = this.boxModel ? d.documentElement : d.body;
+
+ // Returns viewport size excluding scrollbars
+ return {
+ x : w.pageXOffset || b.scrollLeft,
+ y : w.pageYOffset || b.scrollTop,
+ w : w.innerWidth || b.clientWidth,
+ h : w.innerHeight || b.clientHeight
+ };
+ },
+
+ getRect : function(e) {
+ var p, t = this, sr;
+
+ e = t.get(e);
+ p = t.getPos(e);
+ sr = t.getSize(e);
+
+ return {
+ x : p.x,
+ y : p.y,
+ w : sr.w,
+ h : sr.h
+ };
+ },
+
+ getSize : function(e) {
+ var t = this, w, h;
+
+ e = t.get(e);
+ w = t.getStyle(e, 'width');
+ h = t.getStyle(e, 'height');
+
+ // Non pixel value, then force offset/clientWidth
+ if (w.indexOf('px') === -1)
+ w = 0;
+
+ // Non pixel value, then force offset/clientWidth
+ if (h.indexOf('px') === -1)
+ h = 0;
+
+ return {
+ w : parseInt(w, 10) || e.offsetWidth || e.clientWidth,
+ h : parseInt(h, 10) || e.offsetHeight || e.clientHeight
+ };
+ },
+
+ getParent : function(n, f, r) {
+ return this.getParents(n, f, r, false);
+ },
+
+ getParents : function(n, f, r, c) {
+ var t = this, na, se = t.settings, o = [];
+
+ n = t.get(n);
+ c = c === undefined;
+
+ if (se.strict_root)
+ r = r || t.getRoot();
+
+ // Wrap node name as func
+ if (is(f, 'string')) {
+ na = f;
+
+ if (f === '*') {
+ f = function(n) {return n.nodeType == 1;};
+ } else {
+ f = function(n) {
+ return t.is(n, na);
+ };
+ }
+ }
+
+ while (n) {
+ if (n == r || !n.nodeType || n.nodeType === 9)
+ break;
+
+ if (!f || f(n)) {
+ if (c)
+ o.push(n);
+ else
+ return n;
+ }
+
+ n = n.parentNode;
+ }
+
+ return c ? o : null;
+ },
+
+ get : function(e) {
+ var n;
+
+ if (e && this.doc && typeof(e) == 'string') {
+ n = e;
+ e = this.doc.getElementById(e);
+
+ // IE and Opera returns meta elements when they match the specified input ID, but getElementsByName seems to do the trick
+ if (e && e.id !== n)
+ return this.doc.getElementsByName(n)[1];
+ }
+
+ return e;
+ },
+
+ getNext : function(node, selector) {
+ return this._findSib(node, selector, 'nextSibling');
+ },
+
+ getPrev : function(node, selector) {
+ return this._findSib(node, selector, 'previousSibling');
+ },
+
+
+ select : function(pa, s) {
+ var t = this;
+
+ return tinymce.dom.Sizzle(pa, t.get(s) || t.get(t.settings.root_element) || t.doc, []);
+ },
+
+ is : function(n, selector) {
+ var i;
+
+ // If it isn't an array then try to do some simple selectors instead of Sizzle for to boost performance
+ if (n.length === undefined) {
+ // Simple all selector
+ if (selector === '*')
+ return n.nodeType == 1;
+
+ // Simple selector just elements
+ if (simpleSelectorRe.test(selector)) {
+ selector = selector.toLowerCase().split(/,/);
+ n = n.nodeName.toLowerCase();
+
+ for (i = selector.length - 1; i >= 0; i--) {
+ if (selector[i] == n)
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ return tinymce.dom.Sizzle.matches(selector, n.nodeType ? [n] : n).length > 0;
+ },
+
+
+ add : function(p, n, a, h, c) {
+ var t = this;
+
+ return this.run(p, function(p) {
+ var e, k;
+
+ e = is(n, 'string') ? t.doc.createElement(n) : n;
+ t.setAttribs(e, a);
+
+ if (h) {
+ if (h.nodeType)
+ e.appendChild(h);
+ else
+ t.setHTML(e, h);
+ }
+
+ return !c ? p.appendChild(e) : e;
+ });
+ },
+
+ create : function(n, a, h) {
+ return this.add(this.doc.createElement(n), n, a, h, 1);
+ },
+
+ createHTML : function(n, a, h) {
+ var o = '', t = this, k;
+
+ o += '<' + n;
+
+ for (k in a) {
+ if (a.hasOwnProperty(k))
+ o += ' ' + k + '="' + t.encode(a[k]) + '"';
+ }
+
+ // A call to tinymce.is doesn't work for some odd reason on IE9 possible bug inside their JS runtime
+ if (typeof(h) != "undefined")
+ return o + '>' + h + '</' + n + '>';
+
+ return o + ' />';
+ },
+
+ remove : function(node, keep_children) {
+ return this.run(node, function(node) {
+ var child, parent = node.parentNode;
+
+ if (!parent)
+ return null;
+
+ if (keep_children) {
+ while (child = node.firstChild) {
+ // IE 8 will crash if you don't remove completely empty text nodes
+ if (!tinymce.isIE || child.nodeType !== 3 || child.nodeValue)
+ parent.insertBefore(child, node);
+ else
+ node.removeChild(child);
+ }
+ }
+
+ return parent.removeChild(node);
+ });
+ },
+
+ setStyle : function(n, na, v) {
+ var t = this;
+
+ return t.run(n, function(e) {
+ var s, i;
+
+ s = e.style;
+
+ // Camelcase it, if needed
+ na = na.replace(/-(\D)/g, function(a, b){
+ return b.toUpperCase();
+ });
+
+ // Default px suffix on these
+ if (t.pixelStyles.test(na) && (tinymce.is(v, 'number') || /^[\-0-9\.]+$/.test(v)))
+ v += 'px';
+
+ switch (na) {
+ case 'opacity':
+ // IE specific opacity
+ if (isIE) {
+ s.filter = v === '' ? '' : "alpha(opacity=" + (v * 100) + ")";
+
+ if (!n.currentStyle || !n.currentStyle.hasLayout)
+ s.display = 'inline-block';
+ }
+
+ // Fix for older browsers
+ s[na] = s['-moz-opacity'] = s['-khtml-opacity'] = v || '';
+ break;
+
+ case 'float':
+ isIE ? s.styleFloat = v : s.cssFloat = v;
+ break;
+
+ default:
+ s[na] = v || '';
+ }
+
+ // Force update of the style data
+ if (t.settings.update_styles)
+ t.setAttrib(e, 'data-mce-style');
+ });
+ },
+
+ getStyle : function(n, na, c) {
+ n = this.get(n);
+
+ if (!n)
+ return;
+
+ // Gecko
+ if (this.doc.defaultView && c) {
+ // Remove camelcase
+ na = na.replace(/[A-Z]/g, function(a){
+ return '-' + a;
+ });
+
+ try {
+ return this.doc.defaultView.getComputedStyle(n, null).getPropertyValue(na);
+ } catch (ex) {
+ // Old safari might fail
+ return null;
+ }
+ }
+
+ // Camelcase it, if needed
+ na = na.replace(/-(\D)/g, function(a, b){
+ return b.toUpperCase();
+ });
+
+ if (na == 'float')
+ na = isIE ? 'styleFloat' : 'cssFloat';
+
+ // IE & Opera
+ if (n.currentStyle && c)
+ return n.currentStyle[na];
+
+ return n.style ? n.style[na] : undefined;
+ },
+
+ setStyles : function(e, o) {
+ var t = this, s = t.settings, ol;
+
+ ol = s.update_styles;
+ s.update_styles = 0;
+
+ each(o, function(v, n) {
+ t.setStyle(e, n, v);
+ });
+
+ // Update style info
+ s.update_styles = ol;
+ if (s.update_styles)
+ t.setAttrib(e, s.cssText);
+ },
+
+ removeAllAttribs: function(e) {
+ return this.run(e, function(e) {
+ var i, attrs = e.attributes;
+ for (i = attrs.length - 1; i >= 0; i--) {
+ e.removeAttributeNode(attrs.item(i));
+ }
+ });
+ },
+
+ setAttrib : function(e, n, v) {
+ var t = this;
+
+ // Whats the point
+ if (!e || !n)
+ return;
+
+ // Strict XML mode
+ if (t.settings.strict)
+ n = n.toLowerCase();
+
+ return this.run(e, function(e) {
+ var s = t.settings;
+ var originalValue = e.getAttribute(n);
+ if (v !== null) {
+ switch (n) {
+ case "style":
+ if (!is(v, 'string')) {
+ each(v, function(v, n) {
+ t.setStyle(e, n, v);
+ });
+
+ return;
+ }
+
+ // No mce_style for elements with these since they might get resized by the user
+ if (s.keep_values) {
+ if (v && !t._isRes(v))
+ e.setAttribute('data-mce-style', v, 2);
+ else
+ e.removeAttribute('data-mce-style', 2);
+ }
+
+ e.style.cssText = v;
+ break;
+
+ case "class":
+ e.className = v || ''; // Fix IE null bug
+ break;
+
+ case "src":
+ case "href":
+ if (s.keep_values) {
+ if (s.url_converter)
+ v = s.url_converter.call(s.url_converter_scope || t, v, n, e);
+
+ t.setAttrib(e, 'data-mce-' + n, v, 2);
+ }
+
+ break;
+
+ case "shape":
+ e.setAttribute('data-mce-style', v);
+ break;
+ }
+ }
+ if (is(v) && v !== null && v.length !== 0)
+ e.setAttribute(n, '' + v, 2);
+ else
+ e.removeAttribute(n, 2);
+
+ // fire onChangeAttrib event for attributes that have changed
+ if (tinyMCE.activeEditor && originalValue != v) {
+ var ed = tinyMCE.activeEditor;
+ ed.onSetAttrib.dispatch(ed, e, n, v);
+ }
+ });
+ },
+
+ setAttribs : function(e, o) {
+ var t = this;
+
+ return this.run(e, function(e) {
+ each(o, function(v, n) {
+ t.setAttrib(e, n, v);
+ });
+ });
+ },
+
+ getAttrib : function(e, n, dv) {
+ var v, t = this, undef;
+
+ e = t.get(e);
+
+ if (!e || e.nodeType !== 1)
+ return dv === undef ? false : dv;
+
+ if (!is(dv))
+ dv = '';
+
+ // Try the mce variant for these
+ if (/^(src|href|style|coords|shape)$/.test(n)) {
+ v = e.getAttribute("data-mce-" + n);
+
+ if (v)
+ return v;
+ }
+
+ if (isIE && t.props[n]) {
+ v = e[t.props[n]];
+ v = v && v.nodeValue ? v.nodeValue : v;
+ }
+
+ if (!v)
+ v = e.getAttribute(n, 2);
+
+ // Check boolean attribs
+ if (/^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)$/.test(n)) {
+ if (e[t.props[n]] === true && v === '')
+ return n;
+
+ return v ? n : '';
+ }
+
+ // Inner input elements will override attributes on form elements
+ if (e.nodeName === "FORM" && e.getAttributeNode(n))
+ return e.getAttributeNode(n).nodeValue;
+
+ if (n === 'style') {
+ v = v || e.style.cssText;
+
+ if (v) {
+ v = t.serializeStyle(t.parseStyle(v), e.nodeName);
+
+ if (t.settings.keep_values && !t._isRes(v))
+ e.setAttribute('data-mce-style', v);
+ }
+ }
+
+ // Remove Apple and WebKit stuff
+ if (isWebKit && n === "class" && v)
+ v = v.replace(/(apple|webkit)\-[a-z\-]+/gi, '');
+
+ // Handle IE issues
+ if (isIE) {
+ switch (n) {
+ case 'rowspan':
+ case 'colspan':
+ // IE returns 1 as default value
+ if (v === 1)
+ v = '';
+
+ break;
+
+ case 'size':
+ // IE returns +0 as default value for size
+ if (v === '+0' || v === 20 || v === 0)
+ v = '';
+
+ break;
+
+ case 'width':
+ case 'height':
+ case 'vspace':
+ case 'checked':
+ case 'disabled':
+ case 'readonly':
+ if (v === 0)
+ v = '';
+
+ break;
+
+ case 'hspace':
+ // IE returns -1 as default value
+ if (v === -1)
+ v = '';
+
+ break;
+
+ case 'maxlength':
+ case 'tabindex':
+ // IE returns default value
+ if (v === 32768 || v === 2147483647 || v === '32768')
+ v = '';
+
+ break;
+
+ case 'multiple':
+ case 'compact':
+ case 'noshade':
+ case 'nowrap':
+ if (v === 65535)
+ return n;
+
+ return dv;
+
+ case 'shape':
+ v = v.toLowerCase();
+ break;
+
+ default:
+ // IE has odd anonymous function for event attributes
+ if (n.indexOf('on') === 0 && v)
+ v = tinymce._replace(/^function\s+\w+\(\)\s+\{\s+(.*)\s+\}$/, '$1', '' + v);
+ }
+ }
+
+ return (v !== undef && v !== null && v !== '') ? '' + v : dv;
+ },
+
+ getPos : function(n, ro) {
+ var t = this, x = 0, y = 0, e, d = t.doc, r;
+
+ n = t.get(n);
+ ro = ro || d.body;
+
+ if (n) {
+ // Use getBoundingClientRect if it exists since it's faster than looping offset nodes
+ if (n.getBoundingClientRect) {
+ n = n.getBoundingClientRect();
+ e = t.boxModel ? d.documentElement : d.body;
+
+ // Add scroll offsets from documentElement or body since IE with the wrong box model will use d.body and so do WebKit
+ // Also remove the body/documentelement clientTop/clientLeft on IE 6, 7 since they offset the position
+ x = n.left + (d.documentElement.scrollLeft || d.body.scrollLeft) - e.clientTop;
+ y = n.top + (d.documentElement.scrollTop || d.body.scrollTop) - e.clientLeft;
+
+ return {x : x, y : y};
+ }
+
+ r = n;
+ while (r && r != ro && r.nodeType) {
+ x += r.offsetLeft || 0;
+ y += r.offsetTop || 0;
+ r = r.offsetParent;
+ }
+
+ r = n.parentNode;
+ while (r && r != ro && r.nodeType) {
+ x -= r.scrollLeft || 0;
+ y -= r.scrollTop || 0;
+ r = r.parentNode;
+ }
+ }
+
+ return {x : x, y : y};
+ },
+
+ parseStyle : function(st) {
+ return this.styles.parse(st);
+ },
+
+ serializeStyle : function(o, name) {
+ return this.styles.serialize(o, name);
+ },
+
+ addStyle: function(cssText) {
+ var doc = this.doc, head;
+
+ // Create style element if needed
+ styleElm = doc.getElementById('mceDefaultStyles');
+ if (!styleElm) {
+ styleElm = doc.createElement('style'),
+ styleElm.id = 'mceDefaultStyles';
+ styleElm.type = 'text/css';
+
+ head = doc.getElementsByTagName('head')[0]
+ if (head.firstChild) {
+ head.insertBefore(styleElm, head.firstChild);
+ } else {
+ head.appendChild(styleElm);
+ }
+ }
+
+ // Append style data to old or new style element
+ if (styleElm.styleSheet) {
+ styleElm.styleSheet.cssText += cssText;
+ } else {
+ styleElm.appendChild(doc.createTextNode(cssText));
+ }
+ },
+
+ loadCSS : function(u) {
+ var t = this, d = t.doc, head;
+
+ if (!u)
+ u = '';
+
+ head = d.getElementsByTagName('head')[0];
+
+ each(u.split(','), function(u) {
+ var link;
+
+ if (t.files[u])
+ return;
+
+ t.files[u] = true;
+ link = t.create('link', {rel : 'stylesheet', href : tinymce._addVer(u)});
+
+ // IE 8 has a bug where dynamically loading stylesheets would produce a 1 item remaining bug
+ // This fix seems to resolve that issue by realcing the document ones a stylesheet finishes loading
+ // It's ugly but it seems to work fine.
+ if (isIE && d.documentMode && d.recalc) {
+ link.onload = function() {
+ if (d.recalc)
+ d.recalc();
+
+ link.onload = null;
+ };
+ }
+
+ head.appendChild(link);
+ });
+ },
+
+ addClass : function(e, c) {
+ return this.run(e, function(e) {
+ var o;
+
+ if (!c)
+ return 0;
+
+ if (this.hasClass(e, c))
+ return e.className;
+
+ o = this.removeClass(e, c);
+
+ return e.className = (o != '' ? (o + ' ') : '') + c;
+ });
+ },
+
+ removeClass : function(e, c) {
+ var t = this, re;
+
+ return t.run(e, function(e) {
+ var v;
+
+ if (t.hasClass(e, c)) {
+ if (!re)
+ re = new RegExp("(^|\\s+)" + c + "(\\s+|$)", "g");
+
+ v = e.className.replace(re, ' ');
+ v = tinymce.trim(v != ' ' ? v : '');
+
+ e.className = v;
+
+ // Empty class attr
+ if (!v) {
+ e.removeAttribute('class');
+ e.removeAttribute('className');
+ }
+
+ return v;
+ }
+
+ return e.className;
+ });
+ },
+
+ hasClass : function(n, c) {
+ n = this.get(n);
+
+ if (!n || !c)
+ return false;
+
+ return (' ' + n.className + ' ').indexOf(' ' + c + ' ') !== -1;
+ },
+
+ show : function(e) {
+ return this.setStyle(e, 'display', 'block');
+ },
+
+ hide : function(e) {
+ return this.setStyle(e, 'display', 'none');
+ },
+
+ isHidden : function(e) {
+ e = this.get(e);
+
+ return !e || e.style.display == 'none' || this.getStyle(e, 'display') == 'none';
+ },
+
+ uniqueId : function(p) {
+ return (!p ? 'mce_' : p) + (this.counter++);
+ },
+
+ setHTML : function(element, html) {
+ var self = this;
+
+ return self.run(element, function(element) {
+ if (isIE) {
+ // Remove all child nodes, IE keeps empty text nodes in DOM
+ while (element.firstChild)
+ element.removeChild(element.firstChild);
+
+ try {
+ // IE will remove comments from the beginning
+ // unless you padd the contents with something
+ element.innerHTML = '<br />' + html;
+ element.removeChild(element.firstChild);
+ } catch (ex) {
+ // IE sometimes produces an unknown runtime error on innerHTML if it's an block element within a block element for example a div inside a p
+ // This seems to fix this problem
+
+ // Create new div with HTML contents and a BR infront to keep comments
+ var newElement = self.create('div');
+ newElement.innerHTML = '<br />' + html;
+
+ // Add all children from div to target
+ each (tinymce.grep(newElement.childNodes), function(node, i) {
+ // Skip br element
+ if (i && element.canHaveHTML)
+ element.appendChild(node);
+ });
+ }
+ } else
+ element.innerHTML = html;
+
+ return html;
+ });
+ },
+
+ getOuterHTML : function(elm) {
+ var doc, self = this;
+
+ elm = self.get(elm);
+
+ if (!elm)
+ return null;
+
+ if (elm.nodeType === 1 && self.hasOuterHTML)
+ return elm.outerHTML;
+
+ doc = (elm.ownerDocument || self.doc).createElement("body");
+ doc.appendChild(elm.cloneNode(true));
+
+ return doc.innerHTML;
+ },
+
+ setOuterHTML : function(e, h, d) {
+ var t = this;
+
+ function setHTML(e, h, d) {
+ var n, tp;
+
+ tp = d.createElement("body");
+ tp.innerHTML = h;
+
+ n = tp.lastChild;
+ while (n) {
+ t.insertAfter(n.cloneNode(true), e);
+ n = n.previousSibling;
+ }
+
+ t.remove(e);
+ };
+
+ return this.run(e, function(e) {
+ e = t.get(e);
+
+ // Only set HTML on elements
+ if (e.nodeType == 1) {
+ d = d || e.ownerDocument || t.doc;
+
+ if (isIE) {
+ try {
+ // Try outerHTML for IE it sometimes produces an unknown runtime error
+ if (isIE && e.nodeType == 1)
+ e.outerHTML = h;
+ else
+ setHTML(e, h, d);
+ } catch (ex) {
+ // Fix for unknown runtime error
+ setHTML(e, h, d);
+ }
+ } else
+ setHTML(e, h, d);
+ }
+ });
+ },
+
+ decode : Entities.decode,
+
+ encode : Entities.encodeAllRaw,
+
+ insertAfter : function(node, reference_node) {
+ reference_node = this.get(reference_node);
+
+ return this.run(node, function(node) {
+ var parent, nextSibling;
+
+ parent = reference_node.parentNode;
+ nextSibling = reference_node.nextSibling;
+
+ if (nextSibling)
+ parent.insertBefore(node, nextSibling);
+ else
+ parent.appendChild(node);
+
+ return node;
+ });
+ },
+
+ replace : function(n, o, k) {
+ var t = this;
+
+ if (is(o, 'array'))
+ n = n.cloneNode(true);
+
+ return t.run(o, function(o) {
+ if (k) {
+ each(tinymce.grep(o.childNodes), function(c) {
+ n.appendChild(c);
+ });
+ }
+
+ return o.parentNode.replaceChild(n, o);
+ });
+ },
+
+ rename : function(elm, name) {
+ var t = this, newElm;
+
+ if (elm.nodeName != name.toUpperCase()) {
+ // Rename block element
+ newElm = t.create(name);
+
+ // Copy attribs to new block
+ each(t.getAttribs(elm), function(attr_node) {
+ t.setAttrib(newElm, attr_node.nodeName, t.getAttrib(elm, attr_node.nodeName));
+ });
+
+ // Replace block
+ t.replace(newElm, elm, 1);
+ }
+
+ return newElm || elm;
+ },
+
+ findCommonAncestor : function(a, b) {
+ var ps = a, pe;
+
+ while (ps) {
+ pe = b;
+
+ while (pe && ps != pe)
+ pe = pe.parentNode;
+
+ if (ps == pe)
+ break;
+
+ ps = ps.parentNode;
+ }
+
+ if (!ps && a.ownerDocument)
+ return a.ownerDocument.documentElement;
+
+ return ps;
+ },
+
+ toHex : function(s) {
+ var c = /^\s*rgb\s*?\(\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?\)\s*$/i.exec(s);
+
+ function hex(s) {
+ s = parseInt(s, 10).toString(16);
+
+ return s.length > 1 ? s : '0' + s; // 0 -> 00
+ };
+
+ if (c) {
+ s = '#' + hex(c[1]) + hex(c[2]) + hex(c[3]);
+
+ return s;
+ }
+
+ return s;
+ },
+
+ getClasses : function() {
+ var t = this, cl = [], i, lo = {}, f = t.settings.class_filter, ov;
+
+ if (t.classes)
+ return t.classes;
+
+ function addClasses(s) {
+ // IE style imports
+ each(s.imports, function(r) {
+ addClasses(r);
+ });
+
+ each(s.cssRules || s.rules, function(r) {
+ // Real type or fake it on IE
+ switch (r.type || 1) {
+ // Rule
+ case 1:
+ if (r.selectorText) {
+ each(r.selectorText.split(','), function(v) {
+ v = v.replace(/^\s*|\s*$|^\s\./g, "");
+
+ // Is internal or it doesn't contain a class
+ if (/\.mce/.test(v) || !/\.[\w\-]+$/.test(v))
+ return;
+
+ // Remove everything but class name
+ ov = v;
+ v = tinymce._replace(/.*\.([a-z0-9_\-]+).*/i, '$1', v);
+
+ // Filter classes
+ if (f && !(v = f(v, ov)))
+ return;
+
+ if (!lo[v]) {
+ cl.push({'class' : v});
+ lo[v] = 1;
+ }
+ });
+ }
+ break;
+
+ // Import
+ case 3:
+ addClasses(r.styleSheet);
+ break;
+ }
+ });
+ };
+
+ try {
+ each(t.doc.styleSheets, addClasses);
+ } catch (ex) {
+ // Ignore
+ }
+
+ if (cl.length > 0)
+ t.classes = cl;
+
+ return cl;
+ },
+
+ run : function(e, f, s) {
+ var t = this, o;
+
+ if (t.doc && typeof(e) === 'string')
+ e = t.get(e);
+
+ if (!e)
+ return false;
+
+ s = s || this;
+ if (!e.nodeType && (e.length || e.length === 0)) {
+ o = [];
+
+ each(e, function(e, i) {
+ if (e) {
+ if (typeof(e) == 'string')
+ e = t.doc.getElementById(e);
+
+ o.push(f.call(s, e, i));
+ }
+ });
+
+ return o;
+ }
+
+ return f.call(s, e);
+ },
+
+ getAttribs : function(n) {
+ var o;
+
+ n = this.get(n);
+
+ if (!n)
+ return [];
+
+ if (isIE) {
+ o = [];
+
+ // Object will throw exception in IE
+ if (n.nodeName == 'OBJECT')
+ return n.attributes;
+
+ // IE doesn't keep the selected attribute if you clone option elements
+ if (n.nodeName === 'OPTION' && this.getAttrib(n, 'selected'))
+ o.push({specified : 1, nodeName : 'selected'});
+
+ // It's crazy that this is faster in IE but it's because it returns all attributes all the time
+ n.cloneNode(false).outerHTML.replace(/<\/?[\w:\-]+ ?|=[\"][^\"]+\"|=\'[^\']+\'|=[\w\-]+|>/gi, '').replace(/[\w:\-]+/gi, function(a) {
+ o.push({specified : 1, nodeName : a});
+ });
+
+ return o;
+ }
+
+ return n.attributes;
+ },
+
+ isEmpty : function(node, elements) {
+ var self = this, i, attributes, type, walker, name, brCount = 0;
+
+ node = node.firstChild;
+ if (node) {
+ walker = new tinymce.dom.TreeWalker(node, node.parentNode);
+ elements = elements || self.schema ? self.schema.getNonEmptyElements() : null;
+
+ do {
+ type = node.nodeType;
+
+ if (type === 1) {
+ // Ignore bogus elements
+ if (node.getAttribute('data-mce-bogus'))
+ continue;
+
+ // Keep empty elements like <img />
+ name = node.nodeName.toLowerCase();
+ if (elements && elements[name]) {
+ // Ignore single BR elements in blocks like <p><br /></p> or <p><span><br /></span></p>
+ if (name === 'br') {
+ brCount++;
+ continue;
+ }
+
+ return false;
+ }
+
+ // Keep elements with data-bookmark attributes or name attribute like <a name="1"></a>
+ attributes = self.getAttribs(node);
+ i = node.attributes.length;
+ while (i--) {
+ name = node.attributes[i].nodeName;
+ if (name === "name" || name === 'data-mce-bookmark')
+ return false;
+ }
+ }
+
+ // Keep comment nodes
+ if (type == 8)
+ return false;
+
+ // Keep non whitespace text nodes
+ if ((type === 3 && !whiteSpaceRegExp.test(node.nodeValue)))
+ return false;
+ } while (node = walker.next());
+ }
+
+ return brCount <= 1;
+ },
+
+ destroy : function(s) {
+ var t = this;
+
+ t.win = t.doc = t.root = t.events = t.frag = null;
+
+ // Manual destroy then remove unload handler
+ if (!s)
+ tinymce.removeUnload(t.destroy);
+ },
+
+ createRng : function() {
+ var d = this.doc;
+
+ return d.createRange ? d.createRange() : new tinymce.dom.Range(this);
+ },
+
+ nodeIndex : function(node, normalized) {
+ var idx = 0, lastNodeType, lastNode, nodeType;
+
+ if (node) {
+ for (lastNodeType = node.nodeType, node = node.previousSibling, lastNode = node; node; node = node.previousSibling) {
+ nodeType = node.nodeType;
+
+ // Normalize text nodes
+ if (normalized && nodeType == 3) {
+ if (nodeType == lastNodeType || !node.nodeValue.length)
+ continue;
+ }
+ idx++;
+ lastNodeType = nodeType;
+ }
+ }
+
+ return idx;
+ },
+
+ split : function(pe, e, re) {
+ var t = this, r = t.createRng(), bef, aft, pa;
+
+ // W3C valid browsers tend to leave empty nodes to the left/right side of the contents, this makes sense
+ // but we don't want that in our code since it serves no purpose for the end user
+ // For example if this is chopped:
+ // <p>text 1<span><b>CHOP</b></span>text 2</p>
+ // would produce:
+ // <p>text 1<span></span></p><b>CHOP</b><p><span></span>text 2</p>
+ // this function will then trim of empty edges and produce:
+ // <p>text 1</p><b>CHOP</b><p>text 2</p>
+ function trim(node) {
+ var i, children = node.childNodes, type = node.nodeType;
+
+ function surroundedBySpans(node) {
+ var previousIsSpan = node.previousSibling && node.previousSibling.nodeName == 'SPAN';
+ var nextIsSpan = node.nextSibling && node.nextSibling.nodeName == 'SPAN';
+ return previousIsSpan && nextIsSpan;
+ }
+
+ if (type == 1 && node.getAttribute('data-mce-type') == 'bookmark')
+ return;
+
+ for (i = children.length - 1; i >= 0; i--)
+ trim(children[i]);
+
+ if (type != 9) {
+ // Keep non whitespace text nodes
+ if (type == 3 && node.nodeValue.length > 0) {
+ // If parent element isn't a block or there isn't any useful contents for example "<p> </p>"
+ // Also keep text nodes with only spaces if surrounded by spans.
+ // eg. "<p><span>a</span> <span>b</span></p>" should keep space between a and b
+ var trimmedLength = tinymce.trim(node.nodeValue).length;
+ if (!t.isBlock(node.parentNode) || trimmedLength > 0 || trimmedLength === 0 && surroundedBySpans(node))
+ return;
+ } else if (type == 1) {
+ // If the only child is a bookmark then move it up
+ children = node.childNodes;
+ if (children.length == 1 && children[0] && children[0].nodeType == 1 && children[0].getAttribute('data-mce-type') == 'bookmark')
+ node.parentNode.insertBefore(children[0], node);
+
+ // Keep non empty elements or img, hr etc
+ if (children.length || /^(br|hr|input|img)$/i.test(node.nodeName))
+ return;
+ }
+
+ t.remove(node);
+ }
+
+ return node;
+ };
+
+ if (pe && e) {
+ // Get before chunk
+ r.setStart(pe.parentNode, t.nodeIndex(pe));
+ r.setEnd(e.parentNode, t.nodeIndex(e));
+ bef = r.extractContents();
+
+ // Get after chunk
+ r = t.createRng();
+ r.setStart(e.parentNode, t.nodeIndex(e) + 1);
+ r.setEnd(pe.parentNode, t.nodeIndex(pe) + 1);
+ aft = r.extractContents();
+
+ // Insert before chunk
+ pa = pe.parentNode;
+ pa.insertBefore(trim(bef), pe);
+
+ // Insert middle chunk
+ if (re)
+ pa.replaceChild(re, e);
+ else
+ pa.insertBefore(e, pe);
+
+ // Insert after chunk
+ pa.insertBefore(trim(aft), pe);
+ t.remove(pe);
+
+ return re || e;
+ }
+ },
+
+ bind : function(target, name, func, scope) {
+ return this.events.add(target, name, func, scope || this);
+ },
+
+ unbind : function(target, name, func) {
+ return this.events.remove(target, name, func);
+ },
+
+ fire : function(target, name, evt) {
+ return this.events.fire(target, name, evt);
+ },
+
+ // Returns the content editable state of a node
+ getContentEditable: function(node) {
+ var contentEditable;
+
+ // Check type
+ if (node.nodeType != 1) {
+ return null;
+ }
+
+ // Check for fake content editable
+ contentEditable = node.getAttribute("data-mce-contenteditable");
+ if (contentEditable && contentEditable !== "inherit") {
+ return contentEditable;
+ }
+
+ // Check for real content editable
+ return node.contentEditable !== "inherit" ? node.contentEditable : null;
+ },
+
+
+ _findSib : function(node, selector, name) {
+ var t = this, f = selector;
+
+ if (node) {
+ // If expression make a function of it using is
+ if (is(f, 'string')) {
+ f = function(node) {
+ return t.is(node, selector);
+ };
+ }
+
+ // Loop all siblings
+ for (node = node[name]; node; node = node[name]) {
+ if (f(node))
+ return node;
+ }
+ }
+
+ return null;
+ },
+
+ _isRes : function(c) {
+ // Is live resizble element
+ return /^(top|left|bottom|right|width|height)/i.test(c) || /;\s*(top|left|bottom|right|width|height)/i.test(c);
+ }
+
+ /*
+ walk : function(n, f, s) {
+ var d = this.doc, w;
+
+ if (d.createTreeWalker) {
+ w = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);
+
+ while ((n = w.nextNode()) != null)
+ f.call(s || this, n);
+ } else
+ tinymce.walk(n, f, 'childNodes', s);
+ }
+ */
+
+ /*
+ toRGB : function(s) {
+ var c = /^\s*?#([0-9A-F]{2})([0-9A-F]{1,2})([0-9A-F]{2})?\s*?$/.exec(s);
+
+ if (c) {
+ // #FFF -> #FFFFFF
+ if (!is(c[3]))
+ c[3] = c[2] = c[1];
+
+ return "rgb(" + parseInt(c[1], 16) + "," + parseInt(c[2], 16) + "," + parseInt(c[3], 16) + ")";
+ }
+
+ return s;
+ }
+ */
+ });
+
+ tinymce.DOM = new tinymce.dom.DOMUtils(document, {process_html : 0});
+})(tinymce);
+
+(function(ns) {
+ // Range constructor
+ function Range(dom) {
+ var t = this,
+ doc = dom.doc,
+ EXTRACT = 0,
+ CLONE = 1,
+ DELETE = 2,
+ TRUE = true,
+ FALSE = false,
+ START_OFFSET = 'startOffset',
+ START_CONTAINER = 'startContainer',
+ END_CONTAINER = 'endContainer',
+ END_OFFSET = 'endOffset',
+ extend = tinymce.extend,
+ nodeIndex = dom.nodeIndex;
+
+ extend(t, {
+ // Inital states
+ startContainer : doc,
+ startOffset : 0,
+ endContainer : doc,
+ endOffset : 0,
+ collapsed : TRUE,
+ commonAncestorContainer : doc,
+
+ // Range constants
+ START_TO_START : 0,
+ START_TO_END : 1,
+ END_TO_END : 2,
+ END_TO_START : 3,
+
+ // Public methods
+ setStart : setStart,
+ setEnd : setEnd,
+ setStartBefore : setStartBefore,
+ setStartAfter : setStartAfter,
+ setEndBefore : setEndBefore,
+ setEndAfter : setEndAfter,
+ collapse : collapse,
+ selectNode : selectNode,
+ selectNodeContents : selectNodeContents,
+ compareBoundaryPoints : compareBoundaryPoints,
+ deleteContents : deleteContents,
+ extractContents : extractContents,
+ cloneContents : cloneContents,
+ insertNode : insertNode,
+ surroundContents : surroundContents,
+ cloneRange : cloneRange,
+ toStringIE : toStringIE
+ });
+
+ function createDocumentFragment() {
+ return doc.createDocumentFragment();
+ };
+
+ function setStart(n, o) {
+ _setEndPoint(TRUE, n, o);
+ };
+
+ function setEnd(n, o) {
+ _setEndPoint(FALSE, n, o);
+ };
+
+ function setStartBefore(n) {
+ setStart(n.parentNode, nodeIndex(n));
+ };
+
+ function setStartAfter(n) {
+ setStart(n.parentNode, nodeIndex(n) + 1);
+ };
+
+ function setEndBefore(n) {
+ setEnd(n.parentNode, nodeIndex(n));
+ };
+
+ function setEndAfter(n) {
+ setEnd(n.parentNode, nodeIndex(n) + 1);
+ };
+
+ function collapse(ts) {
+ if (ts) {
+ t[END_CONTAINER] = t[START_CONTAINER];
+ t[END_OFFSET] = t[START_OFFSET];
+ } else {
+ t[START_CONTAINER] = t[END_CONTAINER];
+ t[START_OFFSET] = t[END_OFFSET];
+ }
+
+ t.collapsed = TRUE;
+ };
+
+ function selectNode(n) {
+ setStartBefore(n);
+ setEndAfter(n);
+ };
+
+ function selectNodeContents(n) {
+ setStart(n, 0);
+ setEnd(n, n.nodeType === 1 ? n.childNodes.length : n.nodeValue.length);
+ };
+
+ function compareBoundaryPoints(h, r) {
+ var sc = t[START_CONTAINER], so = t[START_OFFSET], ec = t[END_CONTAINER], eo = t[END_OFFSET],
+ rsc = r.startContainer, rso = r.startOffset, rec = r.endContainer, reo = r.endOffset;
+
+ // Check START_TO_START
+ if (h === 0)
+ return _compareBoundaryPoints(sc, so, rsc, rso);
+
+ // Check START_TO_END
+ if (h === 1)
+ return _compareBoundaryPoints(ec, eo, rsc, rso);
+
+ // Check END_TO_END
+ if (h === 2)
+ return _compareBoundaryPoints(ec, eo, rec, reo);
+
+ // Check END_TO_START
+ if (h === 3)
+ return _compareBoundaryPoints(sc, so, rec, reo);
+ };
+
+ function deleteContents() {
+ _traverse(DELETE);
+ };
+
+ function extractContents() {
+ return _traverse(EXTRACT);
+ };
+
+ function cloneContents() {
+ return _traverse(CLONE);
+ };
+
+ function insertNode(n) {
+ var startContainer = this[START_CONTAINER],
+ startOffset = this[START_OFFSET], nn, o;
+
+ // Node is TEXT_NODE or CDATA
+ if ((startContainer.nodeType === 3 || startContainer.nodeType === 4) && startContainer.nodeValue) {
+ if (!startOffset) {
+ // At the start of text
+ startContainer.parentNode.insertBefore(n, startContainer);
+ } else if (startOffset >= startContainer.nodeValue.length) {
+ // At the end of text
+ dom.insertAfter(n, startContainer);
+ } else {
+ // Middle, need to split
+ nn = startContainer.splitText(startOffset);
+ startContainer.parentNode.insertBefore(n, nn);
+ }
+ } else {
+ // Insert element node
+ if (startContainer.childNodes.length > 0)
+ o = startContainer.childNodes[startOffset];
+
+ if (o)
+ startContainer.insertBefore(n, o);
+ else
+ startContainer.appendChild(n);
+ }
+ };
+
+ function surroundContents(n) {
+ var f = t.extractContents();
+
+ t.insertNode(n);
+ n.appendChild(f);
+ t.selectNode(n);
+ };
+
+ function cloneRange() {
+ return extend(new Range(dom), {
+ startContainer : t[START_CONTAINER],
+ startOffset : t[START_OFFSET],
+ endContainer : t[END_CONTAINER],
+ endOffset : t[END_OFFSET],
+ collapsed : t.collapsed,
+ commonAncestorContainer : t.commonAncestorContainer
+ });
+ };
+
+ // Private methods
+
+ function _getSelectedNode(container, offset) {
+ var child;
+
+ if (container.nodeType == 3 /* TEXT_NODE */)
+ return container;
+
+ if (offset < 0)
+ return container;
+
+ child = container.firstChild;
+ while (child && offset > 0) {
+ --offset;
+ child = child.nextSibling;
+ }
+
+ if (child)
+ return child;
+
+ return container;
+ };
+
+ function _isCollapsed() {
+ return (t[START_CONTAINER] == t[END_CONTAINER] && t[START_OFFSET] == t[END_OFFSET]);
+ };
+
+ function _compareBoundaryPoints(containerA, offsetA, containerB, offsetB) {
+ var c, offsetC, n, cmnRoot, childA, childB;
+
+ // In the first case the boundary-points have the same container. A is before B
+ // if its offset is less than the offset of B, A is equal to B if its offset is
+ // equal to the offset of B, and A is after B if its offset is greater than the
+ // offset of B.
+ if (containerA == containerB) {
+ if (offsetA == offsetB)
+ return 0; // equal
+
+ if (offsetA < offsetB)
+ return -1; // before
+
+ return 1; // after
+ }
+
+ // In the second case a child node C of the container of A is an ancestor
+ // container of B. In this case, A is before B if the offset of A is less than or
+ // equal to the index of the child node C and A is after B otherwise.
+ c = containerB;
+ while (c && c.parentNode != containerA)
+ c = c.parentNode;
+
+ if (c) {
+ offsetC = 0;
+ n = containerA.firstChild;
+
+ while (n != c && offsetC < offsetA) {
+ offsetC++;
+ n = n.nextSibling;
+ }
+
+ if (offsetA <= offsetC)
+ return -1; // before
+
+ return 1; // after
+ }
+
+ // In the third case a child node C of the container of B is an ancestor container
+ // of A. In this case, A is before B if the index of the child node C is less than
+ // the offset of B and A is after B otherwise.
+ c = containerA;
+ while (c && c.parentNode != containerB) {
+ c = c.parentNode;
+ }
+
+ if (c) {
+ offsetC = 0;
+ n = containerB.firstChild;
+
+ while (n != c && offsetC < offsetB) {
+ offsetC++;
+ n = n.nextSibling;
+ }
+
+ if (offsetC < offsetB)
+ return -1; // before
+
+ return 1; // after
+ }
+
+ // In the fourth case, none of three other cases hold: the containers of A and B
+ // are siblings or descendants of sibling nodes. In this case, A is before B if
+ // the container of A is before the container of B in a pre-order traversal of the
+ // Ranges' context tree and A is after B otherwise.
+ cmnRoot = dom.findCommonAncestor(containerA, containerB);
+ childA = containerA;
+
+ while (childA && childA.parentNode != cmnRoot)
+ childA = childA.parentNode;
+
+ if (!childA)
+ childA = cmnRoot;
+
+ childB = containerB;
+ while (childB && childB.parentNode != cmnRoot)
+ childB = childB.parentNode;
+
+ if (!childB)
+ childB = cmnRoot;
+
+ if (childA == childB)
+ return 0; // equal
+
+ n = cmnRoot.firstChild;
+ while (n) {
+ if (n == childA)
+ return -1; // before
+
+ if (n == childB)
+ return 1; // after
+
+ n = n.nextSibling;
+ }
+ };
+
+ function _setEndPoint(st, n, o) {
+ var ec, sc;
+
+ if (st) {
+ t[START_CONTAINER] = n;
+ t[START_OFFSET] = o;
+ } else {
+ t[END_CONTAINER] = n;
+ t[END_OFFSET] = o;
+ }
+
+ // If one boundary-point of a Range is set to have a root container
+ // other than the current one for the Range, the Range is collapsed to
+ // the new position. This enforces the restriction that both boundary-
+ // points of a Range must have the same root container.
+ ec = t[END_CONTAINER];
+ while (ec.parentNode)
+ ec = ec.parentNode;
+
+ sc = t[START_CONTAINER];
+ while (sc.parentNode)
+ sc = sc.parentNode;
+
+ if (sc == ec) {
+ // The start position of a Range is guaranteed to never be after the
+ // end position. To enforce this restriction, if the start is set to
+ // be at a position after the end, the Range is collapsed to that
+ // position.
+ if (_compareBoundaryPoints(t[START_CONTAINER], t[START_OFFSET], t[END_CONTAINER], t[END_OFFSET]) > 0)
+ t.collapse(st);
+ } else
+ t.collapse(st);
+
+ t.collapsed = _isCollapsed();
+ t.commonAncestorContainer = dom.findCommonAncestor(t[START_CONTAINER], t[END_CONTAINER]);
+ };
+
+ function _traverse(how) {
+ var c, endContainerDepth = 0, startContainerDepth = 0, p, depthDiff, startNode, endNode, sp, ep;
+
+ if (t[START_CONTAINER] == t[END_CONTAINER])
+ return _traverseSameContainer(how);
+
+ for (c = t[END_CONTAINER], p = c.parentNode; p; c = p, p = p.parentNode) {
+ if (p == t[START_CONTAINER])
+ return _traverseCommonStartContainer(c, how);
+
+ ++endContainerDepth;
+ }
+
+ for (c = t[START_CONTAINER], p = c.parentNode; p; c = p, p = p.parentNode) {
+ if (p == t[END_CONTAINER])
+ return _traverseCommonEndContainer(c, how);
+
+ ++startContainerDepth;
+ }
+
+ depthDiff = startContainerDepth - endContainerDepth;
+
+ startNode = t[START_CONTAINER];
+ while (depthDiff > 0) {
+ startNode = startNode.parentNode;
+ depthDiff--;
+ }
+
+ endNode = t[END_CONTAINER];
+ while (depthDiff < 0) {
+ endNode = endNode.parentNode;
+ depthDiff++;
+ }
+
+ // ascend the ancestor hierarchy until we have a common parent.
+ for (sp = startNode.parentNode, ep = endNode.parentNode; sp != ep; sp = sp.parentNode, ep = ep.parentNode) {
+ startNode = sp;
+ endNode = ep;
+ }
+
+ return _traverseCommonAncestors(startNode, endNode, how);
+ };
+
+ function _traverseSameContainer(how) {
+ var frag, s, sub, n, cnt, sibling, xferNode, start, len;
+
+ if (how != DELETE)
+ frag = createDocumentFragment();
+
+ // If selection is empty, just return the fragment
+ if (t[START_OFFSET] == t[END_OFFSET])
+ return frag;
+
+ // Text node needs special case handling
+ if (t[START_CONTAINER].nodeType == 3 /* TEXT_NODE */) {
+ // get the substring
+ s = t[START_CONTAINER].nodeValue;
+ sub = s.substring(t[START_OFFSET], t[END_OFFSET]);
+
+ // set the original text node to its new value
+ if (how != CLONE) {
+ n = t[START_CONTAINER];
+ start = t[START_OFFSET];
+ len = t[END_OFFSET] - t[START_OFFSET];
+
+ if (start === 0 && len >= n.nodeValue.length - 1) {
+ n.parentNode.removeChild(n);
+ } else {
+ n.deleteData(start, len);
+ }
+
+ // Nothing is partially selected, so collapse to start point
+ t.collapse(TRUE);
+ }
+
+ if (how == DELETE)
+ return;
+
+ if (sub.length > 0) {
+ frag.appendChild(doc.createTextNode(sub));
+ }
+
+ return frag;
+ }
+
+ // Copy nodes between the start/end offsets.
+ n = _getSelectedNode(t[START_CONTAINER], t[START_OFFSET]);
+ cnt = t[END_OFFSET] - t[START_OFFSET];
+
+ while (n && cnt > 0) {
+ sibling = n.nextSibling;
+ xferNode = _traverseFullySelected(n, how);
+
+ if (frag)
+ frag.appendChild( xferNode );
+
+ --cnt;
+ n = sibling;
+ }
+
+ // Nothing is partially selected, so collapse to start point
+ if (how != CLONE)
+ t.collapse(TRUE);
+
+ return frag;
+ };
+
+ function _traverseCommonStartContainer(endAncestor, how) {
+ var frag, n, endIdx, cnt, sibling, xferNode;
+
+ if (how != DELETE)
+ frag = createDocumentFragment();
+
+ n = _traverseRightBoundary(endAncestor, how);
+
+ if (frag)
+ frag.appendChild(n);
+
+ endIdx = nodeIndex(endAncestor);
+ cnt = endIdx - t[START_OFFSET];
+
+ if (cnt <= 0) {
+ // Collapse to just before the endAncestor, which
+ // is partially selected.
+ if (how != CLONE) {
+ t.setEndBefore(endAncestor);
+ t.collapse(FALSE);
+ }
+
+ return frag;
+ }
+
+ n = endAncestor.previousSibling;
+ while (cnt > 0) {
+ sibling = n.previousSibling;
+ xferNode = _traverseFullySelected(n, how);
+
+ if (frag)
+ frag.insertBefore(xferNode, frag.firstChild);
+
+ --cnt;
+ n = sibling;
+ }
+
+ // Collapse to just before the endAncestor, which
+ // is partially selected.
+ if (how != CLONE) {
+ t.setEndBefore(endAncestor);
+ t.collapse(FALSE);
+ }
+
+ return frag;
+ };
+
+ function _traverseCommonEndContainer(startAncestor, how) {
+ var frag, startIdx, n, cnt, sibling, xferNode;
+
+ if (how != DELETE)
+ frag = createDocumentFragment();
+
+ n = _traverseLeftBoundary(startAncestor, how);
+ if (frag)
+ frag.appendChild(n);
+
+ startIdx = nodeIndex(startAncestor);
+ ++startIdx; // Because we already traversed it
+
+ cnt = t[END_OFFSET] - startIdx;
+ n = startAncestor.nextSibling;
+ while (n && cnt > 0) {
+ sibling = n.nextSibling;
+ xferNode = _traverseFullySelected(n, how);
+
+ if (frag)
+ frag.appendChild(xferNode);
+
+ --cnt;
+ n = sibling;
+ }
+
+ if (how != CLONE) {
+ t.setStartAfter(startAncestor);
+ t.collapse(TRUE);
+ }
+
+ return frag;
+ };
+
+ function _traverseCommonAncestors(startAncestor, endAncestor, how) {
+ var n, frag, commonParent, startOffset, endOffset, cnt, sibling, nextSibling;
+
+ if (how != DELETE)
+ frag = createDocumentFragment();
+
+ n = _traverseLeftBoundary(startAncestor, how);
+ if (frag)
+ frag.appendChild(n);
+
+ commonParent = startAncestor.parentNode;
+ startOffset = nodeIndex(startAncestor);
+ endOffset = nodeIndex(endAncestor);
+ ++startOffset;
+
+ cnt = endOffset - startOffset;
+ sibling = startAncestor.nextSibling;
+
+ while (cnt > 0) {
+ nextSibling = sibling.nextSibling;
+ n = _traverseFullySelected(sibling, how);
+
+ if (frag)
+ frag.appendChild(n);
+
+ sibling = nextSibling;
+ --cnt;
+ }
+
+ n = _traverseRightBoundary(endAncestor, how);
+
+ if (frag)
+ frag.appendChild(n);
+
+ if (how != CLONE) {
+ t.setStartAfter(startAncestor);
+ t.collapse(TRUE);
+ }
+
+ return frag;
+ };
+
+ function _traverseRightBoundary(root, how) {
+ var next = _getSelectedNode(t[END_CONTAINER], t[END_OFFSET] - 1), parent, clonedParent, prevSibling, clonedChild, clonedGrandParent, isFullySelected = next != t[END_CONTAINER];
+
+ if (next == root)
+ return _traverseNode(next, isFullySelected, FALSE, how);
+
+ parent = next.parentNode;
+ clonedParent = _traverseNode(parent, FALSE, FALSE, how);
+
+ while (parent) {
+ while (next) {
+ prevSibling = next.previousSibling;
+ clonedChild = _traverseNode(next, isFullySelected, FALSE, how);
+
+ if (how != DELETE)
+ clonedParent.insertBefore(clonedChild, clonedParent.firstChild);
+
+ isFullySelected = TRUE;
+ next = prevSibling;
+ }
+
+ if (parent == root)
+ return clonedParent;
+
+ next = parent.previousSibling;
+ parent = parent.parentNode;
+
+ clonedGrandParent = _traverseNode(parent, FALSE, FALSE, how);
+
+ if (how != DELETE)
+ clonedGrandParent.appendChild(clonedParent);
+
+ clonedParent = clonedGrandParent;
+ }
+ };
+
+ function _traverseLeftBoundary(root, how) {
+ var next = _getSelectedNode(t[START_CONTAINER], t[START_OFFSET]), isFullySelected = next != t[START_CONTAINER], parent, clonedParent, nextSibling, clonedChild, clonedGrandParent;
+
+ if (next == root)
+ return _traverseNode(next, isFullySelected, TRUE, how);
+
+ parent = next.parentNode;
+ clonedParent = _traverseNode(parent, FALSE, TRUE, how);
+
+ while (parent) {
+ while (next) {
+ nextSibling = next.nextSibling;
+ clonedChild = _traverseNode(next, isFullySelected, TRUE, how);
+
+ if (how != DELETE)
+ clonedParent.appendChild(clonedChild);
+
+ isFullySelected = TRUE;
+ next = nextSibling;
+ }
+
+ if (parent == root)
+ return clonedParent;
+
+ next = parent.nextSibling;
+ parent = parent.parentNode;
+
+ clonedGrandParent = _traverseNode(parent, FALSE, TRUE, how);
+
+ if (how != DELETE)
+ clonedGrandParent.appendChild(clonedParent);
+
+ clonedParent = clonedGrandParent;
+ }
+ };
+
+ function _traverseNode(n, isFullySelected, isLeft, how) {
+ var txtValue, newNodeValue, oldNodeValue, offset, newNode;
+
+ if (isFullySelected)
+ return _traverseFullySelected(n, how);
+
+ if (n.nodeType == 3 /* TEXT_NODE */) {
+ txtValue = n.nodeValue;
+
+ if (isLeft) {
+ offset = t[START_OFFSET];
+ newNodeValue = txtValue.substring(offset);
+ oldNodeValue = txtValue.substring(0, offset);
+ } else {
+ offset = t[END_OFFSET];
+ newNodeValue = txtValue.substring(0, offset);
+ oldNodeValue = txtValue.substring(offset);
+ }
+
+ if (how != CLONE)
+ n.nodeValue = oldNodeValue;
+
+ if (how == DELETE)
+ return;
+
+ newNode = dom.clone(n, FALSE);
+ newNode.nodeValue = newNodeValue;
+
+ return newNode;
+ }
+
+ if (how == DELETE)
+ return;
+
+ return dom.clone(n, FALSE);
+ };
+
+ function _traverseFullySelected(n, how) {
+ if (how != DELETE)
+ return how == CLONE ? dom.clone(n, TRUE) : n;
+
+ n.parentNode.removeChild(n);
+ };
+
+ function toStringIE() {
+ return dom.create('body', null, cloneContents()).outerText;
+ }
+
+ return t;
+ };
+
+ ns.Range = Range;
+
+ // Older IE versions doesn't let you override toString by it's constructor so we have to stick it in the prototype
+ Range.prototype.toString = function() {
+ return this.toStringIE();
+ };
+})(tinymce.dom);
+
+(function() {
+ function Selection(selection) {
+ var self = this, dom = selection.dom, TRUE = true, FALSE = false;
+
+ function getPosition(rng, start) {
+ var checkRng, startIndex = 0, endIndex, inside,
+ children, child, offset, index, position = -1, parent;
+
+ // Setup test range, collapse it and get the parent
+ checkRng = rng.duplicate();
+ checkRng.collapse(start);
+ parent = checkRng.parentElement();
+
+ // Check if the selection is within the right document
+ if (parent.ownerDocument !== selection.dom.doc)
+ return;
+
+ // IE will report non editable elements as it's parent so look for an editable one
+ while (parent.contentEditable === "false") {
+ parent = parent.parentNode;
+ }
+
+ // If parent doesn't have any children then return that we are inside the element
+ if (!parent.hasChildNodes()) {
+ return {node : parent, inside : 1};
+ }
+
+ // Setup node list and endIndex
+ children = parent.children;
+ endIndex = children.length - 1;
+
+ // Perform a binary search for the position
+ while (startIndex <= endIndex) {
+ index = Math.floor((startIndex + endIndex) / 2);
+
+ // Move selection to node and compare the ranges
+ child = children[index];
+ checkRng.moveToElementText(child);
+ position = checkRng.compareEndPoints(start ? 'StartToStart' : 'EndToEnd', rng);
+
+ // Before/after or an exact match
+ if (position > 0) {
+ endIndex = index - 1;
+ } else if (position < 0) {
+ startIndex = index + 1;
+ } else {
+ return {node : child};
+ }
+ }
+
+ // Check if child position is before or we didn't find a position
+ if (position < 0) {
+ // No element child was found use the parent element and the offset inside that
+ if (!child) {
+ checkRng.moveToElementText(parent);
+ checkRng.collapse(true);
+ child = parent;
+ inside = true;
+ } else
+ checkRng.collapse(false);
+
+ // Walk character by character in text node until we hit the selected range endpoint, hit the end of document or parent isn't the right one
+ // We need to walk char by char since rng.text or rng.htmlText will trim line endings
+ offset = 0;
+ while (checkRng.compareEndPoints(start ? 'StartToStart' : 'StartToEnd', rng) !== 0) {
+ if (checkRng.move('character', 1) === 0 || parent != checkRng.parentElement()) {
+ break;
+ }
+
+ offset++;
+ }
+ } else {
+ // Child position is after the selection endpoint
+ checkRng.collapse(true);
+
+ // Walk character by character in text node until we hit the selected range endpoint, hit the end of document or parent isn't the right one
+ offset = 0;
+ while (checkRng.compareEndPoints(start ? 'StartToStart' : 'StartToEnd', rng) !== 0) {
+ if (checkRng.move('character', -1) === 0 || parent != checkRng.parentElement()) {
+ break;
+ }
+
+ offset++;
+ }
+ }
+
+ return {node : child, position : position, offset : offset, inside : inside};
+ };
+
+ // Returns a W3C DOM compatible range object by using the IE Range API
+ function getRange() {
+ var ieRange = selection.getRng(), domRange = dom.createRng(), element, collapsed, tmpRange, element2, bookmark, fail;
+
+ // If selection is outside the current document just return an empty range
+ element = ieRange.item ? ieRange.item(0) : ieRange.parentElement();
+ if (element.ownerDocument != dom.doc)
+ return domRange;
+
+ collapsed = selection.isCollapsed();
+
+ // Handle control selection
+ if (ieRange.item) {
+ domRange.setStart(element.parentNode, dom.nodeIndex(element));
+ domRange.setEnd(domRange.startContainer, domRange.startOffset + 1);
+
+ return domRange;
+ }
+
+ function findEndPoint(start) {
+ var endPoint = getPosition(ieRange, start), container, offset, textNodeOffset = 0, sibling, undef, nodeValue;
+
+ container = endPoint.node;
+ offset = endPoint.offset;
+
+ if (endPoint.inside && !container.hasChildNodes()) {
+ domRange[start ? 'setStart' : 'setEnd'](container, 0);
+ return;
+ }
+
+ if (offset === undef) {
+ domRange[start ? 'setStartBefore' : 'setEndAfter'](container);
+ return;
+ }
+
+ if (endPoint.position < 0) {
+ sibling = endPoint.inside ? container.firstChild : container.nextSibling;
+
+ if (!sibling) {
+ domRange[start ? 'setStartAfter' : 'setEndAfter'](container);
+ return;
+ }
+
+ if (!offset) {
+ if (sibling.nodeType == 3)
+ domRange[start ? 'setStart' : 'setEnd'](sibling, 0);
+ else
+ domRange[start ? 'setStartBefore' : 'setEndBefore'](sibling);
+
+ return;
+ }
+
+ // Find the text node and offset
+ while (sibling) {
+ nodeValue = sibling.nodeValue;
+ textNodeOffset += nodeValue.length;
+
+ // We are at or passed the position we where looking for
+ if (textNodeOffset >= offset) {
+ container = sibling;
+ textNodeOffset -= offset;
+ textNodeOffset = nodeValue.length - textNodeOffset;
+ break;
+ }
+
+ sibling = sibling.nextSibling;
+ }
+ } else {
+ // Find the text node and offset
+ sibling = container.previousSibling;
+
+ if (!sibling)
+ return domRange[start ? 'setStartBefore' : 'setEndBefore'](container);
+
+ // If there isn't any text to loop then use the first position
+ if (!offset) {
+ if (container.nodeType == 3)
+ domRange[start ? 'setStart' : 'setEnd'](sibling, container.nodeValue.length);
+ else
+ domRange[start ? 'setStartAfter' : 'setEndAfter'](sibling);
+
+ return;
+ }
+
+ while (sibling) {
+ textNodeOffset += sibling.nodeValue.length;
+
+ // We are at or passed the position we where looking for
+ if (textNodeOffset >= offset) {
+ container = sibling;
+ textNodeOffset -= offset;
+ break;
+ }
+
+ sibling = sibling.previousSibling;
+ }
+ }
+
+ domRange[start ? 'setStart' : 'setEnd'](container, textNodeOffset);
+ };
+
+ try {
+ // Find start point
+ findEndPoint(true);
+
+ // Find end point if needed
+ if (!collapsed)
+ findEndPoint();
+ } catch (ex) {
+ // IE has a nasty bug where text nodes might throw "invalid argument" when you
+ // access the nodeValue or other properties of text nodes. This seems to happend when
+ // text nodes are split into two nodes by a delete/backspace call. So lets detect it and try to fix it.
+ if (ex.number == -2147024809) {
+ // Get the current selection
+ bookmark = self.getBookmark(2);
+
+ // Get start element
+ tmpRange = ieRange.duplicate();
+ tmpRange.collapse(true);
+ element = tmpRange.parentElement();
+
+ // Get end element
+ if (!collapsed) {
+ tmpRange = ieRange.duplicate();
+ tmpRange.collapse(false);
+ element2 = tmpRange.parentElement();
+ element2.innerHTML = element2.innerHTML;
+ }
+
+ // Remove the broken elements
+ element.innerHTML = element.innerHTML;
+
+ // Restore the selection
+ self.moveToBookmark(bookmark);
+
+ // Since the range has moved we need to re-get it
+ ieRange = selection.getRng();
+
+ // Find start point
+ findEndPoint(true);
+
+ // Find end point if needed
+ if (!collapsed)
+ findEndPoint();
+ } else
+ throw ex; // Throw other errors
+ }
+
+ return domRange;
+ };
+
+ this.getBookmark = function(type) {
+ var rng = selection.getRng(), start, end, bookmark = {};
+
+ function getIndexes(node) {
+ var parent, root, children, i, indexes = [];
+
+ parent = node.parentNode;
+ root = dom.getRoot().parentNode;
+
+ while (parent != root && parent.nodeType !== 9) {
+ children = parent.children;
+
+ i = children.length;
+ while (i--) {
+ if (node === children[i]) {
+ indexes.push(i);
+ break;
+ }
+ }
+
+ node = parent;
+ parent = parent.parentNode;
+ }
+
+ return indexes;
+ };
+
+ function getBookmarkEndPoint(start) {
+ var position;
+
+ position = getPosition(rng, start);
+ if (position) {
+ return {
+ position : position.position,
+ offset : position.offset,
+ indexes : getIndexes(position.node),
+ inside : position.inside
+ };
+ }
+ };
+
+ // Non ubstructive bookmark
+ if (type === 2) {
+ // Handle text selection
+ if (!rng.item) {
+ bookmark.start = getBookmarkEndPoint(true);
+
+ if (!selection.isCollapsed())
+ bookmark.end = getBookmarkEndPoint();
+ } else
+ bookmark.start = {ctrl : true, indexes : getIndexes(rng.item(0))};
+ }
+
+ return bookmark;
+ };
+
+ this.moveToBookmark = function(bookmark) {
+ var rng, body = dom.doc.body;
+
+ function resolveIndexes(indexes) {
+ var node, i, idx, children;
+
+ node = dom.getRoot();
+ for (i = indexes.length - 1; i >= 0; i--) {
+ children = node.children;
+ idx = indexes[i];
+
+ if (idx <= children.length - 1) {
+ node = children[idx];
+ }
+ }
+
+ return node;
+ };
+
+ function setBookmarkEndPoint(start) {
+ var endPoint = bookmark[start ? 'start' : 'end'], moveLeft, moveRng, undef;
+
+ if (endPoint) {
+ moveLeft = endPoint.position > 0;
+
+ moveRng = body.createTextRange();
+ moveRng.moveToElementText(resolveIndexes(endPoint.indexes));
+
+ offset = endPoint.offset;
+ if (offset !== undef) {
+ moveRng.collapse(endPoint.inside || moveLeft);
+ moveRng.moveStart('character', moveLeft ? -offset : offset);
+ } else
+ moveRng.collapse(start);
+
+ rng.setEndPoint(start ? 'StartToStart' : 'EndToStart', moveRng);
+
+ if (start)
+ rng.collapse(true);
+ }
+ };
+
+ if (bookmark.start) {
+ if (bookmark.start.ctrl) {
+ rng = body.createControlRange();
+ rng.addElement(resolveIndexes(bookmark.start.indexes));
+ rng.select();
+ } else {
+ rng = body.createTextRange();
+ setBookmarkEndPoint(true);
+ setBookmarkEndPoint();
+ rng.select();
+ }
+ }
+ };
+
+ this.addRange = function(rng) {
+ var ieRng, ctrlRng, startContainer, startOffset, endContainer, endOffset, sibling, doc = selection.dom.doc, body = doc.body;
+
+ function setEndPoint(start) {
+ var container, offset, marker, tmpRng, nodes;
+
+ marker = dom.create('a');
+ container = start ? startContainer : endContainer;
+ offset = start ? startOffset : endOffset;
+ tmpRng = ieRng.duplicate();
+
+ if (container == doc || container == doc.documentElement) {
+ container = body;
+ offset = 0;
+ }
+
+ if (container.nodeType == 3) {
+ container.parentNode.insertBefore(marker, container);
+ tmpRng.moveToElementText(marker);
+ tmpRng.moveStart('character', offset);
+ dom.remove(marker);
+ ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng);
+ } else {
+ nodes = container.childNodes;
+
+ if (nodes.length) {
+ if (offset >= nodes.length) {
+ dom.insertAfter(marker, nodes[nodes.length - 1]);
+ } else {
+ container.insertBefore(marker, nodes[offset]);
+ }
+
+ tmpRng.moveToElementText(marker);
+ } else if (container.canHaveHTML) {
+ // Empty node selection for example <div>|</div>
+ // Setting innerHTML with a span marker then remove that marker seems to keep empty block elements open
+ container.innerHTML = '<span>\uFEFF</span>';
+ marker = container.firstChild;
+ tmpRng.moveToElementText(marker);
+ tmpRng.collapse(FALSE); // Collapse false works better than true for some odd reason
+ }
+
+ ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng);
+ dom.remove(marker);
+ }
+ }
+
+ // Setup some shorter versions
+ startContainer = rng.startContainer;
+ startOffset = rng.startOffset;
+ endContainer = rng.endContainer;
+ endOffset = rng.endOffset;
+ ieRng = body.createTextRange();
+
+ // If single element selection then try making a control selection out of it
+ if (startContainer == endContainer && startContainer.nodeType == 1) {
+ // Trick to place the caret inside an empty block element like <p></p>
+ if (startOffset == endOffset && !startContainer.hasChildNodes()) {
+ if (startContainer.canHaveHTML) {
+ // Check if previous sibling is an empty block if it is then we need to render it
+ // IE would otherwise move the caret into the sibling instead of the empty startContainer see: #5236
+ // Example this: <p></p><p>|</p> would become this: <p>|</p><p></p>
+ sibling = startContainer.previousSibling;
+ if (sibling && !sibling.hasChildNodes() && dom.isBlock(sibling)) {
+ sibling.innerHTML = '\uFEFF';
+ } else {
+ sibling = null;
+ }
+
+ startContainer.innerHTML = '<span>\uFEFF</span><span>\uFEFF</span>';
+ ieRng.moveToElementText(startContainer.lastChild);
+ ieRng.select();
+ dom.doc.selection.clear();
+ startContainer.innerHTML = '';
+
+ if (sibling) {
+ sibling.innerHTML = '';
+ }
+ return;
+ } else {
+ startOffset = dom.nodeIndex(startContainer);
+ startContainer = startContainer.parentNode;
+ }
+ }
+
+ if (startOffset == endOffset - 1) {
+ try {
+ ctrlRng = body.createControlRange();
+ ctrlRng.addElement(startContainer.childNodes[startOffset]);
+ ctrlRng.select();
+ return;
+ } catch (ex) {
+ // Ignore
+ }
+ }
+ }
+
+ // Set start/end point of selection
+ setEndPoint(true);
+ setEndPoint();
+
+ // Select the new range and scroll it into view
+ ieRng.select();
+ };
+
+ // Expose range method
+ this.getRangeAt = getRange;
+ };
+
+ // Expose the selection object
+ tinymce.dom.TridentSelection = Selection;
+})();
+
+
+/*
+ * Sizzle CSS Selector Engine
+ * Copyright, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ * More information: http://sizzlejs.com/
+ */
+(function(){
+
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+ expando = "sizcache",
+ done = 0,
+ toString = Object.prototype.toString,
+ hasDuplicate = false,
+ baseHasDuplicate = true,
+ rBackslash = /\\/g,
+ rReturn = /\r\n/g,
+ rNonWord = /\W/;
+
+// Here we check if the JavaScript engine is using some sort of
+// optimization where it does not always call our comparision
+// function. If that is the case, discard the hasDuplicate value.
+// Thus far that includes Google Chrome.
+[0, 0].sort(function() {
+ baseHasDuplicate = false;
+ return 0;
+});
+
+var Sizzle = function( selector, context, results, seed ) {
+ results = results || [];
+ context = context || document;
+
+ var origContext = context;
+
+ if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
+ return [];
+ }
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ var m, set, checkSet, extra, ret, cur, pop, i,
+ prune = true,
+ contextXML = Sizzle.isXML( context ),
+ parts = [],
+ soFar = selector;
+
+ // Reset the position of the chunker regexp (start from head)
+ do {
+ chunker.exec( "" );
+ m = chunker.exec( soFar );
+
+ if ( m ) {
+ soFar = m[3];
+
+ parts.push( m[1] );
+
+ if ( m[2] ) {
+ extra = m[3];
+ break;
+ }
+ }
+ } while ( m );
+
+ if ( parts.length > 1 && origPOS.exec( selector ) ) {
+
+ if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
+ set = posProcess( parts[0] + parts[1], context, seed );
+
+ } else {
+ set = Expr.relative[ parts[0] ] ?
+ [ context ] :
+ Sizzle( parts.shift(), context );
+
+ while ( parts.length ) {
+ selector = parts.shift();
+
+ if ( Expr.relative[ selector ] ) {
+ selector += parts.shift();
+ }
+
+ set = posProcess( selector, set, seed );
+ }
+ }
+
+ } else {
+ // Take a shortcut and set the context if the root selector is an ID
+ // (but not if it'll be faster if the inner selector is an ID)
+ if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
+ Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
+
+ ret = Sizzle.find( parts.shift(), context, contextXML );
+ context = ret.expr ?
+ Sizzle.filter( ret.expr, ret.set )[0] :
+ ret.set[0];
+ }
+
+ if ( context ) {
+ ret = seed ?
+ { expr: parts.pop(), set: makeArray(seed) } :
+ Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
+
+ set = ret.expr ?
+ Sizzle.filter( ret.expr, ret.set ) :
+ ret.set;
+
+ if ( parts.length > 0 ) {
+ checkSet = makeArray( set );
+
+ } else {
+ prune = false;
+ }
+
+ while ( parts.length ) {
+ cur = parts.pop();
+ pop = cur;
+
+ if ( !Expr.relative[ cur ] ) {
+ cur = "";
+ } else {
+ pop = parts.pop();
+ }
+
+ if ( pop == null ) {
+ pop = context;
+ }
+
+ Expr.relative[ cur ]( checkSet, pop, contextXML );
+ }
+
+ } else {
+ checkSet = parts = [];
+ }
+ }
+
+ if ( !checkSet ) {
+ checkSet = set;
+ }
+
+ if ( !checkSet ) {
+ Sizzle.error( cur || selector );
+ }
+
+ if ( toString.call(checkSet) === "[object Array]" ) {
+ if ( !prune ) {
+ results.push.apply( results, checkSet );
+
+ } else if ( context && context.nodeType === 1 ) {
+ for ( i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
+ results.push( set[i] );
+ }
+ }
+
+ } else {
+ for ( i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
+ results.push( set[i] );
+ }
+ }
+ }
+
+ } else {
+ makeArray( checkSet, results );
+ }
+
+ if ( extra ) {
+ Sizzle( extra, origContext, results, seed );
+ Sizzle.uniqueSort( results );
+ }
+
+ return results;
+};
+
+Sizzle.uniqueSort = function( results ) {
+ if ( sortOrder ) {
+ hasDuplicate = baseHasDuplicate;
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ for ( var i = 1; i < results.length; i++ ) {
+ if ( results[i] === results[ i - 1 ] ) {
+ results.splice( i--, 1 );
+ }
+ }
+ }
+ }
+
+ return results;
+};
+
+Sizzle.matches = function( expr, set ) {
+ return Sizzle( expr, null, null, set );
+};
+
+Sizzle.matchesSelector = function( node, expr ) {
+ return Sizzle( expr, null, null, [node] ).length > 0;
+};
+
+Sizzle.find = function( expr, context, isXML ) {
+ var set, i, len, match, type, left;
+
+ if ( !expr ) {
+ return [];
+ }
+
+ for ( i = 0, len = Expr.order.length; i < len; i++ ) {
+ type = Expr.order[i];
+
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
+ left = match[1];
+ match.splice( 1, 1 );
+
+ if ( left.substr( left.length - 1 ) !== "\\" ) {
+ match[1] = (match[1] || "").replace( rBackslash, "" );
+ set = Expr.find[ type ]( match, context, isXML );
+
+ if ( set != null ) {
+ expr = expr.replace( Expr.match[ type ], "" );
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !set ) {
+ set = typeof context.getElementsByTagName !== "undefined" ?
+ context.getElementsByTagName( "*" ) :
+ [];
+ }
+
+ return { set: set, expr: expr };
+};
+
+Sizzle.filter = function( expr, set, inplace, not ) {
+ var match, anyFound,
+ type, found, item, filter, left,
+ i, pass,
+ old = expr,
+ result = [],
+ curLoop = set,
+ isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
+
+ while ( expr && set.length ) {
+ for ( type in Expr.filter ) {
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
+ filter = Expr.filter[ type ];
+ left = match[1];
+
+ anyFound = false;
+
+ match.splice(1,1);
+
+ if ( left.substr( left.length - 1 ) === "\\" ) {
+ continue;
+ }
+
+ if ( curLoop === result ) {
+ result = [];
+ }
+
+ if ( Expr.preFilter[ type ] ) {
+ match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
+
+ if ( !match ) {
+ anyFound = found = true;
+
+ } else if ( match === true ) {
+ continue;
+ }
+ }
+
+ if ( match ) {
+ for ( i = 0; (item = curLoop[i]) != null; i++ ) {
+ if ( item ) {
+ found = filter( item, match, i, curLoop );
+ pass = not ^ found;
+
+ if ( inplace && found != null ) {
+ if ( pass ) {
+ anyFound = true;
+
+ } else {
+ curLoop[i] = false;
+ }
+
+ } else if ( pass ) {
+ result.push( item );
+ anyFound = true;
+ }
+ }
+ }
+ }
+
+ if ( found !== undefined ) {
+ if ( !inplace ) {
+ curLoop = result;
+ }
+
+ expr = expr.replace( Expr.match[ type ], "" );
+
+ if ( !anyFound ) {
+ return [];
+ }
+
+ break;
+ }
+ }
+ }
+
+ // Improper expression
+ if ( expr === old ) {
+ if ( anyFound == null ) {
+ Sizzle.error( expr );
+
+ } else {
+ break;
+ }
+ }
+
+ old = expr;
+ }
+
+ return curLoop;
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+var getText = Sizzle.getText = function( elem ) {
+ var i, node,
+ nodeType = elem.nodeType,
+ ret = "";
+
+ if ( nodeType ) {
+ if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent || innerText for elements
+ if ( typeof elem.textContent === 'string' ) {
+ return elem.textContent;
+ } else if ( typeof elem.innerText === 'string' ) {
+ // Replace IE's carriage returns
+ return elem.innerText.replace( rReturn, '' );
+ } else {
+ // Traverse it's children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ } else {
+
+ // If no nodeType, this is expected to be an array
+ for ( i = 0; (node = elem[i]); i++ ) {
+ // Do not traverse comment nodes
+ if ( node.nodeType !== 8 ) {
+ ret += getText( node );
+ }
+ }
+ }
+ return ret;
+};
+
+var Expr = Sizzle.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|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
+ TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
+ CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
+ POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
+ PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
+ },
+
+ leftMatch: {},
+
+ attrMap: {
+ "class": "className",
+ "for": "htmlFor"
+ },
+
+ attrHandle: {
+ href: function( elem ) {
+ return elem.getAttribute( "href" );
+ },
+ type: function( elem ) {
+ return elem.getAttribute( "type" );
+ }
+ },
+
+ relative: {
+ "+": function(checkSet, part){
+ var isPartStr = typeof part === "string",
+ isTag = isPartStr && !rNonWord.test( part ),
+ isPartStrNotTag = isPartStr && !isTag;
+
+ if ( isTag ) {
+ part = part.toLowerCase();
+ }
+
+ for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
+ if ( (elem = checkSet[i]) ) {
+ while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
+
+ checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
+ elem || false :
+ elem === part;
+ }
+ }
+
+ if ( isPartStrNotTag ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ },
+
+ ">": function( checkSet, part ) {
+ var elem,
+ isPartStr = typeof part === "string",
+ i = 0,
+ l = checkSet.length;
+
+ if ( isPartStr && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+
+ for ( ; i < l; i++ ) {
+ elem = checkSet[i];
+
+ if ( elem ) {
+ var parent = elem.parentNode;
+ checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
+ }
+ }
+
+ } else {
+ for ( ; i < l; i++ ) {
+ elem = checkSet[i];
+
+ if ( elem ) {
+ checkSet[i] = isPartStr ?
+ elem.parentNode :
+ elem.parentNode === part;
+ }
+ }
+
+ if ( isPartStr ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ }
+ },
+
+ "": function(checkSet, part, isXML){
+ var nodeCheck,
+ doneName = done++,
+ checkFn = dirCheck;
+
+ if ( typeof part === "string" && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+ nodeCheck = part;
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
+ },
+
+ "~": function( checkSet, part, isXML ) {
+ var nodeCheck,
+ doneName = done++,
+ checkFn = dirCheck;
+
+ if ( typeof part === "string" && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+ nodeCheck = part;
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
+ }
+ },
+
+ find: {
+ ID: function( match, context, isXML ) {
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [m] : [];
+ }
+ },
+
+ NAME: function( match, context ) {
+ if ( typeof context.getElementsByName !== "undefined" ) {
+ var ret = [],
+ results = context.getElementsByName( match[1] );
+
+ for ( var i = 0, l = results.length; i < l; i++ ) {
+ if ( results[i].getAttribute("name") === match[1] ) {
+ ret.push( results[i] );
+ }
+ }
+
+ return ret.length === 0 ? null : ret;
+ }
+ },
+
+ TAG: function( match, context ) {
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ return context.getElementsByTagName( match[1] );
+ }
+ }
+ },
+ preFilter: {
+ CLASS: function( match, curLoop, inplace, result, not, isXML ) {
+ match = " " + match[1].replace( rBackslash, "" ) + " ";
+
+ if ( isXML ) {
+ return match;
+ }
+
+ for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
+ if ( elem ) {
+ if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
+ if ( !inplace ) {
+ result.push( elem );
+ }
+
+ } else if ( inplace ) {
+ curLoop[i] = false;
+ }
+ }
+ }
+
+ return false;
+ },
+
+ ID: function( match ) {
+ return match[1].replace( rBackslash, "" );
+ },
+
+ TAG: function( match, curLoop ) {
+ return match[1].replace( rBackslash, "" ).toLowerCase();
+ },
+
+ CHILD: function( match ) {
+ if ( match[1] === "nth" ) {
+ if ( !match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ match[2] = match[2].replace(/^\+|\s*/g, '');
+
+ // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+ var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
+ match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
+ !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
+
+ // calculate the numbers (first)n+(last) including if they are negative
+ match[2] = (test[1] + (test[2] || 1)) - 0;
+ match[3] = test[3] - 0;
+ }
+ else if ( match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // TODO: Move to normal caching system
+ match[0] = done++;
+
+ return match;
+ },
+
+ ATTR: function( match, curLoop, inplace, result, not, isXML ) {
+ var name = match[1] = match[1].replace( rBackslash, "" );
+
+ if ( !isXML && Expr.attrMap[name] ) {
+ match[1] = Expr.attrMap[name];
+ }
+
+ // Handle if an un-quoted value was used
+ match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
+
+ if ( match[2] === "~=" ) {
+ match[4] = " " + match[4] + " ";
+ }
+
+ return match;
+ },
+
+ PSEUDO: function( match, curLoop, inplace, result, not ) {
+ if ( match[1] === "not" ) {
+ // If we're dealing with a complex expression, or a simple one
+ if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
+ match[3] = Sizzle(match[3], null, null, curLoop);
+
+ } else {
+ var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
+
+ if ( !inplace ) {
+ result.push.apply( result, ret );
+ }
+
+ return false;
+ }
+
+ } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
+ return true;
+ }
+
+ return match;
+ },
+
+ POS: function( match ) {
+ match.unshift( true );
+
+ return match;
+ }
+ },
+
+ filters: {
+ enabled: function( elem ) {
+ return elem.disabled === false && elem.type !== "hidden";
+ },
+
+ disabled: function( elem ) {
+ return elem.disabled === true;
+ },
+
+ checked: function( elem ) {
+ return elem.checked === true;
+ },
+
+ selected: function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ parent: function( elem ) {
+ return !!elem.firstChild;
+ },
+
+ empty: function( elem ) {
+ return !elem.firstChild;
+ },
+
+ has: function( elem, i, match ) {
+ return !!Sizzle( match[3], elem ).length;
+ },
+
+ header: function( elem ) {
+ return (/h\d/i).test( elem.nodeName );
+ },
+
+ text: function( elem ) {
+ var attr = elem.getAttribute( "type" ), type = elem.type;
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+ // use getAttribute instead to test this case
+ return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
+ },
+
+ radio: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
+ },
+
+ checkbox: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
+ },
+
+ file: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
+ },
+
+ password: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
+ },
+
+ submit: function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && "submit" === elem.type;
+ },
+
+ image: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
+ },
+
+ reset: function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && "reset" === elem.type;
+ },
+
+ button: function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && "button" === elem.type || name === "button";
+ },
+
+ input: function( elem ) {
+ return (/input|select|textarea|button/i).test( elem.nodeName );
+ },
+
+ focus: function( elem ) {
+ return elem === elem.ownerDocument.activeElement;
+ }
+ },
+ setFilters: {
+ first: function( elem, i ) {
+ return i === 0;
+ },
+
+ last: function( elem, i, match, array ) {
+ return i === array.length - 1;
+ },
+
+ even: function( elem, i ) {
+ return i % 2 === 0;
+ },
+
+ odd: function( elem, i ) {
+ return i % 2 === 1;
+ },
+
+ lt: function( elem, i, match ) {
+ return i < match[3] - 0;
+ },
+
+ gt: function( elem, i, match ) {
+ return i > match[3] - 0;
+ },
+
+ nth: function( elem, i, match ) {
+ return match[3] - 0 === i;
+ },
+
+ eq: function( elem, i, match ) {
+ return match[3] - 0 === i;
+ }
+ },
+ filter: {
+ PSEUDO: function( elem, match, i, array ) {
+ var name = match[1],
+ filter = Expr.filters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+
+ } else if ( name === "contains" ) {
+ return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
+
+ } else if ( name === "not" ) {
+ var not = match[3];
+
+ for ( var j = 0, l = not.length; j < l; j++ ) {
+ if ( not[j] === elem ) {
+ return false;
+ }
+ }
+
+ return true;
+
+ } else {
+ Sizzle.error( name );
+ }
+ },
+
+ CHILD: function( elem, match ) {
+ var first, last,
+ doneName, parent, cache,
+ count, diff,
+ type = match[1],
+ node = elem;
+
+ switch ( type ) {
+ case "only":
+ case "first":
+ while ( (node = node.previousSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ if ( type === "first" ) {
+ return true;
+ }
+
+ node = elem;
+
+ /* falls through */
+ case "last":
+ while ( (node = node.nextSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ return true;
+
+ case "nth":
+ first = match[2];
+ last = match[3];
+
+ if ( first === 1 && last === 0 ) {
+ return true;
+ }
+
+ doneName = match[0];
+ parent = elem.parentNode;
+
+ if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {
+ count = 0;
+
+ for ( node = parent.firstChild; node; node = node.nextSibling ) {
+ if ( node.nodeType === 1 ) {
+ node.nodeIndex = ++count;
+ }
+ }
+
+ parent[ expando ] = doneName;
+ }
+
+ diff = elem.nodeIndex - last;
+
+ if ( first === 0 ) {
+ return diff === 0;
+
+ } else {
+ return ( diff % first === 0 && diff / first >= 0 );
+ }
+ }
+ },
+
+ ID: function( elem, match ) {
+ return elem.nodeType === 1 && elem.getAttribute("id") === match;
+ },
+
+ TAG: function( elem, match ) {
+ return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;
+ },
+
+ CLASS: function( elem, match ) {
+ return (" " + (elem.className || elem.getAttribute("class")) + " ")
+ .indexOf( match ) > -1;
+ },
+
+ ATTR: function( elem, match ) {
+ var name = match[1],
+ result = Sizzle.attr ?
+ Sizzle.attr( elem, name ) :
+ Expr.attrHandle[ name ] ?
+ Expr.attrHandle[ name ]( elem ) :
+ elem[ name ] != null ?
+ elem[ name ] :
+ elem.getAttribute( name ),
+ value = result + "",
+ type = match[2],
+ check = match[4];
+
+ return result == null ?
+ type === "!=" :
+ !type && Sizzle.attr ?
+ result != null :
+ type === "=" ?
+ value === check :
+ type === "*=" ?
+ value.indexOf(check) >= 0 :
+ type === "~=" ?
+ (" " + value + " ").indexOf(check) >= 0 :
+ !check ?
+ value && result !== false :
+ type === "!=" ?
+ value !== check :
+ type === "^=" ?
+ value.indexOf(check) === 0 :
+ type === "$=" ?
+ value.substr(value.length - check.length) === check :
+ type === "|=" ?
+ value === check || value.substr(0, check.length + 1) === check + "-" :
+ false;
+ },
+
+ POS: function( elem, match, i, array ) {
+ var name = match[2],
+ filter = Expr.setFilters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+ }
+ }
+ }
+};
+
+var origPOS = Expr.match.POS,
+ fescape = function(all, num){
+ return "\\" + (num - 0 + 1);
+ };
+
+for ( var type in Expr.match ) {
+ Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
+ Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
+}
+// Expose origPOS
+// "global" as in regardless of relation to brackets/parens
+Expr.match.globalPOS = origPOS;
+
+var makeArray = function( array, results ) {
+ array = Array.prototype.slice.call( array, 0 );
+
+ if ( results ) {
+ results.push.apply( results, array );
+ return results;
+ }
+
+ return array;
+};
+
+// Perform a simple check to determine if the browser is capable of
+// converting a NodeList to an array using builtin methods.
+// Also verifies that the returned array holds DOM nodes
+// (which is not the case in the Blackberry browser)
+try {
+ Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
+
+// Provide a fallback method if it does not work
+} catch( e ) {
+ makeArray = function( array, results ) {
+ var i = 0,
+ ret = results || [];
+
+ if ( toString.call(array) === "[object Array]" ) {
+ Array.prototype.push.apply( ret, array );
+
+ } else {
+ if ( typeof array.length === "number" ) {
+ for ( var l = array.length; i < l; i++ ) {
+ ret.push( array[i] );
+ }
+
+ } else {
+ for ( ; array[i]; i++ ) {
+ ret.push( array[i] );
+ }
+ }
+ }
+
+ return ret;
+ };
+}
+
+var sortOrder, siblingCheck;
+
+if ( document.documentElement.compareDocumentPosition ) {
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
+ return a.compareDocumentPosition ? -1 : 1;
+ }
+
+ return a.compareDocumentPosition(b) & 4 ? -1 : 1;
+ };
+
+} else {
+ sortOrder = function( a, b ) {
+ // The nodes are identical, we can exit early
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+
+ // Fallback to using sourceIndex (in IE) if it's available on both nodes
+ } else if ( a.sourceIndex && b.sourceIndex ) {
+ return a.sourceIndex - b.sourceIndex;
+ }
+
+ var al, bl,
+ ap = [],
+ bp = [],
+ aup = a.parentNode,
+ bup = b.parentNode,
+ cur = aup;
+
+ // If the nodes are siblings (or identical) we can do a quick check
+ if ( aup === bup ) {
+ return siblingCheck( a, b );
+
+ // If no parents were found then the nodes are disconnected
+ } else if ( !aup ) {
+ return -1;
+
+ } else if ( !bup ) {
+ return 1;
+ }
+
+ // Otherwise they're somewhere else in the tree so we need
+ // to build up a full list of the parentNodes for comparison
+ while ( cur ) {
+ ap.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ cur = bup;
+
+ while ( cur ) {
+ bp.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ al = ap.length;
+ bl = bp.length;
+
+ // Start walking down the tree looking for a discrepancy
+ for ( var i = 0; i < al && i < bl; i++ ) {
+ if ( ap[i] !== bp[i] ) {
+ return siblingCheck( ap[i], bp[i] );
+ }
+ }
+
+ // We ended someplace up the tree so do a sibling check
+ return i === al ?
+ siblingCheck( a, bp[i], -1 ) :
+ siblingCheck( ap[i], b, 1 );
+ };
+
+ siblingCheck = function( a, b, ret ) {
+ if ( a === b ) {
+ return ret;
+ }
+
+ var cur = a.nextSibling;
+
+ while ( cur ) {
+ if ( cur === b ) {
+ return -1;
+ }
+
+ cur = cur.nextSibling;
+ }
+
+ return 1;
+ };
+}
+
+// Check to see if the browser returns elements by name when
+// querying by getElementById (and provide a workaround)
+(function(){
+ // We're going to inject a fake input element with a specified name
+ var form = document.createElement("div"),
+ id = "script" + (new Date()).getTime(),
+ root = document.documentElement;
+
+ form.innerHTML = "<a name='" + id + "'/>";
+
+ // Inject it into the root element, check its status, and remove it quickly
+ root.insertBefore( form, root.firstChild );
+
+ // The workaround has to do additional checks after a getElementById
+ // Which slows things down for other browsers (hence the branching)
+ if ( document.getElementById( id ) ) {
+ Expr.find.ID = function( match, context, isXML ) {
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+
+ return m ?
+ m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
+ [m] :
+ undefined :
+ [];
+ }
+ };
+
+ Expr.filter.ID = function( elem, match ) {
+ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+
+ return elem.nodeType === 1 && node && node.nodeValue === match;
+ };
+ }
+
+ root.removeChild( form );
+
+ // release memory in IE
+ root = form = null;
+})();
+
+(function(){
+ // Check to see if the browser returns only elements
+ // when doing getElementsByTagName("*")
+
+ // Create a fake element
+ var div = document.createElement("div");
+ div.appendChild( document.createComment("") );
+
+ // Make sure no comments are found
+ if ( div.getElementsByTagName("*").length > 0 ) {
+ Expr.find.TAG = function( match, context ) {
+ var results = context.getElementsByTagName( match[1] );
+
+ // Filter out possible comments
+ if ( match[1] === "*" ) {
+ var tmp = [];
+
+ for ( var i = 0; results[i]; i++ ) {
+ if ( results[i].nodeType === 1 ) {
+ tmp.push( results[i] );
+ }
+ }
+
+ results = tmp;
+ }
+
+ return results;
+ };
+ }
+
+ // Check to see if an attribute returns normalized href attributes
+ div.innerHTML = "<a href='#'></a>";
+
+ if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
+ div.firstChild.getAttribute("href") !== "#" ) {
+
+ Expr.attrHandle.href = function( elem ) {
+ return elem.getAttribute( "href", 2 );
+ };
+ }
+
+ // release memory in IE
+ div = null;
+})();
+
+if ( document.querySelectorAll ) {
+ (function(){
+ var oldSizzle = Sizzle,
+ div = document.createElement("div"),
+ id = "__sizzle__";
+
+ div.innerHTML = "<p class='TEST'></p>";
+
+ // Safari can't handle uppercase or unicode characters when
+ // in quirks mode.
+ if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
+ return;
+ }
+
+ Sizzle = function( query, context, extra, seed ) {
+ context = context || document;
+
+ // Only use querySelectorAll on non-XML documents
+ // (ID selectors don't work in non-HTML documents)
+ if ( !seed && !Sizzle.isXML(context) ) {
+ // See if we find a selector to speed up
+ var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
+
+ if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
+ // Speed-up: Sizzle("TAG")
+ if ( match[1] ) {
+ return makeArray( context.getElementsByTagName( query ), extra );
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
+ return makeArray( context.getElementsByClassName( match[2] ), extra );
+ }
+ }
+
+ if ( context.nodeType === 9 ) {
+ // Speed-up: Sizzle("body")
+ // The body element only exists once, optimize finding it
+ if ( query === "body" && context.body ) {
+ return makeArray( [ context.body ], extra );
+
+ // Speed-up: Sizzle("#ID")
+ } else if ( match && match[3] ) {
+ var elem = context.getElementById( match[3] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id === match[3] ) {
+ return makeArray( [ elem ], extra );
+ }
+
+ } else {
+ return makeArray( [], extra );
+ }
+ }
+
+ try {
+ return makeArray( context.querySelectorAll(query), extra );
+ } catch(qsaError) {}
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ var oldContext = context,
+ old = context.getAttribute( "id" ),
+ nid = old || id,
+ hasParent = context.parentNode,
+ relativeHierarchySelector = /^\s*[+~]/.test( query );
+
+ if ( !old ) {
+ context.setAttribute( "id", nid );
+ } else {
+ nid = nid.replace( /'/g, "\\$&" );
+ }
+ if ( relativeHierarchySelector && hasParent ) {
+ context = context.parentNode;
+ }
+
+ try {
+ if ( !relativeHierarchySelector || hasParent ) {
+ return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
+ }
+
+ } catch(pseudoError) {
+ } finally {
+ if ( !old ) {
+ oldContext.removeAttribute( "id" );
+ }
+ }
+ }
+ }
+
+ return oldSizzle(query, context, extra, seed);
+ };
+
+ for ( var prop in oldSizzle ) {
+ Sizzle[ prop ] = oldSizzle[ prop ];
+ }
+
+ // release memory in IE
+ div = null;
+ })();
+}
+
+(function(){
+ var html = document.documentElement,
+ matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
+
+ if ( matches ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9 fails this)
+ var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
+ pseudoWorks = false;
+
+ try {
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( document.documentElement, "[test!='']:sizzle" );
+
+ } catch( pseudoError ) {
+ pseudoWorks = true;
+ }
+
+ Sizzle.matchesSelector = function( node, expr ) {
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
+
+ if ( !Sizzle.isXML( node ) ) {
+ try {
+ if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
+ var ret = matches.call( node, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || !disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9, so check for that
+ node.document && node.document.nodeType !== 11 ) {
+ return ret;
+ }
+ }
+ } catch(e) {}
+ }
+
+ return Sizzle(expr, null, null, [node]).length > 0;
+ };
+ }
+})();
+
+(function(){
+ var div = document.createElement("div");
+
+ div.innerHTML = "<div class='test e'></div><div class='test'></div>";
+
+ // Opera can't find a second classname (in 9.6)
+ // Also, make sure that getElementsByClassName actually exists
+ if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
+ return;
+ }
+
+ // Safari caches class attributes, doesn't catch changes (in 3.2)
+ div.lastChild.className = "e";
+
+ if ( div.getElementsByClassName("e").length === 1 ) {
+ return;
+ }
+
+ Expr.order.splice(1, 0, "CLASS");
+ Expr.find.CLASS = function( match, context, isXML ) {
+ if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
+ return context.getElementsByClassName(match[1]);
+ }
+ };
+
+ // release memory in IE
+ div = null;
+})();
+
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+
+ if ( elem ) {
+ var match = false;
+
+ elem = elem[dir];
+
+ while ( elem ) {
+ if ( elem[ expando ] === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 && !isXML ){
+ elem[ expando ] = doneName;
+ elem.sizset = i;
+ }
+
+ if ( elem.nodeName.toLowerCase() === cur ) {
+ match = elem;
+ break;
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+
+ if ( elem ) {
+ var match = false;
+
+ elem = elem[dir];
+
+ while ( elem ) {
+ if ( elem[ expando ] === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 ) {
+ if ( !isXML ) {
+ elem[ expando ] = doneName;
+ elem.sizset = i;
+ }
+
+ if ( typeof cur !== "string" ) {
+ if ( elem === cur ) {
+ match = true;
+ break;
+ }
+
+ } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
+ match = elem;
+ break;
+ }
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+if ( document.documentElement.contains ) {
+ Sizzle.contains = function( a, b ) {
+ return a !== b && (a.contains ? a.contains(b) : true);
+ };
+
+} else if ( document.documentElement.compareDocumentPosition ) {
+ Sizzle.contains = function( a, b ) {
+ return !!(a.compareDocumentPosition(b) & 16);
+ };
+
+} else {
+ Sizzle.contains = function() {
+ return false;
+ };
+}
+
+Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
+
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+var posProcess = function( selector, context, seed ) {
+ var match,
+ tmpSet = [],
+ later = "",
+ root = context.nodeType ? [context] : context;
+
+ // Position selectors must be done after the filter
+ // And so must :not(positional) so we move all PSEUDOs to the end
+ while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
+ later += match[0];
+ selector = selector.replace( Expr.match.PSEUDO, "" );
+ }
+
+ selector = Expr.relative[selector] ? selector + "*" : selector;
+
+ for ( var i = 0, l = root.length; i < l; i++ ) {
+ Sizzle( selector, root[i], tmpSet, seed );
+ }
+
+ return Sizzle.filter( later, tmpSet );
+};
+
+// EXPOSE
+
+window.tinymce.dom.Sizzle = Sizzle;
+
+})();
+
+
+(function(tinymce) {
+ tinymce.dom.Element = function(id, settings) {
+ var t = this, dom, el;
+
+ t.settings = settings = settings || {};
+ t.id = id;
+ t.dom = dom = settings.dom || tinymce.DOM;
+
+ // Only IE leaks DOM references, this is a lot faster
+ if (!tinymce.isIE)
+ el = dom.get(t.id);
+
+ tinymce.each(
+ ('getPos,getRect,getParent,add,setStyle,getStyle,setStyles,' +
+ 'setAttrib,setAttribs,getAttrib,addClass,removeClass,' +
+ 'hasClass,getOuterHTML,setOuterHTML,remove,show,hide,' +
+ 'isHidden,setHTML,get').split(/,/), function(k) {
+ t[k] = function() {
+ var a = [id], i;
+
+ for (i = 0; i < arguments.length; i++)
+ a.push(arguments[i]);
+
+ a = dom[k].apply(dom, a);
+ t.update(k);
+
+ return a;
+ };
+ }
+ );
+
+ tinymce.extend(t, {
+ on : function(n, f, s) {
+ return tinymce.dom.Event.add(t.id, n, f, s);
+ },
+
+ getXY : function() {
+ return {
+ x : parseInt(t.getStyle('left')),
+ y : parseInt(t.getStyle('top'))
+ };
+ },
+
+ getSize : function() {
+ var n = dom.get(t.id);
+
+ return {
+ w : parseInt(t.getStyle('width') || n.clientWidth),
+ h : parseInt(t.getStyle('height') || n.clientHeight)
+ };
+ },
+
+ moveTo : function(x, y) {
+ t.setStyles({left : x, top : y});
+ },
+
+ moveBy : function(x, y) {
+ var p = t.getXY();
+
+ t.moveTo(p.x + x, p.y + y);
+ },
+
+ resizeTo : function(w, h) {
+ t.setStyles({width : w, height : h});
+ },
+
+ resizeBy : function(w, h) {
+ var s = t.getSize();
+
+ t.resizeTo(s.w + w, s.h + h);
+ },
+
+ update : function(k) {
+ var b;
+
+ if (tinymce.isIE6 && settings.blocker) {
+ k = k || '';
+
+ // Ignore getters
+ if (k.indexOf('get') === 0 || k.indexOf('has') === 0 || k.indexOf('is') === 0)
+ return;
+
+ // Remove blocker on remove
+ if (k == 'remove') {
+ dom.remove(t.blocker);
+ return;
+ }
+
+ if (!t.blocker) {
+ t.blocker = dom.uniqueId();
+ b = dom.add(settings.container || dom.getRoot(), 'iframe', {id : t.blocker, style : 'position:absolute;', frameBorder : 0, src : 'javascript:""'});
+ dom.setStyle(b, 'opacity', 0);
+ } else
+ b = dom.get(t.blocker);
+
+ dom.setStyles(b, {
+ left : t.getStyle('left', 1),
+ top : t.getStyle('top', 1),
+ width : t.getStyle('width', 1),
+ height : t.getStyle('height', 1),
+ display : t.getStyle('display', 1),
+ zIndex : parseInt(t.getStyle('zIndex', 1) || 0) - 1
+ });
+ }
+ }
+ });
+ };
+})(tinymce);
+
+(function(tinymce) {
+ function trimNl(s) {
+ return s.replace(/[\n\r]+/g, '');
+ };
+
+ // Shorten names
+ var is = tinymce.is, isIE = tinymce.isIE, each = tinymce.each, TreeWalker = tinymce.dom.TreeWalker;
+
+ tinymce.create('tinymce.dom.Selection', {
+ Selection : function(dom, win, serializer, editor) {
+ var t = this;
+
+ t.dom = dom;
+ t.win = win;
+ t.serializer = serializer;
+ t.editor = editor;
+
+ // Add events
+ each([
+ 'onBeforeSetContent',
+
+ 'onBeforeGetContent',
+
+ 'onSetContent',
+
+ 'onGetContent'
+ ], function(e) {
+ t[e] = new tinymce.util.Dispatcher(t);
+ });
+
+ // No W3C Range support
+ if (!t.win.getSelection)
+ t.tridentSel = new tinymce.dom.TridentSelection(t);
+
+ if (tinymce.isIE && dom.boxModel)
+ this._fixIESelection();
+
+ // Prevent leaks
+ tinymce.addUnload(t.destroy, t);
+ },
+
+ setCursorLocation: function(node, offset) {
+ var t = this; var r = t.dom.createRng();
+ r.setStart(node, offset);
+ r.setEnd(node, offset);
+ t.setRng(r);
+ t.collapse(false);
+ },
+ getContent : function(s) {
+ var t = this, r = t.getRng(), e = t.dom.create("body"), se = t.getSel(), wb, wa, n;
+
+ s = s || {};
+ wb = wa = '';
+ s.get = true;
+ s.format = s.format || 'html';
+ s.forced_root_block = '';
+ t.onBeforeGetContent.dispatch(t, s);
+
+ if (s.format == 'text')
+ return t.isCollapsed() ? '' : (r.text || (se.toString ? se.toString() : ''));
+
+ if (r.cloneContents) {
+ n = r.cloneContents();
+
+ if (n)
+ e.appendChild(n);
+ } else if (is(r.item) || is(r.htmlText)) {
+ // IE will produce invalid markup if elements are present that
+ // it doesn't understand like custom elements or HTML5 elements.
+ // Adding a BR in front of the contents and then remoiving it seems to fix it though.
+ e.innerHTML = '<br>' + (r.item ? r.item(0).outerHTML : r.htmlText);
+ e.removeChild(e.firstChild);
+ } else
+ e.innerHTML = r.toString();
+
+ // Keep whitespace before and after
+ if (/^\s/.test(e.innerHTML))
+ wb = ' ';
+
+ if (/\s+$/.test(e.innerHTML))
+ wa = ' ';
+
+ s.getInner = true;
+
+ s.content = t.isCollapsed() ? '' : wb + t.serializer.serialize(e, s) + wa;
+ t.onGetContent.dispatch(t, s);
+
+ return s.content;
+ },
+
+ setContent : function(content, args) {
+ var self = this, rng = self.getRng(), caretNode, doc = self.win.document, frag, temp;
+
+ args = args || {format : 'html'};
+ args.set = true;
+ content = args.content = content;
+
+ // Dispatch before set content event
+ if (!args.no_events)
+ self.onBeforeSetContent.dispatch(self, args);
+
+ content = args.content;
+
+ if (rng.insertNode) {
+ // Make caret marker since insertNode places the caret in the beginning of text after insert
+ content += '<span id="__caret">_</span>';
+
+ // Delete and insert new node
+ if (rng.startContainer == doc && rng.endContainer == doc) {
+ // WebKit will fail if the body is empty since the range is then invalid and it can't insert contents
+ doc.body.innerHTML = content;
+ } else {
+ rng.deleteContents();
+
+ if (doc.body.childNodes.length === 0) {
+ doc.body.innerHTML = content;
+ } else {
+ // createContextualFragment doesn't exists in IE 9 DOMRanges
+ if (rng.createContextualFragment) {
+ rng.insertNode(rng.createContextualFragment(content));
+ } else {
+ // Fake createContextualFragment call in IE 9
+ frag = doc.createDocumentFragment();
+ temp = doc.createElement('div');
+
+ frag.appendChild(temp);
+ temp.outerHTML = content;
+
+ rng.insertNode(frag);
+ }
+ }
+ }
+
+ // Move to caret marker
+ caretNode = self.dom.get('__caret');
+
+ // Make sure we wrap it compleatly, Opera fails with a simple select call
+ rng = doc.createRange();
+ rng.setStartBefore(caretNode);
+ rng.setEndBefore(caretNode);
+ self.setRng(rng);
+
+ // Remove the caret position
+ self.dom.remove('__caret');
+
+ try {
+ self.setRng(rng);
+ } catch (ex) {
+ // Might fail on Opera for some odd reason
+ }
+ } else {
+ if (rng.item) {
+ // Delete content and get caret text selection
+ doc.execCommand('Delete', false, null);
+ rng = self.getRng();
+ }
+
+ // Explorer removes spaces from the beginning of pasted contents
+ if (/^\s+/.test(content)) {
+ rng.pasteHTML('<span id="__mce_tmp">_</span>' + content);
+ self.dom.remove('__mce_tmp');
+ } else
+ rng.pasteHTML(content);
+ }
+
+ // Dispatch set content event
+ if (!args.no_events)
+ self.onSetContent.dispatch(self, args);
+ },
+
+ getStart : function() {
+ var self = this, rng = self.getRng(), startElement, parentElement, checkRng, node;
+
+ if (rng.duplicate || rng.item) {
+ // Control selection, return first item
+ if (rng.item)
+ return rng.item(0);
+
+ // Get start element
+ checkRng = rng.duplicate();
+ checkRng.collapse(1);
+ startElement = checkRng.parentElement();
+ if (startElement.ownerDocument !== self.dom.doc) {
+ startElement = self.dom.getRoot();
+ }
+
+ // Check if range parent is inside the start element, then return the inner parent element
+ // This will fix issues when a single element is selected, IE would otherwise return the wrong start element
+ parentElement = node = rng.parentElement();
+ while (node = node.parentNode) {
+ if (node == startElement) {
+ startElement = parentElement;
+ break;
+ }
+ }
+
+ return startElement;
+ } else {
+ startElement = rng.startContainer;
+
+ if (startElement.nodeType == 1 && startElement.hasChildNodes())
+ startElement = startElement.childNodes[Math.min(startElement.childNodes.length - 1, rng.startOffset)];
+
+ if (startElement && startElement.nodeType == 3)
+ return startElement.parentNode;
+
+ return startElement;
+ }
+ },
+
+ getEnd : function() {
+ var self = this, rng = self.getRng(), endElement, endOffset;
+
+ if (rng.duplicate || rng.item) {
+ if (rng.item)
+ return rng.item(0);
+
+ rng = rng.duplicate();
+ rng.collapse(0);
+ endElement = rng.parentElement();
+ if (endElement.ownerDocument !== self.dom.doc) {
+ endElement = self.dom.getRoot();
+ }
+
+ if (endElement && endElement.nodeName == 'BODY')
+ return endElement.lastChild || endElement;
+
+ return endElement;
+ } else {
+ endElement = rng.endContainer;
+ endOffset = rng.endOffset;
+
+ if (endElement.nodeType == 1 && endElement.hasChildNodes())
+ endElement = endElement.childNodes[endOffset > 0 ? endOffset - 1 : endOffset];
+
+ if (endElement && endElement.nodeType == 3)
+ return endElement.parentNode;
+
+ return endElement;
+ }
+ },
+
+ getBookmark : function(type, normalized) {
+ var t = this, dom = t.dom, rng, rng2, id, collapsed, name, element, index, chr = '\uFEFF', styles;
+
+ function findIndex(name, element) {
+ var index = 0;
+
+ each(dom.select(name), function(node, i) {
+ if (node == element)
+ index = i;
+ });
+
+ return index;
+ };
+
+ function normalizeTableCellSelection(rng) {
+ function moveEndPoint(start) {
+ var container, offset, childNodes, prefix = start ? 'start' : 'end';
+
+ container = rng[prefix + 'Container'];
+ offset = rng[prefix + 'Offset'];
+
+ if (container.nodeType == 1 && container.nodeName == "TR") {
+ childNodes = container.childNodes;
+ container = childNodes[Math.min(start ? offset : offset - 1, childNodes.length - 1)];
+ if (container) {
+ offset = start ? 0 : container.childNodes.length;
+ rng['set' + (start ? 'Start' : 'End')](container, offset);
+ }
+ }
+ };
+
+ moveEndPoint(true);
+ moveEndPoint();
+
+ return rng;
+ };
+
+ function getLocation() {
+ var rng = t.getRng(true), root = dom.getRoot(), bookmark = {};
+
+ function getPoint(rng, start) {
+ var container = rng[start ? 'startContainer' : 'endContainer'],
+ offset = rng[start ? 'startOffset' : 'endOffset'], point = [], node, childNodes, after = 0;
+
+ if (container.nodeType == 3) {
+ if (normalized) {
+ for (node = container.previousSibling; node && node.nodeType == 3; node = node.previousSibling)
+ offset += node.nodeValue.length;
+ }
+
+ point.push(offset);
+ } else {
+ childNodes = container.childNodes;
+
+ if (offset >= childNodes.length && childNodes.length) {
+ after = 1;
+ offset = Math.max(0, childNodes.length - 1);
+ }
+
+ point.push(t.dom.nodeIndex(childNodes[offset], normalized) + after);
+ }
+
+ for (; container && container != root; container = container.parentNode)
+ point.push(t.dom.nodeIndex(container, normalized));
+
+ return point;
+ };
+
+ bookmark.start = getPoint(rng, true);
+
+ if (!t.isCollapsed())
+ bookmark.end = getPoint(rng);
+
+ return bookmark;
+ };
+
+ if (type == 2) {
+ if (t.tridentSel)
+ return t.tridentSel.getBookmark(type);
+
+ return getLocation();
+ }
+
+ // Handle simple range
+ if (type)
+ return {rng : t.getRng()};
+
+ rng = t.getRng();
+ id = dom.uniqueId();
+ collapsed = tinyMCE.activeEditor.selection.isCollapsed();
+ styles = 'overflow:hidden;line-height:0px';
+
+ // Explorer method
+ if (rng.duplicate || rng.item) {
+ // Text selection
+ if (!rng.item) {
+ rng2 = rng.duplicate();
+
+ try {
+ // Insert start marker
+ rng.collapse();
+ rng.pasteHTML('<span data-mce-type="bookmark" id="' + id + '_start" style="' + styles + '">' + chr + '</span>');
+
+ // Insert end marker
+ if (!collapsed) {
+ rng2.collapse(false);
+
+ // Detect the empty space after block elements in IE and move the end back one character <p></p>] becomes <p>]</p>
+ rng.moveToElementText(rng2.parentElement());
+ if (rng.compareEndPoints('StartToEnd', rng2) === 0)
+ rng2.move('character', -1);
+
+ rng2.pasteHTML('<span data-mce-type="bookmark" id="' + id + '_end" style="' + styles + '">' + chr + '</span>');
+ }
+ } catch (ex) {
+ // IE might throw unspecified error so lets ignore it
+ return null;
+ }
+ } else {
+ // Control selection
+ element = rng.item(0);
+ name = element.nodeName;
+
+ return {name : name, index : findIndex(name, element)};
+ }
+ } else {
+ element = t.getNode();
+ name = element.nodeName;
+ if (name == 'IMG')
+ return {name : name, index : findIndex(name, element)};
+
+ // W3C method
+ rng2 = normalizeTableCellSelection(rng.cloneRange());
+
+ // Insert end marker
+ if (!collapsed) {
+ rng2.collapse(false);
+ rng2.insertNode(dom.create('span', {'data-mce-type' : "bookmark", id : id + '_end', style : styles}, chr));
+ }
+
+ rng = normalizeTableCellSelection(rng);
+ rng.collapse(true);
+ rng.insertNode(dom.create('span', {'data-mce-type' : "bookmark", id : id + '_start', style : styles}, chr));
+ }
+
+ t.moveToBookmark({id : id, keep : 1});
+
+ return {id : id};
+ },
+
+ moveToBookmark : function(bookmark) {
+ var t = this, dom = t.dom, marker1, marker2, rng, root, startContainer, endContainer, startOffset, endOffset;
+
+ function setEndPoint(start) {
+ var point = bookmark[start ? 'start' : 'end'], i, node, offset, children;
+
+ if (point) {
+ offset = point[0];
+
+ // Find container node
+ for (node = root, i = point.length - 1; i >= 1; i--) {
+ children = node.childNodes;
+
+ if (point[i] > children.length - 1)
+ return;
+
+ node = children[point[i]];
+ }
+
+ // Move text offset to best suitable location
+ if (node.nodeType === 3)
+ offset = Math.min(point[0], node.nodeValue.length);
+
+ // Move element offset to best suitable location
+ if (node.nodeType === 1)
+ offset = Math.min(point[0], node.childNodes.length);
+
+ // Set offset within container node
+ if (start)
+ rng.setStart(node, offset);
+ else
+ rng.setEnd(node, offset);
+ }
+
+ return true;
+ };
+
+ function restoreEndPoint(suffix) {
+ var marker = dom.get(bookmark.id + '_' + suffix), node, idx, next, prev, keep = bookmark.keep;
+
+ if (marker) {
+ node = marker.parentNode;
+
+ if (suffix == 'start') {
+ if (!keep) {
+ idx = dom.nodeIndex(marker);
+ } else {
+ node = marker.firstChild;
+ idx = 1;
+ }
+
+ startContainer = endContainer = node;
+ startOffset = endOffset = idx;
+ } else {
+ if (!keep) {
+ idx = dom.nodeIndex(marker);
+ } else {
+ node = marker.firstChild;
+ idx = 1;
+ }
+
+ endContainer = node;
+ endOffset = idx;
+ }
+
+ if (!keep) {
+ prev = marker.previousSibling;
+ next = marker.nextSibling;
+
+ // Remove all marker text nodes
+ each(tinymce.grep(marker.childNodes), function(node) {
+ if (node.nodeType == 3)
+ node.nodeValue = node.nodeValue.replace(/\uFEFF/g, '');
+ });
+
+ // Remove marker but keep children if for example contents where inserted into the marker
+ // Also remove duplicated instances of the marker for example by a split operation or by WebKit auto split on paste feature
+ while (marker = dom.get(bookmark.id + '_' + suffix))
+ dom.remove(marker, 1);
+
+ // If siblings are text nodes then merge them unless it's Opera since it some how removes the node
+ // and we are sniffing since adding a lot of detection code for a browser with 3% of the market isn't worth the effort. Sorry, Opera but it's just a fact
+ if (prev && next && prev.nodeType == next.nodeType && prev.nodeType == 3 && !tinymce.isOpera) {
+ idx = prev.nodeValue.length;
+ prev.appendData(next.nodeValue);
+ dom.remove(next);
+
+ if (suffix == 'start') {
+ startContainer = endContainer = prev;
+ startOffset = endOffset = idx;
+ } else {
+ endContainer = prev;
+ endOffset = idx;
+ }
+ }
+ }
+ }
+ };
+
+ function addBogus(node) {
+ // Adds a bogus BR element for empty block elements
+ if (dom.isBlock(node) && !node.innerHTML && !isIE)
+ node.innerHTML = '<br data-mce-bogus="1" />';
+
+ return node;
+ };
+
+ if (bookmark) {
+ if (bookmark.start) {
+ rng = dom.createRng();
+ root = dom.getRoot();
+
+ if (t.tridentSel)
+ return t.tridentSel.moveToBookmark(bookmark);
+
+ if (setEndPoint(true) && setEndPoint()) {
+ t.setRng(rng);
+ }
+ } else if (bookmark.id) {
+ // Restore start/end points
+ restoreEndPoint('start');
+ restoreEndPoint('end');
+
+ if (startContainer) {
+ rng = dom.createRng();
+ rng.setStart(addBogus(startContainer), startOffset);
+ rng.setEnd(addBogus(endContainer), endOffset);
+ t.setRng(rng);
+ }
+ } else if (bookmark.name) {
+ t.select(dom.select(bookmark.name)[bookmark.index]);
+ } else if (bookmark.rng)
+ t.setRng(bookmark.rng);
+ }
+ },
+
+ select : function(node, content) {
+ var t = this, dom = t.dom, rng = dom.createRng(), idx;
+
+ function setPoint(node, start) {
+ var walker = new TreeWalker(node, node);
+
+ do {
+ // Text node
+ if (node.nodeType == 3 && tinymce.trim(node.nodeValue).length !== 0) {
+ if (start)
+ rng.setStart(node, 0);
+ else
+ rng.setEnd(node, node.nodeValue.length);
+
+ return;
+ }
+
+ // BR element
+ if (node.nodeName == 'BR') {
+ if (start)
+ rng.setStartBefore(node);
+ else
+ rng.setEndBefore(node);
+
+ return;
+ }
+ } while (node = (start ? walker.next() : walker.prev()));
+ };
+
+ if (node) {
+ idx = dom.nodeIndex(node);
+ rng.setStart(node.parentNode, idx);
+ rng.setEnd(node.parentNode, idx + 1);
+
+ // Find first/last text node or BR element
+ if (content) {
+ setPoint(node, 1);
+ setPoint(node);
+ }
+
+ t.setRng(rng);
+ }
+
+ return node;
+ },
+
+ isCollapsed : function() {
+ var t = this, r = t.getRng(), s = t.getSel();
+
+ if (!r || r.item)
+ return false;
+
+ if (r.compareEndPoints)
+ return r.compareEndPoints('StartToEnd', r) === 0;
+
+ return !s || r.collapsed;
+ },
+
+ collapse : function(to_start) {
+ var self = this, rng = self.getRng(), node;
+
+ // Control range on IE
+ if (rng.item) {
+ node = rng.item(0);
+ rng = self.win.document.body.createTextRange();
+ rng.moveToElementText(node);
+ }
+
+ rng.collapse(!!to_start);
+ self.setRng(rng);
+ },
+
+ getSel : function() {
+ var t = this, w = this.win;
+
+ return w.getSelection ? w.getSelection() : w.document.selection;
+ },
+
+ getRng : function(w3c) {
+ var self = this, selection, rng, elm, doc = self.win.document;
+
+ // Found tridentSel object then we need to use that one
+ if (w3c && self.tridentSel) {
+ return self.tridentSel.getRangeAt(0);
+ }
+
+ try {
+ if (selection = self.getSel()) {
+ rng = selection.rangeCount > 0 ? selection.getRangeAt(0) : (selection.createRange ? selection.createRange() : doc.createRange());
+ }
+ } catch (ex) {
+ // IE throws unspecified error here if TinyMCE is placed in a frame/iframe
+ }
+
+ // We have W3C ranges and it's IE then fake control selection since IE9 doesn't handle that correctly yet
+ if (tinymce.isIE && rng && rng.setStart && doc.selection.createRange().item) {
+ elm = doc.selection.createRange().item(0);
+ rng = doc.createRange();
+ rng.setStartBefore(elm);
+ rng.setEndAfter(elm);
+ }
+
+ // No range found then create an empty one
+ // This can occur when the editor is placed in a hidden container element on Gecko
+ // Or on IE when there was an exception
+ if (!rng) {
+ rng = doc.createRange ? doc.createRange() : doc.body.createTextRange();
+ }
+
+ // If range is at start of document then move it to start of body
+ if (rng.setStart && rng.startContainer.nodeType === 9 && rng.collapsed) {
+ elm = self.dom.getRoot();
+ rng.setStart(elm, 0);
+ rng.setEnd(elm, 0);
+ }
+
+ if (self.selectedRange && self.explicitRange) {
+ if (rng.compareBoundaryPoints(rng.START_TO_START, self.selectedRange) === 0 && rng.compareBoundaryPoints(rng.END_TO_END, self.selectedRange) === 0) {
+ // Safari, Opera and Chrome only ever select text which causes the range to change.
+ // This lets us use the originally set range if the selection hasn't been changed by the user.
+ rng = self.explicitRange;
+ } else {
+ self.selectedRange = null;
+ self.explicitRange = null;
+ }
+ }
+
+ return rng;
+ },
+
+ setRng : function(r, forward) {
+ var s, t = this;
+
+ if (!t.tridentSel) {
+ s = t.getSel();
+
+ if (s) {
+ t.explicitRange = r;
+
+ try {
+ s.removeAllRanges();
+ } catch (ex) {
+ // IE9 might throw errors here don't know why
+ }
+
+ s.addRange(r);
+
+ // Forward is set to false and we have an extend function
+ if (forward === false && s.extend) {
+ s.collapse(r.endContainer, r.endOffset);
+ s.extend(r.startContainer, r.startOffset);
+ }
+
+ // adding range isn't always successful so we need to check range count otherwise an exception can occur
+ t.selectedRange = s.rangeCount > 0 ? s.getRangeAt(0) : null;
+ }
+ } else {
+ // Is W3C Range
+ if (r.cloneRange) {
+ try {
+ t.tridentSel.addRange(r);
+ return;
+ } catch (ex) {
+ //IE9 throws an error here if called before selection is placed in the editor
+ }
+ }
+
+ // Is IE specific range
+ try {
+ r.select();
+ } catch (ex) {
+ // Needed for some odd IE bug #1843306
+ }
+ }
+ },
+
+ setNode : function(n) {
+ var t = this;
+
+ t.setContent(t.dom.getOuterHTML(n));
+
+ return n;
+ },
+
+ getNode : function() {
+ var t = this, rng = t.getRng(), sel = t.getSel(), elm, start = rng.startContainer, end = rng.endContainer;
+
+ function skipEmptyTextNodes(n, forwards) {
+ var orig = n;
+ while (n && n.nodeType === 3 && n.length === 0) {
+ n = forwards ? n.nextSibling : n.previousSibling;
+ }
+ return n || orig;
+ };
+
+ // Range maybe lost after the editor is made visible again
+ if (!rng)
+ return t.dom.getRoot();
+
+ if (rng.setStart) {
+ elm = rng.commonAncestorContainer;
+
+ // Handle selection a image or other control like element such as anchors
+ if (!rng.collapsed) {
+ if (rng.startContainer == rng.endContainer) {
+ if (rng.endOffset - rng.startOffset < 2) {
+ if (rng.startContainer.hasChildNodes())
+ elm = rng.startContainer.childNodes[rng.startOffset];
+ }
+ }
+
+ // If the anchor node is a element instead of a text node then return this element
+ //if (tinymce.isWebKit && sel.anchorNode && sel.anchorNode.nodeType == 1)
+ // return sel.anchorNode.childNodes[sel.anchorOffset];
+
+ // Handle cases where the selection is immediately wrapped around a node and return that node instead of it's parent.
+ // This happens when you double click an underlined word in FireFox.
+ if (start.nodeType === 3 && end.nodeType === 3) {
+ if (start.length === rng.startOffset) {
+ start = skipEmptyTextNodes(start.nextSibling, true);
+ } else {
+ start = start.parentNode;
+ }
+ if (rng.endOffset === 0) {
+ end = skipEmptyTextNodes(end.previousSibling, false);
+ } else {
+ end = end.parentNode;
+ }
+
+ if (start && start === end)
+ return start;
+ }
+ }
+
+ if (elm && elm.nodeType == 3)
+ return elm.parentNode;
+
+ return elm;
+ }
+
+ return rng.item ? rng.item(0) : rng.parentElement();
+ },
+
+ getSelectedBlocks : function(st, en) {
+ var t = this, dom = t.dom, sb, eb, n, bl = [];
+
+ sb = dom.getParent(st || t.getStart(), dom.isBlock);
+ eb = dom.getParent(en || t.getEnd(), dom.isBlock);
+
+ if (sb)
+ bl.push(sb);
+
+ if (sb && eb && sb != eb) {
+ n = sb;
+
+ var walker = new TreeWalker(sb, dom.getRoot());
+ while ((n = walker.next()) && n != eb) {
+ if (dom.isBlock(n))
+ bl.push(n);
+ }
+ }
+
+ if (eb && sb != eb)
+ bl.push(eb);
+
+ return bl;
+ },
+
+ isForward: function(){
+ var dom = this.dom, sel = this.getSel(), anchorRange, focusRange;
+
+ // No support for selection direction then always return true
+ if (!sel || sel.anchorNode == null || sel.focusNode == null) {
+ return true;
+ }
+
+ anchorRange = dom.createRng();
+ anchorRange.setStart(sel.anchorNode, sel.anchorOffset);
+ anchorRange.collapse(true);
+
+ focusRange = dom.createRng();
+ focusRange.setStart(sel.focusNode, sel.focusOffset);
+ focusRange.collapse(true);
+
+ return anchorRange.compareBoundaryPoints(anchorRange.START_TO_START, focusRange) <= 0;
+ },
+
+ normalize : function() {
+ var self = this, rng, normalized, collapsed, node, sibling;
+
+ function normalizeEndPoint(start) {
+ var container, offset, walker, dom = self.dom, body = dom.getRoot(), node, nonEmptyElementsMap, nodeName;
+
+ function hasBrBeforeAfter(node, left) {
+ var walker = new TreeWalker(node, dom.getParent(node.parentNode, dom.isBlock) || body);
+
+ while (node = walker[left ? 'prev' : 'next']()) {
+ if (node.nodeName === "BR") {
+ return true;
+ }
+ }
+ };
+
+ // Walks the dom left/right to find a suitable text node to move the endpoint into
+ // It will only walk within the current parent block or body and will stop if it hits a block or a BR/IMG
+ function findTextNodeRelative(left, startNode) {
+ var walker, lastInlineElement;
+
+ startNode = startNode || container;
+ walker = new TreeWalker(startNode, dom.getParent(startNode.parentNode, dom.isBlock) || body);
+
+ // Walk left until we hit a text node we can move to or a block/br/img
+ while (node = walker[left ? 'prev' : 'next']()) {
+ // Found text node that has a length
+ if (node.nodeType === 3 && node.nodeValue.length > 0) {
+ container = node;
+ offset = left ? node.nodeValue.length : 0;
+ normalized = true;
+ return;
+ }
+
+ // Break if we find a block or a BR/IMG/INPUT etc
+ if (dom.isBlock(node) || nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
+ return;
+ }
+
+ lastInlineElement = node;
+ }
+
+ // Only fetch the last inline element when in caret mode for now
+ if (collapsed && lastInlineElement) {
+ container = lastInlineElement;
+ normalized = true;
+ offset = 0;
+ }
+ };
+
+ container = rng[(start ? 'start' : 'end') + 'Container'];
+ offset = rng[(start ? 'start' : 'end') + 'Offset'];
+ nonEmptyElementsMap = dom.schema.getNonEmptyElements();
+
+ // If the container is a document move it to the body element
+ if (container.nodeType === 9) {
+ container = dom.getRoot();
+ offset = 0;
+ }
+
+ // If the container is body try move it into the closest text node or position
+ if (container === body) {
+ // If start is before/after a image, table etc
+ if (start) {
+ node = container.childNodes[offset > 0 ? offset - 1 : 0];
+ if (node) {
+ nodeName = node.nodeName.toLowerCase();
+ if (nonEmptyElementsMap[node.nodeName] || node.nodeName == "TABLE") {
+ return;
+ }
+ }
+ }
+
+ // Resolve the index
+ if (container.hasChildNodes()) {
+ container = container.childNodes[Math.min(!start && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1)];
+ offset = 0;
+
+ // Don't walk into elements that doesn't have any child nodes like a IMG
+ if (container.hasChildNodes() && !/TABLE/.test(container.nodeName)) {
+ // Walk the DOM to find a text node to place the caret at or a BR
+ node = container;
+ walker = new TreeWalker(container, body);
+
+ do {
+ // Found a text node use that position
+ if (node.nodeType === 3 && node.nodeValue.length > 0) {
+ offset = start ? 0 : node.nodeValue.length;
+ container = node;
+ normalized = true;
+ break;
+ }
+
+ // Found a BR/IMG element that we can place the caret before
+ if (nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
+ offset = dom.nodeIndex(node);
+ container = node.parentNode;
+
+ // Put caret after image when moving the end point
+ if (node.nodeName == "IMG" && !start) {
+ offset++;
+ }
+
+ normalized = true;
+ break;
+ }
+ } while (node = (start ? walker.next() : walker.prev()));
+ }
+ }
+ }
+
+ // Lean the caret to the left if possible
+ if (collapsed) {
+ // So this: <b>x</b><i>|x</i>
+ // Becomes: <b>x|</b><i>x</i>
+ // Seems that only gecko has issues with this
+ if (container.nodeType === 3 && offset === 0) {
+ findTextNodeRelative(true);
+ }
+
+ // Lean left into empty inline elements when the caret is before a BR
+ // So this: <i><b></b><i>|<br></i>
+ // Becomes: <i><b>|</b><i><br></i>
+ // Seems that only gecko has issues with this
+ if (container.nodeType === 1) {
+ node = container.childNodes[offset];
+ if(node && node.nodeName === 'BR' && !hasBrBeforeAfter(node) && !hasBrBeforeAfter(node, true)) {
+ findTextNodeRelative(true, container.childNodes[offset]);
+ }
+ }
+ }
+
+ // Lean the start of the selection right if possible
+ // So this: x[<b>x]</b>
+ // Becomes: x<b>[x]</b>
+ if (start && !collapsed && container.nodeType === 3 && offset === container.nodeValue.length) {
+ findTextNodeRelative(false);
+ }
+
+ // Set endpoint if it was normalized
+ if (normalized)
+ rng['set' + (start ? 'Start' : 'End')](container, offset);
+ };
+
+ // Normalize only on non IE browsers for now
+ if (tinymce.isIE)
+ return;
+
+ rng = self.getRng();
+ collapsed = rng.collapsed;
+
+ // Normalize the end points
+ normalizeEndPoint(true);
+
+ if (!collapsed)
+ normalizeEndPoint();
+
+ // Set the selection if it was normalized
+ if (normalized) {
+ // If it was collapsed then make sure it still is
+ if (collapsed) {
+ rng.collapse(true);
+ }
+
+ //console.log(self.dom.dumpRng(rng));
+ self.setRng(rng, self.isForward());
+ }
+ },
+
+ selectorChanged: function(selector, callback) {
+ var self = this, currentSelectors;
+
+ if (!self.selectorChangedData) {
+ self.selectorChangedData = {};
+ currentSelectors = {};
+
+ self.editor.onNodeChange.addToTop(function(ed, cm, node) {
+ var dom = self.dom, parents = dom.getParents(node, null, dom.getRoot()), matchedSelectors = {};
+
+ // Check for new matching selectors
+ each(self.selectorChangedData, function(callbacks, selector) {
+ each(parents, function(node) {
+ if (dom.is(node, selector)) {
+ if (!currentSelectors[selector]) {
+ // Execute callbacks
+ each(callbacks, function(callback) {
+ callback(true, {node: node, selector: selector, parents: parents});
+ });
+
+ currentSelectors[selector] = callbacks;
+ }
+
+ matchedSelectors[selector] = callbacks;
+ return false;
+ }
+ });
+ });
+
+ // Check if current selectors still match
+ each(currentSelectors, function(callbacks, selector) {
+ if (!matchedSelectors[selector]) {
+ delete currentSelectors[selector];
+
+ each(callbacks, function(callback) {
+ callback(false, {node: node, selector: selector, parents: parents});
+ });
+ }
+ });
+ });
+ }
+
+ // Add selector listeners
+ if (!self.selectorChangedData[selector]) {
+ self.selectorChangedData[selector] = [];
+ }
+
+ self.selectorChangedData[selector].push(callback);
+
+ return self;
+ },
+
+ destroy : function(manual) {
+ var self = this;
+
+ self.win = null;
+
+ // Manual destroy then remove unload handler
+ if (!manual)
+ tinymce.removeUnload(self.destroy);
+ },
+
+ // IE has an issue where you can't select/move the caret by clicking outside the body if the document is in standards mode
+ _fixIESelection : function() {
+ var dom = this.dom, doc = dom.doc, body = doc.body, started, startRng, htmlElm;
+
+ // Return range from point or null if it failed
+ function rngFromPoint(x, y) {
+ var rng = body.createTextRange();
+
+ try {
+ rng.moveToPoint(x, y);
+ } catch (ex) {
+ // IE sometimes throws and exception, so lets just ignore it
+ rng = null;
+ }
+
+ return rng;
+ };
+
+ // Fires while the selection is changing
+ function selectionChange(e) {
+ var pointRng;
+
+ // Check if the button is down or not
+ if (e.button) {
+ // Create range from mouse position
+ pointRng = rngFromPoint(e.x, e.y);
+
+ if (pointRng) {
+ // Check if pointRange is before/after selection then change the endPoint
+ if (pointRng.compareEndPoints('StartToStart', startRng) > 0)
+ pointRng.setEndPoint('StartToStart', startRng);
+ else
+ pointRng.setEndPoint('EndToEnd', startRng);
+
+ pointRng.select();
+ }
+ } else
+ endSelection();
+ }
+
+ // Removes listeners
+ function endSelection() {
+ var rng = doc.selection.createRange();
+
+ // If the range is collapsed then use the last start range
+ if (startRng && !rng.item && rng.compareEndPoints('StartToEnd', rng) === 0)
+ startRng.select();
+
+ dom.unbind(doc, 'mouseup', endSelection);
+ dom.unbind(doc, 'mousemove', selectionChange);
+ startRng = started = 0;
+ };
+
+ // Make HTML element unselectable since we are going to handle selection by hand
+ doc.documentElement.unselectable = true;
+
+ // Detect when user selects outside BODY
+ dom.bind(doc, ['mousedown', 'contextmenu'], function(e) {
+ if (e.target.nodeName === 'HTML') {
+ if (started)
+ endSelection();
+
+ // Detect vertical scrollbar, since IE will fire a mousedown on the scrollbar and have target set as HTML
+ htmlElm = doc.documentElement;
+ if (htmlElm.scrollHeight > htmlElm.clientHeight)
+ return;
+
+ started = 1;
+ // Setup start position
+ startRng = rngFromPoint(e.x, e.y);
+ if (startRng) {
+ // Listen for selection change events
+ dom.bind(doc, 'mouseup', endSelection);
+ dom.bind(doc, 'mousemove', selectionChange);
+
+ dom.win.focus();
+ startRng.select();
+ }
+ }
+ });
+ }
+ });
+})(tinymce);
+
+(function(tinymce) {
+ tinymce.dom.Serializer = function(settings, dom, schema) {
+ var onPreProcess, onPostProcess, isIE = tinymce.isIE, each = tinymce.each, htmlParser;
+
+ // Support the old apply_source_formatting option
+ if (!settings.apply_source_formatting)
+ settings.indent = false;
+
+ // Default DOM and Schema if they are undefined
+ dom = dom || tinymce.DOM;
+ schema = schema || new tinymce.html.Schema(settings);
+ settings.entity_encoding = settings.entity_encoding || 'named';
+ settings.remove_trailing_brs = "remove_trailing_brs" in settings ? settings.remove_trailing_brs : true;
+
+ onPreProcess = new tinymce.util.Dispatcher(self);
+
+ onPostProcess = new tinymce.util.Dispatcher(self);
+
+ htmlParser = new tinymce.html.DomParser(settings, schema);
+
+ // Convert move data-mce-src, data-mce-href and data-mce-style into nodes or process them if needed
+ htmlParser.addAttributeFilter('src,href,style', function(nodes, name) {
+ var i = nodes.length, node, value, internalName = 'data-mce-' + name, urlConverter = settings.url_converter, urlConverterScope = settings.url_converter_scope, undef;
+
+ while (i--) {
+ node = nodes[i];
+
+ value = node.attributes.map[internalName];
+ if (value !== undef) {
+ // Set external name to internal value and remove internal
+ node.attr(name, value.length > 0 ? value : null);
+ node.attr(internalName, null);
+ } else {
+ // No internal attribute found then convert the value we have in the DOM
+ value = node.attributes.map[name];
+
+ if (name === "style")
+ value = dom.serializeStyle(dom.parseStyle(value), node.name);
+ else if (urlConverter)
+ value = urlConverter.call(urlConverterScope, value, name, node.name);
+
+ node.attr(name, value.length > 0 ? value : null);
+ }
+ }
+ });
+
+ // Remove internal classes mceItem<..> or mceSelected
+ htmlParser.addAttributeFilter('class', function(nodes, name) {
+ var i = nodes.length, node, value;
+
+ while (i--) {
+ node = nodes[i];
+ value = node.attr('class').replace(/(?:^|\s)mce(Item\w+|Selected)(?!\S)/g, '');
+ node.attr('class', value.length > 0 ? value : null);
+ }
+ });
+
+ // Remove bookmark elements
+ htmlParser.addAttributeFilter('data-mce-type', function(nodes, name, args) {
+ var i = nodes.length, node;
+
+ while (i--) {
+ node = nodes[i];
+
+ if (node.attributes.map['data-mce-type'] === 'bookmark' && !args.cleanup)
+ node.remove();
+ }
+ });
+
+ // Remove expando attributes
+ htmlParser.addAttributeFilter('data-mce-expando', function(nodes, name, args) {
+ var i = nodes.length;
+
+ while (i--) {
+ nodes[i].attr(name, null);
+ }
+ });
+
+ // Force script into CDATA sections and remove the mce- prefix also add comments around styles
+ htmlParser.addNodeFilter('script,style', function(nodes, name) {
+ var i = nodes.length, node, value;
+
+ function trim(value) {
+ return value.replace(/(<!--\[CDATA\[|\]\]-->)/g, '\n')
+ .replace(/^[\r\n]*|[\r\n]*$/g, '')
+ .replace(/^\s*((<!--)?(\s*\/\/)?\s*<!\[CDATA\[|(<!--\s*)?\/\*\s*<!\[CDATA\[\s*\*\/|(\/\/)?\s*<!--|\/\*\s*<!--\s*\*\/)\s*[\r\n]*/gi, '')
+ .replace(/\s*(\/\*\s*\]\]>\s*\*\/(-->)?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g, '');
+ };
+
+ while (i--) {
+ node = nodes[i];
+ value = node.firstChild ? node.firstChild.value : '';
+
+ if (name === "script") {
+ // Remove mce- prefix from script elements
+ node.attr('type', (node.attr('type') || 'text/javascript').replace(/^mce\-/, ''));
+
+ if (value.length > 0)
+ node.firstChild.value = '// <![CDATA[\n' + trim(value) + '\n// ]]>';
+ } else {
+ if (value.length > 0)
+ node.firstChild.value = '<!--\n' + trim(value) + '\n-->';
+ }
+ }
+ });
+
+ // Convert comments to cdata and handle protected comments
+ htmlParser.addNodeFilter('#comment', function(nodes, name) {
+ var i = nodes.length, node;
+
+ while (i--) {
+ node = nodes[i];
+
+ if (node.value.indexOf('[CDATA[') === 0) {
+ node.name = '#cdata';
+ node.type = 4;
+ node.value = node.value.replace(/^\[CDATA\[|\]\]$/g, '');
+ } else if (node.value.indexOf('mce:protected ') === 0) {
+ node.name = "#text";
+ node.type = 3;
+ node.raw = true;
+ node.value = unescape(node.value).substr(14);
+ }
+ }
+ });
+
+ htmlParser.addNodeFilter('xml:namespace,input', function(nodes, name) {
+ var i = nodes.length, node;
+
+ while (i--) {
+ node = nodes[i];
+ if (node.type === 7)
+ node.remove();
+ else if (node.type === 1) {
+ if (name === "input" && !("type" in node.attributes.map))
+ node.attr('type', 'text');
+ }
+ }
+ });
+
+ // Fix list elements, TODO: Replace this later
+ if (settings.fix_list_elements) {
+ htmlParser.addNodeFilter('ul,ol', function(nodes, name) {
+ var i = nodes.length, node, parentNode;
+
+ while (i--) {
+ node = nodes[i];
+ parentNode = node.parent;
+
+ if (parentNode.name === 'ul' || parentNode.name === 'ol') {
+ if (node.prev && node.prev.name === 'li') {
+ node.prev.append(node);
+ }
+ }
+ }
+ });
+ }
+
+ // Remove internal data attributes
+ htmlParser.addAttributeFilter('data-mce-src,data-mce-href,data-mce-style', function(nodes, name) {
+ var i = nodes.length;
+
+ while (i--) {
+ nodes[i].attr(name, null);
+ }
+ });
+
+ // Return public methods
+ return {
+ schema : schema,
+
+ addNodeFilter : htmlParser.addNodeFilter,
+
+ addAttributeFilter : htmlParser.addAttributeFilter,
+
+ onPreProcess : onPreProcess,
+
+ onPostProcess : onPostProcess,
+
+ serialize : function(node, args) {
+ var impl, doc, oldDoc, htmlSerializer, content;
+
+ // Explorer won't clone contents of script and style and the
+ // selected index of select elements are cleared on a clone operation.
+ if (isIE && dom.select('script,style,select,map').length > 0) {
+ content = node.innerHTML;
+ node = node.cloneNode(false);
+ dom.setHTML(node, content);
+ } else
+ node = node.cloneNode(true);
+
+ // Nodes needs to be attached to something in WebKit/Opera
+ // Older builds of Opera crashes if you attach the node to an document created dynamically
+ // and since we can't feature detect a crash we need to sniff the acutal build number
+ // This fix will make DOM ranges and make Sizzle happy!
+ impl = node.ownerDocument.implementation;
+ if (impl.createHTMLDocument) {
+ // Create an empty HTML document
+ doc = impl.createHTMLDocument("");
+
+ // Add the element or it's children if it's a body element to the new document
+ each(node.nodeName == 'BODY' ? node.childNodes : [node], function(node) {
+ doc.body.appendChild(doc.importNode(node, true));
+ });
+
+ // Grab first child or body element for serialization
+ if (node.nodeName != 'BODY')
+ node = doc.body.firstChild;
+ else
+ node = doc.body;
+
+ // set the new document in DOMUtils so createElement etc works
+ oldDoc = dom.doc;
+ dom.doc = doc;
+ }
+
+ args = args || {};
+ args.format = args.format || 'html';
+
+ // Pre process
+ if (!args.no_events) {
+ args.node = node;
+ onPreProcess.dispatch(self, args);
+ }
+
+ // Setup serializer
+ htmlSerializer = new tinymce.html.Serializer(settings, schema);
+
+ // Parse and serialize HTML
+ args.content = htmlSerializer.serialize(
+ htmlParser.parse(tinymce.trim(args.getInner ? node.innerHTML : dom.getOuterHTML(node)), args)
+ );
+
+ // Replace all BOM characters for now until we can find a better solution
+ if (!args.cleanup)
+ args.content = args.content.replace(/\uFEFF|\u200B/g, '');
+
+ // Post process
+ if (!args.no_events)
+ onPostProcess.dispatch(self, args);
+
+ // Restore the old document if it was changed
+ if (oldDoc)
+ dom.doc = oldDoc;
+
+ args.node = null;
+
+ return args.content;
+ },
+
+ addRules : function(rules) {
+ schema.addValidElements(rules);
+ },
+
+ setRules : function(rules) {
+ schema.setValidElements(rules);
+ }
+ };
+ };
+})(tinymce);
+(function(tinymce) {
+ tinymce.dom.ScriptLoader = function(settings) {
+ var QUEUED = 0,
+ LOADING = 1,
+ LOADED = 2,
+ states = {},
+ queue = [],
+ scriptLoadedCallbacks = {},
+ queueLoadedCallbacks = [],
+ loading = 0,
+ undef;
+
+ function loadScript(url, callback) {
+ var t = this, dom = tinymce.DOM, elm, uri, loc, id;
+
+ // Execute callback when script is loaded
+ function done() {
+ dom.remove(id);
+
+ if (elm)
+ elm.onreadystatechange = elm.onload = elm = null;
+
+ callback();
+ };
+
+ function error() {
+ // Report the error so it's easier for people to spot loading errors
+ if (typeof(console) !== "undefined" && console.log)
+ console.log("Failed to load: " + url);
+
+ // We can't mark it as done if there is a load error since
+ // A) We don't want to produce 404 errors on the server and
+ // B) the onerror event won't fire on all browsers.
+ // done();
+ };
+
+ id = dom.uniqueId();
+
+ if (tinymce.isIE6) {
+ uri = new tinymce.util.URI(url);
+ loc = location;
+
+ // If script is from same domain and we
+ // use IE 6 then use XHR since it's more reliable
+ if (uri.host == loc.hostname && uri.port == loc.port && (uri.protocol + ':') == loc.protocol && uri.protocol.toLowerCase() != 'file') {
+ tinymce.util.XHR.send({
+ url : tinymce._addVer(uri.getURI()),
+ success : function(content) {
+ // Create new temp script element
+ var script = dom.create('script', {
+ type : 'text/javascript'
+ });
+
+ // Evaluate script in global scope
+ script.text = content;
+ document.getElementsByTagName('head')[0].appendChild(script);
+ dom.remove(script);
+
+ done();
+ },
+
+ error : error
+ });
+
+ return;
+ }
+ }
+
+ // Create new script element
+ elm = document.createElement('script');
+ elm.id = id;
+ elm.type = 'text/javascript';
+ elm.src = tinymce._addVer(url);
+
+ // Add onload listener for non IE browsers since IE9
+ // fires onload event before the script is parsed and executed
+ if (!tinymce.isIE)
+ elm.onload = done;
+
+ // Add onerror event will get fired on some browsers but not all of them
+ elm.onerror = error;
+
+ // Opera 9.60 doesn't seem to fire the onreadystate event at correctly
+ if (!tinymce.isOpera) {
+ elm.onreadystatechange = function() {
+ var state = elm.readyState;
+
+ // Loaded state is passed on IE 6 however there
+ // are known issues with this method but we can't use
+ // XHR in a cross domain loading
+ if (state == 'complete' || state == 'loaded')
+ done();
+ };
+ }
+
+ // Most browsers support this feature so we report errors
+ // for those at least to help users track their missing plugins etc
+ // todo: Removed since it produced error if the document is unloaded by navigating away, re-add it as an option
+ /*elm.onerror = function() {
+ alert('Failed to load: ' + url);
+ };*/
+
+ // Add script to document
+ (document.getElementsByTagName('head')[0] || document.body).appendChild(elm);
+ };
+
+ this.isDone = function(url) {
+ return states[url] == LOADED;
+ };
+
+ this.markDone = function(url) {
+ states[url] = LOADED;
+ };
+
+ this.add = this.load = function(url, callback, scope) {
+ var item, state = states[url];
+
+ // Add url to load queue
+ if (state == undef) {
+ queue.push(url);
+ states[url] = QUEUED;
+ }
+
+ if (callback) {
+ // Store away callback for later execution
+ if (!scriptLoadedCallbacks[url])
+ scriptLoadedCallbacks[url] = [];
+
+ scriptLoadedCallbacks[url].push({
+ func : callback,
+ scope : scope || this
+ });
+ }
+ };
+
+ this.loadQueue = function(callback, scope) {
+ this.loadScripts(queue, callback, scope);
+ };
+
+ this.loadScripts = function(scripts, callback, scope) {
+ var loadScripts;
+
+ function execScriptLoadedCallbacks(url) {
+ // Execute URL callback functions
+ tinymce.each(scriptLoadedCallbacks[url], function(callback) {
+ callback.func.call(callback.scope);
+ });
+
+ scriptLoadedCallbacks[url] = undef;
+ };
+
+ queueLoadedCallbacks.push({
+ func : callback,
+ scope : scope || this
+ });
+
+ loadScripts = function() {
+ var loadingScripts = tinymce.grep(scripts);
+
+ // Current scripts has been handled
+ scripts.length = 0;
+
+ // Load scripts that needs to be loaded
+ tinymce.each(loadingScripts, function(url) {
+ // Script is already loaded then execute script callbacks directly
+ if (states[url] == LOADED) {
+ execScriptLoadedCallbacks(url);
+ return;
+ }
+
+ // Is script not loading then start loading it
+ if (states[url] != LOADING) {
+ states[url] = LOADING;
+ loading++;
+
+ loadScript(url, function() {
+ states[url] = LOADED;
+ loading--;
+
+ execScriptLoadedCallbacks(url);
+
+ // Load more scripts if they where added by the recently loaded script
+ loadScripts();
+ });
+ }
+ });
+
+ // No scripts are currently loading then execute all pending queue loaded callbacks
+ if (!loading) {
+ tinymce.each(queueLoadedCallbacks, function(callback) {
+ callback.func.call(callback.scope);
+ });
+
+ queueLoadedCallbacks.length = 0;
+ }
+ };
+
+ loadScripts();
+ };
+ };
+
+ // Global script loader
+ tinymce.ScriptLoader = new tinymce.dom.ScriptLoader();
+})(tinymce);
+
+(function(tinymce) {
+ tinymce.dom.RangeUtils = function(dom) {
+ var INVISIBLE_CHAR = '\uFEFF';
+
+ this.walk = function(rng, callback) {
+ var startContainer = rng.startContainer,
+ startOffset = rng.startOffset,
+ endContainer = rng.endContainer,
+ endOffset = rng.endOffset,
+ ancestor, startPoint,
+ endPoint, node, parent, siblings, nodes;
+
+ // Handle table cell selection the table plugin enables
+ // you to fake select table cells and perform formatting actions on them
+ nodes = dom.select('td.mceSelected,th.mceSelected');
+ if (nodes.length > 0) {
+ tinymce.each(nodes, function(node) {
+ callback([node]);
+ });
+
+ return;
+ }
+
+ function exclude(nodes) {
+ var node;
+
+ // First node is excluded
+ node = nodes[0];
+ if (node.nodeType === 3 && node === startContainer && startOffset >= node.nodeValue.length) {
+ nodes.splice(0, 1);
+ }
+
+ // Last node is excluded
+ node = nodes[nodes.length - 1];
+ if (endOffset === 0 && nodes.length > 0 && node === endContainer && node.nodeType === 3) {
+ nodes.splice(nodes.length - 1, 1);
+ }
+
+ return nodes;
+ };
+
+ function collectSiblings(node, name, end_node) {
+ var siblings = [];
+
+ for (; node && node != end_node; node = node[name])
+ siblings.push(node);
+
+ return siblings;
+ };
+
+ function findEndPoint(node, root) {
+ do {
+ if (node.parentNode == root)
+ return node;
+
+ node = node.parentNode;
+ } while(node);
+ };
+
+ function walkBoundary(start_node, end_node, next) {
+ var siblingName = next ? 'nextSibling' : 'previousSibling';
+
+ for (node = start_node, parent = node.parentNode; node && node != end_node; node = parent) {
+ parent = node.parentNode;
+ siblings = collectSiblings(node == start_node ? node : node[siblingName], siblingName);
+
+ if (siblings.length) {
+ if (!next)
+ siblings.reverse();
+
+ callback(exclude(siblings));
+ }
+ }
+ };
+
+ // If index based start position then resolve it
+ if (startContainer.nodeType == 1 && startContainer.hasChildNodes())
+ startContainer = startContainer.childNodes[startOffset];
+
+ // If index based end position then resolve it
+ if (endContainer.nodeType == 1 && endContainer.hasChildNodes())
+ endContainer = endContainer.childNodes[Math.min(endOffset - 1, endContainer.childNodes.length - 1)];
+
+ // Same container
+ if (startContainer == endContainer)
+ return callback(exclude([startContainer]));
+
+ // Find common ancestor and end points
+ ancestor = dom.findCommonAncestor(startContainer, endContainer);
+
+ // Process left side
+ for (node = startContainer; node; node = node.parentNode) {
+ if (node === endContainer)
+ return walkBoundary(startContainer, ancestor, true);
+
+ if (node === ancestor)
+ break;
+ }
+
+ // Process right side
+ for (node = endContainer; node; node = node.parentNode) {
+ if (node === startContainer)
+ return walkBoundary(endContainer, ancestor);
+
+ if (node === ancestor)
+ break;
+ }
+
+ // Find start/end point
+ startPoint = findEndPoint(startContainer, ancestor) || startContainer;
+ endPoint = findEndPoint(endContainer, ancestor) || endContainer;
+
+ // Walk left leaf
+ walkBoundary(startContainer, startPoint, true);
+
+ // Walk the middle from start to end point
+ siblings = collectSiblings(
+ startPoint == startContainer ? startPoint : startPoint.nextSibling,
+ 'nextSibling',
+ endPoint == endContainer ? endPoint.nextSibling : endPoint
+ );
+
+ if (siblings.length)
+ callback(exclude(siblings));
+
+ // Walk right leaf
+ walkBoundary(endContainer, endPoint);
+ };
+
+ this.split = function(rng) {
+ var startContainer = rng.startContainer,
+ startOffset = rng.startOffset,
+ endContainer = rng.endContainer,
+ endOffset = rng.endOffset;
+
+ function splitText(node, offset) {
+ return node.splitText(offset);
+ };
+
+ // Handle single text node
+ if (startContainer == endContainer && startContainer.nodeType == 3) {
+ if (startOffset > 0 && startOffset < startContainer.nodeValue.length) {
+ endContainer = splitText(startContainer, startOffset);
+ startContainer = endContainer.previousSibling;
+
+ if (endOffset > startOffset) {
+ endOffset = endOffset - startOffset;
+ startContainer = endContainer = splitText(endContainer, endOffset).previousSibling;
+ endOffset = endContainer.nodeValue.length;
+ startOffset = 0;
+ } else {
+ endOffset = 0;
+ }
+ }
+ } else {
+ // Split startContainer text node if needed
+ if (startContainer.nodeType == 3 && startOffset > 0 && startOffset < startContainer.nodeValue.length) {
+ startContainer = splitText(startContainer, startOffset);
+ startOffset = 0;
+ }
+
+ // Split endContainer text node if needed
+ if (endContainer.nodeType == 3 && endOffset > 0 && endOffset < endContainer.nodeValue.length) {
+ endContainer = splitText(endContainer, endOffset).previousSibling;
+ endOffset = endContainer.nodeValue.length;
+ }
+ }
+
+ return {
+ startContainer : startContainer,
+ startOffset : startOffset,
+ endContainer : endContainer,
+ endOffset : endOffset
+ };
+ };
+
+ };
+
+ tinymce.dom.RangeUtils.compareRanges = function(rng1, rng2) {
+ if (rng1 && rng2) {
+ // Compare native IE ranges
+ if (rng1.item || rng1.duplicate) {
+ // Both are control ranges and the selected element matches
+ if (rng1.item && rng2.item && rng1.item(0) === rng2.item(0))
+ return true;
+
+ // Both are text ranges and the range matches
+ if (rng1.isEqual && rng2.isEqual && rng2.isEqual(rng1))
+ return true;
+ } else {
+ // Compare w3c ranges
+ return rng1.startContainer == rng2.startContainer && rng1.startOffset == rng2.startOffset;
+ }
+ }
+
+ return false;
+ };
+})(tinymce);
+
+(function(tinymce) {
+ var Event = tinymce.dom.Event, each = tinymce.each;
+
+ tinymce.create('tinymce.ui.KeyboardNavigation', {
+ KeyboardNavigation: function(settings, dom) {
+ var t = this, root = settings.root, items = settings.items,
+ enableUpDown = settings.enableUpDown, enableLeftRight = settings.enableLeftRight || !settings.enableUpDown,
+ excludeFromTabOrder = settings.excludeFromTabOrder,
+ itemFocussed, itemBlurred, rootKeydown, rootFocussed, focussedId;
+
+ dom = dom || tinymce.DOM;
+
+ itemFocussed = function(evt) {
+ focussedId = evt.target.id;
+ };
+
+ itemBlurred = function(evt) {
+ dom.setAttrib(evt.target.id, 'tabindex', '-1');
+ };
+
+ rootFocussed = function(evt) {
+ var item = dom.get(focussedId);
+ dom.setAttrib(item, 'tabindex', '0');
+ item.focus();
+ };
+
+ t.focus = function() {
+ dom.get(focussedId).focus();
+ };
+
+ t.destroy = function() {
+ each(items, function(item) {
+ var elm = dom.get(item.id);
+
+ dom.unbind(elm, 'focus', itemFocussed);
+ dom.unbind(elm, 'blur', itemBlurred);
+ });
+
+ var rootElm = dom.get(root);
+ dom.unbind(rootElm, 'focus', rootFocussed);
+ dom.unbind(rootElm, 'keydown', rootKeydown);
+
+ items = dom = root = t.focus = itemFocussed = itemBlurred = rootKeydown = rootFocussed = null;
+ t.destroy = function() {};
+ };
+
+ t.moveFocus = function(dir, evt) {
+ var idx = -1, controls = t.controls, newFocus;
+
+ if (!focussedId)
+ return;
+
+ each(items, function(item, index) {
+ if (item.id === focussedId) {
+ idx = index;
+ return false;
+ }
+ });
+
+ idx += dir;
+ if (idx < 0) {
+ idx = items.length - 1;
+ } else if (idx >= items.length) {
+ idx = 0;
+ }
+
+ newFocus = items[idx];
+ dom.setAttrib(focussedId, 'tabindex', '-1');
+ dom.setAttrib(newFocus.id, 'tabindex', '0');
+ dom.get(newFocus.id).focus();
+
+ if (settings.actOnFocus) {
+ settings.onAction(newFocus.id);
+ }
+
+ if (evt)
+ Event.cancel(evt);
+ };
+
+ rootKeydown = function(evt) {
+ var DOM_VK_LEFT = 37, DOM_VK_RIGHT = 39, DOM_VK_UP = 38, DOM_VK_DOWN = 40, DOM_VK_ESCAPE = 27, DOM_VK_ENTER = 14, DOM_VK_RETURN = 13, DOM_VK_SPACE = 32;
+
+ switch (evt.keyCode) {
+ case DOM_VK_LEFT:
+ if (enableLeftRight) t.moveFocus(-1);
+ break;
+
+ case DOM_VK_RIGHT:
+ if (enableLeftRight) t.moveFocus(1);
+ break;
+
+ case DOM_VK_UP:
+ if (enableUpDown) t.moveFocus(-1);
+ break;
+
+ case DOM_VK_DOWN:
+ if (enableUpDown) t.moveFocus(1);
+ break;
+
+ case DOM_VK_ESCAPE:
+ if (settings.onCancel) {
+ settings.onCancel();
+ Event.cancel(evt);
+ }
+ break;
+
+ case DOM_VK_ENTER:
+ case DOM_VK_RETURN:
+ case DOM_VK_SPACE:
+ if (settings.onAction) {
+ settings.onAction(focussedId);
+ Event.cancel(evt);
+ }
+ break;
+ }
+ };
+
+ // Set up state and listeners for each item.
+ each(items, function(item, idx) {
+ var tabindex, elm;
+
+ if (!item.id) {
+ item.id = dom.uniqueId('_mce_item_');
+ }
+
+ elm = dom.get(item.id);
+
+ if (excludeFromTabOrder) {
+ dom.bind(elm, 'blur', itemBlurred);
+ tabindex = '-1';
+ } else {
+ tabindex = (idx === 0 ? '0' : '-1');
+ }
+
+ elm.setAttribute('tabindex', tabindex);
+ dom.bind(elm, 'focus', itemFocussed);
+ });
+
+ // Setup initial state for root element.
+ if (items[0]){
+ focussedId = items[0].id;
+ }
+
+ dom.setAttrib(root, 'tabindex', '-1');
+
+ // Setup listeners for root element.
+ var rootElm = dom.get(root);
+ dom.bind(rootElm, 'focus', rootFocussed);
+ dom.bind(rootElm, 'keydown', rootKeydown);
+ }
+ });
+})(tinymce);
+
+(function(tinymce) {
+ // Shorten class names
+ var DOM = tinymce.DOM, is = tinymce.is;
+
+ tinymce.create('tinymce.ui.Control', {
+ Control : function(id, s, editor) {
+ this.id = id;
+ this.settings = s = s || {};
+ this.rendered = false;
+ this.onRender = new tinymce.util.Dispatcher(this);
+ this.classPrefix = '';
+ this.scope = s.scope || this;
+ this.disabled = 0;
+ this.active = 0;
+ this.editor = editor;
+ },
+
+ setAriaProperty : function(property, value) {
+ var element = DOM.get(this.id + '_aria') || DOM.get(this.id);
+ if (element) {
+ DOM.setAttrib(element, 'aria-' + property, !!value);
+ }
+ },
+
+ focus : function() {
+ DOM.get(this.id).focus();
+ },
+
+ setDisabled : function(s) {
+ if (s != this.disabled) {
+ this.setAriaProperty('disabled', s);
+
+ this.setState('Disabled', s);
+ this.setState('Enabled', !s);
+ this.disabled = s;
+ }
+ },
+
+ isDisabled : function() {
+ return this.disabled;
+ },
+
+ setActive : function(s) {
+ if (s != this.active) {
+ this.setState('Active', s);
+ this.active = s;
+ this.setAriaProperty('pressed', s);
+ }
+ },
+
+ isActive : function() {
+ return this.active;
+ },
+
+ setState : function(c, s) {
+ var n = DOM.get(this.id);
+
+ c = this.classPrefix + c;
+
+ if (s)
+ DOM.addClass(n, c);
+ else
+ DOM.removeClass(n, c);
+ },
+
+ isRendered : function() {
+ return this.rendered;
+ },
+
+ renderHTML : function() {
+ },
+
+ renderTo : function(n) {
+ DOM.setHTML(n, this.renderHTML());
+ },
+
+ postRender : function() {
+ var t = this, b;
+
+ // Set pending states
+ if (is(t.disabled)) {
+ b = t.disabled;
+ t.disabled = -1;
+ t.setDisabled(b);
+ }
+
+ if (is(t.active)) {
+ b = t.active;
+ t.active = -1;
+ t.setActive(b);
+ }
+ },
+
+ remove : function() {
+ DOM.remove(this.id);
+ this.destroy();
+ },
+
+ destroy : function() {
+ tinymce.dom.Event.clear(this.id);
+ }
+ });
+})(tinymce);
+tinymce.create('tinymce.ui.Container:tinymce.ui.Control', {
+ Container : function(id, s, editor) {
+ this.parent(id, s, editor);
+
+ this.controls = [];
+
+ this.lookup = {};
+ },
+
+ add : function(c) {
+ this.lookup[c.id] = c;
+ this.controls.push(c);
+
+ return c;
+ },
+
+ get : function(n) {
+ return this.lookup[n];
+ }
+});
+
+
+tinymce.create('tinymce.ui.Separator:tinymce.ui.Control', {
+ Separator : function(id, s) {
+ this.parent(id, s);
+ this.classPrefix = 'mceSeparator';
+ this.setDisabled(true);
+ },
+
+ renderHTML : function() {
+ return tinymce.DOM.createHTML('span', {'class' : this.classPrefix, role : 'separator', 'aria-orientation' : 'vertical', tabindex : '-1'});
+ }
+});
+
+(function(tinymce) {
+ var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, walk = tinymce.walk;
+
+ tinymce.create('tinymce.ui.MenuItem:tinymce.ui.Control', {
+ MenuItem : function(id, s) {
+ this.parent(id, s);
+ this.classPrefix = 'mceMenuItem';
+ },
+
+ setSelected : function(s) {
+ this.setState('Selected', s);
+ this.setAriaProperty('checked', !!s);
+ this.selected = s;
+ },
+
+ isSelected : function() {
+ return this.selected;
+ },
+
+ postRender : function() {
+ var t = this;
+
+ t.parent();
+
+ // Set pending state
+ if (is(t.selected))
+ t.setSelected(t.selected);
+ }
+ });
+})(tinymce);
+
+(function(tinymce) {
+ var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, walk = tinymce.walk;
+
+ tinymce.create('tinymce.ui.Menu:tinymce.ui.MenuItem', {
+ Menu : function(id, s) {
+ var t = this;
+
+ t.parent(id, s);
+ t.items = {};
+ t.collapsed = false;
+ t.menuCount = 0;
+ t.onAddItem = new tinymce.util.Dispatcher(this);
+ },
+
+ expand : function(d) {
+ var t = this;
+
+ if (d) {
+ walk(t, function(o) {
+ if (o.expand)
+ o.expand();
+ }, 'items', t);
+ }
+
+ t.collapsed = false;
+ },
+
+ collapse : function(d) {
+ var t = this;
+
+ if (d) {
+ walk(t, function(o) {
+ if (o.collapse)
+ o.collapse();
+ }, 'items', t);
+ }
+
+ t.collapsed = true;
+ },
+
+ isCollapsed : function() {
+ return this.collapsed;
+ },
+
+ add : function(o) {
+ if (!o.settings)
+ o = new tinymce.ui.MenuItem(o.id || DOM.uniqueId(), o);
+
+ this.onAddItem.dispatch(this, o);
+
+ return this.items[o.id] = o;
+ },
+
+ addSeparator : function() {
+ return this.add({separator : true});
+ },
+
+ addMenu : function(o) {
+ if (!o.collapse)
+ o = this.createMenu(o);
+
+ this.menuCount++;
+
+ return this.add(o);
+ },
+
+ hasMenus : function() {
+ return this.menuCount !== 0;
+ },
+
+ remove : function(o) {
+ delete this.items[o.id];
+ },
+
+ removeAll : function() {
+ var t = this;
+
+ walk(t, function(o) {
+ if (o.removeAll)
+ o.removeAll();
+ else
+ o.remove();
+
+ o.destroy();
+ }, 'items', t);
+
+ t.items = {};
+ },
+
+ createMenu : function(o) {
+ var m = new tinymce.ui.Menu(o.id || DOM.uniqueId(), o);
+
+ m.onAddItem.add(this.onAddItem.dispatch, this.onAddItem);
+
+ return m;
+ }
+ });
+})(tinymce);
+(function(tinymce) {
+ var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, Event = tinymce.dom.Event, Element = tinymce.dom.Element;
+
+ tinymce.create('tinymce.ui.DropMenu:tinymce.ui.Menu', {
+ DropMenu : function(id, s) {
+ s = s || {};
+ s.container = s.container || DOM.doc.body;
+ s.offset_x = s.offset_x || 0;
+ s.offset_y = s.offset_y || 0;
+ s.vp_offset_x = s.vp_offset_x || 0;
+ s.vp_offset_y = s.vp_offset_y || 0;
+
+ if (is(s.icons) && !s.icons)
+ s['class'] += ' mceNoIcons';
+
+ this.parent(id, s);
+ this.onShowMenu = new tinymce.util.Dispatcher(this);
+ this.onHideMenu = new tinymce.util.Dispatcher(this);
+ this.classPrefix = 'mceMenu';
+ },
+
+ createMenu : function(s) {
+ var t = this, cs = t.settings, m;
+
+ s.container = s.container || cs.container;
+ s.parent = t;
+ s.constrain = s.constrain || cs.constrain;
+ s['class'] = s['class'] || cs['class'];
+ s.vp_offset_x = s.vp_offset_x || cs.vp_offset_x;
+ s.vp_offset_y = s.vp_offset_y || cs.vp_offset_y;
+ s.keyboard_focus = cs.keyboard_focus;
+ m = new tinymce.ui.DropMenu(s.id || DOM.uniqueId(), s);
+
+ m.onAddItem.add(t.onAddItem.dispatch, t.onAddItem);
+
+ return m;
+ },
+
+ focus : function() {
+ var t = this;
+ if (t.keyboardNav) {
+ t.keyboardNav.focus();
+ }
+ },
+
+ update : function() {
+ var t = this, s = t.settings, tb = DOM.get('menu_' + t.id + '_tbl'), co = DOM.get('menu_' + t.id + '_co'), tw, th;
+
+ tw = s.max_width ? Math.min(tb.offsetWidth, s.max_width) : tb.offsetWidth;
+ th = s.max_height ? Math.min(tb.offsetHeight, s.max_height) : tb.offsetHeight;
+
+ if (!DOM.boxModel)
+ t.element.setStyles({width : tw + 2, height : th + 2});
+ else
+ t.element.setStyles({width : tw, height : th});
+
+ if (s.max_width)
+ DOM.setStyle(co, 'width', tw);
+
+ if (s.max_height) {
+ DOM.setStyle(co, 'height', th);
+
+ if (tb.clientHeight < s.max_height)
+ DOM.setStyle(co, 'overflow', 'hidden');
+ }
+ },
+
+ showMenu : function(x, y, px) {
+ var t = this, s = t.settings, co, vp = DOM.getViewPort(), w, h, mx, my, ot = 2, dm, tb, cp = t.classPrefix;
+
+ t.collapse(1);
+
+ if (t.isMenuVisible)
+ return;
+
+ if (!t.rendered) {
+ co = DOM.add(t.settings.container, t.renderNode());
+
+ each(t.items, function(o) {
+ o.postRender();
+ });
+
+ t.element = new Element('menu_' + t.id, {blocker : 1, container : s.container});
+ } else
+ co = DOM.get('menu_' + t.id);
+
+ // Move layer out of sight unless it's Opera since it scrolls to top of page due to an bug
+ if (!tinymce.isOpera)
+ DOM.setStyles(co, {left : -0xFFFF , top : -0xFFFF});
+
+ DOM.show(co);
+ t.update();
+
+ x += s.offset_x || 0;
+ y += s.offset_y || 0;
+ vp.w -= 4;
+ vp.h -= 4;
+
+ // Move inside viewport if not submenu
+ if (s.constrain) {
+ w = co.clientWidth - ot;
+ h = co.clientHeight - ot;
+ mx = vp.x + vp.w;
+ my = vp.y + vp.h;
+
+ if ((x + s.vp_offset_x + w) > mx)
+ x = px ? px - w : Math.max(0, (mx - s.vp_offset_x) - w);
+
+ if ((y + s.vp_offset_y + h) > my)
+ y = Math.max(0, (my - s.vp_offset_y) - h);
+ }
+
+ DOM.setStyles(co, {left : x , top : y});
+ t.element.update();
+
+ t.isMenuVisible = 1;
+ t.mouseClickFunc = Event.add(co, 'click', function(e) {
+ var m;
+
+ e = e.target;
+
+ if (e && (e = DOM.getParent(e, 'tr')) && !DOM.hasClass(e, cp + 'ItemSub')) {
+ m = t.items[e.id];
+
+ if (m.isDisabled())
+ return;
+
+ dm = t;
+
+ while (dm) {
+ if (dm.hideMenu)
+ dm.hideMenu();
+
+ dm = dm.settings.parent;
+ }
+
+ if (m.settings.onclick)
+ m.settings.onclick(e);
+
+ return false; // Cancel to fix onbeforeunload problem
+ }
+ });
+
+ if (t.hasMenus()) {
+ t.mouseOverFunc = Event.add(co, 'mouseover', function(e) {
+ var m, r, mi;
+
+ e = e.target;
+ if (e && (e = DOM.getParent(e, 'tr'))) {
+ m = t.items[e.id];
+
+ if (t.lastMenu)
+ t.lastMenu.collapse(1);
+
+ if (m.isDisabled())
+ return;
+
+ if (e && DOM.hasClass(e, cp + 'ItemSub')) {
+ //p = DOM.getPos(s.container);
+ r = DOM.getRect(e);
+ m.showMenu((r.x + r.w - ot), r.y - ot, r.x);
+ t.lastMenu = m;
+ DOM.addClass(DOM.get(m.id).firstChild, cp + 'ItemActive');
+ }
+ }
+ });
+ }
+
+ Event.add(co, 'keydown', t._keyHandler, t);
+
+ t.onShowMenu.dispatch(t);
+
+ if (s.keyboard_focus) {
+ t._setupKeyboardNav();
+ }
+ },
+
+ hideMenu : function(c) {
+ var t = this, co = DOM.get('menu_' + t.id), e;
+
+ if (!t.isMenuVisible)
+ return;
+
+ if (t.keyboardNav) t.keyboardNav.destroy();
+ Event.remove(co, 'mouseover', t.mouseOverFunc);
+ Event.remove(co, 'click', t.mouseClickFunc);
+ Event.remove(co, 'keydown', t._keyHandler);
+ DOM.hide(co);
+ t.isMenuVisible = 0;
+
+ if (!c)
+ t.collapse(1);
+
+ if (t.element)
+ t.element.hide();
+
+ if (e = DOM.get(t.id))
+ DOM.removeClass(e.firstChild, t.classPrefix + 'ItemActive');
+
+ t.onHideMenu.dispatch(t);
+ },
+
+ add : function(o) {
+ var t = this, co;
+
+ o = t.parent(o);
+
+ if (t.isRendered && (co = DOM.get('menu_' + t.id)))
+ t._add(DOM.select('tbody', co)[0], o);
+
+ return o;
+ },
+
+ collapse : function(d) {
+ this.parent(d);
+ this.hideMenu(1);
+ },
+
+ remove : function(o) {
+ DOM.remove(o.id);
+ this.destroy();
+
+ return this.parent(o);
+ },
+
+ destroy : function() {
+ var t = this, co = DOM.get('menu_' + t.id);
+
+ if (t.keyboardNav) t.keyboardNav.destroy();
+ Event.remove(co, 'mouseover', t.mouseOverFunc);
+ Event.remove(DOM.select('a', co), 'focus', t.mouseOverFunc);
+ Event.remove(co, 'click', t.mouseClickFunc);
+ Event.remove(co, 'keydown', t._keyHandler);
+
+ if (t.element)
+ t.element.remove();
+
+ DOM.remove(co);
+ },
+
+ renderNode : function() {
+ var t = this, s = t.settings, n, tb, co, w;
+
+ w = DOM.create('div', {role: 'listbox', id : 'menu_' + t.id, 'class' : s['class'], 'style' : 'position:absolute;left:0;top:0;z-index:200000;outline:0'});
+ if (t.settings.parent) {
+ DOM.setAttrib(w, 'aria-parent', 'menu_' + t.settings.parent.id);
+ }
+ co = DOM.add(w, 'div', {role: 'presentation', id : 'menu_' + t.id + '_co', 'class' : t.classPrefix + (s['class'] ? ' ' + s['class'] : '')});
+ t.element = new Element('menu_' + t.id, {blocker : 1, container : s.container});
+
+ if (s.menu_line)
+ DOM.add(co, 'span', {'class' : t.classPrefix + 'Line'});
+
+// n = DOM.add(co, 'div', {id : 'menu_' + t.id + '_co', 'class' : 'mceMenuContainer'});
+ n = DOM.add(co, 'table', {role: 'presentation', id : 'menu_' + t.id + '_tbl', border : 0, cellPadding : 0, cellSpacing : 0});
+ tb = DOM.add(n, 'tbody');
+
+ each(t.items, function(o) {
+ t._add(tb, o);
+ });
+
+ t.rendered = true;
+
+ return w;
+ },
+
+ // Internal functions
+ _setupKeyboardNav : function(){
+ var contextMenu, menuItems, t=this;
+ contextMenu = DOM.get('menu_' + t.id);
+ menuItems = DOM.select('a[role=option]', 'menu_' + t.id);
+ menuItems.splice(0,0,contextMenu);
+ t.keyboardNav = new tinymce.ui.KeyboardNavigation({
+ root: 'menu_' + t.id,
+ items: menuItems,
+ onCancel: function() {
+ t.hideMenu();
+ },
+ enableUpDown: true
+ });
+ contextMenu.focus();
+ },
+
+ _keyHandler : function(evt) {
+ var t = this, e;
+ switch (evt.keyCode) {
+ case 37: // Left
+ if (t.settings.parent) {
+ t.hideMenu();
+ t.settings.parent.focus();
+ Event.cancel(evt);
+ }
+ break;
+ case 39: // Right
+ if (t.mouseOverFunc)
+ t.mouseOverFunc(evt);
+ break;
+ }
+ },
+
+ _add : function(tb, o) {
+ var n, s = o.settings, a, ro, it, cp = this.classPrefix, ic;
+
+ if (s.separator) {
+ ro = DOM.add(tb, 'tr', {id : o.id, 'class' : cp + 'ItemSeparator'});
+ DOM.add(ro, 'td', {'class' : cp + 'ItemSeparator'});
+
+ if (n = ro.previousSibling)
+ DOM.addClass(n, 'mceLast');
+
+ return;
+ }
+
+ n = ro = DOM.add(tb, 'tr', {id : o.id, 'class' : cp + 'Item ' + cp + 'ItemEnabled'});
+ n = it = DOM.add(n, s.titleItem ? 'th' : 'td');
+ n = a = DOM.add(n, 'a', {id: o.id + '_aria', role: s.titleItem ? 'presentation' : 'option', href : 'javascript:;', onclick : "return false;", onmousedown : 'return false;'});
+
+ if (s.parent) {
+ DOM.setAttrib(a, 'aria-haspopup', 'true');
+ DOM.setAttrib(a, 'aria-owns', 'menu_' + o.id);
+ }
+
+ DOM.addClass(it, s['class']);
+// n = DOM.add(n, 'span', {'class' : 'item'});
+
+ ic = DOM.add(n, 'span', {'class' : 'mceIcon' + (s.icon ? ' mce_' + s.icon : '')});
+
+ if (s.icon_src)
+ DOM.add(ic, 'img', {src : s.icon_src});
+
+ n = DOM.add(n, s.element || 'span', {'class' : 'mceText', title : o.settings.title}, o.settings.title);
+
+ if (o.settings.style) {
+ if (typeof o.settings.style == "function")
+ o.settings.style = o.settings.style();
+
+ DOM.setAttrib(n, 'style', o.settings.style);
+ }
+
+ if (tb.childNodes.length == 1)
+ DOM.addClass(ro, 'mceFirst');
+
+ if ((n = ro.previousSibling) && DOM.hasClass(n, cp + 'ItemSeparator'))
+ DOM.addClass(ro, 'mceFirst');
+
+ if (o.collapse)
+ DOM.addClass(ro, cp + 'ItemSub');
+
+ if (n = ro.previousSibling)
+ DOM.removeClass(n, 'mceLast');
+
+ DOM.addClass(ro, 'mceLast');
+ }
+ });
+})(tinymce);
+(function(tinymce) {
+ var DOM = tinymce.DOM;
+
+ tinymce.create('tinymce.ui.Button:tinymce.ui.Control', {
+ Button : function(id, s, ed) {
+ this.parent(id, s, ed);
+ this.classPrefix = 'mceButton';
+ },
+
+ renderHTML : function() {
+ var cp = this.classPrefix, s = this.settings, h, l;
+
+ l = DOM.encode(s.label || '');
+ h = '<a role="button" id="' + this.id + '" href="javascript:;" class="' + cp + ' ' + cp + 'Enabled ' + s['class'] + (l ? ' ' + cp + 'Labeled' : '') +'" onmousedown="return false;" onclick="return false;" aria-labelledby="' + this.id + '_voice" title="' + DOM.encode(s.title) + '">';
+ if (s.image && !(this.editor &&this.editor.forcedHighContrastMode) )
+ h += '<span class="mceIcon ' + s['class'] + '"><img class="mceIcon" src="' + s.image + '" alt="' + DOM.encode(s.title) + '" /></span>' + (l ? '<span class="' + cp + 'Label">' + l + '</span>' : '');
+ else
+ h += '<span class="mceIcon ' + s['class'] + '"></span>' + (l ? '<span class="' + cp + 'Label">' + l + '</span>' : '');
+
+ h += '<span class="mceVoiceLabel mceIconOnly" style="display: none;" id="' + this.id + '_voice">' + s.title + '</span>';
+ h += '</a>';
+ return h;
+ },
+
+ postRender : function() {
+ var t = this, s = t.settings, imgBookmark;
+
+ // In IE a large image that occupies the entire editor area will be deselected when a button is clicked, so
+ // need to keep the selection in case the selection is lost
+ if (tinymce.isIE && t.editor) {
+ tinymce.dom.Event.add(t.id, 'mousedown', function(e) {
+ var nodeName = t.editor.selection.getNode().nodeName;
+ imgBookmark = nodeName === 'IMG' ? t.editor.selection.getBookmark() : null;
+ });
+ }
+ tinymce.dom.Event.add(t.id, 'click', function(e) {
+ if (!t.isDisabled()) {
+ // restore the selection in case the selection is lost in IE
+ if (tinymce.isIE && t.editor && imgBookmark !== null) {
+ t.editor.selection.moveToBookmark(imgBookmark);
+ }
+ return s.onclick.call(s.scope, e);
+ }
+ });
+ tinymce.dom.Event.add(t.id, 'keyup', function(e) {
+ if (!t.isDisabled() && e.keyCode==tinymce.VK.SPACEBAR)
+ return s.onclick.call(s.scope, e);
+ });
+ }
+ });
+})(tinymce);
+
+(function(tinymce) {
+ var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher, undef;
+
+ tinymce.create('tinymce.ui.ListBox:tinymce.ui.Control', {
+ ListBox : function(id, s, ed) {
+ var t = this;
+
+ t.parent(id, s, ed);
+
+ t.items = [];
+
+ t.onChange = new Dispatcher(t);
+
+ t.onPostRender = new Dispatcher(t);
+
+ t.onAdd = new Dispatcher(t);
+
+ t.onRenderMenu = new tinymce.util.Dispatcher(this);
+
+ t.classPrefix = 'mceListBox';
+ t.marked = {};
+ },
+
+ select : function(va) {
+ var t = this, fv, f;
+
+ t.marked = {};
+
+ if (va == undef)
+ return t.selectByIndex(-1);
+
+ // Is string or number make function selector
+ if (va && typeof(va)=="function")
+ f = va;
+ else {
+ f = function(v) {
+ return v == va;
+ };
+ }
+
+ // Do we need to do something?
+ if (va != t.selectedValue) {
+ // Find item
+ each(t.items, function(o, i) {
+ if (f(o.value)) {
+ fv = 1;
+ t.selectByIndex(i);
+ return false;
+ }
+ });
+
+ if (!fv)
+ t.selectByIndex(-1);
+ }
+ },
+
+ selectByIndex : function(idx) {
+ var t = this, e, o, label;
+
+ t.marked = {};
+
+ if (idx != t.selectedIndex) {
+ e = DOM.get(t.id + '_text');
+ label = DOM.get(t.id + '_voiceDesc');
+ o = t.items[idx];
+
+ if (o) {
+ t.selectedValue = o.value;
+ t.selectedIndex = idx;
+ DOM.setHTML(e, DOM.encode(o.title));
+ DOM.setHTML(label, t.settings.title + " - " + o.title);
+ DOM.removeClass(e, 'mceTitle');
+ DOM.setAttrib(t.id, 'aria-valuenow', o.title);
+ } else {
+ DOM.setHTML(e, DOM.encode(t.settings.title));
+ DOM.setHTML(label, DOM.encode(t.settings.title));
+ DOM.addClass(e, 'mceTitle');
+ t.selectedValue = t.selectedIndex = null;
+ DOM.setAttrib(t.id, 'aria-valuenow', t.settings.title);
+ }
+ e = 0;
+ }
+ },
+
+ mark : function(value) {
+ this.marked[value] = true;
+ },
+
+ add : function(n, v, o) {
+ var t = this;
+
+ o = o || {};
+ o = tinymce.extend(o, {
+ title : n,
+ value : v
+ });
+
+ t.items.push(o);
+ t.onAdd.dispatch(t, o);
+ },
+
+ getLength : function() {
+ return this.items.length;
+ },
+
+ renderHTML : function() {
+ var h = '', t = this, s = t.settings, cp = t.classPrefix;
+
+ h = '<span role="listbox" aria-haspopup="true" aria-labelledby="' + t.id +'_voiceDesc" aria-describedby="' + t.id + '_voiceDesc"><table role="presentation" tabindex="0" id="' + t.id + '" cellpadding="0" cellspacing="0" class="' + cp + ' ' + cp + 'Enabled' + (s['class'] ? (' ' + s['class']) : '') + '"><tbody><tr>';
+ h += '<td>' + DOM.createHTML('span', {id: t.id + '_voiceDesc', 'class': 'voiceLabel', style:'display:none;'}, t.settings.title);
+ h += DOM.createHTML('a', {id : t.id + '_text', tabindex : -1, href : 'javascript:;', 'class' : 'mceText', onclick : "return false;", onmousedown : 'return false;'}, DOM.encode(t.settings.title)) + '</td>';
+ h += '<td>' + DOM.createHTML('a', {id : t.id + '_open', tabindex : -1, href : 'javascript:;', 'class' : 'mceOpen', onclick : "return false;", onmousedown : 'return false;'}, '<span><span style="display:none;" class="mceIconOnly" aria-hidden="true">\u25BC</span></span>') + '</td>';
+ h += '</tr></tbody></table></span>';
+
+ return h;
+ },
+
+ showMenu : function() {
+ var t = this, p2, e = DOM.get(this.id), m;
+
+ if (t.isDisabled() || t.items.length === 0)
+ return;
+
+ if (t.menu && t.menu.isMenuVisible)
+ return t.hideMenu();
+
+ if (!t.isMenuRendered) {
+ t.renderMenu();
+ t.isMenuRendered = true;
+ }
+
+ p2 = DOM.getPos(e);
+
+ m = t.menu;
+ m.settings.offset_x = p2.x;
+ m.settings.offset_y = p2.y;
+ m.settings.keyboard_focus = !tinymce.isOpera; // Opera is buggy when it comes to auto focus
+
+ // Select in menu
+ each(t.items, function(o) {
+ if (m.items[o.id]) {
+ m.items[o.id].setSelected(0);
+ }
+ });
+
+ each(t.items, function(o) {
+ if (m.items[o.id] && t.marked[o.value]) {
+ m.items[o.id].setSelected(1);
+ }
+
+ if (o.value === t.selectedValue) {
+ m.items[o.id].setSelected(1);
+ }
+ });
+
+ m.showMenu(0, e.clientHeight);
+
+ Event.add(DOM.doc, 'mousedown', t.hideMenu, t);
+ DOM.addClass(t.id, t.classPrefix + 'Selected');
+
+ //DOM.get(t.id + '_text').focus();
+ },
+
+ hideMenu : function(e) {
+ var t = this;
+
+ if (t.menu && t.menu.isMenuVisible) {
+ DOM.removeClass(t.id, t.classPrefix + 'Selected');
+
+ // Prevent double toogles by canceling the mouse click event to the button
+ if (e && e.type == "mousedown" && (e.target.id == t.id + '_text' || e.target.id == t.id + '_open'))
+ return;
+
+ if (!e || !DOM.getParent(e.target, '.mceMenu')) {
+ DOM.removeClass(t.id, t.classPrefix + 'Selected');
+ Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);
+ t.menu.hideMenu();
+ }
+ }
+ },
+
+ renderMenu : function() {
+ var t = this, m;
+
+ m = t.settings.control_manager.createDropMenu(t.id + '_menu', {
+ menu_line : 1,
+ 'class' : t.classPrefix + 'Menu mceNoIcons',
+ max_width : 250,
+ max_height : 150
+ });
+
+ m.onHideMenu.add(function() {
+ t.hideMenu();
+ t.focus();
+ });
+
+ m.add({
+ title : t.settings.title,
+ 'class' : 'mceMenuItemTitle',
+ onclick : function() {
+ if (t.settings.onselect('') !== false)
+ t.select(''); // Must be runned after
+ }
+ });
+
+ each(t.items, function(o) {
+ // No value then treat it as a title
+ if (o.value === undef) {
+ m.add({
+ title : o.title,
+ role : "option",
+ 'class' : 'mceMenuItemTitle',
+ onclick : function() {
+ if (t.settings.onselect('') !== false)
+ t.select(''); // Must be runned after
+ }
+ });
+ } else {
+ o.id = DOM.uniqueId();
+ o.role= "option";
+ o.onclick = function() {
+ if (t.settings.onselect(o.value) !== false)
+ t.select(o.value); // Must be runned after
+ };
+
+ m.add(o);
+ }
+ });
+
+ t.onRenderMenu.dispatch(t, m);
+ t.menu = m;
+ },
+
+ postRender : function() {
+ var t = this, cp = t.classPrefix;
+
+ Event.add(t.id, 'click', t.showMenu, t);
+ Event.add(t.id, 'keydown', function(evt) {
+ if (evt.keyCode == 32) { // Space
+ t.showMenu(evt);
+ Event.cancel(evt);
+ }
+ });
+ Event.add(t.id, 'focus', function() {
+ if (!t._focused) {
+ t.keyDownHandler = Event.add(t.id, 'keydown', function(e) {
+ if (e.keyCode == 40) {
+ t.showMenu();
+ Event.cancel(e);
+ }
+ });
+ t.keyPressHandler = Event.add(t.id, 'keypress', function(e) {
+ var v;
+ if (e.keyCode == 13) {
+ // Fake select on enter
+ v = t.selectedValue;
+ t.selectedValue = null; // Needs to be null to fake change
+ Event.cancel(e);
+ t.settings.onselect(v);
+ }
+ });
+ }
+
+ t._focused = 1;
+ });
+ Event.add(t.id, 'blur', function() {
+ Event.remove(t.id, 'keydown', t.keyDownHandler);
+ Event.remove(t.id, 'keypress', t.keyPressHandler);
+ t._focused = 0;
+ });
+
+ // Old IE doesn't have hover on all elements
+ if (tinymce.isIE6 || !DOM.boxModel) {
+ Event.add(t.id, 'mouseover', function() {
+ if (!DOM.hasClass(t.id, cp + 'Disabled'))
+ DOM.addClass(t.id, cp + 'Hover');
+ });
+
+ Event.add(t.id, 'mouseout', function() {
+ if (!DOM.hasClass(t.id, cp + 'Disabled'))
+ DOM.removeClass(t.id, cp + 'Hover');
+ });
+ }
+
+ t.onPostRender.dispatch(t, DOM.get(t.id));
+ },
+
+ destroy : function() {
+ this.parent();
+
+ Event.clear(this.id + '_text');
+ Event.clear(this.id + '_open');
+ }
+ });
+})(tinymce);
+
+(function(tinymce) {
+ var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher, undef;
+
+ tinymce.create('tinymce.ui.NativeListBox:tinymce.ui.ListBox', {
+ NativeListBox : function(id, s) {
+ this.parent(id, s);
+ this.classPrefix = 'mceNativeListBox';
+ },
+
+ setDisabled : function(s) {
+ DOM.get(this.id).disabled = s;
+ this.setAriaProperty('disabled', s);
+ },
+
+ isDisabled : function() {
+ return DOM.get(this.id).disabled;
+ },
+
+ select : function(va) {
+ var t = this, fv, f;
+
+ if (va == undef)
+ return t.selectByIndex(-1);
+
+ // Is string or number make function selector
+ if (va && typeof(va)=="function")
+ f = va;
+ else {
+ f = function(v) {
+ return v == va;
+ };
+ }
+
+ // Do we need to do something?
+ if (va != t.selectedValue) {
+ // Find item
+ each(t.items, function(o, i) {
+ if (f(o.value)) {
+ fv = 1;
+ t.selectByIndex(i);
+ return false;
+ }
+ });
+
+ if (!fv)
+ t.selectByIndex(-1);
+ }
+ },
+
+ selectByIndex : function(idx) {
+ DOM.get(this.id).selectedIndex = idx + 1;
+ this.selectedValue = this.items[idx] ? this.items[idx].value : null;
+ },
+
+ add : function(n, v, a) {
+ var o, t = this;
+
+ a = a || {};
+ a.value = v;
+
+ if (t.isRendered())
+ DOM.add(DOM.get(this.id), 'option', a, n);
+
+ o = {
+ title : n,
+ value : v,
+ attribs : a
+ };
+
+ t.items.push(o);
+ t.onAdd.dispatch(t, o);
+ },
+
+ getLength : function() {
+ return this.items.length;
+ },
+
+ renderHTML : function() {
+ var h, t = this;
+
+ h = DOM.createHTML('option', {value : ''}, '-- ' + t.settings.title + ' --');
+
+ each(t.items, function(it) {
+ h += DOM.createHTML('option', {value : it.value}, it.title);
+ });
+
+ h = DOM.createHTML('select', {id : t.id, 'class' : 'mceNativeListBox', 'aria-labelledby': t.id + '_aria'}, h);
+ h += DOM.createHTML('span', {id : t.id + '_aria', 'style': 'display: none'}, t.settings.title);
+ return h;
+ },
+
+ postRender : function() {
+ var t = this, ch, changeListenerAdded = true;
+
+ t.rendered = true;
+
+ function onChange(e) {
+ var v = t.items[e.target.selectedIndex - 1];
+
+ if (v && (v = v.value)) {
+ t.onChange.dispatch(t, v);
+
+ if (t.settings.onselect)
+ t.settings.onselect(v);
+ }
+ };
+
+ Event.add(t.id, 'change', onChange);
+
+ // Accessibility keyhandler
+ Event.add(t.id, 'keydown', function(e) {
+ var bf;
+
+ Event.remove(t.id, 'change', ch);
+ changeListenerAdded = false;
+
+ bf = Event.add(t.id, 'blur', function() {
+ if (changeListenerAdded) return;
+ changeListenerAdded = true;
+ Event.add(t.id, 'change', onChange);
+ Event.remove(t.id, 'blur', bf);
+ });
+
+ //prevent default left and right keys on chrome - so that the keyboard navigation is used.
+ if (tinymce.isWebKit && (e.keyCode==37 ||e.keyCode==39)) {
+ return Event.prevent(e);
+ }
+
+ if (e.keyCode == 13 || e.keyCode == 32) {
+ onChange(e);
+ return Event.cancel(e);
+ }
+ });
+
+ t.onPostRender.dispatch(t, DOM.get(t.id));
+ }
+ });
+})(tinymce);
+
+(function(tinymce) {
+ var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each;
+
+ tinymce.create('tinymce.ui.MenuButton:tinymce.ui.Button', {
+ MenuButton : function(id, s, ed) {
+ this.parent(id, s, ed);
+
+ this.onRenderMenu = new tinymce.util.Dispatcher(this);
+
+ s.menu_container = s.menu_container || DOM.doc.body;
+ },
+
+ showMenu : function() {
+ var t = this, p1, p2, e = DOM.get(t.id), m;
+
+ if (t.isDisabled())
+ return;
+
+ if (!t.isMenuRendered) {
+ t.renderMenu();
+ t.isMenuRendered = true;
+ }
+
+ if (t.isMenuVisible)
+ return t.hideMenu();
+
+ p1 = DOM.getPos(t.settings.menu_container);
+ p2 = DOM.getPos(e);
+
+ m = t.menu;
+ m.settings.offset_x = p2.x;
+ m.settings.offset_y = p2.y;
+ m.settings.vp_offset_x = p2.x;
+ m.settings.vp_offset_y = p2.y;
+ m.settings.keyboard_focus = t._focused;
+ m.showMenu(0, e.firstChild.clientHeight);
+
+ Event.add(DOM.doc, 'mousedown', t.hideMenu, t);
+ t.setState('Selected', 1);
+
+ t.isMenuVisible = 1;
+ },
+
+ renderMenu : function() {
+ var t = this, m;
+
+ m = t.settings.control_manager.createDropMenu(t.id + '_menu', {
+ menu_line : 1,
+ 'class' : this.classPrefix + 'Menu',
+ icons : t.settings.icons
+ });
+
+ m.onHideMenu.add(function() {
+ t.hideMenu();
+ t.focus();
+ });
+
+ t.onRenderMenu.dispatch(t, m);
+ t.menu = m;
+ },
+
+ hideMenu : function(e) {
+ var t = this;
+
+ // Prevent double toogles by canceling the mouse click event to the button
+ if (e && e.type == "mousedown" && DOM.getParent(e.target, function(e) {return e.id === t.id || e.id === t.id + '_open';}))
+ return;
+
+ if (!e || !DOM.getParent(e.target, '.mceMenu')) {
+ t.setState('Selected', 0);
+ Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);
+ if (t.menu)
+ t.menu.hideMenu();
+ }
+
+ t.isMenuVisible = 0;
+ },
+
+ postRender : function() {
+ var t = this, s = t.settings;
+
+ Event.add(t.id, 'click', function() {
+ if (!t.isDisabled()) {
+ if (s.onclick)
+ s.onclick(t.value);
+
+ t.showMenu();
+ }
+ });
+ }
+ });
+})(tinymce);
+
+(function(tinymce) {
+ var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each;
+
+ tinymce.create('tinymce.ui.SplitButton:tinymce.ui.MenuButton', {
+ SplitButton : function(id, s, ed) {
+ this.parent(id, s, ed);
+ this.classPrefix = 'mceSplitButton';
+ },
+
+ renderHTML : function() {
+ var h, t = this, s = t.settings, h1;
+
+ h = '<tbody><tr>';
+
+ if (s.image)
+ h1 = DOM.createHTML('img ', {src : s.image, role: 'presentation', 'class' : 'mceAction ' + s['class']});
+ else
+ h1 = DOM.createHTML('span', {'class' : 'mceAction ' + s['class']}, '');
+
+ h1 += DOM.createHTML('span', {'class': 'mceVoiceLabel mceIconOnly', id: t.id + '_voice', style: 'display:none;'}, s.title);
+ h += '<td >' + DOM.createHTML('a', {role: 'button', id : t.id + '_action', tabindex: '-1', href : 'javascript:;', 'class' : 'mceAction ' + s['class'], onclick : "return false;", onmousedown : 'return false;', title : s.title}, h1) + '</td>';
+
+ h1 = DOM.createHTML('span', {'class' : 'mceOpen ' + s['class']}, '<span style="display:none;" class="mceIconOnly" aria-hidden="true">\u25BC</span>');
+ h += '<td >' + DOM.createHTML('a', {role: 'button', id : t.id + '_open', tabindex: '-1', href : 'javascript:;', 'class' : 'mceOpen ' + s['class'], onclick : "return false;", onmousedown : 'return false;', title : s.title}, h1) + '</td>';
+
+ h += '</tr></tbody>';
+ h = DOM.createHTML('table', { role: 'presentation', 'class' : 'mceSplitButton mceSplitButtonEnabled ' + s['class'], cellpadding : '0', cellspacing : '0', title : s.title}, h);
+ return DOM.createHTML('div', {id : t.id, role: 'button', tabindex: '0', 'aria-labelledby': t.id + '_voice', 'aria-haspopup': 'true'}, h);
+ },
+
+ postRender : function() {
+ var t = this, s = t.settings, activate;
+
+ if (s.onclick) {
+ activate = function(evt) {
+ if (!t.isDisabled()) {
+ s.onclick(t.value);
+ Event.cancel(evt);
+ }
+ };
+ Event.add(t.id + '_action', 'click', activate);
+ Event.add(t.id, ['click', 'keydown'], function(evt) {
+ var DOM_VK_SPACE = 32, DOM_VK_ENTER = 14, DOM_VK_RETURN = 13, DOM_VK_UP = 38, DOM_VK_DOWN = 40;
+ if ((evt.keyCode === 32 || evt.keyCode === 13 || evt.keyCode === 14) && !evt.altKey && !evt.ctrlKey && !evt.metaKey) {
+ activate();
+ Event.cancel(evt);
+ } else if (evt.type === 'click' || evt.keyCode === DOM_VK_DOWN) {
+ t.showMenu();
+ Event.cancel(evt);
+ }
+ });
+ }
+
+ Event.add(t.id + '_open', 'click', function (evt) {
+ t.showMenu();
+ Event.cancel(evt);
+ });
+ Event.add([t.id, t.id + '_open'], 'focus', function() {t._focused = 1;});
+ Event.add([t.id, t.id + '_open'], 'blur', function() {t._focused = 0;});
+
+ // Old IE doesn't have hover on all elements
+ if (tinymce.isIE6 || !DOM.boxModel) {
+ Event.add(t.id, 'mouseover', function() {
+ if (!DOM.hasClass(t.id, 'mceSplitButtonDisabled'))
+ DOM.addClass(t.id, 'mceSplitButtonHover');
+ });
+
+ Event.add(t.id, 'mouseout', function() {
+ if (!DOM.hasClass(t.id, 'mceSplitButtonDisabled'))
+ DOM.removeClass(t.id, 'mceSplitButtonHover');
+ });
+ }
+ },
+
+ destroy : function() {
+ this.parent();
+
+ Event.clear(this.id + '_action');
+ Event.clear(this.id + '_open');
+ Event.clear(this.id);
+ }
+ });
+})(tinymce);
+
+(function(tinymce) {
+ var DOM = tinymce.DOM, Event = tinymce.dom.Event, is = tinymce.is, each = tinymce.each;
+
+ tinymce.create('tinymce.ui.ColorSplitButton:tinymce.ui.SplitButton', {
+ ColorSplitButton : function(id, s, ed) {
+ var t = this;
+
+ t.parent(id, s, ed);
+
+ t.settings = s = tinymce.extend({
+ colors : '000000,993300,333300,003300,003366,000080,333399,333333,800000,FF6600,808000,008000,008080,0000FF,666699,808080,FF0000,FF9900,99CC00,339966,33CCCC,3366FF,800080,999999,FF00FF,FFCC00,FFFF00,00FF00,00FFFF,00CCFF,993366,C0C0C0,FF99CC,FFCC99,FFFF99,CCFFCC,CCFFFF,99CCFF,CC99FF,FFFFFF',
+ grid_width : 8,
+ default_color : '#888888'
+ }, t.settings);
+
+ t.onShowMenu = new tinymce.util.Dispatcher(t);
+
+ t.onHideMenu = new tinymce.util.Dispatcher(t);
+
+ t.value = s.default_color;
+ },
+
+ showMenu : function() {
+ var t = this, r, p, e, p2;
+
+ if (t.isDisabled())
+ return;
+
+ if (!t.isMenuRendered) {
+ t.renderMenu();
+ t.isMenuRendered = true;
+ }
+
+ if (t.isMenuVisible)
+ return t.hideMenu();
+
+ e = DOM.get(t.id);
+ DOM.show(t.id + '_menu');
+ DOM.addClass(e, 'mceSplitButtonSelected');
+ p2 = DOM.getPos(e);
+ DOM.setStyles(t.id + '_menu', {
+ left : p2.x,
+ top : p2.y + e.firstChild.clientHeight,
+ zIndex : 200000
+ });
+ e = 0;
+
+ Event.add(DOM.doc, 'mousedown', t.hideMenu, t);
+ t.onShowMenu.dispatch(t);
+
+ if (t._focused) {
+ t._keyHandler = Event.add(t.id + '_menu', 'keydown', function(e) {
+ if (e.keyCode == 27)
+ t.hideMenu();
+ });
+
+ DOM.select('a', t.id + '_menu')[0].focus(); // Select first link
+ }
+
+ t.keyboardNav = new tinymce.ui.KeyboardNavigation({
+ root: t.id + '_menu',
+ items: DOM.select('a', t.id + '_menu'),
+ onCancel: function() {
+ t.hideMenu();
+ t.focus();
+ }
+ });
+
+ t.keyboardNav.focus();
+ t.isMenuVisible = 1;
+ },
+
+ hideMenu : function(e) {
+ var t = this;
+
+ if (t.isMenuVisible) {
+ // Prevent double toogles by canceling the mouse click event to the button
+ if (e && e.type == "mousedown" && DOM.getParent(e.target, function(e) {return e.id === t.id + '_open';}))
+ return;
+
+ if (!e || !DOM.getParent(e.target, '.mceSplitButtonMenu')) {
+ DOM.removeClass(t.id, 'mceSplitButtonSelected');
+ Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);
+ Event.remove(t.id + '_menu', 'keydown', t._keyHandler);
+ DOM.hide(t.id + '_menu');
+ }
+
+ t.isMenuVisible = 0;
+ t.onHideMenu.dispatch();
+ t.keyboardNav.destroy();
+ }
+ },
+
+ renderMenu : function() {
+ var t = this, m, i = 0, s = t.settings, n, tb, tr, w, context;
+
+ w = DOM.add(s.menu_container, 'div', {role: 'listbox', id : t.id + '_menu', 'class' : s.menu_class + ' ' + s['class'], style : 'position:absolute;left:0;top:-1000px;'});
+ m = DOM.add(w, 'div', {'class' : s['class'] + ' mceSplitButtonMenu'});
+ DOM.add(m, 'span', {'class' : 'mceMenuLine'});
+
+ n = DOM.add(m, 'table', {role: 'presentation', 'class' : 'mceColorSplitMenu'});
+ tb = DOM.add(n, 'tbody');
+
+ // Generate color grid
+ i = 0;
+ each(is(s.colors, 'array') ? s.colors : s.colors.split(','), function(c) {
+ c = c.replace(/^#/, '');
+
+ if (!i--) {
+ tr = DOM.add(tb, 'tr');
+ i = s.grid_width - 1;
+ }
+
+ n = DOM.add(tr, 'td');
+ var settings = {
+ href : 'javascript:;',
+ style : {
+ backgroundColor : '#' + c
+ },
+ 'title': t.editor.getLang('colors.' + c, c),
+ 'data-mce-color' : '#' + c
+ };
+
+ // adding a proper ARIA role = button causes JAWS to read things incorrectly on IE.
+ if (!tinymce.isIE ) {
+ settings.role = 'option';
+ }
+
+ n = DOM.add(n, 'a', settings);
+
+ if (t.editor.forcedHighContrastMode) {
+ n = DOM.add(n, 'canvas', { width: 16, height: 16, 'aria-hidden': 'true' });
+ if (n.getContext && (context = n.getContext("2d"))) {
+ context.fillStyle = '#' + c;
+ context.fillRect(0, 0, 16, 16);
+ } else {
+ // No point leaving a canvas element around if it's not supported for drawing on anyway.
+ DOM.remove(n);
+ }
+ }
+ });
+
+ if (s.more_colors_func) {
+ n = DOM.add(tb, 'tr');
+ n = DOM.add(n, 'td', {colspan : s.grid_width, 'class' : 'mceMoreColors'});
+ n = DOM.add(n, 'a', {role: 'option', id : t.id + '_more', href : 'javascript:;', onclick : 'return false;', 'class' : 'mceMoreColors'}, s.more_colors_title);
+
+ Event.add(n, 'click', function(e) {
+ s.more_colors_func.call(s.more_colors_scope || this);
+ return Event.cancel(e); // Cancel to fix onbeforeunload problem
+ });
+ }
+
+ DOM.addClass(m, 'mceColorSplitMenu');
+
+ // Prevent IE from scrolling and hindering click to occur #4019
+ Event.add(t.id + '_menu', 'mousedown', function(e) {return Event.cancel(e);});
+
+ Event.add(t.id + '_menu', 'click', function(e) {
+ var c;
+
+ e = DOM.getParent(e.target, 'a', tb);
+
+ if (e && e.nodeName.toLowerCase() == 'a' && (c = e.getAttribute('data-mce-color')))
+ t.setColor(c);
+
+ return false; // Prevent IE auto save warning
+ });
+
+ return w;
+ },
+
+ setColor : function(c) {
+ this.displayColor(c);
+ this.hideMenu();
+ this.settings.onselect(c);
+ },
+
+ displayColor : function(c) {
+ var t = this;
+
+ DOM.setStyle(t.id + '_preview', 'backgroundColor', c);
+
+ t.value = c;
+ },
+
+ postRender : function() {
+ var t = this, id = t.id;
+
+ t.parent();
+ DOM.add(id + '_action', 'div', {id : id + '_preview', 'class' : 'mceColorPreview'});
+ DOM.setStyle(t.id + '_preview', 'backgroundColor', t.value);
+ },
+
+ destroy : function() {
+ var self = this;
+
+ self.parent();
+
+ Event.clear(self.id + '_menu');
+ Event.clear(self.id + '_more');
+ DOM.remove(self.id + '_menu');
+
+ if (self.keyboardNav) {
+ self.keyboardNav.destroy();
+ }
+ }
+ });
+})(tinymce);
+
+(function(tinymce) {
+// Shorten class names
+var dom = tinymce.DOM, each = tinymce.each, Event = tinymce.dom.Event;
+tinymce.create('tinymce.ui.ToolbarGroup:tinymce.ui.Container', {
+ renderHTML : function() {
+ var t = this, h = [], controls = t.controls, each = tinymce.each, settings = t.settings;
+
+ h.push('<div id="' + t.id + '" role="group" aria-labelledby="' + t.id + '_voice">');
+ //TODO: ACC test this out - adding a role = application for getting the landmarks working well.
+ h.push("<span role='application'>");
+ h.push('<span id="' + t.id + '_voice" class="mceVoiceLabel" style="display:none;">' + dom.encode(settings.name) + '</span>');
+ each(controls, function(toolbar) {
+ h.push(toolbar.renderHTML());
+ });
+ h.push("</span>");
+ h.push('</div>');
+
+ return h.join('');
+ },
+
+ focus : function() {
+ var t = this;
+ dom.get(t.id).focus();
+ },
+
+ postRender : function() {
+ var t = this, items = [];
+
+ each(t.controls, function(toolbar) {
+ each (toolbar.controls, function(control) {
+ if (control.id) {
+ items.push(control);
+ }
+ });
+ });
+
+ t.keyNav = new tinymce.ui.KeyboardNavigation({
+ root: t.id,
+ items: items,
+ onCancel: function() {
+ //Move focus if webkit so that navigation back will read the item.
+ if (tinymce.isWebKit) {
+ dom.get(t.editor.id+"_ifr").focus();
+ }
+ t.editor.focus();
+ },
+ excludeFromTabOrder: !t.settings.tab_focus_toolbar
+ });
+ },
+
+ destroy : function() {
+ var self = this;
+
+ self.parent();
+ self.keyNav.destroy();
+ Event.clear(self.id);
+ }
+});
+})(tinymce);
+
+(function(tinymce) {
+// Shorten class names
+var dom = tinymce.DOM, each = tinymce.each;
+tinymce.create('tinymce.ui.Toolbar:tinymce.ui.Container', {
+ renderHTML : function() {
+ var t = this, h = '', c, co, s = t.settings, i, pr, nx, cl;
+
+ cl = t.controls;
+ for (i=0; i<cl.length; i++) {
+ // Get current control, prev control, next control and if the control is a list box or not
+ co = cl[i];
+ pr = cl[i - 1];
+ nx = cl[i + 1];
+
+ // Add toolbar start
+ if (i === 0) {
+ c = 'mceToolbarStart';
+
+ if (co.Button)
+ c += ' mceToolbarStartButton';
+ else if (co.SplitButton)
+ c += ' mceToolbarStartSplitButton';
+ else if (co.ListBox)
+ c += ' mceToolbarStartListBox';
+
+ h += dom.createHTML('td', {'class' : c}, dom.createHTML('span', null, '<!-- IE -->'));
+ }
+
+ // Add toolbar end before list box and after the previous button
+ // This is to fix the o2k7 editor skins
+ if (pr && co.ListBox) {
+ if (pr.Button || pr.SplitButton)
+ h += dom.createHTML('td', {'class' : 'mceToolbarEnd'}, dom.createHTML('span', null, '<!-- IE -->'));
+ }
+
+ // Render control HTML
+
+ // IE 8 quick fix, needed to propertly generate a hit area for anchors
+ if (dom.stdMode)
+ h += '<td style="position: relative">' + co.renderHTML() + '</td>';
+ else
+ h += '<td>' + co.renderHTML() + '</td>';
+
+ // Add toolbar start after list box and before the next button
+ // This is to fix the o2k7 editor skins
+ if (nx && co.ListBox) {
+ if (nx.Button || nx.SplitButton)
+ h += dom.createHTML('td', {'class' : 'mceToolbarStart'}, dom.createHTML('span', null, '<!-- IE -->'));
+ }
+ }
+
+ c = 'mceToolbarEnd';
+
+ if (co.Button)
+ c += ' mceToolbarEndButton';
+ else if (co.SplitButton)
+ c += ' mceToolbarEndSplitButton';
+ else if (co.ListBox)
+ c += ' mceToolbarEndListBox';
+
+ h += dom.createHTML('td', {'class' : c}, dom.createHTML('span', null, '<!-- IE -->'));
+
+ return dom.createHTML('table', {id : t.id, 'class' : 'mceToolbar' + (s['class'] ? ' ' + s['class'] : ''), cellpadding : '0', cellspacing : '0', align : t.settings.align || '', role: 'presentation', tabindex: '-1'}, '<tbody><tr>' + h + '</tr></tbody>');
+ }
+});
+})(tinymce);
+
+(function(tinymce) {
+ var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each;
+
+ tinymce.create('tinymce.AddOnManager', {
+ AddOnManager : function() {
+ var self = this;
+
+ self.items = [];
+ self.urls = {};
+ self.lookup = {};
+ self.onAdd = new Dispatcher(self);
+ },
+
+ get : function(n) {
+ if (this.lookup[n]) {
+ return this.lookup[n].instance;
+ } else {
+ return undefined;
+ }
+ },
+
+ dependencies : function(n) {
+ var result;
+ if (this.lookup[n]) {
+ result = this.lookup[n].dependencies;
+ }
+ return result || [];
+ },
+
+ requireLangPack : function(n) {
+ var s = tinymce.settings;
+
+ if (s && s.language && s.language_load !== false)
+ tinymce.ScriptLoader.add(this.urls[n] + '/langs/' + s.language + '.js');
+ },
+
+ add : function(id, o, dependencies) {
+ this.items.push(o);
+ this.lookup[id] = {instance:o, dependencies:dependencies};
+ this.onAdd.dispatch(this, id, o);
+
+ return o;
+ },
+ createUrl: function(baseUrl, dep) {
+ if (typeof dep === "object") {
+ return dep
+ } else {
+ return {prefix: baseUrl.prefix, resource: dep, suffix: baseUrl.suffix};
+ }
+ },
+
+ addComponents: function(pluginName, scripts) {
+ var pluginUrl = this.urls[pluginName];
+ tinymce.each(scripts, function(script){
+ tinymce.ScriptLoader.add(pluginUrl+"/"+script);
+ });
+ },
+
+ load : function(n, u, cb, s) {
+ var t = this, url = u;
+
+ function loadDependencies() {
+ var dependencies = t.dependencies(n);
+ tinymce.each(dependencies, function(dep) {
+ var newUrl = t.createUrl(u, dep);
+ t.load(newUrl.resource, newUrl, undefined, undefined);
+ });
+ if (cb) {
+ if (s) {
+ cb.call(s);
+ } else {
+ cb.call(tinymce.ScriptLoader);
+ }
+ }
+ }
+
+ if (t.urls[n])
+ return;
+ if (typeof u === "object")
+ url = u.prefix + u.resource + u.suffix;
+
+ if (url.indexOf('/') !== 0 && url.indexOf('://') == -1)
+ url = tinymce.baseURL + '/' + url;
+
+ t.urls[n] = url.substring(0, url.lastIndexOf('/'));
+
+ if (t.lookup[n]) {
+ loadDependencies();
+ } else {
+ tinymce.ScriptLoader.add(url, loadDependencies, s);
+ }
+ }
+ });
+
+ // Create plugin and theme managers
+ tinymce.PluginManager = new tinymce.AddOnManager();
+ tinymce.ThemeManager = new tinymce.AddOnManager();
+}(tinymce));
+
+(function(tinymce) {
+ // Shorten names
+ var each = tinymce.each, extend = tinymce.extend,
+ DOM = tinymce.DOM, Event = tinymce.dom.Event,
+ ThemeManager = tinymce.ThemeManager, PluginManager = tinymce.PluginManager,
+ explode = tinymce.explode,
+ Dispatcher = tinymce.util.Dispatcher, undef, instanceCounter = 0;
+
+ // Setup some URLs where the editor API is located and where the document is
+ tinymce.documentBaseURL = window.location.href.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
+ if (!/[\/\\]$/.test(tinymce.documentBaseURL))
+ tinymce.documentBaseURL += '/';
+
+ tinymce.baseURL = new tinymce.util.URI(tinymce.documentBaseURL).toAbsolute(tinymce.baseURL);
+
+ tinymce.baseURI = new tinymce.util.URI(tinymce.baseURL);
+
+ // Add before unload listener
+ // This was required since IE was leaking memory if you added and removed beforeunload listeners
+ // with attachEvent/detatchEvent so this only adds one listener and instances can the attach to the onBeforeUnload event
+ tinymce.onBeforeUnload = new Dispatcher(tinymce);
+
+ // Must be on window or IE will leak if the editor is placed in frame or iframe
+ Event.add(window, 'beforeunload', function(e) {
+ tinymce.onBeforeUnload.dispatch(tinymce, e);
+ });
+
+ tinymce.onAddEditor = new Dispatcher(tinymce);
+
+ tinymce.onRemoveEditor = new Dispatcher(tinymce);
+
+ tinymce.EditorManager = extend(tinymce, {
+ editors : [],
+
+ i18n : {},
+
+ activeEditor : null,
+
+ init : function(s) {
+ var t = this, pl, sl = tinymce.ScriptLoader, e, el = [], ed;
+
+ function createId(elm) {
+ var id = elm.id;
+
+ // Use element id, or unique name or generate a unique id
+ if (!id) {
+ id = elm.name;
+
+ if (id && !DOM.get(id)) {
+ id = elm.name;
+ } else {
+ // Generate unique name
+ id = DOM.uniqueId();
+ }
+
+ elm.setAttribute('id', id);
+ }
+
+ return id;
+ };
+
+ function execCallback(se, n, s) {
+ var f = se[n];
+
+ if (!f)
+ return;
+
+ if (tinymce.is(f, 'string')) {
+ s = f.replace(/\.\w+$/, '');
+ s = s ? tinymce.resolve(s) : 0;
+ f = tinymce.resolve(f);
+ }
+
+ return f.apply(s || this, Array.prototype.slice.call(arguments, 2));
+ };
+
+ function hasClass(n, c) {
+ return c.constructor === RegExp ? c.test(n.className) : DOM.hasClass(n, c);
+ };
+
+ t.settings = s;
+
+ // Legacy call
+ Event.bind(window, 'ready', function() {
+ var l, co;
+
+ execCallback(s, 'onpageload');
+
+ switch (s.mode) {
+ case "exact":
+ l = s.elements || '';
+
+ if(l.length > 0) {
+ each(explode(l), function(v) {
+ if (DOM.get(v)) {
+ ed = new tinymce.Editor(v, s);
+ el.push(ed);
+ ed.render(1);
+ } else {
+ each(document.forms, function(f) {
+ each(f.elements, function(e) {
+ if (e.name === v) {
+ v = 'mce_editor_' + instanceCounter++;
+ DOM.setAttrib(e, 'id', v);
+
+ ed = new tinymce.Editor(v, s);
+ el.push(ed);
+ ed.render(1);
+ }
+ });
+ });
+ }
+ });
+ }
+ break;
+
+ case "textareas":
+ case "specific_textareas":
+ each(DOM.select('textarea'), function(elm) {
+ if (s.editor_deselector && hasClass(elm, s.editor_deselector))
+ return;
+
+ if (!s.editor_selector || hasClass(elm, s.editor_selector)) {
+ ed = new tinymce.Editor(createId(elm), s);
+ el.push(ed);
+ ed.render(1);
+ }
+ });
+ break;
+
+ default:
+ if (s.types) {
+ // Process type specific selector
+ each(s.types, function(type) {
+ each(DOM.select(type.selector), function(elm) {
+ var editor = new tinymce.Editor(createId(elm), tinymce.extend({}, s, type));
+ el.push(editor);
+ editor.render(1);
+ });
+ });
+ } else if (s.selector) {
+ // Process global selector
+ each(DOM.select(s.selector), function(elm) {
+ var editor = new tinymce.Editor(createId(elm), s);
+ el.push(editor);
+ editor.render(1);
+ });
+ }
+ }
+
+ // Call onInit when all editors are initialized
+ if (s.oninit) {
+ l = co = 0;
+
+ each(el, function(ed) {
+ co++;
+
+ if (!ed.initialized) {
+ // Wait for it
+ ed.onInit.add(function() {
+ l++;
+
+ // All done
+ if (l == co)
+ execCallback(s, 'oninit');
+ });
+ } else
+ l++;
+
+ // All done
+ if (l == co)
+ execCallback(s, 'oninit');
+ });
+ }
+ });
+ },
+
+ get : function(id) {
+ if (id === undef)
+ return this.editors;
+
+ return this.editors[id];
+ },
+
+ getInstanceById : function(id) {
+ return this.get(id);
+ },
+
+ add : function(editor) {
+ var self = this, editors = self.editors;
+
+ // Add named and index editor instance
+ editors[editor.id] = editor;
+ editors.push(editor);
+
+ self._setActive(editor);
+ self.onAddEditor.dispatch(self, editor);
+
+
+ return editor;
+ },
+
+ remove : function(editor) {
+ var t = this, i, editors = t.editors;
+
+ // Not in the collection
+ if (!editors[editor.id])
+ return null;
+
+ delete editors[editor.id];
+
+ for (i = 0; i < editors.length; i++) {
+ if (editors[i] == editor) {
+ editors.splice(i, 1);
+ break;
+ }
+ }
+
+ // Select another editor since the active one was removed
+ if (t.activeEditor == editor)
+ t._setActive(editors[0]);
+
+ editor.destroy();
+ t.onRemoveEditor.dispatch(t, editor);
+
+ return editor;
+ },
+
+ execCommand : function(c, u, v) {
+ var t = this, ed = t.get(v), w;
+
+ function clr() {
+ ed.destroy();
+ w.detachEvent('onunload', clr);
+ w = w.tinyMCE = w.tinymce = null; // IE leak
+ };
+
+ // Manager commands
+ switch (c) {
+ case "mceFocus":
+ ed.focus();
+ return true;
+
+ case "mceAddEditor":
+ case "mceAddControl":
+ if (!t.get(v))
+ new tinymce.Editor(v, t.settings).render();
+
+ return true;
+
+ case "mceAddFrameControl":
+ w = v.window;
+
+ // Add tinyMCE global instance and tinymce namespace to specified window
+ w.tinyMCE = tinyMCE;
+ w.tinymce = tinymce;
+
+ tinymce.DOM.doc = w.document;
+ tinymce.DOM.win = w;
+
+ ed = new tinymce.Editor(v.element_id, v);
+ ed.render();
+
+ // Fix IE memory leaks
+ if (tinymce.isIE) {
+ w.attachEvent('onunload', clr);
+ }
+
+ v.page_window = null;
+
+ return true;
+
+ case "mceRemoveEditor":
+ case "mceRemoveControl":
+ if (ed)
+ ed.remove();
+
+ return true;
+
+ case 'mceToggleEditor':
+ if (!ed) {
+ t.execCommand('mceAddControl', 0, v);
+ return true;
+ }
+
+ if (ed.isHidden())
+ ed.show();
+ else
+ ed.hide();
+
+ return true;
+ }
+
+ // Run command on active editor
+ if (t.activeEditor)
+ return t.activeEditor.execCommand(c, u, v);
+
+ return false;
+ },
+
+ execInstanceCommand : function(id, c, u, v) {
+ var ed = this.get(id);
+
+ if (ed)
+ return ed.execCommand(c, u, v);
+
+ return false;
+ },
+
+ triggerSave : function() {
+ each(this.editors, function(e) {
+ e.save();
+ });
+ },
+
+ addI18n : function(p, o) {
+ var lo, i18n = this.i18n;
+
+ if (!tinymce.is(p, 'string')) {
+ each(p, function(o, lc) {
+ each(o, function(o, g) {
+ each(o, function(o, k) {
+ if (g === 'common')
+ i18n[lc + '.' + k] = o;
+ else
+ i18n[lc + '.' + g + '.' + k] = o;
+ });
+ });
+ });
+ } else {
+ each(o, function(o, k) {
+ i18n[p + '.' + k] = o;
+ });
+ }
+ },
+
+ // Private methods
+
+ _setActive : function(editor) {
+ this.selectedInstance = this.activeEditor = editor;
+ }
+ });
+})(tinymce);
+
+(function(tinymce) {
+ // Shorten these names
+ var DOM = tinymce.DOM, Event = tinymce.dom.Event, extend = tinymce.extend,
+ each = tinymce.each, isGecko = tinymce.isGecko,
+ isIE = tinymce.isIE, isWebKit = tinymce.isWebKit, is = tinymce.is,
+ ThemeManager = tinymce.ThemeManager, PluginManager = tinymce.PluginManager,
+ explode = tinymce.explode;
+
+ tinymce.create('tinymce.Editor', {
+ Editor : function(id, settings) {
+ var self = this, TRUE = true;
+
+ self.settings = settings = extend({
+ id : id,
+ language : 'en',
+ theme : 'advanced',
+ skin : 'default',
+ delta_width : 0,
+ delta_height : 0,
+ popup_css : '',
+ plugins : '',
+ document_base_url : tinymce.documentBaseURL,
+ add_form_submit_trigger : TRUE,
+ submit_patch : TRUE,
+ add_unload_trigger : TRUE,
+ convert_urls : TRUE,
+ relative_urls : TRUE,
+ remove_script_host : TRUE,
+ table_inline_editing : false,
+ object_resizing : TRUE,
+ accessibility_focus : TRUE,
+ doctype : tinymce.isIE6 ? '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">' : '<!DOCTYPE>', // Use old doctype on IE 6 to avoid horizontal scroll
+ visual : TRUE,
+ font_size_style_values : 'xx-small,x-small,small,medium,large,x-large,xx-large',
+ font_size_legacy_values : 'xx-small,small,medium,large,x-large,xx-large,300%', // See: http://www.w3.org/TR/CSS2/fonts.html#propdef-font-size
+ apply_source_formatting : TRUE,
+ directionality : 'ltr',
+ forced_root_block : 'p',
+ hidden_input : TRUE,
+ padd_empty_editor : TRUE,
+ render_ui : TRUE,
+ indentation : '30px',
+ fix_table_elements : TRUE,
+ inline_styles : TRUE,
+ convert_fonts_to_spans : TRUE,
+ indent : 'simple',
+ indent_before : 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,li,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure,option,optgroup,datalist',
+ indent_after : 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,li,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure,option,optgroup,datalist',
+ validate : TRUE,
+ entity_encoding : 'named',
+ url_converter : self.convertURL,
+ url_converter_scope : self,
+ ie7_compat : TRUE
+ }, settings);
+
+ self.id = self.editorId = id;
+
+ self.isNotDirty = false;
+
+ self.plugins = {};
+
+ self.documentBaseURI = new tinymce.util.URI(settings.document_base_url || tinymce.documentBaseURL, {
+ base_uri : tinyMCE.baseURI
+ });
+
+ self.baseURI = tinymce.baseURI;
+
+ self.contentCSS = [];
+
+ self.contentStyles = [];
+
+ // Creates all events like onClick, onSetContent etc see Editor.Events.js for the actual logic
+ self.setupEvents();
+
+ // Internal command handler objects
+ self.execCommands = {};
+ self.queryStateCommands = {};
+ self.queryValueCommands = {};
+
+ // Call setup
+ self.execCallback('setup', self);
+ },
+
+ render : function(nst) {
+ var t = this, s = t.settings, id = t.id, sl = tinymce.ScriptLoader;
+
+ // Page is not loaded yet, wait for it
+ if (!Event.domLoaded) {
+ Event.add(window, 'ready', function() {
+ t.render();
+ });
+ return;
+ }
+
+ tinyMCE.settings = s;
+
+ // Element not found, then skip initialization
+ if (!t.getElement())
+ return;
+
+ // Is a iPad/iPhone and not on iOS5, then skip initialization. We need to sniff
+ // here since the browser says it has contentEditable support but there is no visible caret.
+ if (tinymce.isIDevice && !tinymce.isIOS5)
+ return;
+
+ // Add hidden input for non input elements inside form elements
+ if (!/TEXTAREA|INPUT/i.test(t.getElement().nodeName) && s.hidden_input && DOM.getParent(id, 'form'))
+ DOM.insertAfter(DOM.create('input', {type : 'hidden', name : id}), id);
+
+ // Hide target element early to prevent content flashing
+ if (!s.content_editable) {
+ t.orgVisibility = t.getElement().style.visibility;
+ t.getElement().style.visibility = 'hidden';
+ }
+
+ if (tinymce.WindowManager)
+ t.windowManager = new tinymce.WindowManager(t);
+
+ if (s.encoding == 'xml') {
+ t.onGetContent.add(function(ed, o) {
+ if (o.save)
+ o.content = DOM.encode(o.content);
+ });
+ }
+
+ if (s.add_form_submit_trigger) {
+ t.onSubmit.addToTop(function() {
+ if (t.initialized) {
+ t.save();
+ t.isNotDirty = 1;
+ }
+ });
+ }
+
+ if (s.add_unload_trigger) {
+ t._beforeUnload = tinyMCE.onBeforeUnload.add(function() {
+ if (t.initialized && !t.destroyed && !t.isHidden())
+ t.save({format : 'raw', no_events : true});
+ });
+ }
+
+ tinymce.addUnload(t.destroy, t);
+
+ if (s.submit_patch) {
+ t.onBeforeRenderUI.add(function() {
+ var n = t.getElement().form;
+
+ if (!n)
+ return;
+
+ // Already patched
+ if (n._mceOldSubmit)
+ return;
+
+ // Check page uses id="submit" or name="submit" for it's submit button
+ if (!n.submit.nodeType && !n.submit.length) {
+ t.formElement = n;
+ n._mceOldSubmit = n.submit;
+ n.submit = function() {
+ // Save all instances
+ tinymce.triggerSave();
+ t.isNotDirty = 1;
+
+ return t.formElement._mceOldSubmit(t.formElement);
+ };
+ }
+
+ n = null;
+ });
+ }
+
+ // Load scripts
+ function loadScripts() {
+ if (s.language && s.language_load !== false)
+ sl.add(tinymce.baseURL + '/langs/' + s.language + '.js');
+
+ if (s.theme && typeof s.theme != "function" && s.theme.charAt(0) != '-' && !ThemeManager.urls[s.theme])
+ ThemeManager.load(s.theme, 'themes/' + s.theme + '/editor_template' + tinymce.suffix + '.js');
+
+ each(explode(s.plugins), function(p) {
+ if (p &&!PluginManager.urls[p]) {
+ if (p.charAt(0) == '-') {
+ p = p.substr(1, p.length);
+ var dependencies = PluginManager.dependencies(p);
+ each(dependencies, function(dep) {
+ var defaultSettings = {prefix:'plugins/', resource: dep, suffix:'/editor_plugin' + tinymce.suffix + '.js'};
+ dep = PluginManager.createUrl(defaultSettings, dep);
+ PluginManager.load(dep.resource, dep);
+ });
+ } else {
+ // Skip safari plugin, since it is removed as of 3.3b1
+ if (p == 'safari') {
+ return;
+ }
+ PluginManager.load(p, {prefix:'plugins/', resource: p, suffix:'/editor_plugin' + tinymce.suffix + '.js'});
+ }
+ }
+ });
+
+ // Init when que is loaded
+ sl.loadQueue(function() {
+ if (!t.removed)
+ t.init();
+ });
+ };
+
+ loadScripts();
+ },
+
+ init : function() {
+ var n, t = this, s = t.settings, w, h, mh, e = t.getElement(), o, ti, u, bi, bc, re, i, initializedPlugins = [];
+
+ tinymce.add(t);
+
+ s.aria_label = s.aria_label || DOM.getAttrib(e, 'aria-label', t.getLang('aria.rich_text_area'));
+
+ if (s.theme) {
+ if (typeof s.theme != "function") {
+ s.theme = s.theme.replace(/-/, '');
+ o = ThemeManager.get(s.theme);
+ t.theme = new o();
+
+ if (t.theme.init)
+ t.theme.init(t, ThemeManager.urls[s.theme] || tinymce.documentBaseURL.replace(/\/$/, ''));
+ } else {
+ t.theme = s.theme;
+ }
+ }
+
+ function initPlugin(p) {
+ var c = PluginManager.get(p), u = PluginManager.urls[p] || tinymce.documentBaseURL.replace(/\/$/, ''), po;
+ if (c && tinymce.inArray(initializedPlugins,p) === -1) {
+ each(PluginManager.dependencies(p), function(dep){
+ initPlugin(dep);
+ });
+ po = new c(t, u);
+
+ t.plugins[p] = po;
+
+ if (po.init) {
+ po.init(t, u);
+ initializedPlugins.push(p);
+ }
+ }
+ }
+
+ // Create all plugins
+ each(explode(s.plugins.replace(/\-/g, '')), initPlugin);
+
+ // Setup popup CSS path(s)
+ if (s.popup_css !== false) {
+ if (s.popup_css)
+ s.popup_css = t.documentBaseURI.toAbsolute(s.popup_css);
+ else
+ s.popup_css = t.baseURI.toAbsolute("themes/" + s.theme + "/skins/" + s.skin + "/dialog.css");
+ }
+
+ if (s.popup_css_add)
+ s.popup_css += ',' + t.documentBaseURI.toAbsolute(s.popup_css_add);
+
+ t.controlManager = new tinymce.ControlManager(t);
+
+ // Enables users to override the control factory
+ t.onBeforeRenderUI.dispatch(t, t.controlManager);
+
+ // Measure box
+ if (s.render_ui && t.theme) {
+ t.orgDisplay = e.style.display;
+
+ if (typeof s.theme != "function") {
+ w = s.width || e.style.width || e.offsetWidth;
+ h = s.height || e.style.height || e.offsetHeight;
+ mh = s.min_height || 100;
+ re = /^[0-9\.]+(|px)$/i;
+
+ if (re.test('' + w))
+ w = Math.max(parseInt(w, 10) + (o.deltaWidth || 0), 100);
+
+ if (re.test('' + h))
+ h = Math.max(parseInt(h, 10) + (o.deltaHeight || 0), mh);
+
+ // Render UI
+ o = t.theme.renderUI({
+ targetNode : e,
+ width : w,
+ height : h,
+ deltaWidth : s.delta_width,
+ deltaHeight : s.delta_height
+ });
+
+ // Resize editor
+ DOM.setStyles(o.sizeContainer || o.editorContainer, {
+ width : w,
+ height : h
+ });
+
+ h = (o.iframeHeight || h) + (typeof(h) == 'number' ? (o.deltaHeight || 0) : '');
+ if (h < mh)
+ h = mh;
+ } else {
+ o = s.theme(t, e);
+
+ // Convert element type to id:s
+ if (o.editorContainer.nodeType) {
+ o.editorContainer = o.editorContainer.id = o.editorContainer.id || t.id + "_parent";
+ }
+
+ // Convert element type to id:s
+ if (o.iframeContainer.nodeType) {
+ o.iframeContainer = o.iframeContainer.id = o.iframeContainer.id || t.id + "_iframecontainer";
+ }
+
+ // Use specified iframe height or the targets offsetHeight
+ h = o.iframeHeight || e.offsetHeight;
+
+ // Store away the selection when it's changed to it can be restored later with a editor.focus() call
+ if (isIE) {
+ t.onInit.add(function(ed) {
+ ed.dom.bind(ed.getBody(), 'beforedeactivate keydown', function() {
+ ed.lastIERng = ed.selection.getRng();
+ });
+ });
+ }
+ }
+
+ t.editorContainer = o.editorContainer;
+ }
+
+ // Load specified content CSS last
+ if (s.content_css) {
+ each(explode(s.content_css), function(u) {
+ t.contentCSS.push(t.documentBaseURI.toAbsolute(u));
+ });
+ }
+
+ // Content editable mode ends here
+ if (s.content_editable) {
+ e = n = o = null; // Fix IE leak
+ return t.initContentBody();
+ }
+
+ // User specified a document.domain value
+ if (document.domain && location.hostname != document.domain)
+ tinymce.relaxedDomain = document.domain;
+
+ t.iframeHTML = s.doctype + '<html><head xmlns="http://www.w3.org/1999/xhtml">';
+
+ // We only need to override paths if we have to
+ // IE has a bug where it remove site absolute urls to relative ones if this is specified
+ if (s.document_base_url != tinymce.documentBaseURL)
+ t.iframeHTML += '<base href="' + t.documentBaseURI.getURI() + '" />';
+
+ // IE8 doesn't support carets behind images setting ie7_compat would force IE8+ to run in IE7 compat mode.
+ if (s.ie7_compat)
+ t.iframeHTML += '<meta http-equiv="X-UA-Compatible" content="IE=7" />';
+ else
+ t.iframeHTML += '<meta http-equiv="X-UA-Compatible" content="IE=edge" />';
+
+ t.iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
+
+ // Load the CSS by injecting them into the HTML this will reduce "flicker"
+ for (i = 0; i < t.contentCSS.length; i++) {
+ t.iframeHTML += '<link type="text/css" rel="stylesheet" href="' + t.contentCSS[i] + '" />';
+ }
+
+ t.contentCSS = [];
+
+ bi = s.body_id || 'tinymce';
+ if (bi.indexOf('=') != -1) {
+ bi = t.getParam('body_id', '', 'hash');
+ bi = bi[t.id] || bi;
+ }
+
+ bc = s.body_class || '';
+ if (bc.indexOf('=') != -1) {
+ bc = t.getParam('body_class', '', 'hash');
+ bc = bc[t.id] || '';
+ }
+
+ t.iframeHTML += '</head><body id="' + bi + '" class="mceContentBody ' + bc + '" onload="window.parent.tinyMCE.get(\'' + t.id + '\').onLoad.dispatch();"><br></body></html>';
+
+ // Domain relaxing enabled, then set document domain
+ if (tinymce.relaxedDomain && (isIE || (tinymce.isOpera && parseFloat(opera.version()) < 11))) {
+ // We need to write the contents here in IE since multiple writes messes up refresh button and back button
+ u = 'javascript:(function(){document.open();document.domain="' + document.domain + '";var ed = window.parent.tinyMCE.get("' + t.id + '");document.write(ed.iframeHTML);document.close();ed.initContentBody();})()';
+ }
+
+ // Create iframe
+ // TODO: ACC add the appropriate description on this.
+ n = DOM.add(o.iframeContainer, 'iframe', {
+ id : t.id + "_ifr",
+ src : u || 'javascript:""', // Workaround for HTTPS warning in IE6/7
+ frameBorder : '0',
+ allowTransparency : "true",
+ title : s.aria_label,
+ style : {
+ width : '100%',
+ height : h,
+ display : 'block' // Important for Gecko to render the iframe correctly
+ }
+ });
+
+ t.contentAreaContainer = o.iframeContainer;
+
+ if (o.editorContainer) {
+ DOM.get(o.editorContainer).style.display = t.orgDisplay;
+ }
+
+ // Restore visibility on target element
+ e.style.visibility = t.orgVisibility;
+
+ DOM.get(t.id).style.display = 'none';
+ DOM.setAttrib(t.id, 'aria-hidden', true);
+
+ if (!tinymce.relaxedDomain || !u)
+ t.initContentBody();
+
+ e = n = o = null; // Cleanup
+ },
+
+ initContentBody : function() {
+ var self = this, settings = self.settings, targetElm = DOM.get(self.id), doc = self.getDoc(), html, body, contentCssText;
+
+ // Setup iframe body
+ if ((!isIE || !tinymce.relaxedDomain) && !settings.content_editable) {
+ doc.open();
+ doc.write(self.iframeHTML);
+ doc.close();
+
+ if (tinymce.relaxedDomain)
+ doc.domain = tinymce.relaxedDomain;
+ }
+
+ if (settings.content_editable) {
+ DOM.addClass(targetElm, 'mceContentBody');
+ self.contentDocument = doc = settings.content_document || document;
+ self.contentWindow = settings.content_window || window;
+ self.bodyElement = targetElm;
+
+ // Prevent leak in IE
+ settings.content_document = settings.content_window = null;
+ }
+
+ // It will not steal focus while setting contentEditable
+ body = self.getBody();
+ body.disabled = true;
+
+ if (!settings.readonly)
+ body.contentEditable = self.getParam('content_editable_state', true);
+
+ body.disabled = false;
+
+ self.schema = new tinymce.html.Schema(settings);
+
+ self.dom = new tinymce.dom.DOMUtils(doc, {
+ keep_values : true,
+ url_converter : self.convertURL,
+ url_converter_scope : self,
+ hex_colors : settings.force_hex_style_colors,
+ class_filter : settings.class_filter,
+ update_styles : true,
+ root_element : settings.content_editable ? self.id : null,
+ schema : self.schema
+ });
+
+ self.parser = new tinymce.html.DomParser(settings, self.schema);
+
+ // Convert src and href into data-mce-src, data-mce-href and data-mce-style
+ self.parser.addAttributeFilter('src,href,style', function(nodes, name) {
+ var i = nodes.length, node, dom = self.dom, value, internalName;
+
+ while (i--) {
+ node = nodes[i];
+ value = node.attr(name);
+ internalName = 'data-mce-' + name;
+
+ // Add internal attribute if we need to we don't on a refresh of the document
+ if (!node.attributes.map[internalName]) {
+ if (name === "style")
+ node.attr(internalName, dom.serializeStyle(dom.parseStyle(value), node.name));
+ else
+ node.attr(internalName, self.convertURL(value, name, node.name));
+ }
+ }
+ });
+
+ // Keep scripts from executing
+ self.parser.addNodeFilter('script', function(nodes, name) {
+ var i = nodes.length, node;
+
+ while (i--) {
+ node = nodes[i];
+ node.attr('type', 'mce-' + (node.attr('type') || 'text/javascript'));
+ }
+ });
+
+ self.parser.addNodeFilter('#cdata', function(nodes, name) {
+ var i = nodes.length, node;
+
+ while (i--) {
+ node = nodes[i];
+ node.type = 8;
+ node.name = '#comment';
+ node.value = '[CDATA[' + node.value + ']]';
+ }
+ });
+
+ self.parser.addNodeFilter('p,h1,h2,h3,h4,h5,h6,div', function(nodes, name) {
+ var i = nodes.length, node, nonEmptyElements = self.schema.getNonEmptyElements();
+
+ while (i--) {
+ node = nodes[i];
+
+ if (node.isEmpty(nonEmptyElements))
+ node.empty().append(new tinymce.html.Node('br', 1)).shortEnded = true;
+ }
+ });
+
+ self.serializer = new tinymce.dom.Serializer(settings, self.dom, self.schema);
+
+ self.selection = new tinymce.dom.Selection(self.dom, self.getWin(), self.serializer, self);
+
+ self.formatter = new tinymce.Formatter(self);
+
+ self.undoManager = new tinymce.UndoManager(self);
+
+ self.forceBlocks = new tinymce.ForceBlocks(self);
+ self.enterKey = new tinymce.EnterKey(self);
+ self.editorCommands = new tinymce.EditorCommands(self);
+
+ self.onExecCommand.add(function(editor, command) {
+ // Don't refresh the select lists until caret move
+ if (!/^(FontName|FontSize)$/.test(command))
+ self.nodeChanged();
+ });
+
+ // Pass through
+ self.serializer.onPreProcess.add(function(se, o) {
+ return self.onPreProcess.dispatch(self, o, se);
+ });
+
+ self.serializer.onPostProcess.add(function(se, o) {
+ return self.onPostProcess.dispatch(self, o, se);
+ });
+
+ self.onPreInit.dispatch(self);
+
+ if (!settings.browser_spellcheck && !settings.gecko_spellcheck)
+ doc.body.spellcheck = false;
+
+ if (!settings.readonly) {
+ self.bindNativeEvents();
+ }
+
+ self.controlManager.onPostRender.dispatch(self, self.controlManager);
+ self.onPostRender.dispatch(self);
+
+ self.quirks = tinymce.util.Quirks(self);
+
+ if (settings.directionality)
+ body.dir = settings.directionality;
+
+ if (settings.nowrap)
+ body.style.whiteSpace = "nowrap";
+
+ if (settings.protect) {
+ self.onBeforeSetContent.add(function(ed, o) {
+ each(settings.protect, function(pattern) {
+ o.content = o.content.replace(pattern, function(str) {
+ return '<!--mce:protected ' + escape(str) + '-->';
+ });
+ });
+ });
+ }
+
+ // Add visual aids when new contents is added
+ self.onSetContent.add(function() {
+ self.addVisual(self.getBody());
+ });
+
+ // Remove empty contents
+ if (settings.padd_empty_editor) {
+ self.onPostProcess.add(function(ed, o) {
+ o.content = o.content.replace(/^(<p[^>]*>(&nbsp;|&#160;|\s|\u00a0|)<\/p>[\r\n]*|<br \/>[\r\n]*)$/, '');
+ });
+ }
+
+ self.load({initial : true, format : 'html'});
+ self.startContent = self.getContent({format : 'raw'});
+
+ self.initialized = true;
+
+ self.onInit.dispatch(self);
+ self.execCallback('setupcontent_callback', self.id, body, doc);
+ self.execCallback('init_instance_callback', self);
+ self.focus(true);
+ self.nodeChanged({initial : true});
+
+ // Add editor specific CSS styles
+ if (self.contentStyles.length > 0) {
+ contentCssText = '';
+
+ each(self.contentStyles, function(style) {
+ contentCssText += style + "\r\n";
+ });
+
+ self.dom.addStyle(contentCssText);
+ }
+
+ // Load specified content CSS last
+ each(self.contentCSS, function(url) {
+ self.dom.loadCSS(url);
+ });
+
+ // Handle auto focus
+ if (settings.auto_focus) {
+ setTimeout(function () {
+ var ed = tinymce.get(settings.auto_focus);
+
+ ed.selection.select(ed.getBody(), 1);
+ ed.selection.collapse(1);
+ ed.getBody().focus();
+ ed.getWin().focus();
+ }, 100);
+ }
+
+ // Clean up references for IE
+ targetElm = doc = body = null;
+ },
+
+ focus : function(skip_focus) {
+ var oed, self = this, selection = self.selection, contentEditable = self.settings.content_editable, ieRng, controlElm, doc = self.getDoc(), body;
+
+ if (!skip_focus) {
+ if (self.lastIERng) {
+ selection.setRng(self.lastIERng);
+ }
+
+ // Get selected control element
+ ieRng = selection.getRng();
+ if (ieRng.item) {
+ controlElm = ieRng.item(0);
+ }
+
+ self._refreshContentEditable();
+
+ // Focus the window iframe
+ if (!contentEditable) {
+ self.getWin().focus();
+ }
+
+ // Focus the body as well since it's contentEditable
+ if (tinymce.isGecko || contentEditable) {
+ body = self.getBody();
+
+ // Check for setActive since it doesn't scroll to the element
+ if (body.setActive) {
+ body.setActive();
+ } else {
+ body.focus();
+ }
+
+ if (contentEditable) {
+ selection.normalize();
+ }
+ }
+
+ // Restore selected control element
+ // This is needed when for example an image is selected within a
+ // layer a call to focus will then remove the control selection
+ if (controlElm && controlElm.ownerDocument == doc) {
+ ieRng = doc.body.createControlRange();
+ ieRng.addElement(controlElm);
+ ieRng.select();
+ }
+ }
+
+ if (tinymce.activeEditor != self) {
+ if ((oed = tinymce.activeEditor) != null)
+ oed.onDeactivate.dispatch(oed, self);
+
+ self.onActivate.dispatch(self, oed);
+ }
+
+ tinymce._setActive(self);
+ },
+
+ execCallback : function(n) {
+ var t = this, f = t.settings[n], s;
+
+ if (!f)
+ return;
+
+ // Look through lookup
+ if (t.callbackLookup && (s = t.callbackLookup[n])) {
+ f = s.func;
+ s = s.scope;
+ }
+
+ if (is(f, 'string')) {
+ s = f.replace(/\.\w+$/, '');
+ s = s ? tinymce.resolve(s) : 0;
+ f = tinymce.resolve(f);
+ t.callbackLookup = t.callbackLookup || {};
+ t.callbackLookup[n] = {func : f, scope : s};
+ }
+
+ return f.apply(s || t, Array.prototype.slice.call(arguments, 1));
+ },
+
+ translate : function(s) {
+ var c = this.settings.language || 'en', i18n = tinymce.i18n;
+
+ if (!s)
+ return '';
+
+ return i18n[c + '.' + s] || s.replace(/\{\#([^\}]+)\}/g, function(a, b) {
+ return i18n[c + '.' + b] || '{#' + b + '}';
+ });
+ },
+
+ getLang : function(n, dv) {
+ return tinymce.i18n[(this.settings.language || 'en') + '.' + n] || (is(dv) ? dv : '{#' + n + '}');
+ },
+
+ getParam : function(n, dv, ty) {
+ var tr = tinymce.trim, v = is(this.settings[n]) ? this.settings[n] : dv, o;
+
+ if (ty === 'hash') {
+ o = {};
+
+ if (is(v, 'string')) {
+ each(v.indexOf('=') > 0 ? v.split(/[;,](?![^=;,]*(?:[;,]|$))/) : v.split(','), function(v) {
+ v = v.split('=');
+
+ if (v.length > 1)
+ o[tr(v[0])] = tr(v[1]);
+ else
+ o[tr(v[0])] = tr(v);
+ });
+ } else
+ o = v;
+
+ return o;
+ }
+
+ return v;
+ },
+
+ nodeChanged : function(o) {
+ var self = this, selection = self.selection, node;
+
+ // Fix for bug #1896577 it seems that this can not be fired while the editor is loading
+ if (self.initialized) {
+ o = o || {};
+
+ // Get start node
+ node = selection.getStart() || self.getBody();
+ node = isIE && node.ownerDocument != self.getDoc() ? self.getBody() : node; // Fix for IE initial state
+
+ // Get parents and add them to object
+ o.parents = [];
+ self.dom.getParent(node, function(node) {
+ if (node.nodeName == 'BODY')
+ return true;
+
+ o.parents.push(node);
+ });
+
+ self.onNodeChange.dispatch(
+ self,
+ o ? o.controlManager || self.controlManager : self.controlManager,
+ node,
+ selection.isCollapsed(),
+ o
+ );
+ }
+ },
+
+ addButton : function(name, settings) {
+ var self = this;
+
+ self.buttons = self.buttons || {};
+ self.buttons[name] = settings;
+ },
+
+ addCommand : function(name, callback, scope) {
+ this.execCommands[name] = {func : callback, scope : scope || this};
+ },
+
+ addQueryStateHandler : function(name, callback, scope) {
+ this.queryStateCommands[name] = {func : callback, scope : scope || this};
+ },
+
+ addQueryValueHandler : function(name, callback, scope) {
+ this.queryValueCommands[name] = {func : callback, scope : scope || this};
+ },
+
+ addShortcut : function(pa, desc, cmd_func, sc) {
+ var t = this, c;
+
+ if (t.settings.custom_shortcuts === false)
+ return false;
+
+ t.shortcuts = t.shortcuts || {};
+
+ if (is(cmd_func, 'string')) {
+ c = cmd_func;
+
+ cmd_func = function() {
+ t.execCommand(c, false, null);
+ };
+ }
+
+ if (is(cmd_func, 'object')) {
+ c = cmd_func;
+
+ cmd_func = function() {
+ t.execCommand(c[0], c[1], c[2]);
+ };
+ }
+
+ each(explode(pa), function(pa) {
+ var o = {
+ func : cmd_func,
+ scope : sc || this,
+ desc : t.translate(desc),
+ alt : false,
+ ctrl : false,
+ shift : false
+ };
+
+ each(explode(pa, '+'), function(v) {
+ switch (v) {
+ case 'alt':
+ case 'ctrl':
+ case 'shift':
+ o[v] = true;
+ break;
+
+ default:
+ o.charCode = v.charCodeAt(0);
+ o.keyCode = v.toUpperCase().charCodeAt(0);
+ }
+ });
+
+ t.shortcuts[(o.ctrl ? 'ctrl' : '') + ',' + (o.alt ? 'alt' : '') + ',' + (o.shift ? 'shift' : '') + ',' + o.keyCode] = o;
+ });
+
+ return true;
+ },
+
+ execCommand : function(cmd, ui, val, a) {
+ var t = this, s = 0, o, st;
+
+ if (!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint|SelectAll)$/.test(cmd) && (!a || !a.skip_focus))
+ t.focus();
+
+ a = extend({}, a);
+ t.onBeforeExecCommand.dispatch(t, cmd, ui, val, a);
+ if (a.terminate)
+ return false;
+
+ // Command callback
+ if (t.execCallback('execcommand_callback', t.id, t.selection.getNode(), cmd, ui, val)) {
+ t.onExecCommand.dispatch(t, cmd, ui, val, a);
+ return true;
+ }
+
+ // Registred commands
+ if (o = t.execCommands[cmd]) {
+ st = o.func.call(o.scope, ui, val);
+
+ // Fall through on true
+ if (st !== true) {
+ t.onExecCommand.dispatch(t, cmd, ui, val, a);
+ return st;
+ }
+ }
+
+ // Plugin commands
+ each(t.plugins, function(p) {
+ if (p.execCommand && p.execCommand(cmd, ui, val)) {
+ t.onExecCommand.dispatch(t, cmd, ui, val, a);
+ s = 1;
+ return false;
+ }
+ });
+
+ if (s)
+ return true;
+
+ // Theme commands
+ if (t.theme && t.theme.execCommand && t.theme.execCommand(cmd, ui, val)) {
+ t.onExecCommand.dispatch(t, cmd, ui, val, a);
+ return true;
+ }
+
+ // Editor commands
+ if (t.editorCommands.execCommand(cmd, ui, val)) {
+ t.onExecCommand.dispatch(t, cmd, ui, val, a);
+ return true;
+ }
+
+ // Browser commands
+ t.getDoc().execCommand(cmd, ui, val);
+ t.onExecCommand.dispatch(t, cmd, ui, val, a);
+ },
+
+ queryCommandState : function(cmd) {
+ var t = this, o, s;
+
+ // Is hidden then return undefined
+ if (t._isHidden())
+ return;
+
+ // Registred commands
+ if (o = t.queryStateCommands[cmd]) {
+ s = o.func.call(o.scope);
+
+ // Fall though on true
+ if (s !== true)
+ return s;
+ }
+
+ // Registred commands
+ o = t.editorCommands.queryCommandState(cmd);
+ if (o !== -1)
+ return o;
+
+ // Browser commands
+ try {
+ return this.getDoc().queryCommandState(cmd);
+ } catch (ex) {
+ // Fails sometimes see bug: 1896577
+ }
+ },
+
+ queryCommandValue : function(c) {
+ var t = this, o, s;
+
+ // Is hidden then return undefined
+ if (t._isHidden())
+ return;
+
+ // Registred commands
+ if (o = t.queryValueCommands[c]) {
+ s = o.func.call(o.scope);
+
+ // Fall though on true
+ if (s !== true)
+ return s;
+ }
+
+ // Registred commands
+ o = t.editorCommands.queryCommandValue(c);
+ if (is(o))
+ return o;
+
+ // Browser commands
+ try {
+ return this.getDoc().queryCommandValue(c);
+ } catch (ex) {
+ // Fails sometimes see bug: 1896577
+ }
+ },
+
+ show : function() {
+ var self = this;
+
+ DOM.show(self.getContainer());
+ DOM.hide(self.id);
+ self.load();
+ },
+
+ hide : function() {
+ var self = this, doc = self.getDoc();
+
+ // Fixed bug where IE has a blinking cursor left from the editor
+ if (isIE && doc)
+ doc.execCommand('SelectAll');
+
+ // We must save before we hide so Safari doesn't crash
+ self.save();
+ DOM.hide(self.getContainer());
+ DOM.setStyle(self.id, 'display', self.orgDisplay);
+ },
+
+ isHidden : function() {
+ return !DOM.isHidden(this.id);
+ },
+
+ setProgressState : function(b, ti, o) {
+ this.onSetProgressState.dispatch(this, b, ti, o);
+
+ return b;
+ },
+
+ load : function(o) {
+ var t = this, e = t.getElement(), h;
+
+ if (e) {
+ o = o || {};
+ o.load = true;
+
+ // Double encode existing entities in the value
+ h = t.setContent(is(e.value) ? e.value : e.innerHTML, o);
+ o.element = e;
+
+ if (!o.no_events)
+ t.onLoadContent.dispatch(t, o);
+
+ o.element = e = null;
+
+ return h;
+ }
+ },
+
+ save : function(o) {
+ var t = this, e = t.getElement(), h, f;
+
+ if (!e || !t.initialized)
+ return;
+
+ o = o || {};
+ o.save = true;
+
+ o.element = e;
+ h = o.content = t.getContent(o);
+
+ if (!o.no_events)
+ t.onSaveContent.dispatch(t, o);
+
+ h = o.content;
+
+ if (!/TEXTAREA|INPUT/i.test(e.nodeName)) {
+ e.innerHTML = h;
+
+ // Update hidden form element
+ if (f = DOM.getParent(t.id, 'form')) {
+ each(f.elements, function(e) {
+ if (e.name == t.id) {
+ e.value = h;
+ return false;
+ }
+ });
+ }
+ } else
+ e.value = h;
+
+ o.element = e = null;
+
+ return h;
+ },
+
+ setContent : function(content, args) {
+ var self = this, rootNode, body = self.getBody(), forcedRootBlockName;
+
+ // Setup args object
+ args = args || {};
+ args.format = args.format || 'html';
+ args.set = true;
+ args.content = content;
+
+ // Do preprocessing
+ if (!args.no_events)
+ self.onBeforeSetContent.dispatch(self, args);
+
+ content = args.content;
+
+ // Padd empty content in Gecko and Safari. Commands will otherwise fail on the content
+ // It will also be impossible to place the caret in the editor unless there is a BR element present
+ if (!tinymce.isIE && (content.length === 0 || /^\s+$/.test(content))) {
+ forcedRootBlockName = self.settings.forced_root_block;
+ if (forcedRootBlockName)
+ content = '<' + forcedRootBlockName + '><br data-mce-bogus="1"></' + forcedRootBlockName + '>';
+ else
+ content = '<br data-mce-bogus="1">';
+
+ body.innerHTML = content;
+ self.selection.select(body, true);
+ self.selection.collapse(true);
+ return;
+ }
+
+ // Parse and serialize the html
+ if (args.format !== 'raw') {
+ content = new tinymce.html.Serializer({}, self.schema).serialize(
+ self.parser.parse(content)
+ );
+ }
+
+ // Set the new cleaned contents to the editor
+ args.content = tinymce.trim(content);
+ self.dom.setHTML(body, args.content);
+
+ // Do post processing
+ if (!args.no_events)
+ self.onSetContent.dispatch(self, args);
+
+ // Don't normalize selection if the focused element isn't the body in content editable mode since it will steal focus otherwise
+ if (!self.settings.content_editable || document.activeElement === self.getBody()) {
+ self.selection.normalize();
+ }
+
+ return args.content;
+ },
+
+ getContent : function(args) {
+ var self = this, content;
+
+ // Setup args object
+ args = args || {};
+ args.format = args.format || 'html';
+ args.get = true;
+ args.getInner = true;
+
+ // Do preprocessing
+ if (!args.no_events)
+ self.onBeforeGetContent.dispatch(self, args);
+
+ // Get raw contents or by default the cleaned contents
+ if (args.format == 'raw')
+ content = self.getBody().innerHTML;
+ else
+ content = self.serializer.serialize(self.getBody(), args);
+
+ args.content = tinymce.trim(content);
+
+ // Do post processing
+ if (!args.no_events)
+ self.onGetContent.dispatch(self, args);
+
+ return args.content;
+ },
+
+ isDirty : function() {
+ var self = this;
+
+ return tinymce.trim(self.startContent) != tinymce.trim(self.getContent({format : 'raw', no_events : 1})) && !self.isNotDirty;
+ },
+
+ getContainer : function() {
+ var self = this;
+
+ if (!self.container)
+ self.container = DOM.get(self.editorContainer || self.id + '_parent');
+
+ return self.container;
+ },
+
+ getContentAreaContainer : function() {
+ return this.contentAreaContainer;
+ },
+
+ getElement : function() {
+ return DOM.get(this.settings.content_element || this.id);
+ },
+
+ getWin : function() {
+ var self = this, elm;
+
+ if (!self.contentWindow) {
+ elm = DOM.get(self.id + "_ifr");
+
+ if (elm)
+ self.contentWindow = elm.contentWindow;
+ }
+
+ return self.contentWindow;
+ },
+
+ getDoc : function() {
+ var self = this, win;
+
+ if (!self.contentDocument) {
+ win = self.getWin();
+
+ if (win)
+ self.contentDocument = win.document;
+ }
+
+ return self.contentDocument;
+ },
+
+ getBody : function() {
+ return this.bodyElement || this.getDoc().body;
+ },
+
+ convertURL : function(url, name, elm) {
+ var self = this, settings = self.settings;
+
+ // Use callback instead
+ if (settings.urlconverter_callback)
+ return self.execCallback('urlconverter_callback', url, elm, true, name);
+
+ // Don't convert link href since thats the CSS files that gets loaded into the editor also skip local file URLs
+ if (!settings.convert_urls || (elm && elm.nodeName == 'LINK') || url.indexOf('file:') === 0)
+ return url;
+
+ // Convert to relative
+ if (settings.relative_urls)
+ return self.documentBaseURI.toRelative(url);
+
+ // Convert to absolute
+ url = self.documentBaseURI.toAbsolute(url, settings.remove_script_host);
+
+ return url;
+ },
+
+ addVisual : function(elm) {
+ var self = this, settings = self.settings, dom = self.dom, cls;
+
+ elm = elm || self.getBody();
+
+ if (!is(self.hasVisual))
+ self.hasVisual = settings.visual;
+
+ each(dom.select('table,a', elm), function(elm) {
+ var value;
+
+ switch (elm.nodeName) {
+ case 'TABLE':
+ cls = settings.visual_table_class || 'mceItemTable';
+ value = dom.getAttrib(elm, 'border');
+
+ if (!value || value == '0') {
+ if (self.hasVisual)
+ dom.addClass(elm, cls);
+ else
+ dom.removeClass(elm, cls);
+ }
+
+ return;
+
+ case 'A':
+ if (!dom.getAttrib(elm, 'href', false)) {
+ value = dom.getAttrib(elm, 'name') || elm.id;
+ cls = 'mceItemAnchor';
+
+ if (value) {
+ if (self.hasVisual)
+ dom.addClass(elm, cls);
+ else
+ dom.removeClass(elm, cls);
+ }
+ }
+
+ return;
+ }
+ });
+
+ self.onVisualAid.dispatch(self, elm, self.hasVisual);
+ },
+
+ remove : function() {
+ var self = this, elm = self.getContainer();
+
+ if (!self.removed) {
+ self.removed = 1; // Cancels post remove event execution
+ self.hide();
+
+ // Don't clear the window or document if content editable
+ // is enabled since other instances might still be present
+ if (!self.settings.content_editable) {
+ Event.unbind(self.getWin());
+ Event.unbind(self.getDoc());
+ }
+
+ Event.unbind(self.getBody());
+ Event.clear(elm);
+
+ self.execCallback('remove_instance_callback', self);
+ self.onRemove.dispatch(self);
+
+ // Clear all execCommand listeners this is required to avoid errors if the editor was removed inside another command
+ self.onExecCommand.listeners = [];
+
+ tinymce.remove(self);
+ DOM.remove(elm);
+ }
+ },
+
+ destroy : function(s) {
+ var t = this;
+
+ // One time is enough
+ if (t.destroyed)
+ return;
+
+ // We must unbind on Gecko since it would otherwise produce the pesky "attempt to run compile-and-go script on a cleared scope" message
+ if (isGecko) {
+ Event.unbind(t.getDoc());
+ Event.unbind(t.getWin());
+ Event.unbind(t.getBody());
+ }
+
+ if (!s) {
+ tinymce.removeUnload(t.destroy);
+ tinyMCE.onBeforeUnload.remove(t._beforeUnload);
+
+ // Manual destroy
+ if (t.theme && t.theme.destroy)
+ t.theme.destroy();
+
+ // Destroy controls, selection and dom
+ t.controlManager.destroy();
+ t.selection.destroy();
+ t.dom.destroy();
+ }
+
+ if (t.formElement) {
+ t.formElement.submit = t.formElement._mceOldSubmit;
+ t.formElement._mceOldSubmit = null;
+ }
+
+ t.contentAreaContainer = t.formElement = t.container = t.settings.content_element = t.bodyElement = t.contentDocument = t.contentWindow = null;
+
+ if (t.selection)
+ t.selection = t.selection.win = t.selection.dom = t.selection.dom.doc = null;
+
+ t.destroyed = 1;
+ },
+
+ // Internal functions
+
+ _refreshContentEditable : function() {
+ var self = this, body, parent;
+
+ // Check if the editor was hidden and the re-initalize contentEditable mode by removing and adding the body again
+ if (self._isHidden()) {
+ body = self.getBody();
+ parent = body.parentNode;
+
+ parent.removeChild(body);
+ parent.appendChild(body);
+
+ body.focus();
+ }
+ },
+
+ _isHidden : function() {
+ var s;
+
+ if (!isGecko)
+ return 0;
+
+ // Weird, wheres that cursor selection?
+ s = this.selection.getSel();
+ return (!s || !s.rangeCount || s.rangeCount === 0);
+ }
+ });
+})(tinymce);
+(function(tinymce) {
+ var each = tinymce.each;
+
+ tinymce.Editor.prototype.setupEvents = function() {
+ var self = this, settings = self.settings;
+
+ // Add events to the editor
+ each([
+ 'onPreInit',
+
+ 'onBeforeRenderUI',
+
+ 'onPostRender',
+
+ 'onLoad',
+
+ 'onInit',
+
+ 'onRemove',
+
+ 'onActivate',
+
+ 'onDeactivate',
+
+ 'onClick',
+
+ 'onEvent',
+
+ 'onMouseUp',
+
+ 'onMouseDown',
+
+ 'onDblClick',
+
+ 'onKeyDown',
+
+ 'onKeyUp',
+
+ 'onKeyPress',
+
+ 'onContextMenu',
+
+ 'onSubmit',
+
+ 'onReset',
+
+ 'onPaste',
+
+ 'onPreProcess',
+
+ 'onPostProcess',
+
+ 'onBeforeSetContent',
+
+ 'onBeforeGetContent',
+
+ 'onSetContent',
+
+ 'onGetContent',
+
+ 'onLoadContent',
+
+ 'onSaveContent',
+
+ 'onNodeChange',
+
+ 'onChange',
+
+ 'onBeforeExecCommand',
+
+ 'onExecCommand',
+
+ 'onUndo',
+
+ 'onRedo',
+
+ 'onVisualAid',
+
+ 'onSetProgressState',
+
+ 'onSetAttrib'
+ ], function(name) {
+ self[name] = new tinymce.util.Dispatcher(self);
+ });
+
+ // Handle legacy cleanup_callback option
+ if (settings.cleanup_callback) {
+ self.onBeforeSetContent.add(function(ed, o) {
+ o.content = ed.execCallback('cleanup_callback', 'insert_to_editor', o.content, o);
+ });
+
+ self.onPreProcess.add(function(ed, o) {
+ if (o.set)
+ ed.execCallback('cleanup_callback', 'insert_to_editor_dom', o.node, o);
+
+ if (o.get)
+ ed.execCallback('cleanup_callback', 'get_from_editor_dom', o.node, o);
+ });
+
+ self.onPostProcess.add(function(ed, o) {
+ if (o.set)
+ o.content = ed.execCallback('cleanup_callback', 'insert_to_editor', o.content, o);
+
+ if (o.get)
+ o.content = ed.execCallback('cleanup_callback', 'get_from_editor', o.content, o);
+ });
+ }
+
+ // Handle legacy save_callback option
+ if (settings.save_callback) {
+ self.onGetContent.add(function(ed, o) {
+ if (o.save)
+ o.content = ed.execCallback('save_callback', ed.id, o.content, ed.getBody());
+ });
+ }
+
+ // Handle legacy handle_event_callback option
+ if (settings.handle_event_callback) {
+ self.onEvent.add(function(ed, e, o) {
+ if (self.execCallback('handle_event_callback', e, ed, o) === false) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ });
+ }
+
+ // Handle legacy handle_node_change_callback option
+ if (settings.handle_node_change_callback) {
+ self.onNodeChange.add(function(ed, cm, n) {
+ ed.execCallback('handle_node_change_callback', ed.id, n, -1, -1, true, ed.selection.isCollapsed());
+ });
+ }
+
+ // Handle legacy save_callback option
+ if (settings.save_callback) {
+ self.onSaveContent.add(function(ed, o) {
+ var h = ed.execCallback('save_callback', ed.id, o.content, ed.getBody());
+
+ if (h)
+ o.content = h;
+ });
+ }
+
+ // Handle legacy onchange_callback option
+ if (settings.onchange_callback) {
+ self.onChange.add(function(ed, l) {
+ ed.execCallback('onchange_callback', ed, l);
+ });
+ }
+ };
+
+ tinymce.Editor.prototype.bindNativeEvents = function() {
+ // 'focus', 'blur', 'dblclick', 'beforedeactivate', submit, reset
+ var self = this, i, settings = self.settings, dom = self.dom, nativeToDispatcherMap;
+
+ nativeToDispatcherMap = {
+ mouseup : 'onMouseUp',
+ mousedown : 'onMouseDown',
+ click : 'onClick',
+ keyup : 'onKeyUp',
+ keydown : 'onKeyDown',
+ keypress : 'onKeyPress',
+ submit : 'onSubmit',
+ reset : 'onReset',
+ contextmenu : 'onContextMenu',
+ dblclick : 'onDblClick',
+ paste : 'onPaste' // Doesn't work in all browsers yet
+ };
+
+ // Handler that takes a native event and sends it out to a dispatcher like onKeyDown
+ function eventHandler(evt, args) {
+ var type = evt.type;
+
+ // Don't fire events when it's removed
+ if (self.removed)
+ return;
+
+ // Sends the native event out to a global dispatcher then to the specific event dispatcher
+ if (self.onEvent.dispatch(self, evt, args) !== false) {
+ self[nativeToDispatcherMap[evt.fakeType || evt.type]].dispatch(self, evt, args);
+ }
+ };
+
+ // Opera doesn't support focus event for contentEditable elements so we need to fake it
+ function doOperaFocus(e) {
+ self.focus(true);
+ };
+
+ function nodeChanged() {
+ // Normalize selection for example <b>a</b><i>|a</i> becomes <b>a|</b><i>a</i>
+ self.selection.normalize();
+ self.nodeChanged();
+ }
+
+ // Add DOM events
+ each(nativeToDispatcherMap, function(dispatcherName, nativeName) {
+ var root = settings.content_editable ? self.getBody() : self.getDoc();
+
+ switch (nativeName) {
+ case 'contextmenu':
+ dom.bind(root, nativeName, eventHandler);
+ break;
+
+ case 'paste':
+ dom.bind(self.getBody(), nativeName, eventHandler);
+ break;
+
+ case 'submit':
+ case 'reset':
+ dom.bind(self.getElement().form || tinymce.DOM.getParent(self.id, 'form'), nativeName, eventHandler);
+ break;
+
+ default:
+ dom.bind(root, nativeName, eventHandler);
+ }
+ });
+
+ // Set the editor as active when focused
+ dom.bind(settings.content_editable ? self.getBody() : (tinymce.isGecko ? self.getDoc() : self.getWin()), 'focus', function(e) {
+ self.focus(true);
+ });
+
+ if (settings.content_editable && tinymce.isOpera) {
+ dom.bind(self.getBody(), 'click', doOperaFocus);
+ dom.bind(self.getBody(), 'keydown', doOperaFocus);
+ }
+
+ // Add node change handler
+ self.onMouseUp.add(nodeChanged);
+
+ self.onKeyUp.add(function(ed, e) {
+ var keyCode = e.keyCode;
+
+ if ((keyCode >= 33 && keyCode <= 36) || (keyCode >= 37 && keyCode <= 40) || keyCode == 13 || keyCode == 45 || keyCode == 46 || keyCode == 8 || (tinymce.isMac && (keyCode == 91 || keyCode == 93)) || e.ctrlKey)
+ nodeChanged();
+ });
+
+ // Add reset handler
+ self.onReset.add(function() {
+ self.setContent(self.startContent, {format : 'raw'});
+ });
+
+ // Add shortcuts
+ function handleShortcut(e, execute) {
+ if (e.altKey || e.ctrlKey || e.metaKey) {
+ each(self.shortcuts, function(shortcut) {
+ var ctrlState = tinymce.isMac ? e.metaKey : e.ctrlKey;
+
+ if (shortcut.ctrl != ctrlState || shortcut.alt != e.altKey || shortcut.shift != e.shiftKey)
+ return;
+
+ if (e.keyCode == shortcut.keyCode || (e.charCode && e.charCode == shortcut.charCode)) {
+ e.preventDefault();
+
+ if (execute) {
+ shortcut.func.call(shortcut.scope);
+ }
+
+ return true;
+ }
+ });
+ }
+ };
+
+ self.onKeyUp.add(function(ed, e) {
+ handleShortcut(e);
+ });
+
+ self.onKeyPress.add(function(ed, e) {
+ handleShortcut(e);
+ });
+
+ self.onKeyDown.add(function(ed, e) {
+ handleShortcut(e, true);
+ });
+
+ if (tinymce.isOpera) {
+ self.onClick.add(function(ed, e) {
+ e.preventDefault();
+ });
+ }
+ };
+})(tinymce);
+(function(tinymce) {
+ // Added for compression purposes
+ var each = tinymce.each, undef, TRUE = true, FALSE = false;
+
+ tinymce.EditorCommands = function(editor) {
+ var dom = editor.dom,
+ selection = editor.selection,
+ commands = {state: {}, exec : {}, value : {}},
+ settings = editor.settings,
+ formatter = editor.formatter,
+ bookmark;
+
+ function execCommand(command, ui, value) {
+ var func;
+
+ command = command.toLowerCase();
+ if (func = commands.exec[command]) {
+ func(command, ui, value);
+ return TRUE;
+ }
+
+ return FALSE;
+ };
+
+ function queryCommandState(command) {
+ var func;
+
+ command = command.toLowerCase();
+ if (func = commands.state[command])
+ return func(command);
+
+ return -1;
+ };
+
+ function queryCommandValue(command) {
+ var func;
+
+ command = command.toLowerCase();
+ if (func = commands.value[command])
+ return func(command);
+
+ return FALSE;
+ };
+
+ function addCommands(command_list, type) {
+ type = type || 'exec';
+
+ each(command_list, function(callback, command) {
+ each(command.toLowerCase().split(','), function(command) {
+ commands[type][command] = callback;
+ });
+ });
+ };
+
+ // Expose public methods
+ tinymce.extend(this, {
+ execCommand : execCommand,
+ queryCommandState : queryCommandState,
+ queryCommandValue : queryCommandValue,
+ addCommands : addCommands
+ });
+
+ // Private methods
+
+ function execNativeCommand(command, ui, value) {
+ if (ui === undef)
+ ui = FALSE;
+
+ if (value === undef)
+ value = null;
+
+ return editor.getDoc().execCommand(command, ui, value);
+ };
+
+ function isFormatMatch(name) {
+ return formatter.match(name);
+ };
+
+ function toggleFormat(name, value) {
+ formatter.toggle(name, value ? {value : value} : undef);
+ };
+
+ function storeSelection(type) {
+ bookmark = selection.getBookmark(type);
+ };
+
+ function restoreSelection() {
+ selection.moveToBookmark(bookmark);
+ };
+
+ // Add execCommand overrides
+ addCommands({
+ // Ignore these, added for compatibility
+ 'mceResetDesignMode,mceBeginUndoLevel' : function() {},
+
+ // Add undo manager logic
+ 'mceEndUndoLevel,mceAddUndoLevel' : function() {
+ editor.undoManager.add();
+ },
+
+ 'Cut,Copy,Paste' : function(command) {
+ var doc = editor.getDoc(), failed;
+
+ // Try executing the native command
+ try {
+ execNativeCommand(command);
+ } catch (ex) {
+ // Command failed
+ failed = TRUE;
+ }
+
+ // Present alert message about clipboard access not being available
+ if (failed || !doc.queryCommandSupported(command)) {
+ if (tinymce.isGecko) {
+ editor.windowManager.confirm(editor.getLang('clipboard_msg'), function(state) {
+ if (state)
+ open('http://www.mozilla.org/editor/midasdemo/securityprefs.html', '_blank');
+ });
+ } else
+ editor.windowManager.alert(editor.getLang('clipboard_no_support'));
+ }
+ },
+
+ // Override unlink command
+ unlink : function(command) {
+ if (selection.isCollapsed())
+ selection.select(selection.getNode());
+
+ execNativeCommand(command);
+ selection.collapse(FALSE);
+ },
+
+ // Override justify commands to use the text formatter engine
+ 'JustifyLeft,JustifyCenter,JustifyRight,JustifyFull' : function(command) {
+ var align = command.substring(7);
+
+ // Remove all other alignments first
+ each('left,center,right,full'.split(','), function(name) {
+ if (align != name)
+ formatter.remove('align' + name);
+ });
+
+ toggleFormat('align' + align);
+ execCommand('mceRepaint');
+ },
+
+ // Override list commands to fix WebKit bug
+ 'InsertUnorderedList,InsertOrderedList' : function(command) {
+ var listElm, listParent;
+
+ execNativeCommand(command);
+
+ // WebKit produces lists within block elements so we need to split them
+ // we will replace the native list creation logic to custom logic later on
+ // TODO: Remove this when the list creation logic is removed
+ listElm = dom.getParent(selection.getNode(), 'ol,ul');
+ if (listElm) {
+ listParent = listElm.parentNode;
+
+ // If list is within a text block then split that block
+ if (/^(H[1-6]|P|ADDRESS|PRE)$/.test(listParent.nodeName)) {
+ storeSelection();
+ dom.split(listParent, listElm);
+ restoreSelection();
+ }
+ }
+ },
+
+ // Override commands to use the text formatter engine
+ 'Bold,Italic,Underline,Strikethrough,Superscript,Subscript' : function(command) {
+ toggleFormat(command);
+ },
+
+ // Override commands to use the text formatter engine
+ 'ForeColor,HiliteColor,FontName' : function(command, ui, value) {
+ toggleFormat(command, value);
+ },
+
+ FontSize : function(command, ui, value) {
+ var fontClasses, fontSizes;
+
+ // Convert font size 1-7 to styles
+ if (value >= 1 && value <= 7) {
+ fontSizes = tinymce.explode(settings.font_size_style_values);
+ fontClasses = tinymce.explode(settings.font_size_classes);
+
+ if (fontClasses)
+ value = fontClasses[value - 1] || value;
+ else
+ value = fontSizes[value - 1] || value;
+ }
+
+ toggleFormat(command, value);
+ },
+
+ RemoveFormat : function(command) {
+ formatter.remove(command);
+ },
+
+ mceBlockQuote : function(command) {
+ toggleFormat('blockquote');
+ },
+
+ FormatBlock : function(command, ui, value) {
+ return toggleFormat(value || 'p');
+ },
+
+ mceCleanup : function() {
+ var bookmark = selection.getBookmark();
+
+ editor.setContent(editor.getContent({cleanup : TRUE}), {cleanup : TRUE});
+
+ selection.moveToBookmark(bookmark);
+ },
+
+ mceRemoveNode : function(command, ui, value) {
+ var node = value || selection.getNode();
+
+ // Make sure that the body node isn't removed
+ if (node != editor.getBody()) {
+ storeSelection();
+ editor.dom.remove(node, TRUE);
+ restoreSelection();
+ }
+ },
+
+ mceSelectNodeDepth : function(command, ui, value) {
+ var counter = 0;
+
+ dom.getParent(selection.getNode(), function(node) {
+ if (node.nodeType == 1 && counter++ == value) {
+ selection.select(node);
+ return FALSE;
+ }
+ }, editor.getBody());
+ },
+
+ mceSelectNode : function(command, ui, value) {
+ selection.select(value);
+ },
+
+ mceInsertContent : function(command, ui, value) {
+ var parser, serializer, parentNode, rootNode, fragment, args,
+ marker, nodeRect, viewPortRect, rng, node, node2, bookmarkHtml, viewportBodyElement;
+
+ //selection.normalize();
+
+ // Setup parser and serializer
+ parser = editor.parser;
+ serializer = new tinymce.html.Serializer({}, editor.schema);
+ bookmarkHtml = '<span id="mce_marker" data-mce-type="bookmark">\uFEFF</span>';
+
+ // Run beforeSetContent handlers on the HTML to be inserted
+ args = {content: value, format: 'html'};
+ selection.onBeforeSetContent.dispatch(selection, args);
+ value = args.content;
+
+ // Add caret at end of contents if it's missing
+ if (value.indexOf('{$caret}') == -1)
+ value += '{$caret}';
+
+ // Replace the caret marker with a span bookmark element
+ value = value.replace(/\{\$caret\}/, bookmarkHtml);
+
+ // Insert node maker where we will insert the new HTML and get it's parent
+ if (!selection.isCollapsed())
+ editor.getDoc().execCommand('Delete', false, null);
+
+ parentNode = selection.getNode();
+
+ // Parse the fragment within the context of the parent node
+ args = {context : parentNode.nodeName.toLowerCase()};
+ fragment = parser.parse(value, args);
+
+ // Move the caret to a more suitable location
+ node = fragment.lastChild;
+ if (node.attr('id') == 'mce_marker') {
+ marker = node;
+
+ for (node = node.prev; node; node = node.walk(true)) {
+ if (node.type == 3 || !dom.isBlock(node.name)) {
+ node.parent.insert(marker, node, node.name === 'br');
+ break;
+ }
+ }
+ }
+
+ // If parser says valid we can insert the contents into that parent
+ if (!args.invalid) {
+ value = serializer.serialize(fragment);
+
+ // Check if parent is empty or only has one BR element then set the innerHTML of that parent
+ node = parentNode.firstChild;
+ node2 = parentNode.lastChild;
+ if (!node || (node === node2 && node.nodeName === 'BR'))
+ dom.setHTML(parentNode, value);
+ else
+ selection.setContent(value);
+ } else {
+ // If the fragment was invalid within that context then we need
+ // to parse and process the parent it's inserted into
+
+ // Insert bookmark node and get the parent
+ selection.setContent(bookmarkHtml);
+ parentNode = editor.selection.getNode();
+ rootNode = editor.getBody();
+
+ // Opera will return the document node when selection is in root
+ if (parentNode.nodeType == 9)
+ parentNode = node = rootNode;
+ else
+ node = parentNode;
+
+ // Find the ancestor just before the root element
+ while (node !== rootNode) {
+ parentNode = node;
+ node = node.parentNode;
+ }
+
+ // Get the outer/inner HTML depending on if we are in the root and parser and serialize that
+ value = parentNode == rootNode ? rootNode.innerHTML : dom.getOuterHTML(parentNode);
+ value = serializer.serialize(
+ parser.parse(
+ // Need to replace by using a function since $ in the contents would otherwise be a problem
+ value.replace(/<span (id="mce_marker"|id=mce_marker).+?<\/span>/i, function() {
+ return serializer.serialize(fragment);
+ })
+ )
+ );
+
+ // Set the inner/outer HTML depending on if we are in the root or not
+ if (parentNode == rootNode)
+ dom.setHTML(rootNode, value);
+ else
+ dom.setOuterHTML(parentNode, value);
+ }
+
+ marker = dom.get('mce_marker');
+
+ // Scroll range into view scrollIntoView on element can't be used since it will scroll the main view port as well
+ nodeRect = dom.getRect(marker);
+ viewPortRect = dom.getViewPort(editor.getWin());
+
+ // Check if node is out side the viewport if it is then scroll to it
+ if ((nodeRect.y + nodeRect.h > viewPortRect.y + viewPortRect.h || nodeRect.y < viewPortRect.y) ||
+ (nodeRect.x > viewPortRect.x + viewPortRect.w || nodeRect.x < viewPortRect.x)) {
+ viewportBodyElement = tinymce.isIE ? editor.getDoc().documentElement : editor.getBody();
+ viewportBodyElement.scrollLeft = nodeRect.x;
+ viewportBodyElement.scrollTop = nodeRect.y - viewPortRect.h + 25;
+ }
+
+ // Move selection before marker and remove it
+ rng = dom.createRng();
+
+ // If previous sibling is a text node set the selection to the end of that node
+ node = marker.previousSibling;
+ if (node && node.nodeType == 3) {
+ rng.setStart(node, node.nodeValue.length);
+ } else {
+ // If the previous sibling isn't a text node or doesn't exist set the selection before the marker node
+ rng.setStartBefore(marker);
+ rng.setEndBefore(marker);
+ }
+
+ // Remove the marker node and set the new range
+ dom.remove(marker);
+ selection.setRng(rng);
+
+ // Dispatch after event and add any visual elements needed
+ selection.onSetContent.dispatch(selection, args);
+ editor.addVisual();
+ },
+
+ mceInsertRawHTML : function(command, ui, value) {
+ selection.setContent('tiny_mce_marker');
+ editor.setContent(editor.getContent().replace(/tiny_mce_marker/g, function() { return value }));
+ },
+
+ mceToggleFormat : function(command, ui, value) {
+ toggleFormat(value);
+ },
+
+ mceSetContent : function(command, ui, value) {
+ editor.setContent(value);
+ },
+
+ 'Indent,Outdent' : function(command) {
+ var intentValue, indentUnit, value;
+
+ // Setup indent level
+ intentValue = settings.indentation;
+ indentUnit = /[a-z%]+$/i.exec(intentValue);
+ intentValue = parseInt(intentValue);
+
+ if (!queryCommandState('InsertUnorderedList') && !queryCommandState('InsertOrderedList')) {
+ // If forced_root_blocks is set to false we don't have a block to indent so lets create a div
+ if (!settings.forced_root_block && !dom.getParent(selection.getNode(), dom.isBlock)) {
+ formatter.apply('div');
+ }
+
+ each(selection.getSelectedBlocks(), function(element) {
+ if (command == 'outdent') {
+ value = Math.max(0, parseInt(element.style.paddingLeft || 0) - intentValue);
+ dom.setStyle(element, 'paddingLeft', value ? value + indentUnit : '');
+ } else
+ dom.setStyle(element, 'paddingLeft', (parseInt(element.style.paddingLeft || 0) + intentValue) + indentUnit);
+ });
+ } else
+ execNativeCommand(command);
+ },
+
+ mceRepaint : function() {
+ var bookmark;
+
+ if (tinymce.isGecko) {
+ try {
+ storeSelection(TRUE);
+
+ if (selection.getSel())
+ selection.getSel().selectAllChildren(editor.getBody());
+
+ selection.collapse(TRUE);
+ restoreSelection();
+ } catch (ex) {
+ // Ignore
+ }
+ }
+ },
+
+ mceToggleFormat : function(command, ui, value) {
+ formatter.toggle(value);
+ },
+
+ InsertHorizontalRule : function() {
+ editor.execCommand('mceInsertContent', false, '<hr />');
+ },
+
+ mceToggleVisualAid : function() {
+ editor.hasVisual = !editor.hasVisual;
+ editor.addVisual();
+ },
+
+ mceReplaceContent : function(command, ui, value) {
+ editor.execCommand('mceInsertContent', false, value.replace(/\{\$selection\}/g, selection.getContent({format : 'text'})));
+ },
+
+ mceInsertLink : function(command, ui, value) {
+ var anchor;
+
+ if (typeof(value) == 'string')
+ value = {href : value};
+
+ anchor = dom.getParent(selection.getNode(), 'a');
+
+ // Spaces are never valid in URLs and it's a very common mistake for people to make so we fix it here.
+ value.href = value.href.replace(' ', '%20');
+
+ // Remove existing links if there could be child links or that the href isn't specified
+ if (!anchor || !value.href) {
+ formatter.remove('link');
+ }
+
+ // Apply new link to selection
+ if (value.href) {
+ formatter.apply('link', value, anchor);
+ }
+ },
+
+ selectAll : function() {
+ var root = dom.getRoot(), rng = dom.createRng();
+
+ rng.setStart(root, 0);
+ rng.setEnd(root, root.childNodes.length);
+
+ editor.selection.setRng(rng);
+ }
+ });
+
+ // Add queryCommandState overrides
+ addCommands({
+ // Override justify commands
+ 'JustifyLeft,JustifyCenter,JustifyRight,JustifyFull' : function(command) {
+ var name = 'align' + command.substring(7);
+ var nodes = selection.isCollapsed() ? [dom.getParent(selection.getNode(), dom.isBlock)] : selection.getSelectedBlocks();
+ var matches = tinymce.map(nodes, function(node) {
+ return !!formatter.matchNode(node, name);
+ });
+ return tinymce.inArray(matches, TRUE) !== -1;
+ },
+
+ 'Bold,Italic,Underline,Strikethrough,Superscript,Subscript' : function(command) {
+ return isFormatMatch(command);
+ },
+
+ mceBlockQuote : function() {
+ return isFormatMatch('blockquote');
+ },
+
+ Outdent : function() {
+ var node;
+
+ if (settings.inline_styles) {
+ if ((node = dom.getParent(selection.getStart(), dom.isBlock)) && parseInt(node.style.paddingLeft) > 0)
+ return TRUE;
+
+ if ((node = dom.getParent(selection.getEnd(), dom.isBlock)) && parseInt(node.style.paddingLeft) > 0)
+ return TRUE;
+ }
+
+ return queryCommandState('InsertUnorderedList') || queryCommandState('InsertOrderedList') || (!settings.inline_styles && !!dom.getParent(selection.getNode(), 'BLOCKQUOTE'));
+ },
+
+ 'InsertUnorderedList,InsertOrderedList' : function(command) {
+ return dom.getParent(selection.getNode(), command == 'insertunorderedlist' ? 'UL' : 'OL');
+ }
+ }, 'state');
+
+ // Add queryCommandValue overrides
+ addCommands({
+ 'FontSize,FontName' : function(command) {
+ var value = 0, parent;
+
+ if (parent = dom.getParent(selection.getNode(), 'span')) {
+ if (command == 'fontsize')
+ value = parent.style.fontSize;
+ else
+ value = parent.style.fontFamily.replace(/, /g, ',').replace(/[\'\"]/g, '').toLowerCase();
+ }
+
+ return value;
+ }
+ }, 'value');
+
+ // Add undo manager logic
+ addCommands({
+ Undo : function() {
+ editor.undoManager.undo();
+ },
+
+ Redo : function() {
+ editor.undoManager.redo();
+ }
+ });
+ };
+})(tinymce);
+
+(function(tinymce) {
+ var Dispatcher = tinymce.util.Dispatcher;
+
+ tinymce.UndoManager = function(editor) {
+ var self, index = 0, data = [], beforeBookmark, onAdd, onUndo, onRedo;
+
+ function getContent() {
+ // Remove whitespace before/after and remove pure bogus nodes
+ return tinymce.trim(editor.getContent({format : 'raw', no_events : 1}).replace(/<span[^>]+data-mce-bogus[^>]+>[\u200B\uFEFF]+<\/span>/g, ''));
+ };
+
+ function addNonTypingUndoLevel() {
+ self.typing = false;
+ self.add();
+ };
+
+ // Create event instances
+ onBeforeAdd = new Dispatcher(self);
+ onAdd = new Dispatcher(self);
+ onUndo = new Dispatcher(self);
+ onRedo = new Dispatcher(self);
+
+ // Pass though onAdd event from UndoManager to Editor as onChange
+ onAdd.add(function(undoman, level) {
+ if (undoman.hasUndo())
+ return editor.onChange.dispatch(editor, level, undoman);
+ });
+
+ // Pass though onUndo event from UndoManager to Editor
+ onUndo.add(function(undoman, level) {
+ return editor.onUndo.dispatch(editor, level, undoman);
+ });
+
+ // Pass though onRedo event from UndoManager to Editor
+ onRedo.add(function(undoman, level) {
+ return editor.onRedo.dispatch(editor, level, undoman);
+ });
+
+ // Add initial undo level when the editor is initialized
+ editor.onInit.add(function() {
+ self.add();
+ });
+
+ // Get position before an execCommand is processed
+ editor.onBeforeExecCommand.add(function(ed, cmd, ui, val, args) {
+ if (cmd != 'Undo' && cmd != 'Redo' && cmd != 'mceRepaint' && (!args || !args.skip_undo)) {
+ self.beforeChange();
+ }
+ });
+
+ // Add undo level after an execCommand call was made
+ editor.onExecCommand.add(function(ed, cmd, ui, val, args) {
+ if (cmd != 'Undo' && cmd != 'Redo' && cmd != 'mceRepaint' && (!args || !args.skip_undo)) {
+ self.add();
+ }
+ });
+
+ // Add undo level on save contents, drag end and blur/focusout
+ editor.onSaveContent.add(addNonTypingUndoLevel);
+ editor.dom.bind(editor.dom.getRoot(), 'dragend', addNonTypingUndoLevel);
+ editor.dom.bind(editor.getDoc(), tinymce.isGecko ? 'blur' : 'focusout', function(e) {
+ if (!editor.removed && self.typing) {
+ addNonTypingUndoLevel();
+ }
+ });
+
+ editor.onKeyUp.add(function(editor, e) {
+ var keyCode = e.keyCode;
+
+ if ((keyCode >= 33 && keyCode <= 36) || (keyCode >= 37 && keyCode <= 40) || keyCode == 45 || keyCode == 13 || e.ctrlKey) {
+ addNonTypingUndoLevel();
+ }
+ });
+
+ editor.onKeyDown.add(function(editor, e) {
+ var keyCode = e.keyCode;
+
+ // Is caracter positon keys left,right,up,down,home,end,pgdown,pgup,enter
+ if ((keyCode >= 33 && keyCode <= 36) || (keyCode >= 37 && keyCode <= 40) || keyCode == 45) {
+ if (self.typing) {
+ addNonTypingUndoLevel();
+ }
+
+ return;
+ }
+
+ // If key isn't shift,ctrl,alt,capslock,metakey
+ if ((keyCode < 16 || keyCode > 20) && keyCode != 224 && keyCode != 91 && !self.typing) {
+ self.beforeChange();
+ self.typing = true;
+ self.add();
+ }
+ });
+
+ editor.onMouseDown.add(function(editor, e) {
+ if (self.typing) {
+ addNonTypingUndoLevel();
+ }
+ });
+
+ // Add keyboard shortcuts for undo/redo keys
+ editor.addShortcut('ctrl+z', 'undo_desc', 'Undo');
+ editor.addShortcut('ctrl+y', 'redo_desc', 'Redo');
+
+ self = {
+ // Explose for debugging reasons
+ data : data,
+
+ typing : false,
+
+ onBeforeAdd: onBeforeAdd,
+
+ onAdd : onAdd,
+
+ onUndo : onUndo,
+
+ onRedo : onRedo,
+
+ beforeChange : function() {
+ beforeBookmark = editor.selection.getBookmark(2, true);
+ },
+
+ add : function(level) {
+ var i, settings = editor.settings, lastLevel;
+
+ level = level || {};
+ level.content = getContent();
+
+ self.onBeforeAdd.dispatch(self, level);
+
+ // Add undo level if needed
+ lastLevel = data[index];
+ if (lastLevel && lastLevel.content == level.content)
+ return null;
+
+ // Set before bookmark on previous level
+ if (data[index])
+ data[index].beforeBookmark = beforeBookmark;
+
+ // Time to compress
+ if (settings.custom_undo_redo_levels) {
+ if (data.length > settings.custom_undo_redo_levels) {
+ for (i = 0; i < data.length - 1; i++)
+ data[i] = data[i + 1];
+
+ data.length--;
+ index = data.length;
+ }
+ }
+
+ // Get a non intrusive normalized bookmark
+ level.bookmark = editor.selection.getBookmark(2, true);
+
+ // Crop array if needed
+ if (index < data.length - 1)
+ data.length = index + 1;
+
+ data.push(level);
+ index = data.length - 1;
+
+ self.onAdd.dispatch(self, level);
+ editor.isNotDirty = 0;
+
+ return level;
+ },
+
+ undo : function() {
+ var level, i;
+
+ if (self.typing) {
+ self.add();
+ self.typing = false;
+ }
+
+ if (index > 0) {
+ level = data[--index];
+
+ editor.setContent(level.content, {format : 'raw'});
+ editor.selection.moveToBookmark(level.beforeBookmark);
+
+ self.onUndo.dispatch(self, level);
+ }
+
+ return level;
+ },
+
+ redo : function() {
+ var level;
+
+ if (index < data.length - 1) {
+ level = data[++index];
+
+ editor.setContent(level.content, {format : 'raw'});
+ editor.selection.moveToBookmark(level.bookmark);
+
+ self.onRedo.dispatch(self, level);
+ }
+
+ return level;
+ },
+
+ clear : function() {
+ data = [];
+ index = 0;
+ self.typing = false;
+ },
+
+ hasUndo : function() {
+ return index > 0 || this.typing;
+ },
+
+ hasRedo : function() {
+ return index < data.length - 1 && !this.typing;
+ }
+ };
+
+ return self;
+ };
+})(tinymce);
+
+tinymce.ForceBlocks = function(editor) {
+ var settings = editor.settings, dom = editor.dom, selection = editor.selection, blockElements = editor.schema.getBlockElements();
+
+ function addRootBlocks() {
+ var node = selection.getStart(), rootNode = editor.getBody(), rng, startContainer, startOffset, endContainer, endOffset, rootBlockNode, tempNode, offset = -0xFFFFFF, wrapped, isInEditorDocument;
+
+ if (!node || node.nodeType !== 1 || !settings.forced_root_block)
+ return;
+
+ // Check if node is wrapped in block
+ while (node && node != rootNode) {
+ if (blockElements[node.nodeName])
+ return;
+
+ node = node.parentNode;
+ }
+
+ // Get current selection
+ rng = selection.getRng();
+ if (rng.setStart) {
+ startContainer = rng.startContainer;
+ startOffset = rng.startOffset;
+ endContainer = rng.endContainer;
+ endOffset = rng.endOffset;
+ } else {
+ // Force control range into text range
+ if (rng.item) {
+ node = rng.item(0);
+ rng = editor.getDoc().body.createTextRange();
+ rng.moveToElementText(node);
+ }
+
+ isInEditorDocument = rng.parentElement().ownerDocument === editor.getDoc();
+ tmpRng = rng.duplicate();
+ tmpRng.collapse(true);
+ startOffset = tmpRng.move('character', offset) * -1;
+
+ if (!tmpRng.collapsed) {
+ tmpRng = rng.duplicate();
+ tmpRng.collapse(false);
+ endOffset = (tmpRng.move('character', offset) * -1) - startOffset;
+ }
+ }
+
+ // Wrap non block elements and text nodes
+ node = rootNode.firstChild;
+ while (node) {
+ if (node.nodeType === 3 || (node.nodeType == 1 && !blockElements[node.nodeName])) {
+ if (!rootBlockNode) {
+ rootBlockNode = dom.create(settings.forced_root_block);
+ node.parentNode.insertBefore(rootBlockNode, node);
+ wrapped = true;
+ }
+
+ tempNode = node;
+ node = node.nextSibling;
+ rootBlockNode.appendChild(tempNode);
+ } else {
+ rootBlockNode = null;
+ node = node.nextSibling;
+ }
+ }
+
+ if (wrapped) {
+ if (rng.setStart) {
+ rng.setStart(startContainer, startOffset);
+ rng.setEnd(endContainer, endOffset);
+ selection.setRng(rng);
+ } else {
+ // Only select if the previous selection was inside the document to prevent auto focus in quirks mode
+ if (isInEditorDocument) {
+ try {
+ rng = editor.getDoc().body.createTextRange();
+ rng.moveToElementText(rootNode);
+ rng.collapse(true);
+ rng.moveStart('character', startOffset);
+
+ if (endOffset > 0)
+ rng.moveEnd('character', endOffset);
+
+ rng.select();
+ } catch (ex) {
+ // Ignore
+ }
+ }
+ }
+
+ editor.nodeChanged();
+ }
+ };
+
+ // Force root blocks
+ if (settings.forced_root_block) {
+ editor.onKeyUp.add(addRootBlocks);
+ editor.onNodeChange.add(addRootBlocks);
+ }
+};
+
+(function(tinymce) {
+ // Shorten names
+ var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, extend = tinymce.extend;
+
+ tinymce.create('tinymce.ControlManager', {
+ ControlManager : function(ed, s) {
+ var t = this, i;
+
+ s = s || {};
+ t.editor = ed;
+ t.controls = {};
+ t.onAdd = new tinymce.util.Dispatcher(t);
+ t.onPostRender = new tinymce.util.Dispatcher(t);
+ t.prefix = s.prefix || ed.id + '_';
+ t._cls = {};
+
+ t.onPostRender.add(function() {
+ each(t.controls, function(c) {
+ c.postRender();
+ });
+ });
+ },
+
+ get : function(id) {
+ return this.controls[this.prefix + id] || this.controls[id];
+ },
+
+ setActive : function(id, s) {
+ var c = null;
+
+ if (c = this.get(id))
+ c.setActive(s);
+
+ return c;
+ },
+
+ setDisabled : function(id, s) {
+ var c = null;
+
+ if (c = this.get(id))
+ c.setDisabled(s);
+
+ return c;
+ },
+
+ add : function(c) {
+ var t = this;
+
+ if (c) {
+ t.controls[c.id] = c;
+ t.onAdd.dispatch(c, t);
+ }
+
+ return c;
+ },
+
+ createControl : function(name) {
+ var ctrl, i, l, self = this, editor = self.editor, factories, ctrlName;
+
+ // Build control factory cache
+ if (!self.controlFactories) {
+ self.controlFactories = [];
+ each(editor.plugins, function(plugin) {
+ if (plugin.createControl) {
+ self.controlFactories.push(plugin);
+ }
+ });
+ }
+
+ // Create controls by asking cached factories
+ factories = self.controlFactories;
+ for (i = 0, l = factories.length; i < l; i++) {
+ ctrl = factories[i].createControl(name, self);
+
+ if (ctrl) {
+ return self.add(ctrl);
+ }
+ }
+
+ // Create sepearator
+ if (name === "|" || name === "separator") {
+ return self.createSeparator();
+ }
+
+ // Create control from button collection
+ if (editor.buttons && (ctrl = editor.buttons[name])) {
+ return self.createButton(name, ctrl);
+ }
+
+ return self.add(ctrl);
+ },
+
+ createDropMenu : function(id, s, cc) {
+ var t = this, ed = t.editor, c, bm, v, cls;
+
+ s = extend({
+ 'class' : 'mceDropDown',
+ constrain : ed.settings.constrain_menus
+ }, s);
+
+ s['class'] = s['class'] + ' ' + ed.getParam('skin') + 'Skin';
+ if (v = ed.getParam('skin_variant'))
+ s['class'] += ' ' + ed.getParam('skin') + 'Skin' + v.substring(0, 1).toUpperCase() + v.substring(1);
+
+ s['class'] += ed.settings.directionality == "rtl" ? ' mceRtl' : '';
+
+ id = t.prefix + id;
+ cls = cc || t._cls.dropmenu || tinymce.ui.DropMenu;
+ c = t.controls[id] = new cls(id, s);
+ c.onAddItem.add(function(c, o) {
+ var s = o.settings;
+
+ s.title = ed.getLang(s.title, s.title);
+
+ if (!s.onclick) {
+ s.onclick = function(v) {
+ if (s.cmd)
+ ed.execCommand(s.cmd, s.ui || false, s.value);
+ };
+ }
+ });
+
+ ed.onRemove.add(function() {
+ c.destroy();
+ });
+
+ // Fix for bug #1897785, #1898007
+ if (tinymce.isIE) {
+ c.onShowMenu.add(function() {
+ // IE 8 needs focus in order to store away a range with the current collapsed caret location
+ ed.focus();
+
+ bm = ed.selection.getBookmark(1);
+ });
+
+ c.onHideMenu.add(function() {
+ if (bm) {
+ ed.selection.moveToBookmark(bm);
+ bm = 0;
+ }
+ });
+ }
+
+ return t.add(c);
+ },
+
+ createListBox : function(id, s, cc) {
+ var t = this, ed = t.editor, cmd, c, cls;
+
+ if (t.get(id))
+ return null;
+
+ s.title = ed.translate(s.title);
+ s.scope = s.scope || ed;
+
+ if (!s.onselect) {
+ s.onselect = function(v) {
+ ed.execCommand(s.cmd, s.ui || false, v || s.value);
+ };
+ }
+
+ s = extend({
+ title : s.title,
+ 'class' : 'mce_' + id,
+ scope : s.scope,
+ control_manager : t
+ }, s);
+
+ id = t.prefix + id;
+
+
+ function useNativeListForAccessibility(ed) {
+ return ed.settings.use_accessible_selects && !tinymce.isGecko
+ }
+
+ if (ed.settings.use_native_selects || useNativeListForAccessibility(ed))
+ c = new tinymce.ui.NativeListBox(id, s);
+ else {
+ cls = cc || t._cls.listbox || tinymce.ui.ListBox;
+ c = new cls(id, s, ed);
+ }
+
+ t.controls[id] = c;
+
+ // Fix focus problem in Safari
+ if (tinymce.isWebKit) {
+ c.onPostRender.add(function(c, n) {
+ // Store bookmark on mousedown
+ Event.add(n, 'mousedown', function() {
+ ed.bookmark = ed.selection.getBookmark(1);
+ });
+
+ // Restore on focus, since it might be lost
+ Event.add(n, 'focus', function() {
+ ed.selection.moveToBookmark(ed.bookmark);
+ ed.bookmark = null;
+ });
+ });
+ }
+
+ if (c.hideMenu)
+ ed.onMouseDown.add(c.hideMenu, c);
+
+ return t.add(c);
+ },
+
+ createButton : function(id, s, cc) {
+ var t = this, ed = t.editor, o, c, cls;
+
+ if (t.get(id))
+ return null;
+
+ s.title = ed.translate(s.title);
+ s.label = ed.translate(s.label);
+ s.scope = s.scope || ed;
+
+ if (!s.onclick && !s.menu_button) {
+ s.onclick = function() {
+ ed.execCommand(s.cmd, s.ui || false, s.value);
+ };
+ }
+
+ s = extend({
+ title : s.title,
+ 'class' : 'mce_' + id,
+ unavailable_prefix : ed.getLang('unavailable', ''),
+ scope : s.scope,
+ control_manager : t
+ }, s);
+
+ id = t.prefix + id;
+
+ if (s.menu_button) {
+ cls = cc || t._cls.menubutton || tinymce.ui.MenuButton;
+ c = new cls(id, s, ed);
+ ed.onMouseDown.add(c.hideMenu, c);
+ } else {
+ cls = t._cls.button || tinymce.ui.Button;
+ c = new cls(id, s, ed);
+ }
+
+ return t.add(c);
+ },
+
+ createMenuButton : function(id, s, cc) {
+ s = s || {};
+ s.menu_button = 1;
+
+ return this.createButton(id, s, cc);
+ },
+
+ createSplitButton : function(id, s, cc) {
+ var t = this, ed = t.editor, cmd, c, cls;
+
+ if (t.get(id))
+ return null;
+
+ s.title = ed.translate(s.title);
+ s.scope = s.scope || ed;
+
+ if (!s.onclick) {
+ s.onclick = function(v) {
+ ed.execCommand(s.cmd, s.ui || false, v || s.value);
+ };
+ }
+
+ if (!s.onselect) {
+ s.onselect = function(v) {
+ ed.execCommand(s.cmd, s.ui || false, v || s.value);
+ };
+ }
+
+ s = extend({
+ title : s.title,
+ 'class' : 'mce_' + id,
+ scope : s.scope,
+ control_manager : t
+ }, s);
+
+ id = t.prefix + id;
+ cls = cc || t._cls.splitbutton || tinymce.ui.SplitButton;
+ c = t.add(new cls(id, s, ed));
+ ed.onMouseDown.add(c.hideMenu, c);
+
+ return c;
+ },
+
+ createColorSplitButton : function(id, s, cc) {
+ var t = this, ed = t.editor, cmd, c, cls, bm;
+
+ if (t.get(id))
+ return null;
+
+ s.title = ed.translate(s.title);
+ s.scope = s.scope || ed;
+
+ if (!s.onclick) {
+ s.onclick = function(v) {
+ if (tinymce.isIE)
+ bm = ed.selection.getBookmark(1);
+
+ ed.execCommand(s.cmd, s.ui || false, v || s.value);
+ };
+ }
+
+ if (!s.onselect) {
+ s.onselect = function(v) {
+ ed.execCommand(s.cmd, s.ui || false, v || s.value);
+ };
+ }
+
+ s = extend({
+ title : s.title,
+ 'class' : 'mce_' + id,
+ 'menu_class' : ed.getParam('skin') + 'Skin',
+ scope : s.scope,
+ more_colors_title : ed.getLang('more_colors')
+ }, s);
+
+ id = t.prefix + id;
+ cls = cc || t._cls.colorsplitbutton || tinymce.ui.ColorSplitButton;
+ c = new cls(id, s, ed);
+ ed.onMouseDown.add(c.hideMenu, c);
+
+ // Remove the menu element when the editor is removed
+ ed.onRemove.add(function() {
+ c.destroy();
+ });
+
+ // Fix for bug #1897785, #1898007
+ if (tinymce.isIE) {
+ c.onShowMenu.add(function() {
+ // IE 8 needs focus in order to store away a range with the current collapsed caret location
+ ed.focus();
+ bm = ed.selection.getBookmark(1);
+ });
+
+ c.onHideMenu.add(function() {
+ if (bm) {
+ ed.selection.moveToBookmark(bm);
+ bm = 0;
+ }
+ });
+ }
+
+ return t.add(c);
+ },
+
+ createToolbar : function(id, s, cc) {
+ var c, t = this, cls;
+
+ id = t.prefix + id;
+ cls = cc || t._cls.toolbar || tinymce.ui.Toolbar;
+ c = new cls(id, s, t.editor);
+
+ if (t.get(id))
+ return null;
+
+ return t.add(c);
+ },
+
+ createToolbarGroup : function(id, s, cc) {
+ var c, t = this, cls;
+ id = t.prefix + id;
+ cls = cc || this._cls.toolbarGroup || tinymce.ui.ToolbarGroup;
+ c = new cls(id, s, t.editor);
+
+ if (t.get(id))
+ return null;
+
+ return t.add(c);
+ },
+
+ createSeparator : function(cc) {
+ var cls = cc || this._cls.separator || tinymce.ui.Separator;
+
+ return new cls();
+ },
+
+ setControlType : function(n, c) {
+ return this._cls[n.toLowerCase()] = c;
+ },
+
+ destroy : function() {
+ each(this.controls, function(c) {
+ c.destroy();
+ });
+
+ this.controls = null;
+ }
+ });
+})(tinymce);
+
+(function(tinymce) {
+ var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each, isIE = tinymce.isIE, isOpera = tinymce.isOpera;
+
+ tinymce.create('tinymce.WindowManager', {
+ WindowManager : function(ed) {
+ var t = this;
+
+ t.editor = ed;
+ t.onOpen = new Dispatcher(t);
+ t.onClose = new Dispatcher(t);
+ t.params = {};
+ t.features = {};
+ },
+
+ open : function(s, p) {
+ var t = this, f = '', x, y, mo = t.editor.settings.dialog_type == 'modal', w, sw, sh, vp = tinymce.DOM.getViewPort(), u;
+
+ // Default some options
+ s = s || {};
+ p = p || {};
+ sw = isOpera ? vp.w : screen.width; // Opera uses windows inside the Opera window
+ sh = isOpera ? vp.h : screen.height;
+ s.name = s.name || 'mc_' + new Date().getTime();
+ s.width = parseInt(s.width || 320);
+ s.height = parseInt(s.height || 240);
+ s.resizable = true;
+ s.left = s.left || parseInt(sw / 2.0) - (s.width / 2.0);
+ s.top = s.top || parseInt(sh / 2.0) - (s.height / 2.0);
+ p.inline = false;
+ p.mce_width = s.width;
+ p.mce_height = s.height;
+ p.mce_auto_focus = s.auto_focus;
+
+ if (mo) {
+ if (isIE) {
+ s.center = true;
+ s.help = false;
+ s.dialogWidth = s.width + 'px';
+ s.dialogHeight = s.height + 'px';
+ s.scroll = s.scrollbars || false;
+ }
+ }
+
+ // Build features string
+ each(s, function(v, k) {
+ if (tinymce.is(v, 'boolean'))
+ v = v ? 'yes' : 'no';
+
+ if (!/^(name|url)$/.test(k)) {
+ if (isIE && mo)
+ f += (f ? ';' : '') + k + ':' + v;
+ else
+ f += (f ? ',' : '') + k + '=' + v;
+ }
+ });
+
+ t.features = s;
+ t.params = p;
+ t.onOpen.dispatch(t, s, p);
+
+ u = s.url || s.file;
+ u = tinymce._addVer(u);
+
+ try {
+ if (isIE && mo) {
+ w = 1;
+ window.showModalDialog(u, window, f);
+ } else
+ w = window.open(u, s.name, f);
+ } catch (ex) {
+ // Ignore
+ }
+
+ if (!w)
+ alert(t.editor.getLang('popup_blocked'));
+ },
+
+ close : function(w) {
+ w.close();
+ this.onClose.dispatch(this);
+ },
+
+ createInstance : function(cl, a, b, c, d, e) {
+ var f = tinymce.resolve(cl);
+
+ return new f(a, b, c, d, e);
+ },
+
+ confirm : function(t, cb, s, w) {
+ w = w || window;
+
+ cb.call(s || this, w.confirm(this._decode(this.editor.getLang(t, t))));
+ },
+
+ alert : function(tx, cb, s, w) {
+ var t = this;
+
+ w = w || window;
+ w.alert(t._decode(t.editor.getLang(tx, tx)));
+
+ if (cb)
+ cb.call(s || t);
+ },
+
+ resizeBy : function(dw, dh, win) {
+ win.resizeBy(dw, dh);
+ },
+
+ // Internal functions
+
+ _decode : function(s) {
+ return tinymce.DOM.decode(s).replace(/\\n/g, '\n');
+ }
+ });
+}(tinymce));
+(function(tinymce) {
+ tinymce.Formatter = function(ed) {
+ var formats = {},
+ each = tinymce.each,
+ dom = ed.dom,
+ selection = ed.selection,
+ TreeWalker = tinymce.dom.TreeWalker,
+ rangeUtils = new tinymce.dom.RangeUtils(dom),
+ isValid = ed.schema.isValidChild,
+ isBlock = dom.isBlock,
+ forcedRootBlock = ed.settings.forced_root_block,
+ nodeIndex = dom.nodeIndex,
+ INVISIBLE_CHAR = tinymce.isGecko ? '\u200B' : '\uFEFF',
+ MCE_ATTR_RE = /^(src|href|style)$/,
+ FALSE = false,
+ TRUE = true,
+ formatChangeData,
+ undef,
+ getContentEditable = dom.getContentEditable;
+
+ function isArray(obj) {
+ return obj instanceof Array;
+ };
+
+ function getParents(node, selector) {
+ return dom.getParents(node, selector, dom.getRoot());
+ };
+
+ function isCaretNode(node) {
+ return node.nodeType === 1 && node.id === '_mce_caret';
+ };
+
+ function defaultFormats() {
+ register({
+ alignleft : [
+ {selector : 'figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'left'}, defaultBlock: 'div'},
+ {selector : 'img,table', collapsed : false, styles : {'float' : 'left'}}
+ ],
+
+ aligncenter : [
+ {selector : 'figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'center'}, defaultBlock: 'div'},
+ {selector : 'img', collapsed : false, styles : {display : 'block', marginLeft : 'auto', marginRight : 'auto'}},
+ {selector : 'table', collapsed : false, styles : {marginLeft : 'auto', marginRight : 'auto'}}
+ ],
+
+ alignright : [
+ {selector : 'figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'right'}, defaultBlock: 'div'},
+ {selector : 'img,table', collapsed : false, styles : {'float' : 'right'}}
+ ],
+
+ alignfull : [
+ {selector : 'figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles : {textAlign : 'justify'}, defaultBlock: 'div'}
+ ],
+
+ bold : [
+ {inline : 'strong', remove : 'all'},
+ {inline : 'span', styles : {fontWeight : 'bold'}},
+ {inline : 'b', remove : 'all'}
+ ],
+
+ italic : [
+ {inline : 'em', remove : 'all'},
+ {inline : 'span', styles : {fontStyle : 'italic'}},
+ {inline : 'i', remove : 'all'}
+ ],
+
+ underline : [
+ {inline : 'span', styles : {textDecoration : 'underline'}, exact : true},
+ {inline : 'u', remove : 'all'}
+ ],
+
+ strikethrough : [
+ {inline : 'span', styles : {textDecoration : 'line-through'}, exact : true},
+ {inline : 'strike', remove : 'all'}
+ ],
+
+ forecolor : {inline : 'span', styles : {color : '%value'}, wrap_links : false},
+ hilitecolor : {inline : 'span', styles : {backgroundColor : '%value'}, wrap_links : false},
+ fontname : {inline : 'span', styles : {fontFamily : '%value'}},
+ fontsize : {inline : 'span', styles : {fontSize : '%value'}},
+ fontsize_class : {inline : 'span', attributes : {'class' : '%value'}},
+ blockquote : {block : 'blockquote', wrapper : 1, remove : 'all'},
+ subscript : {inline : 'sub'},
+ superscript : {inline : 'sup'},
+
+ link : {inline : 'a', selector : 'a', remove : 'all', split : true, deep : true,
+ onmatch : function(node) {
+ return true;
+ },
+
+ onformat : function(elm, fmt, vars) {
+ each(vars, function(value, key) {
+ dom.setAttrib(elm, key, value);
+ });
+ }
+ },
+
+ removeformat : [
+ {selector : 'b,strong,em,i,font,u,strike', remove : 'all', split : true, expand : false, block_expand : true, deep : true},
+ {selector : 'span', attributes : ['style', 'class'], remove : 'empty', split : true, expand : false, deep : true},
+ {selector : '*', attributes : ['style', 'class'], split : false, expand : false, deep : true}
+ ]
+ });
+
+ // Register default block formats
+ each('p h1 h2 h3 h4 h5 h6 div address pre div code dt dd samp'.split(/\s/), function(name) {
+ register(name, {block : name, remove : 'all'});
+ });
+
+ // Register user defined formats
+ register(ed.settings.formats);
+ };
+
+ function addKeyboardShortcuts() {
+ // Add some inline shortcuts
+ ed.addShortcut('ctrl+b', 'bold_desc', 'Bold');
+ ed.addShortcut('ctrl+i', 'italic_desc', 'Italic');
+ ed.addShortcut('ctrl+u', 'underline_desc', 'Underline');
+
+ // BlockFormat shortcuts keys
+ for (var i = 1; i <= 6; i++) {
+ ed.addShortcut('ctrl+' + i, '', ['FormatBlock', false, 'h' + i]);
+ }
+
+ ed.addShortcut('ctrl+7', '', ['FormatBlock', false, 'p']);
+ ed.addShortcut('ctrl+8', '', ['FormatBlock', false, 'div']);
+ ed.addShortcut('ctrl+9', '', ['FormatBlock', false, 'address']);
+ };
+
+ // Public functions
+
+ function get(name) {
+ return name ? formats[name] : formats;
+ };
+
+ function register(name, format) {
+ if (name) {
+ if (typeof(name) !== 'string') {
+ each(name, function(format, name) {
+ register(name, format);
+ });
+ } else {
+ // Force format into array and add it to internal collection
+ format = format.length ? format : [format];
+
+ each(format, function(format) {
+ // Set deep to false by default on selector formats this to avoid removing
+ // alignment on images inside paragraphs when alignment is changed on paragraphs
+ if (format.deep === undef)
+ format.deep = !format.selector;
+
+ // Default to true
+ if (format.split === undef)
+ format.split = !format.selector || format.inline;
+
+ // Default to true
+ if (format.remove === undef && format.selector && !format.inline)
+ format.remove = 'none';
+
+ // Mark format as a mixed format inline + block level
+ if (format.selector && format.inline) {
+ format.mixed = true;
+ format.block_expand = true;
+ }
+
+ // Split classes if needed
+ if (typeof(format.classes) === 'string')
+ format.classes = format.classes.split(/\s+/);
+ });
+
+ formats[name] = format;
+ }
+ }
+ };
+
+ var getTextDecoration = function(node) {
+ var decoration;
+
+ ed.dom.getParent(node, function(n) {
+ decoration = ed.dom.getStyle(n, 'text-decoration');
+ return decoration && decoration !== 'none';
+ });
+
+ return decoration;
+ };
+
+ var processUnderlineAndColor = function(node) {
+ var textDecoration;
+ if (node.nodeType === 1 && node.parentNode && node.parentNode.nodeType === 1) {
+ textDecoration = getTextDecoration(node.parentNode);
+ if (ed.dom.getStyle(node, 'color') && textDecoration) {
+ ed.dom.setStyle(node, 'text-decoration', textDecoration);
+ } else if (ed.dom.getStyle(node, 'textdecoration') === textDecoration) {
+ ed.dom.setStyle(node, 'text-decoration', null);
+ }
+ }
+ };
+
+ function apply(name, vars, node) {
+ var formatList = get(name), format = formatList[0], bookmark, rng, i, isCollapsed = selection.isCollapsed();
+
+ function setElementFormat(elm, fmt) {
+ fmt = fmt || format;
+
+ if (elm) {
+ if (fmt.onformat) {
+ fmt.onformat(elm, fmt, vars, node);
+ }
+
+ each(fmt.styles, function(value, name) {
+ dom.setStyle(elm, name, replaceVars(value, vars));
+ });
+
+ each(fmt.attributes, function(value, name) {
+ dom.setAttrib(elm, name, replaceVars(value, vars));
+ });
+
+ each(fmt.classes, function(value) {
+ value = replaceVars(value, vars);
+
+ if (!dom.hasClass(elm, value))
+ dom.addClass(elm, value);
+ });
+ }
+ };
+ function adjustSelectionToVisibleSelection() {
+ function findSelectionEnd(start, end) {
+ var walker = new TreeWalker(end);
+ for (node = walker.current(); node; node = walker.prev()) {
+ if (node.childNodes.length > 1 || node == start || node.tagName == 'BR') {
+ return node;
+ }
+ }
+ };
+
+ // Adjust selection so that a end container with a end offset of zero is not included in the selection
+ // as this isn't visible to the user.
+ var rng = ed.selection.getRng();
+ var start = rng.startContainer;
+ var end = rng.endContainer;
+
+ if (start != end && rng.endOffset === 0) {
+ var newEnd = findSelectionEnd(start, end);
+ var endOffset = newEnd.nodeType == 3 ? newEnd.length : newEnd.childNodes.length;
+
+ rng.setEnd(newEnd, endOffset);
+ }
+
+ return rng;
+ }
+
+ function applyStyleToList(node, bookmark, wrapElm, newWrappers, process){
+ var nodes = [], listIndex = -1, list, startIndex = -1, endIndex = -1, currentWrapElm;
+
+ // find the index of the first child list.
+ each(node.childNodes, function(n, index) {
+ if (n.nodeName === "UL" || n.nodeName === "OL") {
+ listIndex = index;
+ list = n;
+ return false;
+ }
+ });
+
+ // get the index of the bookmarks
+ each(node.childNodes, function(n, index) {
+ if (n.nodeName === "SPAN" && dom.getAttrib(n, "data-mce-type") == "bookmark") {
+ if (n.id == bookmark.id + "_start") {
+ startIndex = index;
+ } else if (n.id == bookmark.id + "_end") {
+ endIndex = index;
+ }
+ }
+ });
+
+ // if the selection spans across an embedded list, or there isn't an embedded list - handle processing normally
+ if (listIndex <= 0 || (startIndex < listIndex && endIndex > listIndex)) {
+ each(tinymce.grep(node.childNodes), process);
+ return 0;
+ } else {
+ currentWrapElm = dom.clone(wrapElm, FALSE);
+
+ // create a list of the nodes on the same side of the list as the selection
+ each(tinymce.grep(node.childNodes), function(n, index) {
+ if ((startIndex < listIndex && index < listIndex) || (startIndex > listIndex && index > listIndex)) {
+ nodes.push(n);
+ n.parentNode.removeChild(n);
+ }
+ });
+
+ // insert the wrapping element either before or after the list.
+ if (startIndex < listIndex) {
+ node.insertBefore(currentWrapElm, list);
+ } else if (startIndex > listIndex) {
+ node.insertBefore(currentWrapElm, list.nextSibling);
+ }
+
+ // add the new nodes to the list.
+ newWrappers.push(currentWrapElm);
+
+ each(nodes, function(node) {
+ currentWrapElm.appendChild(node);
+ });
+
+ return currentWrapElm;
+ }
+ };
+
+ function applyRngStyle(rng, bookmark, node_specific) {
+ var newWrappers = [], wrapName, wrapElm, contentEditable = true;
+
+ // Setup wrapper element
+ wrapName = format.inline || format.block;
+ wrapElm = dom.create(wrapName);
+ setElementFormat(wrapElm);
+
+ rangeUtils.walk(rng, function(nodes) {
+ var currentWrapElm;
+
+ function process(node) {
+ var nodeName, parentName, found, hasContentEditableState, lastContentEditable;
+
+ lastContentEditable = contentEditable;
+ nodeName = node.nodeName.toLowerCase();
+ parentName = node.parentNode.nodeName.toLowerCase();
+
+ // Node has a contentEditable value
+ if (node.nodeType === 1 && getContentEditable(node)) {
+ lastContentEditable = contentEditable;
+ contentEditable = getContentEditable(node) === "true";
+ hasContentEditableState = true; // We don't want to wrap the container only it's children
+ }
+
+ // Stop wrapping on br elements
+ if (isEq(nodeName, 'br')) {
+ currentWrapElm = 0;
+
+ // Remove any br elements when we wrap things
+ if (format.block)
+ dom.remove(node);
+
+ return;
+ }
+
+ // If node is wrapper type
+ if (format.wrapper && matchNode(node, name, vars)) {
+ currentWrapElm = 0;
+ return;
+ }
+
+ // Can we rename the block
+ if (contentEditable && !hasContentEditableState && format.block && !format.wrapper && isTextBlock(nodeName)) {
+ node = dom.rename(node, wrapName);
+ setElementFormat(node);
+ newWrappers.push(node);
+ currentWrapElm = 0;
+ return;
+ }
+
+ // Handle selector patterns
+ if (format.selector) {
+ // Look for matching formats
+ each(formatList, function(format) {
+ // Check collapsed state if it exists
+ if ('collapsed' in format && format.collapsed !== isCollapsed) {
+ return;
+ }
+
+ if (dom.is(node, format.selector) && !isCaretNode(node)) {
+ setElementFormat(node, format);
+ found = true;
+ }
+ });
+
+ // Continue processing if a selector match wasn't found and a inline element is defined
+ if (!format.inline || found) {
+ currentWrapElm = 0;
+ return;
+ }
+ }
+
+ // Is it valid to wrap this item
+ if (contentEditable && !hasContentEditableState && isValid(wrapName, nodeName) && isValid(parentName, wrapName) &&
+ !(!node_specific && node.nodeType === 3 && node.nodeValue.length === 1 && node.nodeValue.charCodeAt(0) === 65279) && !isCaretNode(node)) {
+ // Start wrapping
+ if (!currentWrapElm) {
+ // Wrap the node
+ currentWrapElm = dom.clone(wrapElm, FALSE);
+ node.parentNode.insertBefore(currentWrapElm, node);
+ newWrappers.push(currentWrapElm);
+ }
+
+ currentWrapElm.appendChild(node);
+ } else if (nodeName == 'li' && bookmark) {
+ // Start wrapping - if we are in a list node and have a bookmark, then we will always begin by wrapping in a new element.
+ currentWrapElm = applyStyleToList(node, bookmark, wrapElm, newWrappers, process);
+ } else {
+ // Start a new wrapper for possible children
+ currentWrapElm = 0;
+
+ each(tinymce.grep(node.childNodes), process);
+
+ if (hasContentEditableState) {
+ contentEditable = lastContentEditable; // Restore last contentEditable state from stack
+ }
+
+ // End the last wrapper
+ currentWrapElm = 0;
+ }
+ };
+
+ // Process siblings from range
+ each(nodes, process);
+ });
+
+ // Wrap links inside as well, for example color inside a link when the wrapper is around the link
+ if (format.wrap_links === false) {
+ each(newWrappers, function(node) {
+ function process(node) {
+ var i, currentWrapElm, children;
+
+ if (node.nodeName === 'A') {
+ currentWrapElm = dom.clone(wrapElm, FALSE);
+ newWrappers.push(currentWrapElm);
+
+ children = tinymce.grep(node.childNodes);
+ for (i = 0; i < children.length; i++)
+ currentWrapElm.appendChild(children[i]);
+
+ node.appendChild(currentWrapElm);
+ }
+
+ each(tinymce.grep(node.childNodes), process);
+ };
+
+ process(node);
+ });
+ }
+
+ // Cleanup
+
+ each(newWrappers, function(node) {
+ var childCount;
+
+ function getChildCount(node) {
+ var count = 0;
+
+ each(node.childNodes, function(node) {
+ if (!isWhiteSpaceNode(node) && !isBookmarkNode(node))
+ count++;
+ });
+
+ return count;
+ };
+
+ function mergeStyles(node) {
+ var child, clone;
+
+ each(node.childNodes, function(node) {
+ if (node.nodeType == 1 && !isBookmarkNode(node) && !isCaretNode(node)) {
+ child = node;
+ return FALSE; // break loop
+ }
+ });
+
+ // If child was found and of the same type as the current node
+ if (child && matchName(child, format)) {
+ clone = dom.clone(child, FALSE);
+ setElementFormat(clone);
+
+ dom.replace(clone, node, TRUE);
+ dom.remove(child, 1);
+ }
+
+ return clone || node;
+ };
+
+ childCount = getChildCount(node);
+
+ // Remove empty nodes but only if there is multiple wrappers and they are not block
+ // elements so never remove single <h1></h1> since that would remove the currrent empty block element where the caret is at
+ if ((newWrappers.length > 1 || !isBlock(node)) && childCount === 0) {
+ dom.remove(node, 1);
+ return;
+ }
+
+ if (format.inline || format.wrapper) {
+ // Merges the current node with it's children of similar type to reduce the number of elements
+ if (!format.exact && childCount === 1)
+ node = mergeStyles(node);
+
+ // Remove/merge children
+ each(formatList, function(format) {
+ // Merge all children of similar type will move styles from child to parent
+ // this: <span style="color:red"><b><span style="color:red; font-size:10px">text</span></b></span>
+ // will become: <span style="color:red"><b><span style="font-size:10px">text</span></b></span>
+ each(dom.select(format.inline, node), function(child) {
+ var parent;
+
+ // When wrap_links is set to false we don't want
+ // to remove the format on children within links
+ if (format.wrap_links === false) {
+ parent = child.parentNode;
+
+ do {
+ if (parent.nodeName === 'A')
+ return;
+ } while (parent = parent.parentNode);
+ }
+
+ removeFormat(format, vars, child, format.exact ? child : null);
+ });
+ });
+
+ // Remove child if direct parent is of same type
+ if (matchNode(node.parentNode, name, vars)) {
+ dom.remove(node, 1);
+ node = 0;
+ return TRUE;
+ }
+
+ // Look for parent with similar style format
+ if (format.merge_with_parents) {
+ dom.getParent(node.parentNode, function(parent) {
+ if (matchNode(parent, name, vars)) {
+ dom.remove(node, 1);
+ node = 0;
+ return TRUE;
+ }
+ });
+ }
+
+ // Merge next and previous siblings if they are similar <b>text</b><b>text</b> becomes <b>texttext</b>
+ if (node && format.merge_siblings !== false) {
+ node = mergeSiblings(getNonWhiteSpaceSibling(node), node);
+ node = mergeSiblings(node, getNonWhiteSpaceSibling(node, TRUE));
+ }
+ }
+ });
+ };
+
+ if (format) {
+ if (node) {
+ if (node.nodeType) {
+ rng = dom.createRng();
+ rng.setStartBefore(node);
+ rng.setEndAfter(node);
+ applyRngStyle(expandRng(rng, formatList), null, true);
+ } else {
+ applyRngStyle(node, null, true);
+ }
+ } else {
+ if (!isCollapsed || !format.inline || dom.select('td.mceSelected,th.mceSelected').length) {
+ // Obtain selection node before selection is unselected by applyRngStyle()
+ var curSelNode = ed.selection.getNode();
+
+ // If the formats have a default block and we can't find a parent block then start wrapping it with a DIV this is for forced_root_blocks: false
+ // It's kind of a hack but people should be using the default block type P since all desktop editors work that way
+ if (!forcedRootBlock && formatList[0].defaultBlock && !dom.getParent(curSelNode, dom.isBlock)) {
+ apply(formatList[0].defaultBlock);
+ }
+
+ // Apply formatting to selection
+ ed.selection.setRng(adjustSelectionToVisibleSelection());
+ bookmark = selection.getBookmark();
+ applyRngStyle(expandRng(selection.getRng(TRUE), formatList), bookmark);
+
+ // Colored nodes should be underlined so that the color of the underline matches the text color.
+ if (format.styles && (format.styles.color || format.styles.textDecoration)) {
+ tinymce.walk(curSelNode, processUnderlineAndColor, 'childNodes');
+ processUnderlineAndColor(curSelNode);
+ }
+
+ selection.moveToBookmark(bookmark);
+ moveStart(selection.getRng(TRUE));
+ ed.nodeChanged();
+ } else
+ performCaretAction('apply', name, vars);
+ }
+ }
+ };
+
+ function remove(name, vars, node) {
+ var formatList = get(name), format = formatList[0], bookmark, i, rng, contentEditable = true;
+
+ // Merges the styles for each node
+ function process(node) {
+ var children, i, l, localContentEditable, lastContentEditable, hasContentEditableState;
+
+ // Node has a contentEditable value
+ if (node.nodeType === 1 && getContentEditable(node)) {
+ lastContentEditable = contentEditable;
+ contentEditable = getContentEditable(node) === "true";
+ hasContentEditableState = true; // We don't want to wrap the container only it's children
+ }
+
+ // Grab the children first since the nodelist might be changed
+ children = tinymce.grep(node.childNodes);
+
+ // Process current node
+ if (contentEditable && !hasContentEditableState) {
+ for (i = 0, l = formatList.length; i < l; i++) {
+ if (removeFormat(formatList[i], vars, node, node))
+ break;
+ }
+ }
+
+ // Process the children
+ if (format.deep) {
+ if (children.length) {
+ for (i = 0, l = children.length; i < l; i++)
+ process(children[i]);
+
+ if (hasContentEditableState) {
+ contentEditable = lastContentEditable; // Restore last contentEditable state from stack
+ }
+ }
+ }
+ };
+
+ function findFormatRoot(container) {
+ var formatRoot;
+
+ // Find format root
+ each(getParents(container.parentNode).reverse(), function(parent) {
+ var format;
+
+ // Find format root element
+ if (!formatRoot && parent.id != '_start' && parent.id != '_end') {
+ // Is the node matching the format we are looking for
+ format = matchNode(parent, name, vars);
+ if (format && format.split !== false)
+ formatRoot = parent;
+ }
+ });
+
+ return formatRoot;
+ };
+
+ function wrapAndSplit(format_root, container, target, split) {
+ var parent, clone, lastClone, firstClone, i, formatRootParent;
+
+ // Format root found then clone formats and split it
+ if (format_root) {
+ formatRootParent = format_root.parentNode;
+
+ for (parent = container.parentNode; parent && parent != formatRootParent; parent = parent.parentNode) {
+ clone = dom.clone(parent, FALSE);
+
+ for (i = 0; i < formatList.length; i++) {
+ if (removeFormat(formatList[i], vars, clone, clone)) {
+ clone = 0;
+ break;
+ }
+ }
+
+ // Build wrapper node
+ if (clone) {
+ if (lastClone)
+ clone.appendChild(lastClone);
+
+ if (!firstClone)
+ firstClone = clone;
+
+ lastClone = clone;
+ }
+ }
+
+ // Never split block elements if the format is mixed
+ if (split && (!format.mixed || !isBlock(format_root)))
+ container = dom.split(format_root, container);
+
+ // Wrap container in cloned formats
+ if (lastClone) {
+ target.parentNode.insertBefore(lastClone, target);
+ firstClone.appendChild(target);
+ }
+ }
+
+ return container;
+ };
+
+ function splitToFormatRoot(container) {
+ return wrapAndSplit(findFormatRoot(container), container, container, true);
+ };
+
+ function unwrap(start) {
+ var node = dom.get(start ? '_start' : '_end'),
+ out = node[start ? 'firstChild' : 'lastChild'];
+
+ // If the end is placed within the start the result will be removed
+ // So this checks if the out node is a bookmark node if it is it
+ // checks for another more suitable node
+ if (isBookmarkNode(out))
+ out = out[start ? 'firstChild' : 'lastChild'];
+
+ dom.remove(node, true);
+
+ return out;
+ };
+
+ function removeRngStyle(rng) {
+ var startContainer, endContainer, node;
+
+ rng = expandRng(rng, formatList, TRUE);
+
+ if (format.split) {
+ startContainer = getContainer(rng, TRUE);
+ endContainer = getContainer(rng);
+
+ if (startContainer != endContainer) {
+ // WebKit will render the table incorrectly if we wrap a TD in a SPAN so lets see if the can use the first child instead
+ // This will happen if you tripple click a table cell and use remove formatting
+ if (/^(TR|TD)$/.test(startContainer.nodeName) && startContainer.firstChild) {
+ startContainer = (startContainer.nodeName == "TD" ? startContainer.firstChild : startContainer.firstChild.firstChild) || startContainer;
+ }
+
+ // Wrap start/end nodes in span element since these might be cloned/moved
+ startContainer = wrap(startContainer, 'span', {id : '_start', 'data-mce-type' : 'bookmark'});
+ endContainer = wrap(endContainer, 'span', {id : '_end', 'data-mce-type' : 'bookmark'});
+
+ // Split start/end
+ splitToFormatRoot(startContainer);
+ splitToFormatRoot(endContainer);
+
+ // Unwrap start/end to get real elements again
+ startContainer = unwrap(TRUE);
+ endContainer = unwrap();
+ } else
+ startContainer = endContainer = splitToFormatRoot(startContainer);
+
+ // Update range positions since they might have changed after the split operations
+ rng.startContainer = startContainer.parentNode;
+ rng.startOffset = nodeIndex(startContainer);
+ rng.endContainer = endContainer.parentNode;
+ rng.endOffset = nodeIndex(endContainer) + 1;
+ }
+
+ // Remove items between start/end
+ rangeUtils.walk(rng, function(nodes) {
+ each(nodes, function(node) {
+ process(node);
+
+ // Remove parent span if it only contains text-decoration: underline, yet a parent node is also underlined.
+ if (node.nodeType === 1 && ed.dom.getStyle(node, 'text-decoration') === 'underline' && node.parentNode && getTextDecoration(node.parentNode) === 'underline') {
+ removeFormat({'deep': false, 'exact': true, 'inline': 'span', 'styles': {'textDecoration' : 'underline'}}, null, node);
+ }
+ });
+ });
+ };
+
+ // Handle node
+ if (node) {
+ if (node.nodeType) {
+ rng = dom.createRng();
+ rng.setStartBefore(node);
+ rng.setEndAfter(node);
+ removeRngStyle(rng);
+ } else {
+ removeRngStyle(node);
+ }
+
+ return;
+ }
+
+ if (!selection.isCollapsed() || !format.inline || dom.select('td.mceSelected,th.mceSelected').length) {
+ bookmark = selection.getBookmark();
+ removeRngStyle(selection.getRng(TRUE));
+ selection.moveToBookmark(bookmark);
+
+ // Check if start element still has formatting then we are at: "<b>text|</b>text" and need to move the start into the next text node
+ if (format.inline && match(name, vars, selection.getStart())) {
+ moveStart(selection.getRng(true));
+ }
+
+ ed.nodeChanged();
+ } else
+ performCaretAction('remove', name, vars);
+ };
+
+ function toggle(name, vars, node) {
+ var fmt = get(name);
+
+ if (match(name, vars, node) && (!('toggle' in fmt[0]) || fmt[0].toggle))
+ remove(name, vars, node);
+ else
+ apply(name, vars, node);
+ };
+
+ function matchNode(node, name, vars, similar) {
+ var formatList = get(name), format, i, classes;
+
+ function matchItems(node, format, item_name) {
+ var key, value, items = format[item_name], i;
+
+ // Custom match
+ if (format.onmatch) {
+ return format.onmatch(node, format, item_name);
+ }
+
+ // Check all items
+ if (items) {
+ // Non indexed object
+ if (items.length === undef) {
+ for (key in items) {
+ if (items.hasOwnProperty(key)) {
+ if (item_name === 'attributes')
+ value = dom.getAttrib(node, key);
+ else
+ value = getStyle(node, key);
+
+ if (similar && !value && !format.exact)
+ return;
+
+ if ((!similar || format.exact) && !isEq(value, replaceVars(items[key], vars)))
+ return;
+ }
+ }
+ } else {
+ // Only one match needed for indexed arrays
+ for (i = 0; i < items.length; i++) {
+ if (item_name === 'attributes' ? dom.getAttrib(node, items[i]) : getStyle(node, items[i]))
+ return format;
+ }
+ }
+ }
+
+ return format;
+ };
+
+ if (formatList && node) {
+ // Check each format in list
+ for (i = 0; i < formatList.length; i++) {
+ format = formatList[i];
+
+ // Name name, attributes, styles and classes
+ if (matchName(node, format) && matchItems(node, format, 'attributes') && matchItems(node, format, 'styles')) {
+ // Match classes
+ if (classes = format.classes) {
+ for (i = 0; i < classes.length; i++) {
+ if (!dom.hasClass(node, classes[i]))
+ return;
+ }
+ }
+
+ return format;
+ }
+ }
+ }
+ };
+
+ function match(name, vars, node) {
+ var startNode;
+
+ function matchParents(node) {
+ // Find first node with similar format settings
+ node = dom.getParent(node, function(node) {
+ return !!matchNode(node, name, vars, true);
+ });
+
+ // Do an exact check on the similar format element
+ return matchNode(node, name, vars);
+ };
+
+ // Check specified node
+ if (node)
+ return matchParents(node);
+
+ // Check selected node
+ node = selection.getNode();
+ if (matchParents(node))
+ return TRUE;
+
+ // Check start node if it's different
+ startNode = selection.getStart();
+ if (startNode != node) {
+ if (matchParents(startNode))
+ return TRUE;
+ }
+
+ return FALSE;
+ };
+
+ function matchAll(names, vars) {
+ var startElement, matchedFormatNames = [], checkedMap = {}, i, ni, name;
+
+ // Check start of selection for formats
+ startElement = selection.getStart();
+ dom.getParent(startElement, function(node) {
+ var i, name;
+
+ for (i = 0; i < names.length; i++) {
+ name = names[i];
+
+ if (!checkedMap[name] && matchNode(node, name, vars)) {
+ checkedMap[name] = true;
+ matchedFormatNames.push(name);
+ }
+ }
+ }, dom.getRoot());
+
+ return matchedFormatNames;
+ };
+
+ function canApply(name) {
+ var formatList = get(name), startNode, parents, i, x, selector;
+
+ if (formatList) {
+ startNode = selection.getStart();
+ parents = getParents(startNode);
+
+ for (x = formatList.length - 1; x >= 0; x--) {
+ selector = formatList[x].selector;
+
+ // Format is not selector based, then always return TRUE
+ if (!selector)
+ return TRUE;
+
+ for (i = parents.length - 1; i >= 0; i--) {
+ if (dom.is(parents[i], selector))
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+ };
+
+ function formatChanged(formats, callback) {
+ var currentFormats;
+
+ // Setup format node change logic
+ if (!formatChangeData) {
+ formatChangeData = {};
+ currentFormats = {};
+
+ ed.onNodeChange.addToTop(function(ed, cm, node) {
+ var parents = getParents(node), matchedFormats = {};
+
+ // Check for new formats
+ each(formatChangeData, function(callbacks, format) {
+ each(parents, function(node) {
+ if (matchNode(node, format, {}, true)) {
+ if (!currentFormats[format]) {
+ // Execute callbacks
+ each(callbacks, function(callback) {
+ callback(true, {node: node, format: format, parents: parents});
+ });
+
+ currentFormats[format] = callbacks;
+ }
+
+ matchedFormats[format] = callbacks;
+ return false;
+ }
+ });
+ });
+
+ // Check if current formats still match
+ each(currentFormats, function(callbacks, format) {
+ if (!matchedFormats[format]) {
+ delete currentFormats[format];
+
+ each(callbacks, function(callback) {
+ callback(false, {node: node, format: format, parents: parents});
+ });
+ }
+ });
+ });
+ }
+
+ // Add format listeners
+ each(formats.split(','), function(format) {
+ if (!formatChangeData[format]) {
+ formatChangeData[format] = [];
+ }
+
+ formatChangeData[format].push(callback);
+ });
+
+ return this;
+ };
+
+ // Expose to public
+ tinymce.extend(this, {
+ get : get,
+ register : register,
+ apply : apply,
+ remove : remove,
+ toggle : toggle,
+ match : match,
+ matchAll : matchAll,
+ matchNode : matchNode,
+ canApply : canApply,
+ formatChanged: formatChanged
+ });
+
+ // Initialize
+ defaultFormats();
+ addKeyboardShortcuts();
+
+ // Private functions
+
+ function matchName(node, format) {
+ // Check for inline match
+ if (isEq(node, format.inline))
+ return TRUE;
+
+ // Check for block match
+ if (isEq(node, format.block))
+ return TRUE;
+
+ // Check for selector match
+ if (format.selector)
+ return dom.is(node, format.selector);
+ };
+
+ function isEq(str1, str2) {
+ str1 = str1 || '';
+ str2 = str2 || '';
+
+ str1 = '' + (str1.nodeName || str1);
+ str2 = '' + (str2.nodeName || str2);
+
+ return str1.toLowerCase() == str2.toLowerCase();
+ };
+
+ function getStyle(node, name) {
+ var styleVal = dom.getStyle(node, name);
+
+ // Force the format to hex
+ if (name == 'color' || name == 'backgroundColor')
+ styleVal = dom.toHex(styleVal);
+
+ // Opera will return bold as 700
+ if (name == 'fontWeight' && styleVal == 700)
+ styleVal = 'bold';
+
+ return '' + styleVal;
+ };
+
+ function replaceVars(value, vars) {
+ if (typeof(value) != "string")
+ value = value(vars);
+ else if (vars) {
+ value = value.replace(/%(\w+)/g, function(str, name) {
+ return vars[name] || str;
+ });
+ }
+
+ return value;
+ };
+
+ function isWhiteSpaceNode(node) {
+ return node && node.nodeType === 3 && /^([\t \r\n]+|)$/.test(node.nodeValue);
+ };
+
+ function wrap(node, name, attrs) {
+ var wrapper = dom.create(name, attrs);
+
+ node.parentNode.insertBefore(wrapper, node);
+ wrapper.appendChild(node);
+
+ return wrapper;
+ };
+
+ function expandRng(rng, format, remove) {
+ var sibling, lastIdx, leaf, endPoint,
+ startContainer = rng.startContainer,
+ startOffset = rng.startOffset,
+ endContainer = rng.endContainer,
+ endOffset = rng.endOffset;
+
+ // This function walks up the tree if there is no siblings before/after the node
+ function findParentContainer(start) {
+ var container, parent, child, sibling, siblingName, root;
+
+ container = parent = start ? startContainer : endContainer;
+ siblingName = start ? 'previousSibling' : 'nextSibling';
+ root = dom.getRoot();
+
+ // If it's a text node and the offset is inside the text
+ if (container.nodeType == 3 && !isWhiteSpaceNode(container)) {
+ if (start ? startOffset > 0 : endOffset < container.nodeValue.length) {
+ return container;
+ }
+ }
+
+ for (;;) {
+ // Stop expanding on block elements
+ if (!format[0].block_expand && isBlock(parent))
+ return parent;
+
+ // Walk left/right
+ for (sibling = parent[siblingName]; sibling; sibling = sibling[siblingName]) {
+ if (!isBookmarkNode(sibling) && !isWhiteSpaceNode(sibling)) {
+ return parent;
+ }
+ }
+
+ // Check if we can move up are we at root level or body level
+ if (parent.parentNode == root) {
+ container = parent;
+ break;
+ }
+
+ parent = parent.parentNode;
+ }
+
+ return container;
+ };
+
+ // This function walks down the tree to find the leaf at the selection.
+ // The offset is also returned as if node initially a leaf, the offset may be in the middle of the text node.
+ function findLeaf(node, offset) {
+ if (offset === undef)
+ offset = node.nodeType === 3 ? node.length : node.childNodes.length;
+ while (node && node.hasChildNodes()) {
+ node = node.childNodes[offset];
+ if (node)
+ offset = node.nodeType === 3 ? node.length : node.childNodes.length;
+ }
+ return { node: node, offset: offset };
+ }
+
+ // If index based start position then resolve it
+ if (startContainer.nodeType == 1 && startContainer.hasChildNodes()) {
+ lastIdx = startContainer.childNodes.length - 1;
+ startContainer = startContainer.childNodes[startOffset > lastIdx ? lastIdx : startOffset];
+
+ if (startContainer.nodeType == 3)
+ startOffset = 0;
+ }
+
+ // If index based end position then resolve it
+ if (endContainer.nodeType == 1 && endContainer.hasChildNodes()) {
+ lastIdx = endContainer.childNodes.length - 1;
+ endContainer = endContainer.childNodes[endOffset > lastIdx ? lastIdx : endOffset - 1];
+
+ if (endContainer.nodeType == 3)
+ endOffset = endContainer.nodeValue.length;
+ }
+
+ // Expands the node to the closes contentEditable false element if it exists
+ function findParentContentEditable(node) {
+ var parent = node;
+
+ while (parent) {
+ if (parent.nodeType === 1 && getContentEditable(parent)) {
+ return getContentEditable(parent) === "false" ? parent : node;
+ }
+
+ parent = parent.parentNode;
+ }
+
+ return node;
+ };
+
+ function findWordEndPoint(container, offset, start) {
+ var walker, node, pos, lastTextNode;
+
+ function findSpace(node, offset) {
+ var pos, pos2, str = node.nodeValue;
+
+ if (typeof(offset) == "undefined") {
+ offset = start ? str.length : 0;
+ }
+
+ if (start) {
+ pos = str.lastIndexOf(' ', offset);
+ pos2 = str.lastIndexOf('\u00a0', offset);
+ pos = pos > pos2 ? pos : pos2;
+
+ // Include the space on remove to avoid tag soup
+ if (pos !== -1 && !remove) {
+ pos++;
+ }
+ } else {
+ pos = str.indexOf(' ', offset);
+ pos2 = str.indexOf('\u00a0', offset);
+ pos = pos !== -1 && (pos2 === -1 || pos < pos2) ? pos : pos2;
+ }
+
+ return pos;
+ };
+
+ if (container.nodeType === 3) {
+ pos = findSpace(container, offset);
+
+ if (pos !== -1) {
+ return {container : container, offset : pos};
+ }
+
+ lastTextNode = container;
+ }
+
+ // Walk the nodes inside the block
+ walker = new TreeWalker(container, dom.getParent(container, isBlock) || ed.getBody());
+ while (node = walker[start ? 'prev' : 'next']()) {
+ if (node.nodeType === 3) {
+ lastTextNode = node;
+ pos = findSpace(node);
+
+ if (pos !== -1) {
+ return {container : node, offset : pos};
+ }
+ } else if (isBlock(node)) {
+ break;
+ }
+ }
+
+ if (lastTextNode) {
+ if (start) {
+ offset = 0;
+ } else {
+ offset = lastTextNode.length;
+ }
+
+ return {container: lastTextNode, offset: offset};
+ }
+ };
+
+ function findSelectorEndPoint(container, sibling_name) {
+ var parents, i, y, curFormat;
+
+ if (container.nodeType == 3 && container.nodeValue.length === 0 && container[sibling_name])
+ container = container[sibling_name];
+
+ parents = getParents(container);
+ for (i = 0; i < parents.length; i++) {
+ for (y = 0; y < format.length; y++) {
+ curFormat = format[y];
+
+ // If collapsed state is set then skip formats that doesn't match that
+ if ("collapsed" in curFormat && curFormat.collapsed !== rng.collapsed)
+ continue;
+
+ if (dom.is(parents[i], curFormat.selector))
+ return parents[i];
+ }
+ }
+
+ return container;
+ };
+
+ function findBlockEndPoint(container, sibling_name, sibling_name2) {
+ var node;
+
+ // Expand to block of similar type
+ if (!format[0].wrapper)
+ node = dom.getParent(container, format[0].block);
+
+ // Expand to first wrappable block element or any block element
+ if (!node)
+ node = dom.getParent(container.nodeType == 3 ? container.parentNode : container, isBlock);
+
+ // Exclude inner lists from wrapping
+ if (node && format[0].wrapper)
+ node = getParents(node, 'ul,ol').reverse()[0] || node;
+
+ // Didn't find a block element look for first/last wrappable element
+ if (!node) {
+ node = container;
+
+ while (node[sibling_name] && !isBlock(node[sibling_name])) {
+ node = node[sibling_name];
+
+ // Break on BR but include it will be removed later on
+ // we can't remove it now since we need to check if it can be wrapped
+ if (isEq(node, 'br'))
+ break;
+ }
+ }
+
+ return node || container;
+ };
+
+ // Expand to closest contentEditable element
+ startContainer = findParentContentEditable(startContainer);
+ endContainer = findParentContentEditable(endContainer);
+
+ // Exclude bookmark nodes if possible
+ if (isBookmarkNode(startContainer.parentNode) || isBookmarkNode(startContainer)) {
+ startContainer = isBookmarkNode(startContainer) ? startContainer : startContainer.parentNode;
+ startContainer = startContainer.nextSibling || startContainer;
+
+ if (startContainer.nodeType == 3)
+ startOffset = 0;
+ }
+
+ if (isBookmarkNode(endContainer.parentNode) || isBookmarkNode(endContainer)) {
+ endContainer = isBookmarkNode(endContainer) ? endContainer : endContainer.parentNode;
+ endContainer = endContainer.previousSibling || endContainer;
+
+ if (endContainer.nodeType == 3)
+ endOffset = endContainer.length;
+ }
+
+ if (format[0].inline) {
+ if (rng.collapsed) {
+ // Expand left to closest word boundery
+ endPoint = findWordEndPoint(startContainer, startOffset, true);
+ if (endPoint) {
+ startContainer = endPoint.container;
+ startOffset = endPoint.offset;
+ }
+
+ // Expand right to closest word boundery
+ endPoint = findWordEndPoint(endContainer, endOffset);
+ if (endPoint) {
+ endContainer = endPoint.container;
+ endOffset = endPoint.offset;
+ }
+ }
+
+ // Avoid applying formatting to a trailing space.
+ leaf = findLeaf(endContainer, endOffset);
+ if (leaf.node) {
+ while (leaf.node && leaf.offset === 0 && leaf.node.previousSibling)
+ leaf = findLeaf(leaf.node.previousSibling);
+
+ if (leaf.node && leaf.offset > 0 && leaf.node.nodeType === 3 &&
+ leaf.node.nodeValue.charAt(leaf.offset - 1) === ' ') {
+
+ if (leaf.offset > 1) {
+ endContainer = leaf.node;
+ endContainer.splitText(leaf.offset - 1);
+ }
+ }
+ }
+ }
+
+ // Move start/end point up the tree if the leaves are sharp and if we are in different containers
+ // Example * becomes !: !<p><b><i>*text</i><i>text*</i></b></p>!
+ // This will reduce the number of wrapper elements that needs to be created
+ // Move start point up the tree
+ if (format[0].inline || format[0].block_expand) {
+ if (!format[0].inline || (startContainer.nodeType != 3 || startOffset === 0)) {
+ startContainer = findParentContainer(true);
+ }
+
+ if (!format[0].inline || (endContainer.nodeType != 3 || endOffset === endContainer.nodeValue.length)) {
+ endContainer = findParentContainer();
+ }
+ }
+
+ // Expand start/end container to matching selector
+ if (format[0].selector && format[0].expand !== FALSE && !format[0].inline) {
+ // Find new startContainer/endContainer if there is better one
+ startContainer = findSelectorEndPoint(startContainer, 'previousSibling');
+ endContainer = findSelectorEndPoint(endContainer, 'nextSibling');
+ }
+
+ // Expand start/end container to matching block element or text node
+ if (format[0].block || format[0].selector) {
+ // Find new startContainer/endContainer if there is better one
+ startContainer = findBlockEndPoint(startContainer, 'previousSibling');
+ endContainer = findBlockEndPoint(endContainer, 'nextSibling');
+
+ // Non block element then try to expand up the leaf
+ if (format[0].block) {
+ if (!isBlock(startContainer))
+ startContainer = findParentContainer(true);
+
+ if (!isBlock(endContainer))
+ endContainer = findParentContainer();
+ }
+ }
+
+ // Setup index for startContainer
+ if (startContainer.nodeType == 1) {
+ startOffset = nodeIndex(startContainer);
+ startContainer = startContainer.parentNode;
+ }
+
+ // Setup index for endContainer
+ if (endContainer.nodeType == 1) {
+ endOffset = nodeIndex(endContainer) + 1;
+ endContainer = endContainer.parentNode;
+ }
+
+ // Return new range like object
+ return {
+ startContainer : startContainer,
+ startOffset : startOffset,
+ endContainer : endContainer,
+ endOffset : endOffset
+ };
+ }
+
+ function removeFormat(format, vars, node, compare_node) {
+ var i, attrs, stylesModified;
+
+ // Check if node matches format
+ if (!matchName(node, format))
+ return FALSE;
+
+ // Should we compare with format attribs and styles
+ if (format.remove != 'all') {
+ // Remove styles
+ each(format.styles, function(value, name) {
+ value = replaceVars(value, vars);
+
+ // Indexed array
+ if (typeof(name) === 'number') {
+ name = value;
+ compare_node = 0;
+ }
+
+ if (!compare_node || isEq(getStyle(compare_node, name), value))
+ dom.setStyle(node, name, '');
+
+ stylesModified = 1;
+ });
+
+ // Remove style attribute if it's empty
+ if (stylesModified && dom.getAttrib(node, 'style') == '') {
+ node.removeAttribute('style');
+ node.removeAttribute('data-mce-style');
+ }
+
+ // Remove attributes
+ each(format.attributes, function(value, name) {
+ var valueOut;
+
+ value = replaceVars(value, vars);
+
+ // Indexed array
+ if (typeof(name) === 'number') {
+ name = value;
+ compare_node = 0;
+ }
+
+ if (!compare_node || isEq(dom.getAttrib(compare_node, name), value)) {
+ // Keep internal classes
+ if (name == 'class') {
+ value = dom.getAttrib(node, name);
+ if (value) {
+ // Build new class value where everything is removed except the internal prefixed classes
+ valueOut = '';
+ each(value.split(/\s+/), function(cls) {
+ if (/mce\w+/.test(cls))
+ valueOut += (valueOut ? ' ' : '') + cls;
+ });
+
+ // We got some internal classes left
+ if (valueOut) {
+ dom.setAttrib(node, name, valueOut);
+ return;
+ }
+ }
+ }
+
+ // IE6 has a bug where the attribute doesn't get removed correctly
+ if (name == "class")
+ node.removeAttribute('className');
+
+ // Remove mce prefixed attributes
+ if (MCE_ATTR_RE.test(name))
+ node.removeAttribute('data-mce-' + name);
+
+ node.removeAttribute(name);
+ }
+ });
+
+ // Remove classes
+ each(format.classes, function(value) {
+ value = replaceVars(value, vars);
+
+ if (!compare_node || dom.hasClass(compare_node, value))
+ dom.removeClass(node, value);
+ });
+
+ // Check for non internal attributes
+ attrs = dom.getAttribs(node);
+ for (i = 0; i < attrs.length; i++) {
+ if (attrs[i].nodeName.indexOf('_') !== 0)
+ return FALSE;
+ }
+ }
+
+ // Remove the inline child if it's empty for example <b> or <span>
+ if (format.remove != 'none') {
+ removeNode(node, format);
+ return TRUE;
+ }
+ };
+
+ function removeNode(node, format) {
+ var parentNode = node.parentNode, rootBlockElm;
+
+ function find(node, next, inc) {
+ node = getNonWhiteSpaceSibling(node, next, inc);
+
+ return !node || (node.nodeName == 'BR' || isBlock(node));
+ };
+
+ if (format.block) {
+ if (!forcedRootBlock) {
+ // Append BR elements if needed before we remove the block
+ if (isBlock(node) && !isBlock(parentNode)) {
+ if (!find(node, FALSE) && !find(node.firstChild, TRUE, 1))
+ node.insertBefore(dom.create('br'), node.firstChild);
+
+ if (!find(node, TRUE) && !find(node.lastChild, FALSE, 1))
+ node.appendChild(dom.create('br'));
+ }
+ } else {
+ // Wrap the block in a forcedRootBlock if we are at the root of document
+ if (parentNode == dom.getRoot()) {
+ if (!format.list_block || !isEq(node, format.list_block)) {
+ each(tinymce.grep(node.childNodes), function(node) {
+ if (isValid(forcedRootBlock, node.nodeName.toLowerCase())) {
+ if (!rootBlockElm)
+ rootBlockElm = wrap(node, forcedRootBlock);
+ else
+ rootBlockElm.appendChild(node);
+ } else
+ rootBlockElm = 0;
+ });
+ }
+ }
+ }
+ }
+
+ // Never remove nodes that isn't the specified inline element if a selector is specified too
+ if (format.selector && format.inline && !isEq(format.inline, node))
+ return;
+
+ dom.remove(node, 1);
+ };
+
+ function getNonWhiteSpaceSibling(node, next, inc) {
+ if (node) {
+ next = next ? 'nextSibling' : 'previousSibling';
+
+ for (node = inc ? node : node[next]; node; node = node[next]) {
+ if (node.nodeType == 1 || !isWhiteSpaceNode(node))
+ return node;
+ }
+ }
+ };
+
+ function isBookmarkNode(node) {
+ return node && node.nodeType == 1 && node.getAttribute('data-mce-type') == 'bookmark';
+ };
+
+ function mergeSiblings(prev, next) {
+ var marker, sibling, tmpSibling;
+
+ function compareElements(node1, node2) {
+ // Not the same name
+ if (node1.nodeName != node2.nodeName)
+ return FALSE;
+
+ function getAttribs(node) {
+ var attribs = {};
+
+ each(dom.getAttribs(node), function(attr) {
+ var name = attr.nodeName.toLowerCase();
+
+ // Don't compare internal attributes or style
+ if (name.indexOf('_') !== 0 && name !== 'style')
+ attribs[name] = dom.getAttrib(node, name);
+ });
+
+ return attribs;
+ };
+
+ function compareObjects(obj1, obj2) {
+ var value, name;
+
+ for (name in obj1) {
+ // Obj1 has item obj2 doesn't have
+ if (obj1.hasOwnProperty(name)) {
+ value = obj2[name];
+
+ // Obj2 doesn't have obj1 item
+ if (value === undef)
+ return FALSE;
+
+ // Obj2 item has a different value
+ if (obj1[name] != value)
+ return FALSE;
+
+ // Delete similar value
+ delete obj2[name];
+ }
+ }
+
+ // Check if obj 2 has something obj 1 doesn't have
+ for (name in obj2) {
+ // Obj2 has item obj1 doesn't have
+ if (obj2.hasOwnProperty(name))
+ return FALSE;
+ }
+
+ return TRUE;
+ };
+
+ // Attribs are not the same
+ if (!compareObjects(getAttribs(node1), getAttribs(node2)))
+ return FALSE;
+
+ // Styles are not the same
+ if (!compareObjects(dom.parseStyle(dom.getAttrib(node1, 'style')), dom.parseStyle(dom.getAttrib(node2, 'style'))))
+ return FALSE;
+
+ return TRUE;
+ };
+
+ function findElementSibling(node, sibling_name) {
+ for (sibling = node; sibling; sibling = sibling[sibling_name]) {
+ if (sibling.nodeType == 3 && sibling.nodeValue.length !== 0)
+ return node;
+
+ if (sibling.nodeType == 1 && !isBookmarkNode(sibling))
+ return sibling;
+ }
+
+ return node;
+ };
+
+ // Check if next/prev exists and that they are elements
+ if (prev && next) {
+ // If previous sibling is empty then jump over it
+ prev = findElementSibling(prev, 'previousSibling');
+ next = findElementSibling(next, 'nextSibling');
+
+ // Compare next and previous nodes
+ if (compareElements(prev, next)) {
+ // Append nodes between
+ for (sibling = prev.nextSibling; sibling && sibling != next;) {
+ tmpSibling = sibling;
+ sibling = sibling.nextSibling;
+ prev.appendChild(tmpSibling);
+ }
+
+ // Remove next node
+ dom.remove(next);
+
+ // Move children into prev node
+ each(tinymce.grep(next.childNodes), function(node) {
+ prev.appendChild(node);
+ });
+
+ return prev;
+ }
+ }
+
+ return next;
+ };
+
+ function isTextBlock(name) {
+ return /^(h[1-6]|p|div|pre|address|dl|dt|dd)$/.test(name);
+ };
+
+ function getContainer(rng, start) {
+ var container, offset, lastIdx, walker;
+
+ container = rng[start ? 'startContainer' : 'endContainer'];
+ offset = rng[start ? 'startOffset' : 'endOffset'];
+
+ if (container.nodeType == 1) {
+ lastIdx = container.childNodes.length - 1;
+
+ if (!start && offset)
+ offset--;
+
+ container = container.childNodes[offset > lastIdx ? lastIdx : offset];
+ }
+
+ // If start text node is excluded then walk to the next node
+ if (container.nodeType === 3 && start && offset >= container.nodeValue.length) {
+ container = new TreeWalker(container, ed.getBody()).next() || container;
+ }
+
+ // If end text node is excluded then walk to the previous node
+ if (container.nodeType === 3 && !start && offset === 0) {
+ container = new TreeWalker(container, ed.getBody()).prev() || container;
+ }
+
+ return container;
+ };
+
+ function performCaretAction(type, name, vars) {
+ var caretContainerId = '_mce_caret', debug = ed.settings.caret_debug;
+
+ // Creates a caret container bogus element
+ function createCaretContainer(fill) {
+ var caretContainer = dom.create('span', {id: caretContainerId, 'data-mce-bogus': true, style: debug ? 'color:red' : ''});
+
+ if (fill) {
+ caretContainer.appendChild(ed.getDoc().createTextNode(INVISIBLE_CHAR));
+ }
+
+ return caretContainer;
+ };
+
+ function isCaretContainerEmpty(node, nodes) {
+ while (node) {
+ if ((node.nodeType === 3 && node.nodeValue !== INVISIBLE_CHAR) || node.childNodes.length > 1) {
+ return false;
+ }
+
+ // Collect nodes
+ if (nodes && node.nodeType === 1) {
+ nodes.push(node);
+ }
+
+ node = node.firstChild;
+ }
+
+ return true;
+ };
+
+ // Returns any parent caret container element
+ function getParentCaretContainer(node) {
+ while (node) {
+ if (node.id === caretContainerId) {
+ return node;
+ }
+
+ node = node.parentNode;
+ }
+ };
+
+ // Finds the first text node in the specified node
+ function findFirstTextNode(node) {
+ var walker;
+
+ if (node) {
+ walker = new TreeWalker(node, node);
+
+ for (node = walker.current(); node; node = walker.next()) {
+ if (node.nodeType === 3) {
+ return node;
+ }
+ }
+ }
+ };
+
+ // Removes the caret container for the specified node or all on the current document
+ function removeCaretContainer(node, move_caret) {
+ var child, rng;
+
+ if (!node) {
+ node = getParentCaretContainer(selection.getStart());
+
+ if (!node) {
+ while (node = dom.get(caretContainerId)) {
+ removeCaretContainer(node, false);
+ }
+ }
+ } else {
+ rng = selection.getRng(true);
+
+ if (isCaretContainerEmpty(node)) {
+ if (move_caret !== false) {
+ rng.setStartBefore(node);
+ rng.setEndBefore(node);
+ }
+
+ dom.remove(node);
+ } else {
+ child = findFirstTextNode(node);
+
+ if (child.nodeValue.charAt(0) === INVISIBLE_CHAR) {
+ child = child.deleteData(0, 1);
+ }
+
+ dom.remove(node, 1);
+ }
+
+ selection.setRng(rng);
+ }
+ };
+
+ // Applies formatting to the caret postion
+ function applyCaretFormat() {
+ var rng, caretContainer, textNode, offset, bookmark, container, text;
+
+ rng = selection.getRng(true);
+ offset = rng.startOffset;
+ container = rng.startContainer;
+ text = container.nodeValue;
+
+ caretContainer = getParentCaretContainer(selection.getStart());
+ if (caretContainer) {
+ textNode = findFirstTextNode(caretContainer);
+ }
+
+ // Expand to word is caret is in the middle of a text node and the char before/after is a alpha numeric character
+ if (text && offset > 0 && offset < text.length && /\w/.test(text.charAt(offset)) && /\w/.test(text.charAt(offset - 1))) {
+ // Get bookmark of caret position
+ bookmark = selection.getBookmark();
+
+ // Collapse bookmark range (WebKit)
+ rng.collapse(true);
+
+ // Expand the range to the closest word and split it at those points
+ rng = expandRng(rng, get(name));
+ rng = rangeUtils.split(rng);
+
+ // Apply the format to the range
+ apply(name, vars, rng);
+
+ // Move selection back to caret position
+ selection.moveToBookmark(bookmark);
+ } else {
+ if (!caretContainer || textNode.nodeValue !== INVISIBLE_CHAR) {
+ caretContainer = createCaretContainer(true);
+ textNode = caretContainer.firstChild;
+
+ rng.insertNode(caretContainer);
+ offset = 1;
+
+ apply(name, vars, caretContainer);
+ } else {
+ apply(name, vars, caretContainer);
+ }
+
+ // Move selection to text node
+ selection.setCursorLocation(textNode, offset);
+ }
+ };
+
+ function removeCaretFormat() {
+ var rng = selection.getRng(true), container, offset, bookmark,
+ hasContentAfter, node, formatNode, parents = [], i, caretContainer;
+
+ container = rng.startContainer;
+ offset = rng.startOffset;
+ node = container;
+
+ if (container.nodeType == 3) {
+ if (offset != container.nodeValue.length || container.nodeValue === INVISIBLE_CHAR) {
+ hasContentAfter = true;
+ }
+
+ node = node.parentNode;
+ }
+
+ while (node) {
+ if (matchNode(node, name, vars)) {
+ formatNode = node;
+ break;
+ }
+
+ if (node.nextSibling) {
+ hasContentAfter = true;
+ }
+
+ parents.push(node);
+ node = node.parentNode;
+ }
+
+ // Node doesn't have the specified format
+ if (!formatNode) {
+ return;
+ }
+
+ // Is there contents after the caret then remove the format on the element
+ if (hasContentAfter) {
+ // Get bookmark of caret position
+ bookmark = selection.getBookmark();
+
+ // Collapse bookmark range (WebKit)
+ rng.collapse(true);
+
+ // Expand the range to the closest word and split it at those points
+ rng = expandRng(rng, get(name), true);
+ rng = rangeUtils.split(rng);
+
+ // Remove the format from the range
+ remove(name, vars, rng);
+
+ // Move selection back to caret position
+ selection.moveToBookmark(bookmark);
+ } else {
+ caretContainer = createCaretContainer();
+
+ node = caretContainer;
+ for (i = parents.length - 1; i >= 0; i--) {
+ node.appendChild(dom.clone(parents[i], false));
+ node = node.firstChild;
+ }
+
+ // Insert invisible character into inner most format element
+ node.appendChild(dom.doc.createTextNode(INVISIBLE_CHAR));
+ node = node.firstChild;
+
+ // Insert caret container after the formated node
+ dom.insertAfter(caretContainer, formatNode);
+
+ // Move selection to text node
+ selection.setCursorLocation(node, 1);
+ }
+ };
+
+ // Checks if the parent caret container node isn't empty if that is the case it
+ // will remove the bogus state on all children that isn't empty
+ function unmarkBogusCaretParents() {
+ var i, caretContainer, node;
+
+ caretContainer = getParentCaretContainer(selection.getStart());
+ if (caretContainer && !dom.isEmpty(caretContainer)) {
+ tinymce.walk(caretContainer, function(node) {
+ if (node.nodeType == 1 && node.id !== caretContainerId && !dom.isEmpty(node)) {
+ dom.setAttrib(node, 'data-mce-bogus', null);
+ }
+ }, 'childNodes');
+ }
+ };
+
+ // Only bind the caret events once
+ if (!self._hasCaretEvents) {
+ // Mark current caret container elements as bogus when getting the contents so we don't end up with empty elements
+ ed.onBeforeGetContent.addToTop(function() {
+ var nodes = [], i;
+
+ if (isCaretContainerEmpty(getParentCaretContainer(selection.getStart()), nodes)) {
+ // Mark children
+ i = nodes.length;
+ while (i--) {
+ dom.setAttrib(nodes[i], 'data-mce-bogus', '1');
+ }
+ }
+ });
+
+ // Remove caret container on mouse up and on key up
+ tinymce.each('onMouseUp onKeyUp'.split(' '), function(name) {
+ ed[name].addToTop(function() {
+ removeCaretContainer();
+ unmarkBogusCaretParents();
+ });
+ });
+
+ // Remove caret container on keydown and it's a backspace, enter or left/right arrow keys
+ ed.onKeyDown.addToTop(function(ed, e) {
+ var keyCode = e.keyCode;
+
+ if (keyCode == 8 || keyCode == 37 || keyCode == 39) {
+ removeCaretContainer(getParentCaretContainer(selection.getStart()));
+ }
+
+ unmarkBogusCaretParents();
+ });
+
+ // Remove bogus state if they got filled by contents using editor.selection.setContent
+ selection.onSetContent.add(unmarkBogusCaretParents);
+
+ self._hasCaretEvents = true;
+ }
+
+ // Do apply or remove caret format
+ if (type == "apply") {
+ applyCaretFormat();
+ } else {
+ removeCaretFormat();
+ }
+ };
+
+ function moveStart(rng) {
+ var container = rng.startContainer,
+ offset = rng.startOffset, isAtEndOfText,
+ walker, node, nodes, tmpNode;
+
+ // Convert text node into index if possible
+ if (container.nodeType == 3 && offset >= container.nodeValue.length) {
+ // Get the parent container location and walk from there
+ offset = nodeIndex(container);
+ container = container.parentNode;
+ isAtEndOfText = true;
+ }
+
+ // Move startContainer/startOffset in to a suitable node
+ if (container.nodeType == 1) {
+ nodes = container.childNodes;
+ container = nodes[Math.min(offset, nodes.length - 1)];
+ walker = new TreeWalker(container, dom.getParent(container, dom.isBlock));
+
+ // If offset is at end of the parent node walk to the next one
+ if (offset > nodes.length - 1 || isAtEndOfText)
+ walker.next();
+
+ for (node = walker.current(); node; node = walker.next()) {
+ if (node.nodeType == 3 && !isWhiteSpaceNode(node)) {
+ // IE has a "neat" feature where it moves the start node into the closest element
+ // we can avoid this by inserting an element before it and then remove it after we set the selection
+ tmpNode = dom.create('a', null, INVISIBLE_CHAR);
+ node.parentNode.insertBefore(tmpNode, node);
+
+ // Set selection and remove tmpNode
+ rng.setStart(node, 0);
+ selection.setRng(rng);
+ dom.remove(tmpNode);
+
+ return;
+ }
+ }
+ }
+ };
+ };
+})(tinymce);
+
+tinymce.onAddEditor.add(function(tinymce, ed) {
+ var filters, fontSizes, dom, settings = ed.settings;
+
+ function replaceWithSpan(node, styles) {
+ tinymce.each(styles, function(value, name) {
+ if (value)
+ dom.setStyle(node, name, value);
+ });
+
+ dom.rename(node, 'span');
+ };
+
+ function convert(editor, params) {
+ dom = editor.dom;
+
+ if (settings.convert_fonts_to_spans) {
+ tinymce.each(dom.select('font,u,strike', params.node), function(node) {
+ filters[node.nodeName.toLowerCase()](ed.dom, node);
+ });
+ }
+ };
+
+ if (settings.inline_styles) {
+ fontSizes = tinymce.explode(settings.font_size_legacy_values);
+
+ filters = {
+ font : function(dom, node) {
+ replaceWithSpan(node, {
+ backgroundColor : node.style.backgroundColor,
+ color : node.color,
+ fontFamily : node.face,
+ fontSize : fontSizes[parseInt(node.size, 10) - 1]
+ });
+ },
+
+ u : function(dom, node) {
+ replaceWithSpan(node, {
+ textDecoration : 'underline'
+ });
+ },
+
+ strike : function(dom, node) {
+ replaceWithSpan(node, {
+ textDecoration : 'line-through'
+ });
+ }
+ };
+
+ ed.onPreProcess.add(convert);
+ ed.onSetContent.add(convert);
+
+ ed.onInit.add(function() {
+ ed.selection.onSetContent.add(convert);
+ });
+ }
+});
+
+(function(tinymce) {
+ var TreeWalker = tinymce.dom.TreeWalker;
+
+ tinymce.EnterKey = function(editor) {
+ var dom = editor.dom, selection = editor.selection, settings = editor.settings, undoManager = editor.undoManager, nonEmptyElementsMap = editor.schema.getNonEmptyElements();
+
+ function handleEnterKey(evt) {
+ var rng = selection.getRng(true), tmpRng, editableRoot, container, offset, parentBlock, documentMode,
+ newBlock, fragment, containerBlock, parentBlockName, containerBlockName, newBlockName, isAfterLastNodeInContainer;
+
+ // Returns true if the block can be split into two blocks or not
+ function canSplitBlock(node) {
+ return node &&
+ dom.isBlock(node) &&
+ !/^(TD|TH|CAPTION|FORM)$/.test(node.nodeName) &&
+ !/^(fixed|absolute)/i.test(node.style.position) &&
+ dom.getContentEditable(node) !== "true";
+ };
+
+ // Renders empty block on IE
+ function renderBlockOnIE(block) {
+ var oldRng;
+
+ if (tinymce.isIE && dom.isBlock(block)) {
+ oldRng = selection.getRng();
+ block.appendChild(dom.create('span', null, '\u00a0'));
+ selection.select(block);
+ block.lastChild.outerHTML = '';
+ selection.setRng(oldRng);
+ }
+ };
+
+ // Remove the first empty inline element of the block so this: <p><b><em></em></b>x</p> becomes this: <p>x</p>
+ function trimInlineElementsOnLeftSideOfBlock(block) {
+ var node = block, firstChilds = [], i;
+
+ // Find inner most first child ex: <p><i><b>*</b></i></p>
+ while (node = node.firstChild) {
+ if (dom.isBlock(node)) {
+ return;
+ }
+
+ if (node.nodeType == 1 && !nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
+ firstChilds.push(node);
+ }
+ }
+
+ i = firstChilds.length;
+ while (i--) {
+ node = firstChilds[i];
+ if (!node.hasChildNodes() || (node.firstChild == node.lastChild && node.firstChild.nodeValue === '')) {
+ dom.remove(node);
+ }
+ }
+ };
+
+ // Moves the caret to a suitable position within the root for example in the first non pure whitespace text node or before an image
+ function moveToCaretPosition(root) {
+ var walker, node, rng, y, viewPort, lastNode = root, tempElm;
+
+ rng = dom.createRng();
+
+ if (root.hasChildNodes()) {
+ walker = new TreeWalker(root, root);
+
+ while (node = walker.current()) {
+ if (node.nodeType == 3) {
+ rng.setStart(node, 0);
+ rng.setEnd(node, 0);
+ break;
+ }
+
+ if (nonEmptyElementsMap[node.nodeName.toLowerCase()]) {
+ rng.setStartBefore(node);
+ rng.setEndBefore(node);
+ break;
+ }
+
+ lastNode = node;
+ node = walker.next();
+ }
+
+ if (!node) {
+ rng.setStart(lastNode, 0);
+ rng.setEnd(lastNode, 0);
+ }
+ } else {
+ if (root.nodeName == 'BR') {
+ if (root.nextSibling && dom.isBlock(root.nextSibling)) {
+ // Trick on older IE versions to render the caret before the BR between two lists
+ if (!documentMode || documentMode < 9) {
+ tempElm = dom.create('br');
+ root.parentNode.insertBefore(tempElm, root);
+ }
+
+ rng.setStartBefore(root);
+ rng.setEndBefore(root);
+ } else {
+ rng.setStartAfter(root);
+ rng.setEndAfter(root);
+ }
+ } else {
+ rng.setStart(root, 0);
+ rng.setEnd(root, 0);
+ }
+ }
+
+ selection.setRng(rng);
+
+ // Remove tempElm created for old IE:s
+ dom.remove(tempElm);
+
+ viewPort = dom.getViewPort(editor.getWin());
+
+ // scrollIntoView seems to scroll the parent window in most browsers now including FF 3.0b4 so it's time to stop using it and do it our selfs
+ y = dom.getPos(root).y;
+ if (y < viewPort.y || y + 25 > viewPort.y + viewPort.h) {
+ editor.getWin().scrollTo(0, y < viewPort.y ? y : y - viewPort.h + 25); // Needs to be hardcoded to roughly one line of text if a huge text block is broken into two blocks
+ }
+ };
+
+ // Creates a new block element by cloning the current one or creating a new one if the name is specified
+ // This function will also copy any text formatting from the parent block and add it to the new one
+ function createNewBlock(name) {
+ var node = container, block, clonedNode, caretNode;
+
+ block = name || parentBlockName == "TABLE" ? dom.create(name || newBlockName) : parentBlock.cloneNode(false);
+ caretNode = block;
+
+ // Clone any parent styles
+ if (settings.keep_styles !== false) {
+ do {
+ if (/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(node.nodeName)) {
+ clonedNode = node.cloneNode(false);
+ dom.setAttrib(clonedNode, 'id', ''); // Remove ID since it needs to be document unique
+
+ if (block.hasChildNodes()) {
+ clonedNode.appendChild(block.firstChild);
+ block.appendChild(clonedNode);
+ } else {
+ caretNode = clonedNode;
+ block.appendChild(clonedNode);
+ }
+ }
+ } while (node = node.parentNode);
+ }
+
+ // BR is needed in empty blocks on non IE browsers
+ if (!tinymce.isIE) {
+ caretNode.innerHTML = '<br>';
+ }
+
+ return block;
+ };
+
+ // Returns true/false if the caret is at the start/end of the parent block element
+ function isCaretAtStartOrEndOfBlock(start) {
+ var walker, node, name;
+
+ // Caret is in the middle of a text node like "a|b"
+ if (container.nodeType == 3 && (start ? offset > 0 : offset < container.nodeValue.length)) {
+ return false;
+ }
+
+ // If after the last element in block node edge case for #5091
+ if (container.parentNode == parentBlock && isAfterLastNodeInContainer && !start) {
+ return true;
+ }
+
+ // If the caret if before the first element in parentBlock
+ if (start && container.nodeType == 1 && container == parentBlock.firstChild) {
+ return true;
+ }
+
+ // Caret can be before/after a table
+ if (container.nodeName === "TABLE" || (container.previousSibling && container.previousSibling.nodeName == "TABLE")) {
+ return (isAfterLastNodeInContainer && !start) || (!isAfterLastNodeInContainer && start);
+ }
+
+ // Walk the DOM and look for text nodes or non empty elements
+ walker = new TreeWalker(container, parentBlock);
+
+ // If caret is in beginning or end of a text block then jump to the next/previous node
+ if (container.nodeType == 3) {
+ if (start && offset == 0) {
+ walker.prev();
+ } else if (!start && offset == container.nodeValue.length) {
+ walker.next();
+ }
+ }
+
+ while (node = walker.current()) {
+ if (node.nodeType === 1) {
+ // Ignore bogus elements
+ if (!node.getAttribute('data-mce-bogus')) {
+ // Keep empty elements like <img /> <input /> but not trailing br:s like <p>text|<br></p>
+ name = node.nodeName.toLowerCase();
+ if (nonEmptyElementsMap[name] && name !== 'br') {
+ return false;
+ }
+ }
+ } else if (node.nodeType === 3 && !/^[ \t\r\n]*$/.test(node.nodeValue)) {
+ return false;
+ }
+
+ if (start) {
+ walker.prev();
+ } else {
+ walker.next();
+ }
+ }
+
+ return true;
+ };
+
+ // Wraps any text nodes or inline elements in the specified forced root block name
+ function wrapSelfAndSiblingsInDefaultBlock(container, offset) {
+ var newBlock, parentBlock, startNode, node, next, blockName = newBlockName || 'P';
+
+ // Not in a block element or in a table cell or caption
+ parentBlock = dom.getParent(container, dom.isBlock);
+ if (!parentBlock || !canSplitBlock(parentBlock)) {
+ parentBlock = parentBlock || editableRoot;
+
+ if (!parentBlock.hasChildNodes()) {
+ newBlock = dom.create(blockName);
+ parentBlock.appendChild(newBlock);
+ rng.setStart(newBlock, 0);
+ rng.setEnd(newBlock, 0);
+ return newBlock;
+ }
+
+ // Find parent that is the first child of parentBlock
+ node = container;
+ while (node.parentNode != parentBlock) {
+ node = node.parentNode;
+ }
+
+ // Loop left to find start node start wrapping at
+ while (node && !dom.isBlock(node)) {
+ startNode = node;
+ node = node.previousSibling;
+ }
+
+ if (startNode) {
+ newBlock = dom.create(blockName);
+ startNode.parentNode.insertBefore(newBlock, startNode);
+
+ // Start wrapping until we hit a block
+ node = startNode;
+ while (node && !dom.isBlock(node)) {
+ next = node.nextSibling;
+ newBlock.appendChild(node);
+ node = next;
+ }
+
+ // Restore range to it's past location
+ rng.setStart(container, offset);
+ rng.setEnd(container, offset);
+ }
+ }
+
+ return container;
+ };
+
+ // Inserts a block or br before/after or in the middle of a split list of the LI is empty
+ function handleEmptyListItem() {
+ function isFirstOrLastLi(first) {
+ var node = containerBlock[first ? 'firstChild' : 'lastChild'];
+
+ // Find first/last element since there might be whitespace there
+ while (node) {
+ if (node.nodeType == 1) {
+ break;
+ }
+
+ node = node[first ? 'nextSibling' : 'previousSibling'];
+ }
+
+ return node === parentBlock;
+ };
+
+ newBlock = newBlockName ? createNewBlock(newBlockName) : dom.create('BR');
+
+ if (isFirstOrLastLi(true) && isFirstOrLastLi()) {
+ // Is first and last list item then replace the OL/UL with a text block
+ dom.replace(newBlock, containerBlock);
+ } else if (isFirstOrLastLi(true)) {
+ // First LI in list then remove LI and add text block before list
+ containerBlock.parentNode.insertBefore(newBlock, containerBlock);
+ } else if (isFirstOrLastLi()) {
+ // Last LI in list then temove LI and add text block after list
+ dom.insertAfter(newBlock, containerBlock);
+ renderBlockOnIE(newBlock);
+ } else {
+ // Middle LI in list the split the list and insert a text block in the middle
+ // Extract after fragment and insert it after the current block
+ tmpRng = rng.cloneRange();
+ tmpRng.setStartAfter(parentBlock);
+ tmpRng.setEndAfter(containerBlock);
+ fragment = tmpRng.extractContents();
+ dom.insertAfter(fragment, containerBlock);
+ dom.insertAfter(newBlock, containerBlock);
+ }
+
+ dom.remove(parentBlock);
+ moveToCaretPosition(newBlock);
+ undoManager.add();
+ };
+
+ // Walks the parent block to the right and look for BR elements
+ function hasRightSideBr() {
+ var walker = new TreeWalker(container, parentBlock), node;
+
+ while (node = walker.current()) {
+ if (node.nodeName == 'BR') {
+ return true;
+ }
+
+ node = walker.next();
+ }
+ }
+
+ // Inserts a BR element if the forced_root_block option is set to false or empty string
+ function insertBr() {
+ var brElm, extraBr;
+
+ if (container && container.nodeType == 3 && offset >= container.nodeValue.length) {
+ // Insert extra BR element at the end block elements
+ if (!tinymce.isIE && !hasRightSideBr()) {
+ brElm = dom.create('br')
+ rng.insertNode(brElm);
+ rng.setStartAfter(brElm);
+ rng.setEndAfter(brElm);
+ extraBr = true;
+ }
+ }
+
+ brElm = dom.create('br');
+ rng.insertNode(brElm);
+
+ // Rendering modes below IE8 doesn't display BR elements in PRE unless we have a \n before it
+ if (tinymce.isIE && parentBlockName == 'PRE' && (!documentMode || documentMode < 8)) {
+ brElm.parentNode.insertBefore(dom.doc.createTextNode('\r'), brElm);
+ }
+
+ if (!extraBr) {
+ rng.setStartAfter(brElm);
+ rng.setEndAfter(brElm);
+ } else {
+ rng.setStartBefore(brElm);
+ rng.setEndBefore(brElm);
+ }
+
+ selection.setRng(rng);
+ undoManager.add();
+ };
+
+ // Trims any linebreaks at the beginning of node user for example when pressing enter in a PRE element
+ function trimLeadingLineBreaks(node) {
+ do {
+ if (node.nodeType === 3) {
+ node.nodeValue = node.nodeValue.replace(/^[\r\n]+/, '');
+ }
+
+ node = node.firstChild;
+ } while (node);
+ };
+
+ function getEditableRoot(node) {
+ var root = dom.getRoot(), parent, editableRoot;
+
+ // Get all parents until we hit a non editable parent or the root
+ parent = node;
+ while (parent !== root && dom.getContentEditable(parent) !== "false") {
+ if (dom.getContentEditable(parent) === "true") {
+ editableRoot = parent;
+ }
+
+ parent = parent.parentNode;
+ }
+
+ return parent !== root ? editableRoot : root;
+ };
+
+ // Adds a BR at the end of blocks that only contains an IMG or INPUT since these might be floated and then they won't expand the block
+ function addBrToBlockIfNeeded(block) {
+ var lastChild;
+
+ // IE will render the blocks correctly other browsers needs a BR
+ if (!tinymce.isIE) {
+ block.normalize(); // Remove empty text nodes that got left behind by the extract
+
+ // Check if the block is empty or contains a floated last child
+ lastChild = block.lastChild;
+ if (!lastChild || (/^(left|right)$/gi.test(dom.getStyle(lastChild, 'float', true)))) {
+ dom.add(block, 'br');
+ }
+ }
+ };
+
+ // Delete any selected contents
+ if (!rng.collapsed) {
+ editor.execCommand('Delete');
+ return;
+ }
+
+ // Event is blocked by some other handler for example the lists plugin
+ if (evt.isDefaultPrevented()) {
+ return;
+ }
+
+ // Setup range items and newBlockName
+ container = rng.startContainer;
+ offset = rng.startOffset;
+ newBlockName = settings.forced_root_block;
+ newBlockName = newBlockName ? newBlockName.toUpperCase() : '';
+ documentMode = dom.doc.documentMode;
+
+ // Resolve node index
+ if (container.nodeType == 1 && container.hasChildNodes()) {
+ isAfterLastNodeInContainer = offset > container.childNodes.length - 1;
+ container = container.childNodes[Math.min(offset, container.childNodes.length - 1)] || container;
+ if (isAfterLastNodeInContainer && container.nodeType == 3) {
+ offset = container.nodeValue.length;
+ } else {
+ offset = 0;
+ }
+ }
+
+ // Get editable root node normaly the body element but sometimes a div or span
+ editableRoot = getEditableRoot(container);
+
+ // If there is no editable root then enter is done inside a contentEditable false element
+ if (!editableRoot) {
+ return;
+ }
+
+ undoManager.beforeChange();
+
+ // If editable root isn't block nor the root of the editor
+ if (!dom.isBlock(editableRoot) && editableRoot != dom.getRoot()) {
+ if (!newBlockName || evt.shiftKey) {
+ insertBr();
+ }
+
+ return;
+ }
+
+ // Wrap the current node and it's sibling in a default block if it's needed.
+ // for example this <td>text|<b>text2</b></td> will become this <td><p>text|<b>text2</p></b></td>
+ // This won't happen if root blocks are disabled or the shiftKey is pressed
+ if ((newBlockName && !evt.shiftKey) || (!newBlockName && evt.shiftKey)) {
+ container = wrapSelfAndSiblingsInDefaultBlock(container, offset);
+ }
+
+ // Find parent block and setup empty block paddings
+ parentBlock = dom.getParent(container, dom.isBlock);
+ containerBlock = parentBlock ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null;
+
+ // Setup block names
+ parentBlockName = parentBlock ? parentBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
+ containerBlockName = containerBlock ? containerBlock.nodeName.toUpperCase() : ''; // IE < 9 & HTML5
+
+ // Handle enter inside an empty list item
+ if (parentBlockName == 'LI' && dom.isEmpty(parentBlock)) {
+ // Let the list plugin or browser handle nested lists for now
+ if (/^(UL|OL|LI)$/.test(containerBlock.parentNode.nodeName)) {
+ return false;
+ }
+
+ handleEmptyListItem();
+ return;
+ }
+
+ // Don't split PRE tags but insert a BR instead easier when writing code samples etc
+ if (parentBlockName == 'PRE' && settings.br_in_pre !== false) {
+ if (!evt.shiftKey) {
+ insertBr();
+ return;
+ }
+ } else {
+ // If no root block is configured then insert a BR by default or if the shiftKey is pressed
+ if ((!newBlockName && !evt.shiftKey && parentBlockName != 'LI') || (newBlockName && evt.shiftKey)) {
+ insertBr();
+ return;
+ }
+ }
+
+ // Default block name if it's not configured
+ newBlockName = newBlockName || 'P';
+
+ // Insert new block before/after the parent block depending on caret location
+ if (isCaretAtStartOrEndOfBlock()) {
+ // If the caret is at the end of a header we produce a P tag after it similar to Word unless we are in a hgroup
+ if (/^(H[1-6]|PRE)$/.test(parentBlockName) && containerBlockName != 'HGROUP') {
+ newBlock = createNewBlock(newBlockName);
+ } else {
+ newBlock = createNewBlock();
+ }
+
+ // Split the current container block element if enter is pressed inside an empty inner block element
+ if (settings.end_container_on_empty_block && canSplitBlock(containerBlock) && dom.isEmpty(parentBlock)) {
+ // Split container block for example a BLOCKQUOTE at the current blockParent location for example a P
+ newBlock = dom.split(containerBlock, parentBlock);
+ } else {
+ dom.insertAfter(newBlock, parentBlock);
+ }
+
+ moveToCaretPosition(newBlock);
+ } else if (isCaretAtStartOrEndOfBlock(true)) {
+ // Insert new block before
+ newBlock = parentBlock.parentNode.insertBefore(createNewBlock(), parentBlock);
+ renderBlockOnIE(newBlock);
+ } else {
+ // Extract after fragment and insert it after the current block
+ tmpRng = rng.cloneRange();
+ tmpRng.setEndAfter(parentBlock);
+ fragment = tmpRng.extractContents();
+ trimLeadingLineBreaks(fragment);
+ newBlock = fragment.firstChild;
+ dom.insertAfter(fragment, parentBlock);
+ trimInlineElementsOnLeftSideOfBlock(newBlock);
+ addBrToBlockIfNeeded(parentBlock);
+ moveToCaretPosition(newBlock);
+ }
+
+ dom.setAttrib(newBlock, 'id', ''); // Remove ID since it needs to be document unique
+ undoManager.add();
+ }
+
+ editor.onKeyDown.add(function(ed, evt) {
+ if (evt.keyCode == 13) {
+ if (handleEnterKey(evt) !== false) {
+ evt.preventDefault();
+ }
+ }
+ });
+ };
+})(tinymce);
+
diff --git a/askbot/media/js/tinymce/utils/editable_selects.js b/askbot/media/js/tinymce/utils/editable_selects.js
new file mode 100644
index 00000000..4b920f3d
--- /dev/null
+++ b/askbot/media/js/tinymce/utils/editable_selects.js
@@ -0,0 +1,70 @@
+/**
+ * editable_selects.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+var TinyMCE_EditableSelects = {
+ editSelectElm : null,
+
+ init : function() {
+ var nl = document.getElementsByTagName("select"), i, d = document, o;
+
+ for (i=0; i<nl.length; i++) {
+ if (nl[i].className.indexOf('mceEditableSelect') != -1) {
+ o = new Option(tinyMCEPopup.editor.translate('value'), '__mce_add_custom__');
+
+ o.className = 'mceAddSelectValue';
+
+ nl[i].options[nl[i].options.length] = o;
+ nl[i].onchange = TinyMCE_EditableSelects.onChangeEditableSelect;
+ }
+ }
+ },
+
+ onChangeEditableSelect : function(e) {
+ var d = document, ne, se = window.event ? window.event.srcElement : e.target;
+
+ if (se.options[se.selectedIndex].value == '__mce_add_custom__') {
+ ne = d.createElement("input");
+ ne.id = se.id + "_custom";
+ ne.name = se.name + "_custom";
+ ne.type = "text";
+
+ ne.style.width = se.offsetWidth + 'px';
+ se.parentNode.insertBefore(ne, se);
+ se.style.display = 'none';
+ ne.focus();
+ ne.onblur = TinyMCE_EditableSelects.onBlurEditableSelectInput;
+ ne.onkeydown = TinyMCE_EditableSelects.onKeyDown;
+ TinyMCE_EditableSelects.editSelectElm = se;
+ }
+ },
+
+ onBlurEditableSelectInput : function() {
+ var se = TinyMCE_EditableSelects.editSelectElm;
+
+ if (se) {
+ if (se.previousSibling.value != '') {
+ addSelectValue(document.forms[0], se.id, se.previousSibling.value, se.previousSibling.value);
+ selectByValue(document.forms[0], se.id, se.previousSibling.value);
+ } else
+ selectByValue(document.forms[0], se.id, '');
+
+ se.style.display = 'inline';
+ se.parentNode.removeChild(se.previousSibling);
+ TinyMCE_EditableSelects.editSelectElm = null;
+ }
+ },
+
+ onKeyDown : function(e) {
+ e = e || window.event;
+
+ if (e.keyCode == 13)
+ TinyMCE_EditableSelects.onBlurEditableSelectInput();
+ }
+};
diff --git a/askbot/media/js/tinymce/utils/form_utils.js b/askbot/media/js/tinymce/utils/form_utils.js
new file mode 100644
index 00000000..59da0139
--- /dev/null
+++ b/askbot/media/js/tinymce/utils/form_utils.js
@@ -0,0 +1,210 @@
+/**
+ * form_utils.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+var themeBaseURL = tinyMCEPopup.editor.baseURI.toAbsolute('themes/' + tinyMCEPopup.getParam("theme"));
+
+function getColorPickerHTML(id, target_form_element) {
+ var h = "", dom = tinyMCEPopup.dom;
+
+ if (label = dom.select('label[for=' + target_form_element + ']')[0]) {
+ label.id = label.id || dom.uniqueId();
+ }
+
+ h += '<a role="button" aria-labelledby="' + id + '_label" id="' + id + '_link" href="javascript:;" onclick="tinyMCEPopup.pickColor(event,\'' + target_form_element +'\');" onmousedown="return false;" class="pickcolor">';
+ h += '<span id="' + id + '" title="' + tinyMCEPopup.getLang('browse') + '">&nbsp;<span id="' + id + '_label" class="mceVoiceLabel mceIconOnly" style="display:none;">' + tinyMCEPopup.getLang('browse') + '</span></span></a>';
+
+ return h;
+}
+
+function updateColor(img_id, form_element_id) {
+ document.getElementById(img_id).style.backgroundColor = document.forms[0].elements[form_element_id].value;
+}
+
+function setBrowserDisabled(id, state) {
+ var img = document.getElementById(id);
+ var lnk = document.getElementById(id + "_link");
+
+ if (lnk) {
+ if (state) {
+ lnk.setAttribute("realhref", lnk.getAttribute("href"));
+ lnk.removeAttribute("href");
+ tinyMCEPopup.dom.addClass(img, 'disabled');
+ } else {
+ if (lnk.getAttribute("realhref"))
+ lnk.setAttribute("href", lnk.getAttribute("realhref"));
+
+ tinyMCEPopup.dom.removeClass(img, 'disabled');
+ }
+ }
+}
+
+function getBrowserHTML(id, target_form_element, type, prefix) {
+ var option = prefix + "_" + type + "_browser_callback", cb, html;
+
+ cb = tinyMCEPopup.getParam(option, tinyMCEPopup.getParam("file_browser_callback"));
+
+ if (!cb)
+ return "";
+
+ html = "";
+ html += '<a id="' + id + '_link" href="javascript:openBrowser(\'' + id + '\',\'' + target_form_element + '\', \'' + type + '\',\'' + option + '\');" onmousedown="return false;" class="browse">';
+ html += '<span id="' + id + '" title="' + tinyMCEPopup.getLang('browse') + '">&nbsp;</span></a>';
+
+ return html;
+}
+
+function openBrowser(img_id, target_form_element, type, option) {
+ var img = document.getElementById(img_id);
+
+ if (img.className != "mceButtonDisabled")
+ tinyMCEPopup.openBrowser(target_form_element, type, option);
+}
+
+function selectByValue(form_obj, field_name, value, add_custom, ignore_case) {
+ if (!form_obj || !form_obj.elements[field_name])
+ return;
+
+ if (!value)
+ value = "";
+
+ var sel = form_obj.elements[field_name];
+
+ var found = false;
+ for (var i=0; i<sel.options.length; i++) {
+ var option = sel.options[i];
+
+ if (option.value == value || (ignore_case && option.value.toLowerCase() == value.toLowerCase())) {
+ option.selected = true;
+ found = true;
+ } else
+ option.selected = false;
+ }
+
+ if (!found && add_custom && value != '') {
+ var option = new Option(value, value);
+ option.selected = true;
+ sel.options[sel.options.length] = option;
+ sel.selectedIndex = sel.options.length - 1;
+ }
+
+ return found;
+}
+
+function getSelectValue(form_obj, field_name) {
+ var elm = form_obj.elements[field_name];
+
+ if (elm == null || elm.options == null || elm.selectedIndex === -1)
+ return "";
+
+ return elm.options[elm.selectedIndex].value;
+}
+
+function addSelectValue(form_obj, field_name, name, value) {
+ var s = form_obj.elements[field_name];
+ var o = new Option(name, value);
+ s.options[s.options.length] = o;
+}
+
+function addClassesToList(list_id, specific_option) {
+ // Setup class droplist
+ var styleSelectElm = document.getElementById(list_id);
+ var styles = tinyMCEPopup.getParam('theme_advanced_styles', false);
+ styles = tinyMCEPopup.getParam(specific_option, styles);
+
+ if (styles) {
+ var stylesAr = styles.split(';');
+
+ for (var i=0; i<stylesAr.length; i++) {
+ if (stylesAr != "") {
+ var key, value;
+
+ key = stylesAr[i].split('=')[0];
+ value = stylesAr[i].split('=')[1];
+
+ styleSelectElm.options[styleSelectElm.length] = new Option(key, value);
+ }
+ }
+ } else {
+ tinymce.each(tinyMCEPopup.editor.dom.getClasses(), function(o) {
+ styleSelectElm.options[styleSelectElm.length] = new Option(o.title || o['class'], o['class']);
+ });
+ }
+}
+
+function isVisible(element_id) {
+ var elm = document.getElementById(element_id);
+
+ return elm && elm.style.display != "none";
+}
+
+function convertRGBToHex(col) {
+ var re = new RegExp("rgb\\s*\\(\\s*([0-9]+).*,\\s*([0-9]+).*,\\s*([0-9]+).*\\)", "gi");
+
+ var rgb = col.replace(re, "$1,$2,$3").split(',');
+ if (rgb.length == 3) {
+ r = parseInt(rgb[0]).toString(16);
+ g = parseInt(rgb[1]).toString(16);
+ b = parseInt(rgb[2]).toString(16);
+
+ r = r.length == 1 ? '0' + r : r;
+ g = g.length == 1 ? '0' + g : g;
+ b = b.length == 1 ? '0' + b : b;
+
+ return "#" + r + g + b;
+ }
+
+ return col;
+}
+
+function convertHexToRGB(col) {
+ if (col.indexOf('#') != -1) {
+ col = col.replace(new RegExp('[^0-9A-F]', 'gi'), '');
+
+ r = parseInt(col.substring(0, 2), 16);
+ g = parseInt(col.substring(2, 4), 16);
+ b = parseInt(col.substring(4, 6), 16);
+
+ return "rgb(" + r + "," + g + "," + b + ")";
+ }
+
+ return col;
+}
+
+function trimSize(size) {
+ return size.replace(/([0-9\.]+)(px|%|in|cm|mm|em|ex|pt|pc)/i, '$1$2');
+}
+
+function getCSSSize(size) {
+ size = trimSize(size);
+
+ if (size == "")
+ return "";
+
+ // Add px
+ if (/^[0-9]+$/.test(size))
+ size += 'px';
+ // Sanity check, IE doesn't like broken values
+ else if (!(/^[0-9\.]+(px|%|in|cm|mm|em|ex|pt|pc)$/i.test(size)))
+ return "";
+
+ return size;
+}
+
+function getStyle(elm, attrib, style) {
+ var val = tinyMCEPopup.dom.getAttrib(elm, attrib);
+
+ if (val != '')
+ return '' + val;
+
+ if (typeof(style) == 'undefined')
+ style = attrib;
+
+ return tinyMCEPopup.dom.getStyle(elm, style);
+}
diff --git a/askbot/media/js/tinymce/utils/mctabs.js b/askbot/media/js/tinymce/utils/mctabs.js
new file mode 100644
index 00000000..458ec86d
--- /dev/null
+++ b/askbot/media/js/tinymce/utils/mctabs.js
@@ -0,0 +1,162 @@
+/**
+ * mctabs.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+function MCTabs() {
+ this.settings = [];
+ this.onChange = tinyMCEPopup.editor.windowManager.createInstance('tinymce.util.Dispatcher');
+};
+
+MCTabs.prototype.init = function(settings) {
+ this.settings = settings;
+};
+
+MCTabs.prototype.getParam = function(name, default_value) {
+ var value = null;
+
+ value = (typeof(this.settings[name]) == "undefined") ? default_value : this.settings[name];
+
+ // Fix bool values
+ if (value == "true" || value == "false")
+ return (value == "true");
+
+ return value;
+};
+
+MCTabs.prototype.showTab =function(tab){
+ tab.className = 'current';
+ tab.setAttribute("aria-selected", true);
+ tab.setAttribute("aria-expanded", true);
+ tab.tabIndex = 0;
+};
+
+MCTabs.prototype.hideTab =function(tab){
+ var t=this;
+
+ tab.className = '';
+ tab.setAttribute("aria-selected", false);
+ tab.setAttribute("aria-expanded", false);
+ tab.tabIndex = -1;
+};
+
+MCTabs.prototype.showPanel = function(panel) {
+ panel.className = 'current';
+ panel.setAttribute("aria-hidden", false);
+};
+
+MCTabs.prototype.hidePanel = function(panel) {
+ panel.className = 'panel';
+ panel.setAttribute("aria-hidden", true);
+};
+
+MCTabs.prototype.getPanelForTab = function(tabElm) {
+ return tinyMCEPopup.dom.getAttrib(tabElm, "aria-controls");
+};
+
+MCTabs.prototype.displayTab = function(tab_id, panel_id, avoid_focus) {
+ var panelElm, panelContainerElm, tabElm, tabContainerElm, selectionClass, nodes, i, t = this;
+
+ tabElm = document.getElementById(tab_id);
+
+ if (panel_id === undefined) {
+ panel_id = t.getPanelForTab(tabElm);
+ }
+
+ panelElm= document.getElementById(panel_id);
+ panelContainerElm = panelElm ? panelElm.parentNode : null;
+ tabContainerElm = tabElm ? tabElm.parentNode : null;
+ selectionClass = t.getParam('selection_class', 'current');
+
+ if (tabElm && tabContainerElm) {
+ nodes = tabContainerElm.childNodes;
+
+ // Hide all other tabs
+ for (i = 0; i < nodes.length; i++) {
+ if (nodes[i].nodeName == "LI") {
+ t.hideTab(nodes[i]);
+ }
+ }
+
+ // Show selected tab
+ t.showTab(tabElm);
+ }
+
+ if (panelElm && panelContainerElm) {
+ nodes = panelContainerElm.childNodes;
+
+ // Hide all other panels
+ for (i = 0; i < nodes.length; i++) {
+ if (nodes[i].nodeName == "DIV")
+ t.hidePanel(nodes[i]);
+ }
+
+ if (!avoid_focus) {
+ tabElm.focus();
+ }
+
+ // Show selected panel
+ t.showPanel(panelElm);
+ }
+};
+
+MCTabs.prototype.getAnchor = function() {
+ var pos, url = document.location.href;
+
+ if ((pos = url.lastIndexOf('#')) != -1)
+ return url.substring(pos + 1);
+
+ return "";
+};
+
+
+//Global instance
+var mcTabs = new MCTabs();
+
+tinyMCEPopup.onInit.add(function() {
+ var tinymce = tinyMCEPopup.getWin().tinymce, dom = tinyMCEPopup.dom, each = tinymce.each;
+
+ each(dom.select('div.tabs'), function(tabContainerElm) {
+ var keyNav;
+
+ dom.setAttrib(tabContainerElm, "role", "tablist");
+
+ var items = tinyMCEPopup.dom.select('li', tabContainerElm);
+ var action = function(id) {
+ mcTabs.displayTab(id, mcTabs.getPanelForTab(id));
+ mcTabs.onChange.dispatch(id);
+ };
+
+ each(items, function(item) {
+ dom.setAttrib(item, 'role', 'tab');
+ dom.bind(item, 'click', function(evt) {
+ action(item.id);
+ });
+ });
+
+ dom.bind(dom.getRoot(), 'keydown', function(evt) {
+ if (evt.keyCode === 9 && evt.ctrlKey && !evt.altKey) { // Tab
+ keyNav.moveFocus(evt.shiftKey ? -1 : 1);
+ tinymce.dom.Event.cancel(evt);
+ }
+ });
+
+ each(dom.select('a', tabContainerElm), function(a) {
+ dom.setAttrib(a, 'tabindex', '-1');
+ });
+
+ keyNav = tinyMCEPopup.editor.windowManager.createInstance('tinymce.ui.KeyboardNavigation', {
+ root: tabContainerElm,
+ items: items,
+ onAction: action,
+ actOnFocus: true,
+ enableLeftRight: true,
+ enableUpDown: true
+ }, tinyMCEPopup.dom);
+ });
+}); \ No newline at end of file
diff --git a/askbot/media/js/tinymce/utils/validate.js b/askbot/media/js/tinymce/utils/validate.js
new file mode 100644
index 00000000..27cbfab8
--- /dev/null
+++ b/askbot/media/js/tinymce/utils/validate.js
@@ -0,0 +1,252 @@
+/**
+ * validate.js
+ *
+ * Copyright 2009, Moxiecode Systems AB
+ * Released under LGPL License.
+ *
+ * License: http://tinymce.moxiecode.com/license
+ * Contributing: http://tinymce.moxiecode.com/contributing
+ */
+
+/**
+ // String validation:
+
+ if (!Validator.isEmail('myemail'))
+ alert('Invalid email.');
+
+ // Form validation:
+
+ var f = document.forms['myform'];
+
+ if (!Validator.isEmail(f.myemail))
+ alert('Invalid email.');
+*/
+
+var Validator = {
+ isEmail : function(s) {
+ return this.test(s, '^[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+@[-!#$%&\'*+\\/0-9=?A-Z^_`a-z{|}~]+\.[-!#$%&\'*+\\./0-9=?A-Z^_`a-z{|}~]+$');
+ },
+
+ isAbsUrl : function(s) {
+ return this.test(s, '^(news|telnet|nttp|file|http|ftp|https)://[-A-Za-z0-9\\.]+\\/?.*$');
+ },
+
+ isSize : function(s) {
+ return this.test(s, '^[0-9.]+(%|in|cm|mm|em|ex|pt|pc|px)?$');
+ },
+
+ isId : function(s) {
+ return this.test(s, '^[A-Za-z_]([A-Za-z0-9_])*$');
+ },
+
+ isEmpty : function(s) {
+ var nl, i;
+
+ if (s.nodeName == 'SELECT' && s.selectedIndex < 1)
+ return true;
+
+ if (s.type == 'checkbox' && !s.checked)
+ return true;
+
+ if (s.type == 'radio') {
+ for (i=0, nl = s.form.elements; i<nl.length; i++) {
+ if (nl[i].type == "radio" && nl[i].name == s.name && nl[i].checked)
+ return false;
+ }
+
+ return true;
+ }
+
+ return new RegExp('^\\s*$').test(s.nodeType == 1 ? s.value : s);
+ },
+
+ isNumber : function(s, d) {
+ return !isNaN(s.nodeType == 1 ? s.value : s) && (!d || !this.test(s, '^-?[0-9]*\\.[0-9]*$'));
+ },
+
+ test : function(s, p) {
+ s = s.nodeType == 1 ? s.value : s;
+
+ return s == '' || new RegExp(p).test(s);
+ }
+};
+
+var AutoValidator = {
+ settings : {
+ id_cls : 'id',
+ int_cls : 'int',
+ url_cls : 'url',
+ number_cls : 'number',
+ email_cls : 'email',
+ size_cls : 'size',
+ required_cls : 'required',
+ invalid_cls : 'invalid',
+ min_cls : 'min',
+ max_cls : 'max'
+ },
+
+ init : function(s) {
+ var n;
+
+ for (n in s)
+ this.settings[n] = s[n];
+ },
+
+ validate : function(f) {
+ var i, nl, s = this.settings, c = 0;
+
+ nl = this.tags(f, 'label');
+ for (i=0; i<nl.length; i++) {
+ this.removeClass(nl[i], s.invalid_cls);
+ nl[i].setAttribute('aria-invalid', false);
+ }
+
+ c += this.validateElms(f, 'input');
+ c += this.validateElms(f, 'select');
+ c += this.validateElms(f, 'textarea');
+
+ return c == 3;
+ },
+
+ invalidate : function(n) {
+ this.mark(n.form, n);
+ },
+
+ getErrorMessages : function(f) {
+ var nl, i, s = this.settings, field, msg, values, messages = [], ed = tinyMCEPopup.editor;
+ nl = this.tags(f, "label");
+ for (i=0; i<nl.length; i++) {
+ if (this.hasClass(nl[i], s.invalid_cls)) {
+ field = document.getElementById(nl[i].getAttribute("for"));
+ values = { field: nl[i].textContent };
+ if (this.hasClass(field, s.min_cls, true)) {
+ message = ed.getLang('invalid_data_min');
+ values.min = this.getNum(field, s.min_cls);
+ } else if (this.hasClass(field, s.number_cls)) {
+ message = ed.getLang('invalid_data_number');
+ } else if (this.hasClass(field, s.size_cls)) {
+ message = ed.getLang('invalid_data_size');
+ } else {
+ message = ed.getLang('invalid_data');
+ }
+
+ message = message.replace(/{\#([^}]+)\}/g, function(a, b) {
+ return values[b] || '{#' + b + '}';
+ });
+ messages.push(message);
+ }
+ }
+ return messages;
+ },
+
+ reset : function(e) {
+ var t = ['label', 'input', 'select', 'textarea'];
+ var i, j, nl, s = this.settings;
+
+ if (e == null)
+ return;
+
+ for (i=0; i<t.length; i++) {
+ nl = this.tags(e.form ? e.form : e, t[i]);
+ for (j=0; j<nl.length; j++) {
+ this.removeClass(nl[j], s.invalid_cls);
+ nl[j].setAttribute('aria-invalid', false);
+ }
+ }
+ },
+
+ validateElms : function(f, e) {
+ var nl, i, n, s = this.settings, st = true, va = Validator, v;
+
+ nl = this.tags(f, e);
+ for (i=0; i<nl.length; i++) {
+ n = nl[i];
+
+ this.removeClass(n, s.invalid_cls);
+
+ if (this.hasClass(n, s.required_cls) && va.isEmpty(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.number_cls) && !va.isNumber(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.int_cls) && !va.isNumber(n, true))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.url_cls) && !va.isAbsUrl(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.email_cls) && !va.isEmail(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.size_cls) && !va.isSize(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.id_cls) && !va.isId(n))
+ st = this.mark(f, n);
+
+ if (this.hasClass(n, s.min_cls, true)) {
+ v = this.getNum(n, s.min_cls);
+
+ if (isNaN(v) || parseInt(n.value) < parseInt(v))
+ st = this.mark(f, n);
+ }
+
+ if (this.hasClass(n, s.max_cls, true)) {
+ v = this.getNum(n, s.max_cls);
+
+ if (isNaN(v) || parseInt(n.value) > parseInt(v))
+ st = this.mark(f, n);
+ }
+ }
+
+ return st;
+ },
+
+ hasClass : function(n, c, d) {
+ return new RegExp('\\b' + c + (d ? '[0-9]+' : '') + '\\b', 'g').test(n.className);
+ },
+
+ getNum : function(n, c) {
+ c = n.className.match(new RegExp('\\b' + c + '([0-9]+)\\b', 'g'))[0];
+ c = c.replace(/[^0-9]/g, '');
+
+ return c;
+ },
+
+ addClass : function(n, c, b) {
+ var o = this.removeClass(n, c);
+ n.className = b ? c + (o != '' ? (' ' + o) : '') : (o != '' ? (o + ' ') : '') + c;
+ },
+
+ removeClass : function(n, c) {
+ c = n.className.replace(new RegExp("(^|\\s+)" + c + "(\\s+|$)"), ' ');
+ return n.className = c != ' ' ? c : '';
+ },
+
+ tags : function(f, s) {
+ return f.getElementsByTagName(s);
+ },
+
+ mark : function(f, n) {
+ var s = this.settings;
+
+ this.addClass(n, s.invalid_cls);
+ n.setAttribute('aria-invalid', 'true');
+ this.markLabels(f, n, s.invalid_cls);
+
+ return false;
+ },
+
+ markLabels : function(f, n, ic) {
+ var nl, i;
+
+ nl = this.tags(f, "label");
+ for (i=0; i<nl.length; i++) {
+ if (nl[i].getAttribute("for") == n.id || nl[i].htmlFor == n.id)
+ this.addClass(nl[i], ic);
+ }
+
+ return null;
+ }
+};
diff --git a/askbot/media/js/user.js b/askbot/media/js/user.js
new file mode 100644
index 00000000..2fd1195b
--- /dev/null
+++ b/askbot/media/js/user.js
@@ -0,0 +1,1014 @@
+//todo: refactor this into "Inbox" object or more specialized
+var setup_inbox = function(){
+
+ var getSelected = function(){
+
+ var id_list = new Array();
+ var elements = $('#responses input:checked').parent();
+
+ elements.each(function(index, element){
+ var id = $(element).attr('id').replace(/^re_/,'');
+ id_list.push(id);
+ });
+
+ if (id_list.length === 0){
+ alert(gettext('Please select at least one item'));
+ }
+
+ return {id_list: id_list, elements: elements};
+ };
+
+ var submit = function(id_list, elements, action_type){
+ if (action_type == 'delete' || action_type == 'mark_new' || action_type == 'mark_seen' || action_type == 'remove_flag' || action_type == 'delete_post'){
+ $.ajax({
+ type: 'POST',
+ cache: false,
+ dataType: 'json',
+ data: JSON.stringify({memo_list: id_list, action_type: action_type}),
+ url: askbot['urls']['manageInbox'],
+ success: function(response_data){
+ if (response_data['success'] == true){
+ if (action_type == 'delete' || action_type == 'remove_flag' || action_type == 'delete_post'){
+ elements.remove();
+ }
+ else if (action_type == 'mark_new'){
+ elements.addClass('highlight');
+ elements.addClass('new');
+ elements.removeClass('seen');
+ }
+ else if (action_type == 'mark_seen'){
+ elements.removeClass('highlight');
+ elements.addClass('seen');
+ elements.removeClass('new');
+ }
+ }
+ else {
+ showMessage($('#responses'), response_data['message']);
+ }
+ }
+ });
+ }
+ };
+
+ var startAction = function(action_type){
+ var data = getSelected();
+ if (data['id_list'].length === 0){
+ return;
+ }
+ if (action_type == 'delete'){
+ msg = ngettext('Delete this notification?',
+ 'Delete these notifications?', data['id_list'].length);
+ if (confirm(msg) === false){
+ return;
+ }
+ }
+ if (action_type == 'close'){
+ msg = ngettext('Close this entry?',
+ 'Close these entries?', data['id_list'].length);
+ if (confirm(msg) === false){
+ return;
+ }
+ }
+ if (action_type == 'remove_flag'){
+ msg = ngettext(
+ 'Remove all flags and approve this entry?',
+ 'Remove all flags and approve these entries?',
+ data['id_list'].length
+ );
+ if (confirm(msg) === false){
+ return;
+ }
+ }
+ submit(data['id_list'], data['elements'], action_type);
+ };
+ setupButtonEventHandlers($('#re_mark_seen'), function(){startAction('mark_seen')});
+ setupButtonEventHandlers($('#re_mark_new'), function(){startAction('mark_new')});
+ setupButtonEventHandlers($('#re_dismiss'), function(){startAction('delete')});
+ setupButtonEventHandlers($('#re_remove_flag'), function(){startAction('remove_flag')});
+ //setupButtonEventHandlers($('#re_close'), function(){startAction('close')});
+ setupButtonEventHandlers(
+ $('#sel_all'),
+ function(){
+ setCheckBoxesIn('#responses .new', true);
+ setCheckBoxesIn('#responses .seen', true);
+ }
+ );
+ setupButtonEventHandlers(
+ $('#sel_seen'),
+ function(){
+ setCheckBoxesIn('#responses .seen', true);
+ }
+ );
+ setupButtonEventHandlers(
+ $('#sel_new'),
+ function(){
+ setCheckBoxesIn('#responses .new', true);
+ }
+ );
+ setupButtonEventHandlers(
+ $('#sel_none'),
+ function(){
+ setCheckBoxesIn('#responses .new', false);
+ setCheckBoxesIn('#responses .seen', false);
+ }
+ );
+
+ var rejectPostDialog = new RejectPostDialog();
+ rejectPostDialog.decorate($('#reject-edit-modal'));
+ rejectPostDialog.setSelectedEditDataReader(function(){
+ return getSelected();
+ });
+ setupButtonEventHandlers(
+ $('#re_delete_post'),
+ function(){
+ if (rejectPostDialog.readSelectedEditData()) {
+ rejectPostDialog.show();
+ }
+ }
+ );
+
+ if ($('body').hasClass('inbox-flags')) {
+ var responses = $('.response-parent');
+ responses.each(function(idx, response) {
+ var control = new PostModerationControls();
+ control.setParent($(response));
+ control.setReasonsDialog(rejectPostDialog);
+ rejectPostDialog.addPostModerationControl(control);
+ $(response).append(control.getElement());
+ });
+ }
+};
+
+var setup_badge_details_toggle = function(){
+ $('.badge-context-toggle').each(function(idx, elem){
+ var context_list = $(elem).parent().next('ul');
+ if (context_list.children().length > 0){
+ $(elem).addClass('active');
+ var toggle_display = function(){
+ if (context_list.css('display') == 'none'){
+ $('.badge-context-list').hide();
+ context_list.show();
+ } else {
+ context_list.hide();
+ }
+ };
+ $(elem).click(toggle_display);
+ }
+ });
+};
+
+var PostModerationControls = function() {
+ WrappedElement.call(this);
+};
+inherits(PostModerationControls, WrappedElement);
+
+PostModerationControls.prototype.setParent = function(parent_element) {
+ this._parent_element = parent_element;
+};
+
+PostModerationControls.prototype.setReasonsDialog = function(dialog) {
+ this._reasonsDialog = dialog;
+};
+
+PostModerationControls.prototype.getMemoId = function() {
+ return this._parent_element.data('responseId');
+};
+
+PostModerationControls.prototype.getMemoElement = function() {
+ var reId = this.getMemoId();
+ return $('#re_' + reId);
+};
+
+PostModerationControls.prototype.removeMemo = function() {
+ this.getMemoElement().remove();
+};
+
+PostModerationControls.prototype.markMemo = function() {
+ var memo = this.getMemoElement();
+ var checkbox = memo.find('input[type="checkbox"]');
+ checkbox.attr('checked', true);
+};
+
+PostModerationControls.prototype.addReason = function(id, title) {
+ var li = this.makeElement('li');
+ var anchor = this.makeElement('a');
+ anchor.html(title);
+ anchor.data('postId', id);
+ li.append(anchor);
+ var adderLink = this._reasonList.children().last();
+ adderLink.before(li);
+ //attach event handler
+ var me = this;
+ setupButtonEventHandlers(anchor, function() { me.moderatePost(id, 'delete_post') });
+};
+
+PostModerationControls.prototype.moderatePost = function(reasonId, actionType){
+ var me = this;
+ var data = {
+ reject_reason_id: reasonId,
+ memo_list: [me.getMemoId()],
+ action_type: actionType
+ };
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ cache: false,
+ data: JSON.stringify(data),
+ url: askbot['urls']['manageInbox'],
+ success: function(data){
+ if (data['success']){
+ me.removeMemo();
+ me.dispose();
+ if (actionType === 'delete') {
+ notify.show(gettext('Post deleted'));
+ } else if (actionType === 'remove_flag') {
+ notify.show(gettext('Post approved'));
+ }
+ } else {
+ notify.show(data['message']);
+ }
+ }
+ });
+};
+
+
+PostModerationControls.prototype.createDom = function() {
+ var toolbar = this.makeElement('div');
+ toolbar.addClass('btn-toolbar post-moderation-controls');
+ this._element = toolbar;
+
+ var div = this.makeElement('div');
+ div.addClass('btn-group');
+ toolbar.append(div);
+
+ var acceptBtn = this.makeElement('a');
+ acceptBtn.addClass('btn save-reason');
+ acceptBtn.html(gettext('Accept'));
+ div.append(acceptBtn);
+
+ div = this.makeElement('div');
+ div.addClass('btn-group dropdown');
+ toolbar.append(div);
+
+ var toggle = this.makeElement('button');
+ toggle.addClass('btn btn-danger dropdown-toggle');
+ toggle.append($('<span>' + gettext('Reject') + '</span>'));
+ toggle.append($('<span class="caret"></span>'));
+ div.append(toggle);
+
+ toggle.dropdown();
+
+ var ul = this.makeElement('ul');
+ ul.addClass('dropdown-menu');
+ div.append(ul);
+
+ this._reasonList = ul;
+
+ //reason adder
+ var li = this.makeElement('li');
+ var anchor = this.makeElement('a');
+ anchor.html(gettext('add new reject reason'));
+ li.append(anchor);
+ ul.append(li);
+
+ //append menu items
+ var me = this;
+ $.each(askbot['data']['postRejectReasons'], function(idx, reason) {
+ me.addReason(reason['id'], reason['title']);
+ });
+
+ var reasonsDlg = this._reasonsDialog;
+ setupButtonEventHandlers(anchor, function() {
+ me.markMemo();//mark current post
+ reasonsDlg.readSelectedEditData();//read data of selected edits
+ reasonsDlg.show();//open the "big" dialog
+ });
+ setupButtonEventHandlers(acceptBtn, function() {
+ me.moderatePost(null, 'remove_flag');
+ });
+};
+
+/**
+ * @constructor
+ * manages post/edit reject reasons
+ * in the post moderation view
+ */
+var RejectPostDialog = function(){
+ WrappedElement.call(this);
+ this._selected_edit_ids = null;
+ this._selected_reason_id = null;
+ this._state = null;//'select', 'preview', 'add-new'
+ this._postModerationControls = [];
+ this._selectedEditDataReader = undefined;
+};
+inherits(RejectPostDialog, WrappedElement);
+
+RejectPostDialog.prototype.setSelectedEditDataReader = function(func) {
+ this._selectedEditDataReader = func;
+};
+
+RejectPostDialog.prototype.readSelectedEditData = function() {
+ var data = this._selectedEditDataReader();
+ this.setSelectedEditData(data);
+ return data['id_list'].length > 0;
+};
+
+RejectPostDialog.prototype.setSelectedEditData = function(data){
+ this._selected_edit_data = data;
+};
+
+RejectPostDialog.prototype.addPostModerationControl = function(control) {
+ this._postModerationControls.push(control);
+};
+
+RejectPostDialog.prototype.setState = function(state){
+ this._state = state;
+ this.clearErrors();
+ if (this._element){
+ this._selector.hide();
+ this._adder.hide();
+ this._previewer.hide();
+ if (state === 'select'){
+ this._selector.show();
+ } else if (state === 'preview'){
+ this._previewer.show();
+ } else if (state === 'add-new'){
+ this._adder.show();
+ }
+ }
+};
+
+RejectPostDialog.prototype.show = function(){
+ $(this._element).modal('show');
+};
+
+RejectPostDialog.prototype.hide = function(){
+ $(this._element).modal('hide');
+};
+
+RejectPostDialog.prototype.resetInputs = function(){
+ if (this._title_input){
+ this._title_input.reset();
+ }
+ if (this._details_input){
+ this._details_input.reset();
+ }
+ var selected = this._element.find('.selected');
+ selected.removeClass('selected');
+};
+
+RejectPostDialog.prototype.clearErrors = function(){
+ var error = this._element.find('.alert');
+ error.remove();
+};
+
+RejectPostDialog.prototype.makeAlertBox = function(errors){
+ //construct the alert box
+ var alert_box = new AlertBox();
+ alert_box.setClass('alert-error');
+ if (typeof errors === "string"){
+ alert_box.setText(errors);
+ } else if (errors.constructor === [].constructor){
+ if (errors.length > 1){
+ alert_box.setContent(
+ '<div>' +
+ gettext('Looks there are some things to fix:') +
+ '</div>'
+ )
+ var list = this.makeElement('ul');
+ $.each(errors, function(idx, item){
+ list.append('<li>' + item + '</li>');
+ });
+ alert_box.addContent(list);
+ } else if (errors.length == 1){
+ alert_box.setContent(errors[0]);
+ } else if (errors.length == 0){
+ return;
+ }
+ } else if ('html' in errors){
+ alert_box.setContent(errors);
+ } else {
+ return;//don't know what to do
+ }
+ return alert_box;
+};
+
+RejectPostDialog.prototype.setAdderErrors = function(errors){
+ //clear previous errors
+ this.clearErrors();
+ var alert_box = this.makeAlertBox(errors);
+ this._element
+ .find('#reject-edit-modal-add-new .modal-body')
+ .prepend(alert_box.getElement());
+};
+
+RejectPostDialog.prototype.setSelectorErrors = function(errors){
+ this.clearErrors();
+ var alert_box = this.makeAlertBox(errors);
+ this._element
+ .find('#reject-edit-modal-select .modal-body')
+ .prepend(alert_box.getElement());
+};
+
+RejectPostDialog.prototype.setErrors = function(errors){
+ this.clearErrors();
+ var alert_box = this.makeAlertBox(errors);
+ var current_state = this._state;
+ this._element
+ .find('#reject-edit-modal-' + current_state + ' .modal-body')
+ .prepend(alert_box.getElement());
+};
+
+RejectPostDialog.prototype.addSelectableReason = function(data){
+ var id = data['reason_id'];
+ var title = data['title'];
+ var details = data['details'];
+ this._select_box.addItem(id, title, details);
+
+ askbot['data']['postRejectReasons'].push(
+ {id: data['reason_id'], title: data['title']}
+ );
+ $.each(this._postModerationControls, function(idx, control) {
+ control.addReason(data['reason_id'], data['title']);
+ });
+};
+
+RejectPostDialog.prototype.startSavingReason = function(callback){
+
+ var title_input = this._title_input;
+ var details_input = this._details_input;
+
+ var errors = [];
+ if (title_input.isBlank()){
+ errors.push(gettext('Please provide description.'));
+ }
+ if (details_input.isBlank()){
+ errors.push(gettext('Please provide details.'));
+ }
+
+ if (errors.length > 0){
+ this.setAdderErrors(errors);
+ return;//just show errors and quit
+ }
+
+ var data = {
+ title: title_input.getVal(),
+ details: details_input.getVal()
+ };
+ if (this._selected_reason_id){
+ data['reason_id'] = this._selected_reason_id;
+ }
+
+ var me = this;
+
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ cache: false,
+ url: askbot['urls']['save_post_reject_reason'],
+ data: data,
+ success: function(data){
+ if (data['success']){
+ //show current reason data and focus on it
+ me.addSelectableReason(data);
+ if (callback){
+ callback(data);
+ } else {
+ me.setState('select');
+ }
+ } else {
+ me.setAdderErrors(data['message']);
+ }
+ }
+ });
+};
+
+RejectPostDialog.prototype.rejectPost = function(reason_id){
+ var me = this;
+ var memos = this._selected_edit_data['elements'];
+ var memo_ids = this._selected_edit_data['id_list'];
+ var data = {
+ reject_reason_id: reason_id,
+ memo_list: memo_ids,
+ action_type: 'delete_post'
+ };
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ cache: false,
+ data: JSON.stringify(data),
+ url: askbot['urls']['manageInbox'],
+ success: function(data){
+ if (data['success']){
+ $.each(memos, function(idx, memo) {
+ $(memo).next('.post-moderation-controls').remove();
+ $(memo).remove();
+ });
+ me.hide();
+ } else {
+ //only fatal errors here
+ me.setErrors(data['message']);
+ }
+ }
+ });
+};
+
+RejectPostDialog.prototype.setPreviewerData = function(data){
+ this._selected_reason_id = data['id'];
+ this._element.find('.selected-reason-title').html(data['title']);
+ this._element.find('.selected-reason-details').html(data['details']);
+};
+
+RejectPostDialog.prototype.startEditingReason = function(){
+ var title = this._element.find('.selected-reason-title').html();
+ var details = this._element.find('.selected-reason-details').html();
+ this._title_input.setVal(title);
+ this._details_input.setVal(details);
+ this.setState('add-new');
+};
+
+RejectPostDialog.prototype.resetSelectedReasonId = function(){
+ this._selected_reason_id = null;
+};
+
+RejectPostDialog.prototype.getSelectedReasonId = function(){
+ return this._selected_reason_id;
+};
+
+RejectPostDialog.prototype.startDeletingReason = function(){
+ var select_box = this._select_box;
+ var data = select_box.getSelectedItemData();
+ var reason_id = data['id'];
+ var me = this;
+ if (data['id']){
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ cache: false,
+ url: askbot['urls']['delete_post_reject_reason'],
+ data: {reason_id: reason_id},
+ success: function(data){
+ if (data['success']){
+ select_box.removeItem(reason_id);
+ } else {
+ me.setSelectorErrors(data['message']);
+ }
+ }
+ });
+ } else {
+ me.setSelectorErrors(
+ gettext('A reason must be selected to delete one.')
+ )
+ }
+};
+
+RejectPostDialog.prototype.decorate = function(element){
+ this._element = element;
+ //set default state according to the # of available reasons
+ this._selector = $(element).find('#reject-edit-modal-select');
+ this._adder = $(element).find('#reject-edit-modal-add-new');
+ this._previewer = $(element).find('#reject-edit-modal-preview');
+ if (this._selector.find('li').length > 0){
+ this.setState('select');
+ this.resetInputs();
+ } else {
+ this.setState('add-new');
+ this.resetInputs();
+ }
+
+ $(this._element).find('.dropdown-toggle').dropdown();
+
+ var select_box = new SelectBox();
+ select_box.decorate($(this._selector.find('.select-box')));
+ this._select_box = select_box;
+
+ //setup tipped-inputs
+ var reject_title_input = $(this._element).find('input');
+ var title_input = new TippedInput();
+ title_input.decorate($(reject_title_input));
+ this._title_input = title_input;
+
+ var reject_details_input = $(this._element)
+ .find('textarea.reject-reason-details');
+
+ var details_input = new TippedInput();
+ details_input.decorate($(reject_details_input));
+ this._details_input = details_input;
+
+ var me = this;
+ setupButtonEventHandlers(
+ element.find('.cancel, .modal-header .close'),
+ function() {
+ me.hide();
+ me.clearErrors();
+ me.resetInputs();
+ me.resetSelectedReasonId();
+ me.setState('select');
+ }
+ );
+
+ setupButtonEventHandlers(
+ $(this._element).find('.save-reason'),
+ function(){ me.startSavingReason() }
+ );
+
+ setupButtonEventHandlers(
+ $(this._element).find('.save-reason-and-reject'),
+ function(){
+ me.startSavingReason(
+ function(data){
+ me.rejectPost(data['reason_id']);
+ }
+ );
+ }
+ );
+
+ setupButtonEventHandlers(
+ $(this._element).find('.reject'),
+ function(){
+ me.rejectPost(me.getSelectedReasonId());
+ }
+ );
+
+ setupButtonEventHandlers(
+ element.find('.select-other-reason'),
+ function(){
+ me.resetInputs();
+ me.setState('select');
+ }
+ )
+
+ setupButtonEventHandlers(
+ element.find('.add-new-reason'),
+ function(){
+ me.resetSelectedReasonId();
+ me.resetInputs();
+ me.setState('add-new')
+ }
+ );
+
+ setupButtonEventHandlers(
+ element.find('.select-this-reason'),
+ function(){
+ var data = select_box.getSelectedItemData();
+ if (data['id']){
+ me.setState('preview');
+ me.setPreviewerData(data);
+ } else {
+ me.setSelectorErrors(
+ gettext('A reason must be selected to reject post.')
+ )
+ }
+ }
+ );
+
+ setupButtonEventHandlers(
+ element.find('.edit-reason'),
+ function(){
+ me.startEditingReason();
+ }
+ );
+
+ setupButtonEventHandlers(
+ element.find('.delete-this-reason'),
+ function(){
+ me.startDeletingReason();
+ }
+ )
+};
+
+/**
+ * @constructor
+ * allows to follow/unfollow users
+ */
+var FollowUser = function(){
+ WrappedElement.call(this);
+ this._user_id = null;
+ this._user_name = null;
+};
+inherits(FollowUser, WrappedElement);
+
+/**
+ * @param {string} user_name
+ */
+FollowUser.prototype.setUserName = function(user_name){
+ this._user_name = user_name;
+};
+
+FollowUser.prototype.decorate = function(element){
+ this._element = element;
+ this._user_id = parseInt(element.attr('id').split('-').pop());
+ this._available_action = element.children().hasClass('follow') ? 'follow':'unfollow';
+ var me = this;
+ setupButtonEventHandlers(this._element, function(){ me.go() });
+};
+
+FollowUser.prototype.go = function(){
+ if (askbot['data']['userIsAuthenticated'] === false){
+ var message = gettext('Please <a href="%(signin_url)s">signin</a> to follow %(username)s');
+ var message_data = {
+ signin_url: askbot['urls']['user_signin'] + '?next=' + window.location.href,
+ username: this._user_name
+ }
+ message = interpolate(message, message_data, true);
+ showMessage(this._element, message);
+ return;
+ }
+ var user_id = this._user_id;
+ if (this._available_action === 'follow'){
+ var url = askbot['urls']['follow_user'];
+ } else {
+ var url = askbot['urls']['unfollow_user'];
+ }
+ var me = this;
+ $.ajax({
+ type: 'POST',
+ cache: false,
+ dataType: 'json',
+ url: url.replace('{{userId}}', user_id),
+ success: function(){ me.toggleState() }
+ });
+};
+
+FollowUser.prototype.toggleState = function(){
+ if (this._available_action === 'follow'){
+ this._available_action = 'unfollow';
+ var unfollow_div = document.createElement('div');
+ unfollow_div.setAttribute('class', 'unfollow');
+ var red_div = document.createElement('div');
+ red_div.setAttribute('class', 'unfollow-red');
+ red_div.innerHTML = interpolate(gettext('unfollow %s'), [this._user_name]);
+ var green_div = document.createElement('div');
+ green_div.setAttribute('class', 'unfollow-green');
+ green_div.innerHTML = interpolate(gettext('following %s'), [this._user_name]);
+ unfollow_div.appendChild(red_div);
+ unfollow_div.appendChild(green_div);
+ this._element.html(unfollow_div);
+ } else {
+ var follow_div = document.createElement('div');
+ follow_div.innerHTML = interpolate(gettext('follow %s'), [this._user_name]);
+ follow_div.setAttribute('class', 'follow');
+ this._available_action = 'follow';
+ this._element.html(follow_div);
+ }
+};
+
+/**
+ * @constructor
+ * @param {string} name
+ */
+var UserGroup = function(name){
+ WrappedElement.call(this);
+ this._name = name;
+ this._content = null;
+};
+inherits(UserGroup, WrappedElement);
+
+UserGroup.prototype.getDeleteHandler = function(){
+ var group_name = this._name;
+ var me = this;
+ var groups_container = me._groups_container;
+ return function(){
+ var data = {
+ user_id: askbot['data']['viewUserId'],
+ group_name: group_name,
+ action: 'remove'
+ };
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ data: data,
+ cache: false,
+ url: askbot['urls']['edit_group_membership'],
+ success: function(){
+ groups_container.removeGroup(me);
+ }
+ });
+ };
+};
+
+UserGroup.prototype.setContent = function(content){
+ this._content = content;
+};
+
+UserGroup.prototype.getName = function(){
+ return this._name;
+};
+
+UserGroup.prototype.setGroupsContainer = function(container){
+ this._groups_container = container;
+};
+
+UserGroup.prototype.decorate = function(element){
+ this._element = element;
+ this._name = $.trim(element.find('a').html());
+ var deleter = new DeleteIcon();
+ deleter.setHandler(this.getDeleteHandler());
+ deleter.setContent(gettext('Remove'));
+ this._element.find('td:last').append(deleter.getElement());
+ this._delete_icon = deleter;
+};
+
+UserGroup.prototype.createDom = function(){
+ var element = this.makeElement('tr');
+ element.html(this._content);
+ this._element = element;
+ this.decorate(element);
+};
+
+UserGroup.prototype.dispose = function(){
+ this._delete_icon.dispose();
+ this._element.remove();
+};
+
+/**
+ * @constructor
+ */
+var GroupsContainer = function(){
+ WrappedElement.call(this);
+};
+inherits(GroupsContainer, WrappedElement);
+
+GroupsContainer.prototype.decorate = function(element){
+ this._element = element;
+ var groups = [];
+ var group_names = [];
+ var me = this;
+ //collect list of groups
+ $.each(element.find('tr'), function(idx, li){
+ var group = new UserGroup();
+ group.setGroupsContainer(me);
+ group.decorate($(li));
+ groups.push(group);
+ group_names.push(group.getName());
+ });
+ this._groups = groups;
+ this._group_names = group_names;
+};
+
+GroupsContainer.prototype.addGroup = function(group_data){
+ var group_name = group_data['name'];
+ if ($.inArray(group_name, this._group_names) > -1){
+ return;
+ }
+ var group = new UserGroup(group_name);
+ group.setContent(group_data['html']);
+ group.setGroupsContainer(this);
+ this._groups.push(group);
+ this._group_names.push(group_name);
+ this._element.append(group.getElement());
+};
+
+GroupsContainer.prototype.removeGroup = function(group){
+ var idx = $.inArray(group, this._groups);
+ if (idx === -1){
+ return;
+ }
+ this._groups.splice(idx, 1);
+ this._group_names.splice(idx, 1);
+ group.dispose();
+};
+
+var GroupAdderWidget = function(){
+ WrappedElement.call(this);
+ this._state = 'display';//display or edit
+};
+inherits(GroupAdderWidget, WrappedElement);
+
+/**
+ * @param {string} state
+ */
+GroupAdderWidget.prototype.setState = function(state){
+ if (state === 'display'){
+ this._element.html(gettext('add group'));
+ this._input.hide();
+ this._input.val('');
+ this._button.hide();
+ } else if (state === 'edit'){
+ this._element.html(gettext('cancel'));
+ this._input.show();
+ this._input.focus();
+ this._button.show();
+ } else {
+ return;
+ }
+ this._state = state;
+};
+
+GroupAdderWidget.prototype.getValue = function(){
+ return this._input.val();
+};
+
+GroupAdderWidget.prototype.addGroup = function(group_data){
+ this._groups_container.addGroup(group_data);
+};
+
+GroupAdderWidget.prototype.getAddGroupHandler = function(){
+ var me = this;
+ return function(){
+ var group_name = me.getValue();
+ var data = {
+ group_name: group_name,
+ user_id: askbot['data']['viewUserId'],
+ action: 'add'
+ };
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ data: data,
+ cache: false,
+ url: askbot['urls']['edit_group_membership'],
+ success: function(data){
+ if (data['success'] == true){
+ me.addGroup(data);
+ me.setState('display');
+ } else {
+ var message = data['message'];
+ showMessage(me.getElement(), message, 'after');
+ }
+ }
+ });
+ };
+};
+
+GroupAdderWidget.prototype.setGroupsContainer = function(container){
+ this._groups_container = container;
+};
+
+GroupAdderWidget.prototype.toggleState = function(){
+ if (this._state === 'display'){
+ this.setState('edit');
+ } else if (this._state === 'edit'){
+ this.setState('display');
+ }
+};
+
+GroupAdderWidget.prototype.decorate = function(element){
+ this._element = element;
+ var input = this.makeElement('input');
+ this._input = input;
+
+ var groupsAc = new AutoCompleter({
+ url: askbot['urls']['getGroupsList'],
+ preloadData: true,
+ minChars: 1,
+ useCache: false,
+ matchInside: false,
+ maxCacheLength: 100,
+ delay: 10
+ });
+ groupsAc.decorate(input);
+
+ var button = this.makeElement('button');
+ button.html(gettext('add'));
+ this._button = button;
+ element.before(input);
+ input.after(button);
+ this.setState('display');
+ setupButtonEventHandlers(button, this.getAddGroupHandler());
+ var me = this;
+ setupButtonEventHandlers(
+ element,
+ function(){ me.toggleState() }
+ );
+};
+
+/**
+ * @constructor
+ * allows editing user groups
+ */
+var UserGroupsEditor = function(){
+ WrappedElement.call(this);
+};
+inherits(UserGroupsEditor, WrappedElement);
+
+UserGroupsEditor.prototype.decorate = function(element){
+ this._element = element;
+ var add_link = element.find('#add-group');
+ var adder = new GroupAdderWidget();
+ adder.decorate(add_link);
+
+ var groups_container = new GroupsContainer();
+ groups_container.decorate(element.find('#groups-list'));
+ adder.setGroupsContainer(groups_container);
+ //todo - add group deleters
+};
+
+(function(){
+ var fbtn = $('.follow-user-toggle');
+ if (fbtn.length === 1){
+ var follow_user = new FollowUser();
+ follow_user.decorate(fbtn);
+ follow_user.setUserName(askbot['data']['viewUserName']);
+ }
+ if (askbot['data']['userId'] !== askbot['data']['viewUserId']) {
+ if (askbot['data']['userIsAdminOrMod']){
+ var group_editor = new UserGroupsEditor();
+ group_editor.decorate($('#user-groups'));
+ } else {
+ $('#add-group').remove();
+ }
+ } else {
+ $('#add-group').remove();
+ }
+})();
diff --git a/askbot/media/js/utils.js b/askbot/media/js/utils.js
new file mode 100644
index 00000000..1dddc07d
--- /dev/null
+++ b/askbot/media/js/utils.js
@@ -0,0 +1,2959 @@
+//var $, scriptUrl, askbotSkin
+/**
+ * attention - this function needs to be retired
+ * as it cannot accurately give url to the media file
+ */
+var mediaUrl = function(resource){
+ return askbot['settings']['static_url'] + 'default' + '/' + resource;
+};
+
+var cleanUrl = function(url){
+ var re = new RegExp('//', 'g');
+ return url.replace(re, '/');
+};
+
+var copyAltToTitle = function(sel){
+ sel.attr('title', sel.attr('alt'));
+};
+
+var animateHashes = function(){
+ var id_value = window.location.hash;
+ if (id_value != ""){
+ var previous_color = $(id_value).css('background-color');
+ $(id_value).css('backgroundColor', '#FFF8C6');
+ $(id_value)
+ .animate({backgroundColor: '#ff7f2a'}, 500)
+ .animate({backgroundColor: '#FFF8C6'}, 500, function(){
+ $(id_value).css('backgroundColor', previous_color);
+ });
+ }
+};
+
+var getUniqueValues = function(values) {
+ var uniques = new Object();
+ var out = new Array();
+ $.each(values, function(idx, value){
+ if (!(value in uniques)){
+ uniques[value] = 1;
+ out.push(value);
+ };
+ });
+ return out;
+}
+
+var getUniqueWords = function(value){
+ var words = $.trim(value).split(/\s+/);
+ return getUniqueValues(words);
+};
+
+/**
+ * comma-joins items and uses "and'
+ * between the last and penultimate items
+ * @param {Array<string>} values
+ * @return {string}
+ */
+var joinAsPhrase = function(values) {
+ var count = values.length;
+ if (count === 0) {
+ return '';
+ } else if (count === 1) {
+ return values[0];
+ } else {
+ var last = values.pop();
+ var prev = values.pop();
+ return values.join(', ') + prev + gettext('and') + last;
+ }
+};
+
+var showMessage = function(element, msg, where) {
+ var div = $('<div class="vote-notification"><h3>' + msg + '</h3>(' +
+ gettext('click to close') + ')</div>');
+
+ div.click(function(event) {
+ $(".vote-notification").fadeOut("fast", function() { $(this).remove(); });
+ });
+
+ var where = where || 'parent';
+
+ if (where == 'parent'){
+ element.parent().append(div);
+ }
+ else {
+ element.after(div);
+ }
+
+ div.fadeIn("fast");
+};
+
+//outer html hack - https://github.com/brandonaaron/jquery-outerhtml/
+(function($){
+ var div;
+ $.fn.outerHTML = function() {
+ var elem = this[0],
+ tmp;
+ return !elem ? null
+ : typeof ( tmp = elem.outerHTML ) === 'string' ? tmp
+ : ( div = div || $('<div/>') ).html( this.eq(0).clone() ).html();
+ };
+})(jQuery);
+
+var makeKeyHandler = function(key, callback){
+ return function(e){
+ if ((e.which && e.which == key) || (e.keyCode && e.keyCode == key)){
+ if(!e.shiftKey){
+ callback();
+ return false;
+ }
+ }
+ };
+};
+
+
+var setupButtonEventHandlers = function(button, callback){
+ button.keydown(makeKeyHandler(13, callback));
+ button.click(callback);
+};
+
+
+var putCursorAtEnd = function(element){
+ var el = element.get()[0];
+ if (el.setSelectionRange){
+ var len = element.val().length * 2;
+ el.setSelectionRange(len, len);
+ }
+ else{
+ element.val(element.val());
+ }
+ element.scrollTop = 999999;
+};
+
+var setCheckBoxesIn = function(selector, value){
+ return $(selector + '> input[type=checkbox]').attr('checked', value);
+};
+
+/*
+ * Old style notify handler
+ */
+var notify = function() {
+ var visible = false;
+ return {
+ show: function(html, autohide) {
+ if (html) {
+ $("body").addClass('user-messages');
+ var par = $('<p class="notification"></p>');
+ par.html(html);
+ $(".notify").prepend(par);
+ }
+ $(".notify").fadeIn("slow");
+ visible = true;
+ if (autohide) {
+ setTimeout(
+ function() {
+ notify.close(false);
+ notify.clear();
+ },
+ 3000
+ );
+ }
+ },
+ clear: function() {
+ $('.notify').empty();
+ },
+ close: function(doPostback) {
+ if (doPostback) {
+ $.post(
+ askbot['urls']['mark_read_message'],
+ { formdata: "required" }
+ );
+ }
+ $(".notify").fadeOut("fast");
+ $('body').removeClass('user-messages');
+ visible = false;
+ },
+ isVisible: function() { return visible; }
+ };
+}();
+
+/* **************************************************** */
+// Search query-string manipulation utils
+/* **************************************************** */
+
+var QSutils = QSutils || {}; // TODO: unit-test me
+
+QSutils.TAG_SEP = ','; // should match const.TAG_SEP; TODO: maybe prepopulate this in javascript.html ?
+
+QSutils.get_query_string_selector_value = function (query_string, selector) {
+ var params = query_string.split('/');
+ for(var i=0; i<params.length; i++) {
+ var param_split = params[i].split(':');
+ if(param_split[0] === selector) {
+ return param_split[1];
+ }
+ }
+ return undefined;
+};
+
+QSutils.patch_query_string = function (query_string, patch, remove) {
+ var params = query_string.split('/');
+ var patch_split = patch.split(':');
+
+ var new_query_string = '';
+ var mapping = {};
+
+ if(!remove) {
+ mapping[patch_split[0]] = patch_split[1]; // prepopulate the patched selector if it's not meant to be removed
+ }
+
+ for (var i = 0; i < params.length; i++) {
+ var param_split = params[i].split(':');
+ if(param_split[0] !== patch_split[0] && param_split[1]) {
+ mapping[param_split[0]] = param_split[1];
+ }
+ }
+
+ var add_selector = function(name) {
+ if(name in mapping) {
+ new_query_string += name + ':' + mapping[name] + '/';
+ }
+ };
+
+ /* The order of selectors should match the Django URL */
+ add_selector('scope');
+ add_selector('sort');
+ add_selector('query');
+ add_selector('tags');
+ add_selector('author');
+ add_selector('page');
+
+ return new_query_string;
+};
+
+QSutils.remove_search_tag = function(query_string, tag){
+ var tag_string = this.get_query_string_selector_value(query_string, 'tags');
+ if(!tag_string) {
+ return query_string;
+ }
+
+ var tags = tag_string.split(this.TAG_SEP);
+
+ var pos = $.inArray(encodeURIComponent(tag), tags);
+ if(pos > -1) {
+ tags.splice(pos, 1); /* array.splice() works in-place */
+ }
+
+ if(tags.length === 0) {
+ return this.patch_query_string(query_string, 'tags:', true);
+ } else {
+ return this.patch_query_string(query_string, 'tags:' + tags.join(this.TAG_SEP));
+ }
+};
+
+QSutils.add_search_tag = function(query_string, tag){
+ var tag_string = this.get_query_string_selector_value(query_string, 'tags');
+ tag = encodeURIComponent(tag);
+ if(!tag_string) {
+ tag_string = tag;
+ } else {
+ tag_string = [tag_string, tag].join(this.TAG_SEP);
+ }
+
+ return this.patch_query_string(query_string, 'tags:' + tag_string);
+};
+
+/* **************************************************** */
+
+/* some google closure-like code for the ui elements */
+var inherits = function(childCtor, parentCtor) {
+ /** @constructor taken from google closure */
+ function tempCtor() {};
+ tempCtor.prototype = parentCtor.prototype;
+ childCtor.superClass_ = parentCtor.prototype;
+ childCtor.prototype = new tempCtor();
+ childCtor.prototype.constructor = childCtor;
+};
+
+/** wrapper around jQuery object
+ * @constructor
+ * the top level "class" for other elements
+ * I.e. all other things must inherit this class.
+ * For an example of the inheritance pattern,
+ * please see the "TippedInput" below.
+ */
+var WrappedElement = function(){
+ this._element = null;
+ this._in_document = false;
+};
+/* note that we do not call inherits() here
+ * See TippedInput as an example of a subclass
+ */
+
+/**
+ * notice that we use ObjCls.prototype.someMethod = function()
+ * notation - as we use Javascript's prototypal inheritance
+ * explicitly. The point of this is to be able to eventually
+ * use the Closure Compiler
+ */
+WrappedElement.prototype.setElement = function(element){
+ this._element = element;
+};
+
+/**
+ * this function must be overridden for any object
+ * what will use "DOM generation" pattern
+ *
+ * Inside this function two things can happen:
+ * 1) dom structure creation
+ * 2) event handlers attached to the dom structure
+ */
+WrappedElement.prototype.createDom = function(){
+ /* inside at the very least you must assign
+ * a jQuery object to a parameter called _element
+ */
+ this._element = $('<div></div>');
+};
+
+/**
+ * @param {object} element, a jQuery object wrapping a single
+ * DOM element.
+ *
+ * This function must be overridden in the subclasses
+ * that are used in the "decoration" pattern
+ */
+WrappedElement.prototype.decorate = function(element){
+ this._element = element;
+};
+
+/**
+ * This method should not be overridden
+ * Normally you call this method to generate the dom
+ * structure, if applicable, or just obtain the
+ * jQuery object encapsulating the dom.
+ *
+ * @return {object} jQuery
+ */
+WrappedElement.prototype.getElement = function(){
+ if (this._element === null){
+ this.createDom();
+ }
+ return this._element;
+};
+WrappedElement.prototype.inDocument = function(){
+ return this._in_document;
+};
+WrappedElement.prototype.enterDocument = function(){
+ return this._in_document = true;
+};
+WrappedElement.prototype.hasElement = function(){
+ return (this._element !== null);
+};
+/**
+ * A utility method, returning a new jQuery object for
+ * some HTML tag
+ *
+ * Example:
+ * var ageInput = this.makeElement('input');
+ */
+WrappedElement.prototype.makeElement = function(html_tag){
+ //makes jQuery element with tags
+ return $('<' + html_tag + '></' + html_tag + '>');
+};
+/**
+ * Removes object's DOM element from the DOM tree
+ * should be overridden to remove the event handlers
+ * and properly destroy the dom structure
+ * as well as any other included sub-elements
+ */
+WrappedElement.prototype.dispose = function(){
+ this._element.remove();
+ this._in_document = false;
+};
+
+/**
+ * @constructor
+ * Widget is a Wrapped element with state
+ */
+var Widget = function() {
+ WrappedElement.call(this);
+ this._state = undefined;
+};
+inherits(Widget, WrappedElement);
+
+Widget.prototype.setState = function(state) {
+ this._state = state;
+};
+
+Widget.prototype.getState = function() {
+ return this._state;
+};
+
+Widget.prototype.makeButton = function(label, handler) {
+ var button = this.makeElement('button');
+ button.html(label);
+ setupButtonEventHandlers(button, handler);
+ return button;
+};
+
+/**
+ * Can be used for an input box or textarea.
+ * The original value will be treated as an instruction.
+ * When user focuses on the field, the tip will be gone,
+ * when the user escapes without typing anything besides
+ * perhaps empty text, the instruction is restored.
+ * When instruction is shown, class "blank" is present
+ * in the input/textare element.
+ *
+ * For the usage examples - search for "new TippedInput"
+ * there is at least one example for both - decoration and
+ * the "dom creation" patterns.
+ *
+ * Also - in the FileUploadDialog the TippedInput is used
+ * as a sub-element - the widget composition use case.
+ */
+var TippedInput = function(){
+ /* the call below is part 1 of the inheritance pattern */
+ WrappedElement.call(this);
+ this._instruction = null;
+ this._attrs = {};
+ //this._is_one_shot = false;//if true on starting typing effect is gone
+};
+inherits(TippedInput, WrappedElement);
+/* the line above is part 2 of the inheritance pattern
+ see definition of the function "inherits" for more details
+*/
+
+/* Below are all the custom methods of the
+ TippedInput class, as well as some required functions
+*/
+
+TippedInput.prototype.reset = function(){
+ $(this._element).val(this._instruction);
+ $(this._element).addClass('blank');
+};
+
+/*TippedInput.prototype.setIsOneShot = function(boolValue) {
+ this._is_one_shot = boolValue;
+};*/
+
+TippedInput.prototype.setInstruction = function(text) {
+ this._instruction = text;
+};
+
+TippedInput.prototype.setAttr = function(key, value) {
+ this._attrs[key] = value;
+};
+
+TippedInput.prototype.isBlank = function(){
+ return this.getVal() === this._instruction;
+};
+
+TippedInput.prototype.getVal = function(){
+ return this._element.val();
+};
+
+TippedInput.prototype.setVal = function(value){
+ if (value) {
+ this._element.val(value);
+ if (this.isBlank()){
+ this._element.addClass('blank');
+ } else {
+ this._element.removeClass('blank');
+ }
+ }
+};
+/**
+ * Creates the DOM of tipped input from scratch
+ * Notice that there is also a "decorate" method.
+ * At least one - createDom or decorate is required,
+ * depending on the usage.
+ */
+TippedInput.prototype.createDom = function() {
+ this._element = this.makeElement('input');
+ var element = this._element;
+ element.val(this._instruction);
+
+ //here we re-use the decorate call (next method)
+ //to avoid copy-pasting code
+ this.decorate(element);
+};
+
+/**
+ * Attaches the TippedInput behavior to
+ * a pre-existing <input> element
+ *
+ * decorate() method normally does not create
+ * new dom elements, but it might add some missing elements,
+ * if necessary.
+ *
+ * for example the decorate might be composing inside
+ * a more complex widget, in which case other elements
+ * can be added via a "composition" pattern, or
+ * just "naked dom elements" added to the current widget's element
+ *
+ */
+TippedInput.prototype.decorate = function(element){
+ this._element = element;//mandatory line
+
+ //part 1 - initialize some values and create dom
+ element.attr(this._attrs);
+
+ var instruction_text = this.getVal();
+ this._instruction = instruction_text;
+ this.reset();
+ var me = this;
+
+ //part 2 - attach event handlers
+ $(element).focus(function(){
+ if (me.isBlank()){
+ $(element)
+ .val('')
+ .removeClass('blank');
+ }
+ });
+ $(element).blur(function(){
+ var val = $(element).val();
+ if ($.trim(val) === ''){
+ $(element)
+ .val(instruction_text)
+ .addClass('blank');
+ }
+ });
+ $(element).keydown(
+ makeKeyHandler(27, function(){
+ $(element).blur();
+ })
+ );
+};
+
+/**
+ * will setup a bootstrap.js alert
+ * programmatically
+ */
+var AlertBox = function(){
+ WrappedElement.call(this);
+ this._text = null;
+};
+inherits(AlertBox, WrappedElement);
+
+AlertBox.prototype.setClass = function(classes){
+ this._classes = classes;
+ if (this._element){
+ this._element.addClass(classes);
+ }
+};
+
+AlertBox.prototype.setError = function(state){
+ this._is_error = state;
+ if (this._element) {
+ if (state === true) {
+ this._element.addClass('alert-error');
+ } else {
+ this._element.removeClass('alert-error');
+ }
+ }
+};
+
+AlertBox.prototype.setText = function(text){
+ this._text = text;
+ if (this._content){
+ this._content.html(text);
+ }
+};
+
+AlertBox.prototype.getContent = function(){
+ if (this._content){
+ return this._content;
+ } else {
+ this._content = this.makeElement('div');
+ return this._content;
+ }
+};
+
+AlertBox.prototype.setContent = function(content){
+ var container = this.getContent();
+ container.empty()
+ container.append(content);
+};
+
+AlertBox.prototype.addContent = function(content){
+ var container = this.getContent();
+ container.append(content);
+};
+
+AlertBox.prototype.createDom = function(){
+ this._element = this.makeElement('div');
+ this._element.addClass('alert fade in');
+
+ if (this._is_error) {
+ this.setError(this._is_error);
+ }
+
+ if (this._classes){
+ this._element.addClass(this._classes);
+ }
+
+ this._cancel_button = this.makeElement('button');
+ this._cancel_button
+ .addClass('close')
+ .attr('data-dismiss', 'alert')
+ .html('&times;');
+ this._element.append(this._cancel_button);
+
+ this._element.append(this.getContent());
+ if (this._text){
+ this.setText(this._text);
+ }
+
+ this._element.alert();//bootstrap.js alert
+};
+
+/**
+ * @constructor
+ * just a span with content
+ * useful for subclassing
+ */
+var SimpleContent = function(){
+ WrappedElement.call(this);
+ this._content = '';
+};
+inherits(SimpleContent, WrappedElement);
+
+SimpleContent.prototype.setContent = function(text) {
+ this._content = text;
+ if (this._element) {
+ this._element.html(text);
+ }
+};
+
+SimpleContent.prototype.getContent = function() {
+ return this._content;
+};
+
+SimpleContent.prototype.createDom = function() {
+ this._element = this.makeElement('span');
+ this._element.html(this._content);
+};
+
+var SimpleControl = function(){
+ WrappedElement.call(this);
+ this._handler = null;
+ this._title = null;
+};
+inherits(SimpleControl, WrappedElement);
+
+SimpleControl.prototype.setHandler = function(handler){
+ this._handler = handler;
+ if (this.hasElement()){
+ this.setHandlerInternal();
+ }
+};
+
+SimpleControl.prototype.getHandler = function(){
+ return this._handler;
+};
+
+SimpleControl.prototype.setHandlerInternal = function(){
+ //default internal setHandler behavior
+ setupButtonEventHandlers(this._element, this._handler);
+};
+
+SimpleControl.prototype.setTitle = function(title){
+ this._title = title;
+};
+
+var EditLink = function(){
+ SimpleControl.call(this)
+};
+inherits(EditLink, SimpleControl);
+
+EditLink.prototype.createDom = function(){
+ var element = $('<a></a>');
+ element.addClass('edit');
+ this.decorate(element);
+};
+
+EditLink.prototype.decorate = function(element){
+ this._element = element;
+ this._element.attr('title', gettext('click to edit this comment'));
+ this._element.html(gettext('edit'));
+ this.setHandlerInternal();
+};
+
+var CommentConvertLink = function(comment_id){
+ WrappedElement.call(this)
+ this._comment_id = comment_id;
+};
+inherits(CommentConvertLink, WrappedElement);
+
+CommentConvertLink.prototype.createDom = function(){
+ var element = this.makeElement('form');
+ element.addClass('convert-comment');
+ element.attr('method', 'POST');
+ element.attr('action', askbot['urls']['convertComment']);
+ var hidden_input = this.makeElement('input');
+ hidden_input.attr('type', 'hidden');
+ hidden_input.attr('value', this._comment_id);
+ hidden_input.attr('name', 'comment_id');
+ hidden_input.attr('id', 'id_comment_id');
+ element.append(hidden_input);
+
+ var submit = this.makeElement('input');
+ submit.attr('type', 'submit');
+ submit.attr('value', gettext('convert to answer'));
+ element.append(submit);
+ this.decorate(element);
+};
+
+
+CommentConvertLink.prototype.decorate = function(element){
+ this._element = element;
+};
+
+var DeleteIcon = function(title){
+ SimpleControl.call(this);
+ this._title = title;
+ this._content = null;
+};
+inherits(DeleteIcon, SimpleControl);
+
+DeleteIcon.prototype.decorate = function(element){
+ this._element = element;
+ this._element.attr('class', 'delete-icon');
+ this._element.attr('title', this._title);
+ if (this._handler !== null){
+ this.setHandlerInternal();
+ }
+};
+
+DeleteIcon.prototype.setHandlerInternal = function(){
+ setupButtonEventHandlers(this._element, this._handler);
+};
+
+DeleteIcon.prototype.createDom = function(){
+ this._element = this.makeElement('span');
+ this.decorate(this._element);
+ if (this._content !== null){
+ this.setContent(this._content);
+ }
+};
+
+DeleteIcon.prototype.setContent = function(content){
+ if (this._element === null){
+ this._content = content;
+ } else {
+ this._content = content;
+ this._element.html(content);
+ }
+}
+
+/**
+ * @contstructor
+ * Simple modal dialog with Ok/Cancel buttons by default
+ */
+var ModalDialog = function() {
+ WrappedElement.call(this);
+ this._accept_button_text = gettext('Ok');
+ this._reject_button_text = gettext('Cancel');
+ this._heading_text = 'Add heading by setHeadingText()';
+ this._initial_content = undefined;
+ this._accept_handler = function(){};
+ var me = this;
+ this._reject_handler = function() { me.hide(); };
+ this._content_element = undefined;
+};
+inherits(ModalDialog, WrappedElement);
+
+ModalDialog.prototype.show = function() {
+ this._element.modal('show');
+};
+
+ModalDialog.prototype.hide = function() {
+ this._element.modal('hide');
+};
+
+ModalDialog.prototype.setContent = function(content) {
+ this._initial_content = content;
+ if (this._content_element) {
+ this._content_element.html(content);
+ }
+};
+
+ModalDialog.prototype.prependContent = function(content) {
+ this._content_element.prepend(content);
+};
+
+ModalDialog.prototype.setHeadingText = function(text) {
+ this._heading_text = text;
+};
+
+ModalDialog.prototype.setAcceptButtonText = function(text) {
+ this._accept_button_text = text;
+};
+
+ModalDialog.prototype.setRejectButtonText = function(text) {
+ this._reject_button_text = text;
+};
+
+ModalDialog.prototype.setAcceptHandler = function(handler) {
+ this._accept_handler = handler;
+};
+
+ModalDialog.prototype.setRejectHandler = function(handler) {
+ this._reject_handler = handler;
+};
+
+ModalDialog.prototype.clearMessages = function() {
+ this._element.find('.alert').remove();
+};
+
+ModalDialog.prototype.setMessage = function(text, message_type) {
+ var box = new AlertBox();
+ box.setText(text);
+ if (message_type === 'error') {
+ box.setError(true);
+ }
+ this.prependContent(box.getElement());
+};
+
+ModalDialog.prototype.createDom = function() {
+ this._element = this.makeElement('div')
+ var element = this._element;
+
+ element.addClass('modal');
+
+ //1) create header
+ var header = this.makeElement('div')
+ header.addClass('modal-header');
+ element.append(header);
+
+ var close_link = this.makeElement('div');
+ close_link.addClass('close');
+ close_link.attr('data-dismiss', 'modal');
+ close_link.html('x');
+ header.append(close_link);
+
+ var title = this.makeElement('h3');
+ title.html(this._heading_text);
+ header.append(title);
+
+ //2) create content
+ var body = this.makeElement('div')
+ body.addClass('modal-body');
+ element.append(body);
+ this._content_element = body;
+ if (this._initial_content) {
+ this._content_element.append(this._initial_content);
+ }
+
+ //3) create footer with accept and reject buttons (ok/cancel).
+ var footer = this.makeElement('div');
+ footer.addClass('modal-footer');
+ element.append(footer);
+
+ var accept_btn = this.makeElement('button');
+ accept_btn.addClass('btn btn-primary');
+ accept_btn.html(this._accept_button_text);
+ footer.append(accept_btn);
+
+ if (this._reject_button_text) {
+ var reject_btn = this.makeElement('button');
+ reject_btn.addClass('btn cancel');
+ reject_btn.html(this._reject_button_text);
+ footer.append(reject_btn);
+ }
+
+ //4) attach event handlers to the buttons
+ setupButtonEventHandlers(accept_btn, this._accept_handler);
+ if (this._reject_button_text) {
+ setupButtonEventHandlers(reject_btn, this._reject_handler);
+ }
+ setupButtonEventHandlers(close_link, this._reject_handler);
+
+ this.hide();
+};
+
+/**
+ * @constructor
+ */
+var FileUploadDialog = function() {
+ ModalDialog.call(this);
+ self._post_upload_handler = undefined;
+};
+inherits(FileUploadDialog, ModalDialog);
+
+FileUploadDialog.prototype.setPostUploadHandler = function(handler) {
+ this._post_upload_handler = handler;
+};
+
+FileUploadDialog.prototype.runPostUploadHandler = function(url, descr) {
+ this._post_upload_handler(url, descr);
+};
+
+FileUploadDialog.prototype.setInputId = function(id) {
+ this._input_id = id;
+};
+
+FileUploadDialog.prototype.getInputId = function() {
+ return this._input_id;
+};
+
+FileUploadDialog.prototype.setUrlInputTooltip = function(text) {
+ this._url_input_tooltip = text;
+};
+
+FileUploadDialog.prototype.getUrl = function() {
+ var url_input = this._url_input;
+ if (url_input.isBlank() === false) {
+ return url_input.getVal();
+ }
+ return '';
+};
+
+//disable description for now
+//FileUploadDialog.prototype.getDescription = function() {
+// return this._description_input.getVal();
+//};
+
+FileUploadDialog.prototype.resetInputs = function() {
+ this._url_input.reset();
+ //this._description_input.reset();
+ this._upload_input.val('');
+};
+
+FileUploadDialog.prototype.show = function() {
+ //hack around the ajaxFileUpload plugin
+ FileUploadDialog.superClass_.show.call(this);
+ var upload_input = this._upload_input;
+ upload_input.unbind('change');
+ //todo: fix this - make event handler reinstall work
+ upload_input.change(this.getStartUploadHandler());
+};
+
+FileUploadDialog.prototype.getStartUploadHandler = function(){
+ /* startUploadHandler is passed in to re-install the event handler
+ * which is removed by the ajaxFileUpload jQuery extension
+ */
+ var spinner = this._spinner;
+ var uploadInputId = this.getInputId();
+ var urlInput = this._url_input;
+ var handler = function() {
+ var options = {
+ 'spinner': spinner,
+ 'uploadInputId': uploadInputId,
+ 'urlInput': urlInput.getElement(),
+ 'startUploadHandler': handler//pass in itself
+ };
+ return ajaxFileUpload(options);
+ };
+ return handler;
+};
+
+FileUploadDialog.prototype.createDom = function() {
+
+ var superClass = FileUploadDialog.superClass_;
+
+ var me = this;
+ superClass.setAcceptHandler.call(this, function(){
+ var url = $.trim(me.getUrl());
+ //var description = me.getDescription();
+ //@todo: have url cleaning code here
+ if (url.length > 0) {
+ me.runPostUploadHandler(url);//, description);
+ me.resetInputs();
+ }
+ me.hide();
+ });
+ superClass.setRejectHandler.call(this, function(){
+ me.resetInputs();
+ me.hide();
+ });
+ superClass.createDom.call(this);
+
+ var form = this.makeElement('form');
+ form.css('margin-bottom', 0);
+ this.prependContent(form);
+
+ // File upload button
+ var upload_input = this.makeElement('input');
+ upload_input.attr({
+ id: this._input_id,
+ type: 'file',
+ name: 'file-upload',
+ //size: 26???
+ });
+ form.append(upload_input);
+ this._upload_input = upload_input;
+ form.append($('<br/>'));
+
+ // The url input text box
+ var url_input = new TippedInput();
+ url_input.setInstruction(this._url_input_tooltip || gettext('Or paste file url here'));
+ var url_input_element = url_input.getElement();
+ url_input_element.css({
+ 'width': '200px',
+ 'display': 'none'
+ });
+ form.append(url_input_element);
+ //form.append($('<br/>'));
+ this._url_input = url_input;
+
+ var label = this.makeElement('label');
+ label.attr('for', this._input_id);
+
+ var types = askbot['settings']['allowedUploadFileTypes'];
+ types = types.join(', ');
+ label.html(gettext('Allowed file types are:') + ' ' + types + '.');
+ form.append(label);
+ form.append($('<br/>'));
+
+ /* //Description input box
+ var descr_input = new TippedInput();
+ descr_input.setInstruction(gettext('Describe the image here'));
+ this.makeElement('input');
+ form.append(descr_input.getElement());
+ form.append($('<br/>'));
+ this._description_input = descr_input;
+ */
+ var spinner = this.makeElement('img');
+ spinner.attr('src', mediaUrl('media/images/indicator.gif'));
+ spinner.css('display', 'none');
+ form.append(spinner);
+ this._spinner = spinner;
+
+ upload_input.change(this.getStartUploadHandler());
+};
+
+/**
+ * attaches a modal menu with a text editor
+ * to a link. The modal menu is from bootstrap.js
+ * todo: this should probably be a subclass of ModalDialog,
+ * triggered by a link click, then a whole bunch of methods
+ * would be simply inherited from the modal dialog:
+ * clearMessages, etc.
+ */
+var TextPropertyEditor = function(){
+ WrappedElement.call(this);
+ this._editor = null;
+};
+inherits(TextPropertyEditor, WrappedElement);
+
+TextPropertyEditor.prototype.getWidgetData = function(){
+ var data = this._element.data();
+ return {
+ object_id: data['objectId'],
+ model_name: data['modelName'],
+ property_name: data['propertyName'],
+ url: data['url'],
+ help_text: data['helpText'],
+ editor_heading: data['editorHeading']
+ };
+};
+
+TextPropertyEditor.prototype.makeEditor = function(){
+ if (this._editor) {
+ return this._editor;
+ }
+ var editor = new ModalDialog();
+ this._editor = editor;
+ editor.setHeadingText(this.getWidgetData()['editor_heading']);
+
+ //create main content for the editor
+ var textarea = this.makeElement('textarea');
+ textarea.addClass('tipped-input blank');
+ textarea.val(this.getWidgetData()['help_text']);
+
+ var tipped_input = new TippedInput();
+ tipped_input.decorate(textarea);
+ this._text_input = tipped_input;
+
+ editor.setContent(textarea);
+ //body.append(textarea);
+
+ editor.setAcceptButtonText(gettext('Save'));
+ editor.setRejectButtonText(gettext('Cancel'));
+
+ var me = this;
+ editor.setAcceptHandler(function(){
+ me.saveData();
+ });
+
+ $(document).append(editor.getElement());
+ return editor;
+};
+
+TextPropertyEditor.prototype.openEditor = function(){
+ this._editor.show();
+};
+
+TextPropertyEditor.prototype.clearMessages = function(){
+ this._editor.clearMessages()
+};
+
+TextPropertyEditor.prototype.showAlert = function(text){
+ this._editor.setMessage(text, 'alert');
+};
+
+TextPropertyEditor.prototype.showError = function(text){
+ this._editor.setMessage(text, 'error');
+};
+
+TextPropertyEditor.prototype.setText = function(text){
+ this._text_input.setVal(text);
+};
+
+TextPropertyEditor.prototype.getText = function(){
+ return this._text_input.getVal();
+};
+
+TextPropertyEditor.prototype.hideDialog = function(){
+ this._editor.hide();
+};
+
+TextPropertyEditor.prototype.startOpeningEditor = function(){
+ var me = this;
+ $.ajax({
+ type: 'GET',
+ dataType: 'json',
+ cache: false,
+ url: me.getWidgetData()['url'],
+ data: me.getWidgetData(),
+ success: function(data){
+ if (data['success']) {
+ me.makeEditor();
+ me.setText($.trim(data['text']));
+ me.openEditor();
+ } else {
+ showMessage(me.getElement(), data['message']);
+ }
+ }
+ });
+};
+
+TextPropertyEditor.prototype.saveData = function(){
+ var data = this.getWidgetData();
+ data['text'] = this.getText();
+ var me = this;
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ cache: false,
+ url: me.getWidgetData()['url'],
+ data: data,
+ success: function(data) {
+ if (data['success']) {
+ me.showAlert(gettext('saved'));
+ setTimeout(function(){
+ me.clearMessages();
+ me.hideDialog();
+ }, 1000);
+ } else {
+ me.showError(data['message']);
+ }
+ }
+ });
+};
+
+TextPropertyEditor.prototype.decorate = function(element){
+ this._element = element;
+ var me = this;
+ setupButtonEventHandlers(element, function(){ me.startOpeningEditor() });
+};
+
+/**
+ * A button on which user can click
+ * and become added to some group (followers, group members, etc.)
+ * or toggle some state on/off
+ * The button has four states on-prompt, off-prompt, on-state and off-state
+ * on-prompt is activated on mouseover, when user is not part of group
+ * off-prompt - on mouseover, when user is part of group
+ * on-state - when user is part of group and mouse is not over the button
+ * off-state - same as above, but when user is not part of the group
+ */
+var TwoStateToggle = function(){
+ SimpleControl.call(this);
+ this._state = null;
+ this._state_messages = {};
+ this._states = [
+ 'on-state',
+ 'off-state',
+ 'on-prompt',
+ 'off-prompt'
+ ];
+ this._handler = this.getDefaultHandler();
+ this._post_data = {};
+ this.toggleUrl = '';//public property
+};
+inherits(TwoStateToggle, SimpleControl);
+
+TwoStateToggle.prototype.setPostData = function(data){
+ this._post_data = data;
+};
+
+TwoStateToggle.prototype.getPostData = function(){
+ return this._post_data;
+};
+
+TwoStateToggle.prototype.resetStyles = function(){
+ var element = this._element;
+ var states = this._states;
+ $.each(states, function(idx, state){
+ element.removeClass(state);
+ });
+ this._element.html('');
+};
+
+TwoStateToggle.prototype.isOn = function(){
+ return this._element.hasClass('on');
+};
+
+TwoStateToggle.prototype.getDefaultHandler = function(){
+ var me = this;
+ return function(){
+ var data = me.getPostData();
+ data['disable'] = me.isOn();
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ cache: false,
+ url: me.toggleUrl,
+ data: data,
+ success: function(data) {
+ if (data['success']) {
+ if ( data['is_enabled'] ) {
+ me.setState('on-state');
+ } else {
+ me.setState('off-state');
+ }
+ } else {
+ showMessage(me.getElement(), data['message']);
+ }
+ }
+ });
+ };
+};
+
+TwoStateToggle.prototype.isCheckBox = function(){
+ var element = this._element;
+ return element.attr('type') === 'checkbox';
+};
+
+TwoStateToggle.prototype.setState = function(state){
+ var element = this._element;
+ this._state = state;
+ if (element) {
+ this.resetStyles();
+ element.addClass(state);
+ if (state === 'on-state') {
+ element.addClass('on');
+ } else if (state === 'off-state') {
+ element.removeClass('on');
+ }
+ if ( this.isCheckBox() ) {
+ if (state === 'on-state') {
+ element.attr('checked', true);
+ } else if (state === 'off-state') {
+ element.attr('checked', false);
+ }
+ } else {
+ this._element.html(this._state_messages[state]);
+ }
+ }
+};
+
+TwoStateToggle.prototype.decorate = function(element){
+ this._element = element;
+ //read messages for all states
+ var messages = {};
+ messages['on-state'] =
+ element.attr('data-on-state-text') || gettext('enabled');
+ messages['off-state'] =
+ element.attr('data-off-state-text') || gettext('disabled');
+ messages['on-prompt'] =
+ element.attr('data-on-prompt-text') || messages['on-state'];
+ messages['off-prompt'] =
+ element.attr('data-off-prompt-text') || messages['off-state'];
+ this._state_messages = messages;
+
+ this.toggleUrl = element.attr('data-toggle-url');
+
+ //detect state and save it
+ if (this.isCheckBox()) {
+ this._state = element.attr('checked') ? 'state-on' : 'state-off';
+ } else {
+ var text = $.trim(element.html());
+ for (var i = 0; i < this._states.length; i++){
+ var state = this._states[i];
+ if (text === messages[state]){
+ this._state = state;
+ break;
+ }
+ }
+ }
+
+ //set mouseover handler
+ var me = this;
+ element.mouseover(function(){
+ var is_on = me.isOn();
+ if (is_on){
+ me.setState('off-prompt');
+ } else {
+ me.setState('on-prompt');
+ }
+ //element.css('background-color', 'red');
+ return false;
+ });
+ element.mouseout(function(){
+ var is_on = me.isOn();
+ if (is_on){
+ me.setState('on-state');
+ } else {
+ me.setState('off-state');
+ }
+ //element.css('background-color', 'white');
+ return false;
+ });
+
+ setupButtonEventHandlers(element, this.getHandler());
+};
+
+/**
+ * @contstructor
+ * a simple dropdown select element
+ * which saves data to the server on change
+ */
+var DropdownSelect = function() {
+ WrappedElement.call(this);
+};
+inherits(DropdownSelect, WrappedElement);
+
+DropdownSelect.prototype.setPostData = function(data) {
+ this._postData = data;
+};
+
+/**
+ * posts value of selection to the url given
+ * with data-url and parameter called "value"
+ */
+DropdownSelect.prototype.saveChoice = function() {
+ var element = this._element;
+ var url = this._url;
+ var data = this._postData;
+ data['value'] = element.val();
+ $.ajax({
+ type: 'POST',
+ dataType: 'json',
+ data: data,
+ cache: false,
+ url: url,
+ success: function(data) {
+ if (!data['success']) {
+ showMessage(element, data['message']);
+ }
+ }
+ });
+};
+
+DropdownSelect.prototype.decorate = function(element) {
+ this._element = element;
+ this._url = $(element).data('url');
+ var me = this;
+ this._element.change(function() {
+ me.saveChoice();
+ });
+};
+
+var BoxItemContent = function() {
+ SimpleContent.call(this);
+};
+inherits(BoxItemContent, SimpleContent);
+
+/**
+ * @override to allow for more complex content
+ */
+BoxItemContent.prototype.setName = function(name) {
+ BoxItemContent.superClass_.setContent.call(this, name);
+};
+BoxItemContent.prototype.getName = function() {
+ return BoxItemContent.superClass_.getContent.call(this);
+};
+
+/**
+ * @constructor
+ * an item used for the select box described below
+ */
+var SelectBoxItem = function() {
+ Widget.call(this);
+ this._id = null;
+ this._name = null;
+ this._description = null;
+ this._content_class = BoxItemContent;//default expects a single text node
+ //content element - instance of this._content_class
+ this._content = undefined;
+ this._selector = undefined;//the selector object
+};
+inherits(SelectBoxItem, Widget);
+
+SelectBoxItem.prototype.setId = function(id) {
+ this._id = id;
+ if (this._element) {
+ this._element.data('itemId', id);
+ }
+};
+
+SelectBoxItem.prototype.getId = function() {
+ return this._id;
+};
+
+SelectBoxItem.prototype.setName = function(name) {
+ this._name = name;
+ if (this._content) {
+ this._content.setName(name);
+ }
+};
+
+SelectBoxItem.prototype.setDescription = function(description) {
+ this._description = description;
+ if (this._element) {
+ this._element.data('originalTitle');
+ }
+};
+
+SelectBoxItem.prototype.getData = function () {
+ //todo: stuck using old key names, change after merge
+ //with the user-groups branch
+ return {
+ id: this._id,
+ title: this._name,
+ details: this._description
+ };
+};
+
+SelectBoxItem.prototype.setSelector = function(sel) {
+ this._selector = sel;
+};
+
+SelectBoxItem.prototype.getSelector = function(sel) {
+ return this._selector;
+};
+
+SelectBoxItem.prototype.getContent = function() {
+ return this._content;
+};
+
+SelectBoxItem.prototype.isSelected = function() {
+ return this._element.hasClass('selected');
+};
+
+SelectBoxItem.prototype.setSelected = function(is_selected) {
+ if (is_selected) {
+ this._element.addClass('selected');
+ } else {
+ this._element.removeClass('selected');
+ }
+}
+
+SelectBoxItem.prototype.detach = function() {
+ this._element.detach();
+};
+
+SelectBoxItem.prototype.createDom = function() {
+ var elem = this.makeElement('li');
+ this._element = elem;
+ elem.data('itemId', this._id);
+ elem.data('itemOriginalTitle', this._description);
+ var content = new this._content_class();
+ content.setName(this._name);
+ elem.append(content.getElement());
+ this._content = content;
+}
+/**
+ * this method sets css class to the item's DOM element
+ */
+SelectBoxItem.prototype.addCssClass = function(css_class) {
+ this._element.addClass(css_class);
+};
+
+SelectBoxItem.prototype.decorate = function(element) {
+ this._element = element;
+ //set id and description
+ this._id = element.data('itemId');
+ this._description = element.data('originalTitle');
+
+ //work on setting name
+ var content_source = element.contents().detach();
+ var content = new this._content_class();
+ //assume that we want first node only
+ content.setContent(content_source[0]);
+ this._content = content;
+ this._name = content.getName();//allows to abstract from structure
+
+ this._element.append(content.getElement());
+};
+
+/**
+ * A list of items from where one can be selected
+ */
+var SelectBox = function(){
+ Widget.call(this);
+ this._items = [];
+ this._select_handler = function(){};//empty default
+ this._is_editable = false;
+ this._item_class = SelectBoxItem;
+};
+inherits(SelectBox, Widget);
+
+SelectBox.prototype.setEditable = function(is_editable) {
+ this._is_editable = is_editable;
+};
+
+SelectBox.prototype.isEditable = function() {
+ return this._is_editable;
+};
+
+SelectBox.prototype.detachAllItems = function() {
+ var items = this._items;
+ $.each(items, function(idx, item){
+ item.detach();
+ });
+ this._items = [];
+};
+
+SelectBox.prototype.getItem = function(id){
+ var items = this._items;
+ for (var i = 0; i < items.length; i++) {
+ if (items[i].getId() === id) {
+ return items[i];
+ }
+ }
+ return undefined;
+};
+
+SelectBox.prototype.getItemByIndex = function(idx) {
+ return this._items[idx];
+};
+
+//why do we have these two almost identical methods?
+SelectBox.prototype.removeItem = function(id){
+ var item = this.getItem(id);
+ item.getElement().fadeOut();
+ item.dispose();
+ var idx = $.inArray(item, this._items);
+ if (idx !== -1) {
+ this._items.splice(idx, 1);
+ }
+};
+SelectBox.prototype.deleteItem = function(id) {
+ var item = this.getItem(id);
+ if (item === undefined) {
+ return;
+ }
+ item.dispose();
+ var idx = $.inArray(item, this._items);
+ if (idx !== -1) {
+ this._items.splice(idx, 1);
+ }
+};
+
+SelectBox.prototype.createItem = function() {
+ return new this._item_class();
+};
+
+SelectBox.prototype.getItemIndex = function(item) {
+ var idx = $.inArray(item, this._items);
+ if (idx === -1) {
+ throw "index error";
+ }
+ return idx;
+};
+
+SelectBox.prototype.addItemObject = function(item) {
+ this._items.push(item);
+ this._element.append(item.getElement());
+ this.selectItem(item);
+ item.setSelector(this);
+ //set event handler
+ var me = this;
+ setupButtonEventHandlers(
+ item.getElement(),
+ me.getSelectHandler(item)
+ );
+};
+
+/** @todo: rename to setItem?? have a problem when id's are all say 0 */
+SelectBox.prototype.addItem = function(id, name, description){
+
+ if (this.hasElement() === false) {
+ return;
+ }
+ //delete old item
+ this.deleteItem(id);
+ //create new item
+ var item = this.createItem();
+ item.setId(id);
+ item.setName(name);
+ item.setDescription(description);
+ //add item to the SelectBox
+ this.addItemObject(item);
+
+ return item;
+};
+
+SelectBox.prototype.getSelectedItem = function() {
+ for (var i = 0; i < this._items.length; i++) {
+ var item = this._items[i];
+ if (item.isSelected()) {
+ return item;
+ }
+ }
+ return undefined;
+};
+
+SelectBox.prototype.getSelectedItemData = function() {
+ var item = this.getSelectedItem();
+ if (item) {
+ return item.getData() || undefined;
+ } else {
+ return undefined;
+ }
+};
+
+SelectBox.prototype.selectItem = function(item){
+ this.clearSelection();
+ item.setSelected(true);
+};
+
+SelectBox.prototype.clearSelection = function(){
+ $.each(this._items, function(idx, item) {
+ item.setSelected(false);
+ });
+};
+
+SelectBox.prototype.setSelectHandler = function(handler) {
+ this._select_handler = handler;
+};
+
+SelectBox.prototype.getSelectHandler = function(item) {
+ var me = this;
+ var handler = this._select_handler;
+ return function(){
+ me.selectItem(item);
+ handler(item.getData());
+ };
+};
+
+SelectBox.prototype.decorate = function(element){
+ this._element = element;
+ var me = this;
+ var box_items = this._items;
+ var item_elements = this._element.find('.select-box-item');
+ item_elements.each(function(idx, item_element){
+ var item = me.createItem();
+ item.decorate($(item_element));
+ box_items.push(item);
+ setupButtonEventHandlers(
+ item.getElement(),
+ me.getSelectHandler(item)
+ );
+ });
+};
+
+/**
+ * This is a dropdown list elment
+ */
+
+var GroupDropdown = function(groups){
+ WrappedElement.call(this);
+ this._group_list = groups;
+ this._input_box = new TippedInput();
+ this._input_box.setInstruction('group name');
+ this._input_box.createDom();
+ this._input_box_element = this._input_box.getElement();
+ this._input_box_element.attr('class', 'group-name');
+ this._input_box_element.hide();
+ this._add_link = this.makeElement('a');
+ this._add_link.attr('href', '#');
+ this._add_link.attr('class', 'group-name');
+ this._add_link.text('add new group');
+};
+inherits(GroupDropdown, WrappedElement);
+
+GroupDropdown.prototype.createDom = function(){
+ this._element = this.makeElement('ul');
+ this._element.attr('class', 'dropdown-menu');
+ this._element.attr('id', 'groups-dropdown');
+ this._element.attr('role', 'menu');
+ this._element.attr('aria-labelledby', 'navGroups');
+
+ for (i=0; i<this._group_list.length; i++){
+ li_element = this.makeElement('li');
+ a_element = this.makeElement('a');
+ a_element.text(this._group_list[i].name);
+ a_element.attr('href', this._group_list[i].link);
+ a_element.attr('class', 'group-name');
+ li_element.append(a_element);
+ this._element.append(li_element);
+ }
+};
+
+GroupDropdown.prototype.decorate = function(element){
+ this._element = element;
+ this._element.attr('class', 'dropdown-menu');
+ this._element.attr('id', 'groups-dropdown');
+ this._element.attr('role', 'menu');
+ this._element.attr('aria-labelledby', 'navGroups');
+
+ for (i=0; i<this._group_list.length; i++){
+ li_element = this.makeElement('li');
+ a_element = this.makeElement('a');
+ a_element.text(this._group_list[i].name);
+ a_element.attr('href', this._group_list[i].link);
+ a_element.attr('class', 'group-name');
+ li_element.append(a_element);
+ this._element.append(li_element);
+ }
+};
+
+GroupDropdown.prototype.insertGroup = function(group_name, url){
+ var new_group_li = this.makeElement('li');
+ new_group_a = this.makeElement('a');
+ new_group_a.attr('href', url);
+ new_group_a.attr('class', 'group-name');
+ new_group_a.text(group_name);
+ new_group_li.append(new_group_a);
+ links_array = this._element.find('a')
+ for (i=1; i < links_array.length; i++){
+ var listedName = links_array[i].text;
+ var cleanedListedName = listedName.toLowerCase();
+ var cleanedNewName = group_name.toLowerCase()
+ if (listedName < newName) {
+ if (i == links_array.length - 1){
+ new_group_li.insertAfter(this._element.find('li')[i-1])
+ break;
+ } else {
+ continue;
+ }
+ } else if (cleanedNewName === cleanedNewName) {
+ var message = interpolate(gettext(
+ 'Group %(name)s already exists. Group names are case-insensitive.'
+ ), {'name': listedName}, true
+ );
+ notify.show(message);
+ return;
+ } else {
+ new_group_li.insertAfter(this._element.find('li')[i-1])
+ break;
+ }
+ }
+};
+
+GroupDropdown.prototype._add_group_handler = function(group_name){
+ var group_name = this._input_box_element.val();
+ self = this;
+ if (!group_name){
+ return;
+ }
+
+ $.ajax({
+ type: 'POST',
+ url: askbot['urls']['add_group'],
+ data: {group: group_name},
+ success: function(data){
+ if (data.success){
+ self.insertGroup(data.group_name, data.url);
+ self._input_box_element.hide();
+ self._add_link.show();
+ return true;
+ } else{
+ return false;
+ }
+ },
+ error: function(){console.log('error');}
+ });
+};
+
+GroupDropdown.prototype.enableAddGroups = function(){
+ var self = this;
+ this._add_link.click(function(){
+ self._add_link.hide();
+ self._input_box_element.show();
+ self._input_box_element.focus();
+ });
+ this._input_box_element.keydown(function(event){
+ if (event.which == 13 || event.keyCode==13){
+ self._add_group_handler();
+ self._input_box_element.val('');
+ }
+ });
+
+ var divider = this.makeElement('li');
+ divider.attr('class', 'divider');
+ this._element.append(divider);
+
+ var container = this.makeElement('li');
+ container.append(this._add_link);
+ container.append(this._input_box_element);
+
+ this._element.append(container);
+};
+
+var Tag = function(){
+ SimpleControl.call(this);
+ this._deletable = false;
+ this._delete_handler = null;
+ this._delete_icon_title = null;
+ this._tag_title = null;
+ this._name = null;
+ this._url_params = null;
+ this._inner_html_tag = 'a';
+ this._html_tag = 'li';
+}
+inherits(Tag, SimpleControl);
+
+Tag.prototype.setName = function(name){
+ this._name = name;
+};
+
+Tag.prototype.getName = function(){
+ return this._name;
+};
+
+Tag.prototype.setHtmlTag = function(html_tag){
+ this._html_tag = html_tag;
+};
+
+Tag.prototype.setDeletable = function(is_deletable){
+ this._deletable = is_deletable;
+};
+
+Tag.prototype.setLinkable = function(is_linkable){
+ if (is_linkable === true){
+ this._inner_html_tag = 'a';
+ } else {
+ this._inner_html_tag = 'span';
+ }
+};
+
+Tag.prototype.isLinkable = function(){
+ return (this._inner_html_tag === 'a');
+};
+
+Tag.prototype.isDeletable = function(){
+ return this._deletable;
+};
+
+Tag.prototype.isWildcard = function(){
+ return (this.getName().substr(-1) === '*');
+};
+
+Tag.prototype.setUrlParams = function(url_params){
+ this._url_params = url_params;
+};
+
+Tag.prototype.setHandlerInternal = function(){
+ setupButtonEventHandlers(this._element.find('.tag'), this._handler);
+};
+
+/* delete handler will be specific to the task */
+Tag.prototype.setDeleteHandler = function(delete_handler){
+ this._delete_handler = delete_handler;
+ if (this.hasElement() && this.isDeletable()){
+ this._delete_icon.setHandler(delete_handler);
+ }
+};
+
+Tag.prototype.getDeleteHandler = function(){
+ return this._delete_handler;
+};
+
+Tag.prototype.setDeleteIconTitle = function(title){
+ this._delete_icon_title = title;
+};
+
+Tag.prototype.decorate = function(element){
+ this._element = element;
+ var del = element.find('.delete-icon');
+ if (del.length === 1){
+ this.setDeletable(true);
+ this._delete_icon = new DeleteIcon();
+ if (this._delete_icon_title != null){
+ this._delete_icon.setTitle(this._delete_icon_title);
+ }
+ //do not set the delete handler here
+ this._delete_icon.decorate(del);
+ }
+ this._inner_element = this._element.find('.tag');
+ this._name = this.decodeTagName(
+ $.trim(this._inner_element.attr('data-tag-name'))
+ );
+ if (this._title !== null){
+ this._inner_element.attr('title', this._title);
+ }
+ if (this._handler !== null){
+ this.setHandlerInternal();
+ }
+};
+
+Tag.prototype.getDisplayTagName = function(){
+ //replaces the trailing * symbol with the unicode asterisk
+ return this._name.replace(/\*$/, '&#10045;');
+};
+
+Tag.prototype.decodeTagName = function(encoded_name){
+ return encoded_name.replace('\u273d', '*');
+};
+
+Tag.prototype.createDom = function(){
+ this._element = this.makeElement(this._html_tag);
+ //render the outer element
+ if (this._deletable){
+ this._element.addClass('deletable-tag');
+ }
+ this._element.addClass('tag-left');
+
+ //render the inner element
+ this._inner_element = this.makeElement(this._inner_html_tag);
+ if (this.isLinkable()){
+ var url = askbot['urls']['questions'];
+ var flag = false
+ var author = ''
+ if (this._url_params){
+ url += QSutils.add_search_tag(this._url_params, this.getName());
+ }
+ this._inner_element.attr('href', url);
+ }
+ this._inner_element.addClass('tag tag-right');
+ this._inner_element.attr('rel', 'tag');
+ if (this._title === null){
+ this.setTitle(
+ interpolate(gettext("see questions tagged '%s'"), [this.getName()])
+ );
+ }
+ this._inner_element.attr('title', this._title);
+ this._inner_element.html(this.getDisplayTagName());
+ this._inner_element.data('tagName', this.getName());
+
+ this._element.append(this._inner_element);
+
+ if (!this.isLinkable() && this._handler !== null){
+ this.setHandlerInternal();
+ }
+
+ if (this._deletable){
+ this._delete_icon = new DeleteIcon();
+ this._delete_icon.setHandler(this.getDeleteHandler());
+ if (this._delete_icon_title !== null){
+ this._delete_icon.setTitle(this._delete_icon_title);
+ }
+ var del_icon_elem = this._delete_icon.getElement();
+ del_icon_elem.text('x'); // HACK by Tomasz
+ this._element.append(del_icon_elem);
+ }
+};
+
+//Search Engine Keyword Highlight with Javascript
+//http://scott.yang.id.au/code/se-hilite/
+Hilite={elementid:"content",exact:true,max_nodes:1000,onload:true,style_name:"hilite",style_name_suffix:true,debug_referrer:""};Hilite.search_engines=[["local","q"],["cnprog\\.","q"],["google\\.","q"],["search\\.yahoo\\.","p"],["search\\.msn\\.","q"],["search\\.live\\.","query"],["search\\.aol\\.","userQuery"],["ask\\.com","q"],["altavista\\.","q"],["feedster\\.","q"],["search\\.lycos\\.","q"],["alltheweb\\.","q"],["technorati\\.com/search/([^\\?/]+)",1],["dogpile\\.com/info\\.dogpl/search/web/([^\\?/]+)",1,true]];Hilite.decodeReferrer=function(d){var g=null;var e=new RegExp("");for(var c=0;c<Hilite.search_engines.length;c++){var f=Hilite.search_engines[c];e.compile("^http://(www\\.)?"+f[0],"i");var b=d.match(e);if(b){var a;if(isNaN(f[1])){a=Hilite.decodeReferrerQS(d,f[1])}else{a=b[f[1]+1]}if(a){a=decodeURIComponent(a);if(f.length>2&&f[2]){a=decodeURIComponent(a)}a=a.replace(/\'|"/g,"");a=a.split(/[\s,\+\.]+/);return a}break}}return null};Hilite.decodeReferrerQS=function(f,d){var b=f.indexOf("?");var c;if(b>=0){var a=new String(f.substring(b+1));b=0;c=0;while((b>=0)&&((c=a.indexOf("=",b))>=0)){var e,g;e=a.substring(b,c);b=a.indexOf("&",c)+1;if(e==d){if(b<=0){return a.substring(c+1)}else{return a.substring(c+1,b-1)}}else{if(b<=0){return null}}}}return null};Hilite.hiliteElement=function(f,e){if(!e||f.childNodes.length==0){return}var c=new Array();for(var b=0;b<e.length;b++){e[b]=e[b].toLowerCase();if(Hilite.exact){c.push("\\b"+e[b]+"\\b")}else{c.push(e[b])}}c=new RegExp(c.join("|"),"i");var a={};for(var b=0;b<e.length;b++){if(Hilite.style_name_suffix){a[e[b]]=Hilite.style_name+(b+1)}else{a[e[b]]=Hilite.style_name}}var d=function(m){var j=c.exec(m.data);if(j){var n=j[0];var i="";var h=m.splitText(j.index);var g=h.splitText(n.length);var l=m.ownerDocument.createElement("SPAN");m.parentNode.replaceChild(l,h);l.className=a[n.toLowerCase()];l.appendChild(h);return l}else{return m}};Hilite.walkElements(f.childNodes[0],1,d)};Hilite.hilite=function(){var a=Hilite.debug_referrer?Hilite.debug_referrer:document.referrer;var b=null;a=Hilite.decodeReferrer(a);if(a&&((Hilite.elementid&&(b=document.getElementById(Hilite.elementid)))||(b=document.body))){Hilite.hiliteElement(b,a)}};Hilite.walkElements=function(d,f,e){var a=/^(script|style|textarea)/i;var c=0;while(d&&f>0){c++;if(c>=Hilite.max_nodes){var b=function(){Hilite.walkElements(d,f,e)};setTimeout(b,50);return}if(d.nodeType==1){if(!a.test(d.tagName)&&d.childNodes.length>0){d=d.childNodes[0];f++;continue}}else{if(d.nodeType==3){d=e(d)}}if(d.nextSibling){d=d.nextSibling}else{while(f>0){d=d.parentNode;f--;if(d.nextSibling){d=d.nextSibling;break}}}}};if(Hilite.onload){if(window.attachEvent){window.attachEvent("onload",Hilite.hilite)}else{if(window.addEventListener){window.addEventListener("load",Hilite.hilite,false)}else{var __onload=window.onload;window.onload=function(){Hilite.hilite();__onload()}}}};
+
+if(!this.JSON){this.JSON={}}(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof JSON.stringify!=="function"){JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}}());
+//jquery fieldselection
+(function(){var a={getSelection:function(){var b=this.jquery?this[0]:this;return(("selectionStart" in b&&function(){var c=b.selectionEnd-b.selectionStart;return{start:b.selectionStart,end:b.selectionEnd,length:c,text:b.value.substr(b.selectionStart,c)}})||(document.selection&&function(){b.focus();var d=document.selection.createRange();if(d==null){return{start:0,end:b.value.length,length:0}}var c=b.createTextRange();var e=c.duplicate();c.moveToBookmark(d.getBookmark());e.setEndPoint("EndToStart",c);return{start:e.text.length,end:e.text.length+d.text.length,length:d.text.length,text:d.text}})||function(){return{start:0,end:b.value.length,length:0}})()},replaceSelection:function(){var b=this.jquery?this[0]:this;var c=arguments[0]||"";return(("selectionStart" in b&&function(){b.value=b.value.substr(0,b.selectionStart)+c+b.value.substr(b.selectionEnd,b.value.length);return this})||(document.selection&&function(){b.focus();document.selection.createRange().text=c;return this})||function(){b.value+=c;return this})()}};jQuery.each(a,function(b){jQuery.fn[b]=this})})();
+/**
+ * AutoCompleter Object, refactored closure style from
+ * jQuery autocomplete plugin
+ * @param {Object=} options Settings
+ * @constructor
+ */
+var AutoCompleter = function(options) {
+
+ /**
+ * Default options for autocomplete plugin
+ */
+ var defaults = {
+ promptText: '',
+ autocompleteMultiple: true,
+ multipleSeparator: ' ',//a single character
+ inputClass: 'acInput',
+ loadingClass: 'acLoading',
+ resultsClass: 'acResults',
+ selectClass: 'acSelect',
+ queryParamName: 'q',
+ limitParamName: 'limit',
+ extraParams: {},
+ lineSeparator: '\n',
+ cellSeparator: '|',
+ minChars: 2,
+ maxItemsToShow: 10,
+ delay: 400,
+ useCache: true,
+ maxCacheLength: 10,
+ matchSubset: true,
+ matchCase: false,
+ matchInside: true,
+ mustMatch: false,
+ preloadData: false,
+ selectFirst: false,
+ stopCharRegex: /\s+/,
+ selectOnly: false,
+ formatItem: null, // TBD
+ onItemSelect: false,
+ autoFill: false,
+ filterResults: true,
+ sortResults: true,
+ sortFunction: false,
+ onNoMatch: false
+ };
+
+ /**
+ * Options dictionary
+ * @type Object
+ * @private
+ */
+ this.options = $.extend({}, defaults, options);
+
+ /**
+ * Cached data
+ * @type Object
+ * @private
+ */
+ this.cacheData_ = {};
+
+ /**
+ * Number of cached data items
+ * @type number
+ * @private
+ */
+ this.cacheLength_ = 0;
+
+ /**
+ * Class name to mark selected item
+ * @type string
+ * @private
+ */
+ this.selectClass_ = 'jquery-autocomplete-selected-item';
+
+ /**
+ * Handler to activation timeout
+ * @type ?number
+ * @private
+ */
+ this.keyTimeout_ = null;
+
+ /**
+ * Last key pressed in the input field (store for behavior)
+ * @type ?number
+ * @private
+ */
+ this.lastKeyPressed_ = null;
+
+ /**
+ * Last value processed by the autocompleter
+ * @type ?string
+ * @private
+ */
+ this.lastProcessedValue_ = null;
+
+ /**
+ * Last value selected by the user
+ * @type ?string
+ * @private
+ */
+ this.lastSelectedValue_ = null;
+
+ /**
+ * Is this autocompleter active?
+ * @type boolean
+ * @private
+ */
+ this.active_ = false;
+
+ /**
+ * Is it OK to finish on blur?
+ * @type boolean
+ * @private
+ */
+ this.finishOnBlur_ = true;
+
+ this.options.minChars = parseInt(this.options.minChars, 10);
+ if (isNaN(this.options.minChars) || this.options.minChars < 1) {
+ this.options.minChars = 2;
+ }
+
+ this.options.maxItemsToShow = parseInt(this.options.maxItemsToShow, 10);
+ if (isNaN(this.options.maxItemsToShow) || this.options.maxItemsToShow < 1) {
+ this.options.maxItemsToShow = 10;
+ }
+
+ this.options.maxCacheLength = parseInt(this.options.maxCacheLength, 10);
+ if (isNaN(this.options.maxCacheLength) || this.options.maxCacheLength < 1) {
+ this.options.maxCacheLength = 10;
+ }
+
+ if (this.options['preloadData'] === true){
+ this.fetchRemoteData('', function(){});
+ }
+};
+inherits(AutoCompleter, WrappedElement);
+
+AutoCompleter.prototype.decorate = function(element){
+
+ /**
+ * Init DOM elements repository
+ */
+ this._element = element;
+
+ /**
+ * Switch off the native autocomplete
+ */
+ this._element.attr('autocomplete', 'off');
+
+ /**
+ * Set prompt text
+ */
+ this.setPrompt();
+
+ /**
+ * Create DOM element to hold results
+ */
+ this._results = $('<div></div>').hide();
+ if (this.options.resultsClass) {
+ this._results.addClass(this.options.resultsClass);
+ }
+ this._results.css({
+ position: 'absolute'
+ });
+ $('body').append(this._results);
+
+ this.setEventHandlers();
+};
+
+AutoCompleter.prototype.setPrompt = function() {
+ this._element.val(this.options['promptText']);
+ this._element.addClass('prompt');
+};
+
+AutoCompleter.prototype.removePrompt = function() {
+ if (this._element.hasClass('prompt')) {
+ this._element.removeClass('prompt');
+ var val = this._element.val();
+ if (val === this.options['promptText']) {
+ this._element.val('');
+ }
+ }
+};
+
+AutoCompleter.prototype.setEventHandlers = function(){
+ /**
+ * Shortcut to self
+ */
+ var self = this;
+
+ /**
+ * Attach keyboard monitoring to $elem
+ */
+ self._element.keydown(function(e) {
+
+ self.removePrompt();
+
+ self.lastKeyPressed_ = e.keyCode;
+ switch(self.lastKeyPressed_) {
+
+ case 38: // up
+ e.preventDefault();
+ if (self.active_) {
+ self.focusPrev();
+ } else {
+ self.activate();
+ }
+ return false;
+ break;
+
+ case 40: // down
+ e.preventDefault();
+ if (self.active_) {
+ self.focusNext();
+ } else {
+ self.activate();
+ }
+ return false;
+ break;
+
+ case 9: // tab
+ case 13: // return
+ if (self.active_) {
+ e.preventDefault();
+ self.selectCurrent();
+ return false;
+ }
+ break;
+
+ case 27: // escape
+ if ($.trim(self._element.val()) === '') {
+ self._element.blur();
+ return false;
+ }
+ if (self.active_) {
+ e.preventDefault();
+ self.finish();
+ return false;
+ }
+ break;
+
+ default:
+ self.activate();
+
+ }
+ });
+ self._element.focus(function() {
+ self.removePrompt();
+ });
+ self._element.blur(function() {
+ if ($.trim(self._element.val()) === '') {
+ self.setPrompt();
+ self._results.hide();
+ return true;
+ }
+ if (self.finishOnBlur_) {
+ setTimeout(function() { self.finish(); }, 200);
+ }
+ });
+};
+
+AutoCompleter.prototype.position = function() {
+ var offset = this._element.offset();
+ this._results.css({
+ top: offset.top + this._element.outerHeight(),
+ left: offset.left
+ });
+};
+
+AutoCompleter.prototype.cacheRead = function(filter) {
+ var filterLength, searchLength, search, maxPos, pos;
+ if (this.options.useCache) {
+ filter = String(filter);
+ filterLength = filter.length;
+ if (this.options.matchSubset) {
+ searchLength = 1;
+ } else {
+ searchLength = filterLength;
+ }
+ while (searchLength <= filterLength) {
+ if (this.options.matchInside) {
+ maxPos = filterLength - searchLength;
+ } else {
+ maxPos = 0;
+ }
+ pos = 0;
+ while (pos <= maxPos) {
+ search = filter.substr(0, searchLength);
+ if (this.cacheData_[search] !== undefined) {
+ return this.cacheData_[search];
+ }
+ pos++;
+ }
+ searchLength++;
+ }
+ }
+ return false;
+};
+
+AutoCompleter.prototype.cacheWrite = function(filter, data) {
+ if (this.options.useCache) {
+ if (this.cacheLength_ >= this.options.maxCacheLength) {
+ this.cacheFlush();
+ }
+ filter = String(filter);
+ if (this.cacheData_[filter] !== undefined) {
+ this.cacheLength_++;
+ }
+ return this.cacheData_[filter] = data;
+ }
+ return false;
+};
+
+AutoCompleter.prototype.cacheFlush = function() {
+ this.cacheData_ = {};
+ this.cacheLength_ = 0;
+};
+
+AutoCompleter.prototype.callHook = function(hook, data) {
+ var f = this.options[hook];
+ if (f && $.isFunction(f)) {
+ return f(data, this);
+ }
+ return false;
+};
+
+AutoCompleter.prototype.activate = function() {
+ var self = this;
+ var activateNow = function() {
+ self.activateNow();
+ };
+ var delay = parseInt(this.options.delay, 10);
+ if (isNaN(delay) || delay <= 0) {
+ delay = 250;
+ }
+ if (this.keyTimeout_) {
+ clearTimeout(this.keyTimeout_);
+ }
+ this.keyTimeout_ = setTimeout(activateNow, delay);
+};
+
+AutoCompleter.prototype.activateNow = function() {
+ var value = this.getValue();
+ if (value !== this.lastProcessedValue_ && value !== this.lastSelectedValue_) {
+ if (value.length >= this.options.minChars) {
+ this.active_ = true;
+ this.lastProcessedValue_ = value;
+ this.fetchData(value);
+ }
+ }
+};
+
+AutoCompleter.prototype.fetchData = function(value) {
+ var self = this;
+ this.fetchRemoteData(value, function(remoteData) {
+ self.filterAndShowResults(remoteData, value);
+ });
+};
+
+AutoCompleter.prototype.fetchRemoteData = function(filter, callback) {
+ var data = this.cacheRead(filter);
+ if (data) {
+ callback(data);
+ } else {
+ var self = this;
+ if (this._element){
+ this._element.addClass(this.options.loadingClass);
+ }
+ var ajaxCallback = function(data) {
+ var parsed = false;
+ if (data !== false) {
+ parsed = self.parseRemoteData(data);
+ self.options.data = parsed;//cache data forever - E.F.
+ self.cacheWrite(filter, parsed);
+ }
+ if (self._element){
+ self._element.removeClass(self.options.loadingClass);
+ }
+ callback(parsed);
+ };
+ $.ajax({
+ url: this.makeUrl(filter),
+ success: ajaxCallback,
+ error: function() {
+ ajaxCallback(false);
+ }
+ });
+ }
+};
+
+AutoCompleter.prototype.setOption = function(name, value){
+ this.options[name] = value;
+};
+
+AutoCompleter.prototype.setExtraParam = function(name, value) {
+ var index = $.trim(String(name));
+ if (index) {
+ if (!this.options.extraParams) {
+ this.options.extraParams = {};
+ }
+ if (this.options.extraParams[index] !== value) {
+ this.options.extraParams[index] = value;
+ this.cacheFlush();
+ }
+ }
+};
+
+AutoCompleter.prototype.makeUrl = function(param) {
+ var self = this;
+ var url = this.options.url;
+ var params = $.extend({}, this.options.extraParams);
+ // If options.queryParamName === false, append query to url
+ // instead of using a GET parameter
+ if (this.options.queryParamName === false) {
+ url += encodeURIComponent(param);
+ } else {
+ params[this.options.queryParamName] = param;
+ }
+
+ if (this.options.limitParamName && this.options.maxItemsToShow) {
+ params[this.options.limitParamName] = this.options.maxItemsToShow;
+ }
+
+ var urlAppend = [];
+ $.each(params, function(index, value) {
+ urlAppend.push(self.makeUrlParam(index, value));
+ });
+ if (urlAppend.length) {
+ url += url.indexOf('?') == -1 ? '?' : '&';
+ url += urlAppend.join('&');
+ }
+ return url;
+};
+
+AutoCompleter.prototype.makeUrlParam = function(name, value) {
+ return String(name) + '=' + encodeURIComponent(value);
+};
+
+/**
+ * Sanitize CR and LF, then split into lines
+ */
+AutoCompleter.prototype.splitText = function(text) {
+ return String(text).replace(/(\r\n|\r|\n)/g, '\n').split(this.options.lineSeparator);
+};
+
+AutoCompleter.prototype.parseRemoteData = function(remoteData) {
+ var value, lines, i, j, data;
+ var results = [];
+ var lines = this.splitText(remoteData);
+ for (i = 0; i < lines.length; i++) {
+ var line = lines[i].split(this.options.cellSeparator);
+ data = [];
+ for (j = 0; j < line.length; j++) {
+ data.push(unescape(line[j]));
+ }
+ value = data.shift();
+ results.push({ value: unescape(value), data: data });
+ }
+ return results;
+};
+
+AutoCompleter.prototype.filterAndShowResults = function(results, filter) {
+ this.showResults(this.filterResults(results, filter), filter);
+};
+
+AutoCompleter.prototype.filterResults = function(results, filter) {
+
+ var filtered = [];
+ var value, data, i, result, type, include;
+ var regex, pattern, testValue;
+
+ for (i = 0; i < results.length; i++) {
+ result = results[i];
+ type = typeof result;
+ if (type === 'string') {
+ value = result;
+ data = {};
+ } else if ($.isArray(result)) {
+ value = result[0];
+ data = result.slice(1);
+ } else if (type === 'object') {
+ value = result.value;
+ data = result.data;
+ }
+ value = String(value);
+ if (value > '') {
+ if (typeof data !== 'object') {
+ data = {};
+ }
+ if (this.options.filterResults) {
+ pattern = String(filter);
+ testValue = String(value);
+ if (!this.options.matchCase) {
+ pattern = pattern.toLowerCase();
+ testValue = testValue.toLowerCase();
+ }
+ include = testValue.indexOf(pattern);
+ if (this.options.matchInside) {
+ include = include > -1;
+ } else {
+ include = include === 0;
+ }
+ } else {
+ include = true;
+ }
+ if (include) {
+ filtered.push({ value: value, data: data });
+ }
+ }
+ }
+
+ if (this.options.sortResults) {
+ filtered = this.sortResults(filtered, filter);
+ }
+
+ if (this.options.maxItemsToShow > 0 && this.options.maxItemsToShow < filtered.length) {
+ filtered.length = this.options.maxItemsToShow;
+ }
+
+ return filtered;
+
+};
+
+AutoCompleter.prototype.sortResults = function(results, filter) {
+ var self = this;
+ var sortFunction = this.options.sortFunction;
+ if (!$.isFunction(sortFunction)) {
+ sortFunction = function(a, b, f) {
+ return self.sortValueAlpha(a, b, f);
+ };
+ }
+ results.sort(function(a, b) {
+ return sortFunction(a, b, filter);
+ });
+ return results;
+};
+
+AutoCompleter.prototype.sortValueAlpha = function(a, b, filter) {
+ a = String(a.value);
+ b = String(b.value);
+ if (!this.options.matchCase) {
+ a = a.toLowerCase();
+ b = b.toLowerCase();
+ }
+ if (a > b) {
+ return 1;
+ }
+ if (a < b) {
+ return -1;
+ }
+ return 0;
+};
+
+AutoCompleter.prototype.showResults = function(results, filter) {
+ var self = this;
+ var $ul = $('<ul></ul>');
+ var i, result, $li, extraWidth, first = false, $first = false;
+ var numResults = results.length;
+ for (i = 0; i < numResults; i++) {
+ result = results[i];
+ $li = $('<li>' + this.showResult(result.value, result.data) + '</li>');
+ $li.data('value', result.value);
+ $li.data('data', result.data);
+ $li.click(function() {
+ var $this = $(this);
+ self.selectItem($this);
+ }).mousedown(function() {
+ self.finishOnBlur_ = false;
+ }).mouseup(function() {
+ self.finishOnBlur_ = true;
+ });
+ $ul.append($li);
+ if (first === false) {
+ first = String(result.value);
+ $first = $li;
+ $li.addClass(this.options.firstItemClass);
+ }
+ if (i == numResults - 1) {
+ $li.addClass(this.options.lastItemClass);
+ }
+ }
+
+ // Alway recalculate position before showing since window size or
+ // input element location may have changed. This fixes #14
+ this.position();
+
+ this._results.html($ul).show();
+ extraWidth = this._results.outerWidth() - this._results.width();
+ this._results.width(this._element.outerWidth() - extraWidth);
+ $('li', this._results).hover(
+ function() { self.focusItem(this); },
+ function() { /* void */ }
+ );
+ if (this.autoFill(first, filter)) {
+ this.focusItem($first);
+ }
+};
+
+AutoCompleter.prototype.showResult = function(value, data) {
+ if ($.isFunction(this.options.showResult)) {
+ return this.options.showResult(value, data);
+ } else {
+ return value;
+ }
+};
+
+AutoCompleter.prototype.autoFill = function(value, filter) {
+ var lcValue, lcFilter, valueLength, filterLength;
+ if (this.options.autoFill && this.lastKeyPressed_ != 8) {
+ lcValue = String(value).toLowerCase();
+ lcFilter = String(filter).toLowerCase();
+ valueLength = value.length;
+ filterLength = filter.length;
+ if (lcValue.substr(0, filterLength) === lcFilter) {
+ this._element.val(value);
+ this.selectRange(filterLength, valueLength);
+ return true;
+ }
+ }
+ return false;
+};
+
+AutoCompleter.prototype.focusNext = function() {
+ this.focusMove(+1);
+};
+
+AutoCompleter.prototype.focusPrev = function() {
+ this.focusMove(-1);
+};
+
+AutoCompleter.prototype.focusMove = function(modifier) {
+ var i, $items = $('li', this._results);
+ modifier = parseInt(modifier, 10);
+ for (var i = 0; i < $items.length; i++) {
+ if ($($items[i]).hasClass(this.selectClass_)) {
+ this.focusItem(i + modifier);
+ return;
+ }
+ }
+ this.focusItem(0);
+};
+
+AutoCompleter.prototype.focusItem = function(item) {
+ var $item, $items = $('li', this._results);
+ if ($items.length) {
+ $items.removeClass(this.selectClass_).removeClass(this.options.selectClass);
+ if (typeof item === 'number') {
+ item = parseInt(item, 10);
+ if (item < 0) {
+ item = 0;
+ } else if (item >= $items.length) {
+ item = $items.length - 1;
+ }
+ $item = $($items[item]);
+ } else {
+ $item = $(item);
+ }
+ if ($item) {
+ $item.addClass(this.selectClass_).addClass(this.options.selectClass);
+ }
+ }
+};
+
+AutoCompleter.prototype.selectCurrent = function() {
+ var $item = $('li.' + this.selectClass_, this._results);
+ if ($item.length == 1) {
+ this.selectItem($item);
+ } else {
+ this.finish();
+ }
+};
+
+AutoCompleter.prototype.selectItem = function($li) {
+ var value = $li.data('value');
+ var data = $li.data('data');
+ var displayValue = this.displayValue(value, data);
+ this.lastProcessedValue_ = displayValue;
+ this.lastSelectedValue_ = displayValue;
+
+ this.setValue(displayValue);
+
+ this.setCaret(displayValue.length);
+ this.callHook('onItemSelect', { value: value, data: data });
+ this.finish();
+};
+
+/**
+ * @return {boolean} true if the symbol matches something that is
+ * considered content and false otherwise
+ * @param {string} symbol - a single char string
+ */
+AutoCompleter.prototype.isContentChar = function(symbol){
+ if (symbol.match(this.options['stopCharRegex'])){
+ return false;
+ } else if (symbol === this.options['multipleSeparator']){
+ return false;
+ } else {
+ return true;
+ }
+};
+
+/**
+ * takes value from the input box
+ * and saves _selection_start and _selection_end coordinates
+ * respects settings autocompleteMultiple and
+ * multipleSeparator
+ * @return {string} the current word in the
+ * autocompletable word
+ */
+AutoCompleter.prototype.getValue = function(){
+ var sel = this._element.getSelection();
+ var text = this._element.val();
+ var pos = sel.start;//estimated start
+ //find real start
+ var start = pos;
+ for (cpos = pos; cpos >= 0; cpos = cpos - 1){
+ if (cpos === text.length){
+ continue;
+ }
+ var symbol = text.charAt(cpos);
+ if (!this.isContentChar(symbol)){
+ break;
+ }
+ start = cpos;
+ }
+ //find real end
+ var end = pos;
+ for (cpos = pos; cpos < text.length; cpos = cpos + 1){
+ if (cpos === 0){
+ continue;
+ }
+ var symbol = text.charAt(cpos);
+ if (!this.isContentChar(symbol)){
+ break;
+ }
+ end = cpos;
+ }
+ this._selection_start = start;
+ this._selection_end = end;
+ return text.substring(start, end);
+}
+
+/**
+ * sets value of the input box
+ * by replacing the previous selection
+ * with the value from the autocompleter
+ */
+AutoCompleter.prototype.setValue = function(val){
+ var prefix = this._element.val().substring(0, this._selection_start);
+ var postfix = this._element.val().substring(this._selection_end + 1);
+ this._element.val(prefix + val + postfix);
+};
+
+AutoCompleter.prototype.displayValue = function(value, data) {
+ if ($.isFunction(this.options.displayValue)) {
+ return this.options.displayValue(value, data);
+ } else {
+ return value;
+ }
+};
+
+AutoCompleter.prototype.finish = function() {
+ if (this.keyTimeout_) {
+ clearTimeout(this.keyTimeout_);
+ }
+ if (this._element.val() !== this.lastSelectedValue_) {
+ if (this.options.mustMatch) {
+ this._element.val('');
+ }
+ this.callHook('onNoMatch');
+ }
+ this._results.hide();
+ this.lastKeyPressed_ = null;
+ this.lastProcessedValue_ = null;
+ if (this.active_) {
+ this.callHook('onFinish');
+ }
+ this.active_ = false;
+};
+
+AutoCompleter.prototype.selectRange = function(start, end) {
+ var input = this._element.get(0);
+ if (input.setSelectionRange) {
+ input.focus();
+ input.setSelectionRange(start, end);
+ } else if (this.createTextRange) {
+ var range = this.createTextRange();
+ range.collapse(true);
+ range.moveEnd('character', end);
+ range.moveStart('character', start);
+ range.select();
+ }
+};
+
+AutoCompleter.prototype.setCaret = function(pos) {
+ this.selectRange(pos, pos);
+};
+
+(function($){function isRGBACapable(){var $script=$("script:first"),color=$script.css("color"),result=false;if(/^rgba/.test(color)){result=true}else{try{result=(color!=$script.css("color","rgba(0, 0, 0, 0.5)").css("color"));$script.css("color",color)}catch(e){}}return result}$.extend(true,$,{support:{rgba:isRGBACapable()}});var properties=["color","backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","outlineColor"];$.each(properties,function(i,property){$.fx.step[property]=function(fx){if(!fx.init){fx.begin=parseColor($(fx.elem).css(property));fx.end=parseColor(fx.end);fx.init=true}fx.elem.style[property]=calculateColor(fx.begin,fx.end,fx.pos)}});$.fx.step.borderColor=function(fx){if(!fx.init){fx.end=parseColor(fx.end)}var borders=properties.slice(2,6);$.each(borders,function(i,property){if(!fx.init){fx[property]={begin:parseColor($(fx.elem).css(property))}}fx.elem.style[property]=calculateColor(fx[property].begin,fx.end,fx.pos)});fx.init=true};function calculateColor(begin,end,pos){var color="rgb"+($.support.rgba?"a":"")+"("+parseInt((begin[0]+pos*(end[0]-begin[0])),10)+","+parseInt((begin[1]+pos*(end[1]-begin[1])),10)+","+parseInt((begin[2]+pos*(end[2]-begin[2])),10);if($.support.rgba){color+=","+(begin&&end?parseFloat(begin[3]+pos*(end[3]-begin[3])):1)}color+=")";return color}function parseColor(color){var match,triplet;if(match=/#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})/.exec(color)){triplet=[parseInt(match[1],16),parseInt(match[2],16),parseInt(match[3],16),1]}else{if(match=/#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])/.exec(color)){triplet=[parseInt(match[1],16)*17,parseInt(match[2],16)*17,parseInt(match[3],16)*17,1]}else{if(match=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)){triplet=[parseInt(match[1]),parseInt(match[2]),parseInt(match[3]),1]}else{if(match=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9\.]*)\s*\)/.exec(color)){triplet=[parseInt(match[1],10),parseInt(match[2],10),parseInt(match[3],10),parseFloat(match[4])]}else{if(color=="transparent"){triplet=[0,0,0,0]}}}}}return triplet}})(jQuery);
+
+/**
+ * Timeago is a jQuery plugin that makes it easy to support automatically
+ * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
+ *
+ * @name timeago
+ * @version 0.11.1
+ * @requires jQuery v1.2.3+
+ * @author Ryan McGeary
+ * @license MIT License - http://www.opensource.org/licenses/mit-license.php
+ *
+ * For usage and examples, visit:
+ * http://timeago.yarp.com/
+ *
+ * Copyright (c) 2008-2011, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org)
+ */
+(function($) {
+ $.timeago = function(timestamp) {
+ if (timestamp instanceof Date) {
+ return inWords(timestamp);
+ } else if (typeof timestamp === "string") {
+ return inWords($.timeago.parse(timestamp));
+ } else {
+ return inWords($.timeago.datetime(timestamp));
+ }
+ };
+ var $t = $.timeago;
+
+ $.extend($.timeago, {
+ settings: {
+ refreshMillis: 60000,
+ allowFuture: false,
+ strings: {
+ prefixAgo: null,
+ prefixFromNow: null,
+ suffixAgo: gettext("ago"),
+ suffixFromNow: gettext("from now"),
+ seconds: gettext("just now"),
+ minute: gettext("about a minute"),
+ minutes: gettext("%d minutes"),
+ hour: gettext("about an hour"),
+ hours: gettext("%d hours"),
+ day: gettext("yesterday"),
+ days: gettext("%d days"),
+ month: gettext("about a month"),
+ months: gettext("%d months"),
+ year: gettext("about a year"),
+ years: gettext("%d years"),
+ wordSeparator: " ",
+ numbers: []
+ }
+ },
+ inWords: function(distanceMillis) {
+ var $l = this.settings.strings;
+ var prefix = $l.prefixAgo;
+ var suffix = $l.suffixAgo;
+ if (this.settings.allowFuture) {
+ if (distanceMillis < 0) {
+ prefix = $l.prefixFromNow;
+ suffix = $l.suffixFromNow;
+ }
+ }
+
+ var seconds = Math.abs(distanceMillis) / 1000;
+ var minutes = seconds / 60;
+ var hours = minutes / 60;
+ var days = hours / 24;
+ var years = days / 365;
+
+ function substitute(stringOrFunction, number) {
+ var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
+ var value = ($l.numbers && $l.numbers[number]) || number;
+ return string.replace(/%d/i, value);
+ }
+
+ var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
+ seconds < 90 && substitute($l.minute, 1) ||
+ minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
+ minutes < 90 && substitute($l.hour, 1) ||
+ hours < 24 && substitute($l.hours, Math.round(hours)) ||
+ hours < 42 && substitute($l.day, 1) ||
+ days < 30 && substitute($l.days, Math.round(days)) ||
+ days < 45 && substitute($l.month, 1) ||
+ days < 365 && substitute($l.months, Math.round(days / 30)) ||
+ years < 1.5 && substitute($l.year, 1) ||
+ substitute($l.years, Math.round(years));
+
+ var separator = $l.wordSeparator === undefined ? " " : $l.wordSeparator;
+ return $.trim([prefix, words, suffix].join(separator));
+ },
+ parse: function(iso8601) {
+ var s = $.trim(iso8601);
+ s = s.replace(/\.\d\d\d+/,""); // remove milliseconds
+ s = s.replace(/-/,"/").replace(/-/,"/");
+ s = s.replace(/T/," ").replace(/Z/," UTC");
+ s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
+ return new Date(s);
+ },
+ datetime: function(elem) {
+ // jQuery's `is()` doesn't play well with HTML5 in IE
+ var isTime = $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
+ var iso8601 = isTime ? $(elem).attr("datetime") : $(elem).attr("title");
+ return $t.parse(iso8601);
+ }
+ });
+
+ $.fn.timeago = function() {
+ var self = this;
+ self.each(refresh);
+
+ var $s = $t.settings;
+ if ($s.refreshMillis > 0) {
+ setInterval(function() { self.each(refresh); }, $s.refreshMillis);
+ }
+ return self;
+ };
+
+ function refresh() {
+ var data = prepareData(this);
+ if (!isNaN(data.datetime)) {
+ $(this).text(inWords(data.datetime));
+ }
+ return this;
+ }
+
+ function prepareData(element) {
+ element = $(element);
+ if (!element.data("timeago")) {
+ element.data("timeago", { datetime: $t.datetime(element) });
+ var text = $.trim(element.text());
+ if (text.length > 0) {
+ element.attr("title", text);
+ }
+ }
+ return element.data("timeago");
+ }
+
+ function inWords(date) {
+ var distanceMillis = distance(date);
+ var seconds = Math.abs(distanceMillis) / 1000;
+ var minutes = seconds / 60;
+ var hours = minutes / 60;
+ var days = hours / 24;
+ var years = days / 365;
+ var months = [
+ gettext('Jan'),
+ gettext('Feb'),
+ gettext('Mar'),
+ gettext('Apr'),
+ gettext('May'),
+ gettext('Jun'),
+ gettext('Jul'),
+ gettext('Aug'),
+ gettext('Sep'),
+ gettext('Oct'),
+ gettext('Nov'),
+ gettext('Dec')
+ ];
+ //todo: rewrite this in javascript
+ if (days > 2){
+ var month_date = months[date.getMonth()] + ' ' + date.getDate()
+ if (years == 0){
+ //how to do this in js???
+ return month_date;
+ } else {
+ return month_date + ' ' + "'" + date.getYear() % 20;
+ }
+ } else if (days == 2) {
+ return gettext('2 days ago')
+ } else if (days == 1) {
+ return gettext('yesterday')
+ } else if (minutes >= 60) {
+ return interpolate(
+ ngettext(
+ '%s hour ago',
+ '%s hours ago',
+ hours
+ ),
+ [Math.floor(hours),]
+ )
+ } else if (seconds > 90){
+ return interpolate(
+ ngettext(
+ '%s min ago',
+ '%s mins ago',
+ minutes
+ ),
+ [Math.floor(minutes),]
+ )
+ } else {
+ return gettext('just now')
+ }
+ }
+
+ function distance(date) {
+ return (new Date() - date);
+ }
+
+ // fix for IE6 suckage
+ document.createElement("abbr");
+ document.createElement("time");
+}(jQuery));
diff --git a/askbot/skins/common/media/js/wmd/images/editor-toolbar-background.png b/askbot/media/js/wmd/images/editor-toolbar-background.png
index 41875962..41875962 100644
--- a/askbot/skins/common/media/js/wmd/images/editor-toolbar-background.png
+++ b/askbot/media/js/wmd/images/editor-toolbar-background.png
Binary files differ
diff --git a/askbot/skins/common/media/js/wmd/images/wmd-buttons.png b/askbot/media/js/wmd/images/wmd-buttons.png
index 3013a4ad..3013a4ad 100755
--- a/askbot/skins/common/media/js/wmd/images/wmd-buttons.png
+++ b/askbot/media/js/wmd/images/wmd-buttons.png
Binary files differ
diff --git a/askbot/skins/common/media/js/wmd/showdown-min.js b/askbot/media/js/wmd/showdown-min.js
index 073613b1..073613b1 100644
--- a/askbot/skins/common/media/js/wmd/showdown-min.js
+++ b/askbot/media/js/wmd/showdown-min.js
diff --git a/askbot/skins/common/media/js/wmd/showdown.js b/askbot/media/js/wmd/showdown.js
index 257b8bd1..257b8bd1 100644
--- a/askbot/skins/common/media/js/wmd/showdown.js
+++ b/askbot/media/js/wmd/showdown.js
diff --git a/askbot/skins/common/media/js/wmd/wmd-min.js b/askbot/media/js/wmd/wmd-min.js
index aa643f1a..aa643f1a 100644
--- a/askbot/skins/common/media/js/wmd/wmd-min.js
+++ b/askbot/media/js/wmd/wmd-min.js
diff --git a/askbot/skins/common/media/js/wmd/wmd-test.html b/askbot/media/js/wmd/wmd-test.html
index d748501a..d748501a 100644
--- a/askbot/skins/common/media/js/wmd/wmd-test.html
+++ b/askbot/media/js/wmd/wmd-test.html
diff --git a/askbot/skins/common/media/js/wmd/wmd.css b/askbot/media/js/wmd/wmd.css
index 678d70f3..678d70f3 100644
--- a/askbot/skins/common/media/js/wmd/wmd.css
+++ b/askbot/media/js/wmd/wmd.css
diff --git a/askbot/media/js/wmd/wmd.js b/askbot/media/js/wmd/wmd.js
new file mode 100644
index 00000000..5aeacd98
--- /dev/null
+++ b/askbot/media/js/wmd/wmd.js
@@ -0,0 +1,2510 @@
+var Attacklab = Attacklab || {};
+
+Attacklab.wmdBase = function(){
+
+ // A few handy aliases for readability.
+ var wmd = self.Attacklab;
+ var doc = self.document;
+ var re = self.RegExp;
+ var nav = self.navigator;
+
+ // Some namespaces.
+ wmd.Util = {};
+ wmd.Position = {};
+ wmd.Command = {};
+ wmd.Global = {};
+
+ var util = wmd.Util;
+ var position = wmd.Position;
+ var command = wmd.Command;
+ var global = wmd.Global;
+
+
+ // Used to work around some browser bugs where we can't use feature testing.
+ global.isChrome = /chrome/.test(nav.userAgent.toLowerCase());
+ global.isIE = /msie/.test(nav.userAgent.toLowerCase());
+ global.isIE_5or6 = /msie 6/.test(nav.userAgent.toLowerCase()) || /msie 5/.test(nav.userAgent.toLowerCase());
+ global.isIE_7plus = global.isIE && !global.isIE_5or6;
+ global.isOpera = /opera/.test(nav.userAgent.toLowerCase());
+ global.isKonqueror = /konqueror/.test(nav.userAgent.toLowerCase());
+
+ var toolbar_strong_label = gettext('bold') + " <strong> Ctrl-B";
+ var toolbar_emphasis_label = gettext('italic') + " <em> Ctrl-I";
+ var toolbar_hyperlink_label = gettext('link') + " <a> Ctrl-L";
+ var toolbar_blockquote_label = gettext('quote') + " <blockquote> Ctrl-.";
+ var toolbar_code_label = gettext('preformatted text') + " <pre><code> Ctrl-K";
+ var toolbar_image_label = gettext('image') + " <img> Ctrl-G";
+ var toolbar_attachment_label = gettext('attachment') + " Ctrl-F";
+ var toolbar_numbered_label = gettext('numbered list') + " <ol> Ctrl-O";
+ var toolbar_bulleted_label = gettext('bulleted list') + " <ul> Ctrl-U";
+ var toolbar_heading_label = gettext('heading') + " <h1>/<h2> Ctrl-H";
+ var toolbar_horizontal_label = gettext('horizontal bar') + " <hr> Ctrl-R";
+ var toolbar_undo_label = gettext('undo') + " Ctrl-Z";
+ var toolbar_redo_label = gettext('redo') + " Ctrl-Y";
+
+ // -------------------------------------------------------------------
+ // YOUR CHANGES GO HERE
+ //
+ // I've tried to localize the things you are likely to change to
+ // this area.
+ // -------------------------------------------------------------------
+
+ // The text that appears on the upper part of the dialog box when
+ // entering links.
+ var imageDialogText = "<p style='margin-top: 0px'>" + gettext('enter image url') + '</p>';
+ var linkDialogText = "<p style='margin-top: 0px'>" + gettext('enter url') + '</p>';
+ var fileDialogText = "<p>" + gettext('upload file attachment') + '</p>';
+ // The default text that appears in the dialog input box when entering
+ // links.
+ var imageDefaultText = "http://";
+ var linkDefaultText = "http://";
+
+ // The location of your button images relative to the base directory.
+ var imageDirectory = "images/";
+
+ // Some intervals in ms. These can be adjusted to reduce the control's load.
+ var previewPollInterval = 500;
+ var pastePollInterval = 100;
+
+ // The link and title for the help button
+ var helpLink = "http://wmd-editor.com/";
+ var helpHoverTitle = "WMD website";
+ var helpTarget = "_blank";
+ var localUploadFileName = null;
+
+ // -------------------------------------------------------------------
+ // END OF YOUR CHANGES
+ // -------------------------------------------------------------------
+
+ // A collection of the important regions on the page.
+ // Cached so we don't have to keep traversing the DOM.
+ wmd.PanelCollection = function(){
+ this.buttonBar = doc.getElementById("wmd-button-bar");
+ this.preview = doc.getElementById("previewer");
+ this.output = doc.getElementById("wmd-output");
+ this.input = doc.getElementById("editor");
+ };
+
+ // This PanelCollection object can't be filled until after the page
+ // has loaded.
+ wmd.panels = undefined;
+
+ // Internet explorer has problems with CSS sprite buttons that use HTML
+ // lists. When you click on the background image "button", IE will
+ // select the non-existent link text and discard the selection in the
+ // textarea. The solution to this is to cache the textarea selection
+ // on the button's mousedown event and set a flag. In the part of the
+ // code where we need to grab the selection, we check for the flag
+ // and, if it's set, use the cached area instead of querying the
+ // textarea.
+ //
+ // This ONLY affects Internet Explorer (tested on versions 6, 7
+ // and 8) and ONLY on button clicks. Keyboard shortcuts work
+ // normally since the focus never leaves the textarea.
+ wmd.ieCachedRange = null; // cached textarea selection
+ wmd.ieRetardedClick = false; // flag
+
+ // Returns true if the DOM element is visible, false if it's hidden.
+ // Checks if display is anything other than none.
+ util.isVisible = function (elem) {
+
+ if (window.getComputedStyle) {
+ // Most browsers
+ return window.getComputedStyle(elem, null).getPropertyValue("display") !== "none";
+ }
+ else if (elem.currentStyle) {
+ // IE
+ return elem.currentStyle.display !== "none";
+ }
+ };
+
+
+ // Adds a listener callback to a DOM element which is fired on a specified
+ // event.
+ util.addEvent = function(elem, event, listener){
+ if (elem.attachEvent) {
+ // IE only. The "on" is mandatory.
+ elem.attachEvent("on" + event, listener);
+ }
+ else {
+ // Other browsers.
+ elem.addEventListener(event, listener, false);
+ }
+ };
+
+
+ // Removes a listener callback from a DOM element which is fired on a specified
+ // event.
+ util.removeEvent = function(elem, event, listener){
+ if (elem.detachEvent) {
+ // IE only. The "on" is mandatory.
+ elem.detachEvent("on" + event, listener);
+ }
+ else {
+ // Other browsers.
+ elem.removeEventListener(event, listener, false);
+ }
+ };
+
+ // Converts \r\n and \r to \n.
+ util.fixEolChars = function(text){
+ text = text.replace(/\r\n/g, "\n");
+ text = text.replace(/\r/g, "\n");
+ return text;
+ };
+
+ // Extends a regular expression. Returns a new RegExp
+ // using pre + regex + post as the expression.
+ // Used in a few functions where we have a base
+ // expression and we want to pre- or append some
+ // conditions to it (e.g. adding "$" to the end).
+ // The flags are unchanged.
+ //
+ // regex is a RegExp, pre and post are strings.
+ util.extendRegExp = function(regex, pre, post){
+
+ if (pre === null || pre === undefined)
+ {
+ pre = "";
+ }
+ if(post === null || post === undefined)
+ {
+ post = "";
+ }
+
+ var pattern = regex.toString();
+ var flags;
+
+ // Replace the flags with empty space and store them.
+ pattern = pattern.replace(/\/([gim]*)$/, "");
+ flags = re.$1;
+
+ // Remove the slash delimiters on the regular expression.
+ pattern = pattern.replace(/(^\/|\/$)/g, "");
+ pattern = pre + pattern + post;
+
+ return new re(pattern, flags);
+ };
+
+
+ // Sets the image for a button passed to the WMD editor.
+ // Returns a new element with the image attached.
+ // Adds several style properties to the image.
+ util.createImage = function(img){
+
+ var imgPath = imageDirectory + img;
+
+ var elem = doc.createElement("img");
+ elem.className = "wmd-button";
+ elem.src = imgPath;
+
+ return elem;
+ };
+
+
+// This simulates a modal dialog box and asks for the URL when you
+// click the hyperlink or image buttons.
+//
+// text: The html for the input box.
+// defaultInputText: The default value that appears in the input box.
+// makeLinkMarkdown: The function which is executed when the prompt is dismissed, either via OK or Cancel
+util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
+
+ // These variables need to be declared at this level since they are used
+ // in multiple functions.
+ var dialog;// The dialog box.
+ var background;// The background beind the dialog box.
+ var input;// The text box where you enter the hyperlink.
+
+ if (defaultInputText === undefined) {
+ defaultInputText = "";
+ }
+
+ // Used as a keydown event handler. Esc dismisses the prompt.
+ // Key code 27 is ESC.
+ var checkEscape = function(key){
+ var code = (key.charCode || key.keyCode);
+ if (code === 27) {
+ close(true);
+ }
+ };
+
+ // Dismisses the hyperlink input box.
+ // isCancel is true if we don't care about the input text.
+ // isCancel is false if we are going to keep the text.
+ var close = function(isCancel){
+ util.removeEvent(doc.body, "keydown", checkEscape);
+ var text = input.value;
+
+ if (isCancel){
+ text = null;
+ }
+ else{
+ // Fixes common pasting errors.
+ text = text.replace('http://http://', 'http://');
+ text = text.replace('http://https://', 'https://');
+ text = text.replace('http://ftp://', 'ftp://');
+
+ if (text.indexOf('http://') === -1 && text.indexOf('ftp://') === -1 && text.indexOf('https://') === -1) {
+ if (dialogType == 'link'){
+ //add http only to urls
+ text = 'http://' + text;
+ }
+ }
+ }
+
+ dialog.parentNode.removeChild(dialog);
+ background.parentNode.removeChild(background);
+ makeLinkMarkdown(text);
+ return false;
+ };
+
+ // Creates the background behind the hyperlink text entry box.
+ // Most of this has been moved to CSS but the div creation and
+ // browser-specific hacks remain here.
+ var createBackground = function(){
+
+ background = doc.createElement("div");
+ background.className = "wmd-prompt-background";
+ style = background.style;
+ style.position = "absolute";
+ style.top = "0";
+
+ style.zIndex = "1000";
+
+ // Some versions of Konqueror don't support transparent colors
+ // so we make the whole window transparent.
+ //
+ // Is this necessary on modern konqueror browsers?
+ if (global.isKonqueror){
+ style.backgroundColor = "transparent";
+ }
+ else if (global.isIE){
+ style.filter = "alpha(opacity=50)";
+ }
+ else {
+ style.opacity = "0.5";
+ }
+
+ var pageSize = position.getPageSize();
+ style.height = pageSize[1] + "px";
+
+ if(global.isIE){
+ style.left = doc.documentElement.scrollLeft;
+ style.width = doc.documentElement.clientWidth;
+ }
+ else {
+ style.left = "0";
+ style.width = "100%";
+ }
+
+ doc.body.appendChild(background);
+ };
+
+ // Create the text input box form/window.
+ var createDialog = function(){
+
+ // The main dialog box.
+ dialog = doc.createElement("div");
+ dialog.className = "wmd-prompt-dialog";
+ dialog.style.padding = "10px;";
+ dialog.style.position = "fixed";
+ dialog.style.width = "400px";
+ dialog.style.zIndex = "1001";
+
+ // The dialog text.
+ var question = doc.createElement("div");
+ question.innerHTML = text;
+ question.style.padding = "5px";
+ dialog.appendChild(question);
+
+ // The web form container for the text box and buttons.
+ var form = doc.createElement("form");
+ form.onsubmit = function(){ return close(false); };
+ style = form.style;
+ style.padding = "0";
+ style.margin = "0";
+ style.cssFloat = "left";
+ style.width = "100%";
+ style.textAlign = "center";
+ style.position = "relative";
+ dialog.appendChild(form);
+
+ // The input text box
+ input = doc.createElement("input");
+ if(dialogType == 'image' || dialogType == 'file'){
+ input.id = "image-url";
+ }
+ input.type = "text";
+ if (dialogType == 'file'){
+ input.disabled = "disabled";
+ };
+
+ input.value = defaultInputText;
+ style = input.style;
+ style.display = "block";
+ style.width = "80%";
+ style.marginLeft = style.marginRight = "auto";
+ form.appendChild(input);
+
+ //EF. fucus at the end of the input box
+ //putCursorAtEnd($(input));
+
+ // The upload file input
+ if(dialogType == 'image' || dialogType == 'file'){
+ var upload_container = $('<div></div>');
+ var upload_input = $('<input type="file" />');
+ upload_input.attr('name', 'file-upload');
+ upload_input.attr('id', 'file-upload');
+ upload_input.attr('size', 26);
+
+ var spinner = $('<img />');
+ spinner.attr('id', 'loading');
+ spinner.attr('src', mediaUrl("media/images/indicator.gif"));
+ spinner.css('display', 'none');
+
+ var startUploadHandler = function(){
+ localUploadFileName = $(this).val();//this is a local var
+ /*
+ * startUploadHandler is passed into the ajaxFileUpload
+ * in order to re-install the onchange handler
+ * because the jquery extension ajaxFileUpload removes the handler
+ */
+ var options = {
+ spinner: spinner,
+ uploadInputId: 'file-upload',
+ urlInput: $(input),
+ startUploadHandler: startUploadHandler
+ };
+ return ajaxFileUpload(options);
+ //$('#image-url'), startUploadHandler);
+ };
+
+ upload_input.change(startUploadHandler);
+
+ upload_container.append(upload_input);
+ upload_container.append($('<br/>'));
+
+ upload_container.append(spinner);
+
+ upload_container.css('padding', '5px');
+ $(form).append(upload_container);
+ }
+
+ // The ok button
+ var okButton = doc.createElement("input");
+ okButton.type = "button";
+ okButton.onclick = function(){
+ var isCancel = false;
+ if ($.trim($(input).val()) === ''){
+ isCancel = true;
+ }
+ return close(isCancel);
+ };
+ okButton.value = "OK";
+ style = okButton.style;
+ style.margin = "10px";
+ style.display = "inline";
+ style.width = "7em";
+
+ // The cancel button
+ var cancelButton = doc.createElement("input");
+ cancelButton.type = "button";
+ cancelButton.onclick = function(){ return close(true); };
+ cancelButton.value = "Cancel";
+ style = cancelButton.style;
+ style.margin = "10px";
+ style.display = "inline";
+ style.width = "7em";
+
+ // The order of these buttons is different on macs.
+ if (/mac/.test(nav.platform.toLowerCase())) {
+ form.appendChild(cancelButton);
+ form.appendChild(okButton);
+ }
+ else {
+ form.appendChild(okButton);
+ form.appendChild(cancelButton);
+ }
+
+ util.addEvent(doc.body, "keydown", checkEscape);
+ dialog.style.top = "50%";
+ dialog.style.left = "50%";
+ dialog.style.display = "block";
+ if(global.isIE_5or6){
+ dialog.style.position = "absolute";
+ dialog.style.top = doc.documentElement.scrollTop + 200 + "px";
+ dialog.style.left = "50%";
+ }
+ doc.body.appendChild(dialog);
+
+ // This has to be done AFTER adding the dialog to the form if you
+ // want it to be centered.
+ dialog.style.marginTop = -(position.getHeight(dialog) / 2) + "px";
+ dialog.style.marginLeft = -(position.getWidth(dialog) / 2) + "px";
+
+ };
+
+ createBackground();
+
+ // Why is this in a zero-length timeout?
+ // Is it working around a browser bug?
+ top.setTimeout(function(){
+ createDialog();
+ var defTextLen = defaultInputText.length;
+ if (input.type == 'text' && input.selectionStart !== undefined) {
+ input.selectionStart = 0;
+ input.selectionEnd = defTextLen;
+ }
+ else if (input.createTextRange) {
+ var range = input.createTextRange();
+ range.collapse(false);
+ range.moveStart("character", -defTextLen);
+ range.moveEnd("character", defTextLen);
+ range.select();
+ }
+
+ input.focus();
+ }, 0);
+};
+
+
+ // UNFINISHED
+ // The assignment in the while loop makes jslint cranky.
+ // I'll change it to a better loop later.
+ position.getTop = function(elem, isInner){
+ var result = elem.offsetTop;
+ if (!isInner) {
+ while (elem.offsetParent) {
+ elem = elem.offsetParent;
+ result += elem.offsetTop;
+ }
+ }
+ return result;
+ };
+
+ position.getHeight = function (elem) {
+ return elem.offsetHeight || elem.scrollHeight;
+ };
+
+ position.getWidth = function (elem) {
+ return elem.offsetWidth || elem.scrollWidth;
+ };
+
+ position.getPageSize = function(){
+
+ var scrollWidth, scrollHeight;
+ var innerWidth, innerHeight;
+
+ // It's not very clear which blocks work with which browsers.
+ if(self.innerHeight && self.scrollMaxY){
+ scrollWidth = doc.body.scrollWidth;
+ scrollHeight = self.innerHeight + self.scrollMaxY;
+ }
+ else if(doc.body.scrollHeight > doc.body.offsetHeight){
+ scrollWidth = doc.body.scrollWidth;
+ scrollHeight = doc.body.scrollHeight;
+ }
+ else{
+ scrollWidth = doc.body.offsetWidth;
+ scrollHeight = doc.body.offsetHeight;
+ }
+
+ if(self.innerHeight){
+ // Non-IE browser
+ innerWidth = self.innerWidth;
+ innerHeight = self.innerHeight;
+ }
+ else if(doc.documentElement && doc.documentElement.clientHeight){
+ // Some versions of IE (IE 6 w/ a DOCTYPE declaration)
+ innerWidth = doc.documentElement.clientWidth;
+ innerHeight = doc.documentElement.clientHeight;
+ }
+ else if(doc.body){
+ // Other versions of IE
+ innerWidth = doc.body.clientWidth;
+ innerHeight = doc.body.clientHeight;
+ }
+
+ var maxWidth = Math.max(scrollWidth, innerWidth);
+ var maxHeight = Math.max(scrollHeight, innerHeight);
+ return [maxWidth, maxHeight, innerWidth, innerHeight];
+ };
+
+ // Watches the input textarea, polling at an interval and runs
+ // a callback function if anything has changed.
+ wmd.inputPoller = function(callback, interval){
+
+ var pollerObj = this;
+ var inputArea = wmd.panels.input;
+
+ // Stored start, end and text. Used to see if there are changes to the input.
+ var lastStart;
+ var lastEnd;
+ var markdown;
+
+ var killHandle; // Used to cancel monitoring on destruction.
+ // Checks to see if anything has changed in the textarea.
+ // If so, it runs the callback.
+ this.tick = function(){
+
+ if (!util.isVisible(inputArea)) {
+ return;
+ }
+
+ // Update the selection start and end, text.
+ if (inputArea.selectionStart || inputArea.selectionStart === 0) {
+ var start = inputArea.selectionStart;
+ var end = inputArea.selectionEnd;
+ if (start != lastStart || end != lastEnd) {
+ lastStart = start;
+ lastEnd = end;
+
+ if (markdown != inputArea.value) {
+ markdown = inputArea.value;
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+
+ var doTickCallback = function(){
+
+ if (!util.isVisible(inputArea)) {
+ return;
+ }
+
+ // If anything has changed, call the function.
+ if (pollerObj.tick()) {
+ callback();
+ }
+ };
+
+ // Set how often we poll the textarea for changes.
+ var assignInterval = function(){
+ // previewPollInterval is set at the top of the namespace.
+ killHandle = top.setInterval(doTickCallback, interval);
+ };
+
+ this.destroy = function(){
+ top.clearInterval(killHandle);
+ };
+
+ assignInterval();
+ };
+
+ // Handles pushing and popping TextareaStates for undo/redo commands.
+ // I should rename the stack variables to list.
+ wmd.undoManager = function(callback){
+
+ var undoObj = this;
+ var undoStack = []; // A stack of undo states
+ var stackPtr = 0; // The index of the current state
+ var mode = "none";
+ var lastState; // The last state
+ var poller;
+ var timer; // The setTimeout handle for cancelling the timer
+ var inputStateObj;
+
+ // Set the mode for later logic steps.
+ var setMode = function(newMode, noSave){
+
+ if (mode != newMode) {
+ mode = newMode;
+ if (!noSave) {
+ saveState();
+ }
+ }
+
+ if (!global.isIE || mode != "moving") {
+ timer = top.setTimeout(refreshState, 1);
+ }
+ else {
+ inputStateObj = null;
+ }
+ };
+
+ var refreshState = function(){
+ inputStateObj = new wmd.TextareaState();
+ poller.tick();
+ timer = undefined;
+ };
+
+ this.setCommandMode = function(){
+ mode = "command";
+ saveState();
+ timer = top.setTimeout(refreshState, 0);
+ };
+
+ this.canUndo = function(){
+ return stackPtr > 1;
+ };
+
+ this.canRedo = function(){
+ if (undoStack[stackPtr + 1]) {
+ return true;
+ }
+ return false;
+ };
+
+ // Removes the last state and restores it.
+ this.undo = function(){
+
+ if (undoObj.canUndo()) {
+ if (lastState) {
+ // What about setting state -1 to null or checking for undefined?
+ lastState.restore();
+ lastState = null;
+ }
+ else {
+ undoStack[stackPtr] = new wmd.TextareaState();
+ undoStack[--stackPtr].restore();
+
+ if (callback) {
+ callback();
+ }
+ }
+ }
+
+ mode = "none";
+ wmd.panels.input.focus();
+ refreshState();
+ };
+
+ // Redo an action.
+ this.redo = function(){
+
+ if (undoObj.canRedo()) {
+
+ undoStack[++stackPtr].restore();
+
+ if (callback) {
+ callback();
+ }
+ }
+
+ mode = "none";
+ wmd.panels.input.focus();
+ refreshState();
+ };
+
+ // Push the input area state to the stack.
+ var saveState = function(){
+
+ var currState = inputStateObj || new wmd.TextareaState();
+
+ if (!currState) {
+ return false;
+ }
+ if (mode == "moving") {
+ if (!lastState) {
+ lastState = currState;
+ }
+ return;
+ }
+ if (lastState) {
+ if (undoStack[stackPtr - 1].text != lastState.text) {
+ undoStack[stackPtr++] = lastState;
+ }
+ lastState = null;
+ }
+ undoStack[stackPtr++] = currState;
+ undoStack[stackPtr + 1] = null;
+ if (callback) {
+ callback();
+ }
+ };
+
+ var handleCtrlYZ = function(event){
+
+ var handled = false;
+
+ if (event.ctrlKey || event.metaKey) {
+
+ // IE and Opera do not support charCode.
+ var keyCode = event.charCode || event.keyCode;
+ var keyCodeChar = String.fromCharCode(keyCode);
+
+ switch (keyCodeChar) {
+
+ case "y":
+ undoObj.redo();
+ handled = true;
+ break;
+
+ case "z":
+ if (!event.shiftKey) {
+ undoObj.undo();
+ }
+ else {
+ undoObj.redo();
+ }
+ handled = true;
+ break;
+ }
+ }
+
+ if (handled) {
+ if (event.preventDefault) {
+ event.preventDefault();
+ }
+ if (top.event) {
+ top.event.returnValue = false;
+ }
+ return;
+ }
+ };
+
+ // Set the mode depending on what is going on in the input area.
+ var handleModeChange = function(event){
+
+ if (!event.ctrlKey && !event.metaKey) {
+
+ var keyCode = event.keyCode;
+
+ if ((keyCode >= 33 && keyCode <= 40) || (keyCode >= 63232 && keyCode <= 63235)) {
+ // 33 - 40: page up/dn and arrow keys
+ // 63232 - 63235: page up/dn and arrow keys on safari
+ setMode("moving");
+ }
+ else if (keyCode == 8 || keyCode == 46 || keyCode == 127) {
+ // 8: backspace
+ // 46: delete
+ // 127: delete
+ setMode("deleting");
+ }
+ else if (keyCode == 13) {
+ // 13: Enter
+ setMode("newlines");
+ }
+ else if (keyCode == 27) {
+ // 27: escape
+ setMode("escape");
+ }
+ else if ((keyCode < 16 || keyCode > 20) && keyCode != 91) {
+ // 16-20 are shift, etc.
+ // 91: left window key
+ // I think this might be a little messed up since there are
+ // a lot of nonprinting keys above 20.
+ setMode("typing");
+ }
+ }
+ };
+
+ var setEventHandlers = function(){
+
+ util.addEvent(wmd.panels.input, "keypress", function(event){
+ // keyCode 89: y
+ // keyCode 90: z
+ if ((event.ctrlKey || event.metaKey) && (event.keyCode == 89 || event.keyCode == 90)) {
+ event.preventDefault();
+ }
+ });
+
+ var handlePaste = function(){
+ if (global.isIE || (inputStateObj && inputStateObj.text != wmd.panels.input.value)) {
+ if (timer === undefined) {
+ mode = "paste";
+ saveState();
+ refreshState();
+ }
+ }
+ };
+
+ // pastePollInterval is specified at the beginning of this namespace.
+ poller = new wmd.inputPoller(handlePaste, pastePollInterval);
+
+ util.addEvent(wmd.panels.input, "keydown", handleCtrlYZ);
+ util.addEvent(wmd.panels.input, "keydown", handleModeChange);
+
+ util.addEvent(wmd.panels.input, "mousedown", function(){
+ setMode("moving");
+ });
+ wmd.panels.input.onpaste = handlePaste;
+ wmd.panels.input.ondrop = handlePaste;
+ };
+
+ var init = function(){
+ setEventHandlers();
+ refreshState();
+ saveState();
+ };
+
+ this.destroy = function(){
+ if (poller) {
+ poller.destroy();
+ }
+ };
+
+ init();
+ };
+
+ // I think my understanding of how the buttons and callbacks are stored in the array is incomplete.
+ wmd.editor = function(previewRefreshCallback){
+
+ if (!previewRefreshCallback) {
+ previewRefreshCallback = function(){};
+ }
+
+ var inputBox = wmd.panels.input;
+
+ var offsetHeight = 0;
+
+ var editObj = this;
+
+ var mainDiv;
+ var mainSpan;
+
+ var div; // This name is pretty ambiguous. I should rename this.
+
+ // Used to cancel recurring events from setInterval.
+ var creationHandle;
+
+ var undoMgr; // The undo manager
+
+ var isButtonUsed = function(button){
+ var buttons = $.trim(wmd.wmd_env.buttons).split(/\s+/);
+ return $.inArray(button, buttons) !== -1;
+ };
+
+ // Perform the button's action.
+ var doClick = function(button){
+
+ inputBox.focus();
+
+ if (button.textOp) {
+
+ if (undoMgr) {
+ undoMgr.setCommandMode();
+ }
+
+ var state = new wmd.TextareaState();
+
+ if (!state) {
+ return;
+ }
+
+ var chunks = state.getChunks();
+
+ // Some commands launch a "modal" prompt dialog. Javascript
+ // can't really make a modal dialog box and the WMD code
+ // will continue to execute while the dialog is displayed.
+ // This prevents the dialog pattern I'm used to and means
+ // I can't do something like this:
+ //
+ // var link = CreateLinkDialog();
+ // makeMarkdownLink(link);
+ //
+ // Instead of this straightforward method of handling a
+ // dialog I have to pass any code which would execute
+ // after the dialog is dismissed (e.g. link creation)
+ // in a function parameter.
+ //
+ // Yes this is awkward and I think it sucks, but there's
+ // no real workaround. Only the image and link code
+ // create dialogs and require the function pointers.
+ var fixupInputArea = function(){
+
+ inputBox.focus();
+
+ if (chunks) {
+ state.setChunks(chunks);
+ }
+
+ state.restore();
+ previewRefreshCallback();
+ };
+
+ var noCleanup = button.textOp(chunks, fixupInputArea);
+
+ if(!noCleanup) {
+ fixupInputArea();
+ }
+
+ }
+
+ if (button.execute) {
+ button.execute(editObj);
+ }
+ };
+
+ var setUndoRedoButtonStates = function(){
+ if(undoMgr){
+ setupButton(document.getElementById("wmd-undo-button"), undoMgr.canUndo());
+ setupButton(document.getElementById("wmd-redo-button"), undoMgr.canRedo());
+ }
+ };
+
+ var setupButton = function(button, isEnabled) {
+
+ var normalYShift = "0px";
+ var disabledYShift = "-20px";
+ var highlightYShift = "-40px";
+
+ if(isEnabled) {
+ button.style.backgroundPosition = button.XShift + " " + normalYShift;
+ button.onmouseover = function(){
+ this.style.backgroundPosition = this.XShift + " " + highlightYShift;
+ };
+
+ button.onmouseout = function(){
+ this.style.backgroundPosition = this.XShift + " " + normalYShift;
+ };
+
+ // IE tries to select the background image "button" text (it's
+ // implemented in a list item) so we have to cache the selection
+ // on mousedown.
+ if(global.isIE) {
+ button.onmousedown = function() {
+ wmd.ieRetardedClick = true;
+ wmd.ieCachedRange = document.selection.createRange();
+ };
+ }
+
+ if (!button.isHelp)
+ {
+ button.onclick = function() {
+ if (this.onmouseout) {
+ this.onmouseout();
+ }
+ doClick(this);
+ return false;
+ };
+ }
+ }
+ else {
+ button.style.backgroundPosition = button.XShift + " " + disabledYShift;
+ button.onmouseover = button.onmouseout = button.onclick = function(){};
+ }
+ };
+
+ var makeSpritedButtonRow = function(){
+ var buttonBar = document.getElementById("wmd-button-bar");
+ var normalYShift = "0px";
+ var disabledYShift = "-20px";
+ var highlightYShift = "-40px";
+
+ var buttonRow = document.createElement("ul");
+ buttonRow.id = "wmd-button-row";
+ buttonRow = buttonBar.appendChild(buttonRow);
+
+ if (isButtonUsed('bold')){
+ var boldButton = document.createElement("li");
+ boldButton.className = "wmd-button";
+ boldButton.id = "wmd-bold-button";
+ boldButton.title = toolbar_strong_label;
+ boldButton.XShift = "0px";
+ boldButton.textOp = command.doBold;
+ setupButton(boldButton, true);
+ buttonRow.appendChild(boldButton);
+ }
+
+ if (isButtonUsed('italic')){
+ var italicButton = document.createElement("li");
+ italicButton.className = "wmd-button";
+ italicButton.id = "wmd-italic-button";
+ italicButton.title = toolbar_emphasis_label;
+ italicButton.XShift = "-20px";
+ italicButton.textOp = command.doItalic;
+ setupButton(italicButton, true);
+ buttonRow.appendChild(italicButton);
+ }
+
+ if (
+ isButtonUsed('link') ||
+ isButtonUsed('blockquote') ||
+ isButtonUsed('code') ||
+ isButtonUsed('image') ||
+ isButtonUsed('attachment')
+ ) {
+ var spacer1 = document.createElement("li");
+ spacer1.className = "wmd-spacer";
+ spacer1.id = "wmd-spacer1";
+ buttonRow.appendChild(spacer1);
+ }
+
+ if (isButtonUsed('link')){
+ var linkButton = document.createElement("li");
+ linkButton.className = "wmd-button";
+ linkButton.id = "wmd-link-button";
+ linkButton.title = toolbar_hyperlink_label;
+ linkButton.XShift = "-40px";
+ linkButton.textOp = function(chunk, postProcessing){
+ return command.doLinkOrImage(chunk, postProcessing, 'link');
+ };
+ setupButton(linkButton, true);
+ buttonRow.appendChild(linkButton);
+ }
+
+ if (isButtonUsed('blockquote')){
+ var quoteButton = document.createElement("li");
+ quoteButton.className = "wmd-button";
+ quoteButton.id = "wmd-quote-button";
+ quoteButton.title = toolbar_blockquote_label;
+ quoteButton.XShift = "-60px";
+ quoteButton.textOp = command.doBlockquote;
+ setupButton(quoteButton, true);
+ buttonRow.appendChild(quoteButton);
+ }
+
+ if (isButtonUsed('code')){
+ var codeButton = document.createElement("li");
+ codeButton.className = "wmd-button";
+ codeButton.id = "wmd-code-button";
+ codeButton.title = toolbar_code_label;
+ codeButton.XShift = "-80px";
+ codeButton.textOp = command.doCode;
+ setupButton(codeButton, true);
+ buttonRow.appendChild(codeButton);
+ }
+
+ if (isButtonUsed('image')){
+ var imageButton = document.createElement("li");
+ imageButton.className = "wmd-button";
+ imageButton.id = "wmd-image-button";
+ imageButton.title = toolbar_image_label;
+ imageButton.XShift = "-100px";
+ imageButton.textOp = function(chunk, postProcessing){
+ return command.doLinkOrImage(chunk, postProcessing, 'image');
+ };
+ setupButton(imageButton, true);
+ buttonRow.appendChild(imageButton);
+ }
+
+ if (isButtonUsed('attachment')){
+ var attachmentButton = document.createElement("li");
+ attachmentButton.className = "wmd-button";
+ attachmentButton.id = "wmd-attachment-button";
+ attachmentButton.title = toolbar_attachment_label;
+ attachmentButton.XShift = "-120px";
+ attachmentButton.textOp = function(chunk, postProcessing){
+ return command.doLinkOrImage(chunk, postProcessing, 'file');
+ };
+ setupButton(attachmentButton, true);
+ buttonRow.appendChild(attachmentButton);
+ }
+
+ if (
+ isButtonUsed('ol') ||
+ isButtonUsed('ul') ||
+ isButtonUsed('heading') ||
+ isButtonUsed('hr')
+ ) {
+ var spacer2 = document.createElement("li");
+ spacer2.className = "wmd-spacer";
+ spacer2.id = "wmd-spacer2";
+ buttonRow.appendChild(spacer2);
+ }
+
+ if (isButtonUsed('ol')) {
+ var olistButton = document.createElement("li");
+ olistButton.className = "wmd-button";
+ olistButton.id = "wmd-olist-button";
+ olistButton.title = toolbar_numbered_label;
+ olistButton.XShift = "-140px";
+ olistButton.textOp = function(chunk, postProcessing){
+ command.doList(chunk, postProcessing, true);
+ };
+ setupButton(olistButton, true);
+ buttonRow.appendChild(olistButton);
+ }
+
+ if (isButtonUsed('ul')) {
+ var ulistButton = document.createElement("li");
+ ulistButton.className = "wmd-button";
+ ulistButton.id = "wmd-ulist-button";
+ ulistButton.title = toolbar_bulleted_label;
+ ulistButton.XShift = "-160px";
+ ulistButton.textOp = function(chunk, postProcessing){
+ command.doList(chunk, postProcessing, false);
+ };
+ setupButton(ulistButton, true);
+ buttonRow.appendChild(ulistButton);
+ }
+
+ if (isButtonUsed('heading')) {
+ var headingButton = document.createElement("li");
+ headingButton.className = "wmd-button";
+ headingButton.id = "wmd-heading-button";
+ headingButton.title = toolbar_heading_label;
+ headingButton.XShift = "-180px";
+ headingButton.textOp = command.doHeading;
+ setupButton(headingButton, true);
+ buttonRow.appendChild(headingButton);
+ }
+
+ if (isButtonUsed('hr')) {
+ var hrButton = document.createElement("li");
+ hrButton.className = "wmd-button";
+ hrButton.id = "wmd-hr-button";
+ hrButton.title = toolbar_horizontal_label;
+ hrButton.XShift = "-200px";
+ hrButton.textOp = command.doHorizontalRule;
+ setupButton(hrButton, true);
+ buttonRow.appendChild(hrButton);
+ }
+
+ if (isButtonUsed('undo')){
+ var spacer3 = document.createElement("li");
+ spacer3.className = "wmd-spacer";
+ spacer3.id = "wmd-spacer3";
+ buttonRow.appendChild(spacer3);
+
+ var undoButton = document.createElement("li");
+ undoButton.className = "wmd-button";
+ undoButton.id = "wmd-undo-button";
+ undoButton.title = toolbar_undo_label;
+ undoButton.XShift = "-220px";
+ undoButton.execute = function(manager){
+ manager.undo();
+ };
+ setupButton(undoButton, true);
+ buttonRow.appendChild(undoButton);
+
+ var redoButton = document.createElement("li");
+ redoButton.className = "wmd-button";
+ redoButton.id = "wmd-redo-button";
+ redoButton.title = toolbar_redo_label;
+ if (/win/.test(nav.platform.toLowerCase())) {
+ redoButton.title = toolbar_redo_label;
+ }
+ else {
+ // mac and other non-Windows platforms
+ redoButton.title = gettext('redo') + " - Ctrl+Shift+Z";
+ }
+ redoButton.XShift = "-240px";
+ redoButton.execute = function(manager){
+ manager.redo();
+ };
+ setupButton(redoButton, true);
+ buttonRow.appendChild(redoButton);
+ setUndoRedoButtonStates();
+ }
+ /*
+ var helpButton = document.createElement("li");
+ helpButton.className = "wmd-button";
+ helpButton.id = "wmd-help-button";
+ helpButton.XShift = "-240px";
+ helpButton.isHelp = true;
+
+ var helpAnchor = document.createElement("a");
+ helpAnchor.href = helpLink;
+ helpAnchor.target = helpTarget
+ helpAnchor.title = helpHoverTitle;
+ helpButton.appendChild(helpAnchor);
+
+ setupButton(helpButton, true);
+ buttonRow.appendChild(helpButton);
+ */
+ };
+
+ var setupEditor = function(){
+
+ if (/\?noundo/.test(doc.location.href)) {
+ wmd.nativeUndo = true;
+ }
+
+ if (!wmd.nativeUndo && isButtonUsed('undo')) {
+ undoMgr = new wmd.undoManager(function(){
+ previewRefreshCallback();
+ setUndoRedoButtonStates();
+ });
+ }
+
+ makeSpritedButtonRow();
+
+
+ var keyEvent = "keydown";
+ if (global.isOpera) {
+ keyEvent = "keypress";
+ }
+
+ util.addEvent(inputBox, keyEvent, function(key){
+
+ // Check to see if we have a button key and, if so execute the callback.
+ if (key.ctrlKey || key.metaKey) {
+
+ var keyCode = key.charCode || key.keyCode;
+ var keyCodeStr = String.fromCharCode(keyCode).toLowerCase();
+
+ // Bugfix for messed up DEL and .
+ if (keyCode === 46) {
+ keyCodeStr = "";
+ }
+ if (keyCode === 190) {
+ keyCodeStr = ".";
+ }
+
+ switch(keyCodeStr) {
+ case "b":
+ doClick(document.getElementById("wmd-bold-button"));
+ break;
+ case "i":
+ doClick(document.getElementById("wmd-italic-button"));
+ break;
+ case "l":
+ doClick(document.getElementById("wmd-link-button"));
+ break;
+ case ".":
+ doClick(document.getElementById("wmd-quote-button"));
+ break;
+ case "k":
+ doClick(document.getElementById("wmd-code-button"));
+ break;
+ case "g":
+ doClick(document.getElementById("wmd-image-button"));
+ break;
+ case "o":
+ doClick(document.getElementById("wmd-olist-button"));
+ break;
+ case "u":
+ doClick(document.getElementById("wmd-ulist-button"));
+ break;
+ case "h":
+ doClick(document.getElementById("wmd-heading-button"));
+ break;
+ case "r":
+ doClick(document.getElementById("wmd-hr-button"));
+ break;
+ case "y":
+ doClick(document.getElementById("wmd-redo-button"));
+ break;
+ case "z":
+ if(key.shiftKey) {
+ doClick(document.getElementById("wmd-redo-button"));
+ }
+ else {
+ doClick(document.getElementById("wmd-undo-button"));
+ }
+ break;
+ default:
+ return;
+ }
+
+
+ if (key.preventDefault) {
+ key.preventDefault();
+ }
+
+ if (top.event) {
+ top.event.returnValue = false;
+ }
+ }
+ });
+
+ // Auto-indent on shift-enter
+ util.addEvent(inputBox, "keyup", function(key){
+ if (key.shiftKey && !key.ctrlKey && !key.metaKey) {
+ var keyCode = key.charCode || key.keyCode;
+ // Character 13 is Enter
+ if (keyCode === 13) {
+ fakeButton = {};
+ fakeButton.textOp = command.doAutoindent;
+ doClick(fakeButton);
+ }
+ }
+ });
+
+ if (inputBox.form) {
+ var submitCallback = inputBox.form.onsubmit;
+ inputBox.form.onsubmit = function(){
+ convertToHtml();
+ if (submitCallback) {
+ return submitCallback.apply(this, arguments);
+ }
+ };
+ }
+ };
+
+ // Convert the contents of the input textarea to HTML in the output/preview panels.
+ var convertToHtml = function(){
+
+ if (wmd.showdown) {
+ var markdownConverter = new wmd.showdown.converter();
+ }
+ var text = inputBox.value;
+
+ var callback = function(){
+ inputBox.value = text;
+ //value is assigned here
+ };
+
+ if (!/markdown/.test(wmd.wmd_env.output.toLowerCase())) {
+ if (markdownConverter) {
+ inputBox.value = markdownConverter.makeHtml(text);
+ //value is assigned here
+ top.setTimeout(callback, 0);
+ }
+ }
+ return true;
+ };
+
+
+ this.undo = function(){
+ if (undoMgr) {
+ undoMgr.undo();
+ }
+ };
+
+ this.redo = function(){
+ if (undoMgr) {
+ undoMgr.redo();
+ }
+ };
+
+ // This is pretty useless. The setupEditor function contents
+ // should just be copied here.
+ var init = function(){
+ setupEditor();
+ };
+
+ this.destroy = function(){
+ if (undoMgr) {
+ undoMgr.destroy();
+ }
+ if (div.parentNode) {
+ div.parentNode.removeChild(div);
+ }
+ if (inputBox) {
+ inputBox.style.marginTop = "";
+ }
+ top.clearInterval(creationHandle);
+ };
+
+ init();
+ };
+
+ // The input textarea state/contents.
+ // This is used to implement undo/redo by the undo manager.
+ wmd.TextareaState = function(){
+
+ // Aliases
+ var stateObj = this;
+ var inputArea = wmd.panels.input;
+
+ this.init = function() {
+
+ if (!util.isVisible(inputArea)) {
+ return;
+ }
+
+ this.setInputAreaSelectionStartEnd();
+ this.scrollTop = inputArea.scrollTop;
+ if (!this.text && inputArea.selectionStart || inputArea.selectionStart === 0) {
+ this.text = inputArea.value;
+ }
+
+ };
+
+ // Sets the selected text in the input box after we've performed an
+ // operation.
+ this.setInputAreaSelection = function(){
+
+ if (!util.isVisible(inputArea)) {
+ return;
+ }
+
+ if (inputArea.selectionStart !== undefined && !global.isOpera) {
+
+ inputArea.focus();
+ inputArea.selectionStart = stateObj.start;
+ inputArea.selectionEnd = stateObj.end;
+ inputArea.scrollTop = stateObj.scrollTop;
+ }
+ else if (doc.selection) {
+
+ if (doc.activeElement && doc.activeElement !== inputArea) {
+ return;
+ }
+
+ inputArea.focus();
+ var range = inputArea.createTextRange();
+ range.moveStart("character", -inputArea.value.length);
+ range.moveEnd("character", -inputArea.value.length);
+ range.moveEnd("character", stateObj.end);
+ range.moveStart("character", stateObj.start);
+ range.select();
+ }
+ };
+
+ this.setInputAreaSelectionStartEnd = function(){
+
+ if (inputArea.selectionStart || inputArea.selectionStart === 0) {
+
+ stateObj.start = inputArea.selectionStart;
+ stateObj.end = inputArea.selectionEnd;
+ }
+ else if (doc.selection) {
+
+ stateObj.text = util.fixEolChars(inputArea.value);
+
+ // IE loses the selection in the textarea when buttons are
+ // clicked. On IE we cache the selection and set a flag
+ // which we check for here.
+ var range;
+ if(wmd.ieRetardedClick && wmd.ieCachedRange) {
+ range = wmd.ieCachedRange;
+ wmd.ieRetardedClick = false;
+ }
+ else {
+ range = doc.selection.createRange();
+ }
+
+ var fixedRange = util.fixEolChars(range.text);
+ var marker = "\x07";
+ var markedRange = marker + fixedRange + marker;
+ range.text = markedRange;
+ var inputText = util.fixEolChars(inputArea.value);
+
+ range.moveStart("character", -markedRange.length);
+ range.text = fixedRange;
+
+ stateObj.start = inputText.indexOf(marker);
+ stateObj.end = inputText.lastIndexOf(marker) - marker.length;
+
+ var len = stateObj.text.length - util.fixEolChars(inputArea.value).length;
+
+ if (len) {
+ range.moveStart("character", -fixedRange.length);
+ while (len--) {
+ fixedRange += "\n";
+ stateObj.end += 1;
+ }
+ range.text = fixedRange;
+ }
+
+ this.setInputAreaSelection();
+ }
+ };
+
+ // Restore this state into the input area.
+ this.restore = function(){
+
+ if (stateObj.text !== undefined && stateObj.text != inputArea.value) {
+ inputArea.value = stateObj.text;
+ //value is assigned here
+ }
+ this.setInputAreaSelection();
+ inputArea.scrollTop = stateObj.scrollTop;
+ };
+
+ // Gets a collection of HTML chunks from the inptut textarea.
+ this.getChunks = function(){
+
+ var chunk = new wmd.Chunks();
+
+ chunk.before = util.fixEolChars(stateObj.text.substring(0, stateObj.start));
+ chunk.startTag = "";
+ chunk.selection = util.fixEolChars(stateObj.text.substring(stateObj.start, stateObj.end));
+ chunk.endTag = "";
+ chunk.after = util.fixEolChars(stateObj.text.substring(stateObj.end));
+ chunk.scrollTop = stateObj.scrollTop;
+
+ return chunk;
+ };
+
+ // Sets the TextareaState properties given a chunk of markdown.
+ this.setChunks = function(chunk){
+
+ chunk.before = chunk.before + chunk.startTag;
+ chunk.after = chunk.endTag + chunk.after;
+
+ if (global.isOpera) {
+ chunk.before = chunk.before.replace(/\n/g, "\r\n");
+ chunk.selection = chunk.selection.replace(/\n/g, "\r\n");
+ chunk.after = chunk.after.replace(/\n/g, "\r\n");
+ }
+
+ this.start = chunk.before.length;
+ this.end = chunk.before.length + chunk.selection.length;
+ this.text = chunk.before + chunk.selection + chunk.after;
+ this.scrollTop = chunk.scrollTop;
+ };
+
+ this.init();
+ };
+
+ // before: contains all the text in the input box BEFORE the selection.
+ // after: contains all the text in the input box AFTER the selection.
+ wmd.Chunks = function(){
+ };
+
+ // startRegex: a regular expression to find the start tag
+ // endRegex: a regular expresssion to find the end tag
+ wmd.Chunks.prototype.findTags = function(startRegex, endRegex){
+
+ var chunkObj = this;
+ var regex;
+
+ if (startRegex) {
+
+ regex = util.extendRegExp(startRegex, "", "$");
+
+ this.before = this.before.replace(regex,
+ function(match){
+ chunkObj.startTag = chunkObj.startTag + match;
+ return "";
+ });
+
+ regex = util.extendRegExp(startRegex, "^", "");
+
+ this.selection = this.selection.replace(regex,
+ function(match){
+ chunkObj.startTag = chunkObj.startTag + match;
+ return "";
+ });
+ }
+
+ if (endRegex) {
+
+ regex = util.extendRegExp(endRegex, "", "$");
+
+ this.selection = this.selection.replace(regex,
+ function(match){
+ chunkObj.endTag = match + chunkObj.endTag;
+ return "";
+ });
+
+ regex = util.extendRegExp(endRegex, "^", "");
+
+ this.after = this.after.replace(regex,
+ function(match){
+ chunkObj.endTag = match + chunkObj.endTag;
+ return "";
+ });
+ }
+ };
+
+ // If remove is false, the whitespace is transferred
+ // to the before/after regions.
+ //
+ // If remove is true, the whitespace disappears.
+ wmd.Chunks.prototype.trimWhitespace = function(remove){
+
+ this.selection = this.selection.replace(/^(\s*)/, "");
+
+ if (!remove) {
+ this.before += re.$1;
+ }
+
+ this.selection = this.selection.replace(/(\s*)$/, "");
+
+ if (!remove) {
+ this.after = re.$1 + this.after;
+ }
+ };
+
+
+ wmd.Chunks.prototype.skipLines = function(nLinesBefore, nLinesAfter, findExtraNewlines){
+
+ if (nLinesBefore === undefined) {
+ nLinesBefore = 1;
+ }
+
+ if (nLinesAfter === undefined) {
+ nLinesAfter = 1;
+ }
+
+ nLinesBefore++;
+ nLinesAfter++;
+
+ var regexText;
+ var replacementText;
+
+ if (global.isChrome) {//Chrome bug workaround
+ 'X'.match(/()./);
+ }
+
+ this.selection = this.selection.replace(/(^\n*)/, "");
+ this.startTag = this.startTag + re.$1;
+ this.selection = this.selection.replace(/(\n*$)/, "");
+ this.endTag = this.endTag + re.$1;
+ this.startTag = this.startTag.replace(/(^\n*)/, "");
+ this.before = this.before + re.$1;
+ this.endTag = this.endTag.replace(/(\n*$)/, "");
+ this.after = this.after + re.$1;
+
+ if (this.before) {
+
+ regexText = replacementText = "";
+
+ while (nLinesBefore--) {
+ regexText += "\\n?";
+ replacementText += "\n";
+ }
+
+ if (findExtraNewlines) {
+ regexText = "\\n*";
+ }
+ this.before = this.before.replace(new re(regexText + "$", ""), replacementText);
+ }
+
+ if (this.after) {
+
+ regexText = replacementText = "";
+
+ while (nLinesAfter--) {
+ regexText += "\\n?";
+ replacementText += "\n";
+ }
+ if (findExtraNewlines) {
+ regexText = "\\n*";
+ }
+
+ this.after = this.after.replace(new re(regexText, ""), replacementText);
+ }
+ };
+
+ // The markdown symbols - 4 spaces = code, > = blockquote, etc.
+ command.prefixes = "(?:\\s{4,}|\\s*>|\\s*-\\s+|\\s*\\d+\\.|=|\\+|-|_|\\*|#|\\s*\\[[^\n]]+\\]:)";
+
+ // Remove markdown symbols from the chunk selection.
+ command.unwrap = function(chunk){
+ var txt = new re("([^\\n])\\n(?!(\\n|" + command.prefixes + "))", "g");
+ chunk.selection = chunk.selection.replace(txt, "$1 $2");
+ };
+
+ command.wrap = function(chunk, len){
+ command.unwrap(chunk);
+ var regex = new re("(.{1," + len + "})( +|$\\n?)", "gm");
+
+ chunk.selection = chunk.selection.replace(regex, function(line, marked){
+ if (new re("^" + command.prefixes, "").test(line)) {
+ return line;
+ }
+ return marked + "\n";
+ });
+
+ chunk.selection = chunk.selection.replace(/\s+$/, "");
+ };
+
+ command.doBold = function(chunk, postProcessing){
+ return command.doBorI(chunk, postProcessing, 2, "strong text");
+ };
+
+ command.doItalic = function(chunk, postProcessing){
+ return command.doBorI(chunk, postProcessing, 1, "emphasized text");
+ };
+
+ // chunk: The selected region that will be enclosed with */**
+ // nStars: 1 for italics, 2 for bold
+ // insertText: If you just click the button without highlighting text, this gets inserted
+ command.doBorI = function(chunk, postProcessing, nStars, insertText){
+
+ // Get rid of whitespace and fixup newlines.
+ chunk.trimWhitespace();
+ chunk.selection = chunk.selection.replace(/\n{2,}/g, "\n");
+
+ // Look for stars before and after. Is the chunk already marked up?
+ chunk.before.search(/(\**$)/);
+ var starsBefore = re.$1;
+
+ chunk.after.search(/(^\**)/);
+ var starsAfter = re.$1;
+
+ var prevStars = Math.min(starsBefore.length, starsAfter.length);
+
+ // Remove stars if we have to since the button acts as a toggle.
+ if ((prevStars >= nStars) && (prevStars != 2 || nStars != 1)) {
+ chunk.before = chunk.before.replace(re("[*]{" + nStars + "}$", ""), "");
+ chunk.after = chunk.after.replace(re("^[*]{" + nStars + "}", ""), "");
+ }
+ else if (!chunk.selection && starsAfter) {
+ // It's not really clear why this code is necessary. It just moves
+ // some arbitrary stuff around.
+ chunk.after = chunk.after.replace(/^([*_]*)/, "");
+ chunk.before = chunk.before.replace(/(\s?)$/, "");
+ var whitespace = re.$1;
+ chunk.before = chunk.before + starsAfter + whitespace;
+ }
+ else {
+
+ // In most cases, if you don't have any selected text and click the button
+ // you'll get a selected, marked up region with the default text inserted.
+ if (!chunk.selection && !starsAfter) {
+ chunk.selection = insertText;
+ }
+
+ // Add the true markup.
+ var markup = nStars <= 1 ? "*" : "**"; // shouldn't the test be = ?
+ chunk.before = chunk.before + markup;
+ chunk.after = markup + chunk.after;
+ }
+
+ return;
+ };
+
+ command.stripLinkDefs = function(text, defsToAdd){
+
+ text = text.replace(/^[ ]{0,3}\[(\d+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|$)/gm,
+ function(totalMatch, id, link, newlines, title){
+ defsToAdd[id] = totalMatch.replace(/\s*$/, "");
+ if (newlines) {
+ // Strip the title and return that separately.
+ defsToAdd[id] = totalMatch.replace(/["(](.+?)[")]$/, "");
+ return newlines + title;
+ }
+ return "";
+ });
+
+ return text;
+ };
+
+ command.addLinkDef = function(chunk, linkDef){
+
+ var refNumber = 0; // The current reference number
+ var defsToAdd = {}; //
+ // Start with a clean slate by removing all previous link definitions.
+ chunk.before = command.stripLinkDefs(chunk.before, defsToAdd);
+ chunk.selection = command.stripLinkDefs(chunk.selection, defsToAdd);
+ chunk.after = command.stripLinkDefs(chunk.after, defsToAdd);
+
+ var defs = "";
+ var regex = /(\[(?:\[[^\]]*\]|[^\[\]])*\][ ]?(?:\n[ ]*)?\[)(\d+)(\])/g;
+
+ var addDefNumber = function(def){
+ refNumber++;
+ def = def.replace(/^[ ]{0,3}\[(\d+)\]:/, " [" + refNumber + "]:");
+ defs += "\n" + def;
+ };
+
+ var getLink = function(wholeMatch, link, id, end){
+
+ if (defsToAdd[id]) {
+ addDefNumber(defsToAdd[id]);
+ return link + refNumber + end;
+
+ }
+ return wholeMatch;
+ };
+
+ chunk.before = chunk.before.replace(regex, getLink);
+
+ if (linkDef) {
+ addDefNumber(linkDef);
+ }
+ else {
+ chunk.selection = chunk.selection.replace(regex, getLink);
+ }
+
+ var refOut = refNumber;
+
+ chunk.after = chunk.after.replace(regex, getLink);
+
+ if (chunk.after) {
+ chunk.after = chunk.after.replace(/\n*$/, "");
+ }
+ if (!chunk.after) {
+ chunk.selection = chunk.selection.replace(/\n*$/, "");
+ }
+
+ chunk.after += "\n\n" + defs;
+
+ return refOut;
+ };
+
+ command.doLinkOrImage = function(chunk, postProcessing, itemType){
+
+ chunk.trimWhitespace();
+ chunk.findTags(/\s*!?\[/, /\][ ]?(?:\n[ ]*)?(\[.*?\])?/);
+
+ if (chunk.endTag.length > 1) {
+
+ chunk.startTag = chunk.startTag.replace(/!?\[/, "");
+ chunk.endTag = "";
+ command.addLinkDef(chunk, null);
+
+ }
+ else {
+
+ if (/\n\n/.test(chunk.selection)) {
+ command.addLinkDef(chunk, null);
+ return;
+ }
+
+ // The function to be executed when you enter a link and press OK or Cancel.
+ // Marks up the link and adds the ref.
+ var makeLinkMarkdown = function(link){
+
+ if (link !== null) {
+
+ chunk.startTag = chunk.endTag = "";
+ //var linkDef = " [999]: " + link;
+
+ //var num = command.addLinkDef(chunk, linkDef);
+ chunk.startTag = (itemType == 'image') ? "![" : "[";
+ chunk.endTag = "](" + link + ")";
+
+ if (!chunk.selection) {
+ if (itemType == 'image') {
+ chunk.selection = gettext("image description");
+ }
+ else if (itemType == 'file'){
+ chunk.selection = localUploadFileName || gettext("file name");
+ localUploadFileName = null;
+ }
+ else {
+ chunk.selection = gettext("link text");
+ }
+ }
+ }
+ else {
+ if (itemType == 'image' || itemType == 'file'){
+ return;
+ }
+ }
+ postProcessing();
+ };
+
+ if (itemType == 'image') {
+ // add forth param to identify image window
+ util.prompt(imageDialogText, imageDefaultText, makeLinkMarkdown, 'image');
+ }
+ else if (itemType == 'file'){
+ util.prompt(fileDialogText, '', makeLinkMarkdown, 'file');
+ }
+ else {
+ util.prompt(linkDialogText, linkDefaultText, makeLinkMarkdown, 'link');
+ }
+ return true;
+ }
+};
+
+ util.makeAPI = function(){
+ wmd.wmd = {};
+ wmd.wmd.editor = wmd.editor;
+ wmd.wmd.previewManager = wmd.previewManager;
+ };
+
+ util.startEditor = function(start_now, buttons){
+
+ if (wmd.wmd_env.autostart === false) {
+ util.makeAPI();
+ return;
+ }
+
+ if (buttons){
+ wmd.wmd_env.buttons = buttons;
+ }
+
+ var edit; // The editor (buttons + input + outputs) - the main object.
+ var previewMgr; // The preview manager.
+
+ // Fired after the page has fully loaded.
+ var loadListener = function(){
+
+ wmd.panels = new wmd.PanelCollection();
+
+ previewMgr = new wmd.previewManager();
+ var previewRefreshCallback = previewMgr.refresh;
+
+ edit = new wmd.editor(previewRefreshCallback);
+
+ previewMgr.refresh(true);
+
+ };
+
+ if (start_now){
+ loadListener();
+ } else {
+ util.addEvent(top, "load", loadListener);
+ }
+ };
+
+ wmd.previewManager = function(){
+
+ var managerObj = this;
+ var converter;
+ var poller;
+ var timeout;
+ var elapsedTime;
+ var oldInputText;
+ var htmlOut;
+ var maxDelay = 3000;
+ var startType = "delayed"; // The other legal value is "manual"
+
+ // Adds event listeners to elements and creates the input poller.
+ var setupEvents = function(inputElem, listener){
+
+ util.addEvent(inputElem, "input", listener);
+ inputElem.onpaste = listener;
+ inputElem.ondrop = listener;
+
+ util.addEvent(inputElem, "keypress", listener);
+ util.addEvent(inputElem, "keydown", listener);
+ // previewPollInterval is set at the top of this file.
+ poller = new wmd.inputPoller(listener, previewPollInterval);
+ };
+
+ var getDocScrollTop = function(){
+
+ var result = 0;
+
+ if (top.innerHeight) {
+ result = top.pageYOffset;
+ }
+ else
+ if (doc.documentElement && doc.documentElement.scrollTop) {
+ result = doc.documentElement.scrollTop;
+ }
+ else
+ if (doc.body) {
+ result = doc.body.scrollTop;
+ }
+
+ return result;
+ };
+
+ var makePreviewHtml = function(){
+
+ // If there are no registered preview and output panels
+ // there is nothing to do.
+ if (!wmd.panels.preview && !wmd.panels.output) {
+ return;
+ }
+
+ var text = wmd.panels.input.value;
+ if (text && text == oldInputText) {
+ return; // Input text hasn't changed.
+ }
+ else {
+ oldInputText = text;
+ }
+
+ var prevTime = new Date().getTime();
+
+ if (!converter && wmd.showdown) {
+ converter = new wmd.showdown.converter();
+ }
+
+ if (converter) {
+ text = converter.makeHtml(text);
+ }
+
+ // Calculate the processing time of the HTML creation.
+ // It's used as the delay time in the event listener.
+ var currTime = new Date().getTime();
+ elapsedTime = currTime - prevTime;
+
+ pushPreviewHtml(text);
+ htmlOut = text;
+ };
+
+ // setTimeout is already used. Used as an event listener.
+ var applyTimeout = function(){
+
+ if (timeout) {
+ top.clearTimeout(timeout);
+ timeout = undefined;
+ }
+
+ if (startType !== "manual") {
+
+ var delay = 0;
+
+ if (startType === "delayed") {
+ delay = elapsedTime;
+ }
+
+ if (delay > maxDelay) {
+ delay = maxDelay;
+ }
+ timeout = top.setTimeout(makePreviewHtml, delay);
+ }
+ };
+
+ var getScaleFactor = function(panel){
+ if (panel.scrollHeight <= panel.clientHeight) {
+ return 1;
+ }
+ return panel.scrollTop / (panel.scrollHeight - panel.clientHeight);
+ };
+
+ var setPanelScrollTops = function(){
+
+ if (wmd.panels.preview) {
+ wmd.panels.preview.scrollTop = (wmd.panels.preview.scrollHeight - wmd.panels.preview.clientHeight) * getScaleFactor(wmd.panels.preview);
+ }
+
+ if (wmd.panels.output) {
+ wmd.panels.output.scrollTop = (wmd.panels.output.scrollHeight - wmd.panels.output.clientHeight) * getScaleFactor(wmd.panels.output);
+ }
+ };
+
+ this.refresh = function(requiresRefresh){
+
+ if (requiresRefresh) {
+ oldInputText = "";
+ makePreviewHtml();
+ }
+ else {
+ applyTimeout();
+ }
+ };
+
+ this.processingTime = function(){
+ return elapsedTime;
+ };
+
+ // The output HTML
+ this.output = function(){
+ return htmlOut;
+ };
+
+ // The mode can be "manual" or "delayed"
+ this.setUpdateMode = function(mode){
+ startType = mode;
+ managerObj.refresh();
+ };
+
+ var isFirstTimeFilled = true;
+
+ var pushPreviewHtml = function(text){
+
+ var emptyTop = position.getTop(wmd.panels.input) - getDocScrollTop();
+
+ // Send the encoded HTML to the output textarea/div.
+ if (wmd.panels.output) {
+ // The value property is only defined if the output is a textarea.
+ if (wmd.panels.output.value !== undefined) {
+ wmd.panels.output.value = text;
+ //value is assigned here
+ wmd.panels.output.readOnly = true;
+ }
+ // Otherwise we are just replacing the text in a div.
+ // Send the HTML wrapped in <pre><code>
+ else {
+ var newText = text.replace(/&/g, "&amp;");
+ newText = newText.replace(/</g, "&lt;");
+ wmd.panels.output.innerHTML = "<pre><code>" + newText + "</code></pre>";
+ }
+ }
+
+ if (wmd.panels.preview) {
+ wmd.panels.preview.innerHTML = text;
+ }
+
+ setPanelScrollTops();
+
+ if (isFirstTimeFilled) {
+ isFirstTimeFilled = false;
+ return;
+ }
+
+ var fullTop = position.getTop(wmd.panels.input) - getDocScrollTop();
+
+ if (global.isIE) {
+ top.setTimeout(function(){
+ top.scrollBy(0, fullTop - emptyTop);
+ }, 0);
+ }
+ else {
+ top.scrollBy(0, fullTop - emptyTop);
+ }
+ };
+
+ var init = function(){
+
+ setupEvents(wmd.panels.input, applyTimeout);
+ makePreviewHtml();
+
+ if (wmd.panels.preview) {
+ wmd.panels.preview.scrollTop = 0;
+ }
+ if (wmd.panels.output) {
+ wmd.panels.output.scrollTop = 0;
+ }
+ };
+
+ this.destroy = function(){
+ if (poller) {
+ poller.destroy();
+ }
+ };
+
+ init();
+ };
+
+ // When making a list, hitting shift-enter will put your cursor on the next line
+ // at the current indent level.
+ command.doAutoindent = function(chunk, postProcessing){
+
+ chunk.before = chunk.before.replace(/(\n|^)[ ]{0,3}([*+-]|\d+[.])[ \t]*\n$/, "\n\n");
+ chunk.before = chunk.before.replace(/(\n|^)[ ]{0,3}>[ \t]*\n$/, "\n\n");
+ chunk.before = chunk.before.replace(/(\n|^)[ \t]+\n$/, "\n\n");
+
+ if(/(\n|^)[ ]{0,3}([*+-]|\d+[.])[ \t]+.*\n$/.test(chunk.before)){
+ if(command.doList){
+ command.doList(chunk);
+ }
+ }
+ if(/(\n|^)[ ]{0,3}>[ \t]+.*\n$/.test(chunk.before)){
+ if(command.doBlockquote){
+ command.doBlockquote(chunk);
+ }
+ }
+ if(/(\n|^)(\t|[ ]{4,}).*\n$/.test(chunk.before)){
+ if(command.doCode){
+ command.doCode(chunk);
+ }
+ }
+ };
+
+ command.doBlockquote = function(chunk, postProcessing){
+
+ chunk.selection = chunk.selection.replace(/^(\n*)([^\r]+?)(\n*)$/,
+ function(totalMatch, newlinesBefore, text, newlinesAfter){
+ chunk.before += newlinesBefore;
+ chunk.after = newlinesAfter + chunk.after;
+ return text;
+ });
+
+ chunk.before = chunk.before.replace(/(>[ \t]*)$/,
+ function(totalMatch, blankLine){
+ chunk.selection = blankLine + chunk.selection;
+ return "";
+ });
+
+ chunk.selection = chunk.selection.replace(/^(\s|>)+$/ ,"");
+ chunk.selection = chunk.selection || "Blockquote";
+
+ if(chunk.before){
+ chunk.before = chunk.before.replace(/\n?$/,"\n");
+ }
+ if(chunk.after){
+ chunk.after = chunk.after.replace(/^\n?/,"\n");
+ }
+
+ chunk.before = chunk.before.replace(/(((\n|^)(\n[ \t]*)*>(.+\n)*.*)+(\n[ \t]*)*$)/,
+ function(totalMatch){
+ chunk.startTag = totalMatch;
+ return "";
+ });
+
+ chunk.after = chunk.after.replace(/^(((\n|^)(\n[ \t]*)*>(.+\n)*.*)+(\n[ \t]*)*)/,
+ function(totalMatch){
+ chunk.endTag = totalMatch;
+ return "";
+ });
+
+ var replaceBlanksInTags = function(useBracket){
+
+ var replacement = useBracket ? "> " : "";
+
+ if(chunk.startTag){
+ chunk.startTag = chunk.startTag.replace(/\n((>|\s)*)\n$/,
+ function(totalMatch, markdown){
+ return "\n" + markdown.replace(/^[ ]{0,3}>?[ \t]*$/gm, replacement) + "\n";
+ });
+ }
+ if(chunk.endTag){
+ chunk.endTag = chunk.endTag.replace(/^\n((>|\s)*)\n/,
+ function(totalMatch, markdown){
+ return "\n" + markdown.replace(/^[ ]{0,3}>?[ \t]*$/gm, replacement) + "\n";
+ });
+ }
+ };
+
+ if(/^(?![ ]{0,3}>)/m.test(chunk.selection)){
+ command.wrap(chunk, wmd.wmd_env.lineLength - 2);
+ chunk.selection = chunk.selection.replace(/^/gm, "> ");
+ replaceBlanksInTags(true);
+ chunk.skipLines();
+ }
+ else{
+ chunk.selection = chunk.selection.replace(/^[ ]{0,3}> ?/gm, "");
+ command.unwrap(chunk);
+ replaceBlanksInTags(false);
+
+ if(!/^(\n|^)[ ]{0,3}>/.test(chunk.selection) && chunk.startTag){
+ chunk.startTag = chunk.startTag.replace(/\n{0,2}$/, "\n\n");
+ }
+
+ if(!/(\n|^)[ ]{0,3}>.*$/.test(chunk.selection) && chunk.endTag){
+ chunk.endTag=chunk.endTag.replace(/^\n{0,2}/, "\n\n");
+ }
+ }
+
+ if(!/\n/.test(chunk.selection)){
+ chunk.selection = chunk.selection.replace(/^(> *)/,
+ function(wholeMatch, blanks){
+ chunk.startTag += blanks;
+ return "";
+ });
+ }
+ };
+
+ command.doCode = function(chunk, postProcessing){
+
+ var hasTextBefore = /\S[ ]*$/.test(chunk.before);
+ var hasTextAfter = /^[ ]*\S/.test(chunk.after);
+
+ // Use 'four space' markdown if the selection is on its own
+ // line or is multiline.
+ if((!hasTextAfter && !hasTextBefore) || /\n/.test(chunk.selection)){
+
+ chunk.before = chunk.before.replace(/[ ]{4}$/,
+ function(totalMatch){
+ chunk.selection = totalMatch + chunk.selection;
+ return "";
+ });
+
+ var nLinesBack = 1;
+ var nLinesForward = 1;
+
+ if(/\n(\t|[ ]{4,}).*\n$/.test(chunk.before)){
+ nLinesBack = 0;
+ }
+ if(/^\n(\t|[ ]{4,})/.test(chunk.after)){
+ nLinesForward = 0;
+ }
+
+ chunk.skipLines(nLinesBack, nLinesForward);
+
+ if(!chunk.selection){
+ chunk.startTag = " ";
+ chunk.selection = "enter code here";
+ }
+ else {
+ if(/^[ ]{0,3}\S/m.test(chunk.selection)){
+ chunk.selection = chunk.selection.replace(/^/gm, " ");
+ }
+ else{
+ chunk.selection = chunk.selection.replace(/^[ ]{4}/gm, "");
+ }
+ }
+ }
+ else{
+ // Use backticks (`) to delimit the code block.
+
+ chunk.trimWhitespace();
+ chunk.findTags(/`/, /`/);
+
+ if(!chunk.startTag && !chunk.endTag){
+ chunk.startTag = chunk.endTag="`";
+ if(!chunk.selection){
+ chunk.selection = "enter code here";
+ }
+ }
+ else if(chunk.endTag && !chunk.startTag){
+ chunk.before += chunk.endTag;
+ chunk.endTag = "";
+ }
+ else{
+ chunk.startTag = chunk.endTag="";
+ }
+ }
+ };
+
+ command.doList = function(chunk, postProcessing, isNumberedList){
+
+ // These are identical except at the very beginning and end.
+ // Should probably use the regex extension function to make this clearer.
+ var previousItemsRegex = /(\n|^)(([ ]{0,3}([*+-]|\d+[.])[ \t]+.*)(\n.+|\n{2,}([*+-].*|\d+[.])[ \t]+.*|\n{2,}[ \t]+\S.*)*)\n*$/;
+ var nextItemsRegex = /^\n*(([ ]{0,3}([*+-]|\d+[.])[ \t]+.*)(\n.+|\n{2,}([*+-].*|\d+[.])[ \t]+.*|\n{2,}[ \t]+\S.*)*)\n*/;
+
+ // The default bullet is a dash but others are possible.
+ // This has nothing to do with the particular HTML bullet,
+ // it's just a markdown bullet.
+ var bullet = "-";
+
+ // The number in a numbered list.
+ var num = 1;
+
+ // Get the item prefix - e.g. " 1. " for a numbered list, " - " for a bulleted list.
+ var getItemPrefix = function(){
+ var prefix;
+ if(isNumberedList){
+ prefix = " " + num + ". ";
+ num++;
+ }
+ else{
+ prefix = " " + bullet + " ";
+ }
+ return prefix;
+ };
+
+ // Fixes the prefixes of the other list items.
+ var getPrefixedItem = function(itemText){
+
+ // The numbering flag is unset when called by autoindent.
+ if(isNumberedList === undefined){
+ isNumberedList = /^\s*\d/.test(itemText);
+ }
+
+ // Renumber/bullet the list element.
+ itemText = itemText.replace(/^[ ]{0,3}([*+-]|\d+[.])\s/gm,
+ function( _ ){
+ return getItemPrefix();
+ });
+
+ return itemText;
+ };
+
+ chunk.findTags(/(\n|^)*[ ]{0,3}([*+-]|\d+[.])\s+/, null);
+
+ if(chunk.before && !/\n$/.test(chunk.before) && !/^\n/.test(chunk.startTag)){
+ chunk.before += chunk.startTag;
+ chunk.startTag = "";
+ }
+
+ if(chunk.startTag){
+
+ var hasDigits = /\d+[.]/.test(chunk.startTag);
+ chunk.startTag = "";
+ chunk.selection = chunk.selection.replace(/\n[ ]{4}/g, "\n");
+ command.unwrap(chunk);
+ chunk.skipLines();
+
+ if(hasDigits){
+ // Have to renumber the bullet points if this is a numbered list.
+ chunk.after = chunk.after.replace(nextItemsRegex, getPrefixedItem);
+ }
+ if(isNumberedList == hasDigits){
+ return;
+ }
+ }
+
+ var nLinesUp = 1;
+
+ chunk.before = chunk.before.replace(previousItemsRegex,
+ function(itemText){
+ if(/^\s*([*+-])/.test(itemText)){
+ bullet = re.$1;
+ }
+ nLinesUp = /[^\n]\n\n[^\n]/.test(itemText) ? 1 : 0;
+ return getPrefixedItem(itemText);
+ });
+
+ if(!chunk.selection){
+ chunk.selection = "List item";
+ }
+
+ var prefix = getItemPrefix();
+
+ var nLinesDown = 1;
+
+ chunk.after = chunk.after.replace(nextItemsRegex,
+ function(itemText){
+ nLinesDown = /[^\n]\n\n[^\n]/.test(itemText) ? 1 : 0;
+ return getPrefixedItem(itemText);
+ });
+
+ chunk.trimWhitespace(true);
+ chunk.skipLines(nLinesUp, nLinesDown, true);
+ chunk.startTag = prefix;
+ var spaces = prefix.replace(/./g, " ");
+ command.wrap(chunk, wmd.wmd_env.lineLength - spaces.length);
+ chunk.selection = chunk.selection.replace(/\n/g, "\n" + spaces);
+
+ };
+
+ command.doHeading = function(chunk, postProcessing){
+
+ // Remove leading/trailing whitespace and reduce internal spaces to single spaces.
+ chunk.selection = chunk.selection.replace(/\s+/g, " ");
+ chunk.selection = chunk.selection.replace(/(^\s+|\s+$)/g, "");
+
+ // If we clicked the button with no selected text, we just
+ // make a level 2 hash header around some default text.
+ if(!chunk.selection){
+ chunk.startTag = "## ";
+ chunk.selection = "Heading";
+ chunk.endTag = " ##";
+ return;
+ }
+
+ var headerLevel = 0; // The existing header level of the selected text.
+
+ // Remove any existing hash heading markdown and save the header level.
+ chunk.findTags(/#+[ ]*/, /[ ]*#+/);
+ if(/#+/.test(chunk.startTag)){
+ headerLevel = re.lastMatch.length;
+ }
+ chunk.startTag = chunk.endTag = "";
+
+ // Try to get the current header level by looking for - and = in the line
+ // below the selection.
+ chunk.findTags(null, /\s?(-+|=+)/);
+ if(/=+/.test(chunk.endTag)){
+ headerLevel = 1;
+ }
+ if(/-+/.test(chunk.endTag)){
+ headerLevel = 2;
+ }
+
+ // Skip to the next line so we can create the header markdown.
+ chunk.startTag = chunk.endTag = "";
+ chunk.skipLines(1, 1);
+
+ // We make a level 2 header if there is no current header.
+ // If there is a header level, we substract one from the header level.
+ // If it's already a level 1 header, it's removed.
+ var headerLevelToCreate = headerLevel == 0 ? 2 : headerLevel - 1;
+
+ if(headerLevelToCreate > 0){
+
+ // The button only creates level 1 and 2 underline headers.
+ // Why not have it iterate over hash header levels? Wouldn't that be easier and cleaner?
+ var headerChar = headerLevelToCreate >= 2 ? "-" : "=";
+ var len = chunk.selection.length;
+ if(len > wmd.wmd_env.lineLength){
+ len = wmd.wmd_env.lineLength;
+ }
+ chunk.endTag = "\n";
+ while(len--){
+ chunk.endTag += headerChar;
+ }
+ }
+ };
+
+ command.doHorizontalRule = function(chunk, postProcessing){
+ chunk.startTag = "----------\n";
+ chunk.selection = "";
+ chunk.skipLines(2, 1, true);
+ }
+};
+
+
+Attacklab.wmd_env = {};
+Attacklab.account_options = {};
+Attacklab.wmd_defaults = {version:1, output:"Markdown", lineLength:40, delayLoad:false};
+
+if(!Attacklab.wmd)
+{
+ Attacklab.wmd = function()
+ {
+ Attacklab.loadEnv = function()
+ {
+ var mergeEnv = function(env)
+ {
+ if(!env)
+ {
+ return;
+ }
+
+ for(var key in env)
+ {
+ Attacklab.wmd_env[key] = env[key];
+ }
+ };
+
+ mergeEnv(Attacklab.wmd_defaults);
+ mergeEnv(Attacklab.account_options);
+ mergeEnv(top["wmd_options"]);
+ Attacklab.full = true;
+
+ var defaultButtons = "bold italic link blockquote code image attachment ol ul heading hr";
+ Attacklab.wmd_env.buttons = Attacklab.wmd_env.buttons || defaultButtons;
+ };
+ Attacklab.loadEnv();
+
+ };
+
+ Attacklab.wmd();
+ Attacklab.wmdBase();
+ Attacklab.Util.startEditor();
+};
+
diff --git a/askbot/skins/common/media/style/auth.css b/askbot/media/style/auth.css
index 33702758..33702758 100644
--- a/askbot/skins/common/media/style/auth.css
+++ b/askbot/media/style/auth.css
diff --git a/askbot/skins/default/media/style/jquery.autocomplete.css b/askbot/media/style/jquery.autocomplete.css
index 09b08192..09b08192 100644
--- a/askbot/skins/default/media/style/jquery.autocomplete.css
+++ b/askbot/media/style/jquery.autocomplete.css
diff --git a/askbot/skins/default/media/style/lib_style.css b/askbot/media/style/lib_style.css
index a92af477..a92af477 100644
--- a/askbot/skins/default/media/style/lib_style.css
+++ b/askbot/media/style/lib_style.css
diff --git a/askbot/media/style/lib_style.less b/askbot/media/style/lib_style.less
new file mode 100644
index 00000000..05ab38f5
--- /dev/null
+++ b/askbot/media/style/lib_style.less
@@ -0,0 +1,101 @@
+/* General Predifined classes, read more in lesscss.org */
+
+/* Variables for Colors*/
+
+@header-color:#16160f;
+@link:#1b79bd;
+@question-link:#464646;
+@button-label:#4a757f;
+@section-title:#7ea9b3;
+@info-text:#707070;
+@info-text-dark:#525252;
+
+/* Variables for fonts*/
+
+@body-font:Arial; /* "Trebuchet MS", sans-serif;*/
+@sort-font:Georgia, serif;
+@main-font:'Open Sans Condensed', Arial, sans-serif;
+@secondary-font:Arial;
+
+/* Buttons */
+
+.button-style(@h:20px, @f:14px){
+ height:@h;
+ font-size:@f;
+ text-align:center;
+ text-decoration:none;
+ cursor:pointer;
+ color:@button-label;
+ font-family:@main-font;
+ .text-shadow(0px,1px,0px,#c6d9dd);
+ border-top:#eaf2f3 1px solid;
+ .linear-gradient(#d1e2e5,#a9c2c7);
+ .rounded-corners(4px);
+ .box-shadow(1px, 1px, 2px, #636363)
+}
+
+.button-style-hover{
+ .linear-gradient(#cde5e9,#94b3ba);
+ text-decoration:none;
+ .text-shadow(0px, 1px, 0px, #c6d9dd);
+}
+
+/* General styles for gradients */
+
+.linear-gradient(@start:#eee,@end:#fff,@stop:25%){
+ background-color: @start;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@start), color-stop(@stop, @start), to(@end));
+ background-image: -webkit-linear-gradient(@start, @start @stop, @end);
+ background-image: -moz-linear-gradient(top, @start, @start @stop, @end);
+ background-image: -ms-linear-gradient(@start, @start @stop, @end);
+ background-image: -o-linear-gradient(@start, @start @stop, @end);
+ background-image: linear-gradient(@start, @start @stop, @end);
+}
+
+/* Receive exactly positions for background Sprite */
+
+.sprites(@hor,@vert,@back:url(../images/sprites.png)){
+ background:@hor @vert @back no-repeat;
+}
+
+/* CSS3 Elements */
+
+.box-shadow (@hor: 0px, @vert: 0px, @blur: 5px, @shadow: #929292){
+ -webkit-box-shadow: @arguments ;
+ -moz-box-shadow: @arguments;
+ box-shadow: @arguments;
+}
+
+.text-shadow(@hor: 0px, @vert: 0px, @blur: 5px, @shadow: #929292){
+ text-shadow: @arguments;
+ -moz-text-shadow: @arguments;
+ -webkit-text-shadow: @arguments;
+}
+
+.rounded-corners(@radio: 5px){
+ border-radius: @radio;
+ -ms-border-radius: @radio;
+ -moz-border-radius: @radio;
+ -webkit-border-radius: @radio;
+ -khtml-border-radius: @radio;
+}
+
+.rounded-corners-top(@radio:5px){
+ border-top-right-radius:@radio;
+ border-top-left-radius:@radio;
+ -moz-border-radius-topright:@radio;
+ -moz-border-radius-topleft:@radio;
+ -webkit-border-top-left-radius:@radio;
+ -webkit-border-top-right-radius:@radio;
+}
+
+.rounded-corners-right(@radio:5px){
+ border-top-right-radius:@radio;
+ border-bottom-right-radius:@radio;
+ -moz-border-radius-topright:@radio;
+ -moz-border-radius-bottomright:@radio;
+ -webkit-border-bottom-right-radius:@radio;
+ -webkit-border-top-right-radius:@radio;
+}
+
diff --git a/askbot/skins/common/media/style/openid.css b/askbot/media/style/openid.css
index 0d201df2..0d201df2 100644
--- a/askbot/skins/common/media/style/openid.css
+++ b/askbot/media/style/openid.css
diff --git a/askbot/media/style/prettify.css b/askbot/media/style/prettify.css
new file mode 100644
index 00000000..fabfd3b8
--- /dev/null
+++ b/askbot/media/style/prettify.css
@@ -0,0 +1,27 @@
+/* Pretty printing styles. Used with prettify.js. */
+
+pre .str { color: #080; }
+pre .kwd { color: #008; }
+pre .com { color: #800; }
+pre .typ { color: #606; }
+pre .lit { color: #066; }
+pre .pun { color: #660; }
+pre .pln { color: #000; }
+pre .tag { color: #008; }
+pre .atn { color: #606; }
+pre .atv { color: #080; }
+pre .dec { color: #606; }
+pre.prettyprint { padding: 3px; border: 0px solid #888; }
+
+@media print {
+ pre .str { color: #060; }
+ pre .kwd { color: #006; font-weight: bold; }
+ pre .com { color: #600; font-style: italic; }
+ pre .typ { color: #404; font-weight: bold; }
+ pre .lit { color: #044; }
+ pre .pun { color: #440; }
+ pre .pln { color: #000; }
+ pre .tag { color: #006; font-weight: bold; }
+ pre .atn { color: #404; }
+ pre .atv { color: #060; }
+}
diff --git a/askbot/media/style/style.css b/askbot/media/style/style.css
new file mode 100644
index 00000000..3abbd362
--- /dev/null
+++ b/askbot/media/style/style.css
@@ -0,0 +1,4114 @@
+@import url(jquery.autocomplete.css);
+/* General Predifined classes, read more in lesscss.org */
+/* Variables for Colors*/
+/* Variables for fonts*/
+/* "Trebuchet MS", sans-serif;*/
+/* Buttons */
+.button-style-hover {
+ background-color: #cde5e9;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
+ background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ text-decoration: none;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+}
+/* General styles for gradients */
+/* Receive exactly positions for background Sprite */
+/* CSS3 Elements */
+/* Library of predifined less functions styles */
+/* ----- General HTML Styles----- */
+body {
+ background: #FFF;
+ font-size: 14px;
+ line-height: 150%;
+ margin: 0;
+ padding: 0;
+ color: #666;
+ font-family: Arial;
+}
+div {
+ margin: 0 auto;
+ padding: 0;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+ul,
+li,
+dl,
+dt,
+dd,
+form,
+img,
+p {
+ margin: 0;
+ padding: 0;
+ border: none;
+}
+label {
+ vertical-align: middle;
+}
+hr {
+ border: none;
+ border-top: 1px dashed #ccccce;
+}
+input,
+select {
+ vertical-align: middle;
+ font-family: Trebuchet MS, "segoe ui", Helvetica, Tahoma, Verdana, MingLiu, PMingLiu, Arial, sans-serif;
+ margin-left: 0px;
+}
+input[type="text"].prompt,
+input[type="password"].prompt,
+input.tipped-input.blank {
+ font-style: italic;
+ color: #707070;
+}
+textarea:focus,
+input:focus {
+ outline: none;
+}
+iframe {
+ border: none;
+}
+p {
+ font-size: 14px;
+ line-height: 140%;
+ margin-bottom: 6px;
+}
+a {
+ color: #1b79bd;
+ text-decoration: none;
+ cursor: pointer;
+}
+h2 {
+ font-size: 21px;
+ padding: 3px 0 3px 5px;
+}
+h3 {
+ font-size: 19px;
+ padding: 3px 0 3px 5px;
+}
+ul {
+ list-style: disc;
+ margin-left: 20px;
+ padding-left: 0px;
+ margin-bottom: 1em;
+}
+ol {
+ list-style: decimal;
+ margin-left: 30px;
+ margin-bottom: 1em;
+ padding-left: 0px;
+}
+td ul {
+ vertical-align: middle;
+}
+li input {
+ margin: 3px 3px 4px 3px;
+}
+pre {
+ font-family: Consolas, Monaco, Liberation Mono, Lucida Console, Monospace;
+ font-size: 100%;
+ margin-bottom: 10px;
+ /*overflow: auto;*/
+
+ background-color: #F5F5F5;
+ padding-left: 5px;
+ padding-top: 5px;
+ /*width: 671px;*/
+
+ padding-bottom: 20px ! ie7;
+}
+code {
+ font-family: Consolas, Monaco, Liberation Mono, Lucida Console, Monospace;
+ font-size: 100%;
+}
+blockquote {
+ margin-bottom: 10px;
+ margin-right: 15px;
+ padding: 10px 0px 1px 10px;
+ background-color: #F5F5F5;
+}
+/* http://pathfindersoftware.com/2007/09/developers-note-2/ */
+* html .clearfix,
+* html .paginator {
+ height: 1;
+ overflow: visible;
+}
++ html .clearfix,
++ html .paginator {
+ min-height: 1%;
+}
+.clearfix:after,
+.paginator:after {
+ clear: both;
+ content: ".";
+ display: block;
+ height: 0;
+ visibility: hidden;
+}
+.badges a {
+ color: #763333;
+ text-decoration: underline;
+}
+a:hover {
+ text-decoration: underline;
+}
+.badge-context-toggle.active {
+ cursor: pointer;
+ text-decoration: underline;
+}
+h1 {
+ font-size: 24px;
+ padding: 0px 0 5px 0px;
+}
+/* ----- Extra space above for messages ----- */
+body.user-messages {
+ margin-top: 2.4em;
+}
+/* ----- Custom positions ----- */
+.left {
+ float: left;
+}
+.right {
+ float: right;
+}
+.clean {
+ clear: both;
+}
+.center {
+ margin: 0 auto;
+ padding: 0;
+}
+/* ----- Notify message bar , check blocks/system_messages.html ----- */
+.notify {
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ width: 100%;
+ z-index: 100;
+ padding: 0;
+ text-align: center;
+ background-color: #f5dd69;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+}
+.notify .notification {
+ margin-top: 6px;
+ /*margin-bottom: 6px;*/
+
+ font-size: 16px;
+ color: #424242;
+}
+#closeNotify {
+ position: absolute;
+ right: 5px;
+ top: 7px;
+ color: #735005;
+ text-decoration: none;
+ line-height: 18px;
+ background: -6px -5px url(../images/sprites.png) no-repeat;
+ cursor: pointer;
+ width: 20px;
+ height: 20px;
+}
+#closeNotify:hover {
+ background: -26px -5px url(../images/sprites.png) no-repeat;
+}
+/* ----- Header, check blocks/header.html ----- */
+#header {
+ margin-top: 0px;
+ background: #16160f;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+}
+.content-wrapper {
+ /* wrapper positioning class */
+
+ width: 960px;
+ margin: auto;
+ position: relative;
+}
+#logo img {
+ padding: 5px 0px 5px 0px;
+ height: 75px;
+ width: auto;
+ float: left;
+}
+#userToolsNav {
+ /* Navigation bar containing login link or user information, check widgets/user_navigation.html*/
+
+ height: 20px;
+ padding-bottom: 5px;
+}
+#userToolsNav a {
+ height: 35px;
+ text-align: right;
+ margin-left: 20px;
+ text-decoration: underline;
+ color: #d0e296;
+ font-size: 16px;
+}
+#userToolsNav a:first-child {
+ margin-left: 0;
+}
+#userToolsNav a#ab-responses {
+ margin-left: 3px;
+}
+#userToolsNav .user-info,
+#userToolsNav .user-micro-info {
+ color: #b5b593;
+}
+#userToolsNav a img {
+ vertical-align: middle;
+ margin-bottom: 2px;
+}
+#userToolsNav .user-info a {
+ margin: 0;
+ text-decoration: none;
+}
+#metaNav {
+ /* Top Navigation bar containing links for tags, people and badges, check widgets/header.html */
+
+ float: right;
+ /* for #header.with-logo it is modified */
+
+ margin-right: 7px;
+}
+#metaNav a {
+ color: #e2e2ae;
+ padding: 0px 0px 0px 35px;
+ height: 35px;
+ line-height: 25px;
+ margin: 5px 0px 0px 10px;
+ font-size: 18px;
+ font-weight: 100;
+ text-decoration: none;
+ display: block;
+ float: left;
+}
+#metaNav a:hover {
+ text-decoration: underline;
+}
+#metaNav a.on {
+ font-weight: bold;
+ color: #FFF;
+ text-decoration: none;
+}
+#metaNav a.special {
+ font-size: 18px;
+ color: #B02B2C;
+ font-weight: bold;
+ text-decoration: none;
+}
+#metaNav a.special:hover {
+ text-decoration: underline;
+}
+#metaNav #navTags {
+ background: 0px -95px url(../images/sprites.png) no-repeat;
+}
+#metaNav #navUsers,
+#metaNav #navGroups {
+ background: 3px -133px url(../images/sprites.png) no-repeat;
+}
+#metaNav #navBadges {
+ background: 3px -170px url(../images/sprites.png) no-repeat;
+}
+#metaNav a.group-name {
+ padding: 0px;
+ float: center;
+ margin: 5px 0px 5px 10px;
+}
+#metaNav input.group-name {
+ border: none;
+ height: 25px;
+ font-size: 18px;
+ font-weight: 100;
+ text-decoration: none;
+ display: block;
+ margin: 0px 10px 0px 10px;
+ width: 140px;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ font-weight: 100;
+}
+#metaNav input.group-name:focus {
+ border: none;
+}
+#metaNav a.group-name:hover {
+ background-color: transparent;
+}
+#metaNav span.dropdown:hover ul.dropdown-menu {
+ display: block;
+}
+#metaNav div.dropdown-container:hover ul.dropdown-menu {
+ display: block;
+}
+#metaNav .dropdown {
+ float: left;
+}
+#metaNav .dropdown-menu {
+ border-top: none;
+ left: 7%;
+}
+#metaNav .dropdown-menu a {
+ color: #666;
+ height: 25px;
+}
+#header.with-logo #userToolsNav {
+ position: absolute;
+ bottom: 0;
+ right: 0px;
+}
+#header.without-logo #userToolsNav {
+ float: left;
+ margin-top: 7px;
+}
+#secondaryHeader {
+ /* Div containing Home button, scope navigation, search form and ask button, check blocks/secondary_header.html */
+
+ height: 55px;
+ background: #e9e9e1;
+ border-bottom: #d3d3c2 1px solid;
+ border-top: #fcfcfc 1px solid;
+ margin-bottom: 10px;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+}
+#secondaryHeader #homeButton {
+ border-right: #afaf9e 1px solid;
+ background: -6px -36px url(../images/sprites.png) no-repeat;
+ height: 55px;
+ width: 43px;
+ display: block;
+ float: left;
+}
+#secondaryHeader #homeButton:hover {
+ background: -51px -36px url(../images/sprites.png) no-repeat;
+}
+#secondaryHeader #scopeWrapper {
+ width: 688px;
+ float: left;
+}
+#secondaryHeader #scopeWrapper a {
+ display: block;
+ float: left;
+}
+#secondaryHeader #scopeWrapper .scope-selector {
+ font-size: 20px;
+ color: #7a7a6b;
+ height: 55px;
+ line-height: 55px;
+ margin-left: 16px;
+}
+#secondaryHeader #scopeWrapper .on {
+ background: url(../images/scopearrow.png) no-repeat center bottom;
+}
+#secondaryHeader #scopeWrapper .ask-message {
+ font-size: 24px;
+}
+.validate-email-page label {
+ color: #707070;
+ line-height: 1.35;
+ display: block;
+ margin: 10px 0;
+}
+.validate-email-page #validation-code {
+ padding-left: 5px;
+ border: #cce6ec 3px solid;
+ height: 25px;
+ font-size: 14px;
+ width: 200px;
+}
+.validate-email-page form {
+ margin-bottom: 30px;
+}
+#searchBar {
+ /* Main search form , check widgets/search_bar.html */
+
+ display: inline-block;
+ background-color: #fff;
+ width: 400px;
+ border: 1px solid #c9c9b5;
+ float: right;
+ height: 42px;
+ margin: 6px 0px 0px 15px;
+}
+#searchBar .searchInput,
+#searchBar .searchInputCancelable {
+ font-size: 26px;
+ height: 39px;
+ font-weight: 300;
+ background: #FFF;
+ border: 0px;
+ color: #484848;
+ padding-left: 10px;
+ padding-top: 1px;
+ font-family: Arial;
+ vertical-align: top;
+}
+#searchBar .searchInput {
+ width: 340px;
+}
+#searchBar .searchInputCancelable {
+ width: 305px;
+}
+#searchBar .logoutsearch {
+ width: 337px;
+}
+#searchBar .searchBtn {
+ font-size: 10px;
+ color: #666;
+ background-color: #eee;
+ height: 42px;
+ border: #FFF 1px solid;
+ line-height: 22px;
+ text-align: center;
+ float: right;
+ margin: 0px;
+ width: 48px;
+ background: -98px -36px url(../images/sprites.png) no-repeat;
+ cursor: pointer;
+}
+#searchBar .searchBtn:hover {
+ background: -146px -36px url(../images/sprites.png) no-repeat;
+}
+#searchBar .cancelSearchBtn {
+ font-size: 30px;
+ color: #ce8888;
+ background: #fff;
+ height: 42px;
+ border: 0px;
+ border-left: #deded0 1px solid;
+ text-align: center;
+ width: 35px;
+ cursor: pointer;
+}
+#searchBar .cancelSearchBtn:hover {
+ color: #d84040;
+}
+body.anon #searchBar {
+ width: 500px;
+}
+body.anon #searchBar .searchInput {
+ width: 440px;
+}
+body.anon #searchBar .searchInputCancelable {
+ width: 405px;
+}
+#askButton {
+ /* check blocks/secondary_header.html and widgets/ask_button.html*/
+
+ line-height: 44px;
+ margin-top: 6px;
+ float: right;
+ text-transform: uppercase;
+ height: 42px;
+ font-size: 20px;
+ text-align: center;
+ text-decoration: none;
+ cursor: pointer;
+ color: #4a757f;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+ border-top: #eaf2f3 1px solid;
+ background-color: #d1e2e5;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
+ background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ -webkit-box-shadow: 1px 1px 2px #636363;
+ -moz-box-shadow: 1px 1px 2px #636363;
+ box-shadow: 1px 1px 2px #636363;
+ width: 200px;
+ /* to match width of sidebar */
+
+}
+#askButton:hover {
+ background-color: #cde5e9;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
+ background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ text-decoration: none;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+}
+/* ----- Content layout, check two_column_body.html or one_column_body.html ----- */
+#ContentLeft {
+ width: 730px;
+ float: left;
+ position: relative;
+ padding-bottom: 10px;
+}
+#ContentRight {
+ width: 200px;
+ float: right;
+ padding: 0 0px 10px 0px;
+}
+#ContentFull {
+ float: left;
+ width: 960px;
+}
+/* ----- Sidebar Widgets Box, check main_page/sidebar.html or question/sidebar.html ----- */
+.box {
+ background: #fff;
+ padding: 4px 0px 10px 0px;
+ width: 200px;
+ /* widgets for question template */
+
+ /* notify by email box */
+
+}
+.box p {
+ margin-bottom: 4px;
+ color: #707070;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ font-size: 14px;
+}
+.box p.info-box-follow-up-links {
+ text-align: right;
+ margin: 0;
+}
+.box h2 {
+ padding-left: 0;
+ background: #eceeeb;
+ height: 30px;
+ line-height: 30px;
+ text-align: right;
+ font-size: 18px !important;
+ font-weight: normal;
+ color: #656565;
+ padding-right: 10px;
+ margin-bottom: 10px;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ width: 190px;
+}
+.box h3 {
+ color: #4a757f;
+ font-size: 18px;
+ text-align: left;
+ font-weight: normal;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ padding-left: 0px;
+}
+.box .contributorback {
+ background: #eceeeb url(../images/contributorsback.png) no-repeat center left;
+}
+.box form {
+ margin: 0px;
+}
+.box label {
+ color: #707070;
+ font-size: 15px;
+ vertical-align: bottom;
+ display: inline;
+ text-align: left;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+}
+.box #displayTagFilterControl label,
+.box #emailTagFilterControl label {
+ /*Especial width just for the tag filter boxes in index page*/
+
+ width: 160px;
+}
+.box ul {
+ margin-left: 22px;
+}
+.box li {
+ list-style-type: disc;
+ font-size: 13px;
+ line-height: 20px;
+ margin-bottom: 10px;
+ color: #707070;
+}
+.box ul.tags {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ line-height: 170%;
+ display: block;
+}
+.box #displayTagFilterControl p label {
+ color: #707070;
+ font-size: 15px;
+}
+.box .inputs #interestingTagInput,
+.box .inputs #ignoredTagInput,
+.box .inputs #subscribedTagInput,
+.box .inputs #ab-tag-search {
+ width: 152px;
+ padding-left: 5px;
+ border: #c9c9b5 1px solid;
+ height: 25px;
+ font-size: 14px;
+}
+.box .inputs #ab-tag-search {
+ width: 138px;
+}
+.box .inputs #interestingTagAdd,
+.box .inputs #ignoredTagAdd,
+.box .inputs #subscribedTagAdd,
+.box .inputs #ab-tag-search-add {
+ border: 0;
+ font-weight: bold;
+ margin-top: -2px;
+ height: 27px;
+ font-size: 14px;
+ text-align: center;
+ text-decoration: none;
+ cursor: pointer;
+ color: #4a757f;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+ border-top: #eaf2f3 1px solid;
+ background-color: #d1e2e5;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
+ background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ -webkit-box-shadow: 1px 1px 2px #636363;
+ -moz-box-shadow: 1px 1px 2px #636363;
+ box-shadow: 1px 1px 2px #636363;
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+}
+.box .inputs #interestingTagAdd:hover,
+.box .inputs #ignoredTagAdd:hover,
+.box .inputs #ab-tag-search-add:hover {
+ background-color: #cde5e9;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
+ background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ text-decoration: none;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+}
+.box .inputs #ab-tag-search-add {
+ width: 47px;
+}
+.box img.gravatar {
+ margin: 1px;
+}
+.box a.followed,
+.box a.follow {
+ line-height: 34px;
+ border: 0;
+ font-weight: normal;
+ margin-top: 3px;
+ display: block;
+ height: 34px;
+ font-size: 21px;
+ text-align: center;
+ text-decoration: none;
+ cursor: pointer;
+ color: #4a757f;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+ border-top: #eaf2f3 1px solid;
+ background-color: #d1e2e5;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
+ background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ -webkit-box-shadow: 1px 1px 2px #636363;
+ -moz-box-shadow: 1px 1px 2px #636363;
+ box-shadow: 1px 1px 2px #636363;
+ margin: 0 auto;
+ padding: 0;
+ width: 130px;
+}
+.box a.followed:hover,
+.box a.follow:hover {
+ background-color: #cde5e9;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
+ background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ text-decoration: none;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+}
+.box a.followed div.unfollow {
+ display: none;
+}
+.box a.followed:hover div {
+ display: none;
+}
+.box a.followed:hover div.unfollow {
+ display: inline;
+ color: #a05736;
+}
+.box .favorite-number {
+ padding: 5px 0 0 5px;
+ font-size: 100%;
+ font-family: Arial;
+ font-weight: bold;
+ color: #777;
+ text-align: center;
+}
+.box .notify-sidebar #question-subscribe-sidebar {
+ margin: 0 0 0 3px;
+}
+.users-page .box label {
+ display: inline;
+ float: none;
+}
+.statsWidget p {
+ color: #707070;
+ font-size: 16px;
+ border-bottom: #cccccc 1px solid;
+ font-size: 13px;
+}
+.statsWidget p strong {
+ float: right;
+ padding-right: 10px;
+}
+.questions-related {
+ word-wrap: break-word;
+}
+.questions-related p {
+ line-height: 20px;
+ padding: 4px 0px 9px 0px;
+ font-size: 16px;
+ font-weight: normal;
+ border-bottom: #cccccc 1px solid;
+}
+.questions-related p:first-child {
+ margin-top: -4px;
+}
+.questions-related p:last-child {
+ border: none;
+}
+.questions-related a {
+ font-size: 13px;
+ line-height: 1.3;
+}
+/* tips and markdown help are widgets for ask template */
+#tips li {
+ color: #707070;
+ font-size: 13px;
+ list-style-image: url(../images/tips.png);
+}
+#tips a {
+ font-size: 16px;
+}
+#markdownHelp li {
+ color: #707070;
+ font-size: 13px;
+}
+#markdownHelp a {
+ font-size: 16px;
+}
+/* ----- Sorting top Tab, check main_page/tab_bar.html ------*/
+.tabBar {
+ background-color: #eff5f6;
+ height: 30px;
+ margin-bottom: 3px;
+ margin-top: 3px;
+ float: right;
+ font-family: Georgia, serif;
+ font-size: 16px;
+ border-radius: 5px;
+ -ms-border-radius: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -khtml-border-radius: 5px;
+}
+.tabBar h2 {
+ float: left;
+}
+.tabsA,
+.tabsC {
+ float: right;
+ position: relative;
+ display: block;
+ height: 20px;
+}
+/* tabsA - used for sorting */
+.tabsA {
+ float: right;
+}
+.tabsC {
+ float: left;
+}
+.tabsA a,
+.tabsC a {
+ border-left: 1px solid #d0e1e4;
+ color: #7ea9b3;
+ display: block;
+ float: left;
+ height: 20px;
+ line-height: 20px;
+ padding: 4px 7px 4px 7px;
+ text-decoration: none;
+}
+.tabsA a.on,
+.tabsC a.on,
+.tabsA a:hover,
+.tabsC a:hover {
+ color: #4a757f;
+}
+.tabsA .label,
+.tabsC .label {
+ float: left;
+ color: #646464;
+ margin: 4px 5px 0px 8px;
+}
+.main-page .tabsA .label {
+ margin-left: 8px;
+}
+.tabsB a {
+ background: #eee;
+ border: 1px solid #eee;
+ color: #777;
+ display: block;
+ float: left;
+ height: 22px;
+ line-height: 28px;
+ margin: 5px 0px 0 4px;
+ padding: 0 11px 0 11px;
+ text-decoration: none;
+}
+.tabsC .first {
+ border: none;
+}
+.rss {
+ float: right;
+ font-size: 16px;
+ color: #f57900;
+ margin: 5px 0px 3px 7px;
+ width: 52px;
+ padding-left: 2px;
+ padding-top: 3px;
+ background: #ffffff url(../images/feed-icon-small.png) no-repeat center right;
+ float: right;
+ font-family: Georgia, serif;
+ font-size: 16px;
+}
+.rss:hover {
+ color: #F4A731 !important;
+}
+/* ----- Headline, containing number of questions and tags selected, check main_page/headline.html ----- */
+#questionCount {
+ font-weight: bold;
+ font-size: 20px;
+ color: #7ea9b3;
+ width: 200px;
+ float: left;
+ margin-bottom: 6px;
+ padding-top: 6px;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+}
+#listSearchTags {
+ float: left;
+ margin-top: 3px;
+ color: #707070;
+ font-size: 16px;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+}
+ul#searchTags {
+ margin-left: 10px;
+ float: right;
+ padding-top: 2px;
+}
+.search-tips {
+ font-size: 16px;
+ line-height: 17px;
+ color: #707070;
+ margin: 5px 0 10px 0;
+ padding: 0px;
+ float: left;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+}
+.search-tips a {
+ text-decoration: underline;
+ color: #1b79bd;
+}
+/* ----- Question list , check main_page/content.html and macros/macros.html----- */
+#question-list {
+ float: left;
+ position: relative;
+ background-color: #FFF;
+ padding: 0;
+ width: 100%;
+}
+.short-summary {
+ position: relative;
+ filter: inherit;
+ padding: 10px 0 3px 0;
+ border-bottom: 1px solid #DDDBCE;
+ margin-bottom: 1px;
+ overflow: hidden;
+ width: 733px;
+ float: left;
+ /*background: url(../images/summary-background.png) repeat-x;*/
+
+}
+.short-summary h2 {
+ font-size: 20px;
+ font-weight: normal;
+ line-height: 26px;
+ padding-left: 0;
+ margin-bottom: 7px;
+ display: block;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+}
+.short-summary a {
+ color: #464646;
+}
+.short-summary .userinfo {
+ text-align: right;
+ line-height: 16px;
+ font-family: Arial;
+ padding-right: 4px;
+}
+.short-summary .userinfo .timeago,
+.short-summary span.anonymous {
+ font-size: 11px;
+ clear: both;
+ font-weight: normal;
+ color: #555;
+}
+.short-summary .userinfo a {
+ font-weight: bold;
+ font-size: 11px;
+}
+.short-summary .counts {
+ float: right;
+ margin: 4px 0 0 5px;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+}
+.short-summary .counts .item-count {
+ padding: 0px 5px 0px 5px;
+ font-size: 25px;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+}
+.short-summary .counts .votes div,
+.short-summary .counts .views div,
+.short-summary .counts .answers div,
+.short-summary .counts .favorites div {
+ margin-top: 3px;
+ font-size: 14px;
+ line-height: 14px;
+ color: #646464;
+}
+.short-summary .tags {
+ margin: 0 0 0 1px;
+}
+.short-summary .votes,
+.short-summary .answers,
+.short-summary .favorites,
+.short-summary .views {
+ text-align: center;
+ margin: 0 3px;
+ padding: 8px 2px 0px 2px;
+ width: 51px;
+ float: right;
+ height: 44px;
+ border: #dbdbd4 1px solid;
+}
+.short-summary .votes {
+ background: url(../images/vote-background.png) repeat-x;
+}
+.short-summary .answers {
+ background: url(../images/answers-background.png) repeat-x;
+}
+.short-summary .views {
+ background: url(../images/view-background.png) repeat-x;
+}
+.short-summary .no-votes .item-count {
+ color: #b1b5b6;
+}
+.short-summary .some-votes .item-count {
+ color: #4a757f;
+}
+.short-summary .no-answers .item-count {
+ color: #b1b5b6;
+}
+.short-summary .some-answers .item-count {
+ color: #eab243;
+}
+.short-summary .no-views .item-count {
+ color: #b1b5b6;
+}
+.short-summary .some-views .item-count {
+ color: #d33f00;
+}
+.short-summary .accepted .item-count {
+ background: url(../images/accept.png) no-repeat top right;
+ display: block;
+ text-align: center;
+ width: 40px;
+ color: #eab243;
+}
+.short-summary .some-favorites .item-count {
+ background: #338333;
+ color: #d0f5a9;
+}
+.short-summary .no-favorites .item-count {
+ background: #eab243;
+ color: yellow;
+}
+/* ----- Question list Paginator , check main_content/pager.html and macros/utils_macros.html----- */
+.evenMore {
+ font-size: 13px;
+ color: #707070;
+ padding: 15px 0px 10px 0px;
+ clear: both;
+}
+.evenMore a {
+ text-decoration: underline;
+ color: #1b79bd;
+}
+.pager {
+ margin-top: 10px;
+ margin-bottom: 16px;
+}
+.pagesize {
+ margin-top: 10px;
+ margin-bottom: 16px;
+ float: right;
+}
+.paginator {
+ padding: 5px 0 10px 0;
+ font-size: 13px;
+ margin-bottom: 10px;
+}
+.paginator .prev a,
+.paginator .prev a:visited,
+.paginator .next a,
+.paginator .next a:visited {
+ background-color: #fff;
+ color: #777;
+ padding: 2px 4px 3px 4px;
+}
+.paginator a {
+ color: #7ea9b3;
+}
+.paginator .prev {
+ margin-right: .5em;
+}
+.paginator .next {
+ margin-left: .5em;
+}
+.paginator .page a,
+.paginator .page a:visited,
+.paginator .curr {
+ padding: .25em;
+ background-color: #fff;
+ margin: 0em .25em;
+ color: #ff;
+}
+.paginator .curr {
+ background-color: #8ebcc7;
+ color: #fff;
+ font-weight: bold;
+}
+.paginator .next a,
+.paginator .prev a {
+ color: #7ea9b3;
+}
+.paginator .page a:hover,
+.paginator .curr a:hover,
+.paginator .prev a:hover,
+.paginator .next a:hover {
+ color: #8C8C8C;
+ background-color: #E1E1E1;
+ text-decoration: none;
+}
+.paginator .text {
+ color: #777;
+ padding: .3em;
+}
+.paginator .paginator-container-left {
+ padding: 5px 0 10px 0;
+}
+/* ----- Tags Styles ----- */
+/* tag formatting is also copy-pasted in template
+ because it must be the same in the emails
+ askbot/models/__init__.py:format_instant_notification_email()
+*/
+/* tag cloud */
+.tag-size-1 {
+ font-size: 12px;
+}
+.tag-size-2 {
+ font-size: 13px;
+}
+.tag-size-3 {
+ font-size: 14px;
+}
+.tag-size-4 {
+ font-size: 15px;
+}
+.tag-size-5 {
+ font-size: 16px;
+}
+.tag-size-6 {
+ font-size: 17px;
+}
+.tag-size-7 {
+ font-size: 18px;
+}
+.tag-size-8 {
+ font-size: 19px;
+}
+.tag-size-9 {
+ font-size: 20px;
+}
+.tag-size-10 {
+ font-size: 21px;
+}
+ul.tags,
+ul.tags.marked-tags,
+ul#related-tags {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ line-height: 170%;
+ display: block;
+}
+ul.tags li {
+ float: left;
+ display: block;
+ margin: 0 8px 8px 0;
+ padding: 0;
+ height: 20px;
+}
+.wildcard-tags {
+ clear: both;
+}
+ul.tags.marked-tags li,
+.wildcard-tags ul.tags li {
+ margin-bottom: 5px;
+}
+#tagSelector div.inputs {
+ clear: both;
+ float: none;
+ margin-bottom: 10px;
+}
+.tags-page ul.tags li,
+ul#ab-user-tags li {
+ width: 160px;
+ margin: 5px;
+ margin-left: 0;
+}
+.tags-page ul.tags {
+ margin-left: 5px;
+}
+ul#related-tags li {
+ margin: 0 5px 8px 0;
+ float: left;
+ clear: left;
+}
+/* .tag-left and .tag-right are for the sliding doors decoration of tags */
+.tag-left {
+ cursor: pointer;
+ display: block;
+ float: left;
+ height: 17px;
+ margin: 0 5px 0 0;
+ padding: 0;
+ -webkit-box-shadow: 0px 0px 5px #d3d6d7;
+ -moz-box-shadow: 0px 0px 5px #d3d6d7;
+ box-shadow: 0px 0px 5px #d3d6d7;
+}
+.tag-right {
+ background: #f3f6f6;
+ border: #fff 1px solid ;
+ border-top: #fff 2px solid;
+ outline: #cfdbdb 1px solid;
+ /* .box-shadow(0px,1px,0px,#88a8a8);*/
+
+ display: block;
+ float: left;
+ height: 17px;
+ line-height: 17px;
+ font-weight: normal;
+ font-size: 11px;
+ padding: 0px 8px 0px 8px;
+ text-decoration: none;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: middle;
+ font-family: Arial;
+ color: #717179;
+}
+.deletable-tag {
+ margin-right: 3px;
+ white-space: nowrap;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ -moz-border-radius-topright: 4px;
+ -moz-border-radius-bottomright: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+}
+.tags a.tag-right,
+.tags span.tag-right {
+ color: #585858;
+ text-decoration: none;
+}
+.tags a:hover {
+ color: #1A1A1A;
+}
+.users-page th,
+.tags-page th,
+.groups-page th,
+.moderate-tags-page th {
+ padding-bottom: 5px;
+ font-weight: normal;
+}
+.users-page h1,
+.tags-page h1,
+.groups-page h1,
+.moderate-tags-page h1 {
+ float: left;
+}
+.moderate-tags-page button {
+ line-height: 18px;
+}
+.moderate-tags-page table {
+ border-spacing: 0;
+}
+.moderate-tags-page table.suggested-tags-table {
+ width: 100%;
+}
+.moderate-tags-page th {
+ font-style: italic;
+}
+.moderate-tags-page th,
+.moderate-tags-page tr {
+ vertical-align: top;
+ text-align: left;
+ padding-right: 20px;
+}
+.moderate-tags-page td.per-thread-controls {
+ width: 120px;
+ /* 20px more to compensate for the padding */
+
+ height: 30px;
+}
+.moderate-tags-page td.per-thread-controls button {
+ display: none;
+}
+.moderate-tags-page th.decision-col,
+.moderate-tags-page th.tags-col,
+.moderate-tags-page th.users-col {
+ width: 100px;
+}
+.moderate-tags-page tr.per-tag-controls {
+ height: 30px;
+ text-align: center;
+}
+.moderate-tags-page tr.thread-info a {
+ line-height: 18px;
+}
+.moderate-tags-page tr.thread-info td {
+ padding-bottom: 5px;
+}
+.moderate-tags-page td.tags-col,
+.moderate-tags-page td.users-col {
+ padding-top: 7px;
+}
+.moderate-tags-page td.thread-links-col {
+ padding-top: 5px;
+}
+.main-page h1 {
+ margin-right: 5px;
+}
+.delete-icon {
+ margin-top: -1px;
+ float: left;
+ height: 21px;
+ width: 18px;
+ display: block;
+ line-height: 20px;
+ text-align: center;
+ background: #bbcdcd;
+ cursor: default;
+ color: #fff;
+ border-top: #cfdbdb 1px solid;
+ font-family: Arial;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ -moz-border-radius-topright: 4px;
+ -moz-border-radius-bottomright: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+ text-shadow: 0px 1px 0px #7ea0a0;
+ -moz-text-shadow: 0px 1px 0px #7ea0a0;
+ -webkit-text-shadow: 0px 1px 0px #7ea0a0;
+}
+.delete-icon:hover {
+ background: #b32f2f;
+}
+.tag-number {
+ font-weight: normal;
+ float: left;
+ font-size: 16px;
+ color: #5d5d5d;
+}
+.badges .tag-number {
+ float: none;
+ display: inline;
+ padding-right: 15px;
+}
+/* ----- Ask and Edit Question Form template----- */
+.section-title {
+ color: #7ea9b3;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ font-weight: bold;
+ font-size: 24px;
+}
+#fmask {
+ margin-bottom: 30px;
+ width: 100%;
+}
+#askFormBar {
+ display: inline-block;
+ padding: 4px 7px 0px 0px;
+ margin-top: 0px;
+}
+#askFormBar p {
+ margin: 0 0 5px 0;
+ font-size: 14px;
+ color: #525252;
+ line-height: 1.4;
+}
+#askFormBar .questionTitleInput {
+ font-size: 24px;
+ line-height: 24px;
+ height: 36px;
+ margin: 0px;
+ padding: 0px 0 0 5px;
+ border: #cce6ec 3px solid;
+ width: 719px;
+}
+.ask-page div#question-list,
+.edit-question-page div#question-list {
+ border-bottom: #f0f0ec 1px solid;
+ float: none;
+}
+.ask-page div#question-list a,
+.edit-question-page div#question-list a {
+ line-height: 30px;
+}
+.ask-page div#question-list h2,
+.edit-question-page div#question-list h2 {
+ font-size: 13px;
+ padding-bottom: 0;
+ color: #1b79bd;
+ border-top: #f0f0ec 1px solid;
+ border-left: #f0f0ec 1px solid;
+ min-height: 30px;
+ line-height: 30px;
+ font-weight: normal;
+}
+.ask-page div#question-list span,
+.edit-question-page div#question-list span {
+ width: 28px;
+ height: 26px;
+ line-height: 26px;
+ text-align: center;
+ margin-right: 10px;
+ float: left;
+ display: block;
+ color: #fff;
+ background: #b8d0d5;
+ border-radius: 3px;
+ -ms-border-radius: 3px;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ -khtml-border-radius: 3px;
+}
+.ask-page label,
+.edit-question-page label {
+ color: #525252;
+ font-size: 13px;
+}
+.ask-page #id_tags,
+.edit-question-page #id_tags {
+ border: #cce6ec 3px solid;
+ height: 25px;
+ padding-left: 5px;
+ font-size: 14px;
+ width: 395px;
+}
+.ask-page #id_post_author_username,
+.question-page #id_post_author_username,
+.edit-question-page #id_post_author_username,
+.edit-answer-page #id_post_author_username,
+.ask-page #id_post_author_email,
+.question-page #id_post_author_email,
+.edit-question-page #id_post_author_email,
+.edit-answer-page #id_post_author_email {
+ border: #cce6ec 3px solid;
+ height: 25px;
+ padding-left: 5px;
+ font-size: 14px;
+ width: 186px;
+}
+.ask-page #id_post_author_email,
+.question-page #id_post_author_email,
+.edit-question-page #id_post_author_email,
+.edit-answer-page #id_post_author_email {
+ margin-left: 10px;
+}
+.ask-page table.proxy-user-info,
+.question-page table.proxy-user-info,
+.edit-question-page table.proxy-user-info,
+.edit-answer-page table.proxy-user-info {
+ border-spacing: 0px;
+ width: 100%;
+}
+.ask-page table.proxy-user-info .form-item,
+.question-page table.proxy-user-info .form-item,
+.edit-question-page table.proxy-user-info .form-item,
+.edit-answer-page table.proxy-user-info .form-item {
+ float: left;
+}
+.groups-input,
+.users-input {
+ width: 152px;
+ padding-left: 5px;
+ border: #c9c9b5 1px solid;
+ height: 25px;
+ font-size: 14px;
+}
+.add-groups,
+.add-users {
+ border: 0;
+ font-weight: bold;
+ margin-top: -2px;
+ height: 27px;
+ font-size: 14px;
+ text-align: center;
+ text-decoration: none;
+ cursor: pointer;
+ color: #4a757f;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+ border-top: #eaf2f3 1px solid;
+ background-color: #d1e2e5;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
+ background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ -webkit-box-shadow: 1px 1px 2px #636363;
+ -moz-box-shadow: 1px 1px 2px #636363;
+ box-shadow: 1px 1px 2px #636363;
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+}
+.share-input-col {
+ width: 160px;
+ text-align: center;
+}
+.add-everyone-group {
+ text-align: center;
+ margin: auto;
+ display: block;
+ padding: 0 10px;
+ height: 25px;
+}
+.add-groups:hover {
+ background-color: #cde5e9;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
+ background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ text-decoration: none;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+}
+#id_user,
+#id_user_author {
+ border: #cce6ec 3px solid;
+ height: 25px;
+ padding-left: 5px;
+ width: 395px;
+ font-size: 14px;
+}
+.groups-input,
+.users-input {
+ width: 152px;
+ padding-left: 5px;
+ border: #c9c9b5 1px solid;
+ height: 25px;
+ font-size: 14px;
+}
+.add-groups,
+.add-users {
+ border: 0;
+ font-weight: bold;
+ margin-top: -2px;
+ height: 27px;
+ font-size: 14px;
+ text-align: center;
+ text-decoration: none;
+ cursor: pointer;
+ color: #4a757f;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+ border-top: #eaf2f3 1px solid;
+ background-color: #d1e2e5;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
+ background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ -webkit-box-shadow: 1px 1px 2px #636363;
+ -moz-box-shadow: 1px 1px 2px #636363;
+ box-shadow: 1px 1px 2px #636363;
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+}
+.add-everyone-group {
+ text-align: center;
+ margin: auto;
+ display: block;
+ padding: 0 10px;
+}
+.add-groups:hover {
+ background-color: #cde5e9;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
+ background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ text-decoration: none;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+}
+#id_user,
+#id_user_author {
+ border: #cce6ec 3px solid;
+ height: 25px;
+ padding-left: 5px;
+ width: 395px;
+ font-size: 14px;
+}
+.title-desc {
+ color: #707070;
+ font-size: 13px;
+ margin-bottom: 5px;
+}
+.ask-page .title-desc,
+.question-page .title-desc,
+.ask-page .tags-desc,
+.question-page .tags-desc {
+ color: #707070;
+ font-style: italic;
+ font-size: 16px;
+}
+#fmanswer input.submit,
+.ask-page input.submit,
+.edit-question-page input.submit {
+ float: left;
+ font-weight: normal;
+ margin-top: 3px;
+ height: 34px;
+ font-size: 21px;
+ text-align: center;
+ text-decoration: none;
+ cursor: pointer;
+ color: #4a757f;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+ border-top: #eaf2f3 1px solid;
+ background-color: #d1e2e5;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
+ background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ -webkit-box-shadow: 1px 1px 2px #636363;
+ -moz-box-shadow: 1px 1px 2px #636363;
+ box-shadow: 1px 1px 2px #636363;
+ margin-right: 7px;
+}
+#fmanswer input.submit:hover,
+.ask-page input.submit:hover,
+.edit-question-page input.submit:hover {
+ background-color: #cde5e9;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
+ background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ text-decoration: none;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+}
+.wmd-container {
+ border: #cce6ec 3px solid;
+ min-height: 250px;
+}
+.wmd-container textarea {
+ border: none;
+}
+.users-page .wmd-container {
+ width: 200px;
+}
+.ask-page .wmd-container,
+.question-page .wmd-container,
+.edit-question-page .wmd-container,
+.edit-answer-page .wmd-container {
+ width: 723px;
+}
+.ask-page #editor,
+.question-page #editor,
+.edit-question-page #editor,
+.edit-answer-page #editor {
+ width: 710px;
+ padding: 6px;
+}
+.ask-page .retagger-buttons button,
+.question-page .retagger-buttons button,
+.edit-question-page .retagger-buttons button,
+.edit-answer-page .retagger-buttons button {
+ margin: 8px 10px 5px 0;
+}
+#editor {
+ /* adjustment for editor preview */
+
+ display: block;
+ font-size: 100%;
+ min-height: 200px;
+ line-height: 18px;
+ margin: 0;
+ border: 0;
+}
+.users-page #editor {
+ width: 192px;
+}
+#id_title {
+ width: 100%;
+}
+.wmd-preview {
+ margin: 0;
+ padding: 5px;
+ background-color: #F5F5F5;
+ min-height: 20px;
+ overflow: auto;
+ font-size: 13px;
+ font-family: Arial;
+}
+.wmd-preview p {
+ margin-bottom: 14px;
+ line-height: 1.4;
+ font-size: 14px;
+}
+.wmd-preview p:last-child {
+ margin-bottom: 0;
+}
+.wmd-preview pre {
+ background-color: #E7F1F8;
+}
+.wmd-preview blockquote {
+ background-color: #eee;
+}
+.wmd-preview IMG {
+ max-width: 600px;
+}
+.user-page .wmd-buttons {
+ width: 725px;
+}
+.preview-toggle {
+ width: 100%;
+ color: #b6a475;
+ /*letter-spacing:1px;*/
+
+ text-align: left;
+}
+.preview-toggle span:hover {
+ cursor: pointer;
+}
+.after-editor {
+ margin-top: 15px;
+ margin-bottom: 15px;
+}
+.checkbox {
+ margin-left: 5px;
+ font-weight: normal;
+ cursor: help;
+}
+.question-options {
+ margin-top: 1px;
+ color: #666;
+ line-height: 13px;
+ margin-bottom: 5px;
+}
+.question-options label {
+ vertical-align: text-bottom;
+}
+.edit-content-html {
+ border-top: 1px dotted #D8D2A9;
+ border-bottom: 1px dotted #D8D2A9;
+ margin: 5px 0 5px 0;
+}
+.edit-question-page,
+#fmedit,
+.wmd-preview {
+ color: #525252;
+}
+.edit-question-page #id_revision,
+#fmedit #id_revision,
+.wmd-preview #id_revision {
+ font-size: 14px;
+ margin-top: 5px;
+ margin-bottom: 5px;
+}
+.edit-question-page #id_title,
+#fmedit #id_title,
+.wmd-preview #id_title {
+ font-size: 24px;
+ line-height: 24px;
+ height: 36px;
+ margin: 0px;
+ padding: 0px 0 0 5px;
+ border: #cce6ec 3px solid;
+ width: 719px;
+ margin-bottom: 10px;
+}
+.edit-question-page #id_summary,
+#fmedit #id_summary,
+.wmd-preview #id_summary {
+ border: #cce6ec 3px solid;
+ height: 25px;
+ padding-left: 5px;
+ width: 395px;
+ font-size: 14px;
+}
+.edit-question-page .title-desc,
+#fmedit .title-desc,
+.wmd-preview .title-desc {
+ margin-bottom: 10px;
+}
+/* ----- Question template ----- */
+.question-page h1 {
+ padding-top: 0px;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+}
+.question-page h1 a {
+ color: #464646;
+ font-size: 26px;
+ font-weight: normal;
+ line-height: 1;
+}
+.question-page p.rss {
+ float: none;
+ clear: both;
+ padding: 3px 0 0 23px;
+ font-size: 15px;
+ width: 130px;
+ background-position: center left;
+ margin-left: 0px !important;
+}
+.question-page p.rss a {
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ vertical-align: top;
+}
+.question-page .question-content {
+ float: right;
+ width: 682px;
+ margin-bottom: 10px;
+}
+.question-page .question-content pre,
+.question-page .answer pre,
+.question-page .question-content code,
+.question-page .answer code {
+ clear: both;
+}
+.question-page #question-table {
+ float: left;
+ border-top: #f0f0f0 1px solid;
+}
+.question-page #question-table,
+.question-page .answer-table {
+ margin: 8px 0 6px 0;
+ border-spacing: 0px;
+ width: 670px;
+ padding-right: 10px;
+}
+.question-page .answer-table {
+ margin-top: 0px;
+ border-bottom: 1px solid #D4D4D4;
+ float: right;
+}
+.question-page .answer-table td,
+.question-page #question-table td {
+ width: 20px;
+ vertical-align: top;
+}
+.question-page .question-body,
+.question-page .answer-body {
+ overflow: auto;
+ margin-top: 10px;
+ font-family: Arial;
+ color: #4b4b4b;
+}
+.question-page .question-body p,
+.question-page .answer-body p {
+ margin-bottom: 14px;
+ line-height: 1.4;
+ font-size: 14px;
+ padding: 0px 5px 5px 0px;
+}
+.question-page .question-body a,
+.question-page .answer-body a {
+ color: #1b79bd;
+}
+.question-page .question-body li,
+.question-page .answer-body li {
+ margin-bottom: 7px;
+}
+.question-page .question-body IMG,
+.question-page .answer-body IMG {
+ max-width: 600px;
+}
+.question-page .post-update-info-container {
+ float: right;
+ width: 175px;
+}
+.question-page .post-update-info {
+ background: #ffffff url(../images/background-user-info.png) repeat-x bottom;
+ float: right;
+ font-size: 9px;
+ font-family: Arial;
+ width: 158px;
+ padding: 4px;
+ margin: 0px 0px 5px 5px;
+ line-height: 14px;
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ -webkit-box-shadow: 0px 2px 1px #bfbfbf;
+ -moz-box-shadow: 0px 2px 1px #bfbfbf;
+ box-shadow: 0px 2px 1px #bfbfbf;
+}
+.question-page .post-update-info p {
+ line-height: 13px;
+ font-size: 11px;
+ margin: 0 0 2px 1px;
+ padding: 0;
+}
+.question-page .post-update-info a {
+ color: #444;
+}
+.question-page .post-update-info .gravatar {
+ float: left;
+ margin-right: 4px;
+}
+.question-page .post-update-info p.tip {
+ color: #444;
+ line-height: 13px;
+ font-size: 10px;
+}
+.question-page .post-controls {
+ font-size: 11px;
+ line-height: 12px;
+ min-width: 200px;
+ padding-left: 5px;
+ text-align: right;
+ clear: left;
+ float: right;
+ margin-top: 10px;
+ margin-bottom: 8px;
+}
+.question-page .post-controls a {
+ color: #777;
+ padding: 0px 7px 3px 18px;
+ cursor: pointer;
+ border: none;
+ font-size: 12px;
+ font-family: Arial;
+ text-decoration: none;
+ height: 18px;
+ display: block;
+ float: right;
+ line-height: 18px;
+ margin-top: -2px;
+ margin-left: 4px;
+}
+.question-page .post-controls a:hover {
+ background-color: #f5f0c9;
+ border-radius: 3px;
+ -ms-border-radius: 3px;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ -khtml-border-radius: 3px;
+}
+.question-page .post-controls .sep {
+ color: #ccc;
+ float: right;
+ height: 18px;
+ font-size: 18px;
+}
+.question-page .post-controls .question-delete,
+.question-page .answer-controls .question-delete {
+ background: url(../images/delete.png) no-repeat center left;
+ padding-left: 11px;
+}
+.question-page .post-controls .question-flag,
+.question-page .answer-controls .question-flag {
+ background: url(../images/flag.png) no-repeat center left;
+}
+.question-page .post-controls .question-edit,
+.question-page .answer-controls .question-edit {
+ background: url(../images/edit2.png) no-repeat center left;
+}
+.question-page .post-controls .question-retag,
+.question-page .answer-controls .question-retag {
+ background: url(../images/retag.png) no-repeat center left;
+}
+.question-page .post-controls .question-close,
+.question-page .answer-controls .question-close {
+ background: url(../images/close.png) no-repeat center left;
+}
+.question-page .post-controls .permant-link,
+.question-page .answer-controls .permant-link {
+ background: url(../images/link.png) no-repeat center left;
+}
+.question-page .post-controls .answer-convert,
+.question-page .answer-controls .answer-convert {
+ float: right;
+ clear: left;
+ /*background: url(../images/link.png) no-repeat center left;*/
+
+}
+.question-page .post-controls .answer-convert input,
+.question-page .answer-controls .answer-convert input {
+ font-size: 12px;
+ color: #777;
+ font-family: Arial;
+ text-decoration: none;
+ display: inline;
+ white-space: nowrap;
+ padding-left: 0px;
+ background: none;
+ border: none;
+ padding: 0px 7px 3px 18px;
+ float: right;
+ height: 18px;
+ line-height: 18px;
+ margin-top: -2px;
+ margin-left: 4px;
+ box-shadow: none;
+}
+.question-page .post-controls .answer-convert input:hover,
+.question-page .answer-controls .answer-convert input:hover {
+ background-color: #f5f0c9;
+ border-radius: 3px;
+ -ms-border-radius: 3px;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ -khtml-border-radius: 3px;
+}
+.question-page .tabBar {
+ width: 100%;
+}
+.question-page #questionCount {
+ float: left;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ line-height: 15px;
+}
+.question-page .question-img-upvote,
+.question-page .question-img-downvote,
+.question-page .answer-img-upvote,
+.question-page .answer-img-downvote {
+ width: 25px;
+ height: 20px;
+ cursor: pointer;
+}
+.question-page .question-img-upvote,
+.question-page .answer-img-upvote {
+ background: url(../images/vote-arrow-up-new.png) no-repeat;
+}
+.question-page .question-img-downvote,
+.question-page .answer-img-downvote {
+ background: url(../images/vote-arrow-down-new.png) no-repeat;
+}
+.question-page .question-img-upvote:hover,
+.question-page .question-img-upvote.on,
+.question-page .answer-img-upvote:hover,
+.question-page .answer-img-upvote.on {
+ background: url(../images/vote-arrow-up-on-new.png) no-repeat;
+}
+.question-page .question-img-downvote:hover,
+.question-page .question-img-downvote.on,
+.question-page .answer-img-downvote:hover,
+.question-page .answer-img-downvote.on {
+ background: url(../images/vote-arrow-down-on-new.png) no-repeat;
+}
+.question-page #fmanswer_button {
+ margin: 8px 0px;
+}
+.question-page .question-img-favorite:hover {
+ background: url(../images/vote-favorite-on.png);
+}
+.question-page div.comments {
+ padding: 0;
+}
+.question-page #comment-title {
+ font-weight: bold;
+ font-size: 23px;
+ color: #7ea9b3;
+ width: 200px;
+ float: left;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+}
+.question-page .comments {
+ font-size: 12px;
+ clear: both;
+}
+.question-page .comments div.controls {
+ clear: both;
+ float: left;
+ width: 100%;
+ margin: 3px 0 20px 5px;
+}
+.question-page .comments .controls a {
+ color: #988e4c;
+ padding: 0 3px 2px 22px;
+ font-family: Arial;
+ font-size: 13px;
+ background: url(../images/comment.png) no-repeat center left;
+}
+.question-page .comments .controls a:hover {
+ background-color: #f5f0c9;
+ text-decoration: none;
+}
+.question-page .comments .button {
+ color: #988e4c;
+ font-size: 11px;
+ padding: 3px;
+ cursor: pointer;
+}
+.question-page .comments a {
+ background-color: inherit;
+ color: #1b79bd;
+ padding: 0;
+}
+.question-page .comments form.post-comments {
+ margin: 3px 26px 0 42px;
+}
+.question-page .comments form.post-comments textarea {
+ font-size: 13px;
+ line-height: 1.3;
+}
+.question-page .comments textarea {
+ height: 42px;
+ width: 100%;
+ margin: 7px 0 5px 1px;
+ font-family: Arial;
+ outline: none;
+ overflow: auto;
+ font-size: 12px;
+ line-height: 140%;
+ padding-left: 2px;
+ padding-top: 3px;
+ border: #cce6ec 3px solid;
+}
+.question-page .comments input {
+ margin-left: 10px;
+ margin-top: 1px;
+ vertical-align: top;
+ width: 100px;
+}
+.question-page .comments button {
+ line-height: 25px;
+ margin-bottom: 5px;
+ height: 27px;
+ font-size: 12px;
+ text-align: center;
+ text-decoration: none;
+ cursor: pointer;
+ color: #4a757f;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+ border-top: #eaf2f3 1px solid;
+ background-color: #d1e2e5;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
+ background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ -webkit-box-shadow: 1px 1px 2px #636363;
+ -moz-box-shadow: 1px 1px 2px #636363;
+ box-shadow: 1px 1px 2px #636363;
+ font-family: Arial;
+ font-weight: bold;
+}
+.question-page .comments button:hover {
+ background-color: #cde5e9;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
+ background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ text-decoration: none;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+}
+.question-page .comments .counter {
+ display: inline-block;
+ width: 245px;
+ float: right;
+ color: #b6a475 !important;
+ vertical-align: top;
+ font-family: Arial;
+ float: right;
+ text-align: right;
+}
+.question-page .comments .comment {
+ border-bottom: 1px solid #edeeeb;
+ clear: both;
+ margin: 0;
+ margin-top: 8px;
+ padding-bottom: 4px;
+ overflow: auto;
+ font-family: Arial;
+ font-size: 11px;
+ min-height: 25px;
+ background: #ffffff url(../images/comment-background.png) bottom repeat-x;
+ border-radius: 5px;
+ -ms-border-radius: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -khtml-border-radius: 5px;
+}
+.question-page .comments div.comment:hover {
+ background-color: #efefef;
+}
+.question-page .comments a.author {
+ background-color: inherit;
+ color: #1b79bd;
+ padding: 0;
+}
+.question-page .comments a.author:hover {
+ text-decoration: underline;
+}
+.question-page .comments span.delete-icon {
+ background: url(../images/close-small.png) no-repeat;
+ border: 0;
+ width: 14px;
+ height: 14px;
+}
+.question-page .comments span.delete-icon:hover {
+ border: #BC564B 2px solid;
+ border-radius: 10px;
+ -ms-border-radius: 10px;
+ -moz-border-radius: 10px;
+ -webkit-border-radius: 10px;
+ -khtml-border-radius: 10px;
+ margin: -3px 0px 0px -2px;
+}
+.question-page .comments .content {
+ margin-bottom: 7px;
+}
+.question-page .comments .comment-votes {
+ float: left;
+ width: 37px;
+ line-height: 130%;
+ padding: 6px 5px 6px 3px;
+}
+.question-page .comments .comment-body {
+ line-height: 1.3;
+ margin: 3px 26px 0 46px;
+ padding: 5px 3px;
+ color: #666;
+ font-size: 13px;
+}
+.question-page .comments .comment-body .edit {
+ padding-left: 6px;
+}
+.question-page .comments .comment-body .convert-comment {
+ display: inline;
+ white-space: nowrap;
+ padding-left: 0px;
+}
+.question-page .comments .comment-body .convert-comment input {
+ background: none;
+ padding: 0px;
+ color: #1B79BD;
+ border: none;
+ width: auto;
+ font-family: Arial;
+ line-height: 14px;
+ margin-left: 6px;
+ font-size: 13px;
+ box-shadow: none;
+}
+.question-page .comments .comment-body .convert-comment input:hover {
+ text-decoration: underline;
+ cursor: pointer;
+}
+.question-page .comments .comment-body p {
+ font-size: 13px;
+ line-height: 1.3;
+ margin-bottom: 3px;
+ padding: 0;
+}
+.question-page .comments .comment-delete {
+ float: right;
+ width: 14px;
+ line-height: 130%;
+ padding: 8px 6px;
+}
+.question-page .comments .upvote {
+ margin: 0px;
+ padding-right: 17px;
+ padding-top: 2px;
+ text-align: right;
+ height: 20px;
+ font-size: 13px;
+ font-weight: bold;
+ color: #777;
+}
+.question-page .comments .upvote.upvoted {
+ color: #d64000;
+}
+.question-page .comments .upvote.hover {
+ background: url(../images/go-up-grey.png) no-repeat;
+ background-position: right 1px;
+}
+.question-page .comments .upvote:hover {
+ background: url(../images/go-up-orange.png) no-repeat;
+ background-position: right 1px;
+}
+.question-page .comments .help-text {
+ float: right;
+ text-align: right;
+ color: gray;
+ margin-bottom: 0px;
+ margin-top: 0px;
+ line-height: 50%;
+}
+.question-page #questionTools {
+ font-size: 22px;
+ margin-top: 11px;
+ text-align: left;
+}
+.question-page .question-status {
+ margin-top: 10px;
+ margin-bottom: 15px;
+ padding: 20px;
+ background-color: #fef7cc;
+ text-align: center;
+ border: #e1c04a 1px solid;
+}
+.question-page .question-status h3 {
+ font-size: 20px;
+ color: #707070;
+ font-weight: normal;
+}
+.question-page .vote-buttons {
+ float: left;
+ text-align: center;
+ padding-top: 2px;
+ margin: 0px 10px 0px 3px;
+ /* small IE fixes */
+
+ *margin: 0;
+ *height: 210px;
+ *width: 30px;
+}
+.question-page .vote-buttons IMG {
+ cursor: pointer;
+}
+.question-page .vote-number {
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ padding: 2px 0 5px 0;
+ font-size: 25px;
+ font-weight: bold;
+ color: #777;
+}
+.question-page .vote-buttons .notify-sidebar {
+ text-align: left;
+ width: 130px;
+ margin-top: 7px;
+}
+.question-page .vote-buttons .notify-sidebar label {
+ vertical-align: top;
+}
+.question-page .tabBar-answer {
+ margin-bottom: 15px;
+ padding-left: 7px;
+ width: 723px;
+ margin-top: 10px;
+}
+.question-page .answer .vote-buttons {
+ float: left;
+ margin-top: 10px;
+}
+.question-page .accepted-answer {
+ background-color: #f7fecc;
+ border-bottom-color: #9BD59B;
+}
+.question-page .accepted-answer .vote-buttons {
+ width: 27px;
+ margin-right: 10px;
+ margin-top: 10px;
+}
+.question-page .answer .post-update-info a {
+ color: #444444;
+}
+.question-page .answered {
+ background: #CCC;
+ color: #999;
+}
+.question-page .answered-accepted {
+ background: #DCDCDC;
+ color: #763333;
+}
+.question-page .answered-accepted strong {
+ color: #E1E818;
+}
+.question-page .answered-by-owner {
+ background: #F1F1FF;
+}
+.question-page .answered-by-owner .comments .button {
+ background-color: #E6ECFF;
+}
+.question-page .answered-by-owner .comments {
+ background-color: #E6ECFF;
+}
+.question-page .answered-by-owner .vote-buttons {
+ margin-right: 10px;
+}
+.question-page .answer-img-accept {
+ background: url(../images/vote-accepted.png);
+ width: 23px;
+ height: 23px;
+}
+.question-page .accepted-answer .answer-img-accept,
+.question-page .answer-img-accept:hover {
+ background: url(../images/vote-accepted-on.png);
+}
+.question-page .answer-body a {
+ color: #1b79bd;
+}
+.question-page .answer-body li {
+ margin-bottom: 0.7em;
+}
+.question-page #fmanswer {
+ color: #707070;
+ line-height: 1.2;
+ margin-top: 10px;
+}
+.question-page #fmanswer h2 {
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ color: #7ea9b3;
+ font-size: 24px;
+}
+.question-page #fmanswer label {
+ font-size: 13px;
+}
+.question-page .message {
+ padding: 5px;
+ margin: 0px 0 10px 0;
+}
+.facebook-share.icon,
+.twitter-share.icon,
+.linkedin-share.icon,
+.identica-share.icon {
+ background: url(../images/socialsprite.png) no-repeat;
+ display: block;
+ text-indent: -100em;
+ height: 25px;
+ width: 25px;
+ margin-bottom: 3px;
+}
+.facebook-share.icon:hover,
+.twitter-share.icon:hover,
+.linkedin-share.icon:hover,
+.identica-share.icon:hover {
+ opacity: 0.8;
+ filter: alpha(opacity=80);
+}
+.facebook-share.icon {
+ background-position: -26px 0px;
+}
+.identica-share.icon {
+ background-position: -78px 0px;
+}
+.twitter-share.icon {
+ margin-top: 10px;
+ background-position: 0px 0px;
+}
+.linkedin-share.icon {
+ background-position: -52px 0px;
+}
+/* -----Content pages, Login, About, FAQ, Users----- */
+.openid-signin,
+.meta,
+.user-profile-edit-page {
+ font-size: 13px;
+ line-height: 1.3;
+ color: #525252;
+}
+.openid-signin p,
+.meta p,
+.user-profile-edit-page p {
+ font-size: 13px;
+ color: #707070;
+ line-height: 1.3;
+ font-family: Arial;
+ color: #525252;
+ margin-bottom: 12px;
+}
+.openid-signin h2,
+.meta h2,
+.user-profile-edit-page h2 {
+ color: #525252;
+ padding-left: 0px;
+ font-size: 16px;
+}
+.openid-signin form,
+.meta form,
+.users-page form,
+.user-profile-edit-page form,
+.user-profile-page form {
+ margin-bottom: 15px;
+}
+.openid-signin input[type="text"],
+.meta input[type="text"],
+.users-page input[type="text"],
+.user-profile-edit-page input[type="text"],
+.user-profile-page input[type="text"],
+.openid-signin input[type="password"],
+.meta input[type="password"],
+.users-page input[type="password"],
+.user-profile-edit-page input[type="password"],
+.user-profile-page input[type="password"],
+.openid-signin select,
+.meta select,
+.users-page select,
+.user-profile-edit-page select,
+.user-profile-page select {
+ border: #cce6ec 3px solid;
+ height: 25px;
+ padding-left: 5px;
+ width: 395px;
+ font-size: 14px;
+}
+.openid-signin select,
+.meta select,
+.users-page select,
+.user-profile-edit-page select,
+.user-profile-page select {
+ width: 405px;
+ height: 30px;
+}
+.openid-signin textarea,
+.meta textarea,
+.users-page textarea,
+.user-profile-edit-page textarea,
+.user-profile-page textarea {
+ border: #cce6ec 3px solid;
+ padding-left: 5px;
+ padding-top: 5px;
+ width: 395px;
+ font-size: 14px;
+}
+.openid-signin input.submit,
+.meta input.submit,
+.users-page input.submit,
+.user-profile-edit-page input.submit,
+.user-profile-page input.submit {
+ font-weight: normal;
+ margin: 5px 0px;
+ height: 26px;
+ font-size: 15px;
+ text-align: center;
+ text-decoration: none;
+ cursor: pointer;
+ color: #4a757f;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+ border-top: #eaf2f3 1px solid;
+ background-color: #d1e2e5;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
+ background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ -webkit-box-shadow: 1px 1px 2px #636363;
+ -moz-box-shadow: 1px 1px 2px #636363;
+ box-shadow: 1px 1px 2px #636363;
+ font-family: Arial;
+}
+.openid-signin input.submit:hover,
+.meta input.submit:hover,
+.users-page input.submit:hover,
+.user-profile-edit-page input.submit:hover,
+.user-profile-page input.submit:hover {
+ background-color: #cde5e9;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
+ background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ text-decoration: none;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+}
+.openid-signin .cancel,
+.meta .cancel,
+.users-page .cancel,
+.user-profile-edit-page .cancel,
+.user-profile-page .cancel {
+ background: url(../images/small-button-cancel.png) repeat-x top !important;
+ color: #525252 !important;
+}
+.openid-signin .cancel:hover,
+.meta .cancel:hover,
+.users-page .cancel:hover,
+.user-profile-edit-page .cancel:hover,
+.user-profile-page .cancel:hover {
+ background: url(../images/small-button-cancel.png) repeat-x bottom !important;
+}
+.openid-signin .re,
+.meta .re,
+.users-page .re,
+.user-profile-edit-page .re,
+.user-profile-page .re {
+ float: left;
+ width: 960px;
+}
+.inbox-flags.user-profile-page .re {
+ width: 810px;
+}
+.inbox-flags.user-profile-page .post-moderation-controls {
+ float: left;
+ width: 150px;
+ margin-top: 23px;
+ text-align: right;
+}
+.inbox-flags.user-profile-page .dropdown:hover ul.dropdown-menu {
+ display: block;
+}
+.openid-signin form {
+ margin-bottom: 5px;
+}
+#email-input-fs,
+#local_login_buttons,
+#password-fs,
+#openid-fs {
+ margin-top: 10px;
+}
+#email-input-fs #id_email,
+#local_login_buttons #id_email,
+#password-fs #id_email,
+#openid-fs #id_email,
+#email-input-fs #id_username,
+#local_login_buttons #id_username,
+#password-fs #id_username,
+#openid-fs #id_username,
+#email-input-fs #id_password,
+#local_login_buttons #id_password,
+#password-fs #id_password,
+#openid-fs #id_password {
+ font-size: 12px;
+ line-height: 20px;
+ height: 20px;
+ margin: 0px;
+ padding: 0px 0 0 5px;
+ border: #cce6ec 3px solid;
+ width: 200px;
+}
+#email-input-fs .submit-b,
+#local_login_buttons .submit-b,
+#password-fs .submit-b,
+#openid-fs .submit-b {
+ height: 24px;
+ font-size: 15px;
+ text-align: center;
+ text-decoration: none;
+ cursor: pointer;
+ color: #4a757f;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+ border-top: #eaf2f3 1px solid;
+ background-color: #d1e2e5;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
+ background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ -webkit-box-shadow: 1px 1px 2px #636363;
+ -moz-box-shadow: 1px 1px 2px #636363;
+ box-shadow: 1px 1px 2px #636363;
+ font-family: Arial;
+ font-weight: bold;
+ padding-right: 10px;
+ border: 0;
+}
+#email-input-fs .submit-b:hover,
+#local_login_buttons .submit-b:hover,
+#password-fs .submit-b:hover,
+#openid-fs .submit-b:hover {
+ background-color: #cde5e9;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
+ background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ text-decoration: none;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+}
+.openid-input {
+ background: url(../images/openid.gif) no-repeat;
+ padding-left: 15px;
+ cursor: pointer;
+}
+.openid-login-input {
+ background-position: center left;
+ background: url(../images/openid.gif) no-repeat 0% 50%;
+ padding: 5px 5px 5px 15px;
+ cursor: pointer;
+ font-family: Trebuchet MS;
+ font-weight: 300;
+ font-size: 150%;
+ width: 500px;
+}
+.openid-login-submit {
+ height: 40px;
+ width: 80px;
+ line-height: 40px;
+ cursor: pointer;
+ border: 1px solid #777;
+ font-weight: bold;
+ font-size: 120%;
+}
+/* People page */
+/*.users-page .tabBar{
+ width:375px;
+}*/
+.users-page #group-openness-selector {
+ width: 200px;
+}
+.user {
+ padding: 5px 10px 5px 0;
+ line-height: 140%;
+ width: 166px;
+ height: 32px;
+ margin-bottom: 5px;
+}
+.user .user-micro-info {
+ color: #525252;
+}
+.user ul {
+ margin: 0;
+ list-style-type: none;
+}
+.user .thumb {
+ clear: both;
+ float: left;
+ margin-right: 4px;
+ display: inline;
+}
+/* tags page */
+.tabBar-tags {
+ margin-bottom: 15px;
+}
+/* badges page */
+a.medal {
+ font-size: 17px;
+ line-height: 250%;
+ margin-right: 5px;
+ color: #333;
+ text-decoration: none;
+ background: url(../images/medala.gif) no-repeat;
+ border-left: 1px solid #EEE;
+ border-top: 1px solid #EEE;
+ border-bottom: 1px solid #CCC;
+ border-right: 1px solid #CCC;
+ padding: 4px 12px 4px 6px;
+}
+a:hover.medal {
+ color: #333;
+ text-decoration: none;
+ background: url(../images/medala_on.gif) no-repeat;
+ border-left: 1px solid #E7E296;
+ border-top: 1px solid #E7E296;
+ border-bottom: 1px solid #D1CA3D;
+ border-right: 1px solid #D1CA3D;
+}
+#award-list .user {
+ float: left;
+ margin: 5px;
+}
+/* profile page */
+.tabBar-profile {
+ width: 100%;
+ margin-bottom: 15px;
+ float: left;
+}
+.user-profile-page {
+ font-size: 13px;
+ color: #525252;
+}
+.user-profile-page p {
+ font-size: 13px;
+ line-height: 1.3;
+ color: #525252;
+}
+.user-profile-page .avatar img {
+ border: #eee 1px solid;
+ padding: 5px;
+}
+.user-profile-page h2 {
+ padding: 10px 0px 10px 0px;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+}
+.user-details {
+ font-size: 13px;
+}
+.user-details h3 {
+ font-size: 16px;
+}
+.user-about {
+ background-color: #EEEEEE;
+ height: 200px;
+ line-height: 20px;
+ overflow: auto;
+ padding: 10px;
+ width: 90%;
+}
+.user-about p {
+ font-size: 13px;
+}
+.follow-toggle,
+.submit {
+ border: 0 !important;
+ font-weight: bold;
+ line-height: 26px;
+ margin-top: -2px;
+ height: 26px;
+ font-size: 14px;
+ text-align: center;
+ text-decoration: none;
+ cursor: pointer;
+ color: #4a757f;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+ border-top: #eaf2f3 1px solid;
+ background-color: #d1e2e5;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
+ background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ -webkit-box-shadow: 1px 1px 2px #636363;
+ -moz-box-shadow: 1px 1px 2px #636363;
+ box-shadow: 1px 1px 2px #636363;
+}
+.follow-toggle:hover,
+.submit:hover {
+ background-color: #cde5e9;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
+ background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
+ text-decoration: none;
+ text-shadow: 0px 1px 0px #c6d9dd;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+ text-decoration: none !important;
+}
+.follow-toggle .follow {
+ font-color: #000;
+ font-style: normal;
+}
+.follow-toggle .unfollow div.unfollow-red {
+ display: none;
+}
+.follow-toggle .unfollow:hover div.unfollow-red {
+ display: inline;
+ color: #fff;
+ font-weight: bold;
+ color: #A05736;
+}
+.follow-toggle .unfollow:hover div.unfollow-green {
+ display: none;
+}
+.count {
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ font-size: 200%;
+ font-weight: 700;
+ color: #777777;
+}
+.scoreNumber {
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ font-size: 35px;
+ font-weight: 800;
+ color: #777;
+ line-height: 40px;
+ /*letter-spacing:0px*/
+
+ margin-top: 3px;
+}
+.vote-count {
+ font-family: Arial;
+ font-size: 160%;
+ font-weight: 700;
+ color: #777;
+}
+.answer-summary {
+ display: block;
+ clear: both;
+ padding: 3px;
+}
+.answer-votes {
+ background-color: #EEEEEE;
+ color: #555555;
+ float: left;
+ font-family: Arial;
+ font-size: 15px;
+ font-weight: bold;
+ height: 17px;
+ padding: 2px 4px 5px;
+ text-align: center;
+ text-decoration: none;
+ width: 20px;
+ margin-right: 10px;
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+}
+.karma-summary {
+ padding: 5px;
+ font-size: 13px;
+}
+.karma-summary h3 {
+ text-align: center;
+ font-weight: bold;
+ padding: 5px;
+}
+.karma-diagram {
+ width: 477px;
+ height: 300px;
+ float: left;
+ margin-right: 10px;
+}
+.karma-details {
+ float: right;
+ width: 450px;
+ height: 250px;
+ overflow-y: auto;
+ word-wrap: break-word;
+}
+.karma-details p {
+ margin-bottom: 10px;
+}
+.karma-gained {
+ font-weight: bold;
+ background: #eee;
+ width: 25px;
+ margin-right: 5px;
+ color: green;
+ padding: 3px;
+ display: block;
+ float: left;
+ text-align: center;
+ border-radius: 3px;
+ -ms-border-radius: 3px;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ -khtml-border-radius: 3px;
+}
+.karma-lost {
+ font-weight: bold;
+ background: #eee;
+ width: 25px;
+ color: red;
+ padding: 3px;
+ display: block;
+ margin-right: 5px;
+ float: left;
+ text-align: center;
+ border-radius: 3px;
+ -ms-border-radius: 3px;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ -khtml-border-radius: 3px;
+}
+.submit-row {
+ margin-bottom: 10px;
+}
+/*----- Revision pages ----- */
+.revision {
+ margin: 10px 0 10px 0;
+ font-size: 13px;
+ color: #525252;
+}
+.revision p {
+ font-size: 13px;
+ line-height: 1.3;
+ color: #525252;
+}
+.revision h3 {
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ font-size: 21px;
+ padding-left: 0px;
+}
+.revision .header {
+ background-color: #F5F5F5;
+ padding: 5px;
+ cursor: pointer;
+}
+.revision .author {
+ background-color: #e9f3f5;
+}
+.revision .summary {
+ padding: 5px 0 10px 0;
+}
+.revision .summary span {
+ background-color: #fde785;
+ padding: 6px;
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ display: inline;
+ -webkit-box-shadow: 1px 1px 4px #cfb852;
+ -moz-box-shadow: 1px 1px 4px #cfb852;
+ box-shadow: 1px 1px 4px #cfb852;
+}
+.revision .answerbody {
+ padding: 10px 0 5px 10px;
+}
+.revision .revision-mark {
+ width: 150px;
+ text-align: left;
+ display: inline-block;
+ font-size: 11px;
+ overflow: hidden;
+}
+.revision .revision-mark .gravatar {
+ float: left;
+ margin-right: 4px;
+ padding-top: 5px;
+}
+.revision .revision-number {
+ font-size: 300%;
+ font-weight: bold;
+ font-family: sans-serif;
+}
+del,
+del .post-tag {
+ color: #C34719;
+}
+ins .post-tag,
+ins p,
+ins {
+ background-color: #E6F0A2;
+}
+/* ----- Red Popup notification ----- */
+.vote-notification {
+ z-index: 1;
+ cursor: pointer;
+ display: none;
+ position: absolute;
+ font-family: Arial;
+ font-size: 14px;
+ font-weight: normal;
+ color: white;
+ background-color: #8e0000;
+ text-align: center;
+ padding-bottom: 10px;
+ -webkit-box-shadow: 0px 2px 4px #370000;
+ -moz-box-shadow: 0px 2px 4px #370000;
+ box-shadow: 0px 2px 4px #370000;
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+}
+.vote-notification h3 {
+ background: url(../images/notification.png) repeat-x top;
+ padding: 10px 10px 10px 10px;
+ font-size: 13px;
+ margin-bottom: 5px;
+ border-top: #8e0000 1px solid;
+ color: #fff;
+ font-weight: normal;
+ border-top-right-radius: 4px;
+ border-top-left-radius: 4px;
+ -moz-border-radius-topright: 4px;
+ -moz-border-radius-topleft: 4px;
+ -webkit-border-top-left-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+}
+.vote-notification a {
+ color: #fb7321;
+ text-decoration: underline;
+ font-weight: bold;
+}
+/* ----- Footer links , check blocks/footer.html----- */
+#ground {
+ width: 100%;
+ clear: both;
+ border-top: 1px solid #000;
+ padding: 16px 0 0 0;
+ background: #16160f;
+ font-size: 16px;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+}
+#ground p {
+ margin-bottom: 0;
+}
+.footer-links {
+ color: #EEE;
+ text-align: left;
+ width: 450px;
+ float: left;
+}
+.footer-links a {
+ color: #e7e8a8;
+}
+.powered-link {
+ width: 450px;
+ float: left;
+ text-align: left;
+}
+.powered-link a {
+ color: #8ebcc7;
+}
+.copyright {
+ color: #616161;
+ width: 500px;
+ float: right;
+ text-align: right;
+}
+.copyright a {
+ color: #8ebcc7;
+}
+.copyright img.license-logo {
+ margin: 6px 0px 20px 10px;
+ float: right;
+}
+.notify-me {
+ float: left;
+}
+span.text-counter {
+ margin-right: 20px;
+}
+span.form-error {
+ color: #990000;
+ font-weight: normal;
+ margin-left: 5px;
+}
+ul.errorlist {
+ margin-bottom: 0;
+}
+p.form-item {
+ margin: 0px;
+}
+.deleted {
+ background: #F4E7E7 none repeat scroll 0 0;
+}
+/* openid styles */
+.form-row {
+ line-height: 25px;
+}
+table.form-as-table {
+ margin-top: 5px;
+}
+table.form-as-table ul {
+ list-style-type: none;
+ display: inline;
+}
+table.form-as-table li {
+ display: inline;
+}
+table.form-as-table td {
+ text-align: right;
+}
+table.form-as-table th {
+ text-align: left;
+ font-weight: normal;
+}
+table.ab-subscr-form {
+ width: 45em;
+}
+.submit-row {
+ line-height: 30px;
+ padding-top: 10px;
+ display: block;
+ clear: both;
+}
+.errors {
+ line-height: 20px;
+ color: red;
+}
+.error,
+.openid-signin p.error {
+ color: darkred;
+ margin: 0;
+ font-size: 12px;
+ font-weight: bold;
+ text-align: left;
+}
+.openid-signin p.error {
+ text-align: center;
+}
+label.retag-error {
+ color: darkred;
+ padding-left: 5px;
+ font-size: 10px;
+}
+.fieldset {
+ border: none;
+ margin-top: 10px;
+ padding: 10px;
+}
+span.form-error {
+ color: #990000;
+ font-size: 90%;
+ font-weight: normal;
+ margin-left: 5px;
+}
+/*
+.favorites-count-off {
+ color: #919191;
+ float: left;
+ text-align: center;
+}
+
+.favorites-count {
+ color: #D4A849;
+ float: left;
+ text-align: center;
+}
+*/
+/* todo: get rid of this in html */
+.favorites-empty {
+ width: 32px;
+ height: 45px;
+ float: left;
+}
+.user-info-table {
+ margin-bottom: 10px;
+ border-spacing: 0;
+}
+/* todo: remove this hack? */
+.user-stats-table .narrow {
+ width: 660px;
+}
+.narrow .summary h3 {
+ padding: 0px;
+ margin: 0px;
+}
+.timeago {
+ font-weight: bold;
+ text-decoration: none;
+}
+.narrow .tags {
+ float: left;
+}
+/* todo: make these more semantic */
+.user-action-1 {
+ font-weight: bold;
+ color: #333;
+}
+.user-action-2 {
+ font-weight: bold;
+ color: #CCC;
+}
+.user-action-3 {
+ color: #333;
+}
+.user-action-4 {
+ color: #333;
+}
+.user-action-5 {
+ color: darkred;
+}
+.user-action-6 {
+ color: darkred;
+}
+.user-action-7 {
+ color: #333;
+}
+.user-action-8 {
+ padding: 3px;
+ font-weight: bold;
+ background-color: #CCC;
+ color: #763333;
+}
+.revision-summary {
+ background-color: #FFFE9B;
+ padding: 2px;
+}
+.question-title-link a {
+ font-weight: bold;
+ color: #0077CC;
+}
+.answer-title-link a {
+ color: #333;
+}
+/* todo: make these more semantic */
+.post-type-1 a {
+ font-weight: bold;
+}
+.post-type-3 a {
+ font-weight: bold;
+}
+.post-type-5 a {
+ font-weight: bold;
+}
+.post-type-2 a {
+ color: #333;
+}
+.post-type-4 a {
+ color: #333;
+}
+.post-type-6 a {
+ color: #333;
+}
+.post-type-8 a {
+ color: #333;
+}
+.hilite {
+ background-color: #ff0;
+}
+.hilite1 {
+ background-color: #ff0;
+}
+.hilite2 {
+ background-color: #f0f;
+}
+.hilite3 {
+ background-color: #0ff;
+}
+.gold,
+.badge1 {
+ color: #FFCC00;
+}
+.silver,
+.badge2 {
+ color: #CCCCCC;
+}
+.bronze,
+.badge3 {
+ color: #CC9933;
+}
+.score {
+ font-weight: 800;
+ color: #333;
+}
+a.comment {
+ background: #EEE;
+ color: #993300;
+ padding: 5px;
+}
+a.offensive {
+ color: #999;
+}
+.message h1 {
+ padding-top: 0px;
+ font-size: 15px;
+}
+.message p {
+ margin-bottom: 0px;
+}
+p.space-above {
+ margin-top: 10px;
+}
+.warning {
+ color: red;
+}
+button::-moz-focus-inner {
+ padding: 0;
+ border: none;
+}
+.submit {
+ cursor: pointer;
+ /*letter-spacing:1px;*/
+
+ background-color: #D4D0C8;
+ height: 30px;
+ border: 1px solid #777777;
+ /* width:100px; */
+
+ font-weight: bold;
+ font-size: 120%;
+}
+.submit:hover {
+ text-decoration: underline;
+}
+.submit.small {
+ margin-right: 5px;
+ height: 20px;
+ font-weight: normal;
+ font-size: 12px;
+ padding: 1px 5px;
+}
+.submit.small:hover {
+ text-decoration: none;
+}
+.question-page a.submit {
+ display: -moz-inline-stack;
+ display: inline-block;
+ line-height: 30px;
+ padding: 0 5px;
+ *display: inline;
+}
+.noscript {
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ width: 100%;
+ z-index: 100;
+ padding: 5px 0;
+ text-align: center;
+ font-family: sans-serif;
+ font-size: 120%;
+ font-weight: Bold;
+ color: #FFFFFF;
+ background-color: #AE0000;
+}
+.big {
+ font-size: 14px;
+}
+.strong {
+ font-weight: bold;
+}
+.orange {
+ /* used in django.po */
+
+ color: #d64000;
+ font-weight: bold;
+}
+.grey {
+ color: #808080;
+}
+.about div {
+ padding: 10px 5px 10px 5px;
+ border-top: 1px dashed #aaaaaa;
+}
+.highlight {
+ background-color: #FFF8C6;
+}
+.nomargin {
+ margin: 0;
+}
+.margin-bottom {
+ margin-bottom: 10px;
+}
+.margin-top {
+ margin-top: 10px;
+}
+.inline-block {
+ display: inline-block;
+}
+.action-status {
+ margin: 0;
+ border: none;
+ text-align: center;
+ line-height: 10px;
+ font-size: 12px;
+ padding: 0;
+}
+.action-status span {
+ padding: 3px 5px 3px 5px;
+ background-color: #fff380;
+ /* nice yellow */
+
+ font-weight: normal;
+ -moz-border-radius: 5px;
+ -khtml-border-radius: 5px;
+ -webkit-border-radius: 5px;
+}
+.list-table {
+ border-spacing: 0;
+}
+.list-table td {
+ vertical-align: top;
+}
+/* these need to go */
+table.form-as-table .errorlist {
+ display: block;
+ margin: 0;
+ padding: 0 0 0 5px;
+ text-align: left;
+ font-size: 10px;
+ color: darkred;
+}
+table.form-as-table input {
+ display: inline;
+ margin-left: 4px;
+}
+table.form-as-table th {
+ vertical-align: bottom;
+ padding-bottom: 4px;
+}
+.form-row-vertical {
+ margin-top: 8px;
+ display: block;
+}
+.form-row-vertical label {
+ margin-bottom: 3px;
+ display: block;
+}
+/* above stuff needs to go */
+.text-align-right {
+ text-align: center;
+}
+ul.form-horizontal-rows {
+ list-style: none;
+ margin: 0;
+}
+ul.form-horizontal-rows li {
+ position: relative;
+ height: 40px;
+}
+ul.form-horizontal-rows label {
+ display: inline-block;
+}
+ul.form-horizontal-rows ul.errorlist {
+ list-style: none;
+ color: darkred;
+ font-size: 10px;
+ line-height: 10px;
+ position: absolute;
+ top: 2px;
+ left: 180px;
+ text-align: left;
+ margin: 0;
+}
+ul.form-horizontal-rows ul.errorlist li {
+ height: 10px;
+}
+ul.form-horizontal-rows label {
+ position: absolute;
+ left: 0px;
+ bottom: 6px;
+ margin: 0px;
+ line-height: 12px;
+ font-size: 12px;
+}
+ul.form-horizontal-rows li input {
+ position: absolute;
+ bottom: 0px;
+ left: 180px;
+ margin: 0px;
+}
+.narrow .summary {
+ float: left;
+}
+.user-profile-tool-links {
+ font-weight: bold;
+ vertical-align: top;
+}
+ul.post-tags {
+ margin-left: 3px;
+}
+ul.post-tags li {
+ margin-top: 4px;
+ margin-bottom: 3px;
+}
+ul.post-retag {
+ margin-bottom: 0px;
+ margin-left: 5px;
+}
+ul.post-retag input {
+ width: 400px;
+ height: 1.5em;
+ margin: 3px 0 0 -3px;
+}
+#question-controls .tags {
+ margin: 0 0 3px 0;
+}
+#tagSelector {
+ padding-bottom: 2px;
+ margin-bottom: 0;
+}
+#related-tags {
+ padding-left: 3px;
+}
+#hideIgnoredTagsControl {
+ margin: 5px 0 0 0;
+}
+#hideIgnoredTagsControl label {
+ font-size: 12px;
+ color: #666;
+}
+#hideIgnoredTagsCb {
+ margin: 0 2px 0 1px;
+}
+#recaptcha_widget_div {
+ width: 318px;
+ float: left;
+ clear: both;
+}
+p.signup_p {
+ margin: 20px 0px 0px 0px;
+}
+.simple-subscribe-options ul {
+ list-style: none;
+ list-style-position: outside;
+ margin: 0;
+}
+.simple-subscribe-options input {
+ display: inline;
+}
+/* a workaround to set link colors correctly */
+.wmd-preview a {
+ color: #1b79bd;
+}
+.wmd-preview li {
+ margin-bottom: 7px;
+ font-size: 14px;
+}
+.search-result-summary {
+ font-weight: bold;
+ font-size: 18px;
+ line-height: 22px;
+ margin: 0px 0px 0px 0px;
+ padding: 2px 0 0 0;
+ float: left;
+}
+.faq-rep-item {
+ text-align: right;
+ padding-right: 5px;
+}
+.user-info-table .gravatar {
+ margin: 0;
+}
+#responses {
+ clear: both;
+ line-height: 18px;
+ margin-bottom: 15px;
+}
+#responses div.face {
+ float: left;
+ text-align: center;
+ width: 54px;
+ padding: 3px;
+ overflow: hidden;
+}
+.response-parent {
+ margin-top: 18px;
+}
+.response-parent strong {
+ font-size: 20px;
+}
+.re {
+ min-height: 57px;
+ clear: both;
+ margin-top: 10px;
+}
+#responses input {
+ float: left;
+}
+#re_tools {
+ margin-bottom: 10px;
+}
+#re_sections {
+ margin-bottom: 6px;
+}
+#re_sections .on {
+ font-weight: bold;
+}
+.avatar-page ul {
+ list-style: none;
+}
+.avatar-page li {
+ display: inline;
+}
+.user-profile-page .avatar p {
+ margin-bottom: 0px;
+}
+.user-profile-page .tabBar a#stats {
+ margin-left: 0;
+}
+.user-profile-page img.gravatar {
+ margin: 2px 0 3px 0;
+}
+.user-profile-page h3 {
+ padding: 0;
+ margin-top: -3px;
+}
+.user-profile-page ul.tags {
+ margin-left: 5px;
+}
+.userList {
+ font-size: 13px;
+}
+img.flag {
+ border: 1px solid #eee;
+ vertical-align: text-top;
+}
+.main-page img.flag {
+ vertical-align: text-bottom;
+}
+/* Pretty printing styles. Used with prettify.js. */
+a.edit {
+ padding-left: 3px;
+ color: #145bff;
+}
+pre {
+ /* name conflict here with tags */
+
+}
+pre .str {
+ color: #080;
+}
+pre .kwd {
+ color: #008;
+}
+pre .com {
+ color: #800;
+}
+pre .typ {
+ color: #606;
+}
+pre .lit {
+ color: #066;
+}
+pre .pun {
+ color: #660;
+}
+pre .pln {
+ color: #000;
+}
+pre .tag {
+ color: #008;
+}
+pre .atn {
+ color: #606;
+}
+pre .atv {
+ color: #080;
+}
+pre .dec {
+ color: #606;
+}
+pre.prettyprint {
+ clear: both;
+ padding: 3px;
+ border: 0px solid #888;
+}
+@media print {
+ pre .str {
+ color: #060;
+ }
+ pre .kwd {
+ color: #006;
+ font-weight: bold;
+ }
+ pre .com {
+ color: #600;
+ font-style: italic;
+ }
+ pre .typ {
+ color: #404;
+ font-weight: bold;
+ }
+ pre .lit {
+ color: #044;
+ }
+ pre .pun {
+ color: #440;
+ }
+ pre .pln {
+ color: #000;
+ }
+ pre .tag {
+ color: #006;
+ font-weight: bold;
+ }
+ pre .atn {
+ color: #404;
+ }
+ pre .atv {
+ color: #060;
+ }
+}
+#leading-sidebar {
+ float: left;
+}
+/* language-specific fixes */
+body.lang-es #searchBar {
+ width: 398px;
+}
+body.lang-es #searchBar .searchInput {
+ width: 337px;
+}
+body.lang-es #searchBar .searchInputCancelable {
+ width: 302px;
+}
+body.anon.lang-es #searchBar {
+ width: 485px;
+}
+body.anon.lang-es #searchBar .searchInput {
+ width: 425px;
+}
+body.anon.lang-es #searchBar .searchInputCancelable {
+ width: 390px;
+}
+/* user groups */
+#user-groups ul {
+ margin-bottom: 0px;
+}
+#user-groups .delete-icon {
+ float: none;
+ display: inline;
+ color: #525252;
+ padding: 0 3px 0 3px;
+ background: #ccc;
+ border-radius: 4px;
+ line-height: inherit;
+ -moz-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ -webkit-border-radius: 4px;
+}
+#user-groups .delete-icon:hover {
+ color: white;
+ background: #b32f2f;
+}
+.question-page .post-update-info a.primary-group-name,
+a.primary-group-name {
+ color: #990E08;
+ font-weight: bold;
+}
+.users-page .wmd-prompt-dialog {
+ background: #ccc;
+}
+.group-wiki .content > p:last-child {
+ margin-bottom: 5px;
+}
+.group-wiki .group-logo {
+ float: left;
+ margin: 0 5px 3px 0;
+}
+.group-wiki .follow-toggle.group-join-btn {
+ margin: 4px auto 10px auto;
+ display: block;
+}
+.group-wiki .controls {
+ margin: 0 0 10px 0;
+}
+img.group-logo {
+ height: 60px;
+ /* important to align with the line spacing */
+
+}
+#groups-list {
+ margin-left: 0px;
+}
+#groups-list .group-name {
+ padding-right: 20px;
+}
+#groups-list td {
+ padding-bottom: 5px;
+}
+.groups-page #groups-list th,
+.groups-page #groups-list td {
+ padding-right: 20px;
+}
+.groups-page #groups-list th {
+ font-weight: bold;
+}
+.groups-page #groups-list th:nth-child(2),
+.groups-page #groups-list td:nth-child(2) {
+ text-align: center;
+}
+#reject-edit-modal input,
+#reject-edit-modal textarea {
+ width: 514px;
+}
+input.tipped-input,
+textarea.tipped-input {
+ padding-left: 5px;
+}
+.tipped-input.blank {
+ color: #707070;
+}
+.select-box {
+ margin: 0;
+}
+.select-box li {
+ list-style-type: none;
+ list-style-position: inside;
+ padding-left: 7px;
+ font-size: 14px;
+ line-height: 25px;
+}
+.select-box li input {
+ margin: 0 0 2px -5px;
+ font-size: 14px;
+ line-height: 14px;
+ vertical-align: middle;
+ color: #707070;
+}
+.select-box li.selected,
+.select-box li.selected:hover {
+ background-color: #fcf8e3;
+ color: #c09853;
+}
+.select-box li:hover {
+ background-color: #cecece;
+ color: white;
+}
+/* category selector */
+.category-selector {
+ border-spacing: 0;
+}
+.category-selector ul.select-box {
+ height: 150px;
+ width: 235px;
+ overflow: auto;
+ border: #ccc 3px solid;
+}
+.category-selector td {
+ vertical-align: top;
+}
+.category-selector li {
+ position: relative;
+ color: #707070;
+}
+.category-selector li.tree:after {
+ content: ">>";
+ position: absolute;
+ right: 5px;
+ font-weight: bold;
+}
+.category-selector li.selected.tree:after {
+ color: #C09853;
+}
+.category-selector th {
+ color: #707070;
+ font-style: italic;
+ font-size: 16px;
+ font-weight: normal;
+ padding-top: 5px;
+ text-align: left;
+}
+.question-page .category-selector ul.select-box {
+ width: 217px;
+}
+.question-page .category-selector ul.select-box input {
+ width: 95px;
+}
+.question-page .tag-editor {
+ width: 660px;
+ margin-left: 0;
+}
+.editor-status {
+ float: right;
+ margin: 7px 350px 0 0;
+ font-weight: bold;
+}
+.editor-status span {
+ display: none;
+}
+/* tag editor */
+.tag-editor {
+ height: 64px;
+ border: #ccc 3px solid;
+ padding-left: 8px;
+}
+.tag-editor ul.tags {
+ margin: 0;
+}
+.tag-editor ul.tags li {
+ margin-top: 8px;
+ height: 13px;
+}
+.tag-editor input.new-tags-input,
+.tag-editor input.new-tags-input:focus {
+ border: none;
+ font-size: 15px;
+ font-color: #707070;
+ line-height: 16px;
+ margin-top: 9px;
+ -webkit-box-shadow: none;
+ /* undo bootstrap glow */
+
+ -moz-box-shadow: none;
+ box-shadow: none;
+}
+/* fixes for bootstrap */
+.caret {
+ margin-bottom: 7px;
+}
+.btn-group {
+ text-align: left;
+}
+.btn-toolbar {
+ margin: 0;
+}
+.modal-footer {
+ text-align: left;
+}
+.modal p {
+ font-size: 14px;
+}
+.modal-body > textarea {
+ width: 515px;
+ margin-bottom: 0px;
+}
diff --git a/askbot/media/style/style.less b/askbot/media/style/style.less
new file mode 100644
index 00000000..607261ce
--- /dev/null
+++ b/askbot/media/style/style.less
@@ -0,0 +1,4005 @@
+@import url(jquery.autocomplete.css);
+@import "lib_style.less"; /* Library of predifined less functions styles */
+
+/* ----- General HTML Styles----- */
+
+body {
+ background: #FFF;
+ font-size: 14px;
+ line-height: 150%;
+ margin: 0;
+ padding: 0;
+ color: #666;
+ font-family:@body-font;
+}
+
+div {
+ margin: 0 auto;
+ padding: 0;
+}
+
+h1, h2, h3, h4, h5, h6, ul, li, dl, dt, dd, form, img, p {
+ margin: 0;
+ padding: 0;
+ border: none;
+}
+
+label {
+ vertical-align: middle;
+}
+
+hr {
+ border: none;
+ border-top: 1px dashed #ccccce;
+}
+
+input, select {
+ vertical-align: middle;
+ font-family: Trebuchet MS, "segoe ui", Helvetica, Tahoma, Verdana, MingLiu, PMingLiu, Arial, sans-serif;
+ margin-left:0px;
+}
+
+input[type="text"].prompt,
+input[type="password"].prompt,
+input.tipped-input.blank {
+ font-style: italic;
+ color: @info-text;
+}
+
+textarea:focus, input:focus{
+ outline: none;
+}
+
+iframe {
+ border: none;
+}
+
+p {
+ font-size: 14px;
+ line-height: 140%;
+ margin-bottom: 6px;
+}
+
+a {
+ color:@link;
+ text-decoration: none;
+ cursor: pointer;
+}
+
+h2 {
+ font-size: 21px;
+ padding: 3px 0 3px 5px;
+}
+
+h3 {
+ font-size: 19px;
+ padding: 3px 0 3px 5px;
+}
+
+ul {
+ list-style: disc;
+ margin-left: 20px;
+ padding-left: 0px;
+ margin-bottom: 1em;
+}
+
+ol {
+ list-style: decimal;
+ margin-left: 30px;
+ margin-bottom: 1em;
+ padding-left: 0px;
+}
+
+td ul {
+ vertical-align: middle;
+}
+
+li input {
+ margin: 3px 3px 4px 3px;
+}
+
+pre {
+ font-family: Consolas, Monaco, Liberation Mono, Lucida Console, Monospace;
+ font-size: 100%;
+ margin-bottom: 10px;
+ /*overflow: auto;*/
+ background-color: #F5F5F5;
+ padding-left: 5px;
+ padding-top: 5px;
+ /*width: 671px;*/
+ padding-bottom: 20px ! ie7;
+}
+
+code {
+ font-family: Consolas, Monaco, Liberation Mono, Lucida Console, Monospace;
+ font-size: 100%;
+
+}
+
+blockquote {
+ margin-bottom: 10px;
+ margin-right: 15px;
+ padding: 10px 0px 1px 10px;
+ background-color: #F5F5F5;
+}
+
+html {
+ overflow-y: scroll;
+}
+
+/* http://pathfindersoftware.com/2007/09/developers-note-2/ */
+* html .clearfix,
+* html .paginator {
+ height: 1;
+ overflow: visible;
+}
++ html .clearfix,
++ html .paginator {
+ min-height: 1%;
+}
+.clearfix:after,
+.paginator:after {
+ clear: both;
+ content:".";
+ display:block;
+ height: 0;
+ visibility: hidden;
+}
+
+.badges a {
+ color: #763333;
+ text-decoration: underline;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+.badge-context-toggle.active {
+ cursor: pointer;
+ text-decoration: underline;
+}
+
+h1 {
+ font-size: 24px;
+ padding: 0px 0 5px 0px;
+}
+
+
+/* ----- Extra space above for messages ----- */
+
+body.user-messages {
+ margin-top: 2.4em;
+}
+
+/* ----- Custom positions ----- */
+
+.left{float:left}
+.right{float:right}
+.clean{clear:both}
+.center{
+ margin: 0 auto;
+ padding: 0;
+}
+
+
+/* ----- Notify message bar , check blocks/system_messages.html ----- */
+
+.notify {
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ width: 100%;
+ z-index: 100;
+ padding: 0;
+ text-align: center;
+ background-color: #f5dd69;
+ font-family:@main-font;
+
+ .notification {
+ margin-top: 6px;
+ /*margin-bottom: 6px;*/
+ font-size: 16px;
+ color:#424242
+ }
+}
+
+#closeNotify {
+ position: absolute;
+ right: 5px;
+ top: 7px;
+ color: #735005;
+ text-decoration: none;
+ line-height: 18px;
+ .sprites(-6px,-5px);
+ cursor: pointer;
+ width:20px;
+ height:20px;
+}
+
+#closeNotify:hover {
+ .sprites(-26px,-5px);
+}
+
+/* ----- Header, check blocks/header.html ----- */
+
+#header {
+ margin-top: 0px;
+ background: @header-color;
+ font-family:@main-font;
+}
+
+.content-wrapper {/* wrapper positioning class */
+ width: 960px;
+ margin: auto;
+ position:relative;
+}
+
+#logo img{
+ padding: 5px 0px 5px 0px;
+ height: 75px;
+ width: auto;
+ float: left;
+}
+
+#userToolsNav {/* Navigation bar containing login link or user information, check widgets/user_navigation.html*/
+ height: 20px;
+ padding-bottom:5px;
+
+ a {
+ height: 35px;
+ text-align: right;
+ margin-left: 20px;
+ text-decoration: underline;
+ color:#d0e296;
+ font-size:16px;
+ }
+
+ a:first-child {
+ margin-left: 0;
+ }
+
+ a#ab-responses {
+ margin-left: 3px;
+ }
+
+ .user-info,.user-micro-info{
+ color:#b5b593;
+ }
+
+ a img {
+ vertical-align:middle;
+ margin-bottom:2px;
+ }
+
+ .user-info a {
+ margin: 0;
+ text-decoration: none;
+ }
+}
+
+#metaNav {/* Top Navigation bar containing links for tags, people and badges, check widgets/header.html */
+ float: right;/* for #header.with-logo it is modified */
+ margin-right: 7px;
+
+ a {
+ color: #e2e2ae;
+ padding: 0px 0px 0px 35px;
+ height: 35px;
+ line-height: 25px;
+ margin:5px 0px 0px 10px;
+ font-size: 18px;
+ font-weight: 100;
+ text-decoration: none;
+ display: block;
+ float: left;
+ }
+
+ a:hover {
+ text-decoration: underline;
+ }
+
+ a.on {
+ font-weight:bold;
+ color: #FFF;
+ text-decoration: none;
+ }
+
+ a.special {
+ font-size: 18px;
+ color: #B02B2C;
+ font-weight: bold;
+ text-decoration: none;
+ }
+
+ a.special:hover {
+ text-decoration: underline;
+ }
+
+ #navTags{
+ .sprites(0px,-95px);
+ }
+
+ #navUsers,
+ #navGroups{
+ .sprites(3px,-133px)
+ }
+
+ #navBadges{
+ .sprites(3px,-170px)
+ }
+
+ a.group-name {
+ padding: 0px;
+ float:center;
+ margin:5px 0px 5px 10px;
+ }
+
+ input.group-name{
+ border:none;
+ height: 25px;
+ font-size: 18px;
+ font-weight: 100;
+ text-decoration: none;
+ display: block;
+ margin: 0px 10px 0px 10px;
+ width: 140px;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ font-weight: 100;
+ }
+
+ input.group-name:focus{
+ border:none;
+ }
+
+ a.group-name:hover{
+ background-color: transparent;
+ }
+
+ span.dropdown:hover ul.dropdown-menu {
+ display: block;
+ }
+
+ div.dropdown-container:hover ul.dropdown-menu {
+ display: block;
+ }
+
+ .dropdown {
+ float:left;
+ }
+
+ .dropdown-menu{
+ border-top: none;
+ left: 7%;
+ a{
+ color: #666;
+ height: 25px;
+ }
+ }
+
+}
+
+#header.with-logo #userToolsNav {
+ position:absolute;
+ bottom: 0;
+ right:0px;
+}
+
+#header.without-logo #userToolsNav {
+ float:left;
+ margin-top: 7px;
+}
+
+
+#secondaryHeader{ /* Div containing Home button, scope navigation, search form and ask button, check blocks/secondary_header.html */
+ height:55px;
+ background:#e9e9e1;
+ border-bottom:#d3d3c2 1px solid;
+ border-top:#fcfcfc 1px solid;
+ margin-bottom:10px;
+ font-family:@main-font;
+
+ #homeButton{
+ border-right:#afaf9e 1px solid;
+ .sprites(-6px,-36px);
+ height:55px;
+ width:43px;
+ display:block;
+ float:left;
+ }
+
+ #homeButton:hover{
+ .sprites(-6px-45,-36px);
+ }
+
+ #scopeWrapper{
+ width:688px;
+ float:left;
+
+ a{
+ display:block;
+ float:left;
+ }
+
+ .scope-selector{
+ font-size:20px;
+ color:#7a7a6b;
+ height:55px;
+ line-height:55px;
+ margin-left:16px
+ }
+ .on{
+ background:url(../images/scopearrow.png) no-repeat center bottom;
+ }
+
+ .ask-message{
+ font-size:24px;
+ }
+ }
+}
+
+.validate-email-page {
+ label {
+ color: @info-text;
+ line-height: 1.35;
+ display: block;
+ margin: 10px 0;
+ }
+ #validation-code {
+ padding-left:5px;
+ border:#cce6ec 3px solid;
+ height:25px;
+ font-size: 14px;
+ width: 200px;
+ }
+ form {
+ margin-bottom: 30px;
+ }
+}
+
+#searchBar { /* Main search form , check widgets/search_bar.html */
+ display: inline-block;
+ background-color: #fff;
+ width: 400px;
+ border: 1px solid #c9c9b5;
+ float:right;
+ height:42px;
+ margin:6px 0px 0px 15px;
+
+ .searchInput, .searchInputCancelable{
+ font-size: 26px;
+ height: 39px;
+ font-weight:300;
+ background:#FFF;
+ border:0px;
+ color:#484848;
+ padding-left:10px;
+ padding-top: 1px;
+ font-family:@body-font;
+ vertical-align: top;
+ }
+
+ .searchInput,{
+ width: 340px;
+ }
+
+ .searchInputCancelable {
+ width: 305px;
+ }
+
+ .logoutsearch {
+ width: 337px;
+ }
+
+ .searchBtn {
+ font-size: 10px;
+ color: #666;
+ background-color: #eee;
+ height: 42px;
+ border:#FFF 1px solid;
+ line-height: 22px;
+ text-align: center;
+ float:right;
+ margin: 0px;
+ width:48px;
+ .sprites(-98px,-36px);
+ cursor:pointer;
+ }
+
+ .searchBtn:hover {
+ .sprites(-98px-48,-36px);
+ }
+
+ .cancelSearchBtn {
+ font-size: 30px;
+ color: #ce8888;
+ background:#fff;
+ height: 42px;
+ border:0px;
+ border-left:#deded0 1px solid;
+ text-align: center;
+ width: 35px;
+ cursor:pointer;
+ }
+
+ .cancelSearchBtn:hover {
+ color: #d84040;
+ }
+}
+
+body.anon {
+ #searchBar {
+ width: 500px;
+ .searchInput {
+ width: 440px;
+ }
+
+ .searchInputCancelable {
+ width: 405px;
+ }
+ }
+}
+
+
+#askButton{ /* check blocks/secondary_header.html and widgets/ask_button.html*/
+ line-height:44px;
+ margin-top:6px;
+ float:right;
+ text-transform:uppercase;
+ .button-style(42px, 20px);
+ width: 200px;/* to match width of sidebar */
+}
+
+#askButton:hover{
+ .button-style-hover;
+}
+
+/* ----- Content layout, check two_column_body.html or one_column_body.html ----- */
+
+#ContentLeft {
+ width: 730px;
+ float: left;
+ position: relative;
+ padding-bottom:10px;
+}
+
+#ContentRight {
+ width: 200px;
+ float: right;
+ padding: 0 0px 10px 0px;
+}
+
+#ContentFull {
+ float: left;
+ width: 960px;
+}
+
+/* ----- Sidebar Widgets Box, check main_page/sidebar.html or question/sidebar.html ----- */
+
+.box {
+ background: #fff;
+ padding: 4px 0px 10px 0px;
+ width:200px;
+
+ p {
+ margin-bottom: 4px;
+ color: @info-text;
+ font-family:@main-font;
+ font-size: 14px;
+ }
+
+ p.info-box-follow-up-links {
+ text-align: right;
+ margin: 0;
+ }
+
+ h2 {
+ padding-left: 0;
+ background:#eceeeb;
+ height:30px;
+ line-height:30px;
+ text-align:right;
+ font-size:18px !important;
+ font-weight:normal;
+ color:#656565;
+ padding-right:10px;
+ margin-bottom:10px;
+ font-family:@main-font;
+ width:190px;
+ }
+ h3{
+ color:#4a757f;
+ font-size:18px;
+ text-align:left;
+ font-weight:normal;
+ font-family:@main-font;
+ padding-left:0px;
+ }
+ .contributorback{
+ background: #eceeeb url(../images/contributorsback.png) no-repeat center left;
+ }
+
+ form {
+ margin: 0px;
+ }
+
+ label {
+ color: @info-text;
+ font-size:15px;
+ vertical-align: bottom;
+ display: inline;
+ text-align:left;
+ font-family:@main-font;
+ }
+
+ #displayTagFilterControl label,
+ #emailTagFilterControl label { /*Especial width just for the tag filter boxes in index page*/
+ width:160px;
+ }
+
+ ul {
+ margin-left: 22px;
+ }
+
+ li {
+ list-style-type: disc;
+ font-size: 13px;
+ line-height: 20px;
+ margin-bottom: 10px;
+ color:@info-text;
+ }
+ ul.tags {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ line-height: 170%;
+ display: block;
+ }
+ #displayTagFilterControl p label{
+ color:@info-text;
+ font-size:15px;
+ }
+
+ .inputs{
+ #interestingTagInput,
+ #ignoredTagInput,
+ #subscribedTagInput,
+ #ab-tag-search {
+ width:152px;
+ padding-left:5px;
+ border:#c9c9b5 1px solid;
+ height:25px;
+ font-size: 14px;
+ }
+ #ab-tag-search {
+ width: 138px;
+ }
+ #interestingTagAdd,
+ #ignoredTagAdd,
+ #subscribedTagAdd,
+ #ab-tag-search-add {
+ border:0;
+ font-weight:bold;
+ margin-top:-2px;
+ .button-style(27px, 14px);
+ .rounded-corners(4px);
+ }
+ #interestingTagAdd:hover,
+ #ignoredTagAdd:hover,
+ #ab-tag-search-add:hover {
+ .button-style-hover;
+ }
+ #ab-tag-search-add {
+ width: 47px;
+ }
+ }
+
+ img.gravatar {
+ margin:1px;
+ }
+
+/* widgets for question template */
+
+ a.followed, a.follow{
+ line-height:34px;
+ border:0;
+ font-weight:normal;
+ margin-top:3px;
+ display:block;
+ .button-style(34px,21px);
+ .center;
+ width: 130px;
+ }
+
+ a.followed:hover, a.follow:hover{
+ .button-style-hover;
+ .text-shadow(0px, 1px, 0px, #c6d9dd);
+ }
+
+ a.followed div.unfollow{
+ display:none;
+ }
+
+ a.followed:hover div{
+ display:none;
+ }
+ a.followed:hover div.unfollow{
+ display:inline;
+ color:#a05736;
+ }
+
+ .favorite-number {
+ padding: 5px 0 0 5px;
+ font-size: 100%;
+ font-family: Arial;
+ font-weight: bold;
+ color: #777;
+ text-align:center;
+ }
+
+ /* notify by email box */
+ .notify-sidebar #question-subscribe-sidebar {
+ margin: 0 0 0 3px;
+ }
+}
+
+.users-page .box label {
+ display: inline;
+ float: none;
+}
+
+.statsWidget p{
+ color:@info-text;
+ font-size:16px;
+ border-bottom:#cccccc 1px solid;
+ font-size:13px;
+
+ strong{
+ float:right;
+ padding-right:10px;
+ }
+}
+.questions-related {
+ word-wrap: break-word;
+
+ p {
+ line-height: 20px;
+ padding: 4px 0px 9px 0px;
+ font-size: 16px;
+ font-weight:normal;
+ border-bottom:#cccccc 1px solid;
+ }
+ p:first-child {
+ margin-top: -4px;
+ }
+ p:last-child {
+ border: none;
+ }
+ a {
+ font-size:13px;
+ line-height: 1.3;
+ }
+}
+/* tips and markdown help are widgets for ask template */
+
+#tips{
+ li{
+ color:@info-text;
+ font-size:13px;
+ list-style-image: url(../images/tips.png);
+ }
+ a{
+ font-size:16px;
+ }
+}
+
+#markdownHelp{
+ li{
+ color:@info-text;
+ font-size:13px;
+ }
+ a{
+ font-size:16px;
+ }
+}
+
+
+/* ----- Sorting top Tab, check main_page/tab_bar.html ------*/
+
+.tabBar {
+ background-color: #eff5f6;
+ height: 30px;
+ margin-bottom: 3px;
+ margin-top: 3px;
+ float:right;
+ font-family:@sort-font;
+ font-size:16px;
+ .rounded-corners(5px);
+}
+
+.tabBar h2 {
+ float: left;
+}
+
+.tabsA, .tabsC {
+ float: right;
+ position: relative;
+ display: block;
+ height: 20px;
+}
+
+/* tabsA - used for sorting */
+.tabsA { float: right; }
+.tabsC { float: left; }
+
+.tabsA a, .tabsC a{
+
+ border-left: 1px solid #d0e1e4;
+ color: @section-title;
+ display: block;
+ float: left;
+ height: 20px;
+ line-height: 20px;
+ padding:4px 7px 4px 7px;
+ text-decoration: none;
+}
+
+.tabsA a.on, .tabsC a.on, .tabsA a:hover, .tabsC a:hover {
+ color: @button-label;
+}
+
+.tabsA a.rev.on, tabsA a.rev.on:hover {
+}
+
+.tabsA .label, .tabsC .label {
+ float: left;
+ color: #646464;
+ margin:4px 5px 0px 8px;
+}
+
+.main-page .tabsA .label {
+ margin-left: 8px;
+}
+
+.tabsB a {
+ background: #eee;
+ border: 1px solid #eee;
+ color: #777;
+ display: block;
+ float: left;
+ height: 22px;
+ line-height: 28px;
+ margin: 5px 0px 0 4px;
+ padding: 0 11px 0 11px;
+ text-decoration: none;
+}
+
+.tabsC .first{
+ border:none;
+}
+
+.rss {
+ float: right;
+ font-size: 16px;
+ color: #f57900;
+ margin: 5px 0px 3px 7px;
+ width:52px;
+ padding-left: 2px;
+ padding-top:3px;
+ background:#fff url(../images/feed-icon-small.png) no-repeat center right;
+ float:right;
+ font-family:@sort-font;
+ font-size:16px;
+}
+
+.rss:hover {
+ color: #F4A731 !important;
+}
+
+/* ----- Headline, containing number of questions and tags selected, check main_page/headline.html ----- */
+
+#questionCount{
+ font-weight:bold;
+ font-size:20px;
+ color:@section-title;
+ width:200px;
+ float:left;
+ margin-bottom:6px;
+ padding-top: 6px;
+ font-family:@main-font;
+}
+
+#listSearchTags{
+ float:left;
+ margin-top:3px;
+ color:@info-text;
+ font-size:16px;
+ font-family:@main-font;
+}
+
+ul#searchTags {
+ margin-left:10px;
+ float:right;
+ padding-top:2px;
+}
+
+.search-tips {
+ font-size:16px;
+ line-height:17px;
+ color: @info-text;
+ margin:5px 0 10px 0;
+ padding:0px;
+ float:left;
+ font-family:@main-font;
+
+ a {
+ text-decoration: underline;
+ color: @link;
+ }
+}
+
+/* ----- Question list , check main_page/content.html and macros/macros.html----- */
+
+#question-list {
+ float: left;
+ position: relative;
+ background-color: #FFF;
+ padding: 0;
+ width: 100%;
+}
+
+.short-summary {
+ position: relative;
+ filter: inherit;
+ padding: 10px 0 3px 0;
+ border-bottom: 1px solid #DDDBCE;
+ margin-bottom:1px;
+ overflow: hidden;
+ width: 733px;
+ float: left;
+ /*background: url(../images/summary-background.png) repeat-x;*/
+
+ h2 {
+ font-size: 20px;
+ font-weight:normal;
+ line-height: 26px;
+ padding-left: 0;
+ margin-bottom:7px;
+ display:block;
+ font-family:@main-font;
+ }
+
+ a {
+ color:@question-link;
+ }
+
+ .userinfo {
+ text-align:right;
+ line-height:16px;
+ font-family:@body-font;
+ padding-right:4px;
+ }
+
+
+ .userinfo .timeago, span.anonymous
+ {
+ font-size: 11px;
+ clear:both;
+ font-weight: normal;
+ color: #555;
+ }
+
+ .userinfo a{
+ font-weight:bold;
+ font-size:11px;
+ }
+
+ .counts {
+ float: right;
+ margin: 4px 0 0 5px;
+ font-family:@main-font;
+ }
+
+ .counts .item-count {
+ padding:0px 5px 0px 5px;
+ font-size: 25px;
+ font-family:@main-font;
+ }
+
+ .counts .votes div,
+ .counts .views div,
+ .counts .answers div,
+ .counts .favorites div
+ {
+ margin-top:3px;
+ font-size: 14px;
+ line-height:14px;
+ color: #646464;
+ }
+
+ .tags {
+ margin: 0 0 0 1px;
+ }
+
+ .votes, .answers, .favorites, .views {
+ text-align: center;
+ margin: 0 3px;
+ padding: 8px 2px 0px 2px;
+ width: 51px;
+ float: right;
+ height:44px;
+ border:#dbdbd4 1px solid;
+ }
+
+ .votes{
+ background: url(../images/vote-background.png) repeat-x;
+ }
+
+ .answers{
+ background:url(../images/answers-background.png) repeat-x;
+ }
+
+ .views {
+ background:url(../images/view-background.png) repeat-x;
+ }
+
+ .no-votes .item-count {
+ color: #b1b5b6;
+ }
+ .some-votes .item-count {
+ color: #4a757f;
+ }
+
+ .no-answers .item-count {
+ color: #b1b5b6;
+ }
+ .some-answers .item-count {
+ color: #eab243;
+ }
+
+ .no-views .item-count {
+ color: #b1b5b6;
+ }
+ .some-views .item-count {
+ color: #d33f00;
+ }
+
+ .accepted .item-count {
+ background:url(../images/accept.png) no-repeat top right;
+ display: block;
+ text-align: center;
+ width: 40px;
+ color: #eab243;
+ }
+
+ .some-favorites .item-count {
+ background:#338333;
+ color:#d0f5a9;
+ }
+ .no-favorites .item-count {
+ background: #eab243;
+ color: yellow;
+ }
+
+}
+
+/* ----- Question list Paginator , check main_content/pager.html and macros/utils_macros.html----- */
+
+.evenMore {
+ font-size: 13px;
+ color:@info-text;
+ padding:15px 0px 10px 0px;
+ clear:both;
+}
+
+.evenMore a {
+ text-decoration: underline;
+ color:@link;
+}
+
+.pager {
+ margin-top: 10px;
+ margin-bottom: 16px;
+}
+
+.pagesize {
+ margin-top: 10px;
+ margin-bottom: 16px;
+ float: right;
+}
+
+.paginator {
+ padding: 5px 0 10px 0;
+ font-size:13px;
+ margin-bottom:10px;
+
+ .prev a, .prev a:visited,
+ .next a, .next a:visited {
+ background-color: #fff;
+ color: #777;
+ padding: 2px 4px 3px 4px;
+ }
+ a{
+ color:@section-title;
+ }
+ .prev {
+ margin-right: .5em;
+ }
+
+ .next {
+ margin-left: .5em;
+ }
+
+ .page a, .page a:visited, .curr {
+ padding: .25em;
+ background-color: #fff;
+ margin: 0em .25em;
+ color: #ff;
+ }
+
+ .curr {
+ background-color: #8ebcc7;
+ color: #fff;
+ font-weight: bold;
+ }
+ .next a, .prev a{
+ color:@section-title
+ }
+ .page a:hover,
+ .curr a:hover,
+ .prev a:hover,
+ .next a:hover {
+ color: #8C8C8C;
+ background-color: #E1E1E1;
+ text-decoration: none;
+ }
+
+ .text {
+ color: #777;
+ padding: .3em;
+ }
+
+ .paginator-container-left {
+ padding: 5px 0 10px 0;
+ }
+
+}
+
+/* ----- Tags Styles ----- */
+
+/* tag formatting is also copy-pasted in template
+ because it must be the same in the emails
+ askbot/models/__init__.py:format_instant_notification_email()
+*/
+
+/* tag cloud */
+
+.tag-size-1 {
+ font-size:12px;
+}
+.tag-size-2 {
+ font-size:13px;
+}
+.tag-size-3 {
+ font-size:14px;
+}
+.tag-size-4 {
+ font-size:15px;
+}
+.tag-size-5 {
+ font-size:16px;
+}
+.tag-size-6 {
+ font-size:17px;
+}
+.tag-size-7 {
+ font-size:18px;
+}
+.tag-size-8 {
+ font-size:19px;
+}
+.tag-size-9 {
+ font-size:20px;
+}
+.tag-size-10 {
+ font-size:21px;
+}
+
+ul.tags,
+ul.tags.marked-tags,
+ul#related-tags {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ line-height: 170%;
+ display: block;
+}
+
+ul.tags li {
+ float:left;
+ display: block;
+ margin: 0 8px 8px 0;
+ padding: 0;
+ height:20px;
+}
+
+.wildcard-tags {
+ clear: both;
+}
+
+ul.tags.marked-tags li,
+.wildcard-tags ul.tags li {
+ margin-bottom: 5px;
+}
+
+#tagSelector div.inputs {
+ clear: both;
+ float: none;
+ margin-bottom:10px;
+}
+
+.tags-page ul.tags li,
+ul#ab-user-tags li {
+ width: 160px;
+ margin:5px;
+ margin-left: 0;
+}
+.tags-page ul.tags {
+ margin-left: 5px;
+}
+
+ul#related-tags li {
+ margin: 0 5px 8px 0;
+ float: left;
+ clear: left;
+}
+
+/* .tag-left and .tag-right are for the sliding doors decoration of tags */
+
+.tag-left {
+ cursor: pointer;
+ display: block;
+ float: left;
+ height: 17px;
+ margin: 0 5px 0 0;
+ padding: 0;
+ .box-shadow(0px,0px,5px,#d3d6d7);
+}
+
+.tag-right {
+ background: #f3f6f6;
+ border:#fff 1px solid ;
+ border-top:#fff 2px solid;
+ outline:#cfdbdb 1px solid;
+ /* .box-shadow(0px,1px,0px,#88a8a8);*/
+ display: block;
+ float: left;
+ height: 17px;
+ line-height: 17px;
+ font-weight: normal;
+ font-size: 11px;
+ padding: 0px 8px 0px 8px;
+ text-decoration: none;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: middle;
+ font-family:@body-font;
+ color:#717179;
+}
+.deletable-tag {
+ margin-right: 3px;
+ white-space: nowrap;
+ .rounded-corners-right(4px);
+}
+
+.tags a.tag-right,
+.tags span.tag-right {
+ color: #585858;
+ text-decoration: none;
+
+}
+.tags a:hover{
+ color: #1A1A1A;
+}
+
+.users-page,
+.tags-page,
+.groups-page,
+.moderate-tags-page {
+ th {
+ padding-bottom: 5px;
+ font-weight: normal;
+ }
+ h1 {
+ float: left;
+ }
+}
+
+.moderate-tags-page {
+ button {
+ line-height: 18px;
+ }
+ table {
+ border-spacing: 0;
+ }
+ table.suggested-tags-table {
+ width: 100%;
+ }
+ th {
+ font-style: italic;
+ }
+ th, tr {
+ vertical-align: top;
+ text-align: left;
+ padding-right: 20px;
+ }
+ td.per-thread-controls {
+ width: 120px;/* 20px more to compensate for the padding */
+ height: 30px;
+ button {
+ display: none;
+ }
+ }
+ th.decision-col,
+ th.tags-col,
+ th.users-col {
+ width: 100px;
+ }
+ tr.per-tag-controls {
+ height: 30px;
+ text-align: center;
+ }
+ tr.thread-info {
+ a {
+ line-height: 18px;
+ }
+ }
+ tr.thread-info td {
+ padding-bottom: 5px;
+ }
+ td.tags-col,
+ td.users-col {
+ padding-top: 7px
+ }
+ td.thread-links-col {
+ padding-top: 5px;
+ }
+}
+
+.main-page h1 {
+ margin-right: 5px;
+}
+
+.delete-icon {
+ margin-top:-1px;
+ float: left;
+ height: 21px;
+ width:18px;
+ display: block;
+ line-height:20px;
+ text-align:center;
+ background: #bbcdcd;
+ cursor: default;
+ color:#fff;
+ border-top:#cfdbdb 1px solid;
+ font-family:@body-font;
+ .rounded-corners-right(4px);
+ .text-shadow(0px,1px,0px,#7ea0a0)
+
+}
+.delete-icon:hover {
+ background: #b32f2f;
+}
+
+
+
+.tag-number {
+ font-weight: normal;
+ float: left;
+ font-size:16px;
+ color:#5d5d5d;
+}
+
+.badges .tag-number {
+ float: none;
+ display: inline;
+ padding-right: 15px;
+}
+
+/* ----- Ask and Edit Question Form template----- */
+
+.section-title{
+ color:@section-title;
+ font-family:@main-font;
+ font-weight:bold;
+ font-size:24px;
+}
+
+#fmask{
+ margin-bottom:30px;
+ width:100%;
+}
+
+#askFormBar {
+ display:inline-block;
+ padding: 4px 7px 0px 0px;
+ margin-top:0px;
+
+ p{
+ margin:0 0 5px 0;
+ font-size:14px;
+ color:@info-text-dark;
+ line-height:1.4;
+ }
+ .questionTitleInput {
+ font-size: 24px;
+ line-height: 24px;
+ height: 36px;
+ margin: 0px;
+ padding: 0px 0 0 5px;
+ border:#cce6ec 3px solid;
+ width:719px;
+ }
+}
+
+.ask-page, .edit-question-page {
+
+ div#question-list {
+ border-bottom:#f0f0ec 1px solid;
+ float: none;
+ a {
+ line-height:30px;
+ }
+
+ }
+
+ div#question-list h2 {
+ font-size: 13px;
+ padding-bottom: 0;
+ color: @link;
+ border-top: #f0f0ec 1px solid;
+ border-left: #f0f0ec 1px solid;
+ min-height: 30px;
+ line-height: 30px;
+ font-weight: normal;
+ }
+
+ div#question-list span {
+ width:28px;
+ height:26px;
+ line-height:26px;
+ text-align:center;
+ margin-right: 10px;
+ float:left;
+ display:block;
+ color:#fff;
+ background: #b8d0d5;
+ .rounded-corners(3px);
+ }
+ label{
+ color:@info-text-dark;
+ font-size:13px;
+ }
+
+ #id_tags {
+ border:#cce6ec 3px solid;
+ height:25px;
+ padding-left:5px;
+ font-size:14px;
+ width:395px;
+ }
+}
+
+.ask-page,
+.question-page,
+.edit-question-page,
+.edit-answer-page {
+ #id_post_author_username,
+ #id_post_author_email {
+ border:#cce6ec 3px solid;
+ height:25px;
+ padding-left:5px;
+ font-size:14px;
+ width:186px;
+ }
+ #id_post_author_email {
+ margin-left: 10px;
+ }
+ table.proxy-user-info {
+ border-spacing: 0px;
+ width: 100%;
+
+ .form-item {
+ float: left;
+ }
+ }
+}
+
+.groups-input,
+.users-input {
+ width:152px;
+ padding-left:5px;
+ border:#c9c9b5 1px solid;
+ height:25px;
+ font-size: 14px;
+}
+
+.add-groups,
+.add-users {
+ border:0;
+ font-weight:bold;
+ margin-top:-2px;
+ .button-style(27px, 14px);
+ .rounded-corners(4px);
+}
+
+.share-input-col {
+ width: 160px;
+ text-align: center;
+}
+
+.add-everyone-group {
+ text-align: center;
+ margin: auto;
+ display: block;
+ padding: 0 10px;
+ height: 25px;
+}
+
+.add-groups:hover {
+ .button-style-hover;
+}
+
+#id_user,
+#id_user_author {
+ border:#cce6ec 3px solid;
+ height:25px;
+ padding-left:5px;
+ width:395px;
+ font-size:14px;
+}
+
+.groups-input,
+.users-input {
+ width:152px;
+ padding-left:5px;
+ border:#c9c9b5 1px solid;
+ height:25px;
+ font-size: 14px;
+}
+
+.add-groups,
+.add-users {
+ border:0;
+ font-weight:bold;
+ margin-top:-2px;
+ .button-style(27px, 14px);
+ .rounded-corners(4px);
+}
+
+.add-everyone-group {
+ text-align: center;
+ margin: auto;
+ display: block;
+ padding: 0 10px;
+}
+
+.add-groups:hover {
+ .button-style-hover;
+}
+
+#id_user,
+#id_user_author {
+ border:#cce6ec 3px solid;
+ height:25px;
+ padding-left:5px;
+ width:395px;
+ font-size:14px;
+}
+
+.title-desc {
+ color: @info-text;
+ font-size: 13px;
+ margin-bottom: 5px;
+}
+
+.ask-page, .question-page {
+ .title-desc, .tags-desc {
+ color: @info-text;
+ font-style: italic;
+ font-size: 16px;
+ }
+}
+
+#fmanswer input.submit,
+.ask-page input.submit,
+.edit-question-page input.submit {
+ float: left;
+ font-weight:normal;
+ margin-top:3px;
+ .button-style(34px,21px);
+ margin-right:7px;
+}
+
+#fmanswer input.submit:hover,
+.ask-page input.submit:hover,
+.edit-question-page input.submit:hover{
+ .button-style-hover;
+ .text-shadow(0px, 1px, 0px, #c6d9dd)
+}
+
+.wmd-container {
+ border:#cce6ec 3px solid;
+ min-height: 250px;
+ textarea {
+ border: none;
+ }
+}
+.users-page .wmd-container {
+ width: 200px;
+}
+.ask-page,
+.question-page,
+.edit-question-page,
+.edit-answer-page {
+ .wmd-container {
+ width: 723px;
+ }
+ #editor {
+ width: 710px;
+ padding: 6px;
+ }
+ .retagger-buttons {
+ button {
+ margin: 8px 10px 5px 0;
+ }
+ }
+}
+
+#editor { /* adjustment for editor preview */
+ display: block;
+ font-size: 100%;
+ min-height: 200px;
+ line-height: 18px;
+ margin: 0;
+ border: 0;
+}
+
+.users-page #editor {
+ width: 192px;
+}
+
+#id_title {
+ width: 100%;
+}
+
+.wmd-preview {
+ margin: 0;
+ padding: 5px;
+ background-color: #F5F5F5;
+ min-height: 20px;
+ overflow: auto;
+ font-size:13px;
+ font-family:@body-font;
+
+ p{
+ margin-bottom: 14px;
+ line-height: 1.4;
+ font-size: 14px;
+ }
+
+ p:last-child{
+ margin-bottom: 0;
+ }
+}
+
+.wmd-preview pre {
+ background-color: #E7F1F8;
+
+}
+
+.wmd-preview blockquote {
+ background-color: #eee;
+}
+
+.wmd-preview IMG {
+ max-width: 600px;
+}
+
+.defaultSkin table.mceLayout,
+.defaultSkin table.mceLayout tr.mceFirst td {
+ border: none;
+}
+.defaultSkin table.mceLayout tr.mceLast td {
+ border-bottom: none;
+}
+.mceStatusbar {
+ height: 5px;
+ background: #fff;
+}
+.defaultSkin span.mce_askbot_imageuploader {
+ background-position: -380px 0px;
+}
+.defaultSkin span.mce_askbot_attachment {
+ background-image: url(../images/attachment.png);
+ background-position: 0px 0px;
+}
+
+.user-page .wmd-buttons {
+ width: 725px;
+}
+
+.preview-toggle {
+ width: 100%;
+ color: #b6a475; /*letter-spacing:1px;*/
+ text-align: left;
+}
+
+.preview-toggle span:hover {
+ cursor: pointer;
+}
+
+.after-editor {
+ margin-top: 15px;
+ margin-bottom: 15px;
+}
+
+.checkbox {
+ margin-left:5px;
+ font-weight:normal;
+ cursor:help
+}
+
+.question-options {
+ margin-top: 1px;
+ color: #666;
+ line-height: 13px;
+ margin-bottom:5px;
+}
+.question-options label {
+ vertical-align: text-bottom;
+}
+
+.edit-content-html {
+ border-top: 1px dotted #D8D2A9;
+ border-bottom: 1px dotted #D8D2A9;
+ margin: 5px 0 5px 0;
+}
+
+.edit-question-page, #fmedit, .wmd-preview{
+ color:@info-text-dark;
+
+ #id_revision{
+ font-size:14px;
+ margin-top:5px;
+ margin-bottom:5px;
+ }
+ #id_title{
+ font-size: 24px;
+ line-height: 24px;
+ height: 36px;
+ margin: 0px;
+ padding: 0px 0 0 5px;
+ border:#cce6ec 3px solid;
+ width: 719px;
+ margin-bottom:10px;
+ }
+ #id_summary{
+ border:#cce6ec 3px solid;
+ height:25px;
+ padding-left:5px;
+ width:395px;
+ font-size:14px;
+ }
+ .title-desc{
+ margin-bottom:10px;
+ }
+}
+
+/* ----- Question template ----- */
+
+.question-page{
+
+ h1{
+ padding-top:0px;
+ font-family:@main-font;
+
+ a {
+ color:@question-link;
+ font-size:26px;
+ font-weight:normal;
+ line-height:1;
+ }
+ }
+
+ p.rss {
+ float:none;
+ clear:both;
+ padding: 3px 0 0 23px;
+ font-size: 15px;
+ width:130px;
+ background-position:center left;
+ margin-left:0px !important;
+ }
+
+ p.rss a {
+ font-family:@main-font;
+ vertical-align: top;
+ }
+
+ .question-content{
+ float:right;
+ width:682px;
+ margin-bottom:10px;
+ }
+
+ .question-content, .answer {
+ pre, code {
+ clear:both;
+ }
+ }
+
+ #question-table{
+ float:left;
+ border-top:#f0f0f0 1px solid;
+ }
+
+ #question-table,
+ .answer-table {
+ margin: 8px 0 6px 0;
+ border-spacing: 0px;
+ width: 670px;
+ padding-right:10px;
+ }
+
+ .answer-table {
+ margin-top:0px;
+ border-bottom: 1px solid #D4D4D4;
+ float:right;
+ }
+
+ .answer-table td,
+ #question-table td {
+ width:20px;
+ vertical-align:top;
+ }
+ .question-body, .answer-body {
+ overflow: auto;
+ margin-top:10px;
+ font-family:@body-font;
+ color:#4b4b4b;
+
+ p{
+ margin-bottom:14px;
+ line-height:1.4;
+ font-size:14px;
+ padding:0px 5px 5px 0px;
+ }
+
+ a {
+ color:@link;
+ }
+
+ li {
+ margin-bottom:7px;
+ }
+ }
+
+ .question-body IMG, .answer-body IMG {
+ max-width: 600px;
+ }
+
+ .post-update-info-container {
+ float: right;
+ width: 175px;
+ }
+
+ .post-update-info {
+ background: #fff url(../images/background-user-info.png) repeat-x bottom;
+ float: right;
+ font-size: 9px;
+ font-family:@secondary-font;
+ width: 158px;
+ padding:4px;
+ margin:0px 0px 5px 5px;
+ line-height: 14px;
+ .rounded-corners(4px);
+ .box-shadow (0px, 2px,1px,#bfbfbf);
+
+ p {
+ line-height: 13px;
+ font-size: 11px;
+ margin: 0 0 2px 1px;
+ padding: 0;
+ }
+ a{
+ color:#444;
+ }
+ .gravatar {
+ float: left;
+ margin-right: 4px;
+ }
+
+ p.tip {
+ color: #444;
+ line-height: 13px;
+ font-size: 10px;
+ }
+ }
+
+ .post-controls{
+ font-size: 11px;
+ line-height: 12px;
+ min-width: 200px;
+ padding-left: 5px;
+ text-align:right;
+ clear: left;
+ float: right;
+ margin-top:10px;
+ margin-bottom:8px;
+
+ a {
+ color: #777;
+ padding: 0px 7px 3px 18px;
+ cursor: pointer;
+ border: none;
+ font-size:12px;
+ font-family:@body-font;
+ text-decoration: none;
+ height:18px;
+ display:block;
+ float:right;
+ line-height:18px;
+ margin-top:-2px;
+ margin-left:4px;
+ }
+
+ a:hover {
+ background-color: #f5f0c9;
+ .rounded-corners(3px);
+
+ }
+ .sep {
+ color: #ccc;
+ float:right;
+ height:18px;
+ font-size:18px;
+ }
+ }
+ .post-controls, .answer-controls{
+ .question-delete{
+ background: url(../images/delete.png) no-repeat left 2px;
+ padding-left:11px;
+ }
+ .question-flag{
+ background: url(../images/flag.png) no-repeat center left;
+ }
+ .answer-publish{
+ background: url(../images/publish.png) no-repeat center left;
+ }
+ .answer-unpublish{
+ background: url(../images/unpublish.png) no-repeat 2px center;
+ }
+ .question-edit{
+ background: url(../images/edit2.png) no-repeat 2px center;
+ }
+ .question-retag{
+ background: url(../images/retag.png) no-repeat center left;
+ }
+ .question-close{
+ background: url(../images/close.png) no-repeat center left;
+ }
+ .permant-link{
+ background: url(../images/link.png) no-repeat center left;
+ }
+
+ .answer-convert{
+ float:right;
+ clear: left;
+ /*background: url(../images/link.png) no-repeat center left;*/
+ }
+
+ .answer-convert input{
+ font-size:12px;
+ color: #777;
+ font-family:@body-font;
+ text-decoration: none;
+ display:inline;
+ white-space:nowrap;
+ padding-left: 0px;
+ background: none;
+ border: none;
+ padding: 0px 7px 3px 18px;
+ float:right;
+ height:18px;
+ line-height:18px;
+ margin-top:-2px;
+ margin-left:4px;
+ box-shadow: none;
+ }
+
+ .answer-convert input:hover{
+ background-color: #f5f0c9;
+ .rounded-corners(3px);
+ }
+ }
+ .tabBar{
+ width:100%;
+ }
+
+ #questionCount{
+ float:left;
+ font-family:@main-font;
+ line-height:15px;
+ }
+
+ .question-img-upvote, .question-img-downvote,
+ .answer-img-upvote, .answer-img-downvote {
+ width: 25px;
+ height: 20px;
+ cursor:pointer;
+ }
+
+ .question-img-upvote, .answer-img-upvote {
+ background: url(../images/vote-arrow-up-new.png) no-repeat;
+ }
+
+ .question-img-downvote, .answer-img-downvote {
+ background: url(../images/vote-arrow-down-new.png) no-repeat;
+ }
+
+ .question-img-upvote:hover, .question-img-upvote.on,
+ .answer-img-upvote:hover, .answer-img-upvote.on {
+ background: url(../images/vote-arrow-up-on-new.png) no-repeat;
+ }
+
+ .question-img-downvote:hover, .question-img-downvote.on,
+ .answer-img-downvote:hover, .answer-img-downvote.on {
+ background: url(../images/vote-arrow-down-on-new.png) no-repeat;
+ }
+
+ #fmanswer_button{
+ margin:8px 0px;
+ }
+ .question-img-favorite:hover {
+ background: url(../images/vote-favorite-on.png)
+ }
+ div.comments {
+ padding: 0;
+ }
+ #comment-title{
+ font-weight:bold;
+ font-size:23px;
+ color:@section-title;
+ width:200px;
+ float:left;
+ font-family:@main-font;
+ }
+ .comments {
+ font-size: 12px;
+ clear: both;
+
+ div.controls {
+ clear: both;
+ float:left;
+ width: 100%;
+ margin: 3px 0 20px 5px;
+ }
+
+ .controls a {
+ color: #988e4c;
+ padding: 0 3px 2px 22px;
+ font-family:@body-font;
+ font-size:13px;
+ background:url(../images/comment.png) no-repeat center left;
+ }
+
+ .controls a:hover {
+ background-color: #f5f0c9;
+ text-decoration: none;
+ }
+
+ .button {
+ color: #988e4c;
+ font-size: 11px;
+ padding: 3px;
+ cursor: pointer;
+ }
+ a {
+ background-color: inherit;
+ color: @link;
+ padding: 0;
+ }
+
+ form.post-comments {
+ margin: 3px 26px 0 42px;
+ textarea{
+ font-size: 13px;
+ line-height: 1.3;
+
+ }
+ }
+
+ textarea {
+ height: 42px;
+ width:100%;
+ margin: 7px 0 5px 1px;
+ font-family: @body-font;
+ outline: none;
+ overflow:auto;
+ font-size: 12px;
+ line-height: 140%;
+ padding-left:2px;
+ padding-top:3px;
+ border:#cce6ec 3px solid;
+ }
+
+ input {
+ margin-left: 10px;
+ margin-top: 1px;
+ vertical-align: top;
+ width: 100px;
+ }
+ button{
+ line-height:25px;
+ margin-bottom:5px;
+ .button-style(27px, 12px);
+ font-family:@body-font;
+ font-weight:bold;
+ }
+ button:hover{
+ .button-style-hover;
+ }
+ .counter {
+ display: inline-block;
+ width: 245px;
+ float:right;
+ color:#b6a475 !important;
+ vertical-align: top;
+ font-family:@body-font;
+ float:right;
+ text-align:right;
+ }
+ .comment {
+ border-bottom: 1px solid #edeeeb;
+ clear:both;
+ margin: 0;
+ margin-top:8px;
+ padding-bottom:4px;
+ overflow: auto;
+ font-family:@body-font;
+ font-size:11px;
+ min-height: 25px;
+ background:#fff url(../images/comment-background.png) bottom repeat-x;
+ .rounded-corners(5px);
+ }
+ div.comment:hover {
+ background-color: #efefef;
+ }
+ a.author{
+ background-color: inherit;
+ color: @link;
+ padding: 0;
+ }
+
+ a.author:hover {
+ text-decoration: underline;
+ }
+ span.delete-icon{
+ background:url(../images/close-small.png) no-repeat;
+ border:0;
+ width:14px;
+ height:14px;
+ }
+ span.delete-icon:hover{
+ border:#BC564B 2px solid;
+ .rounded-corners(10px);
+ margin: -3px 0px 0px -2px;
+ }
+ .content {
+ margin-bottom: 7px;
+ }
+
+ .comment-votes {
+ float: left;
+ width: 37px;
+ line-height: 130%;
+ padding: 6px 5px 6px 3px;
+ }
+
+ .comment-body {
+ line-height: 1.3;
+ margin: 3px 26px 0 46px;
+ padding: 5px 3px;
+ color: #666;
+ font-size:13px;
+
+ .edit{
+ padding-left:6px;
+ }
+
+ .convert-comment{
+ display: inline;
+ white-space: nowrap;
+ padding-left: 0px;
+ }
+
+ .convert-comment input{
+ background: none;
+ padding: 0px;
+ color: #1B79BD;
+ border:none;
+ width:auto;
+ font-family: Arial;
+ line-height: 14px;
+ margin-left: 6px;
+ font-size: 13px;
+ box-shadow: none;
+ }
+
+ .convert-comment input:hover{
+ text-decoration:underline;
+ cursor:pointer;
+ }
+ }
+
+ .comment-body p{
+ font-size:13px;
+ line-height:1.3;
+ margin-bottom: 3px;
+ padding: 0;
+ }
+
+ .comment-delete {
+ float: right;
+ width: 14px;
+ line-height: 130%;
+ padding: 8px 6px;
+ }
+
+ .upvote {
+ margin: 0px;
+ padding-right: 17px;
+ padding-top: 2px;
+ text-align: right;
+ height: 20px;
+ font-size: 13px;
+ font-weight: bold;
+ color: #777;
+ }
+
+ .upvote.upvoted {
+ color: #d64000;
+ }
+
+ .upvote.hover {
+ background: url(../images/go-up-grey.png) no-repeat;
+ background-position: right 1px;
+ }
+
+ .upvote:hover {
+ background: url(../images/go-up-orange.png) no-repeat;
+ background-position: right 1px;
+ }
+
+ .help-text{
+ float: right;
+ text-align:right;
+ color: gray;
+ margin-bottom: 0px;
+ margin-top: 0px;
+ line-height: 50%;
+ }
+ }
+ #questionTools {
+ font-size: 22px;
+ margin-top: 11px;
+ text-align: left;
+ }
+
+ .question-status {
+ margin-top: 10px;
+ margin-bottom:15px;
+ padding: 20px;
+ background-color: #fef7cc;
+ text-align: center;
+ border:#e1c04a 1px solid;
+ }
+
+ .question-status h3 {
+ font-size: 20px;
+ color:@info-text;
+ font-weight:normal;
+ }
+
+ .vote-buttons {
+ float: left;
+ text-align: center;
+ padding-top: 2px;
+ margin:0px 10px 0px 3px;
+ /* small IE fixes */
+ *margin:0;
+ *height:210px;
+ *width:30px;
+ }
+
+ .vote-buttons IMG {
+ cursor: pointer;
+ }
+
+ .vote-number {
+ font-family: @main-font;
+ padding: 2px 0 5px 0;
+ font-size: 25px;
+ font-weight: bold;
+ color: #777;
+ }
+
+ .vote-buttons .notify-sidebar {
+ text-align: left;
+ width:130px;
+ margin-top: 7px;
+ label {
+ vertical-align: top;
+ }
+ }
+
+ .tabBar-answer{
+ margin-bottom:15px;
+ padding-left:7px;
+ width:723px;
+ margin-top:10px;
+ }
+ .answer{
+ .vote-buttons {
+ float:left;
+ margin-top: 10px;
+ }
+ }
+ .accepted-answer {
+ background-color: #f7fecc;
+ border-bottom-color: #9BD59B;
+
+ .vote-buttons {
+ width:27px;
+ margin-right:10px;
+ margin-top:10px;
+ }
+ }
+
+ .answer .post-update-info a{
+ color:#444444;
+ }
+
+ .answered {
+ background: #CCC;
+ color: #999;
+ }
+
+ .answered-accepted {
+ background: #DCDCDC;
+ color: #763333;
+
+ strong {
+ color: #E1E818;
+ }
+ }
+
+ .answered-by-owner {
+ background: #F1F1FF;
+
+ .comments .button {
+ background-color: #E6ECFF;
+ }
+ .comments {
+ background-color: #E6ECFF;
+ }
+ .vote-buttons {
+ margin-right:10px;
+ }
+ }
+
+ .answer-img-accept {
+ background: url(../images/vote-accepted.png);
+ width: 23px;
+ height: 23px;
+ }
+
+ .accepted-answer .answer-img-accept,
+ .answer-img-accept:hover {
+ background: url(../images/vote-accepted-on.png)
+ }
+
+ .answer-body a {
+ color:@link;
+ }
+ .answer-body li {
+ margin-bottom:0.7em;
+ }
+
+ #fmanswer{
+ color:@info-text;
+ line-height:1.2;
+ margin-top:10px;
+
+ h2{
+ font-family:@main-font;
+ color:@section-title;
+ font-size:24px;
+ }
+ label{
+ font-size:13px;
+ }
+ }
+ .message {
+ padding: 5px;
+ margin: 0px 0 10px 0;
+
+ }
+
+}
+
+.facebook-share.icon, .twitter-share.icon, .linkedin-share.icon, .identica-share.icon {
+ background: url(../images/socialsprite.png) no-repeat;
+ display:block;
+ text-indent:-100em;
+ height:25px;
+ width:25px;
+ margin-bottom:3px;
+}
+
+.facebook-share.icon:hover, .twitter-share.icon:hover, .linkedin-share.icon:hover, .identica-share.icon:hover{
+ opacity:0.8;
+ filter: alpha(opacity=80);
+}
+
+.facebook-share.icon {
+ background-position: -26px 0px;
+}
+.identica-share.icon {
+ background-position: -78px 0px;
+}
+.twitter-share.icon {
+ margin-top:10px;
+ background-position: 0px 0px;
+}
+.linkedin-share.icon {
+ background-position: -52px 0px;
+}
+
+/* -----Content pages, Login, About, FAQ, Users----- */
+
+.openid-signin,
+.meta,
+.user-profile-edit-page,
+{
+ font-size:13px;
+ line-height:1.3;
+ color:@info-text-dark;
+ p{
+ font-size:13px;
+ color:@info-text;
+ line-height:1.3;
+ font-family:@body-font;
+ color:@info-text-dark;
+ margin-bottom:12px;
+ }
+ h2{
+ color:@info-text-dark;
+ padding-left:0px;
+ font-size:16px;
+ }
+}
+
+.openid-signin,
+.meta,
+.users-page,
+.user-profile-edit-page,
+.user-profile-page,
+{
+ form{
+ margin-bottom:15px;
+ }
+ input[type="text"],input[type="password"],select{
+ border:#cce6ec 3px solid;
+ height:25px;
+ padding-left:5px;
+ width:395px;
+ font-size:14px;
+ }
+ select{
+ width:405px;
+ height:30px;
+ }
+ textarea{
+ border:#cce6ec 3px solid;
+ padding-left:5px;
+ padding-top:5px;
+ width:395px;
+ font-size:14px;
+ }
+ input.submit{
+ font-weight:normal;
+ margin:5px 0px;
+ .button-style(26px,15px);
+ font-family:@body-font;
+ }
+ input.submit:hover{
+ .button-style-hover;
+ }
+ .cancel{
+ background:url(../images/small-button-cancel.png) repeat-x top !important;
+ color:#525252 !important;
+ }
+ .cancel:hover{
+ background:url(../images/small-button-cancel.png) repeat-x bottom !important;
+ }
+ .re {
+ float: left;
+ width: 960px;
+ }
+}
+
+.inbox-flags.user-profile-page {
+ .re {
+ width: 810px;
+ }
+ .post-moderation-controls {
+ float: left;
+ width: 150px;
+ margin-top: 23px;
+ text-align: right;
+ }
+ .dropdown:hover {
+ ul.dropdown-menu {
+ display: block;
+ }
+ }
+}
+
+.openid-signin form {
+ margin-bottom: 5px;
+}
+
+#email-input-fs,#local_login_buttons,#password-fs,#openid-fs{
+ margin-top:10px;
+ #id_email,#id_username,#id_password{
+ font-size: 12px;
+ line-height: 20px;
+ height: 20px;
+ margin: 0px;
+ padding: 0px 0 0 5px;
+ border:#cce6ec 3px solid;
+ width:200px;
+ }
+ .submit-b{
+ .button-style(24px,15px);
+ font-family:@body-font;
+ font-weight:bold;
+ padding-right:10px;
+ border:0;
+ }
+
+ .submit-b:hover{
+ .button-style-hover;
+ }
+}
+
+
+.openid-input {
+ background: url(../images/openid.gif) no-repeat;
+ padding-left: 15px;
+ cursor: pointer;
+}
+
+.openid-login-input {
+ background-position: center left;
+ background: url(../images/openid.gif) no-repeat 0% 50%;
+ padding: 5px 5px 5px 15px;
+ cursor: pointer;
+ font-family: Trebuchet MS;
+ font-weight: 300;
+ font-size: 150%;
+ width: 500px;
+}
+
+.openid-login-submit {
+ height: 40px;
+ width: 80px;
+ line-height: 40px;
+ cursor: pointer;
+ border: 1px solid #777;
+ font-weight: bold;
+ font-size: 120%;
+}
+
+/* People page */
+
+/*.users-page .tabBar{
+ width:375px;
+}*/
+
+.users-page #group-openness-selector {
+ width: 200px;
+}
+
+.user {
+ padding: 5px 10px 5px 0;
+ line-height: 140%;
+ width: 166px;
+ height: 32px;
+ margin-bottom:5px;
+ .user-micro-info{
+ color:@info-text-dark;
+ }
+
+}
+
+.user ul {
+ margin: 0;
+ list-style-type: none;
+}
+
+.user .thumb {
+ clear: both;
+ float: left;
+ margin-right: 4px;
+ display: inline;
+}
+
+/* tags page */
+
+.tabBar-tags{
+ margin-bottom:15px;
+}
+
+/* badges page */
+
+a.medal {
+ font-size: 17px;
+ line-height: 250%;
+ margin-right:5px;
+ color: #333;
+ text-decoration: none;
+ background: url(../images/medala.gif) no-repeat;
+ border-left: 1px solid #EEE;
+ border-top: 1px solid #EEE;
+ border-bottom: 1px solid #CCC;
+ border-right: 1px solid #CCC;
+ padding: 4px 12px 4px 6px;
+}
+
+a:hover.medal {
+ color: #333;
+ text-decoration: none;
+ background: url(../images/medala_on.gif) no-repeat;
+ border-left: 1px solid #E7E296;
+ border-top: 1px solid #E7E296;
+ border-bottom: 1px solid #D1CA3D;
+ border-right: 1px solid #D1CA3D;
+}
+
+#award-list{
+ .user{
+ float:left;
+ margin:5px;
+ }
+}
+
+/* profile page */
+
+.tabBar-profile{
+ width:100%;
+ margin-bottom:5px;
+ float:left;
+}
+
+.user-profile-page{
+ font-size:13px;
+ color:@info-text-dark;
+
+ p{
+ font-size:13px;
+ line-height:1.3;
+ color:@info-text-dark;
+ }
+ .avatar img{
+ border:#eee 1px solid;
+ padding:5px;
+ }
+ h2{
+ padding:10px 0px 10px 0px;
+ font-family:@main-font;
+ }
+}
+
+.user-details {
+ font-size: 13px;
+ h3{
+ font-size:16px;
+ }
+}
+
+.user-about {
+ background-color: #EEEEEE;
+ height: 200px;
+ line-height: 20px;
+ overflow: auto;
+ padding: 10px;
+ width: 90%;
+ p{font-size:13px;}
+}
+
+.follow-toggle,.submit {
+ border:0 !important;
+ font-weight:bold;
+ line-height:26px;
+ margin-top:-2px;
+ .button-style(26px,14px);
+}
+
+.follow-toggle:hover, .submit:hover {
+ .button-style-hover;
+ text-decoration:none !important;
+}
+
+.follow-toggle .follow{
+ font-color: #000;
+ font-style:normal;
+}
+
+.follow-toggle .unfollow div.unfollow-red{
+ display:none;
+}
+
+.follow-toggle .unfollow:hover div.unfollow-red{
+ display:inline;
+ color:#fff;
+ font-weight:bold;
+ color:#A05736;
+}
+
+.follow-toggle .unfollow:hover div.unfollow-green{
+ display:none;
+}
+
+.count {
+ font-family: @main-font;
+ font-size: 200%;
+ font-weight: 700;
+ color: #777
+}
+
+.scoreNumber {
+ font-family: @main-font;
+ font-size: 35px;
+ font-weight: 800;
+ color: #777;
+ line-height: 40px; /*letter-spacing:0px*/
+ margin-top: 3px;
+}
+
+.vote-count {
+ font-family: Arial;
+ font-size: 160%;
+ font-weight: 700;
+ color: #777;
+}
+
+.answer-summary {
+ display: block;
+ clear: both;
+ padding: 3px;
+}
+
+.answer-votes {
+ background-color: #EEEEEE;
+ color: #555555;
+ float: left;
+ font-family: Arial;
+ font-size: 15px;
+ font-weight: bold;
+ height: 17px;
+ padding: 2px 4px 5px;
+ text-align: center;
+ text-decoration: none;
+ width: 20px;
+ margin-right: 10px;
+ .rounded-corners(4px);
+}
+
+.karma-summary {
+ padding:5px;
+ font-size:13px;
+}
+
+.karma-summary h3 {
+ text-align: center;
+ font-weight: bold;
+ padding:5px;
+}
+
+.karma-diagram {
+ width:477px;
+ height:300px;
+ float:left;
+ margin-right:10px;
+}
+
+.karma-details {
+ float:right;
+ width:450px;
+ height:250px;
+ overflow-y:auto;
+ word-wrap:break-word;
+ p{margin-bottom:10px;}
+}
+
+.karma-gained {
+ font-weight:bold;
+ background:#eee;
+ width:25px;
+ margin-right:5px;
+ color:green;
+ padding:3px;
+ display:block;
+ float:left;
+ text-align:center;
+ .rounded-corners(3px);
+}
+
+.karma-lost {
+ font-weight:bold;
+ background:#eee;
+ width:25px;
+ color:red;
+ padding:3px;
+ display:block;
+ margin-right:5px;
+ float:left;
+ text-align:center;
+ .rounded-corners(3px);
+}
+
+.submit-row{
+ margin-bottom:10px;
+}
+
+/*----- Revision pages ----- */
+
+.revision {
+ margin: 10px 0 10px 0;
+ font-size: 13px;
+ color:@info-text-dark;
+
+ p{
+ font-size:13px;
+ line-height:1.3;
+ color:@info-text-dark;
+ }
+
+ h3{
+ font-family:@main-font;
+ font-size:21px;
+ padding-left:0px;
+ }
+
+ .header {
+ background-color: #F5F5F5;
+ padding: 5px;
+ cursor: pointer;
+ }
+
+ .author {
+ background-color: #e9f3f5;
+ }
+
+ .summary {
+ padding: 5px 0 10px 0;
+ }
+
+ .summary span {
+ background-color:#fde785;
+ padding:6px;
+ .rounded-corners(4px);
+ display: inline;
+ .box-shadow(1px, 1px, 4px, #cfb852);
+ }
+
+ .answerbody {
+ padding: 10px 0 5px 10px;
+ }
+
+ .revision-mark {
+ width: 150px;
+ text-align: left;
+ display: inline-block;
+ font-size: 11px;
+ overflow: hidden;
+
+ .gravatar{
+ float:left;
+ margin-right:4px;
+ padding-top:5px;
+ }
+ }
+
+ .revision-number {
+ font-size: 300%;
+ font-weight: bold;
+ font-family: sans-serif;
+ }
+}
+
+del, del .post-tag {
+ color: #C34719;
+}
+
+ins .post-tag, ins p, ins {
+ background-color: #E6F0A2;
+}
+
+/* ----- Red Popup notification ----- */
+
+.vote-notification {
+ z-index: 1;
+ cursor: pointer;
+ display: none;
+ position: absolute;
+ font-family:@secondary-font;
+ font-size:14px;
+ font-weight:normal;
+ color: white;
+ background-color: #8e0000;
+ text-align: center;
+ padding-bottom:10px;
+ .box-shadow(0px, 2px, 4px, #370000);
+ .rounded-corners(4px);
+
+ h3{
+ background:url(../images/notification.png) repeat-x top;
+ padding:10px 10px 10px 10px;
+ font-size:13px;
+ margin-bottom:5px;
+ border-top:#8e0000 1px solid;
+ color:#fff;
+ font-weight:normal;
+ .rounded-corners-top(4px);
+ }
+ a {
+ color: #fb7321;
+ text-decoration: underline;
+ font-weight:bold;
+ }
+
+}
+
+
+/* ----- Footer links , check blocks/footer.html----- */
+
+#ground {
+ width: 100%;
+ clear: both;
+ border-top: 1px solid #000;
+ padding: 16px 0 0 0;
+ background: @header-color;
+ font-size:16px;
+ font-family:@main-font;
+
+ p {
+ margin-bottom:0;
+ }
+}
+
+.footer-links {
+ color: #EEE;
+ text-align:left;
+ width:450px;
+ float:left;
+ a {
+ color: #e7e8a8;
+ }
+}
+
+.powered-link{
+ width:450px;
+ float:left;
+ text-align:left;
+ a{
+ color:#8ebcc7;
+ }
+}
+
+.copyright{
+ color:#616161;
+ width:500px;
+ float:right;
+ text-align:right;
+
+ a{
+ color:#8ebcc7;
+ }
+ img.license-logo {
+ margin: 6px 0px 20px 10px;
+ float:right;
+ }
+}
+
+
+.notify-me {
+ float: left;
+}
+
+
+span.text-counter {
+ margin-right: 20px;
+}
+
+span.form-error {
+ color: #990000;
+ font-weight: normal;
+ margin-left: 5px;
+}
+
+ul.errorlist {
+ margin-bottom: 0;
+}
+
+p.form-item {
+ margin: 0px;
+}
+
+
+
+
+.deleted {
+ background: #F4E7E7 none repeat scroll 0 0;
+}
+
+
+/* openid styles */
+.form-row {
+ line-height: 25px;
+}
+
+table.form-as-table {
+ margin-top: 5px;
+}
+
+table.form-as-table ul {
+ list-style-type: none;
+ display: inline;
+}
+
+table.form-as-table li {
+ display: inline;
+}
+
+table.form-as-table td {
+ text-align: right;
+}
+
+table.form-as-table th {
+ text-align: left;
+ font-weight: normal;
+}
+
+table.ab-subscr-form {
+ width: 45em;
+}
+
+.submit-row {
+ line-height: 30px;
+ padding-top: 10px;
+ display: block;
+ clear: both;
+}
+
+.errors {
+ line-height: 20px;
+ color: #990000;
+}
+
+.error,
+.openid-signin p.error {
+ color: darkred;
+ margin: 0;
+ font-size: 12px;
+ font-weight: bold;
+ text-align: left;
+}
+
+.openid-signin p.error {
+ text-align: center;
+}
+
+label.retag-error {
+ color: darkred;
+ padding-left: 5px;
+ font-size: 10px;
+}
+
+.fieldset {
+ border: none;
+ margin-top: 10px;
+ padding: 10px;
+}
+
+
+span.form-error {
+ color: #990000;
+ font-size: 90%;
+ font-weight: normal;
+ margin-left: 5px;
+}
+
+
+/*
+.favorites-count-off {
+ color: #919191;
+ float: left;
+ text-align: center;
+}
+
+.favorites-count {
+ color: #D4A849;
+ float: left;
+ text-align: center;
+}
+*/
+
+/* todo: get rid of this in html */
+.favorites-empty {
+ width: 32px;
+ height: 45px;
+ float: left;
+}
+
+.user-info-table {
+ margin-bottom: 10px;
+ border-spacing: 0;
+}
+
+/* todo: remove this hack? */
+.user-stats-table .narrow {
+ width: 660px;
+}
+
+.narrow .summary h3 {
+ padding: 0px;
+ margin: 0px;
+}
+
+.timeago {
+ font-weight: bold;
+ text-decoration: none;
+}
+
+.narrow .tags {
+ float: left;
+}
+
+
+
+
+/* todo: make these more semantic */
+.user-action-1 {
+ font-weight: bold;
+ color: #333;
+}
+
+.user-action-2 {
+ font-weight: bold;
+ color: #CCC;
+}
+
+.user-action-3 {
+ color: #333;
+}
+
+.user-action-4 {
+ color: #333;
+}
+
+.user-action-5 {
+ color: darkred;
+}
+
+.user-action-6 {
+ color: darkred;
+}
+
+.user-action-7 {
+ color: #333;
+}
+
+.user-action-8 {
+ padding: 3px;
+ font-weight: bold;
+ background-color: #CCC;
+ color: #763333;
+}
+
+.revision-summary {
+ background-color: #FFFE9B;
+ padding: 2px;
+}
+
+.question-title-link a {
+ font-weight: bold;
+ color: #0077CC;
+}
+
+.answer-title-link a {
+ color: #333;
+}
+
+/* todo: make these more semantic */
+.post-type-1 a {
+ font-weight: bold;
+
+}
+
+.post-type-3 a {
+ font-weight: bold;
+
+}
+
+.post-type-5 a {
+ font-weight: bold;
+}
+
+.post-type-2 a {
+ color: #333;
+}
+
+.post-type-4 a {
+ color: #333;
+}
+
+.post-type-6 a {
+ color: #333;
+}
+
+.post-type-8 a {
+ color: #333;
+}
+
+.hilite {
+ background-color: #ff0;
+}
+
+.hilite1 {
+ background-color: #ff0;
+}
+
+.hilite2 {
+ background-color: #f0f;
+}
+
+.hilite3 {
+ background-color: #0ff;
+}
+
+.gold, .badge1 {
+ color: #FFCC00;
+}
+
+.silver, .badge2 {
+ color: #CCCCCC;
+}
+
+.bronze, .badge3 {
+ color: #CC9933;
+}
+
+.score {
+ font-weight: 800;
+ color: #333;
+}
+
+
+a.comment {
+ background: #EEE;
+ color: #993300;
+ padding: 5px;
+}
+
+a.offensive {
+ color: #999;
+}
+
+.message h1 {
+ padding-top: 0px;
+ font-size: 15px;
+}
+
+.message p {
+ margin-bottom: 0px;
+}
+
+p.space-above {
+ margin-top: 10px;
+}
+
+.warning {
+ color: red;
+}
+
+
+
+button::-moz-focus-inner {
+ padding:0;
+ border:none;
+}
+.submit {
+ cursor: pointer; /*letter-spacing:1px;*/
+ background-color: #D4D0C8;
+ height: 30px;
+ border: 1px solid #777777; /* width:100px; */
+ font-weight: bold;
+ font-size: 120%;
+}
+
+.submit:hover {
+ text-decoration: underline;
+}
+
+.submit.small {
+ margin-right:5px;
+ height:20px;
+ font-weight:normal;
+ font-size:12px;
+ padding:1px 5px;
+}
+.submit.small:hover {
+ text-decoration:none;
+}
+.question-page a.submit {
+ display: -moz-inline-stack;
+ display: inline-block;
+ line-height: 30px;
+ padding: 0 5px;
+ *display: inline;
+}
+
+.noscript {
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ width: 100%;
+ z-index: 100;
+ padding: 5px 0;
+ text-align: center;
+ font-family: sans-serif;
+ font-size: 120%;
+ font-weight: Bold;
+ color: #FFFFFF;
+ background-color: #AE0000;
+}
+
+.big {
+ font-size: 14px;
+}
+
+.strong {
+ font-weight: bold;
+}
+
+.orange {/* used in django.po */
+ color: #d64000;
+ font-weight: bold;
+}
+
+.grey {
+ color: #808080;
+}
+
+.about div {
+ padding: 10px 5px 10px 5px;
+ border-top: 1px dashed #aaaaaa;
+}
+
+.highlight {
+ background-color: #FFF8C6;
+}
+
+.nomargin {
+ margin: 0;
+}
+
+.margin-bottom {
+ margin-bottom: 10px;
+}
+
+.margin-top {
+ margin-top: 10px;
+}
+
+.inline-block {
+ display: inline-block;
+}
+
+.action-status {
+ margin: 0;
+ border: none;
+ text-align: center;
+ line-height: 10px;
+ font-size: 12px;
+ padding: 0;
+}
+
+.action-status span {
+ padding: 3px 5px 3px 5px;
+ background-color: #fff380; /* nice yellow */
+ font-weight: normal;
+ -moz-border-radius: 5px;
+ -khtml-border-radius: 5px;
+ -webkit-border-radius: 5px;
+}
+
+.list-table {
+ td {
+ vertical-align: top;
+ }
+ border-spacing: 0;
+}
+
+/* these need to go */
+table.form-as-table .errorlist {
+ display: block;
+ margin: 0;
+ padding: 0 0 0 5px;
+ text-align: left;
+ font-size: 10px;
+ color: darkred;
+}
+
+table.form-as-table input {
+ display: inline;
+ margin-left: 4px;
+}
+
+table.form-as-table th {
+ vertical-align: bottom;
+ padding-bottom: 4px;
+}
+
+.form-row-vertical {
+ margin-top: 8px;
+ display: block;
+}
+
+.form-row-vertical label {
+ margin-bottom: 3px;
+ display: block;
+}
+
+/* above stuff needs to go */
+.text-align-right {
+ text-align: center;
+}
+
+ul.form-horizontal-rows {
+ list-style: none;
+ margin: 0;
+}
+
+ul.form-horizontal-rows li {
+ position: relative;
+ height: 40px;
+}
+
+ul.form-horizontal-rows label {
+ display: inline-block;
+}
+
+ul.form-horizontal-rows ul.errorlist {
+ list-style: none;
+ color: darkred;
+ font-size: 10px;
+ line-height: 10px;
+ position: absolute;
+ top: 2px;
+ left: 180px;
+ text-align: left;
+ margin: 0;
+}
+
+ul.form-horizontal-rows ul.errorlist li {
+ height: 10px;
+}
+
+ul.form-horizontal-rows label {
+ position: absolute;
+ left: 0px;
+ bottom: 6px;
+ margin: 0px;
+ line-height: 12px;
+ font-size: 12px;
+}
+
+ul.form-horizontal-rows li input {
+ position: absolute;
+ bottom: 0px;
+ left: 180px;
+ margin: 0px;
+}
+
+.narrow .summary {
+ float: left;
+}
+
+.user-profile-tool-links {
+ font-weight: bold;
+ vertical-align: top;
+}
+
+
+ul.post-tags {
+ margin-left: 3px;
+}
+ul.post-tags li {
+ margin-top: 4px;
+ margin-bottom: 3px;
+}
+
+ul.post-retag {
+ margin-bottom:0px;
+ margin-left:5px;
+ input {
+ width: 400px;
+ height: 1.5em;
+ margin: 3px 0 0 -3px;
+ }
+}
+
+#question-controls .tags {
+ margin: 0 0 3px 0;
+}
+
+#tagSelector {
+ padding-bottom: 2px;
+ margin-bottom: 0;
+}
+
+#related-tags {
+ padding-left: 3px;
+}
+
+#hideIgnoredTagsControl {
+ margin: 5px 0 0 0;
+}
+
+#hideIgnoredTagsControl label {
+ font-size: 12px;
+ color: #666;
+}
+
+#hideIgnoredTagsCb {
+ margin: 0 2px 0 1px;
+}
+
+#recaptcha_widget_div {
+ width: 318px;
+ float: left;
+ clear: both;
+}
+
+p.signup_p {
+ margin: 20px 0px 0px 0px;
+}
+
+.simple-subscribe-options {
+ ul {
+ list-style: none;
+ list-style-position: outside;
+ margin: 0;
+ }
+ input {
+ display: inline;
+ }
+}
+
+/* a workaround to set link colors correctly */
+
+.wmd-preview a {
+ color:@link;
+}
+
+.wmd-preview li {
+ margin-bottom:7px;
+ font-size:14px;
+}
+
+.search-result-summary {
+ font-weight: bold;
+ font-size:18px;
+ line-height:22px;
+ margin:0px 0px 0px 0px;
+ padding:2px 0 0 0;
+ float: left;
+}
+
+.faq-rep-item {
+ text-align:right;
+ padding-right:5px;
+}
+
+
+.user-info-table .gravatar {
+ margin:0;
+}
+
+#responses {
+ clear:both;
+ line-height:18px;
+ margin-bottom:15px;
+}
+
+#responses div.face {
+ float:left;
+ text-align: center;
+ width: 54px;
+ padding: 3px;
+ overflow:hidden;
+}
+
+.response-parent {
+ margin-top: 18px;
+}
+
+.response-parent strong{
+ font-size: 20px;
+}
+
+.re {
+ min-height: 57px;
+ clear: both;
+ margin-top: 10px;
+}
+
+#responses input {
+ float:left;
+}
+#re_tools {
+ margin-bottom:10px;
+}
+#re_sections {
+ margin-bottom:6px;
+}
+#re_sections .on {
+ font-weight:bold;
+}
+
+.avatar-page ul {
+ list-style: none;
+}
+.avatar-page li {
+ display: inline;
+}
+
+.user-profile-page {
+ .avatar p {
+ margin-bottom: 0px;
+ }
+ .tabBar a#stats {
+ margin-left: 0;
+ }
+ img.gravatar {
+ margin: 2px 0 3px 0;
+ }
+ h3 {
+ padding: 0;
+ margin-top: -3px;
+ }
+ ul.tags {
+ margin-left: 5px;
+ }
+}
+
+.userList {
+ font-size: 13px;
+}
+
+img.flag {
+ border: 1px solid #eee;
+ vertical-align: text-top;
+}
+
+.main-page img.flag {
+ vertical-align: text-bottom;
+}
+
+
+/* Pretty printing styles. Used with prettify.js. */
+
+a.edit {
+ padding-left:3px;
+ color: #145bff;
+}
+
+pre {
+ .str { color: #080; }
+ .kwd { color: #008; }
+ .com { color: #800; }
+ .typ { color: #606; }
+ .lit { color: #066; }
+ .pun { color: #660; }
+ .pln { color: #000; }
+ .tag { color: #008; }/* name conflict here with tags */
+ .atn { color: #606; }
+ .atv { color: #080; }
+ .dec { color: #606; }
+}
+pre.prettyprint { clear:both;padding: 3px; border: 0px solid #888; }
+
+@media print {
+ pre {
+ .str { color: #060; }
+ .kwd { color: #006; font-weight: bold; }
+ .com { color: #600; font-style: italic; }
+ .typ { color: #404; font-weight: bold; }
+ .lit { color: #044; }
+ .pun { color: #440; }
+ .pln { color: #000; }
+ .tag { color: #006; font-weight: bold; }
+ .atn { color: #404; }
+ .atv { color: #060; }
+ }
+}
+
+#leading-sidebar {
+ float: left;
+}
+
+/* language-specific fixes */
+body.lang-es {
+ #searchBar {
+ width: 398px;
+ .searchInput {
+ width: 337px;
+ }
+ .searchInputCancelable {
+ width: 302px;
+ }
+ }
+}
+body.anon.lang-es {
+ #searchBar {
+ width: 485px;
+ .searchInput {
+ width: 425px;
+ }
+ .searchInputCancelable {
+ width: 390px;
+ }
+ }
+}
+
+/* user groups */
+#user-groups ul {
+ margin-bottom: 0px;
+}
+#user-groups .delete-icon {
+ float: none;
+ display: inline;
+ color: #525252;
+ padding: 0 3px 0 3px;
+ background: #ccc;
+ border-radius: 4px;
+ line-height:inherit;
+ -moz-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ -webkit-border-radius: 4px;
+}
+#user-groups .delete-icon:hover {
+ color: white;
+ background: #b32f2f;
+}
+
+.question-page .post-update-info a.primary-group-name,
+a.primary-group-name {
+ color: #990E08;
+ font-weight: bold;
+}
+
+.users-page {
+ .wmd-prompt-dialog {
+ background: #ccc;
+ }
+}
+
+.group-wiki {
+ .content {
+ > p:last-child {
+ margin-bottom: 5px;
+ }
+ }
+ .group-logo {
+ float: left;
+ margin: 0 5px 3px 0;
+ }
+ .follow-toggle.group-join-btn {
+ margin: 4px auto 10px auto;
+ display: block;
+ }
+ .controls {
+ margin: 0 0 10px 0;
+ }
+}
+
+img.group-logo {
+ height: 60px;/* important to align with the line spacing */
+}
+
+#groups-list {
+ margin-left: 0px;
+ .group-name {
+ padding-right: 20px;
+ }
+ td {
+ padding-bottom: 5px;
+ }
+}
+
+.groups-page #groups-list {
+ th, td {
+ padding-right: 20px;
+ }
+ th {
+ font-weight: bold;
+ }
+ th:nth-child(2),
+ td:nth-child(2) {
+ text-align: center;
+ }
+}
+
+#reject-edit-modal {
+ input, textarea {
+ width: 514px;
+ }
+}
+
+input.tipped-input,
+textarea.tipped-input {
+ padding-left: 5px;
+}
+
+.tipped-input.blank {
+ color: @info-text;
+}
+
+.select-box {
+
+ margin: 0;
+
+ li {
+ list-style-type: none;
+ list-style-position: inside;
+ padding-left: 7px;
+ font-size: 14px;
+ line-height: 25px;
+ input {
+ margin: 0 0 2px -5px;
+ font-size: 14px;
+ line-height: 14px;
+ vertical-align: middle;
+ color: @info-text;
+ }
+ }
+ li.selected,
+ li.selected:hover {
+ background-color: #fcf8e3;
+ color: #c09853;
+ }
+ li:hover {
+ background-color: #cecece;
+ color: white;
+ }
+}
+
+/* category selector */
+.category-selector {
+ border-spacing: 0;
+ ul.select-box {
+ height: 150px;
+ width: 235px;
+ overflow: auto;
+ border: #ccc 3px solid;
+ }
+ td {
+ vertical-align: top;
+ }
+ li {
+ position: relative;
+ color: @info-text;
+ }
+ li.tree:after {
+ content: ">>";
+ position: absolute;
+ right: 5px;
+ font-weight: bold;
+ }
+ li.selected.tree:after {
+ color: #C09853;
+ }
+ th {
+ color: @info-text;
+ font-style: italic;
+ font-size: 16px;
+ font-weight: normal;
+ padding-top: 5px;
+ text-align: left;
+ }
+}
+
+.question-page {
+ .category-selector ul.select-box {
+ width: 217px;
+ input {
+ width: 95px;
+ }
+ }
+ .tag-editor {
+ width: 660px;
+ margin-left: 0;
+ }
+}
+
+.editor-status {
+ float: right;
+ margin: 7px 350px 0 0;
+ font-weight: bold;
+
+ span {
+ display: none;
+ }
+}
+
+/* tag editor */
+.tag-editor {
+ height: 64px;
+ border: #ccc 3px solid;
+ padding-left: 8px;
+ ul.tags {
+ margin: 0;
+ li {
+ margin-top: 8px;
+ height: 13px;
+ }
+ }
+ input.new-tags-input,
+ input.new-tags-input:focus {
+ border: none;
+ font-size: 15px;
+ font-color: @info-text;
+ line-height: 16px;
+ margin-top: 9px;
+ -webkit-box-shadow: none;/* undo bootstrap glow */
+ -moz-box-shadow: none;
+ box-shadow: none;
+ }
+}
+
+/* fixes for bootstrap */
+.caret {
+ margin-bottom: 7px;
+}
+.btn-group {
+ text-align: left;
+}
+.btn-toolbar {
+ margin: 0;
+}
+.modal-footer {
+ text-align: left;
+}
+.modal p {
+ font-size: 14px;
+}
+.modal-body > textarea {
+ width: 515px;
+ margin-bottom: 0px;
+}
diff --git a/askbot/media/style/tinymce/content.css b/askbot/media/style/tinymce/content.css
new file mode 100644
index 00000000..41c45d1e
--- /dev/null
+++ b/askbot/media/style/tinymce/content.css
@@ -0,0 +1,58 @@
+body, td, pre {color:#000; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px; margin:8px;}
+body {background:#FFF;}
+body.mceForceColors {background:#FFF; color:#000;}
+body.mceBrowserDefaults {background:transparent; color:inherit; font-size:inherit; font-family:inherit;}
+h1 {font-size: 2em}
+h2 {font-size: 1.5em}
+h3 {font-size: 1.17em}
+h4 {font-size: 1em}
+h5 {font-size: .83em}
+h6 {font-size: .75em}
+.mceItemTable, .mceItemTable td, .mceItemTable th, .mceItemTable caption, .mceItemVisualAid {border: 1px dashed #BBB;}
+a.mceItemAnchor {display:inline-block; -webkit-user-select:all; -webkit-user-modify:read-only; -moz-user-select:all; -moz-user-modify:read-only; width:11px !important; height:11px !important; background:url(img/items.gif) no-repeat center center}
+span.mceItemNbsp {background: #DDD}
+td.mceSelected, th.mceSelected {background-color:#3399ff !important}
+img {border:0;}
+table, img, hr, .mceItemAnchor {cursor:default}
+table td, table th {cursor:text}
+ins {border-bottom:1px solid green; text-decoration: none; color:green}
+del {color:red; text-decoration:line-through}
+cite {border-bottom:1px dashed blue}
+acronym {border-bottom:1px dotted #CCC; cursor:help}
+abbr {border-bottom:1px dashed #CCC; cursor:help}
+
+/* IE */
+* html body {
+scrollbar-3dlight-color:#F0F0EE;
+scrollbar-arrow-color:#676662;
+scrollbar-base-color:#F0F0EE;
+scrollbar-darkshadow-color:#DDD;
+scrollbar-face-color:#E0E0DD;
+scrollbar-highlight-color:#F0F0EE;
+scrollbar-shadow-color:#F0F0EE;
+scrollbar-track-color:#F5F5F5;
+}
+
+img:-moz-broken {-moz-force-broken-image-icon:1; width:24px; height:24px}
+font[face=mceinline] {font-family:inherit !important}
+*[contentEditable]:focus {outline:0}
+
+.mceItemMedia {border:1px dotted #cc0000; background-position:center; background-repeat:no-repeat; background-color:#ffffcc}
+.mceItemShockWave {background-image:url(../../img/shockwave.gif)}
+.mceItemFlash {background-image:url(../../img/flash.gif)}
+.mceItemQuickTime {background-image:url(../../img/quicktime.gif)}
+.mceItemWindowsMedia {background-image:url(../../img/windowsmedia.gif)}
+.mceItemRealMedia {background-image:url(../../img/realmedia.gif)}
+.mceItemVideo {background-image:url(../../img/video.gif)}
+.mceItemAudio {background-image:url(../../img/video.gif)}
+.mceItemEmbeddedAudio {background-image:url(../../img/video.gif)}
+.mceItemIframe {background-image:url(../../img/iframe.gif)}
+.mcePageBreak {display:block;border:0;width:100%;height:12px;border-top:1px dotted #ccc;margin-top:15px;background:#fff url(../../img/pagebreak.gif) no-repeat center top;}
+
+/* overrides on top of default */
+body.mceContentBody {
+ font-size: 13px;
+ background-color:#fff;
+ padding: 0;
+ line-height:135%;
+}
diff --git a/askbot/middleware/forum_mode.py b/askbot/middleware/forum_mode.py
index 7f1e29b1..d593a6f2 100644
--- a/askbot/middleware/forum_mode.py
+++ b/askbot/middleware/forum_mode.py
@@ -45,6 +45,10 @@ class ForumModeMiddleware(object):
and request.user.is_anonymous()):
resolver_match = ResolverMatch(resolve(request.path))
+ internal_ips = getattr(settings, 'ASKBOT_INTERNAL_IPS', None)
+ if internal_ips and request.META['REMOTE_ADDR'] in internal_ips:
+ return None
+
if is_view_allowed(resolver_match.func):
return
diff --git a/askbot/migrations/0001_initial.py b/askbot/migrations/0001_initial.py
index 97febea3..d11c8f2f 100644
--- a/askbot/migrations/0001_initial.py
+++ b/askbot/migrations/0001_initial.py
@@ -4,39 +4,25 @@ import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
+from askbot.migrations_api import safe_add_column
app_dir_name = os.path.basename(os.path.dirname(os.path.dirname(__file__)))
-def safe_add_column(table, column, column_data, keep_default = False):
- """when user calls syncdb with askbot the first time
- the auth_user table will be created together with the patched columns
- so, we need to add these columns here in separate transactions
- and roll back if they fail, if we want we could also record - which columns clash
- """
- try:
- db.start_transaction()
- db.add_column(table, column, column_data, keep_default = keep_default)
- db.commit_transaction()
- return True
- except:
- db.rollback_transaction()
- return False
-
class Migration(SchemaMigration):
def forwards(self, orm):
#1) patch the existing auth_user table
- safe_add_column('auth_user', 'website', self.gf('django.db.models.fields.URLField')(max_length=200, blank=True), keep_default = False)
- safe_add_column('auth_user', 'about', self.gf('django.db.models.fields.TextField')(blank=True), keep_default = False)
+ safe_add_column('auth_user', 'website', self.gf('django.db.models.fields.URLField')(max_length=200, blank=True, null=True), keep_default = False)
+ safe_add_column('auth_user', 'about', self.gf('django.db.models.fields.TextField')(blank=True, null=True), keep_default = False)
safe_add_column('auth_user', 'hide_ignored_questions', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default = False)
safe_add_column('auth_user', 'gold', self.gf('django.db.models.fields.SmallIntegerField')(default=0), keep_default = False)
safe_add_column('auth_user', 'email_isvalid', self.gf('django.db.models.fields.BooleanField')(default=False, blank=True), keep_default = False)
- safe_add_column('auth_user', 'real_name', self.gf('django.db.models.fields.CharField')(max_length=100, blank=True), keep_default = False)
- safe_add_column('auth_user', 'location', self.gf('django.db.models.fields.CharField')(max_length=100, blank=True), keep_default = False)
+ safe_add_column('auth_user', 'real_name', self.gf('django.db.models.fields.CharField')(max_length=100, blank=True, null=True), keep_default = False)
+ safe_add_column('auth_user', 'location', self.gf('django.db.models.fields.CharField')(max_length=100, blank=True, null=True), keep_default = False)
safe_add_column('auth_user', 'email_key', self.gf('django.db.models.fields.CharField')(max_length=32, null=True), keep_default = False)
safe_add_column('auth_user', 'date_of_birth', self.gf('django.db.models.fields.DateField')(null=True, blank=True), keep_default = False)
safe_add_column('auth_user', 'reputation', self.gf('django.db.models.fields.PositiveIntegerField')(default=1), keep_default = False)
- safe_add_column('auth_user', 'gravatar', self.gf('django.db.models.fields.CharField')(max_length=32), keep_default = False)
+ safe_add_column('auth_user', 'gravatar', self.gf('django.db.models.fields.CharField')(max_length=32, null=True), keep_default = False)
safe_add_column('auth_user', 'bronze', self.gf('django.db.models.fields.SmallIntegerField')(default=0), keep_default = False)
safe_add_column('auth_user', 'tag_filter_setting', self.gf('django.db.models.fields.CharField')(default='ignored', max_length=16), keep_default = False)
safe_add_column('auth_user', 'last_seen', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now), keep_default = False)
diff --git a/askbot/migrations/0124_auto__add_field_post_is_private__add_field_replyaddress_reply_action.py b/askbot/migrations/0124_auto__add_field_post_is_private__add_field_replyaddress_reply_action.py
index ecb66552..b5a1e0c9 100644
--- a/askbot/migrations/0124_auto__add_field_post_is_private__add_field_replyaddress_reply_action.py
+++ b/askbot/migrations/0124_auto__add_field_post_is_private__add_field_replyaddress_reply_action.py
@@ -9,6 +9,7 @@ class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Post.is_private'
+ db.start_transaction()
db.add_column('askbot_post', 'is_private',
self.gf('django.db.models.fields.BooleanField')(default=False),
keep_default=False)
@@ -20,17 +21,19 @@ class Migration(SchemaMigration):
# Changing field 'ReplyAddress.post'
db.alter_column('askbot_replyaddress', 'post_id', self.gf('django.db.models.fields.related.ForeignKey')(null=True, to=orm['askbot.Post']))
+ db.commit_transaction()
try:
+ db.start_transaction()
# Adding field 'User.interesting_tags'
db.add_column(u'auth_user', 'email_signature', self.gf('django.db.models.fields.TextField')(blank=True, default = ''), keep_default=False)
+ db.commit_transaction()
except:
- pass
+ db.rollback_transaction()
def backwards(self, orm):
db.delete_column('askbot_post', 'is_private')
db.delete_column('askbot_replyaddress', 'reply_action')
- db.delete_column('auth_user', 'email_signature')
db.alter_column('askbot_replyaddress', 'post_id', self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['askbot.Post']))
models = {
diff --git a/askbot/migrations/0126_add_field__auth_user__is_fake.py b/askbot/migrations/0126_add_field__auth_user__is_fake.py
new file mode 100644
index 00000000..e0928ed7
--- /dev/null
+++ b/askbot/migrations/0126_add_field__auth_user__is_fake.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from south.db import db
+from south.v2 import SchemaMigration
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ try:
+ # Adding field 'User.is_fake'
+ db.add_column(
+ u'auth_user', 'is_fake',
+ self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False)
+ except:
+ pass
+
+ def backwards(self, orm):
+ db.delete_column('auth_user', 'is_fake')
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0127_save_category_tree_as_json.py b/askbot/migrations/0127_save_category_tree_as_json.py
new file mode 100644
index 00000000..b13cd2fe
--- /dev/null
+++ b/askbot/migrations/0127_save_category_tree_as_json.py
@@ -0,0 +1,385 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.utils import simplejson
+from django.db import models
+from askbot.conf import settings as askbot_settings
+
+def get_subtree(tree, path):
+ """#this might be simpler, but not tested
+ clevel = tree
+ for step in path:
+ try:
+ level = clevel[step]
+ except IndexError:
+ return False
+ return clevel
+ """
+ if len(path) == 1:
+ assert(path[0] == 0)
+ return tree
+ else:
+ import copy
+ parent_path = copy.copy(path)
+ leaf_index = parent_path.pop()
+ branch_index = parent_path[-1]
+ parent_tree = get_subtree(tree, parent_path)
+ return parent_tree[branch_index][1]
+
+def parse_tree(text):
+ """parse tree represented as indented text
+ one item per line, with two spaces per level of indentation
+ """
+ lines = text.split('\n')
+ import re
+ in_re = re.compile(r'^([ ]*)')
+
+ tree = [['dummy', []]]
+ subtree_path = [0]
+ clevel = 0
+
+ for line in lines:
+ if line.strip() == '':
+ continue
+ match = in_re.match(line)
+ level = len(match.group(1))/2 + 1
+
+ if level > clevel:
+ subtree_path.append(0)#
+ elif level < clevel:
+ subtree_path = subtree_path[:level+1]
+ leaf_index = subtree_path.pop()
+ subtree_path.append(leaf_index + 1)
+ else:
+ leaf_index = subtree_path.pop()
+ subtree_path.append(leaf_index + 1)
+
+ clevel = level
+ try:
+ subtree = get_subtree(tree, subtree_path)
+ except:
+ return tree
+ subtree.append([line.strip(), []])
+
+ return tree
+
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ """reads category tree saved as string,
+ translates it to json and saves back"""
+ old_data = askbot_settings.CATEGORY_TREE
+ json_data = parse_tree(old_data)
+ json_string = simplejson.dumps(json_data)
+ askbot_settings.update('CATEGORY_TREE', json_string)
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+ pass
+
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'GroupMembership'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_memberships'", 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_memberships'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupprofile': {
+ 'Meta': {'object_name': 'GroupProfile'},
+ 'group_tag': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'group_profile'", 'unique': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_private': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'revision_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
+ symmetrical = True
diff --git a/askbot/migrations/0128_add_groups_field__to__thread_and_post.py b/askbot/migrations/0128_add_groups_field__to__thread_and_post.py
new file mode 100644
index 00000000..ab8bf919
--- /dev/null
+++ b/askbot/migrations/0128_add_groups_field__to__thread_and_post.py
@@ -0,0 +1,335 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding M2M table for field groups on 'Thread'
+ db.create_table('askbot_thread_groups', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('thread', models.ForeignKey(orm['askbot.thread'], null=False)),
+ ('tag', models.ForeignKey(orm['askbot.tag'], null=False))
+ ))
+ db.create_unique('askbot_thread_groups', ['thread_id', 'tag_id'])
+ # Adding M2M table for field groups on 'Post'
+ db.create_table('askbot_post_groups', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('post', models.ForeignKey(orm['askbot.post'], null=False)),
+ ('tag', models.ForeignKey(orm['askbot.tag'], null=False))
+ ))
+ db.create_unique('askbot_post_groups', ['post_id', 'tag_id'])
+
+ def backwards(self, orm):
+
+ # Removing M2M tables for field groups on 'Thread' and 'Post'
+ db.delete_table('askbot_thread_groups')
+ db.delete_table('askbot_post_groups')
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'GroupMembership'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_memberships'", 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_memberships'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupprofile': {
+ 'Meta': {'object_name': 'GroupProfile'},
+ 'group_tag': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'group_profile'", 'unique': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_private': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'revision_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0129_auto__del_field_post_is_private.py b/askbot/migrations/0129_auto__del_field_post_is_private.py
new file mode 100644
index 00000000..68637bdc
--- /dev/null
+++ b/askbot/migrations/0129_auto__del_field_post_is_private.py
@@ -0,0 +1,322 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Deleting field 'Post.is_private'
+ db.delete_column('askbot_post', 'is_private')
+
+ def backwards(self, orm):
+ # Adding field 'Post.is_private'
+ db.add_column('askbot_post', 'is_private',
+ self.gf('django.db.models.fields.BooleanField')(default=False),
+ keep_default=False)
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'GroupMembership'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_memberships'", 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_memberships'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupprofile': {
+ 'Meta': {'object_name': 'GroupProfile'},
+ 'group_tag': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'group_profile'", 'unique': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'revision_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0130_auto__del_field_postrevision_revision_type.py b/askbot/migrations/0130_auto__del_field_postrevision_revision_type.py
new file mode 100644
index 00000000..4143ffa8
--- /dev/null
+++ b/askbot/migrations/0130_auto__del_field_postrevision_revision_type.py
@@ -0,0 +1,321 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Deleting field 'PostRevision.revision_type'
+ db.delete_column('askbot_postrevision', 'revision_type')
+
+ def backwards(self, orm):
+ # Adding field 'PostRevision.revision_type'
+ db.add_column('askbot_postrevision', 'revision_type',
+ self.gf('django.db.models.fields.SmallIntegerField')(default=1),
+ keep_default=False)
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'GroupMembership'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_memberships'", 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_memberships'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupprofile': {
+ 'Meta': {'object_name': 'GroupProfile'},
+ 'group_tag': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'group_profile'", 'unique': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0131_auto__add_field_tag_status.py b/askbot/migrations/0131_auto__add_field_tag_status.py
new file mode 100644
index 00000000..f5557546
--- /dev/null
+++ b/askbot/migrations/0131_auto__add_field_tag_status.py
@@ -0,0 +1,335 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Tag.status'
+ db.add_column(u'tag', 'status',
+ self.gf('django.db.models.fields.SmallIntegerField')(default=1),
+ keep_default=False)
+
+ # Adding M2M table for field suggested_by on 'Tag'
+ db.create_table(u'tag_suggested_by', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('tag', models.ForeignKey(orm['askbot.tag'], null=False)),
+ ('user', models.ForeignKey(orm['auth.user'], null=False))
+ ))
+ db.create_unique(u'tag_suggested_by', ['tag_id', 'user_id'])
+
+ def backwards(self, orm):
+ # Deleting field 'Tag.status'
+ db.delete_column(u'tag', 'status')
+
+ # Removing M2M table for field suggested_by on 'Tag'
+ db.delete_table('tag_suggested_by')
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'GroupMembership'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_memberships'", 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_memberships'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupprofile': {
+ 'Meta': {'object_name': 'GroupProfile'},
+ 'group_tag': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'group_profile'", 'unique': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0132_auto__add_draftquestion__add_draftanswer.py b/askbot/migrations/0132_auto__add_draftquestion__add_draftanswer.py
new file mode 100644
index 00000000..bceca754
--- /dev/null
+++ b/askbot/migrations/0132_auto__add_draftquestion__add_draftanswer.py
@@ -0,0 +1,356 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding model 'DraftQuestion'
+ db.create_table('askbot_draftquestion', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('author', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=300, null=True)),
+ ('text', self.gf('django.db.models.fields.TextField')(null=True)),
+ ('tagnames', self.gf('django.db.models.fields.CharField')(max_length=125, null=True)),
+ ))
+ db.send_create_signal('askbot', ['DraftQuestion'])
+
+ # Adding model 'DraftAnswer'
+ db.create_table('askbot_draftanswer', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('thread', self.gf('django.db.models.fields.related.ForeignKey')(related_name='draft_answers', to=orm['askbot.Thread'])),
+ ('author', self.gf('django.db.models.fields.related.ForeignKey')(related_name='draft_answers', to=orm['auth.User'])),
+ ('text', self.gf('django.db.models.fields.TextField')(null=True)),
+ ))
+ db.send_create_signal('askbot', ['DraftAnswer'])
+
+ def backwards(self, orm):
+ # Deleting model 'DraftQuestion'
+ db.delete_table('askbot_draftquestion')
+
+ # Deleting model 'DraftAnswer'
+ db.delete_table('askbot_draftanswer')
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'GroupMembership'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_memberships'", 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_memberships'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupprofile': {
+ 'Meta': {'object_name': 'GroupProfile'},
+ 'group_tag': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'group_profile'", 'unique': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot'] \ No newline at end of file
diff --git a/askbot/migrations/0133_apply_global_group_to_posts_and_users.py b/askbot/migrations/0133_apply_global_group_to_posts_and_users.py
new file mode 100644
index 00000000..8c14b55d
--- /dev/null
+++ b/askbot/migrations/0133_apply_global_group_to_posts_and_users.py
@@ -0,0 +1,453 @@
+# -*- coding: utf-8 -*-
+import datetime
+import re
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from django.core.management.base import CommandError
+from askbot.conf import settings as askbot_settings
+from askbot.utils.console import ProgressBar
+
+def clean_group_name(name):
+ """group names allow spaces,
+ tag names do not, so we use this method
+ to replace spaces with dashes"""
+ return re.sub('\s+', '-', name.strip())
+
+def get_superuser(orm):
+ """returns superuser, assumes that user
+ with the lowest id with the superuser status
+ otherwise - if there are no users at all -
+ will return None
+ and finally if there are users, but no super -
+ will fail and ask create a superuser
+ """
+ try:
+ return orm['auth.User'].objects.filter(
+ is_superuser=True
+ ).order_by('id')[0]
+ except IndexError:
+ if orm['auth.User'].objects.count() > 0:
+ raise CommandError('Please create a superuser to continue')
+ else:
+ return None
+
+def create_group(orm, name=None, created_by=None):
+ """creates a group with a given name and the founder"""
+ group = orm['askbot.Tag']()
+ group.name = name
+ group.created_by = created_by
+ group.save()
+
+ group_profile = orm['askbot.GroupProfile']()
+ group_profile.group_tag = group
+ group_profile.save()
+
+ return group
+
+def get_global_group(orm):
+ """returns the "global user group" if exists
+ otherwise will attempt to create the group -
+ if a superuser exists (which may fail)
+ and if superuser does not exist - then
+ return None
+ """
+ group_name = clean_group_name(askbot_settings.GLOBAL_GROUP_NAME)
+ model = orm['askbot.Tag']
+ try:
+ return model.objects.get(name=group_name)
+ except model.DoesNotExist:
+ superuser = get_superuser(orm)
+ if superuser:
+ return create_group(
+ orm,
+ name=group_name,
+ created_by=superuser
+ )
+ else:
+ return None
+
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ "Write your forwards methods here."
+ group = get_global_group(orm)
+
+ items = orm['askbot.Thread'].objects.all()
+ message = 'Moving group-less threads to the global group'
+ done_count = 0
+ for thread in ProgressBar(items.iterator(), items.count(), message):
+ if thread.groups.count() == 0:
+ thread.groups.add(group)
+ done_count += 1
+
+ if items.count():
+ print 'Added global group to %d threads.\n' % done_count
+
+ post_types = ('question', 'answer')
+ posts = orm['askbot.Post'].objects.filter(post_type__in=post_types)
+ message = 'Move groupless questions and answers to the global group'
+ done_count = 0
+ for post in ProgressBar(posts.iterator(), posts.count(), message):
+ if post.groups.count() == 0:
+ post.groups.add(group)
+ done_count += 1
+
+ if posts.count():
+ print 'Added global group to %d posts.\n' % done_count
+
+ comments = orm['askbot.Post'].objects.filter(post_type='comment')
+ message = 'Copying group information from answers ' +\
+ 'and questions to comments'
+ done_count = 0
+ for comment in ProgressBar(comments.iterator(), comments.count(), message):
+ if comment.groups.count() == 0:
+ parent_post_groups = comment.parent.groups.all()
+ comment.groups.add(*parent_post_groups)
+ done_count += 1
+
+ if comments.count():
+ print 'Added global group to %d comments.\n' % done_count
+
+ users = orm['auth.User'].objects.all()
+ message = 'Adding all users to the global group'
+ done_count = 0
+ for user in ProgressBar(users.iterator(), users.count(), message):
+ cls = orm['askbot.GroupMembership']
+ if not cls.objects.filter(user=user, group=group).exists():
+ membership = cls(user=user, group=group)
+ membership.save()
+ done_count += 1
+
+ if users.count():
+ print 'Added global group to %d users.' % done_count
+
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+ pass
+
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'GroupMembership'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_memberships'", 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_memberships'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupprofile': {
+ 'Meta': {'object_name': 'GroupProfile'},
+ 'group_tag': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'group_profile'", 'unique': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
+ symmetrical = True
diff --git a/askbot/migrations/0134_create_personal_groups_for_all_users.py b/askbot/migrations/0134_create_personal_groups_for_all_users.py
new file mode 100644
index 00000000..e1c45ec1
--- /dev/null
+++ b/askbot/migrations/0134_create_personal_groups_for_all_users.py
@@ -0,0 +1,378 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from askbot.utils.console import ProgressBar
+
+def format_group_name(user):
+ """returns name of the personal group
+ given the user object
+ """
+ return '_internal_%s_%d' % (user.username, user.id)
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ "Write your forwards methods here."
+ message = 'Creating personal group for the users'
+ users = orm['auth.User'].objects.all()
+ for user in ProgressBar(users.iterator(), users.count(), message):
+ group_name = format_group_name(user)
+ group_tag = orm['askbot.Tag'](name=group_name, created_by=user)
+ group_tag.save()
+ group_profile = orm['askbot.GroupProfile'](
+ group_tag=group_tag, is_open=False
+ )
+ group_profile.save()
+ membership = orm['askbot.GroupMembership'](group=group_tag, user=user)
+ membership.save()
+
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+ for user in orm['auth.User'].objects.iterator():
+ group_name = format_group_name(user)
+
+ memberships = orm['askbot.GroupMembership'].objects.filter(
+ user=user,
+ group__name=group_name
+ )
+ memberships.delete()
+
+ group_profiles = orm['askbot.GroupProfile'].objects.filter(
+ group_tag__name=group_name
+ )
+ group_profiles.delete()
+
+ orm['askbot.Tag'].objects.filter(name=group_name).delete()
+
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'GroupMembership'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_memberships'", 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_memberships'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupprofile': {
+ 'Meta': {'object_name': 'GroupProfile'},
+ 'group_tag': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'group_profile'", 'unique': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Tag']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.posttogroup': {
+ 'Meta': {'unique_together': "(('post', 'tag'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']"})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
+ symmetrical = True
diff --git a/askbot/migrations/0135_auto__add_questionwidget__add_askwidget.py b/askbot/migrations/0135_auto__add_questionwidget__add_askwidget.py
new file mode 100644
index 00000000..dafdafb4
--- /dev/null
+++ b/askbot/migrations/0135_auto__add_questionwidget__add_askwidget.py
@@ -0,0 +1,393 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model 'QuestionWidget'
+ db.create_table('askbot_questionwidget', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=100)),
+ ('question_number', self.gf('django.db.models.fields.PositiveIntegerField')(default=7)),
+ ('tagnames', self.gf('django.db.models.fields.CharField')(max_length=50)),
+ ('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['askbot.Tag'], null=True, blank=True)),
+ ('search_query', self.gf('django.db.models.fields.CharField')(max_length=50, null=True, blank=True, default='')),
+ ('order_by', self.gf('django.db.models.fields.CharField')(default='-added_at', max_length=18)),
+ ('style', self.gf('django.db.models.fields.TextField')(default='', blank=True, null=True)),
+ ))
+ db.send_create_signal('askbot', ['QuestionWidget'])
+
+ # Adding model 'AskWidget'
+ db.create_table('askbot_askwidget', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('title', self.gf('django.db.models.fields.CharField')(max_length=100)),
+ ('group', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='groups', null=True, to=orm['askbot.Tag'])),
+ ('tag', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['askbot.Tag'], null=True, blank=True)),
+ ('include_text_field', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ('inner_style', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
+ ('outer_style', self.gf('django.db.models.fields.TextField')(default='', blank=True)),
+ ))
+ db.send_create_signal('askbot', ['AskWidget'])
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'QuestionWidget'
+ db.delete_table('askbot_questionwidget')
+
+ # Deleting model 'AskWidget'
+ db.delete_table('askbot_askwidget')
+
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.askwidget': {
+ 'Meta': {'object_name': 'AskWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'groups'", 'null': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'include_text_field': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'inner_style': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'outer_style': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'GroupMembership'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_memberships'", 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_memberships'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupprofile': {
+ 'Meta': {'object_name': 'GroupProfile'},
+ 'group_tag': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'group_profile'", 'unique': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Tag']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.posttogroup': {
+ 'Meta': {'unique_together': "(('post', 'tag'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']"})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.questionwidget': {
+ 'Meta': {'object_name': 'QuestionWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order_by': ('django.db.models.fields.CharField', [], {'default': "'-added_at'", 'max_length': '18'}),
+ 'question_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '7'}),
+ 'search_query': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'style': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0136_auto__add_group__add_threadtogroup__add_unique_threadtogroup_thread_ta.py b/askbot/migrations/0136_auto__add_group__add_threadtogroup__add_unique_threadtogroup_thread_ta.py
new file mode 100644
index 00000000..7ea6c02c
--- /dev/null
+++ b/askbot/migrations/0136_auto__add_group__add_threadtogroup__add_unique_threadtogroup_thread_ta.py
@@ -0,0 +1,417 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding model 'Group'
+ db.create_table('askbot_group', (
+ ('group_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['auth.Group'], unique=True, primary_key=True)),
+ ('logo_url', self.gf('django.db.models.fields.URLField')(max_length=200, null=True)),
+ ('moderate_email', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('is_open', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ('preapproved_emails', self.gf('django.db.models.fields.TextField')(default='', null=True, blank=True)),
+ ('preapproved_email_domains', self.gf('django.db.models.fields.TextField')(default='', null=True, blank=True)),
+ ))
+ db.send_create_signal('askbot', ['Group'])
+
+ # Adding field 'PostToGroup.group'
+ db.add_column('askbot_post_groups', 'group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['askbot.Group'], null=True, blank=True), keep_default=False)
+ db.add_column('askbot_thread_groups', 'group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['askbot.Group'], null=True, blank=True), keep_default=False)
+
+
+ def backwards(self, orm):
+
+ # Removing unique constraint on 'ThreadToGroup', fields ['thread', 'tag']
+ db.delete_unique('askbot_thread_groups', ['thread_id', 'tag_id'])
+
+ # Deleting model 'Group'
+ db.delete_table('askbot_group')
+
+ # Deleting model 'ThreadToGroup'
+ db.delete_table('askbot_thread_groups')
+
+ # Deleting field 'PostToGroup.group'
+ db.delete_column('askbot_post_groups', 'group_id')
+
+ # Changing field 'QuestionWidget.search_query'
+ db.alter_column('askbot_questionwidget', 'search_query', self.gf('django.db.models.fields.CharField')(default=None, max_length=50))
+
+ # Adding M2M table for field groups on 'Thread'
+ db.create_table('askbot_thread_groups', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('thread', models.ForeignKey(orm['askbot.thread'], null=False)),
+ ('tag', models.ForeignKey(orm['askbot.tag'], null=False))
+ ))
+ db.create_unique('askbot_thread_groups', ['thread_id', 'tag_id'])
+
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.askwidget': {
+ 'Meta': {'object_name': 'AskWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'groups'", 'null': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'include_text_field': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'inner_style': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'outer_style': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.group': {
+ 'Meta': {'object_name': 'Group', '_ormbases': ['auth.Group']},
+ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'GroupMembership'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_memberships'", 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_memberships'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupprofile': {
+ 'Meta': {'object_name': 'GroupProfile'},
+ 'group_tag': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'group_profile'", 'unique': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Tag']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.posttogroup': {
+ 'Meta': {'unique_together': "(('post', 'tag'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']"})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.questionwidget': {
+ 'Meta': {'object_name': 'QuestionWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order_by': ('django.db.models.fields.CharField', [], {'default': "'-added_at'", 'max_length': '18'}),
+ 'question_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '7'}),
+ 'search_query': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'style': ('django.db.models.fields.TextField', [], {'default': '"\\n@import url(\'http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700\');\\nbody {\\n overflow: hidden;\\n}\\n\\n#container {\\n width: 200px;\\n height: 350px;\\n}\\nul {\\n list-style: none;\\n padding: 5px;\\n margin: 5px;\\n}\\nli {\\n border-bottom: #CCC 1px solid;\\n padding-bottom: 5px;\\n padding-top: 5px;\\n}\\nli:last-child {\\n border: none;\\n}\\na {\\n text-decoration: none;\\n color: #464646;\\n font-family: \'Yanone Kaffeesatz\', sans-serif;\\n font-size: 15px;\\n}\\n"', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'through': "orm['askbot.ThreadToGroup']", 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.threadtogroup': {
+ 'Meta': {'unique_together': "(('thread', 'tag'),)", 'object_name': 'ThreadToGroup', 'db_table': "'askbot_thread_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']"}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0137_create_groups_from_relevant_tags.py b/askbot/migrations/0137_create_groups_from_relevant_tags.py
new file mode 100644
index 00000000..0150fcbc
--- /dev/null
+++ b/askbot/migrations/0137_create_groups_from_relevant_tags.py
@@ -0,0 +1,447 @@
+# encoding: utf-8
+import datetime
+import os
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+import askbot
+from askbot.utils.console import ProgressBar
+from askbot.search.postgresql import setup_full_text_search
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ "Write your forwards methods here."
+ profiles = orm['askbot.GroupProfile'].objects.all()
+ items = profiles.iterator()
+ count = profiles.count()
+ message = 'Transfering group information from Tag to Group model'
+ for profile in ProgressBar(items, count, message):
+ group_tag = profile.group_tag
+ group_name = group_tag.name.replace('-', ' ')
+ group = orm['askbot.Group']()
+ group.name = group_name
+ group.logo_url = profile.logo_url
+ group.moderate_email = profile.moderate_email
+ group.is_open = profile.is_open
+ group.preapproved_emails = profile.preapproved_emails
+ group.preapproved_email_domains = profile.preapproved_email_domains
+
+ try:
+ #see if such group is already there
+ auth_group = orm['auth.Group'].objects.get(name=group_name)
+ group.group_ptr = auth_group
+ except orm['auth.Group'].DoesNotExist:
+ pass
+
+ group.save()
+
+ #update thread groups
+ thread_groups = orm['askbot.ThreadToGroup'].objects
+ thread_groups = thread_groups.filter(tag=group_tag)
+ thread_groups.update(group=group)
+ #update post groups
+ post_groups = orm['askbot.PostToGroup'].objects
+ post_groups = post_groups.filter(tag=group_tag)
+ post_groups.update(group=group)
+ #update user groups
+ memberships = group_tag.user_memberships.all()
+ for membership in memberships:
+ membership.user.groups.add(group)
+
+ db_engine_name = askbot.get_database_engine_name()
+ if 'postgresql_psycopg2' in db_engine_name:
+ from django.db import connection
+ cursor = connection.cursor()
+ cursor.execute(
+ 'DROP TRIGGER IF EXISTS group_membership_tsv_update_trigger '
+ 'ON askbot_groupmembership'
+ )
+
+ message = 'Deleting old group information'
+ items = profiles.iterator()
+ for profile in ProgressBar(items, count, message):
+ group_tag = profile.group_tag
+ group_tag.user_memberships.all().delete()
+ profile.delete()
+
+ #for postgresql setup new user full text search
+ if 'postgresql_psycopg2' in db_engine_name:
+
+ script_path = os.path.join(
+ askbot.get_install_directory(),
+ 'search', 'postgresql',
+ 'user_profile_search_08312012.plsql'
+ )
+ setup_full_text_search(script_path)
+
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.askwidget': {
+ 'Meta': {'object_name': 'AskWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'groups'", 'null': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'include_text_field': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'inner_style': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'outer_style': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.group': {
+ 'Meta': {'object_name': 'Group', '_ormbases': ['auth.Group']},
+ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'GroupMembership'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_memberships'", 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'group_memberships'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.groupprofile': {
+ 'Meta': {'object_name': 'GroupProfile'},
+ 'group_tag': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'group_profile'", 'unique': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Tag']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.posttogroup': {
+ 'Meta': {'unique_together': "(('post', 'tag'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']"})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.questionwidget': {
+ 'Meta': {'object_name': 'QuestionWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order_by': ('django.db.models.fields.CharField', [], {'default': "'-added_at'", 'max_length': '18'}),
+ 'question_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '7'}),
+ 'search_query': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'style': ('django.db.models.fields.TextField', [], {'default': '"\\n@import url(\'http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700\');\\nbody {\\n overflow: hidden;\\n}\\n\\n#container {\\n width: 200px;\\n height: 350px;\\n}\\nul {\\n list-style: none;\\n padding: 5px;\\n margin: 5px;\\n}\\nli {\\n border-bottom: #CCC 1px solid;\\n padding-bottom: 5px;\\n padding-top: 5px;\\n}\\nli:last-child {\\n border: none;\\n}\\na {\\n text-decoration: none;\\n color: #464646;\\n font-family: \'Yanone Kaffeesatz\', sans-serif;\\n font-size: 15px;\\n}\\n"', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'through': "orm['askbot.ThreadToGroup']", 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.threadtogroup': {
+ 'Meta': {'unique_together': "(('thread', 'tag'),)", 'object_name': 'ThreadToGroup', 'db_table': "'askbot_thread_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']"}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0138_auto__del_groupprofile__del_groupmembership__del_unique_groupmembershi.py b/askbot/migrations/0138_auto__del_groupprofile__del_groupmembership__del_unique_groupmembershi.py
new file mode 100644
index 00000000..4a466637
--- /dev/null
+++ b/askbot/migrations/0138_auto__del_groupprofile__del_groupmembership__del_unique_groupmembershi.py
@@ -0,0 +1,441 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Removing unique constraint on 'ThreadToGroup', fields ['tag', 'thread']
+ db.delete_unique('askbot_thread_groups', ['tag_id', 'thread_id'])
+
+ # Removing unique constraint on 'PostToGroup', fields ['post', 'tag']
+ db.delete_unique('askbot_post_groups', ['post_id', 'tag_id'])
+
+ # Removing unique constraint on 'GroupMembership', fields ['group', 'user']
+ db.delete_unique('askbot_groupmembership', ['group_id', 'user_id'])
+
+ # Deleting model 'GroupProfile'
+ db.delete_table('askbot_groupprofile')
+
+ # Deleting model 'GroupMembership'
+ db.delete_table('askbot_groupmembership')
+
+ # Deleting field 'PostToGroup.tag'
+ db.delete_column('askbot_post_groups', 'tag_id')
+
+ # Changing field 'PostToGroup.group'
+ db.alter_column('askbot_post_groups', 'group_id', self.gf('django.db.models.fields.related.ForeignKey')(null=True, blank=True, to=orm['askbot.Group']))
+
+ # Adding unique constraint on 'PostToGroup', fields ['post', 'group']
+ db.create_unique('askbot_post_groups', ['post_id', 'group_id'])
+
+ # Deleting field 'ThreadToGroup.tag'
+ db.delete_column('askbot_thread_groups', 'tag_id')
+
+ # Changing field 'ThreadToGroup.group'
+ db.alter_column('askbot_thread_groups', 'group_id', self.gf('django.db.models.fields.related.ForeignKey')(null=True, blank=True, to=orm['askbot.Group']))
+
+ # Adding unique constraint on 'ThreadToGroup', fields ['group', 'thread']
+ db.create_unique('askbot_thread_groups', ['group_id', 'thread_id'])
+
+
+ def backwards(self, orm):
+
+ # Removing unique constraint on 'ThreadToGroup', fields ['group', 'thread']
+ db.delete_unique('askbot_thread_groups', ['group_id', 'thread_id'])
+
+ # Removing unique constraint on 'PostToGroup', fields ['post', 'group']
+ db.delete_unique('askbot_post_groups', ['post_id', 'group_id'])
+
+ # Adding model 'GroupProfile'
+ db.create_table('askbot_groupprofile', (
+ ('preapproved_emails', self.gf('django.db.models.fields.TextField')(default='', null=True, blank=True)),
+ ('is_open', self.gf('django.db.models.fields.BooleanField')(default=False)),
+ ('preapproved_email_domains', self.gf('django.db.models.fields.TextField')(default='', null=True, blank=True)),
+ ('moderate_email', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ('logo_url', self.gf('django.db.models.fields.URLField')(max_length=200, null=True)),
+ ('group_tag', self.gf('django.db.models.fields.related.OneToOneField')(related_name='group_profile', unique=True, to=orm['askbot.Tag'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ))
+ db.send_create_signal('askbot', ['GroupProfile'])
+
+ # Adding model 'GroupMembership'
+ db.create_table('askbot_groupmembership', (
+ ('group', self.gf('django.db.models.fields.related.ForeignKey')(related_name='user_memberships', to=orm['askbot.Tag'])),
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(related_name='group_memberships', to=orm['auth.User'])),
+ ))
+ db.send_create_signal('askbot', ['GroupMembership'])
+
+ # Adding unique constraint on 'GroupMembership', fields ['group', 'user']
+ db.create_unique('askbot_groupmembership', ['group_id', 'user_id'])
+
+ # Adding field 'PostToGroup.tag'
+ db.add_column('askbot_post_groups', 'tag', self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['askbot.Tag']), keep_default=False)
+
+ # Changing field 'PostToGroup.group'
+ db.alter_column('askbot_post_groups', 'group_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['askbot.Group'], null=True))
+
+ # Adding unique constraint on 'PostToGroup', fields ['post', 'tag']
+ db.create_unique('askbot_post_groups', ['post_id', 'tag_id'])
+
+ # Adding field 'ThreadToGroup.tag'
+ db.add_column('askbot_thread_groups', 'tag', self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['askbot.Tag']), keep_default=False)
+
+ # Changing field 'ThreadToGroup.group'
+ db.alter_column('askbot_thread_groups', 'group_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['askbot.Group'], null=True))
+
+ # Adding unique constraint on 'ThreadToGroup', fields ['tag', 'thread']
+ db.create_unique('askbot_thread_groups', ['tag_id', 'thread_id'])
+
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.askwidget': {
+ 'Meta': {'object_name': 'AskWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'groups'", 'null': 'True', 'to': "orm['askbot.Tag']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'include_text_field': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'inner_style': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'outer_style': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.group': {
+ 'Meta': {'object_name': 'Group', '_ormbases': ['auth.Group']},
+ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Group']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.posttogroup': {
+ 'Meta': {'unique_together': "(('post', 'group'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.questionwidget': {
+ 'Meta': {'object_name': 'QuestionWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order_by': ('django.db.models.fields.CharField', [], {'default': "'-added_at'", 'max_length': '18'}),
+ 'question_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '7'}),
+ 'search_query': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'style': ('django.db.models.fields.TextField', [], {'default': '"\\n@import url(\'http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700\');\\nbody {\\n overflow: hidden;\\n}\\n\\n#container {\\n width: 200px;\\n height: 350px;\\n}\\nul {\\n list-style: none;\\n padding: 5px;\\n margin: 5px;\\n}\\nli {\\n border-bottom: #CCC 1px solid;\\n padding-bottom: 5px;\\n padding-top: 5px;\\n}\\nli:last-child {\\n border: none;\\n}\\na {\\n text-decoration: none;\\n color: #464646;\\n font-family: \'Yanone Kaffeesatz\', sans-serif;\\n font-size: 15px;\\n}\\n"', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'through': "orm['askbot.ThreadToGroup']", 'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.threadtogroup': {
+ 'Meta': {'unique_together': "(('thread', 'group'),)", 'object_name': 'ThreadToGroup', 'db_table': "'askbot_thread_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0139_add__openness__field_to_group.py b/askbot/migrations/0139_add__openness__field_to_group.py
new file mode 100644
index 00000000..e909782a
--- /dev/null
+++ b/askbot/migrations/0139_add__openness__field_to_group.py
@@ -0,0 +1,359 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Group.openness'
+ db.add_column('askbot_group', 'openness',
+ self.gf('django.db.models.fields.SmallIntegerField')(default=2),
+ keep_default=False)
+
+ def backwards(self, orm):
+ # Deleting field 'Group.openness'
+ db.delete_column('askbot_group', 'openness')
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.askwidget': {
+ 'Meta': {'object_name': 'AskWidget'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'include_text_field': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'inner_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'outer_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.group': {
+ 'Meta': {'object_name': 'Group', '_ormbases': ['auth.Group']},
+ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'openness': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Group']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.posttogroup': {
+ 'Meta': {'unique_together': "(('post', 'group'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.questionwidget': {
+ 'Meta': {'object_name': 'QuestionWidget'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order_by': ('django.db.models.fields.CharField', [], {'default': "'-added_at'", 'max_length': '18'}),
+ 'question_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '7'}),
+ 'search_query': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'style': ('django.db.models.fields.TextField', [], {'default': '"\\n@import url(\'http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700\');\\nbody {\\n overflow: hidden;\\n}\\n\\n#container {\\n width: 200px;\\n height: 350px;\\n}\\nul {\\n list-style: none;\\n padding: 5px;\\n margin: 5px;\\n}\\nli {\\n border-bottom: #CCC 1px solid;\\n padding-bottom: 5px;\\n padding-top: 5px;\\n}\\nli:last-child {\\n border: none;\\n}\\na {\\n text-decoration: none;\\n color: #464646;\\n font-family: \'Yanone Kaffeesatz\', sans-serif;\\n font-size: 15px;\\n}\\n"', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'db_table': "'askbot_thread_groups'", 'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0140_move_group_field__is_open__to_openness.py b/askbot/migrations/0140_move_group_field__is_open__to_openness.py
new file mode 100644
index 00000000..36655aea
--- /dev/null
+++ b/askbot/migrations/0140_move_group_field__is_open__to_openness.py
@@ -0,0 +1,380 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from askbot.utils.console import ProgressBar
+
+#copied from askbot.models.Group for reference
+OPENNESS_CHOICES = (
+ (0, 'open'),
+ (1, 'moderated'),
+ (2, 'closed'),
+)
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ "Write your forwards methods here."
+ groups = orm['askbot.Group'].objects.all()
+ objects = groups.iterator()
+ count = groups.count()
+ message = 'Translating group is_open to openness setting'
+ for group in ProgressBar(objects, count, message):
+ if group.is_open:
+ group.openness = 0
+ group.save()
+
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+ groups = orm['askbot.Group'].objects.all()
+ objects = groups.iterator()
+ count = groups.count()
+ message = 'Translating group openness to back to is_open setting'
+ for group in ProgressBar(objects, count, message):
+ group.is_open = group.openness in (0, 1)
+ group.save()
+
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.askwidget': {
+ 'Meta': {'object_name': 'AskWidget'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'include_text_field': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'inner_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'outer_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.group': {
+ 'Meta': {'object_name': 'Group', '_ormbases': ['auth.Group']},
+ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
+ 'is_open': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'openness': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Group']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.posttogroup': {
+ 'Meta': {'unique_together': "(('post', 'group'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.questionwidget': {
+ 'Meta': {'object_name': 'QuestionWidget'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order_by': ('django.db.models.fields.CharField', [], {'default': "'-added_at'", 'max_length': '18'}),
+ 'question_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '7'}),
+ 'search_query': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'style': ('django.db.models.fields.TextField', [], {'default': '"\\n@import url(\'http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700\');\\nbody {\\n overflow: hidden;\\n}\\n\\n#container {\\n width: 200px;\\n height: 350px;\\n}\\nul {\\n list-style: none;\\n padding: 5px;\\n margin: 5px;\\n}\\nli {\\n border-bottom: #CCC 1px solid;\\n padding-bottom: 5px;\\n padding-top: 5px;\\n}\\nli:last-child {\\n border: none;\\n}\\na {\\n text-decoration: none;\\n color: #464646;\\n font-family: \'Yanone Kaffeesatz\', sans-serif;\\n font-size: 15px;\\n}\\n"', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'db_table': "'askbot_thread_groups'", 'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
+ symmetrical = True
diff --git a/askbot/migrations/0141_auto__del_field_group_is_open.py b/askbot/migrations/0141_auto__del_field_group_is_open.py
new file mode 100644
index 00000000..0c0c1803
--- /dev/null
+++ b/askbot/migrations/0141_auto__del_field_group_is_open.py
@@ -0,0 +1,358 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Deleting field 'Group.is_open'
+ db.delete_column('askbot_group', 'is_open')
+
+ def backwards(self, orm):
+ # Adding field 'Group.is_open'
+ db.add_column('askbot_group', 'is_open',
+ self.gf('django.db.models.fields.BooleanField')(default=False),
+ keep_default=False)
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.askwidget': {
+ 'Meta': {'object_name': 'AskWidget'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'include_text_field': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'inner_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'outer_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.group': {
+ 'Meta': {'object_name': 'Group', '_ormbases': ['auth.Group']},
+ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'openness': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Group']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.posttogroup': {
+ 'Meta': {'unique_together': "(('post', 'group'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.questionwidget': {
+ 'Meta': {'object_name': 'QuestionWidget'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order_by': ('django.db.models.fields.CharField', [], {'default': "'-added_at'", 'max_length': '18'}),
+ 'question_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '7'}),
+ 'search_query': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'style': ('django.db.models.fields.TextField', [], {'default': '"\\n@import url(\'http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700\');\\nbody {\\n overflow: hidden;\\n}\\n\\n#container {\\n width: 200px;\\n height: 350px;\\n}\\nul {\\n list-style: none;\\n padding: 5px;\\n margin: 5px;\\n}\\nli {\\n border-bottom: #CCC 1px solid;\\n padding-bottom: 5px;\\n padding-top: 5px;\\n}\\nli:last-child {\\n border: none;\\n}\\na {\\n text-decoration: none;\\n color: #464646;\\n font-family: \'Yanone Kaffeesatz\', sans-serif;\\n font-size: 15px;\\n}\\n"', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'db_table': "'askbot_thread_groups'", 'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot'] \ No newline at end of file
diff --git a/askbot/migrations/0142_auto__add_groupmembership.py b/askbot/migrations/0142_auto__add_groupmembership.py
new file mode 100644
index 00000000..80c5ba22
--- /dev/null
+++ b/askbot/migrations/0142_auto__add_groupmembership.py
@@ -0,0 +1,371 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding model 'GroupMembership'
+ db.create_table('askbot_groupmembership', (
+ ('authusergroups_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['auth.AuthUserGroups'], unique=True, primary_key=True)),
+ ('level', self.gf('django.db.models.fields.SmallIntegerField')(default=1)),
+ ))
+ db.send_create_signal('askbot', ['GroupMembership'])
+
+ def backwards(self, orm):
+ # Deleting model 'GroupMembership'
+ db.delete_table('askbot_groupmembership')
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.askwidget': {
+ 'Meta': {'object_name': 'AskWidget'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'include_text_field': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'inner_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'outer_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.group': {
+ 'Meta': {'object_name': 'Group', '_ormbases': ['auth.Group']},
+ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'openness': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'object_name': 'GroupMembership', '_ormbases': ['auth.AuthUserGroups']},
+ 'authusergroups_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.AuthUserGroups']", 'unique': 'True', 'primary_key': 'True'}),
+ 'level': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Group']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.posttogroup': {
+ 'Meta': {'unique_together': "(('post', 'group'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.questionwidget': {
+ 'Meta': {'object_name': 'QuestionWidget'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order_by': ('django.db.models.fields.CharField', [], {'default': "'-added_at'", 'max_length': '18'}),
+ 'question_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '7'}),
+ 'search_query': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'style': ('django.db.models.fields.TextField', [], {'default': '"\\n@import url(\'http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700\');\\nbody {\\n overflow: hidden;\\n}\\n\\n#container {\\n width: 200px;\\n height: 350px;\\n}\\nul {\\n list-style: none;\\n padding: 5px;\\n margin: 5px;\\n}\\nli {\\n border-bottom: #CCC 1px solid;\\n padding-bottom: 5px;\\n padding-top: 5px;\\n}\\nli:last-child {\\n border: none;\\n}\\na {\\n text-decoration: none;\\n color: #464646;\\n font-family: \'Yanone Kaffeesatz\', sans-serif;\\n font-size: 15px;\\n}\\n"', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'db_table': "'askbot_thread_groups'", 'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.authusergroups': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'AuthUserGroups', 'db_table': "'auth_user_groups'", 'managed': 'False'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot'] \ No newline at end of file
diff --git a/askbot/migrations/0143_populate_group_memberships.py b/askbot/migrations/0143_populate_group_memberships.py
new file mode 100644
index 00000000..b2fd086d
--- /dev/null
+++ b/askbot/migrations/0143_populate_group_memberships.py
@@ -0,0 +1,378 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from askbot.utils.console import ProgressBar
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ "Write your forwards methods here."
+ auth_memberships = orm['auth.AuthUserGroups'].objects.all()
+ count = auth_memberships.count()
+ objects = auth_memberships.iterator()
+ message = 'Populating Askbot group memberships'
+
+ for auth_membership in ProgressBar(objects, count, message):
+ membership = orm['askbot.GroupMembership']()
+ membership.authusergroups_ptr = auth_membership
+ membership.group = auth_membership.group
+ membership.user = auth_membership.user
+ membership.save()
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.askwidget': {
+ 'Meta': {'object_name': 'AskWidget'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'include_text_field': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'inner_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'outer_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.group': {
+ 'Meta': {'object_name': 'Group', '_ormbases': ['auth.Group']},
+ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'openness': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'object_name': 'GroupMembership', '_ormbases': ['auth.AuthUserGroups']},
+ 'authusergroups_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.AuthUserGroups']", 'unique': 'True', 'primary_key': 'True'}),
+ 'level': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Group']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.posttogroup': {
+ 'Meta': {'unique_together': "(('post', 'group'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.questionwidget': {
+ 'Meta': {'object_name': 'QuestionWidget'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order_by': ('django.db.models.fields.CharField', [], {'default': "'-added_at'", 'max_length': '18'}),
+ 'question_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '7'}),
+ 'search_query': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'style': ('django.db.models.fields.TextField', [], {'default': '"\\n@import url(\'http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700\');\\nbody {\\n overflow: hidden;\\n}\\n\\n#container {\\n width: 200px;\\n height: 350px;\\n}\\nul {\\n list-style: none;\\n padding: 5px;\\n margin: 5px;\\n}\\nli {\\n border-bottom: #CCC 1px solid;\\n padding-bottom: 5px;\\n padding-top: 5px;\\n}\\nli:last-child {\\n border: none;\\n}\\na {\\n text-decoration: none;\\n color: #464646;\\n font-family: \'Yanone Kaffeesatz\', sans-serif;\\n font-size: 15px;\\n}\\n"', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'db_table': "'askbot_thread_groups'", 'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.authusergroups': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'AuthUserGroups', 'db_table': "'auth_user_groups'", 'managed': 'False'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
+ symmetrical = True
diff --git a/askbot/migrations/0144_auto__add_field_questionwidget_group__add_field_askwidget_group.py b/askbot/migrations/0144_auto__add_field_questionwidget_group__add_field_askwidget_group.py
new file mode 100644
index 00000000..cb2a63f0
--- /dev/null
+++ b/askbot/migrations/0144_auto__add_field_questionwidget_group__add_field_askwidget_group.py
@@ -0,0 +1,384 @@
+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+
+ # Adding field 'QuestionWidget.group'
+ try:
+ db.delete_column('askbot_askwidget', 'group_id')
+ db.delete_column('askbot_questionwidget', 'group_id')
+ except:
+ pass
+
+ db.add_column('askbot_questionwidget', 'group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['askbot.Group'], null=True, blank=True), keep_default=False)
+
+ # Adding field 'AskWidget.group'
+ db.add_column('askbot_askwidget', 'group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['askbot.Group'], null=True, blank=True), keep_default=False)
+
+
+ def backwards(self, orm):
+
+ # Deleting field 'QuestionWidget.group'
+ db.delete_column('askbot_questionwidget', 'group_id')
+
+ # Deleting field 'AskWidget.group'
+ db.delete_column('askbot_askwidget', 'group_id')
+
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.askwidget': {
+ 'Meta': {'object_name': 'AskWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'include_text_field': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'inner_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'outer_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.group': {
+ 'Meta': {'object_name': 'Group', '_ormbases': ['auth.Group']},
+ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'openness': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'object_name': 'GroupMembership', '_ormbases': ['auth.AuthUserGroups']},
+ 'authusergroups_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.AuthUserGroups']", 'unique': 'True', 'primary_key': 'True'}),
+ 'level': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Group']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.posttogroup': {
+ 'Meta': {'unique_together': "(('post', 'group'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.questionwidget': {
+ 'Meta': {'object_name': 'QuestionWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order_by': ('django.db.models.fields.CharField', [], {'default': "'-added_at'", 'max_length': '18'}),
+ 'question_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '7'}),
+ 'search_query': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'style': ('django.db.models.fields.TextField', [], {'default': '"\\n@import url(\'http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700\');\\nbody {\\n overflow: hidden;\\n}\\n\\n#container {\\n width: 200px;\\n height: 350px;\\n}\\nul {\\n list-style: none;\\n padding: 5px;\\n margin: 5px;\\n}\\nli {\\n border-bottom: #CCC 1px solid;\\n padding-bottom: 5px;\\n padding-top: 5px;\\n}\\nli:last-child {\\n border: none;\\n}\\na {\\n text-decoration: none;\\n color: #464646;\\n font-family: \'Yanone Kaffeesatz\', sans-serif;\\n font-size: 15px;\\n}\\n"', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'db_table': "'askbot_thread_groups'", 'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.authusergroups': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'AuthUserGroups', 'db_table': "'auth_user_groups'", 'managed': 'False'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0145_add_moderate_answers_to_enquirers__to_askbot_group.py b/askbot/migrations/0145_add_moderate_answers_to_enquirers__to_askbot_group.py
new file mode 100644
index 00000000..74735130
--- /dev/null
+++ b/askbot/migrations/0145_add_moderate_answers_to_enquirers__to_askbot_group.py
@@ -0,0 +1,378 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Group.moderate_answers_to_enquirers'
+ db.add_column('askbot_group', 'moderate_answers_to_enquirers',
+ self.gf('django.db.models.fields.BooleanField')(default=False),
+ keep_default=False)
+
+ def backwards(self, orm):
+ # Deleting field 'Group.moderate_answers_to_enquirers'
+ db.delete_column('askbot_group', 'moderate_answers_to_enquirers')
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.askwidget': {
+ 'Meta': {'object_name': 'AskWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'include_text_field': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'inner_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'outer_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.group': {
+ 'Meta': {'object_name': 'Group', '_ormbases': ['auth.Group']},
+ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_answers_to_enquirers': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'openness': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'object_name': 'GroupMembership', '_ormbases': ['auth.AuthUserGroups']},
+ 'authusergroups_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.AuthUserGroups']", 'unique': 'True', 'primary_key': 'True'}),
+ 'level': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Group']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.posttogroup': {
+ 'Meta': {'unique_together': "(('post', 'group'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.questionwidget': {
+ 'Meta': {'object_name': 'QuestionWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order_by': ('django.db.models.fields.CharField', [], {'default': "'-added_at'", 'max_length': '18'}),
+ 'question_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '7'}),
+ 'search_query': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'style': ('django.db.models.fields.TextField', [], {'default': '"\\n@import url(\'http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700\');\\nbody {\\n overflow: hidden;\\n}\\n\\n#container {\\n width: 200px;\\n height: 350px;\\n}\\nul {\\n list-style: none;\\n padding: 5px;\\n margin: 5px;\\n}\\nli {\\n border-bottom: #CCC 1px solid;\\n padding-bottom: 5px;\\n padding-top: 5px;\\n}\\nli:last-child {\\n border: none;\\n}\\na {\\n text-decoration: none;\\n color: #464646;\\n font-family: \'Yanone Kaffeesatz\', sans-serif;\\n font-size: 15px;\\n}\\n"', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'through': "orm['askbot.ThreadToGroup']", 'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.threadtogroup': {
+ 'Meta': {'unique_together': "(('thread', 'group'),)", 'object_name': 'ThreadToGroup', 'db_table': "'askbot_thread_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.authusergroups': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'AuthUserGroups', 'db_table': "'auth_user_groups'", 'managed': 'False'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
diff --git a/askbot/migrations/0146_auto__add_field_threadtogroup_visibility.py b/askbot/migrations/0146_auto__add_field_threadtogroup_visibility.py
new file mode 100644
index 00000000..bc1d4377
--- /dev/null
+++ b/askbot/migrations/0146_auto__add_field_threadtogroup_visibility.py
@@ -0,0 +1,379 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'ThreadToGroup.visibility'
+ db.add_column('askbot_thread_groups', 'visibility',
+ self.gf('django.db.models.fields.SmallIntegerField')(default=1),
+ keep_default=False)
+
+ def backwards(self, orm):
+ # Deleting field 'ThreadToGroup.visibility'
+ db.delete_column('askbot_thread_groups', 'visibility')
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.askwidget': {
+ 'Meta': {'object_name': 'AskWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'include_text_field': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'inner_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'outer_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.group': {
+ 'Meta': {'object_name': 'Group', '_ormbases': ['auth.Group']},
+ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_answers_to_enquirers': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'openness': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'object_name': 'GroupMembership', '_ormbases': ['auth.AuthUserGroups']},
+ 'authusergroups_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.AuthUserGroups']", 'unique': 'True', 'primary_key': 'True'}),
+ 'level': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Group']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.posttogroup': {
+ 'Meta': {'unique_together': "(('post', 'group'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.questionwidget': {
+ 'Meta': {'object_name': 'QuestionWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order_by': ('django.db.models.fields.CharField', [], {'default': "'-added_at'", 'max_length': '18'}),
+ 'question_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '7'}),
+ 'search_query': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'style': ('django.db.models.fields.TextField', [], {'default': '"\\n@import url(\'http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700\');\\nbody {\\n overflow: hidden;\\n}\\n\\n#container {\\n width: 200px;\\n height: 350px;\\n}\\nul {\\n list-style: none;\\n padding: 5px;\\n margin: 5px;\\n}\\nli {\\n border-bottom: #CCC 1px solid;\\n padding-bottom: 5px;\\n padding-top: 5px;\\n}\\nli:last-child {\\n border: none;\\n}\\na {\\n text-decoration: none;\\n color: #464646;\\n font-family: \'Yanone Kaffeesatz\', sans-serif;\\n font-size: 15px;\\n}\\n"', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'through': "orm['askbot.ThreadToGroup']", 'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.threadtogroup': {
+ 'Meta': {'unique_together': "(('thread', 'group'),)", 'object_name': 'ThreadToGroup', 'db_table': "'askbot_thread_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'visibility': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.authusergroups': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'AuthUserGroups', 'db_table': "'auth_user_groups'", 'managed': 'False'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot'] \ No newline at end of file
diff --git a/askbot/migrations/0147_auto__add_field_group_description.py b/askbot/migrations/0147_auto__add_field_group_description.py
new file mode 100644
index 00000000..223fd974
--- /dev/null
+++ b/askbot/migrations/0147_auto__add_field_group_description.py
@@ -0,0 +1,380 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding field 'Group.description'
+ db.add_column('askbot_group', 'description',
+ self.gf('django.db.models.fields.related.OneToOneField')(blank=True, related_name='described_group', unique=True, null=True, to=orm['askbot.Post']),
+ keep_default=False)
+
+ def backwards(self, orm):
+ # Deleting field 'Group.description'
+ db.delete_column('askbot_group', 'description_id')
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.askwidget': {
+ 'Meta': {'object_name': 'AskWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'include_text_field': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'inner_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'outer_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.group': {
+ 'Meta': {'object_name': 'Group', '_ormbases': ['auth.Group']},
+ 'description': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'described_group'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_answers_to_enquirers': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'openness': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'object_name': 'GroupMembership', '_ormbases': ['auth.AuthUserGroups']},
+ 'authusergroups_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.AuthUserGroups']", 'unique': 'True', 'primary_key': 'True'}),
+ 'level': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Group']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.posttogroup': {
+ 'Meta': {'unique_together': "(('post', 'group'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.questionwidget': {
+ 'Meta': {'object_name': 'QuestionWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order_by': ('django.db.models.fields.CharField', [], {'default': "'-added_at'", 'max_length': '18'}),
+ 'question_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '7'}),
+ 'search_query': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'style': ('django.db.models.fields.TextField', [], {'default': '"\\n@import url(\'http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700\');\\nbody {\\n overflow: hidden;\\n}\\n\\n#container {\\n width: 200px;\\n height: 350px;\\n}\\nul {\\n list-style: none;\\n padding: 5px;\\n margin: 5px;\\n}\\nli {\\n border-bottom: #CCC 1px solid;\\n padding-bottom: 5px;\\n padding-top: 5px;\\n}\\nli:last-child {\\n border: none;\\n}\\na {\\n text-decoration: none;\\n color: #464646;\\n font-family: \'Yanone Kaffeesatz\', sans-serif;\\n font-size: 15px;\\n}\\n"', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'through': "orm['askbot.ThreadToGroup']", 'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.threadtogroup': {
+ 'Meta': {'unique_together': "(('thread', 'group'),)", 'object_name': 'ThreadToGroup', 'db_table': "'askbot_thread_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'visibility': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.authusergroups': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'AuthUserGroups', 'db_table': "'auth_user_groups'", 'managed': 'False'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot'] \ No newline at end of file
diff --git a/askbot/migrations/0148_rename_personal_groups.py b/askbot/migrations/0148_rename_personal_groups.py
new file mode 100644
index 00000000..e27f92d1
--- /dev/null
+++ b/askbot/migrations/0148_rename_personal_groups.py
@@ -0,0 +1,405 @@
+# -*- coding: utf-8 -*-
+"""renaming personal groups from old format to new format
+old format: _internal_<username>_<user_id>
+new format: _personal_<user_id>
+"""
+
+import datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+from askbot.utils.console import ProgressBar
+
+NEW_PREFIX = '_personal_'
+OLD_PREFIX = '_internal_'
+MESSAGE = 'Renaming personal groups'
+
+class Migration(DataMigration):
+
+ def forwards(self, orm):
+ "Write your forwards methods here."
+ groups = orm['askbot.Group'].objects.filter(name__startswith=OLD_PREFIX)
+ items = groups.iterator()
+ count = groups.count()
+ for group in ProgressBar(items, count, MESSAGE):
+ bits = group.name.split('_')
+ user_id_str = bits[-1]
+ group.name = NEW_PREFIX + user_id_str
+ group.save()
+
+
+
+ def backwards(self, orm):
+ "Write your backwards methods here."
+ groups = orm['askbot.Group'].objects.filter(name__startswith=NEW_PREFIX)
+ items = groups.iterator()
+ count = groups.count()
+ for group in ProgressBar(items, count, MESSAGE):
+ bits = group.name.split('_')
+ user_id_str = bits[-1]
+ user = orm['auth.User'].objects.get(id=int(user_id_str))
+ group.name = OLD_PREFIX + user.username + '_' + str(user.id)
+ group.save()
+
+ models = {
+ 'askbot.activity': {
+ 'Meta': {'object_name': 'Activity', 'db_table': "u'activity'"},
+ 'active_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'activity_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_auditted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True'}),
+ 'receiving_users': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'received_activity'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'incoming_activity'", 'symmetrical': 'False', 'through': "orm['askbot.ActivityAuditStatus']", 'to': "orm['auth.User']"}),
+ 'summary': ('django.db.models.fields.TextField', [], {'default': "''"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.activityauditstatus': {
+ 'Meta': {'unique_together': "(('user', 'activity'),)", 'object_name': 'ActivityAuditStatus'},
+ 'activity': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Activity']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.anonymousanswer': {
+ 'Meta': {'object_name': 'AnonymousAnswer'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'anonymous_answers'", 'to': "orm['askbot.Post']"}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.anonymousquestion': {
+ 'Meta': {'object_name': 'AnonymousQuestion'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ip_addr': ('django.db.models.fields.IPAddressField', [], {'max_length': '15'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'session_key': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'askbot.askwidget': {
+ 'Meta': {'object_name': 'AskWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'include_text_field': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'inner_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'outer_style': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Tag']", 'null': 'True', 'blank': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.award': {
+ 'Meta': {'object_name': 'Award', 'db_table': "u'award'"},
+ 'awarded_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'badge': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_badge'", 'to': "orm['askbot.BadgeData']"}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'notified': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'award_user'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.badgedata': {
+ 'Meta': {'ordering': "('slug',)", 'object_name': 'BadgeData'},
+ 'awarded_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'awarded_to': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'badges'", 'symmetrical': 'False', 'through': "orm['askbot.Award']", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50'})
+ },
+ 'askbot.draftanswer': {
+ 'Meta': {'object_name': 'DraftAnswer'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'draft_answers'", 'to': "orm['askbot.Thread']"})
+ },
+ 'askbot.draftquestion': {
+ 'Meta': {'object_name': 'DraftQuestion'},
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125', 'null': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300', 'null': 'True'})
+ },
+ 'askbot.emailfeedsetting': {
+ 'Meta': {'unique_together': "(('subscriber', 'feed_type'),)", 'object_name': 'EmailFeedSetting'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'feed_type': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'frequency': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '8'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reported_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
+ 'subscriber': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'notification_subscriptions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.favoritequestion': {
+ 'Meta': {'object_name': 'FavoriteQuestion', 'db_table': "u'favorite_question'"},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_favorite_questions'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.group': {
+ 'Meta': {'object_name': 'Group', '_ormbases': ['auth.Group']},
+ 'description': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'described_group'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'group_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.Group']", 'unique': 'True', 'primary_key': 'True'}),
+ 'logo_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True'}),
+ 'moderate_answers_to_enquirers': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'moderate_email': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'openness': ('django.db.models.fields.SmallIntegerField', [], {'default': '2'}),
+ 'preapproved_email_domains': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'}),
+ 'preapproved_emails': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.groupmembership': {
+ 'Meta': {'object_name': 'GroupMembership', '_ormbases': ['auth.AuthUserGroups']},
+ 'authusergroups_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.AuthUserGroups']", 'unique': 'True', 'primary_key': 'True'}),
+ 'level': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'})
+ },
+ 'askbot.markedtag': {
+ 'Meta': {'object_name': 'MarkedTag'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '16'}),
+ 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'user_selections'", 'to': "orm['askbot.Tag']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'tag_selections'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.post': {
+ 'Meta': {'object_name': 'Post'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'posts'", 'to': "orm['auth.User']"}),
+ 'comment_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_posts'", 'symmetrical': 'False', 'through': "orm['askbot.PostToGroup']", 'to': "orm['askbot.Group']"}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_edited_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'last_edited_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'last_edited_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'locked': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'locked_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'locked_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'locked_posts'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'offensive_flag_count': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'old_answer_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_comment_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'old_question_id': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'comments'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'post_type': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '180'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'posts'", 'null': 'True', 'blank': 'True', 'to': "orm['askbot.Thread']"}),
+ 'vote_down_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'vote_up_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'wiki': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'wikified_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'askbot.postflagreason': {
+ 'Meta': {'object_name': 'PostFlagReason'},
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
+ 'details': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'post_reject_reasons'", 'to': "orm['askbot.Post']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '128'})
+ },
+ 'askbot.postrevision': {
+ 'Meta': {'ordering': "('-revision',)", 'unique_together': "(('post', 'revision'),)", 'object_name': 'PostRevision'},
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
+ 'approved_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'approved_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'author': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postrevisions'", 'to': "orm['auth.User']"}),
+ 'by_email': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_address': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'is_anonymous': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'revisions'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'revised_at': ('django.db.models.fields.DateTimeField', [], {}),
+ 'revision': ('django.db.models.fields.PositiveIntegerField', [], {}),
+ 'summary': ('django.db.models.fields.CharField', [], {'max_length': '300', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '125', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {}),
+ 'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '300', 'blank': 'True'})
+ },
+ 'askbot.posttogroup': {
+ 'Meta': {'unique_together': "(('post', 'group'),)", 'object_name': 'PostToGroup', 'db_table': "'askbot_post_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']"})
+ },
+ 'askbot.questionview': {
+ 'Meta': {'object_name': 'QuestionView'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'viewed'", 'to': "orm['askbot.Post']"}),
+ 'when': ('django.db.models.fields.DateTimeField', [], {}),
+ 'who': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'question_views'", 'to': "orm['auth.User']"})
+ },
+ 'askbot.questionwidget': {
+ 'Meta': {'object_name': 'QuestionWidget'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']", 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order_by': ('django.db.models.fields.CharField', [], {'default': "'-added_at'", 'max_length': '18'}),
+ 'question_number': ('django.db.models.fields.PositiveIntegerField', [], {'default': '7'}),
+ 'search_query': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'style': ('django.db.models.fields.TextField', [], {'default': '"\\n@import url(\'http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700\');\\nbody {\\n overflow: hidden;\\n}\\n\\n#container {\\n width: 200px;\\n height: 350px;\\n}\\nul {\\n list-style: none;\\n padding: 5px;\\n margin: 5px;\\n}\\nli {\\n border-bottom: #CCC 1px solid;\\n padding-bottom: 5px;\\n padding-top: 5px;\\n}\\nli:last-child {\\n border: none;\\n}\\na {\\n text-decoration: none;\\n color: #464646;\\n font-family: \'Yanone Kaffeesatz\', sans-serif;\\n font-size: 15px;\\n}\\n"', 'blank': 'True'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'askbot.replyaddress': {
+ 'Meta': {'object_name': 'ReplyAddress'},
+ 'address': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '25'}),
+ 'allowed_from_email': ('django.db.models.fields.EmailField', [], {'max_length': '150'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'reply_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'reply_action': ('django.db.models.fields.CharField', [], {'default': "'auto_answer_or_comment'", 'max_length': '32'}),
+ 'response_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'edit_addresses'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_at': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.repute': {
+ 'Meta': {'object_name': 'Repute', 'db_table': "u'repute'"},
+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'negative': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'positive': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'question': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Post']", 'null': 'True', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'reputation_type': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'reputed_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'askbot.tag': {
+ 'Meta': {'ordering': "('-used_count', 'name')", 'object_name': 'Tag', 'db_table': "u'tag'"},
+ 'created_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'created_tags'", 'to': "orm['auth.User']"}),
+ 'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'deleted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'deleted_by': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'deleted_tags'", 'null': 'True', 'to': "orm['auth.User']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'suggested_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'suggested_tags'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'tag_wiki': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'described_tag'", 'unique': 'True', 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'used_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.thread': {
+ 'Meta': {'object_name': 'Thread'},
+ 'accepted_answer': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'+'", 'null': 'True', 'to': "orm['askbot.Post']"}),
+ 'added_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'answer_accepted_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'answer_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'approved': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
+ 'close_reason': ('django.db.models.fields.SmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'closed_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'closed_by': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}),
+ 'favorited_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'unused_favorite_threads'", 'symmetrical': 'False', 'through': "orm['askbot.FavoriteQuestion']", 'to': "orm['auth.User']"}),
+ 'favourite_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
+ 'followed_by': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'followed_threads'", 'symmetrical': 'False', 'to': "orm['auth.User']"}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'group_threads'", 'symmetrical': 'False', 'through': "orm['askbot.ThreadToGroup']", 'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_activity_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_activity_by': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'unused_last_active_in_threads'", 'to': "orm['auth.User']"}),
+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'tagnames': ('django.db.models.fields.CharField', [], {'max_length': '125'}),
+ 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'threads'", 'symmetrical': 'False', 'to': "orm['askbot.Tag']"}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '300'}),
+ 'view_count': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
+ },
+ 'askbot.threadtogroup': {
+ 'Meta': {'unique_together': "(('thread', 'group'),)", 'object_name': 'ThreadToGroup', 'db_table': "'askbot_thread_groups'"},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'thread': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['askbot.Thread']"}),
+ 'visibility': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'})
+ },
+ 'askbot.vote': {
+ 'Meta': {'unique_together': "(('user', 'voted_post'),)", 'object_name': 'Vote', 'db_table': "u'vote'"},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['auth.User']"}),
+ 'vote': ('django.db.models.fields.SmallIntegerField', [], {}),
+ 'voted_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'voted_post': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'votes'", 'to': "orm['askbot.Post']"})
+ },
+ 'auth.authusergroups': {
+ 'Meta': {'unique_together': "(('group', 'user'),)", 'object_name': 'AuthUserGroups', 'db_table': "'auth_user_groups'", 'managed': 'False'},
+ 'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ }
+ }
+
+ complete_apps = ['askbot']
+ symmetrical = True
diff --git a/askbot/migrations_api/__init__.py b/askbot/migrations_api/__init__.py
index 1e213613..586c02d9 100644
--- a/askbot/migrations_api/__init__.py
+++ b/askbot/migrations_api/__init__.py
@@ -4,6 +4,23 @@ by mitigating absence of access to the django model api
since models change with time, this api is implemented in different
versions. Different versions do not need to have all the same functions.
"""
+from south.db import db
+
+def safe_add_column(table, column, column_data, keep_default = False):
+ """when user calls syncdb with askbot the first time
+ the auth_user table will be created together with the patched columns
+ so, we need to add these columns here in separate transactions
+ and roll back if they fail, if we want we could also record - which columns clash
+ """
+ try:
+ db.start_transaction()
+ db.add_column(table, column, column_data, keep_default = keep_default)
+ db.commit_transaction()
+ return True
+ except:
+ db.rollback_transaction()
+ return False
+
class BaseAPI(object):
def __init__(self, orm):
diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py
index 03ab218b..4cddacb9 100644
--- a/askbot/models/__init__.py
+++ b/askbot/models/__init__.py
@@ -1,17 +1,27 @@
from askbot import startup_procedures
startup_procedures.run()
+from django.contrib.auth.models import User
+#set up a possibility for the users to follow others
+try:
+ import followit
+ followit.register(User)
+except ImportError:
+ pass
+
import collections
import datetime
import hashlib
import logging
import urllib
+import uuid
+from celery import states
+from celery.task import task
from django.core.urlresolvers import reverse, NoReverseMatch
from django.db.models import signals as django_signals
from django.template import Context
from django.utils.translation import ugettext as _
from django.utils.translation import ungettext
-from django.contrib.auth.models import User
from django.utils.safestring import mark_safe
from django.utils.html import escape
from django.db import models
@@ -26,16 +36,27 @@ from askbot.const.message_keys import get_i18n_message
from askbot.conf import settings as askbot_settings
from askbot.models.question import Thread
from askbot.skins import utils as skin_utils
+from askbot.mail import messages
from askbot.models.question import QuestionView, AnonymousQuestion
+from askbot.models.question import DraftQuestion
from askbot.models.question import FavoriteQuestion
from askbot.models.tag import Tag, MarkedTag
+from askbot.models.tag import get_global_group
+from askbot.models.tag import get_group_names
+from askbot.models.tag import get_groups
+from askbot.models.tag import format_personal_group_name
from askbot.models.user import EmailFeedSetting, ActivityAuditStatus, Activity
-from askbot.models.user import GroupMembership, GroupProfile
-from askbot.models.post import Post, PostRevision, PostFlagReason, AnonymousAnswer
+from askbot.models.user import GroupMembership
+from askbot.models.user import Group
+from askbot.models.post import Post, PostRevision
+from askbot.models.post import PostFlagReason, AnonymousAnswer
+from askbot.models.post import PostToGroup
+from askbot.models.post import DraftAnswer
from askbot.models.reply_by_email import ReplyAddress
from askbot.models import signals
from askbot.models.badges import award_badges_signal, get_badge, BadgeData
from askbot.models.repute import Award, Repute, Vote
+from askbot.models.widgets import AskWidget, QuestionWidget
from askbot import auth
from askbot.utils.decorators import auto_now_timestamp
from askbot.utils.slug import slugify
@@ -48,14 +69,27 @@ def get_model(model_name):
"""a shortcut for getting model for an askbot app"""
return models.get_model('askbot', model_name)
-def get_admins_and_moderators():
- """returns query set of users who are site administrators
- and moderators"""
- return User.objects.filter(
- models.Q(is_superuser=True) | models.Q(status='m')
- )
+def get_admin():
+ """returns admin with the lowest user ID
+ if there are no users at all - creates one
+ with name "admin" and unusable password
+ otherwise raises User.DoesNotExist
+ """
+ try:
+ return User.objects.filter(
+ is_superuser=True
+ ).order_by('id')[0]
+ except IndexError:
+ if User.objects.filter(username='_admin_').count() == 0:
+ admin = User.objects.create_user('_admin_', '')
+ admin.set_unusable_password()
+ admin.set_admin_status()
+ admin.save()
+ return admin
+ else:
+ raise User.DoesNotExist
-def get_users_by_text_query(search_query):
+def get_users_by_text_query(search_query, users_query_set = None):
"""Runs text search in user names and profile.
For postgres, search also runs against user group names.
"""
@@ -65,11 +99,13 @@ def get_users_by_text_query(search_query):
return qs
else:
import askbot
+ if users_query_set is None:
+ users_query_set = User.objects.all()
if 'postgresql_psycopg2' in askbot.get_database_engine_name():
from askbot.search import postgresql
- return postgresql.run_full_text_search(User.objects.all(), search_query)
+ return postgresql.run_full_text_search(users_query_set, search_query)
else:
- return User.objects.filter(
+ return users_query_set.filter(
models.Q(username__icontains=search_query) |
models.Q(about__icontains=search_query)
)
@@ -88,6 +124,7 @@ User.add_to_class(
choices = const.USER_STATUS_CHOICES
)
)
+User.add_to_class('is_fake', models.BooleanField(default=False))
User.add_to_class('email_isvalid', models.BooleanField(default=False)) #@UndefinedVariable
User.add_to_class('email_key', models.CharField(max_length=32, null=True))
@@ -337,6 +374,13 @@ def user_has_interesting_wildcard_tags(self):
and self.interesting_tags != ''
)
+def user_can_create_tags(self):
+ """true if user can create tags"""
+ if askbot_settings.ENABLE_TAG_MODERATION:
+ return self.is_administrator_or_moderator()
+ else:
+ return True
+
def user_can_have_strong_url(self):
"""True if user's homepage url can be
followed by the search engine crawlers"""
@@ -348,6 +392,52 @@ def user_can_post_by_email(self):
return askbot_settings.REPLY_BY_EMAIL and \
self.reputation > askbot_settings.MIN_REP_TO_POST_BY_EMAIL
+def user_get_or_create_fake_user(self, username, email):
+ """
+ Get's or creates a user, most likely with the purpose
+ of posting under that account.
+ """
+ assert(self.is_administrator())
+
+ try:
+ user = User.objects.get(username=username)
+ except User.DoesNotExist:
+ user = User()
+ user.username = username
+ user.email = email
+ user.is_fake = True
+ user.set_unusable_password()
+ user.save()
+ return user
+
+def user_notify_users(
+ self, notification_type=None, recipients=None, content_object=None
+):
+ """A utility function that creates instance
+ of :class:`Activity` and adds recipients
+ * `notification_type` - value should be one of TYPE_ACTIVITY_...
+ * `recipients` - an iterable of user objects
+ * `content_object` - any object related to the notification
+
+ todo: possibly add checks on the content_object, depending on the
+ notification_type
+ """
+ activity = Activity(
+ user=self,
+ activity_type=notification_type,
+ content_object=content_object
+ )
+ activity.save()
+ activity.add_recipients(recipients)
+
+def user_get_notifications(self, notification_types=None, **kwargs):
+ """returns query set of activity audit status objects"""
+ return ActivityAuditStatus.objects.filter(
+ user=self,
+ activity__activity_type__in=notification_types,
+ **kwargs
+ )
+
def _assert_user_can(
user = None,
post = None, #related post (may be parent)
@@ -556,9 +646,16 @@ def user_assert_can_post_question(self):
)
-def user_assert_can_post_answer(self):
+def user_assert_can_post_answer(self, thread = None):
"""same as user_can_post_question
"""
+ limit_answers = askbot_settings.LIMIT_ONE_ANSWER_PER_USER
+ if limit_answers and thread.has_answer_by_user(self):
+ message = _(
+ 'Sorry, you already gave an answer, please edit it instead.'
+ )
+ raise askbot_exceptions.AnswerAlreadyGiven(message)
+
self.assert_can_post_question()
@@ -842,7 +939,9 @@ def user_assert_can_close_question(self, question = None):
def user_assert_can_reopen_question(self, question = None):
assert(question.post_type == 'question')
+ #for some reason rep to reopen own questions != rep to close own q's
owner_min_rep_setting = askbot_settings.MIN_REP_TO_REOPEN_OWN_QUESTIONS
+ min_rep_setting = askbot_settings.MIN_REP_TO_CLOSE_OTHERS_QUESTIONS
general_error_message = _(
'Sorry, only administrators, moderators '
@@ -855,15 +954,27 @@ def user_assert_can_reopen_question(self, question = None):
'a minimum reputation of %(min_rep)s is required'
) % {'min_rep': owner_min_rep_setting}
+ blocked_error_message = _(
+ 'Sorry, you cannot reopen questions '
+ 'because your account is blocked'
+ )
+
+ suspended_error_message = _(
+ 'Sorry, you cannot reopen questions '
+ 'because your account is suspended'
+ )
+
_assert_user_can(
user = self,
post = question,
- admin_or_moderator_required = True,
owner_can = True,
suspended_owner_cannot = True,
owner_min_rep_setting = owner_min_rep_setting,
+ min_rep_setting = min_rep_setting,
owner_low_rep_error_message = owner_low_rep_error_message,
- general_error_message = general_error_message
+ general_error_message = general_error_message,
+ blocked_error_message = blocked_error_message,
+ suspended_error_message = suspended_error_message
)
@@ -1094,6 +1205,8 @@ def user_post_comment(
added_at = timestamp,
by_email = by_email
)
+ comment.add_to_groups([self.get_personal_group()])
+
parent_post.thread.invalidate_cached_data()
award_badges_signal.send(
None,
@@ -1104,21 +1217,21 @@ def user_post_comment(
)
return comment
-def user_post_tag_wiki(
+def user_post_object_description(
self,
- tag = None,
- body_text = None,
- timestamp = None
+ obj=None,
+ body_text=None,
+ timestamp=None
):
- """Creates a tag wiki post and assigns it
- to the given tag. Returns the newly created post"""
- tag_wiki_post = Post.objects.create_new_tag_wiki(
- author = self,
- text = body_text
+ """Creates an object description post and assigns it
+ to the given object. Returns the newly created post"""
+ description_post = Post.objects.create_new_tag_wiki(
+ author=self,
+ text=body_text
)
- tag.tag_wiki = tag_wiki_post
- tag.save()
- return tag_wiki_post
+ obj.description = description_post
+ obj.save()
+ return description_post
def user_post_anonymous_askbot_content(user, session_key):
@@ -1443,6 +1556,8 @@ def user_post_question(
tags = None,
wiki = False,
is_anonymous = False,
+ is_private = False,
+ group_id = None,
timestamp = None,
by_email = False,
email_address = None
@@ -1472,6 +1587,8 @@ def user_post_question(
added_at = timestamp,
wiki = wiki,
is_anonymous = is_anonymous,
+ is_private = is_private,
+ group_id = group_id,
by_email = by_email,
email_address = email_address
)
@@ -1509,7 +1626,8 @@ def user_edit_post(self,
body_text = None,
revision_comment = None,
timestamp = None,
- by_email = False
+ by_email = False,
+ is_private = False
):
"""a simple method that edits post body
todo: unify it in the style of just a generic post
@@ -1536,7 +1654,8 @@ def user_edit_post(self,
body_text = body_text,
timestamp = timestamp,
revision_comment = revision_comment,
- by_email = by_email
+ by_email = by_email,
+ is_private = is_private
)
elif post.post_type == 'tag_wiki':
post.apply_edit(
@@ -1561,6 +1680,7 @@ def user_edit_question(
tags = None,
wiki = False,
edit_anonymously = False,
+ is_private = False,
timestamp = None,
force = False,#if True - bypass the assert
by_email = False
@@ -1578,6 +1698,7 @@ def user_edit_question(
tags = tags,
wiki = wiki,
edit_anonymously = edit_anonymously,
+ is_private = is_private,
by_email = by_email
)
@@ -1597,6 +1718,7 @@ def user_edit_answer(
body_text = None,
revision_comment = None,
wiki = False,
+ is_private = False,
timestamp = None,
force = False,#if True - bypass the assert
by_email = False
@@ -1609,8 +1731,10 @@ def user_edit_answer(
text = body_text,
comment = revision_comment,
wiki = wiki,
+ is_private = is_private,
by_email = by_email
)
+
answer.thread.invalidate_cached_data()
award_badges_signal.send(None,
event = 'edit_answer',
@@ -1637,7 +1761,7 @@ def user_create_post_reject_reason(
added_at = timestamp,
text = details
)
- details.parse_and_save(author = self)
+ details.parse_and_save(author=self)
details.add_revision(
author = self,
revised_at = timestamp,
@@ -1667,6 +1791,7 @@ def user_post_answer(
body_text = None,
follow = False,
wiki = False,
+ is_private = False,
timestamp = None,
by_email = False
):
@@ -1709,7 +1834,7 @@ def user_post_answer(
assert(error_message is not None)
raise django_exceptions.PermissionDenied(error_message)
- self.assert_can_post_answer()
+ self.assert_can_post_answer(thread = question.thread)
if getattr(question, 'post_type', '') != 'question':
raise TypeError('question argument must be provided')
@@ -1732,8 +1857,12 @@ def user_post_answer(
added_at = timestamp,
email_notify = follow,
wiki = wiki,
+ is_private = is_private,
by_email = by_email
)
+ #add to the answerer's group
+ answer_post.add_to_groups([self.get_personal_group()])
+
answer_post.thread.invalidate_cached_data()
award_badges_signal.send(None,
event = 'post_answer',
@@ -2105,16 +2234,55 @@ def get_profile_link(self):
return mark_safe(profile_link)
+def user_get_groups(self, private=False):
+ """returns a query set of groups to which user belongs"""
+ #todo: maybe cache this query
+ return Group.objects.get_for_user(self, private=private)
+
+def user_get_personal_group(self):
+ group_name = format_personal_group_name(self)
+ return Group.objects.get(name=group_name)
+
+def user_get_foreign_groups(self):
+ """returns a query set of groups to which user does not belong"""
+ #todo: maybe cache this query
+ user_group_ids = self.get_groups().values_list('id', flat = True)
+ return get_groups().exclude(id__in = user_group_ids)
+
+def user_get_primary_group(self):
+ """a temporary function - returns ether None or
+ first non-personal non-everyone group
+ works only for one real private group per-person
+ """
+ groups = self.get_groups(private=True)
+ for group in groups:
+ if group.is_personal():
+ continue
+ return group
+ return None
+
+def user_can_make_group_private_posts(self):
+ """simplest implementation: user belongs to at least one group"""
+ return self.get_groups(private=True).count() > 0
+
+def user_get_group_membership(self, group):
+ """returns a group membership object or None
+ if it is not there
+ """
+ try:
+ return GroupMembership.objects.get(user=self, group=group)
+ except GroupMembership.DoesNotExist:
+ return None
+
+
def user_get_groups_membership_info(self, groups):
- """returts a defaultdict with values that are
+ """returns a defaultdict with values that are
dictionaries with the following keys and values:
- * key: can_join, value: True if user can join group
- * key: is_member, value: True if user is member of group
+ * key: acceptance_level, value: 'closed', 'moderated', 'open'
+ * key: membership_level, value: 'none', 'pending', 'full'
``groups`` is a group tag query set
"""
- groups = groups.select_related('group_profile')
-
group_ids = groups.values_list('id', flat = True)
memberships = GroupMembership.objects.filter(
user__id = self.id,
@@ -2122,18 +2290,17 @@ def user_get_groups_membership_info(self, groups):
)
info = collections.defaultdict(
- lambda: {'can_join': False, 'is_member': False}
+ lambda: {'acceptance_level': 'closed', 'membership_level': 'none'}
)
for membership in memberships:
- info[membership.group_id]['is_member'] = True
+ membership_level = membership.get_level_display()
+ info[membership.group_id]['membership_level'] = membership_level
for group in groups:
- info[group.id]['can_join'] = group.group_profile.can_accept_user(self)
+ info[group.id]['acceptance_level'] = group.get_openness_level_for_user(self)
return info
-
-
def user_get_karma_summary(self):
"""returns human readable sentence about
status of user's karma"""
@@ -2156,14 +2323,14 @@ def user_get_badge_summary(self):
bit = ungettext(
'one silver badge',
'%(count)d silver badges',
- self.gold
+ self.silver
) % {'count': self.silver}
badge_bits.append(bit)
- if self.silver:
+ if self.bronze:
bit = ungettext(
'one bronze badge',
'%(count)d bronze badges',
- self.gold
+ self.bronze
) % {'count': self.bronze}
badge_bits.append(bit)
@@ -2357,15 +2524,18 @@ def user_approve_post_revision(user, post_revision, timestamp = None):
)
@auto_now_timestamp
-def flag_post(user, post, timestamp=None, cancel=False, cancel_all = False, force = False):
+def flag_post(
+ user, post, timestamp=None, cancel=False, cancel_all=False, force=False
+):
if cancel_all:
# remove all flags
if force == False:
- user.assert_can_remove_all_flags_offensive(post = post)
+ user.assert_can_remove_all_flags_offensive(post=post)
post_content_type = ContentType.objects.get_for_model(post)
all_flags = Activity.objects.filter(
- activity_type = const.TYPE_ACTIVITY_MARK_OFFENSIVE,
- content_type = post_content_type, object_id=post.id
+ activity_type=const.TYPE_ACTIVITY_MARK_OFFENSIVE,
+ content_type=post_content_type,
+ object_id=post.id
)
for flag in all_flags:
auth.onUnFlaggedItem(post, flag.user, timestamp=timestamp)
@@ -2377,7 +2547,7 @@ def flag_post(user, post, timestamp=None, cancel=False, cancel_all = False, forc
else:
if force == False:
- user.assert_can_flag_offensive(post = post)
+ user.assert_can_flag_offensive(post=post)
auth.onFlaggedItem(post, user, timestamp=timestamp)
award_badges_signal.send(None,
event = 'flag_post',
@@ -2483,23 +2653,54 @@ def user_update_wildcard_tag_selections(
return new_tags
-def user_edit_group_membership(self, user = None, group = None, action = None):
+def user_edit_group_membership(self, user=None, group=None, action=None):
"""allows one user to add another to a group
or remove user from group.
If when adding, the group does not exist, it will be created
the delete function is not symmetric, the group will remain
even if it becomes empty
+
+ returns instance of GroupMembership (if action is "add") or None
"""
if action == 'add':
- GroupMembership.objects.get_or_create(user = user, group = group)
+ #calculate new level
+ openness = group.get_openness_level_for_user(user)
+
+ #let people join these special groups, but not leave
+ if group.name == askbot_settings.GLOBAL_GROUP_NAME:
+ openness = 'open'
+ elif group.name == format_personal_group_name(user):
+ openness = 'open'
+
+ if openness == 'open':
+ level = GroupMembership.FULL
+ elif openness == 'moderated':
+ level = GroupMembership.PENDING
+ elif openness == 'closed':
+ raise django_exceptions.PermissionDenied()
+
+ membership, created = GroupMembership.objects.get_or_create(
+ user=user, group=group, level=level
+ )
+ return membership
+
elif action == 'remove':
GroupMembership.objects.get(user = user, group = group).delete()
+ return None
else:
raise ValueError('invalid action')
-def user_is_group_member(self, group = None):
- return self.group_memberships.filter(group = group).count() == 1
+def user_join_group(self, group):
+ return self.edit_group_membership(group=group, user=self, action='add')
+
+def user_leave_group(self, group):
+ self.edit_group_membership(group=group, user=self, action='remove')
+
+def user_is_group_member(self, group=None):
+ return GroupMembership.objects.filter(
+ user=self, group=group
+ ).count() == 1
User.add_to_class(
'add_missing_askbot_subscriptions',
@@ -2521,8 +2722,15 @@ User.add_to_class('get_absolute_url', user_get_absolute_url)
User.add_to_class('get_avatar_url', user_get_avatar_url)
User.add_to_class('get_default_avatar_url', user_get_default_avatar_url)
User.add_to_class('get_gravatar_url', user_get_gravatar_url)
+User.add_to_class('get_or_create_fake_user', user_get_or_create_fake_user)
User.add_to_class('get_marked_tags', user_get_marked_tags)
User.add_to_class('get_marked_tag_names', user_get_marked_tag_names)
+User.add_to_class('get_groups', user_get_groups)
+User.add_to_class('get_foreign_groups', user_get_foreign_groups)
+User.add_to_class('get_group_membership', user_get_group_membership)
+User.add_to_class('get_personal_group', user_get_personal_group)
+User.add_to_class('get_primary_group', user_get_primary_group)
+User.add_to_class('get_notifications', user_get_notifications)
User.add_to_class('strip_email_signature', user_strip_email_signature)
User.add_to_class('get_groups_membership_info', user_get_groups_membership_info)
User.add_to_class('get_anonymous_name', user_get_anonymous_name)
@@ -2542,7 +2750,7 @@ User.add_to_class('edit_comment', user_edit_comment)
User.add_to_class('create_post_reject_reason', user_create_post_reject_reason)
User.add_to_class('edit_post_reject_reason', user_edit_post_reject_reason)
User.add_to_class('delete_post', user_delete_post)
-User.add_to_class('post_tag_wiki', user_post_tag_wiki)
+User.add_to_class('post_object_description', user_post_object_description)
User.add_to_class('visit_question', user_visit_question)
User.add_to_class('upvote', upvote)
User.add_to_class('downvote', downvote)
@@ -2565,13 +2773,17 @@ User.add_to_class('unfollow_question', user_unfollow_question)
User.add_to_class('is_following_question', user_is_following_question)
User.add_to_class('mark_tags', user_mark_tags)
User.add_to_class('update_response_counts', user_update_response_counts)
+User.add_to_class('can_create_tags', user_can_create_tags)
User.add_to_class('can_have_strong_url', user_can_have_strong_url)
User.add_to_class('can_post_by_email', user_can_post_by_email)
User.add_to_class('can_post_comment', user_can_post_comment)
+User.add_to_class('can_make_group_private_posts', user_can_make_group_private_posts)
User.add_to_class('is_administrator', user_is_administrator)
User.add_to_class('is_administrator_or_moderator', user_is_administrator_or_moderator)
User.add_to_class('set_admin_status', user_set_admin_status)
User.add_to_class('edit_group_membership', user_edit_group_membership)
+User.add_to_class('join_group', user_join_group)
+User.add_to_class('leave_group', user_leave_group)
User.add_to_class('is_group_member', user_is_group_member)
User.add_to_class('remove_admin_status', user_remove_admin_status)
User.add_to_class('is_moderator', user_is_moderator)
@@ -2602,6 +2814,7 @@ User.add_to_class(
user_update_wildcard_tag_selections
)
User.add_to_class('approve_post_revision', user_approve_post_revision)
+User.add_to_class('notify_users', user_notify_users)
#assertions
User.add_to_class('assert_can_vote_for_post', user_assert_can_vote_for_post)
@@ -2683,6 +2896,8 @@ def format_instant_notification_email(
assert(isinstance(post, Post) and post.is_question())
elif update_type == 'new_question':
assert(isinstance(post, Post) and post.is_question())
+ elif update_type == 'post_shared':
+ pass
else:
raise ValueError('unexpected update_type %s' % update_type)
@@ -2707,9 +2922,11 @@ def format_instant_notification_email(
content_preview += '<p>======= Full thread summary =======</p>'
- content_preview += post.thread.format_for_email()
+ content_preview += post.thread.format_for_email(user=to_user)
- if post.is_comment():
+ if update_type == 'post_shared':
+ user_action = _('%(user)s shared a %(post_link)s.')
+ elif post.is_comment():
if update_type.endswith('update'):
user_action = _('%(user)s edited a %(post_link)s.')
else:
@@ -2732,6 +2949,7 @@ def format_instant_notification_email(
user_action = user_action % {
'user': '<a href="%s">%s</a>' % (user_url, from_user.username),
'post_link': '<a href="%s">%s</a>' % (post_url, _(post.post_type))
+ #'post_link': '%s <a href="%s">>>></a>' % (_(post.post_type), post_url)
}
can_reply = to_user.can_post_by_email()
@@ -2749,6 +2967,10 @@ def format_instant_notification_email(
reply_separator += '<p>' + \
const.REPLY_WITH_COMMENT_TEMPLATE % data
reply_separator += '</p>'
+ else:
+ reply_separator = '<p>%s</p>' % reply_separator
+
+ reply_separator += user_action
else:
reply_separator = user_action
@@ -2763,14 +2985,12 @@ def format_instant_notification_email(
'post_url': post_url,
'origin_post_title': origin_post.thread.title,
'user_subscriptions_url': user_subscriptions_url,
- 'reply_separator': reply_separator
+ 'reply_separator': reply_separator,
+ 'reply_address': reply_address
}
subject_line = _('"%(title)s"') % {'title': origin_post.thread.title}
content = template.render(Context(update_data))
- if can_reply:
- content += '<p style="font-size:8px;color:#aaa">' + \
- reply_address + '</p>'
return subject_line, content
@@ -2818,17 +3038,15 @@ def get_reply_to_addresses(user, post):
return primary_addr, secondary_addr
#todo: action
+@task()
def send_instant_notifications_about_activity_in_post(
update_activity = None,
post = None,
recipients = None,
):
- """
- function called when posts are updated
- newly mentioned users are carried through to reduce
- database hits
- """
- if askbot_settings.ENABLE_CONTENT_MODERATION and post.approved == False:
+ #reload object from the database
+ post = Post.objects.get(id=post.id)
+ if post.is_approved() is False:
return
if recipients is None:
@@ -2849,8 +3067,20 @@ def send_instant_notifications_about_activity_in_post(
origin_post,
update_activity.activity_type
)
- #send email for all recipients
+
+ logger = logging.getLogger()
+ if logger.getEffectiveLevel() <= logging.DEBUG:
+ log_id = uuid.uuid1()
+ message = 'email-alert %s, logId=%s' % (post.get_absolute_url(), log_id)
+ logger.debug(message)
+ else:
+ log_id = None
+
+
for user in recipients:
+ if user.is_blocked():
+ continue
+
reply_address, alt_reply_address = get_reply_to_addresses(user, post)
subject_line, body_text = format_instant_notification_email(
@@ -2860,18 +3090,27 @@ def send_instant_notifications_about_activity_in_post(
reply_address = reply_address,
alt_reply_address = alt_reply_address,
update_type = update_type,
- template = get_template('instant_notification.html')
+ template = get_template('email/instant_notification.html')
)
headers['Reply-To'] = reply_address
- mail.send_mail(
- subject_line = subject_line,
- body_text = body_text,
- recipient_list = [user.email],
- related_object = origin_post,
- activity_type = const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT,
- headers = headers
- )
+ try:
+ mail.send_mail(
+ subject_line=subject_line,
+ body_text=body_text,
+ recipient_list=[user.email],
+ related_object=origin_post,
+ activity_type=const.TYPE_ACTIVITY_EMAIL_UPDATE_SENT,
+ headers=headers,
+ raise_on_failure=True
+ )
+ except askbot_exceptions.EmailNotSent, error:
+ logger.debug(
+ '%s, error=%s, logId=%s' % (user.email, error, log_id)
+ )
+ else:
+ logger.debug('success %s, logId=%s' % (user.email, log_id))
+
def notify_author_of_published_revision(
revision = None, was_approved = None, **kwargs
@@ -3095,7 +3334,7 @@ def record_flag_offensive(instance, mark_by, **kwargs):
# recipients = instance.get_author_list(
# exclude_list = [mark_by]
# )
- activity.add_recipients(get_admins_and_moderators())
+ activity.add_recipients(instance.get_moderators())
def remove_flag_offensive(instance, mark_by, **kwargs):
"Remove flagging activity"
@@ -3195,22 +3434,60 @@ def send_respondable_email_validation_message(
)
-def send_welcome_email(user, **kwargs):
+def add_user_to_global_group(sender, instance, created, **kwargs):
+ """auto-joins user to the global group
+ ``instance`` is an instance of ``User`` class
+ """
+ if created:
+ from askbot.models.tag import get_global_group
+ instance.edit_group_membership(
+ group=get_global_group(),
+ user=instance,
+ action='add'
+ )
+
+
+def add_user_to_personal_group(sender, instance, created, **kwargs):
+ """auto-joins user to his/her personal group
+ ``instance`` is an instance of ``User`` class
+ """
+ if created:
+ #todo: groups will indeed need to be separated from tags
+ #so that we can use less complicated naming scheme
+ #in theore here we may have two users that will have
+ #identical group names!!!
+ group_name = format_personal_group_name(instance)
+ group = Group.objects.get_or_create(
+ name=group_name, user=instance
+ )
+ instance.edit_group_membership(
+ group=group, user=instance, action='add'
+ )
+
+
+def greet_new_user(user, **kwargs):
"""sends welcome email to the newly created user
todo: second branch should send email with a simple
clickable link.
"""
+ if askbot_settings.NEW_USER_GREETING:
+ user.message_set.create(message = askbot_settings.NEW_USER_GREETING)
+
if askbot_settings.REPLY_BY_EMAIL:#with this on we also collect signature
- data = {
- 'site_name': askbot_settings.APP_SHORT_NAME
- }
- send_respondable_email_validation_message(
- user = user,
- subject_line = _('Welcome to %(site_name)s') % data,
- data = data,
- template_name = 'email/welcome_lamson_on.html'
- )
+ template_name = 'email/welcome_lamson_on.html'
+ else:
+ template_name = 'email/welcome_lamson_off.html'
+
+ data = {
+ 'site_name': askbot_settings.APP_SHORT_NAME
+ }
+ send_respondable_email_validation_message(
+ user = user,
+ subject_line = _('Welcome to %(site_name)s') % data,
+ data = data,
+ template_name = template_name
+ )
def complete_pending_tag_subscriptions(sender, request, *args, **kwargs):
@@ -3274,16 +3551,29 @@ def make_admin_if_first_user(instance, **kwargs):
instance.set_admin_status()
cache.cache.set('admin-created', True)
+def moderate_group_joining(sender, instance=None, created=False, **kwargs):
+ if created and instance.level == GroupMembership.PENDING:
+ user = instance.user
+ group = instance.group
+ user.notify_users(
+ notification_type=const.TYPE_ACTIVITY_ASK_TO_JOIN_GROUP,
+ recipients = group.get_moderators(),
+ content_object = group
+ )
+
#signal for User model save changes
django_signals.pre_save.connect(make_admin_if_first_user, sender=User)
django_signals.pre_save.connect(calculate_gravatar_hash, sender=User)
django_signals.post_save.connect(add_missing_subscriptions, sender=User)
+django_signals.post_save.connect(add_user_to_global_group, sender=User)
+django_signals.post_save.connect(add_user_to_personal_group, sender=User)
django_signals.post_save.connect(record_award_event, sender=Award)
django_signals.post_save.connect(notify_award_message, sender=Award)
django_signals.post_save.connect(record_answer_accepted, sender=Post)
django_signals.post_save.connect(record_vote, sender=Vote)
django_signals.post_save.connect(record_favorite_question, sender=FavoriteQuestion)
+django_signals.post_save.connect(moderate_group_joining, sender=GroupMembership)
if 'avatar' in django_settings.INSTALLED_APPS:
from avatar.models import Avatar
@@ -3297,7 +3587,7 @@ signals.delete_question_or_answer.connect(record_delete_question, sender=Post)
signals.flag_offensive.connect(record_flag_offensive, sender=Post)
signals.remove_flag_offensive.connect(remove_flag_offensive, sender=Post)
signals.tags_updated.connect(record_update_tags)
-signals.user_registered.connect(send_welcome_email)
+signals.user_registered.connect(greet_new_user)
signals.user_updated.connect(record_user_full_updated, sender=User)
signals.user_logged_in.connect(complete_pending_tag_subscriptions)#todo: add this to fake onlogin middleware
signals.user_logged_in.connect(post_anonymous_askbot_content)
@@ -3308,13 +3598,6 @@ signals.post_updated.connect(record_post_update_activity)
signals.post_revision_published.connect(notify_author_of_published_revision)
signals.site_visited.connect(record_user_visit)
-#set up a possibility for the users to follow others
-try:
- import followit
- followit.register(User)
-except ImportError:
- pass
-
__all__ = [
'signals',
@@ -3323,11 +3606,14 @@ __all__ = [
'QuestionView',
'FavoriteQuestion',
'AnonymousQuestion',
+ 'DraftQuestion',
'AnonymousAnswer',
+ 'DraftAnswer',
'Post',
'PostRevision',
+ 'PostToGroup',
'Tag',
'Vote',
@@ -3342,12 +3628,13 @@ __all__ = [
'ActivityAuditStatus',
'EmailFeedSetting',
'GroupMembership',
- 'GroupProfile',
+ 'Group',
'User',
'ReplyAddress',
'get_model',
- 'get_admins_and_moderators'
+ 'get_group_names',
+ 'get_groups'
]
diff --git a/askbot/models/base.py b/askbot/models/base.py
index b3a12fbf..74b8c2dd 100644
--- a/askbot/models/base.py
+++ b/askbot/models/base.py
@@ -41,7 +41,7 @@ class BaseQuerySetManager(models.Manager):
return getattr(self.get_query_set(), attr, *args)
-class AnonymousContent(models.Model):
+class DraftContent(models.Model):
"""Base class for AnonymousQuestion and AnonymousAnswer"""
session_key = models.CharField(max_length=40) #session id for anonymous questions
wiki = models.BooleanField(default=False)
diff --git a/askbot/models/post.py b/askbot/models/post.py
index c280acf4..c7b162b8 100644
--- a/askbot/models/post.py
+++ b/askbot/models/post.py
@@ -16,25 +16,42 @@ from django.utils.translation import ugettext as _
from django.utils.translation import ungettext
from django.utils.http import urlquote as django_urlquote
from django.core import exceptions as django_exceptions
+from django.core import cache
from django.core.exceptions import ValidationError
+from django.core.urlresolvers import reverse
from django.contrib.contenttypes.models import ContentType
import askbot
from askbot.utils.slug import slugify
from askbot import const
+from askbot.models.user import Activity
from askbot.models.user import EmailFeedSetting
-from askbot.models.tag import Tag, MarkedTag, tags_match_some_wildcard
+from askbot.models.user import Group
+from askbot.models.user import GroupMembership
+from askbot.models.tag import Tag, MarkedTag
+from askbot.models.tag import get_groups, tags_match_some_wildcard
+from askbot.models.tag import get_global_group
from askbot.conf import settings as askbot_settings
from askbot import exceptions
from askbot.utils import markup
from askbot.utils.html import sanitize_html
-from askbot.models.base import BaseQuerySetManager, AnonymousContent
+from askbot.models.base import BaseQuerySetManager, DraftContent
#todo: maybe merge askbot.utils.markup and forum.utils.html
from askbot.utils.diff import textDiff as htmldiff
from askbot.utils import mysql
+class PostToGroup(models.Model):
+ post = models.ForeignKey('Post')
+ group = models.ForeignKey(Group)
+
+ class Meta:
+ unique_together = ('post', 'group')
+ app_label = 'askbot'
+ db_table = 'askbot_post_groups'
+
+
class PostQuerySet(models.query.QuerySet):
"""
Custom query set subclass for :class:`~askbot.models.Post`
@@ -142,8 +159,21 @@ class PostManager(BaseQuerySetManager):
def get_questions(self):
return self.filter(post_type='question')
- def get_answers(self):
- return self.filter(post_type='answer')
+ def get_answers(self, user = None):
+ """returns query set of answer posts,
+ optionally filtered to exclude posts of groups
+ to which user does not belong"""
+ answers = self.filter(post_type='answer')
+
+ if askbot_settings.GROUPS_ENABLED:
+ if user is None or user.is_anonymous():
+ groups = [get_global_group()]
+ else:
+ groups = user.get_groups()
+ answers = answers.filter(groups__in = groups).distinct()
+
+ return answers
+
def get_comments(self):
return self.filter(post_type='comment')
@@ -166,6 +196,7 @@ class PostManager(BaseQuerySetManager):
text,
parent = None,
wiki = False,
+ is_private = False,
email_notify = False,
post_type = None,
by_email = False
@@ -190,7 +221,23 @@ class PostManager(BaseQuerySetManager):
post.last_edited_at = added_at
post.wikified_at = added_at
- post.parse_and_save(author=author)
+ #possibly modify the is_private, if one of the groups
+ #mandates explicit publishing of the posts
+ is_private = is_private or \
+ (thread and thread.requires_response_moderation(author))
+
+ parse_results = post.parse_and_save(author=author, is_private=is_private)
+
+ from askbot.models import signals
+ signals.post_updated.send(
+ post=post,
+ updated_by=author,
+ newly_mentioned_users=parse_results['newly_mentioned_users'],
+ timestamp=added_at,
+ created=True,
+ diff=parse_results['diff'],
+ sender=post.__class__
+ )
post.add_revision(
author = author,
@@ -210,6 +257,7 @@ class PostManager(BaseQuerySetManager):
added_at,
text,
wiki = False,
+ is_private = False,
email_notify = False,
by_email = False
):
@@ -219,6 +267,7 @@ class PostManager(BaseQuerySetManager):
added_at,
text,
wiki = wiki,
+ is_private = is_private,
post_type = 'answer',
by_email = by_email
)
@@ -288,6 +337,7 @@ class Post(models.Model):
parent = models.ForeignKey('Post', blank=True, null=True, related_name='comments') # Answer or Question for Comment
thread = models.ForeignKey('Thread', blank=True, null=True, default = None, related_name='posts')
+ groups = models.ManyToManyField(Group, through='PostToGroup', related_name = 'group_posts')#used for group-private posts
author = models.ForeignKey(User, related_name='posts')
added_at = models.DateTimeField(default=datetime.datetime.now)
@@ -332,11 +382,6 @@ class Post(models.Model):
#the reason is that the title and tags belong to thread,
#but the question body to Post
is_anonymous = models.BooleanField(default=False)
- #When is_private == True
- #the post is visible only to the some privileged users.
- #The privilege may be defined through groups to which
- #the thread belongs or in some other way.
- is_private = models.BooleanField(default=False)
objects = PostManager()
@@ -449,7 +494,7 @@ class Post(models.Model):
return data
#todo: when models are merged, it would be great to remove author parameter
- def parse_and_save(self, author = None, **kwargs):
+ def parse_and_save(self, author=None, **kwargs):
"""generic method to use with posts to be used prior to saving
post edit or addition
"""
@@ -473,9 +518,27 @@ class Post(models.Model):
created = self.pk is None
+ is_private = kwargs.pop('is_private', False)
+ group_id = kwargs.pop('group_id', None)
+
#this save must precede saving the mention activity
+ #as well as assigning groups to the post
#because generic relation needs primary key of the related object
super(self.__class__, self).save(**kwargs)
+
+ if self.is_comment():
+ #copy groups from the parent post into the comment
+ groups = self.parent.groups.all()
+ self.add_to_groups(groups)
+ elif is_private or group_id:
+ self.make_private(author, group_id = group_id)
+ elif self.thread_id:#is connected to thread
+ #inherit privacy scope from thread
+ thread_groups = self.thread.groups.all()
+ self.add_to_groups(thread_groups)
+ else:
+ self.make_public()
+
if last_revision:
diff = htmldiff(
sanitize_html(last_revision),
@@ -486,19 +549,6 @@ class Post(models.Model):
timestamp = self.get_time_of_last_edit()
- #todo: this is handled in signal because models for posts
- #are too spread out
- from askbot.models import signals
- signals.post_updated.send(
- post = self,
- updated_by = author,
- newly_mentioned_users = newly_mentioned_users,
- timestamp = timestamp,
- created = created,
- diff = diff,
- sender = self.__class__
- )
-
try:
from askbot.conf import settings as askbot_settings
if askbot_settings.GOOGLE_SITEMAP_CODE != '':
@@ -506,6 +556,8 @@ class Post(models.Model):
except Exception:
logging.debug('cannot ping google - did you register with them?')
+ return {'diff': diff, 'newly_mentioned_users': newly_mentioned_users}
+
def is_question(self):
return self.post_type == 'question'
@@ -521,8 +573,162 @@ class Post(models.Model):
def is_reject_reason(self):
return self.post_type == 'reject_reason'
+ def get_moderators(self):
+ """returns query set of users who are site administrators
+ and moderators"""
+ user_filter = models.Q(is_superuser=True) | models.Q(status='m')
+ if askbot_settings.GROUPS_ENABLED:
+ user_filter = user_filter & models.Q(groups__in=self.groups.all())
+ return User.objects.filter(user_filter)
+
+ def has_group(self, group):
+ """true if post belongs to the group"""
+ return self.groups.filter(id=group.id).exists()
+
+ def add_to_groups(self, groups):
+ #todo: use bulk-creation
+ for group in groups:
+ PostToGroup.objects.get_or_create(post=self, group=group)
+ if self.is_answer() or self.is_question():
+ comments = self.comments.all()
+ for group in groups:
+ for comment in comments:
+ PostToGroup.objects.get_or_create(post=comment, group=group)
+
+ def remove_from_groups(self, groups):
+ PostToGroup.objects.filter(post=self, group__in=groups).delete()
+ if self.is_answer() or self.is_question():
+ comment_ids = self.comments.all().values_list('id', flat=True)
+ PostToGroup.objects.filter(
+ post__id__in=comment_ids,
+ group__in=groups
+ ).delete()
+
+
+ def issue_update_notifications(
+ self,
+ updated_by=None,
+ notify_sets=None,
+ activity_type=None,
+ timestamp=None,
+ diff=None
+ ):
+ """Called when a post is updated. Arguments:
+
+ * ``notify_sets`` - result of ``Post.get_notify_sets()`` method
+
+ The method does two things:
+
+ * records "red envelope" recipients of the post
+ * sends email alerts to all subscribers to the post
+ """
+ assert(activity_type is not None)
+ if diff:
+ summary = diff
+ else:
+ summary = self.get_snippet()
+
+ update_activity = Activity(
+ user = updated_by,
+ active_at = timestamp,
+ content_object = self,
+ activity_type = activity_type,
+ question = self.get_origin_post(),
+ summary = summary
+ )
+ update_activity.save()
+
+ update_activity.add_recipients(notify_sets['for_inbox'])
+
+ #create new mentions (barring the double-adds)
+ for u in notify_sets['for_mentions'] - notify_sets['for_inbox']:
+ Activity.objects.create_new_mention(
+ mentioned_whom = u,
+ mentioned_in = self,
+ mentioned_by = updated_by,
+ mentioned_at = timestamp
+ )
+
+ for user in (notify_sets['for_inbox'] | notify_sets['for_mentions']):
+ user.update_response_counts()
+
+ #shortcircuit if the email alerts are disabled
+ if askbot_settings.ENABLE_EMAIL_ALERTS == False:
+ return
+ #todo: fix this temporary spam protection plug
+ if askbot_settings.MIN_REP_TO_TRIGGER_EMAIL:
+ if not (updated_by.is_administrator() or updated_by.is_moderator()):
+ if updated_by.reputation < askbot_settings.MIN_REP_TO_TRIGGER_EMAIL:
+ notify_sets['for_email'] = \
+ [u for u in notify_sets['for_email'] if u.is_administrator()]
+
+ if not settings.CELERY_ALWAYS_EAGER:
+ cache_key = 'instant-notification-%d-%d' % (self.thread.id, updated_by.id)
+ if cache.cache.get(cache_key):
+ return
+ cache.cache.set(cache_key, True, settings.NOTIFICATION_DELAY_TIME)
+
+ from askbot.models import send_instant_notifications_about_activity_in_post
+ send_instant_notifications_about_activity_in_post.apply_async((
+ update_activity,
+ self,
+ notify_sets['for_email']),
+ countdown = settings.NOTIFICATION_DELAY_TIME
+ )
+
+ def make_private(self, user, group_id=None):
+ """makes post private within user's groups
+ todo: this is a copy-paste in thread and post
+ """
+ if group_id:
+ group = Group.objects.get(id=group_id)
+ groups = [group]
+ self.add_to_groups(groups)
+
+ global_group = get_global_group()
+ if group != global_group:
+ self.remove_from_groups((global_group,))
+ else:
+ if self.thread_id and self.is_question() is False:
+ #for thread-related responses we base
+ #privacy scope on thread + add a personal group
+ personal_group = user.get_personal_group()
+ thread_groups = self.thread.get_groups_shared_with()
+ groups = set([personal_group]) | set(thread_groups)
+ else:
+ groups = user.get_groups(private=True)
+
+ self.add_to_groups(groups)
+ self.remove_from_groups((get_global_group(),))
+
+ if len(groups) == 0:
+ message = 'Sharing did not work, because group is unknown'
+ user.message_set.create(message=message)
+
+ def make_public(self):
+ """removes the privacy mark from users groups"""
+ groups = (get_global_group(),)
+ self.add_to_groups(groups)
+
+ def is_private(self):
+ """true, if post belongs to the global group"""
+ if askbot_settings.GROUPS_ENABLED:
+ group = get_global_group()
+ return not self.groups.filter(id=group.id).exists()
+ return False
+
+ def is_approved(self):
+ """``False`` only when moderation is ``True`` and post
+ ``self.approved is False``
+ """
+ if askbot_settings.ENABLE_CONTENT_MODERATION:
+ if self.approved == False:
+ return False
+ return True
+
def needs_moderation(self):
- return self.approved == False
+ #todo: do we need this, can't we just use is_approved()?
+ return self.approved is False
def get_absolute_url(self, no_slug = False, question_post=None, thread=None):
from askbot.utils.slug import slugify
@@ -614,22 +820,48 @@ class Post(models.Model):
"""
return html_utils.strip_tags(self.html)[:max_length] + ' ...'
+ def filter_authorized_users(self, candidates):
+ """returns list of users who are allowed to see this post"""
+ if askbot_settings.GROUPS_ENABLED == False:
+ return candidates
+ else:
+ if len(candidates) == 0:
+ return candidates
+ #get post groups
+ groups = list(self.groups.all())
+
+ if len(groups) == 0:
+ logging.critical('post %d is groupless' % self.id)
+ return list()
+
+ #load group memberships for the candidates
+ memberships = GroupMembership.objects.filter(
+ user__in=candidates,
+ group__in=groups
+ )
+ user_ids = set(memberships.values_list('user__id', flat=True))
+
+ #scan through the user ids and see which are group members
+ filtered_candidates = set()
+ for candidate in candidates:
+ if candidate.id in user_ids:
+ filtered_candidates.add(candidate)
+
+ return filtered_candidates
+
def format_for_email(
- self, quote_level = 0, is_leaf_post = False, format = None
+ self, quote_level=0, is_leaf_post=False, format=None
):
"""format post for the output in email,
if quote_level > 0, the post will be indented that number of times
todo: move to views?
"""
- from askbot.templatetags.extra_filters_jinja \
- import absolutize_urls_func
from askbot.skins.loaders import get_template
from django.template import Context
template = get_template('email/quoted_post.html')
data = {
'post': self,
'quote_level': quote_level,
- #'html': absolutize_urls_func(self.html),
'is_leaf_post': is_leaf_post,
'format': format
}
@@ -758,9 +990,8 @@ class Post(models.Model):
user_set_getter(
tag_selections__in = tag_selections
).filter(
+ email_tag_filter_strategy = email_tag_filter_strategy,
notification_subscriptions__in = subscription_records
- ).filter(
- email_tag_filter_strategy = email_tag_filter_strategy
)
)
@@ -847,6 +1078,7 @@ class Post(models.Model):
):
"""get list of users who have subscribed to
receive instant notifications for a given post
+
this method works for questions and answers
Arguments:
@@ -910,7 +1142,11 @@ class Post(models.Model):
#4) question asked by me (todo: not "edited_by_me" ???)
question_author = origin_post.author
- if EmailFeedSetting.objects.filter(subscriber = question_author, frequency = 'i', feed_type = 'q_ask').exists():
+ if EmailFeedSetting.objects.filter(
+ subscriber = question_author,
+ frequency = 'i',
+ feed_type = 'q_ask'
+ ).exists():
subscriber_set.add(question_author)
#4) questions answered by me -make sure is that people
@@ -931,10 +1167,7 @@ class Post(models.Model):
#print 'answer subscribers: ', answer_subscribers
#print 'exclude_list is ', exclude_list
- subscriber_set -= set(exclude_list)
-
- #print 'final subscriber set is ', subscriber_set
- return list(subscriber_set)
+ return subscriber_set - set(exclude_list)
def _comment__get_instant_notification_subscribers(
self,
@@ -1000,30 +1233,60 @@ class Post(models.Model):
subscriber_set.update(global_subscribers)
- #print 'exclude list is: ', exclude_list
- if exclude_list:
- subscriber_set -= set(exclude_list)
-
- #print 'final list of subscribers:', subscriber_set
+ return subscriber_set - set(exclude_list)
- return list(subscriber_set)
-
- def get_instant_notification_subscribers(self, potential_subscribers = None, mentioned_users = None, exclude_list = None):
+ def get_instant_notification_subscribers(
+ self, potential_subscribers = None,
+ mentioned_users = None, exclude_list = None
+ ):
if self.is_question() or self.is_answer():
- return self._qa__get_instant_notification_subscribers(
+ subscribers = self._qa__get_instant_notification_subscribers(
potential_subscribers=potential_subscribers,
mentioned_users=mentioned_users,
exclude_list=exclude_list
)
elif self.is_comment():
- return self._comment__get_instant_notification_subscribers(
+ subscribers = self._comment__get_instant_notification_subscribers(
potential_subscribers=potential_subscribers,
mentioned_users=mentioned_users,
exclude_list=exclude_list
)
elif self.is_tag_wiki() or self.is_reject_reason():
- return list()
- raise NotImplementedError
+ return set()
+ else:
+ raise NotImplementedError
+
+ #if askbot_settings.GROUPS_ENABLED and self.is_effectively_private():
+ # for subscriber in subscribers:
+ return self.filter_authorized_users(subscribers)
+
+ def get_notify_sets(self, mentioned_users=None, exclude_list=None):
+ """returns three lists in a dictionary with keys:
+ * 'for_inbox' - users for which to add inbox items
+ * 'for_mentions' - for whom mentions are added
+ * 'for_email' - to whom email notifications should be sent
+ """
+ result = dict()
+ result['for_mentions'] = set(mentioned_users) - set(exclude_list)
+ #what users are included depends on the post type
+ #for example for question - all Q&A contributors
+ #are included, for comments only authors of comments and parent
+ #post are included
+ result['for_inbox'] = self.get_response_receivers(exclude_list=exclude_list)
+
+ if askbot_settings.ENABLE_EMAIL_ALERTS == False:
+ result['for_email'] = set()
+ else:
+ #todo: weird thing is that only comments need the recipients
+ #todo: debug these calls and then uncomment in the repo
+ #argument to this call
+ result['for_email'] = self.get_instant_notification_subscribers(
+ potential_subscribers=result['for_inbox'],
+ mentioned_users=result['for_mentions'],
+ exclude_list=exclude_list
+ )
+ return result
+
def get_latest_revision(self):
return self.revisions.order_by('-revised_at')[0]
@@ -1215,9 +1478,8 @@ class Post(models.Model):
def _question__assert_is_visible_to(self, user):
"""raises QuestionHidden"""
- if askbot_settings.ENABLE_CONTENT_MODERATION:
- if self.approved == False:
- raise exceptions.QuestionHidden()
+ if self.is_approved() is False:
+ raise exceptions.QuestionHidden()
if self.deleted:
message = _(
'Sorry, this question has been '
@@ -1272,8 +1534,33 @@ class Post(models.Model):
)
raise exceptions.AnswerHidden(message)
+ def assert_is_visible_to_user_groups(self, user):
+ """raises permission denied of the post
+ is hidden due to group memberships"""
+ assert(self.is_comment() == False)
+ post_groups = self.groups.all()
+ global_group_name = askbot_settings.GLOBAL_GROUP_NAME
+ if post_groups.filter(name=global_group_name).count() == 1:
+ return
+
+ if self.is_question():#todo maybe merge the "hidden" exceptions
+ exception = exceptions.QuestionHidden
+ elif self.is_answer():
+ exception = exceptions.AnswerHidden
+ else:
+ raise NotImplementedError
+
+ message = _('This post is temporarily not available')
+ if user.is_anonymous():
+ raise exception(message)
+ else:
+ user_groups_ids = user.get_groups().values_list('id', flat = True)
+ if post_groups.filter(id__in = user_groups_ids).count() == 0:
+ raise exception(message)
def assert_is_visible_to(self, user):
+ if self.is_comment() == False and askbot_settings.GROUPS_ENABLED:
+ self.assert_is_visible_to_user_groups(user)
if self.is_question():
return self._question__assert_is_visible_to(user)
elif self.is_answer():
@@ -1313,7 +1600,6 @@ class Post(models.Model):
else:
return const.TYPE_ACTIVITY_UPDATE_REJECT_REASON, self
-
raise NotImplementedError
def get_tag_names(self):
@@ -1321,13 +1607,14 @@ class Post(models.Model):
def __apply_edit(
self,
- edited_at = None,
- edited_by = None,
- text = None,
- comment = None,
- wiki = False,
- edit_anonymously = False,
- by_email = False
+ edited_at=None,
+ edited_by=None,
+ text=None,
+ comment=None,
+ wiki=False,
+ edit_anonymously=False,
+ is_private=False,
+ by_email=False
):
if text is None:
text = self.get_latest_revision().text
@@ -1355,7 +1642,19 @@ class Post(models.Model):
by_email = by_email
)
- self.parse_and_save(author = edited_by)
+ parse_results = self.parse_and_save(author=edited_by, is_private=is_private)
+
+ from askbot.models import signals
+ signals.post_updated.send(
+ post=self,
+ updated_by=edited_by,
+ newly_mentioned_users=parse_results['newly_mentioned_users'],
+ timestamp=edited_at,
+ created=False,
+ diff=parse_results['diff'],
+ sender=self.__class__
+ )
+
def _answer__apply_edit(
self,
@@ -1364,24 +1663,34 @@ class Post(models.Model):
text = None,
comment = None,
wiki = False,
+ is_private = False,
by_email = False
):
+ ##it is important to do this before __apply_edit b/c of signals!!!
+ if self.is_private() != is_private:
+ if is_private:
+ self.make_private(self.author)
+ else:
+ self.make_public()
+
self.__apply_edit(
- edited_at = edited_at,
- edited_by = edited_by,
- text = text,
- comment = comment,
- wiki = wiki,
- by_email = by_email
+ edited_at=edited_at,
+ edited_by=edited_by,
+ text=text,
+ comment=comment,
+ wiki=wiki,
+ by_email=by_email,
+ is_private=is_private
)
+
if edited_at is None:
edited_at = datetime.datetime.now()
self.thread.set_last_activity(last_activity_at=edited_at, last_activity_by=edited_by)
def _question__apply_edit(self, edited_at=None, edited_by=None, title=None,\
text=None, comment=None, tags=None, wiki=False,\
- edit_anonymously = False,
+ edit_anonymously = False, is_private = False,
by_email = False
):
@@ -1399,20 +1708,30 @@ class Post(models.Model):
# Update the Question tag associations
if latest_revision.tagnames != tags:
- self.thread.update_tags(tagnames = tags, user = edited_by, timestamp = edited_at)
+ self.thread.update_tags(
+ tagnames = tags, user = edited_by, timestamp = edited_at
+ )
self.thread.title = title
self.thread.tagnames = tags
self.thread.save()
+ ##it is important to do this before __apply_edit b/c of signals!!!
+ if self.is_private() != is_private:
+ if is_private:
+ self.make_private(self.author)
+ else:
+ self.make_public()
+
self.__apply_edit(
- edited_at = edited_at,
- edited_by = edited_by,
- text = text,
- comment = comment,
- wiki = wiki,
- edit_anonymously = edit_anonymously,
- by_email = by_email
+ edited_at=edited_at,
+ edited_by=edited_by,
+ text=text,
+ comment=comment,
+ wiki=wiki,
+ edit_anonymously=edit_anonymously,
+ is_private=is_private,
+ by_email=by_email
)
self.thread.set_last_activity(last_activity_at=edited_at, last_activity_by=edited_by)
@@ -1447,8 +1766,7 @@ class Post(models.Model):
comment = const.POST_STATUS['default_version']
else:
comment = 'No.%s Revision' % rev_no
- from askbot.models.post import PostRevision
- return PostRevision.objects.create_answer_revision(
+ return PostRevision.objects.create(
post = self,
author = author,
revised_at = revised_at,
@@ -1477,8 +1795,7 @@ class Post(models.Model):
else:
comment = 'No.%s Revision' % rev_no
- from askbot.models.post import PostRevision
- return PostRevision.objects.create_question_revision(
+ return PostRevision.objects.create(
post = self,
revision = rev_no,
title = self.thread.title,
@@ -1525,9 +1842,7 @@ class Post(models.Model):
for answer in question.thread.posts.get_answers().all():
recipients.update(answer.get_author_list())
- recipients -= set(exclude_list)
-
- return list(recipients)
+ return recipients - set(exclude_list)
def _question__get_response_receivers(self, exclude_list = None):
"""returns list of users who might be interested
@@ -1548,8 +1863,7 @@ class Post(models.Model):
for a in self.thread.posts.get_answers().all():
recipients.update(a.get_author_list())
- recipients -= set(exclude_list)
- return recipients
+ return recipients - set(exclude_list)
def _comment__get_response_receivers(self, exclude_list = None):
"""Response receivers are commenters of the
@@ -1563,21 +1877,24 @@ class Post(models.Model):
include_comments = True,
)
)
- users -= set(exclude_list)
- return list(users)
-
+ return users - set(exclude_list)
def get_response_receivers(self, exclude_list = None):
- """returns a list of response receiving users"""
+ """returns a list of response receiving users
+ who see the on-screen notifications
+ """
if self.is_answer():
- return self._answer__get_response_receivers(exclude_list)
+ receivers = self._answer__get_response_receivers(exclude_list)
elif self.is_question():
- return self._question__get_response_receivers(exclude_list)
+ receivers = self._question__get_response_receivers(exclude_list)
elif self.is_comment():
- return self._comment__get_response_receivers(exclude_list)
+ receivers = self._comment__get_response_receivers(exclude_list)
elif self.is_tag_wiki() or self.is_reject_reason():
- return list()#todo: who should get these?
- raise NotImplementedError
+ return set()#todo: who should get these?
+ else:
+ raise NotImplementedError
+
+ return self.filter_authorized_users(receivers)
def get_question_title(self):
if self.is_question():
@@ -1644,52 +1961,22 @@ class Post(models.Model):
class PostRevisionManager(models.Manager):
def create(self, *kargs, **kwargs):
- raise NotImplementedError # Prevent accidental creation of PostRevision instance without `revision_type` set
-
- def create_question_revision(self, *kargs, **kwargs):
- kwargs['revision_type'] = self.model.QUESTION_REVISION
revision = super(PostRevisionManager, self).create(*kargs, **kwargs)
revision.moderate_or_publish()
return revision
- def create_answer_revision(self, *kargs, **kwargs):
- kwargs['revision_type'] = self.model.ANSWER_REVISION
- revision = super(PostRevisionManager, self).create(*kargs, **kwargs)
- revision.moderate_or_publish()
- return revision
-
- def question_revisions(self):
- return self.filter(revision_type=self.model.QUESTION_REVISION)
-
- def answer_revisions(self):
- return self.filter(revision_type=self.model.ANSWER_REVISION)
-
-
class PostRevision(models.Model):
QUESTION_REVISION_TEMPLATE_NO_TAGS = (
'<h3>%(title)s</h3>\n'
'<div class="text">%(html)s</div>\n'
)
- QUESTION_REVISION = 1
- ANSWER_REVISION = 2
- REVISION_TYPE_CHOICES = (
- (QUESTION_REVISION, 'question'),
- (ANSWER_REVISION, 'answer'),
- )
- REVISION_TYPE_CHOICES_DICT = dict(REVISION_TYPE_CHOICES)
-
post = models.ForeignKey('askbot.Post', related_name='revisions', null=True, blank=True)
-
- #todo: remove this field, as revision type is determined by the
- #Post.post_type revision_type is a useless field
- revision_type = models.SmallIntegerField(choices=REVISION_TYPE_CHOICES) # TODO: remove as we have Post now
-
- revision = models.PositiveIntegerField()
- author = models.ForeignKey('auth.User', related_name='%(class)ss')
+ revision = models.PositiveIntegerField()
+ author = models.ForeignKey('auth.User', related_name='%(class)ss')
revised_at = models.DateTimeField()
- summary = models.CharField(max_length=300, blank=True)
- text = models.TextField()
+ summary = models.CharField(max_length=300, blank=True)
+ text = models.TextField()
approved = models.BooleanField(default=False, db_index=True)
approved_by = models.ForeignKey(User, null = True, blank = True)
@@ -1699,8 +1986,8 @@ class PostRevision(models.Model):
email_address = models.EmailField(null = True, blank = True)
# Question-specific fields
- title = models.CharField(max_length=300, blank=True, default='')
- tagnames = models.CharField(max_length=125, blank=True, default='')
+ title = models.CharField(max_length=300, blank=True, default='')
+ tagnames = models.CharField(max_length=125, blank=True, default='')
is_anonymous = models.BooleanField(default=False)
objects = PostRevisionManager()
@@ -1726,13 +2013,14 @@ class PostRevision(models.Model):
if self.by_email and self.email_address:
group_name = self.email_address.split('@')[0]
try:
- group = Tag.objects.get(name = group_name, deleted = False)
+ group = Group.objects.get(name = group_name, deleted = False)
return group.group.profile.moderate_email
- except Tag.DoesNotExist:
+ except Group.DoesNotExist:
pass
return True
return False
+
def place_on_moderation_queue(self):
"""If revision is the first one,
keeps the post invisible until the revision
@@ -1789,7 +2077,7 @@ class PostRevision(models.Model):
#merging multiple edits. We don't have a solution for this yet.
activity_type = const.TYPE_ACTIVITY_MODERATED_POST_EDIT
- from askbot.models import Activity, get_admins_and_moderators
+ from askbot.models import Activity
activity = Activity(
user = self.author,
content_object = self,
@@ -1798,7 +2086,7 @@ class PostRevision(models.Model):
)
activity.save()
#todo: make this group-sensitive
- activity.add_recipients(get_admins_and_moderators())
+ activity.add_recipients(self.post.get_moderators())
def moderate_or_publish(self):
"""either place on moderation queue or announce
@@ -1827,48 +2115,34 @@ class PostRevision(models.Model):
#schedule = askbot_settings.SELF_NOTIFY_WEB_POST_AUTHOR_WHEN
return False
- def revision_type_str(self):
- return self.REVISION_TYPE_CHOICES_DICT[self.revision_type]
-
def __unicode__(self):
- return u'%s - revision %s of %s' % (self.revision_type_str(), self.revision, self.title)
+ return u'%s - revision %s of %s' % (self.post.post_type, self.revision, self.title)
def parent(self):
return self.post
def clean(self):
"Internal cleaning method, called from self.save() by self.full_clean()"
- # TODO: Remove this when we remove `revision_type`
if not self.post:
raise ValidationError('Post field has to be set.')
- if (self.post.post_type == 'question' and not self.is_question_revision()) or \
- (self.post.post_type == 'answer' and not self.is_answer_revision()):
- raise ValidationError('Revision_type doesn`t match values in question/answer fields.')
-
def save(self, **kwargs):
# Determine the revision number, if not set
if not self.revision:
# TODO: Maybe use Max() aggregation? Or `revisions.count() + 1`
- self.revision = self.parent().revisions.values_list('revision', flat=True)[0] + 1
-
- # Make sure that everything is ok, in particular that `revision_type` and `revision` are set to valid values
+ self.revision = self.parent().revisions.values_list(
+ 'revision', flat=True
+ )[0] + 1
self.full_clean()
-
super(PostRevision, self).save(**kwargs)
- def is_question_revision(self):
- return self.revision_type == self.QUESTION_REVISION
-
- def is_answer_revision(self):
- return self.revision_type == self.ANSWER_REVISION
-
- @models.permalink
def get_absolute_url(self):
- if self.is_question_revision():
- return 'question_revisions', (self.post.id,), {}
- elif self.is_answer_revision():
- return 'answer_revisions', (), {'id':self.post.id}
+ if self.post.is_question():
+ return reverse('question_revisions', args = (self.post.id,))
+ elif self.post.is_answer():
+ return reverse('answer_revisions', kwargs = {'id':self.post.id})
+ else:
+ return self.post.get_absolute_url()
def get_question_title(self):
#INFO: ack-grepping shows that it's only used for Questions, so there's no code for Answers
@@ -1883,12 +2157,12 @@ class PostRevision(models.Model):
markdowner = markup.get_parser()
sanitized_html = sanitize_html(markdowner.convert(self.text))
- if self.is_question_revision():
+ if self.post.is_question():
return self.QUESTION_REVISION_TEMPLATE_NO_TAGS % {
'title': self.title,
'html': sanitized_html
}
- elif self.is_answer_revision():
+ elif self.post.is_answer():
return sanitized_html
def get_snippet(self, max_length = 120):
@@ -1905,7 +2179,21 @@ class PostFlagReason(models.Model):
app_label = 'askbot'
-class AnonymousAnswer(AnonymousContent):
+class DraftAnswer(models.Model):
+ """Provides space for draft answers,
+ note that unlike ``AnonymousAnswer`` the foreign key
+ is going to ``Thread`` as it should.
+ """
+ thread = models.ForeignKey('Thread', related_name='draft_answers')
+ author = models.ForeignKey(User, related_name='draft_answers')
+ text = models.TextField(null=True)
+
+ class Meta:
+ app_label = 'askbot'
+
+
+class AnonymousAnswer(DraftContent):
+ """Todo: re-route the foreign key to ``Thread``"""
question = models.ForeignKey(Post, related_name='anonymous_answers')
def publish(self, user):
diff --git a/askbot/models/question.py b/askbot/models/question.py
index e310e676..5b726257 100644
--- a/askbot/models/question.py
+++ b/askbot/models/question.py
@@ -12,10 +12,20 @@ from django.utils.translation import ugettext as _
from django.utils.translation import ungettext
import askbot
-import askbot.conf
+from askbot.conf import settings as askbot_settings
+from askbot import mail
+from askbot.mail import messages
from askbot.models.tag import Tag
-from askbot.models.base import AnonymousContent
+from askbot.models.tag import get_groups
+from askbot.models.tag import get_global_group
+from askbot.models.tag import get_tags_by_names
+from askbot.models.tag import filter_accepted_tags, filter_suggested_tags
+from askbot.models.tag import delete_tags, separate_unused_tags
+from askbot.models.base import DraftContent, BaseQuerySetManager
+from askbot.models.tag import Tag, get_groups
from askbot.models.post import Post, PostRevision
+from askbot.models.post import PostToGroup
+from askbot.models.user import Group, PERSONAL_GROUP_NAME_PREFIX
from askbot.models import signals
from askbot import const
from askbot.utils.lists import LazyList
@@ -24,8 +34,20 @@ from askbot.utils.slug import slugify
from askbot.skins.loaders import get_template #jinja2 template loading enviroment
from askbot.search.state_manager import DummySearchState
+class ThreadQuerySet(models.query.QuerySet):
+ def get_visible(self, user):
+ """filters out threads not belonging to the user groups"""
+ if user.is_authenticated():
+ groups = user.get_groups()
+ else:
+ groups = [get_global_group()]
+ return self.filter(groups__in=groups).distinct()
+
+class ThreadManager(BaseQuerySetManager):
+
+ def get_query_set(self):
+ return ThreadQuerySet(self.model)
-class ThreadManager(models.Manager):
def get_tag_summary_from_threads(self, threads):
"""returns a humanized string containing up to
five most frequently used
@@ -71,6 +93,8 @@ class ThreadManager(models.Manager):
text,
tagnames = None,
is_anonymous = False,
+ is_private = False,
+ group_id = None,
by_email = False,
email_address = None
):
@@ -108,20 +132,43 @@ class ThreadManager(models.Manager):
question.last_edited_at = added_at
question.wikified_at = added_at
- question.parse_and_save(author = author)
-
- question.add_revision(
- author = author,
- is_anonymous = is_anonymous,
- text = text,
- comment = const.POST_STATUS['default_version'],
- revised_at = added_at,
- by_email = by_email,
- email_address = email_address
+ #this is kind of bad, but we save assign privacy groups to posts and thread
+ #this call is rather heavy, we should split into several functions
+ parse_results = question.parse_and_save(author=author, is_private=is_private)
+
+ revision = question.add_revision(
+ author=author,
+ is_anonymous=is_anonymous,
+ text=text,
+ comment=const.POST_STATUS['default_version'],
+ revised_at=added_at,
+ by_email=by_email,
+ email_address=email_address
)
+ author_group = author.get_personal_group()
+ thread.add_to_groups([author_group], visibility=ThreadToGroup.SHOW_PUBLISHED_RESPONSES)
+ question.add_to_groups([author_group])
+
+ if is_private or group_id:#add groups to thread and question
+ thread.make_private(author, group_id=group_id)
+ else:
+ thread.make_public()
+
# INFO: Question has to be saved before update_tags() is called
- thread.update_tags(tagnames = tagnames, user = author, timestamp = added_at)
+ thread.update_tags(tagnames=tagnames, user=author, timestamp=added_at)
+
+ #todo: this is handled in signal because models for posts
+ #are too spread out
+ signals.post_updated.send(
+ post=question,
+ updated_by=author,
+ newly_mentioned_users=parse_results['newly_mentioned_users'],
+ timestamp=added_at,
+ created=True,
+ diff=parse_results['diff'],
+ sender=question.__class__
+ )
return thread
@@ -176,33 +223,60 @@ class ThreadManager(models.Manager):
if askbot_settings.ENABLE_CONTENT_MODERATION:
qs = qs.filter(approved = True)
- meta_data = {}
+ #if groups feature is enabled, filter out threads
+ #that are private in groups to which current user does not belong
+ if askbot_settings.GROUPS_ENABLED:
+ #get group names
+ qs = qs.get_visible(user=request_user)
+
+ #run text search while excluding any modifier in the search string
+ #like #tag [title: something] @user
if search_state.stripped_query:
qs = self.get_for_query(search_query=search_state.stripped_query, qs=qs)
+
+ #we run other things after full text search, because
+ #FTS may break the chain of the query set calls,
+ #since it might go into an external asset, like Solr
+
+ #search in titles, if necessary
if search_state.query_title:
qs = qs.filter(title__icontains = search_state.query_title)
+
+ #search user names if @user is added to search string
+ #or if user name exists in the search state
if search_state.query_users:
query_users = User.objects.filter(username__in=search_state.query_users)
if query_users:
- qs = qs.filter(posts__post_type='question', posts__author__in=query_users) # TODO: unify with search_state.author ?
-
+ qs = qs.filter(
+ posts__post_type='question',
+ posts__author__in=query_users
+ ) # TODO: unify with search_state.author ?
+
+ #unified tags - is list of tags taken from the tag selection
+ #plus any tags added to the query string with #tag or [tag:something]
+ #syntax.
+ #run tag search in addition to these unified tags
+ meta_data = {}
tags = search_state.unified_tags()
if len(tags) > 0:
if askbot_settings.TAG_SEARCH_INPUT_ENABLED:
#todo: this may be gone or disabled per option
#"tag_search_box_enabled"
- existing_tags = set(
- Tag.objects.filter(
- name__in = tags
- ).values_list(
- 'name',
- flat = True
- )
- )
+ existing_tags = set()
+ non_existing_tags = set()
+ #we're using a one-by-one tag retreival, b/c
+ #we want to take advantage of case-insensitive search indexes
+ #in postgresql, plus it is most likely that there will be
+ #only one or two search tags anyway
+ for tag in tags:
+ try:
+ tag_record = Tag.objects.get(name__iexact=tag)
+ existing_tags.add(tag_record.name)
+ except Tag.DoesNotExist:
+ non_existing_tags.add(tag)
- non_existing_tags = set(tags) - existing_tags
meta_data['non_existing_tags'] = list(non_existing_tags)
tags = existing_tags
else:
@@ -217,6 +291,8 @@ class ThreadManager(models.Manager):
if search_state.scope == 'unanswered':
qs = qs.filter(closed = False) # Do not show closed questions in unanswered section
if askbot_settings.UNANSWERED_QUESTION_MEANING == 'NO_ANSWERS':
+ # todo: this will introduce a problem if there are private answers
+ # which are counted here
qs = qs.filter(answer_count=0) # TODO: expand for different meanings of this
elif askbot_settings.UNANSWERED_QUESTION_MEANING == 'NO_ACCEPTED_ANSWERS':
qs = qs.filter(accepted_answer__isnull=True)
@@ -255,11 +331,13 @@ class ThreadManager(models.Manager):
user_selections__user = request_user,
user_selections__reason = 'bad'
)
+ subscribed_tags = Tag.objects.none()
if askbot_settings.SUBSCRIBED_TAG_SELECTOR_ENABLED:
- meta_data['subscribed_tag_names'] = Tag.objects.filter(
+ subscribed_tags = Tag.objects.filter(
user_selections__user = request_user,
user_selections__reason = 'subscribed'
- ).values_list('name', flat = True)
+ )
+ meta_data['subscribed_tag_names'] = [tag.name for tag in subscribed_tags]
meta_data['interesting_tag_names'] = [tag.name for tag in interesting_tags]
meta_data['ignored_tag_names'] = [tag.name for tag in ignored_tags]
@@ -282,6 +360,10 @@ class ThreadManager(models.Manager):
extra_ignored_tags = Tag.objects.get_by_wildcards(ignored_wildcards)
qs = qs.exclude(tags__in = extra_ignored_tags)
+ if request_user.display_tag_filter_strategy == const.INCLUDE_SUBSCRIBED \
+ and subscribed_tags:
+ qs = qs.filter(tags__in = subscribed_tags)
+
if askbot_settings.USE_WILDCARD_TAGS:
meta_data['interesting_tag_names'].extend(request_user.interesting_tags.split())
meta_data['ignored_tag_names'].extend(request_user.ignored_tags.split())
@@ -327,8 +409,13 @@ class ThreadManager(models.Manager):
# Precache data only for non-cached threads - only those will be rendered
#threads = [thread for thread in threads if not thread.summary_html_cached()]
- page_questions = Post.objects.filter(post_type='question', thread__in=[obj.id for obj in threads])\
- .only('id', 'thread', 'points', 'is_anonymous', 'summary', 'post_type', 'deleted') # pick only the used fields
+ thread_ids = [obj.id for obj in threads]
+ page_questions = Post.objects.filter(
+ post_type='question', thread__id__in = thread_ids
+ ).only(# pick only the used fields
+ 'id', 'thread', 'points', 'is_anonymous',
+ 'summary', 'post_type', 'deleted'
+ )
page_question_map = {}
for pq in page_questions:
page_question_map[pq.thread_id] = pq
@@ -375,6 +462,30 @@ class ThreadManager(models.Manager):
return self.filter(id__in = thread_ids)
+class ThreadToGroup(models.Model):
+ """the "through" many-to-many relation between
+ threads and groups - to distinguish full and "what's published"
+ visibility of threads to various groups
+ """
+ SHOW_PUBLISHED_RESPONSES = 0
+ SHOW_ALL_RESPONSES = 1
+ VISIBILITY_CHOICES = (
+ (SHOW_PUBLISHED_RESPONSES, 'show only published responses'),
+ (SHOW_ALL_RESPONSES, 'show all responses')
+ )
+ thread = models.ForeignKey('Thread')
+ group = models.ForeignKey(Group)
+ visibility = models.SmallIntegerField(
+ choices=VISIBILITY_CHOICES,
+ default=SHOW_ALL_RESPONSES
+ )
+
+ class Meta:
+ unique_together = ('thread', 'group')
+ db_table = 'askbot_thread_groups'
+ app_label = 'askbot'
+
+
class Thread(models.Model):
SUMMARY_CACHE_KEY_TPL = 'thread-question-summary-%d'
ANSWER_LIST_KEY_TPL = 'thread-answer-list-%d'
@@ -382,6 +493,7 @@ class Thread(models.Model):
title = models.CharField(max_length=300)
tags = models.ManyToManyField('Tag', related_name='threads')
+ groups = models.ManyToManyField(Group, through=ThreadToGroup, related_name='group_threads')
# Denormalised data, transplanted from Question
tagnames = models.CharField(max_length=125)
@@ -443,6 +555,85 @@ class Thread(models.Model):
#question_id = self._question_post().id
#return reverse('question', args = [question_id]) + slugify(self.title)
+ def get_answer_count(self, user = None):
+ """returns answer count depending on who the user is.
+ When user groups are enabled and some answers are hidden,
+ the answer count to show must be reflected accordingly"""
+ if askbot_settings.GROUPS_ENABLED == False:
+ return self.answer_count
+ else:
+ return self.get_answers(user).count()
+
+ def get_sharing_info(self, visitor=None):
+ """returns a dictionary with abbreviated thread sharing info:
+ * users - up to a certain number of users, excluding the visitor
+ * groups - up to a certain number of groups
+ * more_users_count - remaining count of shared-with users
+ * more_groups_count - remaining count of shared-with groups
+ """
+ shared_users = self.get_users_shared_with(
+ max_count=2,#"visitor" is implicit
+ exclude_user=visitor
+ )
+ groups = self.groups
+ ugroups = groups.get_personal()
+ ggroups = groups.exclude_personal()
+
+ sharing_info = {
+ 'users': shared_users,
+ 'groups': self.get_groups_shared_with(max_count=3),
+ 'more_users_count': max(0, ugroups.count() - 3),
+ 'more_groups_count': max(0, ggroups.count() - 3)
+ }
+ return sharing_info
+
+ def get_users_shared_with(self, max_count=None, exclude_user=None):
+ """returns query set of users with whom
+ this thread is shared
+ """
+ filter = models.Q(
+ thread=self,
+ visibility=ThreadToGroup.SHOW_ALL_RESPONSES
+ ) & models.Q(
+ group__name__startswith=PERSONAL_GROUP_NAME_PREFIX
+ )
+
+ if exclude_user:
+ user_group = exclude_user.get_personal_group()
+ filter = filter & ~models.Q(group_id=user_group.id)
+
+ thread_groups = ThreadToGroup.objects.filter(filter)
+
+ if max_count:
+ thread_groups = thread_groups[:max_count]
+
+ group_ids = thread_groups.values_list('group_id', flat=True)
+
+ from askbot.models import GroupMembership
+ user_ids = GroupMembership.objects.filter(
+ group__id__in=group_ids
+ ).values_list(
+ 'user__id', flat=True
+ )
+
+ return User.objects.filter(id__in=user_ids)
+
+ def get_groups_shared_with(self, max_count=None):
+ """returns query set of groups with whom thread is shared"""
+ thread_groups = ThreadToGroup.objects.filter(
+ models.Q(
+ thread=self,
+ visibility=ThreadToGroup.SHOW_ALL_RESPONSES
+ ) & ~models.Q(
+ group__name__startswith=PERSONAL_GROUP_NAME_PREFIX
+ )
+ )
+ if max_count:
+ thread_groups = thread_groups[:max_count]
+
+ group_ids = thread_groups.values_list('group_id', flat=True)
+ return Group.objects.filter(id__in=group_ids)
+
def update_favorite_count(self):
self.favourite_count = FavoriteQuestion.objects.filter(thread=self).count()
self.save()
@@ -492,10 +683,13 @@ class Thread(models.Model):
def get_title(self, question=None):
if not question:
question = self._question_post() # allow for optimization if the caller has already fetched the question post for this thread
- if self.closed:
+ if self.is_private():
+ attr = const.POST_STATUS['private']
+ elif self.closed:
attr = const.POST_STATUS['closed']
elif question.deleted:
attr = const.POST_STATUS['deleted']
+
else:
attr = None
if attr is not None:
@@ -503,9 +697,9 @@ class Thread(models.Model):
else:
return self.title
- def format_for_email(self):
+ def format_for_email(self, user=None):
"""experimental function: output entire thread for email"""
- question, answers, junk = self.get_cached_post_data()
+ question, answers, junk, published_ans_ids = self.get_cached_post_data(user=user)
output = question.format_for_email_as_subthread()
if answers:
answer_heading = ungettext(
@@ -518,6 +712,36 @@ class Thread(models.Model):
output += answer.format_for_email_as_subthread()
return output
+ def get_answers_by_user(self, user):
+ """regardless - deleted or not"""
+ return self.posts.filter(post_type = 'answer', author = user)
+
+ def has_answer_by_user(self, user):
+ #use len to cache the queryset
+ return len(self.get_answers_by_user(user)) > 0
+
+ def has_moderator(self, user):
+ """true if ``user`` is also a thread moderator"""
+ if user.is_anonymous():
+ return False
+ elif askbot_settings.GROUPS_ENABLED:
+ if user.is_administrator_or_moderator():
+ user_groups = user.get_groups(private=True)
+ thread_groups = self.get_groups_shared_with()
+ return bool(set(user_groups) & set(thread_groups))
+ return False
+
+ def requires_response_moderation(self, author):
+ """true, if answers by a given author must be moderated
+ before publishing to the enquirers"""
+ author_groups = author.get_groups()
+ thread_groups = self.get_groups_shared_with()
+ for group in set(author_groups) & set(thread_groups):
+ if group.moderate_answers_to_enquirers:
+ return True
+
+ return False
+
def tagname_meta_generator(self):
return u','.join([unicode(tag) for tag in self.get_tag_names()])
@@ -532,12 +756,13 @@ class Thread(models.Model):
return self.posts.get_answers().filter(deleted=False)
else:
if user.is_administrator() or user.is_moderator():
- return self.posts.get_answers()
+ return self.posts.get_answers(user = user)
else:
- return self.posts.get_answers().filter(
- models.Q(deleted = False) | models.Q(author = user) \
- | models.Q(deleted_by = user)
- )
+ return self.posts.get_answers(user = user).filter(
+ models.Q(deleted = False) \
+ | models.Q(author = user) \
+ | models.Q(deleted_by = user)
+ )
def invalidate_cached_thread_content_fragment(self):
cache.cache.delete(self.SUMMARY_CACHE_KEY_TPL % self.id)
@@ -558,9 +783,12 @@ class Thread(models.Model):
#self.invalidate_cached_thread_content_fragment()
self.update_summary_html()
- def get_cached_post_data(self, sort_method = 'votes'):
+ def get_cached_post_data(self, user = None, sort_method = 'votes'):
"""returns cached post data, as calculated by
the method get_post_data()"""
+ if askbot_settings.GROUPS_ENABLED:
+ #temporary plug: bypass cache where groups are enabled
+ return self.get_post_data(sort_method=sort_method, user=user)
key = self.get_post_data_cache_key(sort_method)
post_data = cache.cache.get(key)
if not post_data:
@@ -568,14 +796,25 @@ class Thread(models.Model):
cache.cache.set(key, post_data, const.LONG_TIME)
return post_data
- def get_post_data(self, sort_method = 'votes'):
+ def get_post_data(self, sort_method='votes', user=None):
"""returns question, answers as list and a list of post ids
- for the given thread
+ for the given thread, and the list of published post ids
+ (four values)
the returned posts are pre-stuffed with the comments
all (both posts and the comments sorted in the correct
order)
"""
- thread_posts = self.posts.all().order_by(
+ thread_posts = self.posts.all()
+ if askbot_settings.GROUPS_ENABLED:
+ if user is None or user.is_anonymous():
+ groups = (get_global_group(),)
+ else:
+ groups = user.get_groups()
+
+ thread_posts = thread_posts.filter(groups__in=groups)
+ thread_posts = thread_posts.distinct()#important for >1 group
+
+ thread_posts = thread_posts.order_by(
{
'latest':'-added_at',
'oldest':'added_at',
@@ -592,7 +831,7 @@ class Thread(models.Model):
#pass through only deleted question posts
if post.deleted and post.post_type != 'question':
continue
- if post.approved == False:#hide posts on the moderation queue
+ if post.is_approved() is False:#hide posts on the moderation queue
continue
post_to_author[post.id] = post.author_id
@@ -623,11 +862,36 @@ class Thread(models.Model):
if self.has_accepted_answer() and self.accepted_answer.deleted == False:
#Put the accepted answer to front
#the second check is for the case when accepted answer is deleted
- accepted_answer = post_map[self.accepted_answer_id]
- answers.remove(accepted_answer)
- answers.insert(0, accepted_answer)
-
- return (question_post, answers, post_to_author)
+ if self.accepted_answer_id in post_map:
+ accepted_answer = post_map[self.accepted_answer_id]
+ answers.remove(accepted_answer)
+ answers.insert(0, accepted_answer)
+
+ #if user is not an inquirer, and thread is moderated,
+ #put published answers first
+ #todo: there may be > 1 enquirers
+ published_answer_ids = list()
+ if self.is_moderated() and user != question_post.author:
+ #if moderated - then author is guaranteed to be the
+ #limited visibility enquirer
+ published_answers = self.posts.get_answers(
+ user=question_post.author#todo: may be > 1
+ ).filter(
+ deleted=False
+ ).order_by(
+ {
+ 'latest':'-added_at',
+ 'oldest':'added_at',
+ 'votes':'-score'
+ }[sort_method]
+ )
+ #now put those answers first
+ for answer in reversed(published_answers):
+ answers.remove(answer)
+ answers.insert(0, answer)
+ published_answer_ids.append(answer.id)
+
+ return (question_post, answers, post_to_author, published_answer_ids)
def has_accepted_answer(self):
return self.accepted_answer_id != None
@@ -653,6 +917,8 @@ class Thread(models.Model):
"""
def get_data():
+ # todo: code in this function would be simpler if
+ # we had question post id denormalized on the thread
tags_list = self.get_tag_names()
similar_threads = Thread.objects.filter(
tags__name__in=tags_list
@@ -671,20 +937,28 @@ class Thread(models.Model):
similar_threads = similar_threads[:10]
# Denormalize questions to speed up template rendering
+ # todo: just denormalize question_post_id on the thread!
thread_map = dict([(thread.id, thread) for thread in similar_threads])
questions = Post.objects.get_questions()
questions = questions.select_related('thread').filter(thread__in=similar_threads)
for q in questions:
thread_map[q.thread_id].question_denorm = q
- # Postprocess data
- similar_threads = [
- {
- 'url': thread.question_denorm.get_absolute_url(),
- 'title': thread.get_title(thread.question_denorm)
- } for thread in similar_threads
- ]
- return similar_threads
+ # Postprocess data for the final output
+ result = list()
+ for thread in similar_threads:
+ question_post = getattr(thread, 'question_denorm', None)
+ # unfortunately the if statement below is necessary due to
+ # a possible bug
+ # all this proves that it's wrong to reference threads by
+ # the question post id in the question page urls!!!
+ # this is a "legacy" problem inherited from the old models
+ if question_post:
+ url = question_post.get_absolute_url()
+ title = thread.get_title(question_post)
+ result.append({'url': url, 'title': title})
+
+ return result
def get_cached_data():
"""similar thread data will expire
@@ -718,76 +992,203 @@ class Thread(models.Model):
return self.followed_by.filter(id = user.id).count() > 0
return False
- def update_tags(self, tagnames = None, user = None, timestamp = None):
+ def is_moderated(self):
+ """True, if tread has SHOW_PUBLISHED_RESPONSES
+ group memberships"""
+ if askbot_settings.GROUPS_ENABLED:
+ return ThreadToGroup.objects.filter(
+ thread=self,
+ visibility=ThreadToGroup.SHOW_PUBLISHED_RESPONSES
+ )
+ return False
+
+ def add_child_posts_to_groups(self, groups):
+ """adds questions and answers of the thread to
+ given groups, comments are taken care of implicitly
+ by the underlying ``Post`` methods
+ """
+ post_types = ('question', 'answer')
+ posts = self.posts.filter(post_type__in=post_types)
+ for post in posts:
+ post.add_to_groups(groups)
+
+ def remove_child_posts_from_groups(self, groups):
+ """removes child posts from given groups"""
+ post_ids = self.posts.all().values_list('id', flat=True)
+ group_ids = [group.id for group in groups]
+ PostToGroup.objects.filter(
+ post__id__in=post_ids,
+ tag__id__in=group_ids
+ ).delete()
+
+ def add_to_groups(
+ self, groups, visibility=ThreadToGroup.SHOW_ALL_RESPONSES, recursive=False
+ ):
+ """adds thread to a list of groups
+ ``groups`` argument may be any iterable of groups
+ """
+ for group in groups:
+ #todo: change to bulk create when django 1.3 goes out of use
+ thread_group, created = ThreadToGroup.objects.get_or_create(
+ thread=self,
+ group=group
+ )
+
+ if thread_group.visibility != visibility:
+ thread_group.visibility = visibility
+ thread_group.save()
+
+ if recursive == True:
+ #comments are taken care of automatically
+ self.add_child_posts_to_groups(groups)
+
+ def remove_from_groups(self, groups, recursive=False):
+ thread_groups = ThreadToGroup.objects.filter(
+ thread=self, group__in=groups
+ )
+ thread_groups.delete()
+ if recursive == True:
+ self.remove_child_posts_from_groups(groups)
+
+ def make_public(self, recursive=False):
+ """adds the global group to the thread"""
+ groups = (get_global_group(), )
+ self.add_to_groups(groups, recursive=recursive)
+ if recursive == False:
+ self._question_post().make_public()
+
+ def make_private(self, user, group_id = None):
+ """adds thread to all user's groups, excluding
+ the global, or to a group given by id.
+ The add by ID now only works if user belongs to that group
+ """
+ if group_id:
+ group = Group.objects.get(id=group_id)
+ groups = [group]
+ self.add_to_groups(groups)
+
+ global_group = get_global_group()
+ if group != global_group:
+ self.remove_from_groups((global_group,))
+ else:
+ groups = user.get_groups(private=True)
+ self.add_to_groups(groups)
+ self.remove_from_groups((get_global_group(),))
+
+ self._question_post().make_private(user, group_id)
+
+ if len(groups) == 0:
+ message = 'Sharing did not work, because group is unknown'
+ user.message_set.create(message=message)
+
+ def is_private(self):
+ """true, if thread belongs to the global group"""
+ if askbot_settings.GROUPS_ENABLED:
+ group = get_global_group()
+ return not self.groups.filter(id=group.id).exists()
+ return False
+
+
+ def remove_tags_by_names(self, tagnames):
+ """removes tags from thread by names"""
+ removed_tags = list()
+ for tag in self.tags.all():
+ if tag.name in tagnames:
+ tag.used_count -= 1
+ removed_tags.append(tag)
+ self.tags.remove(*removed_tags)
+ return removed_tags
+
+
+ def update_tags(
+ self, tagnames = None, user = None, timestamp = None
+ ):
"""
Updates Tag associations for a thread to match the given
tagname string.
-
When tags are removed and their use count hits 0 - the tag is
automatically deleted.
-
When an added tag does not exist - it is created
+ If tag moderation is on - new tags are placed on the queue
Tag use counts are recalculated
-
A signal tags updated is sent
- *IMPORTANT*: self._question_post() has to exist when update_tags() is called!
+ *IMPORTANT*: self._question_post() has to
+ exist when update_tags() is called!
"""
- previous_tags = list(self.tags.all())
+ if tagnames.strip() == '':
+ return
- previous_tagnames = set([tag.name for tag in previous_tags])
- updated_tagnames = set(t for t in tagnames.strip().split(' '))
+ previous_tags = list(self.tags.filter(status = Tag.STATUS_ACCEPTED))
+ ordered_updated_tagnames = [t for t in tagnames.strip().split(' ')]
+
+ previous_tagnames = set([tag.name for tag in previous_tags])
+ updated_tagnames = set(ordered_updated_tagnames)
removed_tagnames = previous_tagnames - updated_tagnames
- added_tagnames = updated_tagnames - previous_tagnames
- modified_tags = list()
#remove tags from the question's tags many2many relation
- if removed_tagnames:
- removed_tags = [tag for tag in previous_tags if tag.name in removed_tagnames]
- self.tags.remove(*removed_tags)
+ #used_count values are decremented on all tags
+ removed_tags = self.remove_tags_by_names(removed_tagnames)
- #if any of the removed tags reached use count == 1 that means they must be deleted
- for tag in removed_tags:
- if tag.used_count == 1:
- #we won't modify used count b/c it's done below anyway
- removed_tags.remove(tag)
- #todo - do we need to use fields deleted_by and deleted_at?
- tag.delete()#auto-delete tags whose use count dwindled
+ #modified tags go on to recounting their use
+ #todo - this can actually be done asynchronously - not so important
+ modified_tags, unused_tags = separate_unused_tags(removed_tags)
+ delete_tags(unused_tags)#tags with used_count == 0 are deleted
- #remember modified tags, we'll need to update use counts on them
- modified_tags = removed_tags
+ modified_tags = removed_tags
#add new tags to the relation
+ added_tagnames = updated_tagnames - previous_tagnames
+
if added_tagnames:
#find reused tags
- reused_tags = Tag.objects.filter(name__in = added_tagnames)
- #undelete them, because we are using them
- reused_count = reused_tags.update(
- deleted = False,
- deleted_by = None,
- deleted_at = None
- )
- #if there are brand new tags, create them and finalize the added tag list
- if reused_count < len(added_tagnames):
- added_tags = list(reused_tags)
-
- reused_tagnames = set([tag.name for tag in reused_tags])
- new_tagnames = added_tagnames - reused_tagnames
- for name in new_tagnames:
- new_tag = Tag.objects.create(
- name = name,
- created_by = user,
- used_count = 1
+ reused_tags, new_tagnames = get_tags_by_names(added_tagnames)
+ reused_tags.mark_undeleted()
+
+ added_tags = list(reused_tags)
+ #tag moderation is in the call below
+ created_tags = Tag.objects.create_in_bulk(
+ tag_names = new_tagnames, user = user
)
- added_tags.append(new_tag)
- else:
- added_tags = reused_tags
- #finally add tags to the relation and extend the modified list
+ added_tags.extend(created_tags)
+ #todo: not nice that assignment of added_tags is way above
self.tags.add(*added_tags)
modified_tags.extend(added_tags)
+ else:
+ added_tags = Tag.objects.none()
+
+ #Save denormalized tag names on thread. Preserve order from user input.
+ accepted_added_tags = filter_accepted_tags(added_tags)
+ added_tagnames = set([tag.name for tag in accepted_added_tags])
+ final_tagnames = (previous_tagnames - removed_tagnames) | added_tagnames
+ ordered_final_tagnames = list()
+ for tagname in ordered_updated_tagnames:
+ if tagname in final_tagnames:
+ ordered_final_tagnames.append(tagname)
+
+ self.tagnames = ' '.join(ordered_final_tagnames)
+ self.save()#need to save here?
+
+ #todo: factor out - tell author about suggested tags
+ suggested_tags = filter_suggested_tags(added_tags)
+ if len(suggested_tags) > 0:
+ #1) notify author that the tag is going to be moderated
+ #todo: factor this out
+ if len(suggested_tags) == 1:
+ msg = _(
+ 'Tag %s is new and will be submitted for the '
+ 'moderators approval'
+ ) % suggested_tags[0].name
+ else:
+ msg = _(
+ 'Tags %s are new and will be submitted for the '
+ 'moderators approval'
+ ) % ', '.join([tag.name for tag in suggested_tags])
+ user.message_set.create(message = msg)
+ #2) todo: notify moderators about newly suggested tags
####################################################################
self.update_summary_html() # regenerate question/thread summary html
@@ -806,6 +1207,22 @@ class Thread(models.Model):
return False
+ def add_tag(
+ self, user = None, timestamp = None, tag_name = None, silent = False
+ ):
+ """adds one tag to thread"""
+ tag_names = self.get_tag_names()
+ if tag_name in tag_names:
+ return
+ tag_names.append(tag_name)
+
+ self.retag(
+ retagged_by = user,
+ retagged_at = timestamp,
+ tagnames = ' '.join(tag_names),
+ silent = silent
+ )
+
def retag(self, retagged_by=None, retagged_at=None, tagnames=None, silent=False):
"""changes thread tags"""
if None in (retagged_by, retagged_at, tagnames):
@@ -829,7 +1246,7 @@ class Thread(models.Model):
# Create a new revision
latest_revision = thread_question.get_latest_revision()
- PostRevision.objects.create_question_revision(
+ PostRevision.objects.create(
post = thread_question,
title = latest_revision.title,
author = retagged_by,
@@ -858,11 +1275,13 @@ class Thread(models.Model):
return last_updated_at, last_updated_by
- def get_summary_html(self, search_state):
- html = self.get_cached_summary_html()
+ def get_summary_html(self, search_state, visitor = None):
+ html = self.get_cached_summary_html(visitor)
if not html:
- html = self.update_summary_html()
+ html = self.update_summary_html(visitor)
+ # todo: this work may be pushed onto javascript we post-process tag names
+ # in the snippet so that tag urls match the search state
# use `<<<` and `>>>` because they cannot be confused with user input
# - if user accidentialy types <<<tag-name>>> into question title or body,
# then in html it'll become escaped like this: &lt;&lt;&lt;tag-name&gt;&gt;&gt;
@@ -882,14 +1301,21 @@ class Thread(models.Model):
return html
- def get_cached_summary_html(self):
+ def get_cached_summary_html(self, visitor = None):
+ #todo: remove this plug by adding cached foreign user group
+ #parameter to the key. Now with groups on caching is turned off
+ #parameter visitor is there to get summary out by the user groups
+ if askbot_settings.GROUPS_ENABLED:
+ return None
return cache.cache.get(self.SUMMARY_CACHE_KEY_TPL % self.id)
- def update_summary_html(self):
+ def update_summary_html(self, visitor = None):
context = {
'thread': self,
- 'question': self._question_post(refresh=True), # fetch new question post to make sure we're up-to-date
+ #fetch new question post to make sure we're up-to-date
+ 'question': self._question_post(refresh=True),
'search_state': DummySearchState(),
+ 'visitor': visitor
}
html = get_template('widgets/question_summary.html').render(context)
# INFO: Timeout is set to 30 days:
@@ -928,7 +1354,20 @@ class FavoriteQuestion(models.Model):
return '[%s] favorited at %s' %(self.user, self.added_at)
-class AnonymousQuestion(AnonymousContent):
+class DraftQuestion(models.Model):
+ """Provides space to solve unpublished draft
+ questions. Contents is used to populate the Ask form.
+ """
+ author = models.ForeignKey(User)
+ title = models.CharField(max_length=300, null=True)
+ text = models.TextField(null=True)
+ tagnames = models.CharField(max_length=125, null=True)
+
+ class Meta:
+ app_label = 'askbot'
+
+
+class AnonymousQuestion(DraftContent):
"""question that was asked before logging in
maybe the name is a little misleading, the user still
may or may not want to stay anonymous after the question
@@ -940,6 +1379,7 @@ class AnonymousQuestion(AnonymousContent):
def publish(self,user):
added_at = datetime.datetime.now()
+ #todo: wrong - use User.post_question() instead
Thread.objects.create_new(
title = self.title,
added_at = added_at,
diff --git a/askbot/models/tag.py b/askbot/models/tag.py
index cb9070a4..647ea5cf 100644
--- a/askbot/models/tag.py
+++ b/askbot/models/tag.py
@@ -1,10 +1,90 @@
import re
+import logging
from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from django.conf import settings
from askbot.models.base import BaseQuerySetManager
from askbot import const
+from askbot.conf import settings as askbot_settings
+from askbot.utils import category_tree
+
+def get_global_group():
+ """Returns the global group,
+ if necessary, creates one
+ """
+ #todo: when groups are disconnected from tags,
+ #find comment as shown below in the test cases and
+ #revert the values
+ #todo: change groups to django groups
+ group_name = askbot_settings.GLOBAL_GROUP_NAME
+ from askbot.models import Group
+ try:
+ return Group.objects.get(name=group_name)
+ except Group.DoesNotExist:
+ return Group.objects.create(name=group_name)
+
+def delete_tags(tags):
+ """deletes tags in the list"""
+ tag_ids = [tag.id for tag in tags]
+ Tag.objects.filter(id__in = tag_ids).delete()
+
+def get_tags_by_names(tag_names):
+ """returns query set of tags
+ and a set of tag names that were not found
+ """
+ tags = Tag.objects.filter(name__in = tag_names)
+ #if there are brand new tags, create them
+ #and finalize the added tag list
+ if tags.count() < len(tag_names):
+ found_tag_names = set([tag.name for tag in tags])
+ new_tag_names = set(tag_names) - found_tag_names
+ else:
+ new_tag_names = set()
+
+ return tags, new_tag_names
+
+def filter_tags_by_status(tags, status = None):
+ """returns a list or a query set of tags which are accepted"""
+ if isinstance(tags, models.query.QuerySet):
+ return tags.filter(status = status)
+ else:
+ return [tag for tag in tags if tag.status == status]
+
+def filter_accepted_tags(tags):
+ return filter_tags_by_status(tags, status = Tag.STATUS_ACCEPTED)
+
+def filter_suggested_tags(tags):
+ return filter_tags_by_status(tags, status = Tag.STATUS_SUGGESTED)
+
+def format_personal_group_name(user):
+ #todo: after migration of groups away from tags,
+ #this function will be moved somewhere else
+ from askbot.models.user import PERSONAL_GROUP_NAME_PREFIX as prefix
+ return '%s%d' % (prefix, user.id)
+
+def is_preapproved_tag_name(tag_name):
+ """true if tag name is in the category tree
+ or any other container of preapproved tags"""
+ #get list of preapproved tags, to make exceptions for
+ if askbot_settings.TAG_SOURCE == 'category-tree':
+ return tag_name in category_tree.get_leaf_names()
+ return False
+
+def separate_unused_tags(tags):
+ """returns two lists::
+ * first where tags whose use counts are >0
+ * second - with use counts == 0
+ """
+ used = list()
+ unused = list()
+ for tag in tags:
+ if tag.used_count == 0:
+ unused.append(tag)
+ else:
+ assert(tag.used_count > 0)
+ used.append(tag)
+ return used, unused
def tags_match_some_wildcard(tag_names, wildcard_tags):
"""Same as
@@ -21,12 +101,29 @@ def get_mandatory_tags():
"""returns list of mandatory tags,
or an empty list, if there aren't any"""
from askbot.conf import settings as askbot_settings
- raw_mandatory_tags = askbot_settings.MANDATORY_TAGS.strip()
- if len(raw_mandatory_tags) == 0:
- return []
+ #TAG_SOURCE setting is hidden
+ #and only is accessible via livesettings overrides
+ if askbot_settings.TAG_SOURCE == 'category-tree':
+ return []#hack: effectively we disable the mandatory tags feature
else:
- split_re = re.compile(const.TAG_SPLIT_REGEX)
- return split_re.split(raw_mandatory_tags)
+ #todo - in the future clean this up
+ #we might need to have settings:
+ #* prepopulated tags - json structure - either a flat list or a tree
+ # if structure is tree - then use some multilevel selector for choosing tags
+ # if it is a list - then make users click on tags to select them
+ #* use prepopulated tags (boolean)
+ #* tags are required
+ #* regular users can create tags (boolean)
+ #the category tree and the mandatory tag lists can be merged
+ #into the same setting - and mandatory tags should use json
+ #keep in mind that in the future multiword tags will be allowed
+ raw_mandatory_tags = askbot_settings.MANDATORY_TAGS.strip()
+ if len(raw_mandatory_tags) == 0:
+ return []
+ else:
+ split_re = re.compile(const.TAG_SPLIT_REGEX)
+ return split_re.split(raw_mandatory_tags)
+
class TagQuerySet(models.query.QuerySet):
def get_valid_tags(self, page_size):
@@ -39,6 +136,14 @@ class TagQuerySet(models.query.QuerySet):
tag.used_count = tag.threads.count()
tag.save()
+ def mark_undeleted(self):
+ """removes deleted(+at/by) marks"""
+ self.update(#undelete them
+ deleted = False,
+ deleted_by = None,
+ deleted_at = None
+ )
+
def tags_match_some_wildcard(self, wildcard_tags = None):
"""True if any one of the tags in the query set
matches a wildcard
@@ -83,22 +188,93 @@ class TagManager(BaseQuerySetManager):
def get_query_set(self):
return TagQuerySet(self.model)
-class GroupTagQuerySet(TagQuerySet):
- """Custom query set for the group"""
+ def get_content_tags(self):
+ """temporary function that filters out the group tags"""
+ return self.all()
+
+ def create(self, name = None, created_by = None, **kwargs):
+ """Creates a new tag"""
+ if created_by.can_create_tags() or is_preapproved_tag_name(name):
+ status = Tag.STATUS_ACCEPTED
+ else:
+ status = Tag.STATUS_SUGGESTED
+
+ kwargs['created_by'] = created_by
+ kwargs['name'] = name
+ kwargs['status'] = status
- def get_for_user(self, user = None):
- return self.filter(user_memberships__user = user)
+ return super(TagManager, self).create(**kwargs)
- def get_all(self):
- return self.annotate(
- member_count = models.Count('user_memberships')
- ).filter(
- member_count__gt = 0
+ def create_suggested_tag(self, tag_names = None, user = None):
+ """This function is not used, and will probably need
+ to be retired. In the previous version we were sending
+ email to admins when the new tags were created,
+ now we have a separate page where new tags are listed.
+ """
+ #todo: stuff below will probably go after
+ #tag moderation actions are implemented
+ from askbot import mail
+ from askbot.mail import messages
+ body_text = messages.notify_admins_about_new_tags(
+ tags = tag_names,
+ user = user,
+ thread = self
+ )
+ site_name = askbot_settings.APP_SHORT_NAME
+ subject_line = _('New tags added to %s') % site_name
+ mail.mail_moderators(
+ subject_line,
+ body_text,
+ headers = {'Reply-To': user.email}
+ )
+
+ msg = _(
+ 'Tags %s are new and will be submitted for the '
+ 'moderators approval'
+ ) % ', '.join(tag_names)
+ user.message_set.create(message = msg)
+
+ def create_in_bulk(self, tag_names = None, user = None):
+ """creates tags by names. If user can create tags,
+ then they are set status ``STATUS_ACCEPTED``,
+ otherwise the status will be set to ``STATUS_SUGGESTED``.
+
+ One exception: if suggested tag is in the category tree
+ and source of tags is category tree - then status of newly
+ created tag is ``STATUS_ACCEPTED``
+ """
+
+ #load suggested tags
+ pre_suggested_tags = self.filter(
+ name__in = tag_names, status = Tag.STATUS_SUGGESTED
)
- def get_by_name(self, group_name = None):
- return self.get(name = clean_group_name(group_name))
+ #deal with suggested tags
+ if user.can_create_tags():
+ #turn previously suggested tags into accepted
+ pre_suggested_tags.update(status = Tag.STATUS_ACCEPTED)
+ else:
+ #increment use count and add user to "suggested_by"
+ for tag in pre_suggested_tags:
+ tag.times_used += 1
+ tag.suggested_by.add(user)
+ tag.save()
+
+ created_tags = list()
+ pre_suggested_tag_names = list()
+ for tag in pre_suggested_tags:
+ pre_suggested_tag_names.append(tag.name)
+ created_tags.append(tag)
+
+ for tag_name in set(tag_names) - set(pre_suggested_tag_names):
+ #status for the new tags is automatically set within the create()
+ new_tag = Tag.objects.create(name = tag_name, created_by = user)
+ created_tags.append(new_tag)
+ if new_tag.status == Tag.STATUS_SUGGESTED:
+ new_tag.suggested_by.add(user)
+
+ return created_tags
def clean_group_name(name):
"""group names allow spaces,
@@ -106,33 +282,21 @@ def clean_group_name(name):
to replace spaces with dashes"""
return re.sub('\s+', '-', name.strip())
-class GroupTagManager(BaseQuerySetManager):
- """manager for group tags"""
+class Tag(models.Model):
+ #a couple of status constants
+ STATUS_SUGGESTED = 0
+ STATUS_ACCEPTED = 1
- def get_query_set(self):
- return GroupTagQuerySet(self.model)
-
- def get_or_create(self, group_name = None, user = None):
- """creates a group tag or finds one, if exists"""
- #todo: here we might fill out the group profile
-
- #replace spaces with dashes
- group_name = clean_group_name(group_name)
- try:
- #iexact is important!!! b/c we don't want case variants
- #of tags
- tag = self.get(name__iexact = group_name)
- except self.model.DoesNotExist:
- tag = self.model(name = group_name, created_by = user)
- tag.save()
- from askbot.models.user import GroupProfile
- group_profile = GroupProfile(group_tag = tag)
- group_profile.save()
- return tag
+ name = models.CharField(max_length=255, unique=True)
+ created_by = models.ForeignKey(User, related_name='created_tags')
+
+ suggested_by = models.ManyToManyField(
+ User, related_name='suggested_tags',
+ help_text = 'Works only for suggested tags for tag moderation'
+ )
+
+ status = models.SmallIntegerField(default = STATUS_ACCEPTED)
-class Tag(models.Model):
- name = models.CharField(max_length=255, unique=True)
- created_by = models.ForeignKey(User, related_name='created_tags')
# Denormalised data
used_count = models.PositiveIntegerField(default=0)
@@ -147,7 +311,6 @@ class Tag(models.Model):
)
objects = TagManager()
- group_tags = GroupTagManager()
class Meta:
app_label = 'askbot'
@@ -169,3 +332,11 @@ class MarkedTag(models.Model):
class Meta:
app_label = 'askbot'
+
+def get_groups():
+ from askbot.models import Group
+ return Group.objects.all()
+
+def get_group_names():
+ #todo: cache me
+ return get_groups().values_list('name', flat = True)
diff --git a/askbot/models/user.py b/askbot/models/user.py
index e4077ea5..39bb8ea9 100644
--- a/askbot/models/user.py
+++ b/askbot/models/user.py
@@ -6,14 +6,21 @@ from django.db.backends.dummy.base import IntegrityError
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.contrib.auth.models import User
+from django.contrib.auth.models import Group as AuthGroup
from django.core import exceptions
from django.forms import EmailField, URLField
from django.utils.translation import ugettext as _
from django.utils.html import strip_tags
from askbot import const
+from askbot.conf import settings as askbot_settings
from askbot.utils import functions
-from askbot.models.tag import Tag
+from askbot.models.base import BaseQuerySetManager
+from askbot.models.tag import Tag, get_global_group
+from askbot.models.tag import clean_group_name#todo - delete this
from askbot.forms import DomainNameField
+from askbot.utils.forms import email_is_allowed
+
+PERSONAL_GROUP_NAME_PREFIX = '_personal_'
class ResponseAndMentionActivityManager(models.Manager):
def get_query_set(self):
@@ -205,10 +212,7 @@ class Activity(models.Model):
return user_qs[0]
def get_snippet(self, max_length = 120):
- if self.summary == '':
- return self.content_object.get_snippet(max_length)
- else:
- return self.summary
+ return self.content_object.get_snippet(max_length)
def get_absolute_url(self):
return self.content_object.get_absolute_url()
@@ -267,6 +271,13 @@ class EmailFeedSetting(models.Model):
'q_sel': 'n',
'm_and_c': 'n'
}
+ MAX_EMAIL_SCHEDULE = {
+ 'q_ask': 'i',
+ 'q_ans': 'i',
+ 'q_all': 'i',
+ 'q_sel': 'i',
+ 'm_and_c': 'i'
+ }
FEED_TYPE_CHOICES = (
('q_all',_('Entire forum')),
('q_ask',_('Questions that I asked')),
@@ -339,28 +350,131 @@ class EmailFeedSetting(models.Model):
self.save()
-class GroupMembership(models.Model):
- """an explicit model to link users and the tags
- that by being recorded with this relation automatically
- become group tags
+class AuthUserGroups(models.Model):
+ """explicit model for the auth_user_groups bridge table.
"""
- group = models.ForeignKey(Tag, related_name = 'user_memberships')
- user = models.ForeignKey(User, related_name = 'group_memberships')
+ group = models.ForeignKey(AuthGroup)
+ user = models.ForeignKey(User)
class Meta:
- app_label = 'askbot'
+ app_label = 'auth'
unique_together = ('group', 'user')
+ db_table = 'auth_user_groups'
+ managed = False
+
+
+class GroupMembership(AuthUserGroups):
+ """contains one-to-one relation to ``auth_user_group``
+ and extra membership profile fields"""
+ #note: this may hold info on when user joined, etc
+ NONE = -1#not part of the choices as for this records should be just missing
+ PENDING = 0
+ FULL = 1
+ LEVEL_CHOICES = (#'none' is by absence of membership
+ (PENDING, 'pending'),
+ (FULL, 'full')
+ )
+ ALL_LEVEL_CHOICES = LEVEL_CHOICES + ((NONE, 'none'),)
-class GroupProfile(models.Model):
- """stores group profile data"""
- group_tag = models.OneToOneField(
- Tag,
- unique = True,
- related_name = 'group_profile'
- )
- logo_url = models.URLField(null = True)
- moderate_email = models.BooleanField(default = True)
- is_open = models.BooleanField(default = False)
+ level = models.SmallIntegerField(
+ default=FULL,
+ choices=LEVEL_CHOICES,
+ )
+
+
+ class Meta:
+ app_label = 'askbot'
+
+ @classmethod
+ def get_level_value_display(cls, level):
+ """returns verbose value given a numerical value
+ includes the "fanthom" NONE
+ """
+ values_dict = dict(cls.ALL_LEVEL_CHOICES)
+ return values_dict[level]
+
+
+class GroupQuerySet(models.query.QuerySet):
+ """Custom query set for the group"""
+
+ def exclude_personal(self):
+ """excludes the personal groups"""
+ return self.exclude(
+ name__startswith=PERSONAL_GROUP_NAME_PREFIX
+ )
+
+ def get_personal(self):
+ """filters for the personal groups"""
+ return self.filter(
+ name__startswith=PERSONAL_GROUP_NAME_PREFIX
+ )
+
+ def get_for_user(self, user=None, private=False):
+ if private:
+ global_group = get_global_group()
+ return self.filter(
+ user=user
+ ).exclude(id=global_group.id)
+ else:
+ return self.filter(user = user)
+
+ def get_by_name(self, group_name = None):
+ return self.get(name = clean_group_name(group_name))
+
+
+class GroupManager(BaseQuerySetManager):
+ """model manager for askbot groups"""
+
+ def get_query_set(self):
+ return GroupQuerySet(self.model)
+
+ def create(self, **kwargs):
+ name = kwargs['name']
+ try:
+ group_ptr = AuthGroup.objects.get(name=name)
+ kwargs['group_ptr'] = group_ptr
+ except AuthGroup.DoesNotExist:
+ pass
+ return super(GroupManager, self).create(**kwargs)
+
+ def get_or_create(self, name = None, user = None, openness=None):
+ """creates a group tag or finds one, if exists"""
+ #todo: here we might fill out the group profile
+ try:
+ #iexact is important!!! b/c we don't want case variants
+ #of tags
+ group = self.get(name__iexact = name)
+ except self.model.DoesNotExist:
+ if openness is None:
+ group = self.create(name=name)
+ else:
+ group = self.create(name=name, openness=openness)
+ return group
+
+
+class Group(AuthGroup):
+ """group profile for askbot"""
+ OPEN = 0
+ MODERATED = 1
+ CLOSED = 2
+ OPENNESS_CHOICES = (
+ (OPEN, 'open'),
+ (MODERATED, 'moderated'),
+ (CLOSED, 'closed'),
+ )
+ logo_url = models.URLField(null=True)
+ description = models.OneToOneField(
+ 'Post', related_name='described_group',
+ null=True, blank=True
+ )
+ moderate_email = models.BooleanField(default=True)
+ moderate_answers_to_enquirers = models.BooleanField(
+ default=False,
+ help_text='If true, answers to outsiders questions '
+ 'will be shown to the enquirers only when '
+ 'selected by the group moderators.'
+ )
+ openness = models.SmallIntegerField(default=CLOSED, choices=OPENNESS_CHOICES)
#preapproved email addresses and domain names to auto-join groups
#trick - the field is padded with space and all tokens are space separated
preapproved_emails = models.TextField(
@@ -371,33 +485,69 @@ class GroupProfile(models.Model):
null = True, blank = True, default = ''
)
+ objects = GroupManager()
+
class Meta:
- #added to make account merges work properly
app_label = 'askbot'
-
- def can_accept_user(self, user):
- """True if user is preapproved to join the group"""
+ db_table = 'askbot_group'
+
+ def get_moderators(self):
+ """returns group moderators"""
+ user_filter = models.Q(is_superuser=True) | models.Q(status='m')
+ user_filter = user_filter & models.Q(groups__in=[self])
+ return User.objects.filter(user_filter)
+
+ def has_moderator(self, user):
+ """true, if user is a group moderator"""
+ mod_ids = self.get_moderators().values_list('id', flat=True)
+ return user.id in mod_ids
+
+ def get_openness_choices(self):
+ """gives answers to question
+ "How can users join this group?"
+ """
+ return (
+ (Group.OPEN, _('Can join when they want')),
+ (Group.MODERATED, _('Users ask permission')),
+ (Group.CLOSED, _('Moderator adds users'))
+ )
+
+ def get_openness_level_for_user(self, user):
+ """returns descriptive value, because it is to be used in the
+ templates. The value must match the verbose versions of the
+ openness choices!!!
+ """
if user.is_anonymous():
- return False
+ return 'closed'
- if self.is_open:
- return True
+ #a special case - automatic global group cannot be joined or left
+ if self.name == askbot_settings.GLOBAL_GROUP_NAME:
+ return 'closed'
+
+ #todo - return 'closed' for internal per user groups too
+
+ if self.openness == Group.OPEN:
+ return 'open'
if user.is_administrator_or_moderator():
- return True
+ return 'open'
#relying on a specific method of storage
- if self.preapproved_emails:
- email_match_re = re.compile(r'\s%s\s' % user.email)
- if email_match_re.search(self.preapproved_emails):
- return True
+ if email_is_allowed(
+ user.email,
+ allowed_emails=self.preapproved_emails,
+ allowed_email_domains=self.preapproved_email_domains
+ ):
+ return 'open'
+
+ if self.openness == Group.MODERATED:
+ return 'moderated'
- if self.preapproved_email_domains:
- email_domain = user.email.split('@')[1]
- domain_match_re = re.compile(r'\s%s\s' % email_domain)
- return domain_match_re.search(self.preapproved_email_domains)
+ return 'closed'
- return False
+ def is_personal(self):
+ """``True`` if the group is personal"""
+ return self.name.startswith(PERSONAL_GROUP_NAME_PREFIX)
def clean(self):
"""called in `save()`
@@ -424,4 +574,4 @@ class GroupProfile(models.Model):
def save(self, *args, **kwargs):
self.clean()
- super(GroupProfile, self).save(*args, **kwargs)
+ super(Group, self).save(*args, **kwargs)
diff --git a/askbot/models/widgets.py b/askbot/models/widgets.py
new file mode 100644
index 00000000..27fc3d84
--- /dev/null
+++ b/askbot/models/widgets.py
@@ -0,0 +1,38 @@
+from django.db import models
+from django.utils.translation import ugettext as _
+from askbot.models import Tag, Group
+from askbot.const import DEFAULT_QUESTION_WIDGET_STYLE, SEARCH_ORDER_BY
+
+class AskWidget(models.Model):
+ '''stores widgets styles and options'''
+ title = models.CharField(max_length=100)
+ group = models.ForeignKey(Group, null=True, blank=True)
+ tag = models.ForeignKey(Tag, null=True, blank=True)
+
+ include_text_field = models.BooleanField(default=False, blank=True)
+
+ inner_style = models.TextField(blank=True)
+ outer_style = models.TextField(blank=True)
+
+ class Meta:
+ app_label = 'askbot'
+
+ def __unicode__(self):
+ return "Widget: %s" % self.title
+
+
+class QuestionWidget(models.Model):
+ title = models.CharField(max_length=100)
+ question_number = models.PositiveIntegerField(default=7)
+ tagnames = models.CharField(_('tags'), max_length=50)
+ group = models.ForeignKey(Group, null=True, blank=True)
+ search_query = models.CharField(
+ max_length=50, null=True, blank=True, default=''
+ )
+ order_by = models.CharField(max_length=18,
+ choices=SEARCH_ORDER_BY, default='-added_at')
+ style = models.TextField(_('css for the widget'),
+ default=DEFAULT_QUESTION_WIDGET_STYLE, blank=True)
+
+ class Meta:
+ app_label = 'askbot'
diff --git a/askbot/search/postgresql/thread_and_post_models_05222012.plsql b/askbot/search/postgresql/thread_and_post_models_05222012.plsql
new file mode 100644
index 00000000..1fe12625
--- /dev/null
+++ b/askbot/search/postgresql/thread_and_post_models_05222012.plsql
@@ -0,0 +1,225 @@
+/* function testing for existence of a column in a table
+ if table does not exists, function will return "false" */
+CREATE OR REPLACE FUNCTION column_exists(colname text, tablename text)
+RETURNS boolean AS
+$$
+DECLARE
+ q text;
+ onerow record;
+BEGIN
+
+ q = 'SELECT attname FROM pg_attribute WHERE attrelid = ( SELECT oid FROM pg_class WHERE relname = '''||tablename||''') AND attname = '''||colname||'''';
+
+ FOR onerow IN EXECUTE q LOOP
+ RETURN true;
+ END LOOP;
+
+ RETURN false;
+END;
+$$ LANGUAGE plpgsql;
+
+/* function adding tsvector column to table if it does not exists */
+CREATE OR REPLACE FUNCTION add_tsvector_column(colname text, tablename text)
+RETURNS boolean AS
+$$
+DECLARE
+ q text;
+BEGIN
+ IF NOT column_exists(colname, tablename) THEN
+ q = 'ALTER TABLE ' || tablename || ' ADD COLUMN ' || colname || ' tsvector';
+ EXECUTE q;
+ RETURN true;
+ ELSE
+ q = 'UPDATE ' || tablename || ' SET ' || colname || '=NULL';
+ EXECUTE q;
+ RETURN false;
+ END IF;
+END;
+$$ LANGUAGE plpgsql;
+
+/* aggregate function that concatenates tsvectors */
+CREATE OR REPLACE FUNCTION tsv_add(tsv1 tsvector, tsv2 tsvector)
+RETURNS tsvector AS
+$$
+BEGIN
+ RETURN tsv1 || tsv2;
+END;
+$$ LANGUAGE plpgsql;
+
+CREATE OR REPLACE FUNCTION setup_aggregates() RETURNS boolean AS
+$$
+DECLARE
+ onerow record;
+BEGIN
+ FOR onerow IN SELECT * FROM pg_proc WHERE proname = 'concat_tsvectors' AND proisagg LOOP
+ DROP AGGREGATE concat_tsvectors(tsvector);
+ END LOOP;
+ CREATE AGGREGATE concat_tsvectors (
+ BASETYPE = tsvector,
+ SFUNC = tsv_add,
+ STYPE = tsvector,
+ INITCOND = ''
+ );
+ RETURN true;
+END;
+$$ LANGUAGE plpgsql;
+
+SELECT setup_aggregates();
+
+/* calculates text search vector for the individual thread row
+DOES not include question body post, answers or comments */
+CREATE OR REPLACE FUNCTION get_thread_tsv(title text, tagnames text)
+RETURNS tsvector AS
+$$
+BEGIN
+ /* todo add weight depending on votes */
+ RETURN setweight(to_tsvector('english', coalesce(title, '')), 'A') ||
+ setweight(to_tsvector('english', coalesce(tagnames, '')), 'A');
+END;
+$$ LANGUAGE plpgsql;
+
+/* calculates text seanch vector for the individual question row */
+CREATE OR REPLACE FUNCTION get_post_tsv(text text, post_type text)
+RETURNS tsvector AS
+$$
+BEGIN
+ /* todo adjust weights to reflect votes */
+ IF post_type='question' THEN
+ RETURN setweight(to_tsvector('english', coalesce(text, '')), 'B');
+ ELSIF post_type='answer' THEN
+ /* todo reflect whether the answer acepted or has many points */
+ RETURN setweight(to_tsvector('english', coalesce(text, '')), 'C');
+ ELSIF post_type='comment' THEN
+ RETURN setweight(to_tsvector('english', coalesce(text, '')), 'D');
+ ELSE
+ RETURN to_tsvector('');
+ END IF;
+END;
+$$ LANGUAGE plpgsql;
+
+/* calculates text search vector for the question body part by thread id
+here we extract question title and the text by thread_id and then
+calculate the text search vector. In the future question
+title will be moved to the askbot_thread table and this function
+will be simpler.
+*/
+CREATE OR REPLACE FUNCTION get_thread_question_tsv(thread_id integer)
+RETURNS tsvector AS
+$$
+DECLARE
+ query text;
+ onerow record;
+BEGIN
+ query = 'SELECT text FROM askbot_post WHERE thread_id=' || thread_id ||
+ ' AND post_type=''question'' AND deleted=false';
+ FOR onerow in EXECUTE query LOOP
+ RETURN get_post_tsv(onerow.text, 'question');
+ END LOOP;
+ RETURN to_tsvector('');
+END;
+$$ LANGUAGE plpgsql;
+
+DROP FUNCTION IF EXISTS get_dependent_comments_tsv(object_id integer, tablename text);
+CREATE OR REPLACE FUNCTION get_dependent_comments_tsv(parent_id integer)
+RETURNS tsvector AS
+$$
+DECLARE
+ query text;
+ onerow record;
+BEGIN
+ query = 'SELECT concat_tsvectors(text_search_vector) FROM askbot_post' ||
+ ' WHERE parent_id=' || parent_id ||
+ ' AND post_type=''comment'' AND deleted=false';
+ FOR onerow IN EXECUTE query LOOP
+ RETURN onerow.concat_tsvectors;
+ END LOOP;
+ RETURN to_tsvector('');
+END;
+$$ LANGUAGE plpgsql;
+
+DROP FUNCTION IF EXISTS get_dependent_answers_tsv(question_id integer);
+CREATE OR REPLACE FUNCTION get_dependent_answers_tsv(thread_id integer)
+RETURNS tsvector AS
+$$
+DECLARE
+ query text;
+ onerow record;
+BEGIN
+ query = 'SELECT concat_tsvectors(text_search_vector) ' ||
+ 'FROM askbot_post WHERE thread_id = ' || thread_id ||
+ ' AND deleted=false';
+ FOR onerow IN EXECUTE query LOOP
+ RETURN onerow.concat_tsvectors;
+ END LOOP;
+ RETURN to_tsvector('');
+END;
+$$ LANGUAGE plpgsql;
+
+/* create tsvector columns in the content tables */
+SELECT add_tsvector_column('text_search_vector', 'askbot_thread');
+SELECT add_tsvector_column('text_search_vector', 'askbot_post');
+
+/* populate tsvectors with data */
+-- post tsvectors
+UPDATE askbot_post set text_search_vector = get_post_tsv(text, 'comment') WHERE post_type='comment';
+UPDATE askbot_post SET text_search_vector = get_post_tsv(text, 'answer') WHERE post_type='answer';
+UPDATE askbot_post SET text_search_vector = get_post_tsv(text, 'question') WHERE post_type='question';
+UPDATE askbot_post as q SET text_search_vector = text_search_vector ||
+ get_dependent_comments_tsv(q.id) WHERE post_type IN ('question', 'answer');
+
+--thread tsvector
+UPDATE askbot_thread SET text_search_vector = get_thread_tsv(title, tagnames);
+UPDATE askbot_thread as t SET text_search_vector = text_search_vector ||
+ get_dependent_answers_tsv(t.id) ||
+ get_thread_question_tsv(t.id);
+
+/* one trigger per table for tsv updates */
+
+/* set up update triggers */
+CREATE OR REPLACE FUNCTION thread_update_trigger() RETURNS trigger AS
+$$
+BEGIN
+ new.text_search_vector = get_thread_tsv(new.title, new.tagnames) ||
+ get_thread_question_tsv(new.id) ||
+ get_dependent_answers_tsv(new.id);
+ RETURN new;
+END;
+$$ LANGUAGE plpgsql;
+DROP TRIGGER IF EXISTS thread_search_vector_update_trigger on askbot_thread;
+CREATE TRIGGER thread_search_vector_update_trigger
+BEFORE UPDATE ON askbot_thread FOR EACH ROW EXECUTE PROCEDURE thread_update_trigger();
+
+CREATE OR REPLACE FUNCTION thread_insert_trigger() RETURNS trigger AS
+$$
+BEGIN
+ new.text_search_vector = get_thread_tsv(new.title, new.tagnames);
+ RETURN new;
+END;
+$$ LANGUAGE plpgsql;
+DROP TRIGGER IF EXISTS thread_search_vector_insert_trigger on askbot_thread;
+CREATE TRIGGER thread_search_vector_insert_trigger
+BEFORE INSERT ON askbot_thread FOR EACH ROW EXECUTE PROCEDURE thread_insert_trigger();
+
+/* post trigger */
+CREATE OR REPLACE FUNCTION post_trigger() RETURNS trigger AS
+$$
+BEGIN
+ IF new.post_type = 'question' THEN
+ new.text_search_vector = get_post_tsv(new.text, 'question') ||
+ get_dependent_comments_tsv(new.id);
+ ELSIF new.post_type = 'answer' THEN
+ new.text_search_vector = get_post_tsv(new.text, 'answer') ||
+ get_dependent_comments_tsv(new.id);
+ ELSIF new.post_type = 'comment' THEN
+ new.text_search_vector = get_post_tsv(new.text, 'comment');
+ END IF;
+ UPDATE askbot_thread SET id=new.thread_id WHERE id=new.thread_id;
+ return new;
+END;
+$$ LANGUAGE plpgsql;
+DROP TRIGGER IF EXISTS post_search_vector_update_trigger on askbot_post;
+CREATE TRIGGER post_search_vector_update_trigger
+BEFORE INSERT OR UPDATE ON askbot_post FOR EACH ROW EXECUTE PROCEDURE post_trigger();
+
+DROP INDEX IF EXISTS askbot_search_idx;
+CREATE INDEX askbot_search_idx ON askbot_thread USING gin(text_search_vector);
diff --git a/askbot/search/postgresql/user_profile_search_08312012.plsql b/askbot/search/postgresql/user_profile_search_08312012.plsql
new file mode 100644
index 00000000..90b73148
--- /dev/null
+++ b/askbot/search/postgresql/user_profile_search_08312012.plsql
@@ -0,0 +1,93 @@
+/*
+Script depends on functions defined for general askbot full text search.
+to_tsvector(), add_tsvector_column()
+
+calculates text search vector for the user profile
+the searched fields are:
+1) user name
+2) user profile
+3) group names - for groups to which user belongs
+*/
+CREATE OR REPLACE FUNCTION get_auth_user_tsv(user_id integer)
+RETURNS tsvector AS
+$$
+DECLARE
+ group_query text;
+ user_query text;
+ onerow record;
+ tsv tsvector;
+BEGIN
+ group_query =
+ 'SELECT user_group.name as group_name ' ||
+ 'FROM auth_group AS user_group ' ||
+ 'INNER JOIN auth_user_groups AS gm ' ||
+ 'ON gm.user_id= ' || user_id || ' AND gm.group_id=user_group.id';
+
+ tsv = to_tsvector('');
+ FOR onerow in EXECUTE group_query LOOP
+ tsv = tsv || to_tsvector(onerow.group_name);
+ END LOOP;
+
+ user_query = 'SELECT username, about FROM auth_user WHERE id=' || user_id;
+ FOR onerow in EXECUTE user_query LOOP
+ tsv = tsv || to_tsvector(onerow.username) || to_tsvector(onerow.about);
+ END LOOP;
+ RETURN tsv;
+END;
+$$ LANGUAGE plpgsql;
+
+/* create tsvector columns in the content tables */
+SELECT add_tsvector_column('text_search_vector', 'auth_user');
+
+/* populate tsvectors with data */
+UPDATE auth_user SET text_search_vector = get_auth_user_tsv(id);
+
+/* one trigger per table for tsv updates */
+
+/* set up auth_user triggers */
+CREATE OR REPLACE FUNCTION auth_user_tsv_update_handler()
+RETURNS trigger AS
+$$
+BEGIN
+ new.text_search_vector = get_auth_user_tsv(new.id);
+ RETURN new;
+END;
+$$ LANGUAGE plpgsql;
+DROP TRIGGER IF EXISTS auth_user_tsv_update_trigger ON auth_user;
+
+CREATE TRIGGER auth_user_tsv_update_trigger
+BEFORE INSERT OR UPDATE ON auth_user
+FOR EACH ROW EXECUTE PROCEDURE auth_user_tsv_update_handler();
+
+/* group membership trigger - reindex users when group membership
+ * changes */
+CREATE OR REPLACE FUNCTION group_membership_tsv_update_handler()
+RETURNS trigger AS
+$$
+DECLARE
+ tsv tsvector;
+ user_query text;
+BEGIN
+ user_query = 'UPDATE auth_user SET username=username WHERE ' ||
+ 'id=' || new.user_id;
+ /* just trigger the tsv update on user */
+ EXECUTE user_query;
+ RETURN new;
+END;
+$$ LANGUAGE plpgsql;
+
+DROP TRIGGER IF EXISTS group_membership_tsv_update_trigger
+ON auth_user_groups;
+
+CREATE TRIGGER group_membership_tsv_update_trigger
+AFTER INSERT OR DELETE
+ON auth_user_groups
+FOR EACH ROW EXECUTE PROCEDURE group_membership_tsv_update_handler();
+
+/* todo: whenever group name changes - also
+ * reindex users belonging to the group */
+
+DROP INDEX IF EXISTS auth_user_search_idx;
+
+CREATE INDEX auth_user_search_idx ON auth_user
+USING gin(text_search_vector);
diff --git a/askbot/search/state_manager.py b/askbot/search/state_manager.py
index f8154865..a02f1577 100644
--- a/askbot/search/state_manager.py
+++ b/askbot/search/state_manager.py
@@ -117,6 +117,10 @@ class SearchState(object):
else:
self.sort = sort
+ #patch for empty stripped query, relevance sorting is useless then
+ if self.stripped_query in (None, '') and sort == 'relevance-desc':
+ self.sort = const.DEFAULT_POST_SORT_METHOD
+
self.tags = []
if tags:
for t in tags.split(const.TAG_SEP):
diff --git a/askbot/setup_templates/settings.py b/askbot/setup_templates/settings.py
index d0a34d55..94df6f29 100644
--- a/askbot/setup_templates/settings.py
+++ b/askbot/setup_templates/settings.py
@@ -150,6 +150,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
INSTALLED_APPS = (
+ 'longerusername',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
@@ -182,6 +183,8 @@ INSTALLED_APPS = (
CACHE_BACKEND = 'locmem://'
#needed for django-keyedcache
CACHE_TIMEOUT = 6000
+#sets a special timeout for livesettings if you want to make them different
+LIVESETTINGS_CACHE_TIMEOUT = CACHE_TIMEOUT
CACHE_PREFIX = 'askbot' #make this unique
CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True
#If you use memcache you may want to uncomment the following line to enable memcached based sessions
@@ -227,7 +230,9 @@ CSRF_COOKIE_NAME = 'askbot_csrf'
#enter domain name here - e.g. example.com
#CSRF_COOKIE_DOMAIN = ''
-STATICFILES_DIRS = ( os.path.join(ASKBOT_ROOT, 'skins'),)
+STATICFILES_DIRS = (
+ ('default/media', os.path.join(ASKBOT_ROOT, 'media')),
+)
RECAPTCHA_USE_SSL = True
@@ -237,3 +242,32 @@ HAYSTACK_SITECONF = 'askbot.search.haystack'
#more information
#http://django-haystack.readthedocs.org/en/v1.2.7/settings.html
HAYSTACK_SEARCH_ENGINE = 'simple'
+
+TINYMCE_COMPRESSOR = True
+TINYMCE_SPELLCHECKER = False
+TINYMCE_JS_ROOT = os.path.join(STATIC_ROOT, 'common/media/js/tinymce/')
+TINYMCE_URL = STATIC_URL + 'common/media/js/tinymce/'
+TINYMCE_DEFAULT_CONFIG = {
+ 'plugins': 'askbot_imageuploader,askbot_attachment',
+ 'theme': 'advanced',
+ 'content_css': STATIC_URL + 'default/media/style/tinymce/content.css',
+ 'force_br_newlines': True,
+ 'force_p_newlines': False,
+ 'forced_root_block': '',
+ 'mode' : 'textareas',
+ 'oninit': "function(){ tinyMCE.activeEditor.setContent(askbot['data']['editorContent'] || ''); }",
+ 'plugins': 'askbot_imageuploader,askbot_attachment',
+ 'theme_advanced_toolbar_location' : 'top',
+ 'theme_advanced_toolbar_align': 'left',
+ 'theme_advanced_buttons1': 'bold,italic,underline,|,bullist,numlist,|,undo,redo,|,link,unlink,askbot_imageuploader,askbot_attachment',
+ 'theme_advanced_buttons2': '',
+ 'theme_advanced_buttons3' : '',
+ 'theme_advanced_path': False,
+ 'theme_advanced_resizing': True,
+ 'theme_advanced_resize_horizontal': False,
+ 'theme_advanced_statusbar_location': 'bottom',
+ 'height': '250'
+}
+
+#delayed notifications, time in seconds, 15 mins by default
+NOTIFICATION_DELAY_TIME = 60 * 15
diff --git a/askbot/setup_templates/settings.py.mustache b/askbot/setup_templates/settings.py.mustache
index 07e6aef0..74295513 100644
--- a/askbot/setup_templates/settings.py.mustache
+++ b/askbot/setup_templates/settings.py.mustache
@@ -97,7 +97,7 @@ TEMPLATE_LOADERS = (
MIDDLEWARE_CLASSES = (
#'django.middleware.gzip.GZipMiddleware',
- 'askbot.middleware.locale.LocaleMiddleware',
+ #'askbot.middleware.locale.LocaleMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
#'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware',
@@ -149,6 +149,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
INSTALLED_APPS = (
+ 'longerusername',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
@@ -182,6 +183,8 @@ INSTALLED_APPS = (
CACHE_BACKEND = 'locmem://'
#needed for django-keyedcache
CACHE_TIMEOUT = 6000
+#sets a special timeout for livesettings if you want to make them different
+LIVESETTINGS_CACHE_TIMEOUT = CACHE_TIMEOUT
CACHE_PREFIX = 'askbot' #make this unique
CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True
#If you use memcache you may want to uncomment the following line to enable memcached based sessions
@@ -229,7 +232,9 @@ CSRF_COOKIE_NAME = '{{domain_name}}_csrf'
#CSRF_COOKIE_DOMAIN = DOMAIN_NAME
STATIC_ROOT = os.path.join(PROJECT_ROOT, "static")
-STATICFILES_DIRS = (os.path.join(ASKBOT_ROOT, 'skins'),)
+STATICFILES_DIRS = (
+ ('default/media', os.path.join(ASKBOT_ROOT, 'media')),
+)
RECAPTCHA_USE_SSL = True
@@ -239,3 +244,33 @@ HAYSTACK_SITECONF = 'askbot.search.haystack'
#more information
#http://django-haystack.readthedocs.org/en/v1.2.7/settings.html
HAYSTACK_SEARCH_ENGINE = 'simple'
+
+TINYMCE_COMPRESSOR = True
+TINYMCE_SPELLCHECKER = False
+TINYMCE_JS_ROOT = os.path.join(STATIC_ROOT, 'common/media/js/tinymce/')
+TINYMCE_URL = STATIC_URL + 'common/media/js/tinymce/'
+TINYMCE_DEFAULT_CONFIG = {
+ 'plugins': 'askbot_imageuploader,askbot_attachment',
+ 'theme': 'advanced',
+ 'content_css': STATIC_URL + 'default/media/style/tinymce/content.css',
+ 'force_br_newlines': True,
+ 'force_p_newlines': False,
+ 'forced_root_block': '',
+ 'mode' : 'textareas',
+ 'oninit': "function(){ tinyMCE.activeEditor.setContent(askbot['data']['editorContent'] || ''); }",
+ 'plugins': 'askbot_imageuploader,askbot_attachment',
+ 'theme_advanced_toolbar_location' : 'top',
+ 'theme_advanced_toolbar_align': 'left',
+ 'theme_advanced_buttons1': 'bold,italic,underline,|,bullist,numlist,|,undo,redo,|,link,unlink,askbot_imageuploader,askbot_attachment',
+ 'theme_advanced_buttons2': '',
+ 'theme_advanced_buttons3' : '',
+ 'theme_advanced_path': False,
+ 'theme_advanced_resizing': True,
+ 'theme_advanced_resize_horizontal': False,
+ 'theme_advanced_statusbar_location': 'bottom',
+ 'width': '723',
+ 'height': '250'
+}
+
+#delayed notifications, time in seconds, 15 mins by default
+NOTIFICATION_DELAY_TIME = 60 * 15
diff --git a/askbot/setup_templates/tinymce_sample_config.py b/askbot/setup_templates/tinymce_sample_config.py
new file mode 100644
index 00000000..11085212
--- /dev/null
+++ b/askbot/setup_templates/tinymce_sample_config.py
@@ -0,0 +1,27 @@
+TINYMCE_COMPRESSOR = True
+TINYMCE_SPELLCHECKER = False
+TINYMCE_JS_ROOT = os.path.join(STATIC_ROOT, 'default/media/js/tinymce/')
+TINYMCE_URL = STATIC_URL + 'default/media/js/tinymce/'
+TINYMCE_DEFAULT_CONFIG = {
+ 'convert_urls': False,
+ 'plugins': 'askbot_imageuploader,askbot_attachment',
+ 'theme': 'advanced',
+ 'content_css': STATIC_URL + 'default/media/style/tinymce/content.css',
+ 'force_br_newlines': True,
+ 'force_p_newlines': False,
+ 'forced_root_block': '',
+ 'mode' : 'textareas',
+ 'oninit': "function(){ tinyMCE.activeEditor.setContent(askbot['data']['editorContent'] || ''); }",
+ 'plugins': 'askbot_imageuploader,askbot_attachment',
+ 'theme_advanced_toolbar_location' : 'top',
+ 'theme_advanced_toolbar_align': 'left',
+ 'theme_advanced_buttons1': 'bold,italic,underline,|,bullist,numlist,|,undo,redo,|,link,unlink,askbot_imageuploader,askbot_attachment',
+ 'theme_advanced_buttons2': '',
+ 'theme_advanced_buttons3' : '',
+ 'theme_advanced_path': False,
+ 'theme_advanced_resizing': True,
+ 'theme_advanced_resize_horizontal': False,
+ 'theme_advanced_statusbar_location': 'bottom',
+ 'width': '723',
+ 'height': '250'
+}
diff --git a/askbot/skins/README b/askbot/skins/README
index 3fbc8c33..354de985 100644
--- a/askbot/skins/README
+++ b/askbot/skins/README
@@ -17,7 +17,7 @@ How skins work in Askbot
The skins reside in up to two directories:
-* `askbot/skins` in the source code (contains any stock skins)
+* `askbot` in the source within `templates` and `media` subdirectories
* directory pointed to by a ASKBOT_EXTRA_SKINS_DIR in your settings.py
with any other skins
@@ -27,7 +27,7 @@ absent in other skins. In a way - all other skins inherit from the "default".
Templates and media are resolved in the following way:
* check in skin named as in settings.ASKBOT_DEFAULT_SKIN
-* then skin named 'default'
+* then skin named 'default' - distributed within `askbot` source directory
How to customize a skin
=======================
diff --git a/askbot/skins/common/media/images/close-small-dark.png b/askbot/skins/common/media/images/close-small-dark.png
deleted file mode 100755
index 280c1fc7..00000000
--- a/askbot/skins/common/media/images/close-small-dark.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/common/media/images/logo.gif b/askbot/skins/common/media/images/logo.gif
deleted file mode 100644
index ac4ceda6..00000000
--- a/askbot/skins/common/media/images/logo.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/common/media/images/sprites.png b/askbot/skins/common/media/images/sprites.png
deleted file mode 100644
index e7244673..00000000
--- a/askbot/skins/common/media/images/sprites.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/common/media/images/summary-background.png b/askbot/skins/common/media/images/summary-background.png
deleted file mode 100644
index 58c3855a..00000000
--- a/askbot/skins/common/media/images/summary-background.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/common/media/images/tag-left.png b/askbot/skins/common/media/images/tag-left.png
deleted file mode 100644
index 5a9d8a0d..00000000
--- a/askbot/skins/common/media/images/tag-left.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/common/media/images/tag-right.png b/askbot/skins/common/media/images/tag-right.png
deleted file mode 100644
index 871664c3..00000000
--- a/askbot/skins/common/media/images/tag-right.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/common/media/js/autocompleter.js b/askbot/skins/common/media/js/autocompleter.js
deleted file mode 100644
index a7c54315..00000000
--- a/askbot/skins/common/media/js/autocompleter.js
+++ /dev/null
@@ -1,766 +0,0 @@
-/**
- * AutoCompleter Object, refactored closure style from
- * jQuery autocomplete plugin
- * @param {Object=} options Settings
- * @constructor
- */
-var AutoCompleter = function(options) {
-
- /**
- * Default options for autocomplete plugin
- */
- var defaults = {
- autocompleteMultiple: true,
- multipleSeparator: ' ',//a single character
- inputClass: 'acInput',
- loadingClass: 'acLoading',
- resultsClass: 'acResults',
- selectClass: 'acSelect',
- queryParamName: 'q',
- limitParamName: 'limit',
- extraParams: {},
- lineSeparator: '\n',
- cellSeparator: '|',
- minChars: 2,
- maxItemsToShow: 10,
- delay: 400,
- useCache: true,
- maxCacheLength: 10,
- matchSubset: true,
- matchCase: false,
- matchInside: true,
- mustMatch: false,
- preloadData: false,
- selectFirst: false,
- stopCharRegex: /\s+/,
- selectOnly: false,
- formatItem: null, // TBD
- onItemSelect: false,
- autoFill: false,
- filterResults: true,
- sortResults: true,
- sortFunction: false,
- onNoMatch: false
- };
-
- /**
- * Options dictionary
- * @type Object
- * @private
- */
- this.options = $.extend({}, defaults, options);
-
- /**
- * Cached data
- * @type Object
- * @private
- */
- this.cacheData_ = {};
-
- /**
- * Number of cached data items
- * @type number
- * @private
- */
- this.cacheLength_ = 0;
-
- /**
- * Class name to mark selected item
- * @type string
- * @private
- */
- this.selectClass_ = 'jquery-autocomplete-selected-item';
-
- /**
- * Handler to activation timeout
- * @type ?number
- * @private
- */
- this.keyTimeout_ = null;
-
- /**
- * Last key pressed in the input field (store for behavior)
- * @type ?number
- * @private
- */
- this.lastKeyPressed_ = null;
-
- /**
- * Last value processed by the autocompleter
- * @type ?string
- * @private
- */
- this.lastProcessedValue_ = null;
-
- /**
- * Last value selected by the user
- * @type ?string
- * @private
- */
- this.lastSelectedValue_ = null;
-
- /**
- * Is this autocompleter active?
- * @type boolean
- * @private
- */
- this.active_ = false;
-
- /**
- * Is it OK to finish on blur?
- * @type boolean
- * @private
- */
- this.finishOnBlur_ = true;
-
- this.options.minChars = parseInt(this.options.minChars, 10);
- if (isNaN(this.options.minChars) || this.options.minChars < 1) {
- this.options.minChars = 2;
- }
-
- this.options.maxItemsToShow = parseInt(this.options.maxItemsToShow, 10);
- if (isNaN(this.options.maxItemsToShow) || this.options.maxItemsToShow < 1) {
- this.options.maxItemsToShow = 10;
- }
-
- this.options.maxCacheLength = parseInt(this.options.maxCacheLength, 10);
- if (isNaN(this.options.maxCacheLength) || this.options.maxCacheLength < 1) {
- this.options.maxCacheLength = 10;
- }
-
- if (this.options['preloadData'] === true){
- this.fetchRemoteData('', function(){});
- }
-};
-inherits(AutoCompleter, WrappedElement);
-
-AutoCompleter.prototype.decorate = function(element){
-
- /**
- * Init DOM elements repository
- */
- this._element = element;
-
- /**
- * Switch off the native autocomplete
- */
- this._element.attr('autocomplete', 'off');
-
- /**
- * Create DOM element to hold results
- */
- this._results = $('<div></div>').hide();
- if (this.options.resultsClass) {
- this._results.addClass(this.options.resultsClass);
- }
- this._results.css({
- position: 'absolute'
- });
- $('body').append(this._results);
-
- this.setEventHandlers();
-};
-
-AutoCompleter.prototype.setEventHandlers = function(){
- /**
- * Shortcut to self
- */
- var self = this;
-
- /**
- * Attach keyboard monitoring to $elem
- */
- self._element.keydown(function(e) {
- self.lastKeyPressed_ = e.keyCode;
- switch(self.lastKeyPressed_) {
-
- case 38: // up
- e.preventDefault();
- if (self.active_) {
- self.focusPrev();
- } else {
- self.activate();
- }
- return false;
- break;
-
- case 40: // down
- e.preventDefault();
- if (self.active_) {
- self.focusNext();
- } else {
- self.activate();
- }
- return false;
- break;
-
- case 9: // tab
- case 13: // return
- if (self.active_) {
- e.preventDefault();
- self.selectCurrent();
- return false;
- }
- break;
-
- case 27: // escape
- if (self.active_) {
- e.preventDefault();
- self.finish();
- return false;
- }
- break;
-
- default:
- self.activate();
-
- }
- });
- self._element.blur(function() {
- if (self.finishOnBlur_) {
- setTimeout(function() { self.finish(); }, 200);
- }
- });
-};
-
-AutoCompleter.prototype.position = function() {
- var offset = this._element.offset();
- this._results.css({
- top: offset.top + this._element.outerHeight(),
- left: offset.left
- });
-};
-
-AutoCompleter.prototype.cacheRead = function(filter) {
- var filterLength, searchLength, search, maxPos, pos;
- if (this.options.useCache) {
- filter = String(filter);
- filterLength = filter.length;
- if (this.options.matchSubset) {
- searchLength = 1;
- } else {
- searchLength = filterLength;
- }
- while (searchLength <= filterLength) {
- if (this.options.matchInside) {
- maxPos = filterLength - searchLength;
- } else {
- maxPos = 0;
- }
- pos = 0;
- while (pos <= maxPos) {
- search = filter.substr(0, searchLength);
- if (this.cacheData_[search] !== undefined) {
- return this.cacheData_[search];
- }
- pos++;
- }
- searchLength++;
- }
- }
- return false;
-};
-
-AutoCompleter.prototype.cacheWrite = function(filter, data) {
- if (this.options.useCache) {
- if (this.cacheLength_ >= this.options.maxCacheLength) {
- this.cacheFlush();
- }
- filter = String(filter);
- if (this.cacheData_[filter] !== undefined) {
- this.cacheLength_++;
- }
- return this.cacheData_[filter] = data;
- }
- return false;
-};
-
-AutoCompleter.prototype.cacheFlush = function() {
- this.cacheData_ = {};
- this.cacheLength_ = 0;
-};
-
-AutoCompleter.prototype.callHook = function(hook, data) {
- var f = this.options[hook];
- if (f && $.isFunction(f)) {
- return f(data, this);
- }
- return false;
-};
-
-AutoCompleter.prototype.activate = function() {
- var self = this;
- var activateNow = function() {
- self.activateNow();
- };
- var delay = parseInt(this.options.delay, 10);
- if (isNaN(delay) || delay <= 0) {
- delay = 250;
- }
- if (this.keyTimeout_) {
- clearTimeout(this.keyTimeout_);
- }
- this.keyTimeout_ = setTimeout(activateNow, delay);
-};
-
-AutoCompleter.prototype.activateNow = function() {
- var value = this.getValue();
- if (value !== this.lastProcessedValue_ && value !== this.lastSelectedValue_) {
- if (value.length >= this.options.minChars) {
- this.active_ = true;
- this.lastProcessedValue_ = value;
- this.fetchData(value);
- }
- }
-};
-
-AutoCompleter.prototype.fetchData = function(value) {
- if (this.options.data) {
- this.filterAndShowResults(this.options.data, value);
- } else {
- var self = this;
- this.fetchRemoteData(value, function(remoteData) {
- self.filterAndShowResults(remoteData, value);
- });
- }
-};
-
-AutoCompleter.prototype.fetchRemoteData = function(filter, callback) {
- var data = this.cacheRead(filter);
- if (data) {
- callback(data);
- } else {
- var self = this;
- if (this._element){
- this._element.addClass(this.options.loadingClass);
- }
- var ajaxCallback = function(data) {
- var parsed = false;
- if (data !== false) {
- parsed = self.parseRemoteData(data);
- self.options.data = parsed;//cache data forever - E.F.
- self.cacheWrite(filter, parsed);
- }
- if (self._element){
- self._element.removeClass(self.options.loadingClass);
- }
- callback(parsed);
- };
- $.ajax({
- url: this.makeUrl(filter),
- success: ajaxCallback,
- error: function() {
- ajaxCallback(false);
- }
- });
- }
-};
-
-AutoCompleter.prototype.setOption = function(name, value){
- this.options[name] = value;
-};
-
-AutoCompleter.prototype.setExtraParam = function(name, value) {
- var index = $.trim(String(name));
- if (index) {
- if (!this.options.extraParams) {
- this.options.extraParams = {};
- }
- if (this.options.extraParams[index] !== value) {
- this.options.extraParams[index] = value;
- this.cacheFlush();
- }
- }
-};
-
-AutoCompleter.prototype.makeUrl = function(param) {
- var self = this;
- var url = this.options.url;
- var params = $.extend({}, this.options.extraParams);
- // If options.queryParamName === false, append query to url
- // instead of using a GET parameter
- if (this.options.queryParamName === false) {
- url += encodeURIComponent(param);
- } else {
- params[this.options.queryParamName] = param;
- }
-
- if (this.options.limitParamName && this.options.maxItemsToShow) {
- params[this.options.limitParamName] = this.options.maxItemsToShow;
- }
-
- var urlAppend = [];
- $.each(params, function(index, value) {
- urlAppend.push(self.makeUrlParam(index, value));
- });
- if (urlAppend.length) {
- url += url.indexOf('?') == -1 ? '?' : '&';
- url += urlAppend.join('&');
- }
- return url;
-};
-
-AutoCompleter.prototype.makeUrlParam = function(name, value) {
- return String(name) + '=' + encodeURIComponent(value);
-};
-
-/**
- * Sanitize CR and LF, then split into lines
- */
-AutoCompleter.prototype.splitText = function(text) {
- return String(text).replace(/(\r\n|\r|\n)/g, '\n').split(this.options.lineSeparator);
-};
-
-AutoCompleter.prototype.parseRemoteData = function(remoteData) {
- var value, lines, i, j, data;
- var results = [];
- var lines = this.splitText(remoteData);
- for (i = 0; i < lines.length; i++) {
- var line = lines[i].split(this.options.cellSeparator);
- data = [];
- for (j = 0; j < line.length; j++) {
- data.push(unescape(line[j]));
- }
- value = data.shift();
- results.push({ value: unescape(value), data: data });
- }
- return results;
-};
-
-AutoCompleter.prototype.filterAndShowResults = function(results, filter) {
- this.showResults(this.filterResults(results, filter), filter);
-};
-
-AutoCompleter.prototype.filterResults = function(results, filter) {
-
- var filtered = [];
- var value, data, i, result, type, include;
- var regex, pattern, testValue;
-
- for (i = 0; i < results.length; i++) {
- result = results[i];
- type = typeof result;
- if (type === 'string') {
- value = result;
- data = {};
- } else if ($.isArray(result)) {
- value = result[0];
- data = result.slice(1);
- } else if (type === 'object') {
- value = result.value;
- data = result.data;
- }
- value = String(value);
- if (value > '') {
- if (typeof data !== 'object') {
- data = {};
- }
- if (this.options.filterResults) {
- pattern = String(filter);
- testValue = String(value);
- if (!this.options.matchCase) {
- pattern = pattern.toLowerCase();
- testValue = testValue.toLowerCase();
- }
- include = testValue.indexOf(pattern);
- if (this.options.matchInside) {
- include = include > -1;
- } else {
- include = include === 0;
- }
- } else {
- include = true;
- }
- if (include) {
- filtered.push({ value: value, data: data });
- }
- }
- }
-
- if (this.options.sortResults) {
- filtered = this.sortResults(filtered, filter);
- }
-
- if (this.options.maxItemsToShow > 0 && this.options.maxItemsToShow < filtered.length) {
- filtered.length = this.options.maxItemsToShow;
- }
-
- return filtered;
-
-};
-
-AutoCompleter.prototype.sortResults = function(results, filter) {
- var self = this;
- var sortFunction = this.options.sortFunction;
- if (!$.isFunction(sortFunction)) {
- sortFunction = function(a, b, f) {
- return self.sortValueAlpha(a, b, f);
- };
- }
- results.sort(function(a, b) {
- return sortFunction(a, b, filter);
- });
- return results;
-};
-
-AutoCompleter.prototype.sortValueAlpha = function(a, b, filter) {
- a = String(a.value);
- b = String(b.value);
- if (!this.options.matchCase) {
- a = a.toLowerCase();
- b = b.toLowerCase();
- }
- if (a > b) {
- return 1;
- }
- if (a < b) {
- return -1;
- }
- return 0;
-};
-
-AutoCompleter.prototype.showResults = function(results, filter) {
- var self = this;
- var $ul = $('<ul></ul>');
- var i, result, $li, extraWidth, first = false, $first = false;
- var numResults = results.length;
- for (i = 0; i < numResults; i++) {
- result = results[i];
- $li = $('<li>' + this.showResult(result.value, result.data) + '</li>');
- $li.data('value', result.value);
- $li.data('data', result.data);
- $li.click(function() {
- var $this = $(this);
- self.selectItem($this);
- }).mousedown(function() {
- self.finishOnBlur_ = false;
- }).mouseup(function() {
- self.finishOnBlur_ = true;
- });
- $ul.append($li);
- if (first === false) {
- first = String(result.value);
- $first = $li;
- $li.addClass(this.options.firstItemClass);
- }
- if (i == numResults - 1) {
- $li.addClass(this.options.lastItemClass);
- }
- }
-
- // Alway recalculate position before showing since window size or
- // input element location may have changed. This fixes #14
- this.position();
-
- this._results.html($ul).show();
- extraWidth = this._results.outerWidth() - this._results.width();
- this._results.width(this._element.outerWidth() - extraWidth);
- $('li', this._results).hover(
- function() { self.focusItem(this); },
- function() { /* void */ }
- );
- if (this.autoFill(first, filter)) {
- this.focusItem($first);
- }
-};
-
-AutoCompleter.prototype.showResult = function(value, data) {
- if ($.isFunction(this.options.showResult)) {
- return this.options.showResult(value, data);
- } else {
- return value;
- }
-};
-
-AutoCompleter.prototype.autoFill = function(value, filter) {
- var lcValue, lcFilter, valueLength, filterLength;
- if (this.options.autoFill && this.lastKeyPressed_ != 8) {
- lcValue = String(value).toLowerCase();
- lcFilter = String(filter).toLowerCase();
- valueLength = value.length;
- filterLength = filter.length;
- if (lcValue.substr(0, filterLength) === lcFilter) {
- this._element.val(value);
- this.selectRange(filterLength, valueLength);
- return true;
- }
- }
- return false;
-};
-
-AutoCompleter.prototype.focusNext = function() {
- this.focusMove(+1);
-};
-
-AutoCompleter.prototype.focusPrev = function() {
- this.focusMove(-1);
-};
-
-AutoCompleter.prototype.focusMove = function(modifier) {
- var i, $items = $('li', this._results);
- modifier = parseInt(modifier, 10);
- for (var i = 0; i < $items.length; i++) {
- if ($($items[i]).hasClass(this.selectClass_)) {
- this.focusItem(i + modifier);
- return;
- }
- }
- this.focusItem(0);
-};
-
-AutoCompleter.prototype.focusItem = function(item) {
- var $item, $items = $('li', this._results);
- if ($items.length) {
- $items.removeClass(this.selectClass_).removeClass(this.options.selectClass);
- if (typeof item === 'number') {
- item = parseInt(item, 10);
- if (item < 0) {
- item = 0;
- } else if (item >= $items.length) {
- item = $items.length - 1;
- }
- $item = $($items[item]);
- } else {
- $item = $(item);
- }
- if ($item) {
- $item.addClass(this.selectClass_).addClass(this.options.selectClass);
- }
- }
-};
-
-AutoCompleter.prototype.selectCurrent = function() {
- var $item = $('li.' + this.selectClass_, this._results);
- if ($item.length == 1) {
- this.selectItem($item);
- } else {
- this.finish();
- }
-};
-
-AutoCompleter.prototype.selectItem = function($li) {
- var value = $li.data('value');
- var data = $li.data('data');
- var displayValue = this.displayValue(value, data);
- this.lastProcessedValue_ = displayValue;
- this.lastSelectedValue_ = displayValue;
-
- this.setValue(displayValue);
-
- this.setCaret(displayValue.length);
- this.callHook('onItemSelect', { value: value, data: data });
- this.finish();
-};
-
-/**
- * @return {boolean} true if the symbol matches something that is
- * considered content and false otherwise
- * @param {string} symbol - a single char string
- */
-AutoCompleter.prototype.isContentChar = function(symbol){
- if (symbol.match(this.options['stopCharRegex'])){
- return false;
- } else if (symbol === this.options['multipleSeparator']){
- return false;
- } else {
- return true;
- }
-};
-
-/**
- * takes value from the input box
- * and saves _selection_start and _selection_end coordinates
- * respects settings autocompleteMultiple and
- * multipleSeparator
- * @return {string} the current word in the
- * autocompletable word
- */
-AutoCompleter.prototype.getValue = function(){
- var sel = this._element.getSelection();
- var text = this._element.val();
- var pos = sel.start;//estimated start
- //find real start
- var start = pos;
- for (cpos = pos; cpos >= 0; cpos = cpos - 1){
- if (cpos === text.length){
- continue;
- }
- var symbol = text.charAt(cpos);
- if (!this.isContentChar(symbol)){
- break;
- }
- start = cpos;
- }
- //find real end
- var end = pos;
- for (cpos = pos; cpos < text.length; cpos = cpos + 1){
- if (cpos === 0){
- continue;
- }
- var symbol = text.charAt(cpos);
- if (!this.isContentChar(symbol)){
- break;
- }
- end = cpos;
- }
- this._selection_start = start;
- this._selection_end = end;
- return text.substring(start, end);
-}
-
-/**
- * sets value of the input box
- * by replacing the previous selection
- * with the value from the autocompleter
- */
-AutoCompleter.prototype.setValue = function(val){
- var prefix = this._element.val().substring(0, this._selection_start);
- var postfix = this._element.val().substring(this._selection_end + 1);
- this._element.val(prefix + val + postfix);
-};
-
-AutoCompleter.prototype.displayValue = function(value, data) {
- if ($.isFunction(this.options.displayValue)) {
- return this.options.displayValue(value, data);
- } else {
- return value;
- }
-};
-
-AutoCompleter.prototype.finish = function() {
- if (this.keyTimeout_) {
- clearTimeout(this.keyTimeout_);
- }
- if (this._element.val() !== this.lastSelectedValue_) {
- if (this.options.mustMatch) {
- this._element.val('');
- }
- this.callHook('onNoMatch');
- }
- this._results.hide();
- this.lastKeyPressed_ = null;
- this.lastProcessedValue_ = null;
- if (this.active_) {
- this.callHook('onFinish');
- }
- this.active_ = false;
-};
-
-AutoCompleter.prototype.selectRange = function(start, end) {
- var input = this._element.get(0);
- if (input.setSelectionRange) {
- input.focus();
- input.setSelectionRange(start, end);
- } else if (this.createTextRange) {
- var range = this.createTextRange();
- range.collapse(true);
- range.moveEnd('character', end);
- range.moveStart('character', start);
- range.select();
- }
-};
-
-AutoCompleter.prototype.setCaret = function(pos) {
- this.selectRange(pos, pos);
-};
-
diff --git a/askbot/skins/common/media/js/editor.js b/askbot/skins/common/media/js/editor.js
deleted file mode 100644
index ae4f5aea..00000000
--- a/askbot/skins/common/media/js/editor.js
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- jQuery TextAreaResizer plugin
- Created on 17th January 2008 by Ryan O'Dell
- Version 1.0.4
-*/(function($){var textarea,staticOffset;var iLastMousePos=0;var iMin=32;var grip;$.fn.TextAreaResizer=function(){return this.each(function(){textarea=$(this).addClass('processed'),staticOffset=null;$(this).wrap('<div class="resizable-textarea"><span></span></div>').parent().append($('<div class="grippie"></div>').bind("mousedown",{el:this},startDrag));var grippie=$('div.grippie',$(this).parent())[0];grippie.style.marginRight=(grippie.offsetWidth-$(this)[0].offsetWidth)+'px'})};function startDrag(e){textarea=$(e.data.el);textarea.blur();iLastMousePos=mousePosition(e).y;staticOffset=textarea.height()-iLastMousePos;textarea.css('opacity',0.25);$(document).mousemove(performDrag).mouseup(endDrag);return false}function performDrag(e){var iThisMousePos=mousePosition(e).y;var iMousePos=staticOffset+iThisMousePos;if(iLastMousePos>=(iThisMousePos)){iMousePos-=5}iLastMousePos=iThisMousePos;iMousePos=Math.max(iMin,iMousePos);textarea.height(iMousePos+'px');if(iMousePos<iMin){endDrag(e)}return false}function endDrag(e){$(document).unbind('mousemove',performDrag).unbind('mouseup',endDrag);textarea.css('opacity',1);textarea.focus();textarea=null;staticOffset=null;iLastMousePos=0}function mousePosition(e){return{x:e.clientX+document.documentElement.scrollLeft,y:e.clientY+document.documentElement.scrollTop}}})(jQuery);
-/*
- * TypeWatch 2.0 - Original by Denny Ferrassoli / Refactored by Charles Christolini
- * Copyright(c) 2007 Denny Ferrassoli - DennyDotNet.com
- * Coprright(c) 2008 Charles Christolini - BinaryPie.com
- * Dual licensed under the MIT and GPL licenses:
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
-*/(function(jQuery){jQuery.fn.typeWatch=function(o){var options=jQuery.extend({wait:750,callback:function(){},highlight:true,captureLength:2},o);function checkElement(timer,override){var elTxt=jQuery(timer.el).val();if((elTxt.length>options.captureLength&&elTxt.toUpperCase()!=timer.text)||(override&&elTxt.length>options.captureLength)){timer.text=elTxt.toUpperCase();timer.cb(elTxt)}};function watchElement(elem){if(elem.type.toUpperCase()=="TEXT"||elem.nodeName.toUpperCase()=="TEXTAREA"){var timer={timer:null,text:jQuery(elem).val().toUpperCase(),cb:options.callback,el:elem,wait:options.wait};if(options.highlight){jQuery(elem).focus(function(){this.select()})}var startWatch=function(evt){var timerWait=timer.wait;var overrideBool=false;if(evt.keyCode==13&&this.type.toUpperCase()=="TEXT"){timerWait=1;overrideBool=true}var timerCallbackFx=function(){checkElement(timer,overrideBool)};clearTimeout(timer.timer);timer.timer=setTimeout(timerCallbackFx,timerWait)};jQuery(elem).keydown(startWatch)}};return this.each(function(index){watchElement(this)})}})(jQuery);
-/*
-Ajax upload
-*/jQuery.extend({createUploadIframe:function(d,b){var a="jUploadFrame"+d;if(window.ActiveXObject){var c=document.createElement('<iframe id="'+a+'" name="'+a+'" />');if(typeof b=="boolean"){c.src="javascript:false"}else{if(typeof b=="string"){c.src=b}}}else{var c=document.createElement("iframe");c.id=a;c.name=a}c.style.position="absolute";c.style.top="-1000px";c.style.left="-1000px";document.body.appendChild(c);return c},createUploadForm:function(g,b){var e="jUploadForm"+g;var a="jUploadFile"+g;var d=$('<form action="" method="POST" name="'+e+'" id="'+e+'" enctype="multipart/form-data"></form>');var c=$("#"+b);var f=$(c).clone();$(c).attr("id",a);$(c).before(f);$(c).appendTo(d);$(d).css("position","absolute");$(d).css("top","-1200px");$(d).css("left","-1200px");$(d).appendTo("body");return d},ajaxFileUpload:function(k){k=jQuery.extend({},jQuery.ajaxSettings,k);var a=new Date().getTime();var b=jQuery.createUploadForm(a,k.fileElementId);var i=jQuery.createUploadIframe(a,k.secureuri);var h="jUploadFrame"+a;var j="jUploadForm"+a;if(k.global&&!jQuery.active++){jQuery.event.trigger("ajaxStart")}var c=false;var f={};if(k.global){jQuery.event.trigger("ajaxSend",[f,k])}var d=function(l){var p=document.getElementById(h);try{if(p.contentWindow){f.responseText=p.contentWindow.document.body?p.contentWindow.document.body.innerText:null;f.responseXML=p.contentWindow.document.XMLDocument?p.contentWindow.document.XMLDocument:p.contentWindow.document}else{if(p.contentDocument){f.responseText=p.contentDocument.document.body?p.contentDocument.document.body.textContent||document.body.innerText:null;f.responseXML=p.contentDocument.document.XMLDocument?p.contentDocument.document.XMLDocument:p.contentDocument.document}}}catch(o){jQuery.handleError(k,f,null,o)}if(f||l=="timeout"){c=true;var m;try{m=l!="timeout"?"success":"error";if(m!="error"){var n=jQuery.uploadHttpData(f,k.dataType);if(k.success){k.success(n,m)}if(k.global){jQuery.event.trigger("ajaxSuccess",[f,k])}}else{jQuery.handleError(k,f,m)}}catch(o){m="error";jQuery.handleError(k,f,m,o)}if(k.global){jQuery.event.trigger("ajaxComplete",[f,k])}if(k.global&&!--jQuery.active){jQuery.event.trigger("ajaxStop")}if(k.complete){k.complete(f,m)}jQuery(p).unbind();setTimeout(function(){try{$(p).remove();$(b).remove()}catch(q){jQuery.handleError(k,f,null,q)}},100);f=null}};if(k.timeout>0){setTimeout(function(){if(!c){d("timeout")}},k.timeout)}try{var b=$("#"+j);$(b).attr("action",k.url);$(b).attr("method","POST");$(b).attr("target",h);if(b.encoding){b.encoding="multipart/form-data"}else{b.enctype="multipart/form-data"}$(b).submit()}catch(g){jQuery.handleError(k,f,null,g)}if(window.attachEvent){document.getElementById(h).attachEvent("onload",d)}else{document.getElementById(h).addEventListener("load",d,false)}return{abort:function(){}}},uploadHttpData:function(r,type){var data=!type;data=type=="xml"||data?r.responseXML:r.responseText;if(type=="script"){jQuery.globalEval(data)}if(type=="json"){eval("data = "+data)}if(type=="html"){jQuery("<div>").html(data).evalScripts()}return data}});
-/**
- * Upload call. Used only once in the wmd file upload
- * this is "tightly coupled" with the wmd file uploader
- * @param {Object} jquery object imageUrl - where the
- * uploaded url must be inserted on successful upload
- * @param {Function} handler that is run upon change
- * of the file upload field
- */
-function ajaxFileUpload(imageUrl, startUploadHandler)
-{
- $("#loading").ajaxStart(function(){
- $(this).show();
- }).ajaxComplete(function(){
- $(this).hide();
- });
-
- $("#upload").ajaxStart(function(){
- $(this).hide();
- }).ajaxComplete(function(){
- $(this).show();
- });
-
- $.ajaxFileUpload
- (
- {
- url: askbot['urls']['upload'],
- secureuri:false,
- fileElementId:'file-upload',
- dataType: 'xml',
- success: function (data, status)
- {
- var fileURL = $(data).find('file_url').text();
- /*
- * hopefully a fix for the "fakepath" issue
- * https://www.mediawiki.org/wiki/Special:Code/MediaWiki/83225
- */
- fileURL = fileURL.replace(/\w:.*\\(.*)$/,'$1');
- var error = $(data).find('error').text();
- if(error != ''){
- alert(error);
- if (startUploadHandler){
- /* re-install this as the upload extension
- * will remove the handler to prevent double uploading */
- $('#file-upload').change(startUploadHandler);
- }
- }else{
- imageUrl.attr('value', fileURL);
- }
-
- },
- error: function (data, status, e)
- {
- alert(e);
- if (startUploadHandler){
- /* re-install this as the upload extension
- * will remove the handler to prevent double uploading */
- $('#file-upload').change(startUploadHandler);
- }
- }
- }
- )
-
- return false;
-};
diff --git a/askbot/skins/common/media/js/jquery.ajaxfileupload.js b/askbot/skins/common/media/js/jquery.ajaxfileupload.js
deleted file mode 100644
index 75292776..00000000
--- a/askbot/skins/common/media/js/jquery.ajaxfileupload.js
+++ /dev/null
@@ -1,195 +0,0 @@
-jQuery.extend({
- createUploadIframe: function(id, uri){
- //create frame
- var frameId = 'jUploadFrame' + id;
- if(window.ActiveXObject) {
- var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
- if(typeof uri== 'boolean'){
- io.src = 'javascript:false';
- }
- else if(typeof uri== 'string'){
- io.src = uri;
- }
- }
- else {
- var io = document.createElement('iframe');
- io.id = frameId;
- io.name = frameId;
- }
- io.style.position = 'absolute';
- io.style.top = '-1000px';
- io.style.left = '-1000px';
-
- document.body.appendChild(io);
- return io;
- },
- createUploadForm: function(id, fileElementId)
- {
- //create form
- var formId = 'jUploadForm' + id;
- var fileId = 'jUploadFile' + id;
- var form = $('<form action="" method="POST" name="' + formId + '" id="' + formId
- + '" enctype="multipart/form-data"></form>');
- var oldElement = $('#' + fileElementId);
- var newElement = $(oldElement).clone();
- $(oldElement).attr('id', fileId);
- $(oldElement).before(newElement);
- $(oldElement).appendTo(form);
- //set attributes
- $(form).css('position', 'absolute');
- $(form).css('top', '-1200px');
- $(form).css('left', '-1200px');
- $(form).appendTo('body');
- return form;
- },
-
- ajaxFileUpload: function(s) {
- // TODO introduce global settings, allowing the client to modify them for all requests, not only timeout
- s = jQuery.extend({}, jQuery.ajaxSettings, s);
- var id = new Date().getTime()
- var form = jQuery.createUploadForm(id, s.fileElementId);
- var io = jQuery.createUploadIframe(id, s.secureuri);
- var frameId = 'jUploadFrame' + id;
- var formId = 'jUploadForm' + id;
- // Watch for a new set of requests
- if ( s.global && ! jQuery.active++ )
- {
- jQuery.event.trigger( "ajaxStart" );
- }
- var requestDone = false;
- // Create the request object
- var xml = {}
- if ( s.global )
- jQuery.event.trigger("ajaxSend", [xml, s]);
- // Wait for a response to come back
- var uploadCallback = function(isTimeout)
- {
- var io = document.getElementById(frameId);
- try {
- if(io.contentWindow){
- xml.responseText = io.contentWindow.document.body ?
- io.contentWindow.document.body.innerText : null;
- xml.responseXML = io.contentWindow.document.XMLDocument ?
- io.contentWindow.document.XMLDocument : io.contentWindow.document;
-
- }
- else if(io.contentDocument)
- {
- xml.responseText = io.contentDocument.document.body ?
- io.contentDocument.document.body.textContent || document.body.innerText : null;
- xml.responseXML = io.contentDocument.document.XMLDocument ?
- io.contentDocument.document.XMLDocument : io.contentDocument.document;
- }
- }
- catch(e)
- {
- jQuery.handleError(s, xml, null, e);
- }
- if ( xml || isTimeout == "timeout")
- {
- requestDone = true;
- var status;
- try {
- status = isTimeout != "timeout" ? "success" : "error";
- // Make sure that the request was successful or notmodified
- if ( status != "error" )
- {
- // process the data (runs the xml through httpData regardless of callback)
- var data = jQuery.uploadHttpData( xml, s.dataType );
- // If a local callback was specified, fire it and pass it the data
- if ( s.success )
- s.success( data, status );
-
- // Fire the global callback
- if( s.global )
- jQuery.event.trigger( "ajaxSuccess", [xml, s] );
- } else
- jQuery.handleError(s, xml, status);
- } catch(e)
- {
- status = "error";
- jQuery.handleError(s, xml, status, e);
- }
-
- // The request was completed
- if( s.global )
- jQuery.event.trigger( "ajaxComplete", [xml, s] );
-
- // Handle the global AJAX counter
- if ( s.global && ! --jQuery.active )
- jQuery.event.trigger( "ajaxStop" );
-
- // Process result
- if ( s.complete )
- s.complete(xml, status);
-
- jQuery(io).unbind();
-
- setTimeout(function()
- { try
- {
- $(io).remove();
- $(form).remove();
-
- } catch(e) {
- jQuery.handleError(s, xml, null, e);
- }
- }, 100)
- xml = null;
- }
- }
- // Timeout checker
- if ( s.timeout > 0 ) {
- setTimeout(function(){
- // Check to see if the request is still happening
- if( !requestDone ) uploadCallback( "timeout" );
- }, s.timeout);
- }
- try
- {
- // var io = $('#' + frameId);
- var form = $('#' + formId);
- $(form).attr('action', s.url);
- $(form).attr('method', 'POST');
- $(form).attr('target', frameId);
- if(form.encoding)
- {
- form.encoding = 'multipart/form-data';
- }
- else
- {
- form.enctype = 'multipart/form-data';
- }
- $(form).submit();
-
- } catch(e)
- {
- jQuery.handleError(s, xml, null, e);
- }
- if(window.attachEvent){
- document.getElementById(frameId).attachEvent('onload', uploadCallback);
- }
- else{
- document.getElementById(frameId).addEventListener('load', uploadCallback, false);
- }
- return {abort: function () {}};
-
- },
-
- uploadHttpData: function( r, type ) {
- var data = !type;
- data = type == "xml" || data ? r.responseXML : r.responseText;
- // If the type is "script", eval it in global context
- if ( type == "script" )
- jQuery.globalEval( data );
- // Get the JavaScript object, if JSON is used.
- if ( type == "json" )
- eval( "data = " + data );
- // evaluate scripts within html
- if ( type == "html" )
- jQuery("<div>").html(data).evalScripts();
- //alert($('param', data).each(function(){alert($(this).attr('value'));}));
- return data;
- }
-})
-
diff --git a/askbot/skins/common/media/js/live_search_new_thread.js b/askbot/skins/common/media/js/live_search_new_thread.js
deleted file mode 100644
index 53c820fa..00000000
--- a/askbot/skins/common/media/js/live_search_new_thread.js
+++ /dev/null
@@ -1,82 +0,0 @@
-
-var liveSearchNewThreadInit = function() {
- var query = $('input#id_title.questionTitleInput');
- var prev_text = $.trim(query.val());
- var search_url = askbot['urls']['api_get_questions'];
- var running = false;
- var q_list_sel = 'question-list'; //id of question listing div
-
- running = false;
- var ask_page_eval_handle;
- query.keyup(function(e){
- if (running === false){
- clearTimeout(ask_page_eval_handle);
- ask_page_eval_handle = setTimeout(eval_query, 400);
- }
- });
-
- var eval_query = function(){
- cur_text = $.trim(query.val());
- if (cur_text !== prev_text && running === false){
- if (cur_text.length >= minSearchWordLength){
- send_query(cur_text);
- } else if (cur_text.length === 0){
- /* restart query */
- $('#' + q_list_sel).css('height',0).children().remove();
- running = false;
- prev_text = '';
- }
- }
- };
-
- var render_result = function(data, text_status, xhr){
- var container = $('#' + q_list_sel);
- container.fadeOut(200, function() {
- container.children().remove();
- $.each(data, function(idx, question){
- var url = question['url'];
- var title = question['title'];
- var answer_count = question['answer_count'];
- var list_item = $('<h2></h2>');
- var count_element = $('<span class="item-count"></span>');
- count_element.html(answer_count);
- list_item.append(count_element);
- var link = $('<a></a>');
- link.attr('href', url);
- list_item.append(link);
- title_element = $('<span class="title"></span>');
- title_element.html(title);
- link.append(title)
- container.append(list_item);
- });
- container.show();//show just to measure
- var unit_height = container.children(':first').outerHeight();
- container.hide();//now hide
- if (data.length > 5){
- container.css('overflow-y', 'scroll');
- container.css('height', unit_height*5 + 'px');
- } else {
- container.css('height', data.length*unit_height + 'px');
- container.css('overflow-y', 'hidden');
- }
- container.fadeIn();
- });
- };
-
- var send_query = function(query_text){
- prev_text = query_text;
- running = true;
- $.ajax({
- url: search_url,
- dataType: 'json',
- success: render_result,
- complete: function() {
- running = false;
- eval_query();
- },
- data: {query: query_text},
- cache: false
- });
- }
-
-};
diff --git a/askbot/skins/common/media/js/post.js b/askbot/skins/common/media/js/post.js
deleted file mode 100644
index 58f2436d..00000000
--- a/askbot/skins/common/media/js/post.js
+++ /dev/null
@@ -1,2418 +0,0 @@
-/*
-Scripts for cnprog.com
-Project Name: Lanai
-All Rights Resevred 2008. CNPROG.COM
-*/
-var lanai =
-{
- /**
- * Finds any <pre><code></code></pre> tags which aren't registered for
- * pretty printing, adds the appropriate class name and invokes prettify.
- */
- highlightSyntax: function(){
- var styled = false;
- $("pre code").parent().each(function(){
- if (!$(this).hasClass('prettyprint')){
- $(this).addClass('prettyprint');
- styled = true;
- }
- });
-
- if (styled){
- prettyPrint();
- }
- }
-};
-
-function appendLoader(element) {
- loading = gettext('loading...')
- element.append('<img class="ajax-loader" ' +
- 'src="' + mediaUrl("media/images/indicator.gif") + '" title="' +
- loading +
- '" alt="' +
- loading +
- '" />');
-}
-
-function removeLoader() {
- $("img.ajax-loader").remove();
-}
-
-function setSubmitButtonDisabled(form, isDisabled) {
- form.find('input[type="submit"]').attr("disabled", isDisabled);
-}
-
-function enableSubmitButton(form) {
- setSubmitButtonDisabled(form, false);
-}
-
-function disableSubmitButton(form) {
- setSubmitButtonDisabled(form, true);
-}
-
-function setupFormValidation(form, validationRules, validationMessages, onSubmitCallback) {
- enableSubmitButton(form);
- form.validate({
- debug: true,
- rules: (validationRules ? validationRules : {}),
- messages: (validationMessages ? validationMessages : {}),
- errorElement: "span",
- errorClass: "form-error",
- errorPlacement: function(error, element) {
- var span = element.next().find("span.form-error");
- if (span.length === 0) {
- span = element.parent().find("span.form-error");
- if (span.length === 0){
- //for resizable textarea
- var element_id = element.attr('id');
- span = $('label[for="' + element_id + '"]');
- }
- }
- span.replaceWith(error);
- },
- submitHandler: function(form_dom) {
- disableSubmitButton($(form_dom));
-
- if (onSubmitCallback){
- onSubmitCallback();
- }
- else{
- form_dom.submit();
- }
- }
- });
-}
-
-var validateTagLength = function(value){
- var tags = getUniqueWords(value);
- var are_tags_ok = true;
- $.each(tags, function(index, value){
- if (value.length > askbot['settings']['maxTagLength']){
- are_tags_ok = false;
- }
- });
- return are_tags_ok;
-};
-var validateTagCount = function(value){
- var tags = getUniqueWords(value);
- return (tags.length <= askbot['settings']['maxTagsPerPost']);
-};
-
-$.validator.addMethod('limit_tag_count', validateTagCount);
-$.validator.addMethod('limit_tag_length', validateTagLength);
-
-var CPValidator = function(){
- return {
- getQuestionFormRules : function(){
- return {
- tags: {
- required: askbot['settings']['tagsAreRequired'],
- maxlength: 105,
- limit_tag_count: true,
- limit_tag_length: true
- },
- text: {
- minlength: askbot['settings']['minQuestionBodyLength']
- },
- title: {
- minlength: askbot['settings']['minTitleLength']
- }
- };
- },
- getQuestionFormMessages: function(){
- return {
- tags: {
- required: " " + gettext('tags cannot be empty'),
- maxlength: askbot['messages']['tagLimits'],
- limit_tag_count: askbot['messages']['maxTagsPerPost'],
- limit_tag_length: askbot['messages']['maxTagLength']
- },
- text: {
- required: " " + gettext('content cannot be empty'),
- minlength: interpolate(
- ngettext(
- 'question body must be > %s character',
- 'question body must be > %s characters',
- askbot['settings']['minQuestionBodyLength']
- ),
- [askbot['settings']['minQuestionBodyLength'], ]
- )
- },
- title: {
- required: " " + gettext('please enter title'),
- minlength: interpolate(
- ngettext(
- 'title must be > %s character',
- 'title must be > %s characters',
- askbot['settings']['minTitleLength']
- ),
- [askbot['settings']['minTitleLength'], ]
- )
- }
- };
- },
- getAnswerFormRules : function(){
- return {
- text: {
- minlength: askbot['settings']['minAnswerBodyLength']
- },
- };
- },
- getAnswerFormMessages: function(){
- return {
- text: {
- required: " " + gettext('content cannot be empty'),
- minlength: interpolate(
- ngettext(
- 'answer must be > %s character',
- 'answer must be > %s characters',
- askbot['settings']['minAnswerBodyLength']
- ),
- [askbot['settings']['minAnswerBodyLength'], ]
- )
- },
- }
- }
- };
-}();
-
-/**
- * @constructor
- * @extends {SimpleControl}
- * @param {Comment} comment to upvote
- */
-var CommentVoteButton = function(comment){
- SimpleControl.call(this);
- /**
- * @param {Comment}
- */
- this._comment = comment;
- /**
- * @type {boolean}
- */
- this._voted = false;
- /**
- * @type {number}
- */
- this._score = 0;
-};
-inherits(CommentVoteButton, SimpleControl);
-/**
- * @param {number} score
- */
-CommentVoteButton.prototype.setScore = function(score){
- this._score = score;
- if (this._element){
- this._element.html(score);
- }
-};
-/**
- * @param {boolean} voted
- */
-CommentVoteButton.prototype.setVoted = function(voted){
- this._voted = voted;
- if (this._element){
- this._element.addClass('upvoted');
- }
-};
-
-CommentVoteButton.prototype.getVoteHandler = function(){
- var me = this;
- var comment = this._comment;
- return function(){
- var voted = me._voted;
- var post_id = me._comment.getId();
- var data = {
- cancel_vote: voted ? true:false,
- post_id: post_id
- };
- $.ajax({
- type: 'POST',
- data: data,
- dataType: 'json',
- url: askbot['urls']['upvote_comment'],
- cache: false,
- success: function(data){
- if (data['success'] == true){
- me.setScore(data['score']);
- me.setVoted(true);
- } else {
- showMessage(comment.getElement(), data['message'], 'after');
- }
- }
- });
- };
-};
-
-CommentVoteButton.prototype.decorate = function(element){
- this._element = element;
- this.setHandler(this.getVoteHandler());
-
- var element = this._element;
- var comment = this._comment;
- /* can't call comment.getElement() here due
- * an issue in the getElement() of comment
- * so use an "illegal" access to comment._element here
- */
- comment._element.mouseenter(function(){
- //outside height may not be known
- //var height = comment.getElement().height();
- //element.height(height);
- element.addClass('hover');
- });
- comment._element.mouseleave(function(){
- element.removeClass('hover');
- });
-
-};
-
-CommentVoteButton.prototype.createDom = function(){
- this._element = this.makeElement('div');
- if (this._score > 0){
- this._element.html(this._score);
- }
- this._element.addClass('upvote');
- if (this._voted){
- this._element.addClass('upvoted');
- }
- this.decorate(this._element);
-};
-
-/**
- * legacy Vote class
- * handles all sorts of vote-like operations
- */
-var Vote = function(){
- // All actions are related to a question
- var questionId;
- //question slug to build redirect urls
- var questionSlug;
- // The object we operate on actually. It can be a question or an answer.
- var postId;
- var questionAuthorId;
- var currentUserId;
- var answerContainerIdPrefix = 'post-id-';
- var voteContainerId = 'vote-buttons';
- var imgIdPrefixAccept = 'answer-img-accept-';
- var classPrefixFollow= 'button follow';
- var classPrefixFollowed= 'button followed';
- var imgIdPrefixQuestionVoteup = 'question-img-upvote-';
- var imgIdPrefixQuestionVotedown = 'question-img-downvote-';
- var imgIdPrefixAnswerVoteup = 'answer-img-upvote-';
- var imgIdPrefixAnswerVotedown = 'answer-img-downvote-';
- var divIdFavorite = 'favorite-number';
- var commentLinkIdPrefix = 'comment-';
- var voteNumberClass = "vote-number";
- var offensiveIdPrefixQuestionFlag = 'question-offensive-flag-';
- var removeOffensiveIdPrefixQuestionFlag = 'question-offensive-remove-flag-';
- var removeAllOffensiveIdPrefixQuestionFlag = 'question-offensive-remove-all-flag-';
- var offensiveIdPrefixAnswerFlag = 'answer-offensive-flag-';
- var removeOffensiveIdPrefixAnswerFlag = 'answer-offensive-remove-flag-';
- var removeAllOffensiveIdPrefixAnswerFlag = 'answer-offensive-remove-all-flag-';
- var offensiveClassFlag = 'offensive-flag';
- var questionControlsId = 'question-controls';
- var removeAnswerLinkIdPrefix = 'answer-delete-link-';
- var questionSubscribeUpdates = 'question-subscribe-updates';
- var questionSubscribeSidebar= 'question-subscribe-sidebar';
-
- var acceptAnonymousMessage = gettext('insufficient privilege');
- var acceptOwnAnswerMessage = gettext('cannot pick own answer as best');
-
- var pleaseLogin = " <a href='" + askbot['urls']['user_signin']
- + "?next=" + askbot['urls']['question_url_template']
- + "'>"
- + gettext('please login') + "</a>";
-
- var favoriteAnonymousMessage = gettext('anonymous users cannot follow questions') + pleaseLogin;
- var subscribeAnonymousMessage = gettext('anonymous users cannot subscribe to questions') + pleaseLogin;
- var voteAnonymousMessage = gettext('anonymous users cannot vote') + pleaseLogin;
- //there were a couple of more messages...
- var offensiveConfirmation = gettext('please confirm offensive');
- var removeOffensiveConfirmation = gettext('please confirm removal of offensive flag');
- var offensiveAnonymousMessage = gettext('anonymous users cannot flag offensive posts') + pleaseLogin;
- var removeConfirmation = gettext('confirm delete');
- var removeAnonymousMessage = gettext('anonymous users cannot delete/undelete') + pleaseLogin;
- var recoveredMessage = gettext('post recovered');
- var deletedMessage = gettext('post deleted');
-
- var VoteType = {
- acceptAnswer : 0,
- questionUpVote : 1,
- questionDownVote : 2,
- favorite : 4,
- answerUpVote: 5,
- answerDownVote:6,
- offensiveQuestion : 7,
- removeOffensiveQuestion : 7.5,
- removeAllOffensiveQuestion : 7.6,
- offensiveAnswer:8,
- removeOffensiveAnswer:8.5,
- removeAllOffensiveAnswer:8.6,
- removeQuestion: 9,//deprecate
- removeAnswer:10,//deprecate
- questionSubscribeUpdates:11,
- questionUnsubscribeUpdates:12
- };
-
- var getFavoriteButton = function(){
- var favoriteButton = 'div.'+ voteContainerId +' a[class="'+ classPrefixFollow +'"]';
- favoriteButton += ', div.'+ voteContainerId +' a[class="'+ classPrefixFollowed +'"]';
- return $(favoriteButton);
- };
- var getFavoriteNumber = function(){
- var favoriteNumber = '#'+ divIdFavorite ;
- return $(favoriteNumber);
- };
- var getQuestionVoteUpButton = function(){
- var questionVoteUpButton = 'div.'+ voteContainerId +' div[id^="'+ imgIdPrefixQuestionVoteup +'"]';
- return $(questionVoteUpButton);
- };
- var getQuestionVoteDownButton = function(){
- var questionVoteDownButton = 'div.'+ voteContainerId +' div[id^="'+ imgIdPrefixQuestionVotedown +'"]';
- return $(questionVoteDownButton);
- };
- var getAnswerVoteUpButtons = function(){
- var answerVoteUpButton = 'div.'+ voteContainerId +' div[id^="'+ imgIdPrefixAnswerVoteup +'"]';
- return $(answerVoteUpButton);
- };
- var getAnswerVoteDownButtons = function(){
- var answerVoteDownButton = 'div.'+ voteContainerId +' div[id^="'+ imgIdPrefixAnswerVotedown +'"]';
- return $(answerVoteDownButton);
- };
- var getAnswerVoteUpButton = function(id){
- var answerVoteUpButton = 'div.'+ voteContainerId +' div[id="'+ imgIdPrefixAnswerVoteup + id + '"]';
- return $(answerVoteUpButton);
- };
- var getAnswerVoteDownButton = function(id){
- var answerVoteDownButton = 'div.'+ voteContainerId +' div[id="'+ imgIdPrefixAnswerVotedown + id + '"]';
- return $(answerVoteDownButton);
- };
-
- var getOffensiveQuestionFlag = function(){
- var offensiveQuestionFlag = '#question-table span[id^="'+ offensiveIdPrefixQuestionFlag +'"]';
- return $(offensiveQuestionFlag);
- };
-
- var getRemoveOffensiveQuestionFlag = function(){
- var removeOffensiveQuestionFlag = '#question-table span[id^="'+ removeOffensiveIdPrefixQuestionFlag +'"]';
- return $(removeOffensiveQuestionFlag);
- };
-
- var getRemoveAllOffensiveQuestionFlag = function(){
- var removeAllOffensiveQuestionFlag = '#question-table span[id^="'+ removeAllOffensiveIdPrefixQuestionFlag +'"]';
- return $(removeAllOffensiveQuestionFlag);
- };
-
- var getOffensiveAnswerFlags = function(){
- var offensiveQuestionFlag = 'div.answer span[id^="'+ offensiveIdPrefixAnswerFlag +'"]';
- return $(offensiveQuestionFlag);
- };
-
- var getRemoveOffensiveAnswerFlag = function(){
- var removeOffensiveAnswerFlag = 'div.answer span[id^="'+ removeOffensiveIdPrefixAnswerFlag +'"]';
- return $(removeOffensiveAnswerFlag);
- };
-
- var getRemoveAllOffensiveAnswerFlag = function(){
- var removeAllOffensiveAnswerFlag = 'div.answer span[id^="'+ removeAllOffensiveIdPrefixAnswerFlag +'"]';
- return $(removeAllOffensiveAnswerFlag);
- };
-
- var getquestionSubscribeUpdatesCheckbox = function(){
- return $('#' + questionSubscribeUpdates);
- };
-
- var getquestionSubscribeSidebarCheckbox= function(){
- return $('#' + questionSubscribeSidebar);
- };
-
- var getremoveAnswersLinks = function(){
- var removeAnswerLinks = 'div.answer-controls a[id^="'+ removeAnswerLinkIdPrefix +'"]';
- return $(removeAnswerLinks);
- };
-
- var setVoteImage = function(voteType, undo, object){
- var flag = undo ? false : true;
- if (object.hasClass("on")) {
- object.removeClass("on");
- }else{
- object.addClass("on");
- }
-
- if(undo){
- if(voteType == VoteType.questionUpVote || voteType == VoteType.questionDownVote){
- $(getQuestionVoteUpButton()).removeClass("on");
- $(getQuestionVoteDownButton()).removeClass("on");
- }
- else{
- $(getAnswerVoteUpButton(postId)).removeClass("on");
- $(getAnswerVoteDownButton(postId)).removeClass("on");
- }
- }
- };
-
- var setVoteNumber = function(object, number){
- var voteNumber = object.parent('div.'+ voteContainerId).find('div.'+ voteNumberClass);
- $(voteNumber).text(number);
- };
-
- var bindEvents = function(){
- // accept answers
- var acceptedButtons = 'div.'+ voteContainerId +' div[id^="'+ imgIdPrefixAccept +'"]';
- $(acceptedButtons).unbind('click').click(function(event){
- Vote.accept($(event.target));
- });
- // set favorite question
- var favoriteButton = getFavoriteButton();
- favoriteButton.unbind('click').click(function(event){
- //Vote.favorite($(event.target));
- Vote.favorite(favoriteButton);
- });
-
- // question vote up
- var questionVoteUpButton = getQuestionVoteUpButton();
- questionVoteUpButton.unbind('click').click(function(event){
- Vote.vote($(event.target), VoteType.questionUpVote);
- });
-
- var questionVoteDownButton = getQuestionVoteDownButton();
- questionVoteDownButton.unbind('click').click(function(event){
- Vote.vote($(event.target), VoteType.questionDownVote);
- });
-
- var answerVoteUpButton = getAnswerVoteUpButtons();
- answerVoteUpButton.unbind('click').click(function(event){
- Vote.vote($(event.target), VoteType.answerUpVote);
- });
-
- var answerVoteDownButton = getAnswerVoteDownButtons();
- answerVoteDownButton.unbind('click').click(function(event){
- Vote.vote($(event.target), VoteType.answerDownVote);
- });
-
- getOffensiveQuestionFlag().unbind('click').click(function(event){
- Vote.offensive(this, VoteType.offensiveQuestion);
- });
-
- getRemoveOffensiveQuestionFlag().unbind('click').click(function(event){
- Vote.remove_offensive(this, VoteType.removeOffensiveQuestion);
- });
-
- getRemoveAllOffensiveQuestionFlag().unbind('click').click(function(event){
- Vote.remove_all_offensive(this, VoteType.removeAllOffensiveQuestion);
- });
-
- getOffensiveAnswerFlags().unbind('click').click(function(event){
- Vote.offensive(this, VoteType.offensiveAnswer);
- });
-
- getRemoveOffensiveAnswerFlag().unbind('click').click(function(event){
- Vote.remove_offensive(this, VoteType.removeOffensiveAnswer);
- });
-
- getRemoveAllOffensiveAnswerFlag().unbind('click').click(function(event){
- Vote.remove_all_offensive(this, VoteType.removeAllOffensiveAnswer);
- });
-
- getquestionSubscribeUpdatesCheckbox().unbind('click').click(function(event){
- //despeluchar esto
- if (this.checked){
- getquestionSubscribeSidebarCheckbox().attr({'checked': true});
- Vote.vote($(event.target), VoteType.questionSubscribeUpdates);
- }
- else {
- getquestionSubscribeSidebarCheckbox().attr({'checked': false});
- Vote.vote($(event.target), VoteType.questionUnsubscribeUpdates);
- }
- });
-
- getquestionSubscribeSidebarCheckbox().unbind('click').click(function(event){
- if (this.checked){
- getquestionSubscribeUpdatesCheckbox().attr({'checked': true});
- Vote.vote($(event.target), VoteType.questionSubscribeUpdates);
- }
- else {
- getquestionSubscribeUpdatesCheckbox().attr({'checked': false});
- Vote.vote($(event.target), VoteType.questionUnsubscribeUpdates);
- }
- });
-
- getremoveAnswersLinks().unbind('click').click(function(event){
- Vote.remove(this, VoteType.removeAnswer);
- });
- };
-
- var submit = function(object, voteType, callback) {
- //this function submits votes
- $.ajax({
- type: "POST",
- cache: false,
- dataType: "json",
- url: askbot['urls']['vote_url_template'].replace('{{QuestionID}}', questionId),
- data: { "type": voteType, "postId": postId },
- error: handleFail,
- success: function(data){callback(object, voteType, data);}
- });
- };
-
- var handleFail = function(xhr, msg){
- alert("Callback invoke error: " + msg);
- };
-
- // callback function for Accept Answer action
- var callback_accept = function(object, voteType, data){
- if(data.allowed == "0" && data.success == "0"){
- showMessage(object, acceptAnonymousMessage);
- }
- else if(data.allowed == "-1"){
- showMessage(object, acceptOwnAnswerMessage);
- }
- else if(data.status == "1"){
- $("#"+answerContainerIdPrefix+postId).removeClass("accepted-answer");
- $("#"+commentLinkIdPrefix+postId).removeClass("comment-link-accepted");
- }
- else if(data.success == "1"){
- var answers = ('div[id^="'+answerContainerIdPrefix +"']");
- $(answers).removeClass("accepted-answer");
- var commentLinks = ('div[id^="'+answerContainerIdPrefix +'"] div[id^="'+ commentLinkIdPrefix +'"]');
- $(commentLinks).removeClass("comment-link-accepted");
-
- $("#"+answerContainerIdPrefix+postId).addClass("accepted-answer");
- $("#"+commentLinkIdPrefix+postId).addClass("comment-link-accepted");
- }
- else{
- showMessage(object, data.message);
- }
- };
-
- var callback_favorite = function(object, voteType, data){
- if(data.allowed == "0" && data.success == "0"){
- showMessage(
- object,
- favoriteAnonymousMessage.replace(
- '{{QuestionID}}',
- questionId).replace(
- '{{questionSlug}}',
- ''
- )
- );
- }
- else if(data.status == "1"){
- var follow_html = gettext('Follow');
- object.attr("class", 'button follow');
- object.html(follow_html);
- var fav = getFavoriteNumber();
- fav.removeClass("my-favorite-number");
- if(data.count === 0){
- data.count = '';
- fav.text('');
- }else{
- var fmts = ngettext('%s follower', '%s followers', data.count);
- fav.text(interpolate(fmts, [data.count]));
- }
- }
- else if(data.success == "1"){
- var followed_html = gettext('<div>Following</div><div class="unfollow">Unfollow</div>');
- object.html(followed_html);
- object.attr("class", 'button followed');
- var fav = getFavoriteNumber();
- var fmts = ngettext('%s follower', '%s followers', data.count);
- fav.text(interpolate(fmts, [data.count]));
- fav.addClass("my-favorite-number");
- }
- else{
- showMessage(object, data.message);
- }
- };
-
- var callback_vote = function(object, voteType, data){
- if (data.success == '0'){
- showMessage(object, data.message);
- return;
- }
- else {
- if (data.status == '1'){
- setVoteImage(voteType, true, object);
- }
- else {
- setVoteImage(voteType, false, object);
- }
- setVoteNumber(object, data.count);
- if (data.message && data.message.length > 0){
- showMessage(object, data.message);
- }
- return;
- }
- //may need to take a look at this again
- if (data.status == "1"){
- setVoteImage(voteType, true, object);
- setVoteNumber(object, data.count);
- }
- else if (data.success == "1"){
- setVoteImage(voteType, false, object);
- setVoteNumber(object, data.count);
- if (data.message.length > 0){
- showMessage(object, data.message);
- }
- }
- };
-
- var callback_offensive = function(object, voteType, data){
- //todo: transfer proper translations of these from i18n.js
- //to django.po files
- //_('anonymous users cannot flag offensive posts') + pleaseLogin;
- if (data.success == "1"){
- if(data.count > 0)
- $(object).children('span[class="darkred"]').text("("+ data.count +")");
- else
- $(object).children('span[class="darkred"]').text("");
-
- // Change the link text and rebind events
- $(object).find("a.question-flag").html(gettext("remove flag"));
- var obj_id = $(object).attr("id");
- $(object).attr("id", obj_id.replace("flag-", "remove-flag-"));
-
- getRemoveOffensiveQuestionFlag().unbind('click').click(function(event){
- Vote.remove_offensive(this, VoteType.removeOffensiveQuestion);
- });
-
- getRemoveOffensiveAnswerFlag().unbind('click').click(function(event){
- Vote.remove_offensive(this, VoteType.removeOffensiveAnswer);
- });
- }
- else {
- object = $(object);
- showMessage(object, data.message)
- }
- };
-
- var callback_remove_offensive = function(object, voteType, data){
- //todo: transfer proper translations of these from i18n.js
- //to django.po files
- //_('anonymous users cannot flag offensive posts') + pleaseLogin;
- if (data.success == "1"){
- if(data.count > 0){
- $(object).children('span[class="darkred"]').text("("+ data.count +")");
- }
- else{
- $(object).children('span[class="darkred"]').text("");
- // Remove "remove all flags link" since there are no more flags to remove
- var remove_all = $(object).siblings('span.offensive-flag[id*="-offensive-remove-all-flag-"]');
- $(remove_all).next("span.sep").remove();
- $(remove_all).remove();
- }
- // Change the link text and rebind events
- $(object).find("a.question-flag").html(gettext("flag offensive"));
- var obj_id = $(object).attr("id");
- $(object).attr("id", obj_id.replace("remove-flag-", "flag-"));
-
- getOffensiveQuestionFlag().unbind('click').click(function(event){
- Vote.offensive(this, VoteType.offensiveQuestion);
- });
-
- getOffensiveAnswerFlags().unbind('click').click(function(event){
- Vote.offensive(this, VoteType.offensiveAnswer);
- });
- }
- else {
- object = $(object);
- showMessage(object, data.message)
- }
- };
-
- var callback_remove_all_offensive = function(object, voteType, data){
- //todo: transfer proper translations of these from i18n.js
- //to django.po files
- //_('anonymous users cannot flag offensive posts') + pleaseLogin;
- if (data.success == "1"){
- if(data.count > 0)
- $(object).children('span[class="darkred"]').text("("+ data.count +")");
- else
- $(object).children('span[class="darkred"]').text("");
- // remove the link. All flags are gone
- var remove_own = $(object).siblings('span.offensive-flag[id*="-offensive-remove-flag-"]');
- $(remove_own).find("a.question-flag").html(gettext("flag offensive"));
- $(remove_own).attr("id", $(remove_own).attr("id").replace("remove-flag-", "flag-"));
-
- $(object).next("span.sep").remove();
- $(object).remove();
-
-
-
- getOffensiveQuestionFlag().unbind('click').click(function(event){
- Vote.offensive(this, VoteType.offensiveQuestion);
- });
-
- getOffensiveAnswerFlags().unbind('click').click(function(event){
- Vote.offensive(this, VoteType.offensiveAnswer);
- });
- }
- else {
- object = $(object);
- showMessage(object, data.message)
- }
- };
-
- var callback_remove = function(object, voteType, data){
- if (data.success == "1"){
- if (removeActionType == 'delete'){
- postNode.addClass('deleted');
- postRemoveLink.innerHTML = gettext('undelete');
- showMessage(object, deletedMessage);
- }
- else if (removeActionType == 'undelete') {
- postNode.removeClass('deleted');
- postRemoveLink.innerHTML = gettext('delete');
- showMessage(object, recoveredMessage);
- }
- }
- else {
- showMessage(object, data.message)
- }
- };
-
- return {
- init : function(qId, qSlug, questionAuthor, userId){
- questionId = qId;
- questionSlug = qSlug;
- questionAuthorId = questionAuthor;
- currentUserId = userId;
- bindEvents();
- },
-
- //accept answer
- accept: function(object){
- postId = object.attr("id").substring(imgIdPrefixAccept.length);
- submit(object, VoteType.acceptAnswer, callback_accept);
- },
- //mark question as favorite
- favorite: function(object){
- if (!currentUserId || currentUserId.toUpperCase() == "NONE"){
- showMessage(
- object,
- favoriteAnonymousMessage.replace(
- "{{QuestionID}}",
- questionId
- ).replace(
- '{{questionSlug}}',
- questionSlug
- )
- );
- return false;
- }
- submit(object, VoteType.favorite, callback_favorite);
- },
-
- vote: function(object, voteType){
- if (!currentUserId || currentUserId.toUpperCase() == "NONE"){
- if (voteType == VoteType.questionSubscribeUpdates || voteType == VoteType.questionUnsubscribeUpdates){
- getquestionSubscribeSidebarCheckbox().removeAttr('checked');
- getquestionSubscribeUpdatesCheckbox().removeAttr('checked');
- showMessage(object, subscribeAnonymousMessage);
- }else {
- showMessage(
- $(object),
- voteAnonymousMessage.replace(
- "{{QuestionID}}",
- questionId
- ).replace(
- '{{questionSlug}}',
- questionSlug
- )
- );
- }
- return false;
- }
- // up and downvote processor
- if (voteType == VoteType.answerUpVote){
- postId = object.attr("id").substring(imgIdPrefixAnswerVoteup.length);
- }
- else if (voteType == VoteType.answerDownVote){
- postId = object.attr("id").substring(imgIdPrefixAnswerVotedown.length);
- }
-
- submit(object, voteType, callback_vote);
- },
- //flag offensive
- offensive: function(object, voteType){
- if (!currentUserId || currentUserId.toUpperCase() == "NONE"){
- showMessage(
- $(object),
- offensiveAnonymousMessage.replace(
- "{{QuestionID}}",
- questionId
- ).replace(
- '{{questionSlug}}',
- questionSlug
- )
- );
- return false;
- }
- if (confirm(offensiveConfirmation)){
- postId = object.id.substr(object.id.lastIndexOf('-') + 1);
- submit(object, voteType, callback_offensive);
- }
- },
- //remove flag offensive
- remove_offensive: function(object, voteType){
- if (!currentUserId || currentUserId.toUpperCase() == "NONE"){
- showMessage(
- $(object),
- offensiveAnonymousMessage.replace(
- "{{QuestionID}}",
- questionId
- ).replace(
- '{{questionSlug}}',
- questionSlug
- )
- );
- return false;
- }
- if (confirm(removeOffensiveConfirmation)){
- postId = object.id.substr(object.id.lastIndexOf('-') + 1);
- submit(object, voteType, callback_remove_offensive);
- }
- },
- remove_all_offensive: function(object, voteType){
- if (!currentUserId || currentUserId.toUpperCase() == "NONE"){
- showMessage(
- $(object),
- offensiveAnonymousMessage.replace(
- "{{QuestionID}}",
- questionId
- ).replace(
- '{{questionSlug}}',
- questionSlug
- )
- );
- return false;
- }
- if (confirm(removeOffensiveConfirmation)){
- postId = object.id.substr(object.id.lastIndexOf('-') + 1);
- submit(object, voteType, callback_remove_all_offensive);
- }
- },
- //delete question or answer (comments are deleted separately)
- remove: function(object, voteType){
- if (!currentUserId || currentUserId.toUpperCase() == "NONE"){
- showMessage(
- $(object),
- removeAnonymousMessage.replace(
- '{{QuestionID}}',
- questionId
- ).replace(
- '{{questionSlug}}',
- questionSlug
- )
- );
- return false;
- }
- bits = object.id.split('-');
- postId = bits.pop();/* this seems to be used within submit! */
- postType = bits.shift();
-
- var do_proceed = false;
- if (postType == 'answer'){
- postNode = $('#post-id-' + postId);
- }
- else if (postType == 'question'){
- postNode = $('#question-table');
- }
- postRemoveLink = object;
- if (postNode.hasClass('deleted')){
- removeActionType = 'undelete';
- do_proceed = true;
- }
- else {
- removeActionType = 'delete';
- do_proceed = confirm(removeConfirmation);
- }
- if (do_proceed) {
- submit($(object), voteType, callback_remove);
- }
- }
- };
-} ();
-
-var questionRetagger = function(){
-
- var oldTagsHTML = '';
- var tagInput = null;
- var tagsDiv = null;
- var retagLink = null;
-
- var restoreEventHandlers = function(){
- $(document).unbind('click');
- };
-
- var cancelRetag = function(){
- tagsDiv.html(oldTagsHTML);
- tagsDiv.removeClass('post-retag');
- tagsDiv.addClass('post-tags');
- restoreEventHandlers();
- initRetagger();
- };
-
- var render_tag = function(tag_name){
- //copy-paste from live search!!!
- var tag = new Tag();
- tag.setName(tag_name);
- return tag.getElement().outerHTML();
- };
-
- var drawNewTags = function(new_tags){
- if (new_tags === ''){
- tagsDiv.html('');
- return;
- }
- new_tags = new_tags.split(/\s+/);
- var tags_html = ''
- $.each(new_tags, function(index, name){
- tags_html += render_tag(name);
- });
- tagsDiv.html(tags_html);
- };
-
- var doRetag = function(){
- $.ajax({
- type: "POST",
- url: retagUrl,
- dataType: "json",
- data: { tags: getUniqueWords(tagInput.val()).join(' ') },
- success: function(json) {
- if (json['success'] === true){
- new_tags = getUniqueWords(json['new_tags']);
- oldTagsHtml = '';
- cancelRetag();
- drawNewTags(new_tags.join(' '));
- }
- else {
- cancelRetag();
- showMessage(tagsDiv, json['message']);
- }
- },
- error: function(xhr, textStatus, errorThrown) {
- showMessage(tagsDiv, 'sorry, somethin is not right here');
- cancelRetag();
- }
- });
- return false;
- }
-
- var setupInputEventHandlers = function(input){
- input.keydown(function(e){
- if ((e.which && e.which == 27) || (e.keyCode && e.keyCode == 27)){
- cancelRetag();
- }
- });
- $(document).unbind('click').click(cancelRetag, false);
- input.click(function(){return false});
- };
-
- var createRetagForm = function(old_tags_string){
- var div = $('<form method="post"></form>');
- tagInput = $('<input id="retag_tags" type="text" autocomplete="off" name="tags" size="30"/>');
- //var tagLabel = $('<label for="retag_tags" class="error"></label>');
- tagInput.val(old_tags_string);
- //populate input
- var tagAc = new AutoCompleter({
- url: askbot['urls']['get_tag_list'],
- preloadData: true,
- minChars: 1,
- useCache: true,
- matchInside: true,
- maxCacheLength: 100,
- delay: 10
- });
- tagAc.decorate(tagInput);
- div.append(tagInput);
- //div.append(tagLabel);
- setupInputEventHandlers(tagInput);
-
- //button = $('<input type="submit" />');
- //button.val(gettext('save tags'));
- //div.append(button);
- //setupButtonEventHandlers(button);
- div.validate({//copy-paste from utils.js
- rules: {
- tags: {
- required: askbot['settings']['tagsAreRequired'],
- maxlength: askbot['settings']['maxTagsPerPost'] * askbot['settings']['maxTagLength'],
- limit_tag_count: true,
- limit_tag_length: true
- }
- },
- messages: {
- tags: {
- required: gettext('tags cannot be empty'),
- maxlength: askbot['messages']['tagLimits'],
- limit_tag_count: askbot['messages']['maxTagsPerPost'],
- limit_tag_length: askbot['messages']['maxTagLength']
- }
- },
- submitHandler: doRetag,
- errorClass: "retag-error"
- });
-
- return div;
- };
-
- var getTagsAsString = function(tags_div){
- var links = tags_div.find('a');
- var tags_str = '';
- links.each(function(index, element){
- if (index === 0){
- //this is pretty bad - we should use Tag.getName()
- tags_str = $(element).attr('data-tag-name');
- }
- else {
- tags_str += ' ' + $(element).attr('data-tag-name');
- }
- });
- return tags_str;
- };
-
- var noopHandler = function(){
- tagInput.focus();
- return false;
- };
-
- var deactivateRetagLink = function(){
- retagLink.unbind('click').click(noopHandler);
- retagLink.unbind('keypress').keypress(noopHandler);
- };
-
- var startRetag = function(){
- tagsDiv = $('#question-tags');
- oldTagsHTML = tagsDiv.html();//save to restore on cancel
- var old_tags_string = getTagsAsString(tagsDiv);
- var retag_form = createRetagForm(old_tags_string);
- tagsDiv.html('');
- tagsDiv.append(retag_form);
- tagsDiv.removeClass('post-tags');
- tagsDiv.addClass('post-retag');
- tagInput.focus();
- deactivateRetagLink();
- return false;
- };
-
- var setupClickAndEnterHandler = function(element, callback){
- element.unbind('click').click(callback);
- element.unbind('keypress').keypress(function(e){
- if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)){
- callback();
- }
- });
- }
-
- var initRetagger = function(){
- setupClickAndEnterHandler(retagLink, startRetag);
- };
-
- return {
- init: function(){
- retagLink = $('#retag');
- initRetagger();
- }
- };
-}();
-
-var DeletePostLink = function(){
- SimpleControl.call(this);
- this._post_id = null;
-};
-inherits(DeletePostLink, SimpleControl);
-
-DeletePostLink.prototype.setPostId = function(id){
- this._post_id = id;
-};
-
-DeletePostLink.prototype.getPostId = function(){
- return this._post_id;
-};
-
-DeletePostLink.prototype.getPostElement = function(){
- return $('#post-id-' + this.getPostId());
-};
-
-DeletePostLink.prototype.isPostDeleted = function(){
- return this._post_deleted;
-};
-
-DeletePostLink.prototype.setPostDeleted = function(is_deleted){
- var post = this.getPostElement();
- if (is_deleted === true){
- post.addClass('deleted');
- this._post_deleted = true;
- this.getElement().html(gettext('undelete'));
- } else if (is_deleted === false){
- post.removeClass('deleted');
- this._post_deleted = false;
- this.getElement().html(gettext('delete'));
- }
-};
-
-DeletePostLink.prototype.getDeleteHandler = function(){
- var me = this;
- var post_id = this.getPostId();
- return function(){
- var data = {
- 'post_id': me.getPostId(),
- //todo rename cancel_vote -> undo
- 'cancel_vote': me.isPostDeleted() ? true: false
- };
- $.ajax({
- type: 'POST',
- data: data,
- dataType: 'json',
- url: askbot['urls']['delete_post'],
- cache: false,
- success: function(data){
- if (data['success'] == true){
- me.setPostDeleted(data['is_deleted']);
- } else {
- showMessage(me.getElement(), data['message']);
- }
- }
- });
- };
-};
-
-DeletePostLink.prototype.decorate = function(element){
- this._element = element;
- this._post_deleted = this.getPostElement().hasClass('deleted');
- this.setHandler(this.getDeleteHandler());
-}
-
-//constructor for the form
-var EditCommentForm = function(){
- WrappedElement.call(this);
- this._comment = null;
- this._comment_widget = null;
- this._element = null;
- this._text = '';
- this._id = 'edit-comment-form';
-};
-inherits(EditCommentForm, WrappedElement);
-
-EditCommentForm.prototype.getElement = function(){
- EditCommentForm.superClass_.getElement.call(this);
- this._textarea.val(this._text);
- return this._element;
-};
-
-EditCommentForm.prototype.attachTo = function(comment, mode){
- this._comment = comment;
- this._type = mode;
- this._comment_widget = comment.getContainerWidget();
- this._text = comment.getText();
- comment.getElement().after(this.getElement());
- comment.getElement().hide();
- this._comment_widget.hideButton();
- if (this._type == 'add'){
- this._submit_btn.html(gettext('add comment'));
- }
- else {
- this._submit_btn.html(gettext('save comment'));
- }
- this.getElement().show();
- this.enableButtons();
- this.focus();
- putCursorAtEnd(this._textarea);
-};
-
-EditCommentForm.prototype.getCounterUpdater = function(){
- //returns event handler
- var counter = this._text_counter;
- var handler = function(){
- var textarea = $(this);
- var length = textarea.val() ? textarea.val().length : 0;
- var length1 = maxCommentLength - 100;
- if (length1 < 0){
- length1 = Math.round(0.7*maxCommentLength);
- }
- var length2 = maxCommentLength - 30;
- if (length2 < 0){
- length2 = Math.round(0.9*maxCommentLength);
- }
-
- //todo:
- //1) use class instead of color - move color def to css
- var color = 'maroon';
- var chars = 10;
- if (length === 0){
- var feedback = interpolate(gettext('%s title minchars'), [chars]);
- }
- else if (length < 10){
- var feedback = interpolate(gettext('enter %s more characters'), [chars - length]);
- }
- else {
- color = length > length2 ? "#f00" : length > length1 ? "#f60" : "#999"
- chars = maxCommentLength - length
- var feedback = interpolate(gettext('%s characters left'), [chars])
- }
- counter.html(feedback).css('color', color)
- };
- return handler;
-};
-
-EditCommentForm.prototype.canCancel = function(){
- if (this._element === null){
- return true;
- }
- var ctext = $.trim(this._textarea.val());
- if ($.trim(ctext) == $.trim(this._text)){
- return true;
- }
- else if (this.confirmAbandon()){
- return true;
- }
- this.focus();
- return false;
-};
-
-EditCommentForm.prototype.getCancelHandler = function(){
- var form = this;
- return function(){
- if (form.canCancel()){
- form.detach();
- }
- return false;
- };
-};
-
-EditCommentForm.prototype.detach = function(){
- if (this._comment === null){
- return;
- }
- this._comment.getContainerWidget().showButton();
- if (this._comment.isBlank()){
- this._comment.dispose();
- }
- else {
- this._comment.getElement().show();
- }
- this.reset();
- this._element = this._element.detach();
-};
-
-EditCommentForm.prototype.createDom = function(){
- this._element = $('<form></form>');
- this._element.attr('class', 'post-comments');
-
- var div = $('<div></div>');
- this._textarea = $('<textarea></textarea>');
- this._textarea.attr('id', this._id);
-
- /*
- this._help_text = $('<span></span>').attr('class', 'help-text');
- this._help_text.html(gettext('Markdown is allowed in the comments'));
- div.append(this._help_text);
-
- this._help_text = $('<div></div>').attr('class', 'clearfix');
- div.append(this._help_text);
- */
-
- this._element.append(div);
- div.append(this._textarea);
- this._text_counter = $('<span></span>').attr('class', 'counter');
- div.append(this._text_counter);
- this._submit_btn = $('<button class="submit small"></button>');
- div.append(this._submit_btn);
- this._cancel_btn = $('<button class="submit small"></button>');
- this._cancel_btn.html(gettext('cancel'));
- div.append(this._cancel_btn);
-
- setupButtonEventHandlers(this._submit_btn, this.getSaveHandler());
- setupButtonEventHandlers(this._cancel_btn, this.getCancelHandler());
-
- var update_counter = this.getCounterUpdater();
- var escape_handler = makeKeyHandler(27, this.getCancelHandler());
- this._textarea.attr('name', 'comment')
- .attr('cols', 60)
- .attr('rows', 5)
- .attr('maxlength', maxCommentLength)
- .blur(update_counter)
- .focus(update_counter)
- .keyup(update_counter)
- .keyup(escape_handler);
- if (askbot['settings']['saveCommentOnEnter']){
- var save_handler = makeKeyHandler(13, this.getSaveHandler());
- this._textarea.keydown(save_handler);
- }
- this._textarea.val(this._text);
-};
-
-EditCommentForm.prototype.enableButtons = function(){
- this._submit_btn.attr('disabled', false);
- this._cancel_btn.attr('disabled', false);
-};
-
-EditCommentForm.prototype.disableButtons = function(){
- this._submit_btn.attr('disabled', true);
- this._cancel_btn.attr('disabled', true);
-};
-
-EditCommentForm.prototype.reset = function(){
- this._comment = null;
- this._text = '';
- this._textarea.val('');
- this.enableButtons();
-};
-
-EditCommentForm.prototype.confirmAbandon = function(){
- this.focus(true);
- this._textarea.addClass('highlight');
- var answer = confirm(gettext('confirm abandon comment'));
- this._textarea.removeClass('highlight');
- return answer;
-};
-
-EditCommentForm.prototype.focus = function(hard){
- this._textarea.focus();
- if (hard === true){
- $(this._textarea).scrollTop();
- }
-};
-
-EditCommentForm.prototype.getSaveHandler = function(){
-
- var me = this;
- return function(){
- var text = me._textarea.val();
- if (text.length < 10){
- me.focus();
- return false;
- }
-
- var post_data = {
- comment: text
- };
-
- if (me._type == 'edit'){
- post_data['comment_id'] = me._comment.getId();
- post_url = askbot['urls']['editComment'];
- }
- else {
- post_data['post_type'] = me._comment.getParentType();
- post_data['post_id'] = me._comment.getParentId();
- post_url = askbot['urls']['postComments'];
- }
-
- me.disableButtons();
-
- $.ajax({
- type: "POST",
- url: post_url,
- dataType: "json",
- data: post_data,
- success: function(json) {
- if (me._type == 'add'){
- me._comment.dispose();
- me._comment.getContainerWidget().reRenderComments(json);
- }
- else {
- me._comment.setContent(json);
- me._comment.getElement().show();
- }
- me.detach();
- },
- error: function(xhr, textStatus, errorThrown) {
- me._comment.getElement().show();
- showMessage(me._comment.getElement(), xhr.responseText, 'after');
- me.detach();
- me.enableButtons();
- }
- });
- return false;
- };
-};
-
-//a single instance to reuse
-var editCommentForm = new EditCommentForm();
-
-var Comment = function(widget, data){
- WrappedElement.call(this);
- this._container_widget = widget;
- this._data = data || {};
- this._blank = true;//set to false by setContent
- this._element = null;
- this._delete_prompt = gettext('delete this comment');
- if (data && data['is_deletable']){
- this._deletable = data['is_deletable'];
- }
- else {
- this._deletable = false;
- }
- if (data && data['is_editable']){
- this._editable = data['is_deletable'];
- }
- else {
- this._editable = false;
- }
-};
-inherits(Comment, WrappedElement);
-
-Comment.prototype.decorate = function(element){
- this._element = $(element);
- var parent_type = this._element.parent().parent().attr('id').split('-')[2];
- var comment_id = this._element.attr('id').replace('comment-','');
- this._data = {id: comment_id};
- var delete_img = this._element.find('span.delete-icon');
- if (delete_img.length > 0){
- this._deletable = true;
- this._delete_icon = new DeleteIcon(this.deletePrompt);
- this._delete_icon.setHandler(this.getDeleteHandler());
- this._delete_icon.decorate(delete_img);
- }
- var edit_link = this._element.find('a.edit');
- if (edit_link.length > 0){
- this._editable = true;
- this._edit_link = new EditLink();
- this._edit_link.setHandler(this.getEditHandler());
- this._edit_link.decorate(edit_link);
- }
-
- var vote = new CommentVoteButton(this);
- vote.decorate(this._element.find('.comment-votes .upvote'));
-
- this._blank = false;
-};
-
-Comment.prototype.isBlank = function(){
- return this._blank;
-};
-
-Comment.prototype.getId = function(){
- return this._data['id'];
-};
-
-Comment.prototype.hasContent = function(){
- return ('id' in this._data);
- //shortcut for 'user_url' 'html' 'user_display_name' 'comment_age'
-};
-
-Comment.prototype.hasText = function(){
- return ('text' in this._data);
-}
-
-Comment.prototype.getContainerWidget = function(){
- return this._container_widget;
-};
-
-Comment.prototype.getParentType = function(){
- return this._container_widget.getPostType();
-};
-
-Comment.prototype.getParentId = function(){
- return this._container_widget.getPostId();
-};
-
-Comment.prototype.setContent = function(data){
- this._data = data || this._data;
- this._element.html('');
- this._element.attr('class', 'comment');
- this._element.attr('id', 'comment-' + this._data['id']);
-
- var votes = this.makeElement('div');
- votes.addClass('comment-votes');
-
- var vote = new CommentVoteButton(this);
- if (this._data['upvoted_by_user']){
- vote.setVoted(true);
- }
- vote.setScore(this._data['score']);
- votes.append(vote.getElement());
-
- this._element.append(votes);
-
- this._comment_delete = $('<div class="comment-delete"></div>');
- if (this._deletable){
- this._delete_icon = new DeleteIcon(this._delete_prompt);
- this._delete_icon.setHandler(this.getDeleteHandler());
- this._comment_delete.append(this._delete_icon.getElement());
- }
- this._element.append(this._comment_delete);
-
- this._comment_body = $('<div class="comment-body"></div>');
- this._comment_body.html(this._data['html']);
- //this._comment_body.append(' &ndash; ');
-
- this._user_link = $('<a></a>').attr('class', 'author');
- this._user_link.attr('href', this._data['user_url']);
- this._user_link.html(this._data['user_display_name']);
- this._comment_body.append(this._user_link);
-
- this._comment_body.append(' (');
- this._comment_added_at = $('<abbr class="timeago"></abbr>');
- this._comment_added_at.html(this._data['comment_added_at']);
- this._comment_added_at.attr('title', this._data['comment_added_at']);
- this._comment_added_at.timeago();
- this._comment_body.append(this._comment_added_at);
- this._comment_body.append(')');
-
- if (this._editable){
- this._edit_link = new EditLink();
- this._edit_link.setHandler(this.getEditHandler())
- this._comment_body.append(this._edit_link.getElement());
- }
- this._element.append(this._comment_body);
-
- this._blank = false;
-};
-
-Comment.prototype.dispose = function(){
- if (this._comment_body){
- this._comment_body.remove();
- }
- if (this._comment_delete){
- this._comment_delete.remove();
- }
- if (this._user_link){
- this._user_link.remove();
- }
- if (this._comment_added_at){
- this._comment_added_at.remove();
- }
- if (this._delete_icon){
- this._delete_icon.dispose();
- }
- if (this._edit_link){
- this._edit_link.dispose();
- }
- this._data = null;
- Comment.superClass_.dispose.call(this);
-};
-
-Comment.prototype.getElement = function(){
- Comment.superClass_.getElement.call(this);
- if (this.isBlank() && this.hasContent()){
- this.setContent();
- if (enableMathJax === true){
- MathJax.Hub.Queue(['Typeset', MathJax.Hub]);
- }
- }
- return this._element;
-};
-
-Comment.prototype.loadText = function(on_load_handler){
- var me = this;
- $.ajax({
- type: "GET",
- url: askbot['urls']['getComment'],
- data: {id: this._data['id']},
- success: function(json){
- me._data['text'] = json['text'];
- on_load_handler()
- },
- error: function(xhr, textStatus, exception) {
- showMessage(me.getElement(), xhr.responseText, 'after');
- }
- });
-};
-
-Comment.prototype.getText = function(){
- if (!this.isBlank()){
- if ('text' in this._data){
- return this._data['text'];
- }
- }
- return '';
-}
-
-Comment.prototype.getEditHandler = function(){
- var comment = this;
- return function(){
- if (editCommentForm.canCancel()){
- editCommentForm.detach();
- if (comment.hasText()){
- editCommentForm.attachTo(comment, 'edit');
- }
- else {
- comment.loadText(
- function(){
- editCommentForm.attachTo(comment, 'edit');
- }
- );
- }
- }
- };
-};
-
-Comment.prototype.getDeleteHandler = function(){
- var comment = this;
- var del_icon = this._delete_icon;
- return function(){
- if (confirm(gettext('confirm delete comment'))){
- comment.getElement().hide();
- $.ajax({
- type: 'POST',
- url: askbot['urls']['deleteComment'],
- data: { comment_id: comment.getId() },
- success: function(json, textStatus, xhr) {
- comment.dispose();
- },
- error: function(xhr, textStatus, exception) {
- comment.getElement().show()
- showMessage(del_icon.getElement(), xhr.responseText);
- },
- dataType: "json"
- });
- }
- };
-};
-
-var PostCommentsWidget = function(){
- WrappedElement.call(this);
- this._denied = false;
-};
-inherits(PostCommentsWidget, WrappedElement);
-
-PostCommentsWidget.prototype.decorate = function(element){
- var element = $(element);
- this._element = element;
-
- var widget_id = element.attr('id');
- var id_bits = widget_id.split('-');
- this._post_id = id_bits[3];
- this._post_type = id_bits[2];
- this._is_truncated = askbot['data'][widget_id]['truncated'];
- this._user_can_post = askbot['data'][widget_id]['can_post'];
-
- //see if user can comment here
- var controls = element.find('.controls');
- this._activate_button = controls.find('.button');
-
- if (this._user_can_post == false){
- setupButtonEventHandlers(
- this._activate_button,
- this.getReadOnlyLoadHandler()
- );
- }
- else {
- setupButtonEventHandlers(
- this._activate_button,
- this.getActivateHandler()
- );
- }
-
- this._cbox = element.find('.content');
- var comments = new Array();
- var me = this;
- this._cbox.children('.comment').each(function(index, element){
- var comment = new Comment(me);
- comments.push(comment)
- comment.decorate(element);
- });
- this._comments = comments;
-};
-
-PostCommentsWidget.prototype.getPostType = function(){
- return this._post_type;
-};
-
-PostCommentsWidget.prototype.getPostId = function(){
- return this._post_id;
-};
-
-PostCommentsWidget.prototype.hideButton = function(){
- this._activate_button.hide();
-};
-
-PostCommentsWidget.prototype.showButton = function(){
- if (this._is_truncated === false){
- this._activate_button.html(askbot['messages']['addComment']);
- }
- this._activate_button.show();
-}
-
-PostCommentsWidget.prototype.startNewComment = function(){
- var comment = new Comment(this);
- this._cbox.append(comment.getElement());
- editCommentForm.attachTo(comment, 'add');
-};
-
-PostCommentsWidget.prototype.needToReload = function(){
- return this._is_truncated;
-};
-
-PostCommentsWidget.prototype.getActivateHandler = function(){
- var me = this;
- return function() {
- if (editCommentForm.canCancel()){
- editCommentForm.detach();
- if (me.needToReload()){
- me.reloadAllComments(function(json){
- me.reRenderComments(json);
- me.startNewComment();
- });
- }
- else {
- me.startNewComment();
- }
- }
- };
-};
-
-PostCommentsWidget.prototype.getReadOnlyLoadHandler = function(){
- var me = this;
- return function(){
- me.reloadAllComments(function(json){
- me.reRenderComments(json);
- me._activate_button.remove();
- });
- };
-};
-
-
-PostCommentsWidget.prototype.reloadAllComments = function(callback){
- var post_data = {post_id: this._post_id, post_type: this._post_type};
- var me = this;
- $.ajax({
- type: "GET",
- url: askbot['urls']['postComments'],
- data: post_data,
- success: function(json){
- callback(json);
- me._is_truncated = false;
- },
- dataType: "json"
- });
-};
-
-PostCommentsWidget.prototype.reRenderComments = function(json){
- $.each(this._comments, function(i, item){
- item.dispose();
- });
- this._comments = new Array();
- var me = this;
- $.each(json, function(i, item){
- var comment = new Comment(me, item);
- me._cbox.append(comment.getElement());
- me._comments.push(comment);
- });
-};
-
-
-var socialSharing = function(){
-
- var SERVICE_DATA = {
- //url - template for the sharing service url, params are for the popup
- identica: {
- url: "http://identi.ca/notice/new?status_textarea={TEXT}%20{URL}",
- params: "width=820, height=526,toolbar=1,status=1,resizable=1,scrollbars=1"
- },
- twitter: {
- url: "http://twitter.com/share?url={URL}&ref=twitbtn&text={TEXT}",
- params: "width=820,height=526,toolbar=1,status=1,resizable=1,scrollbars=1"
- },
- facebook: {
- url: "http://www.facebook.com/sharer.php?u={URL}&ref=fbshare&t={TEXT}",
- params: "width=630,height=436,toolbar=1,status=1,resizable=1,scrollbars=1"
- },
- linkedin: {
- url: "http://www.linkedin.com/shareArticle?mini=true&url={URL}&title={TEXT}",
- params: "width=630,height=436,toolbar=1,status=1,resizable=1,scrollbars=1"
- }
- };
- var URL = "";
- var TEXT = "";
-
- var share_page = function(service_name){
- if (SERVICE_DATA[service_name]){
- var url = SERVICE_DATA[service_name]['url'];
- $.ajax({
- async: false,
- url: "http://json-tinyurl.appspot.com/?&callback=?",
- dataType: "json",
- data: {'url':URL},
- success: function(data){
- url = url.replace('{URL}', data.tinyurl);
- },
- error: function(data){
- url = url.replace('{URL}', URL);
- },
- complete: function(data){
- url = url.replace('{TEXT}', TEXT);
- var params = SERVICE_DATA[service_name]['params'];
- if(!window.open(url, "sharing", params)){
- window.location.href=url;
- }
- }
- });
- }
- }
-
- return {
- init: function(){
- URL = window.location.href;
- TEXT = escape($('h1 > a').html());
- var fb = $('a.facebook-share')
- var tw = $('a.twitter-share');
- var ln = $('a.linkedin-share');
- var ica = $('a.identica-share');
- copyAltToTitle(fb);
- copyAltToTitle(tw);
- copyAltToTitle(ln);
- copyAltToTitle(ica);
- setupButtonEventHandlers(fb, function(){share_page("facebook")});
- setupButtonEventHandlers(tw, function(){share_page("twitter")});
- setupButtonEventHandlers(ln, function(){share_page("linkedin")});
- setupButtonEventHandlers(ica, function(){share_page("identica")});
- }
- }
-}();
-
-/**
- * @constructor
- * @extends {SimpleControl}
- */
-var QASwapper = function(){
- SimpleControl.call(this);
- this._ans_id = null;
-};
-inherits(QASwapper, SimpleControl);
-
-QASwapper.prototype.decorate = function(element){
- this._element = element;
- this._ans_id = parseInt(element.attr('id').split('-').pop());
- var me = this;
- this.setHandler(function(){
- me.startSwapping();
- });
-};
-
-QASwapper.prototype.startSwapping = function(){
- while (true){
- var title = prompt(gettext('Please enter question title (>10 characters)'));
- if (title.length >= 10){
- var data = {new_title: title, answer_id: this._ans_id};
- $.ajax({
- type: "POST",
- cache: false,
- dataType: "json",
- url: askbot['urls']['swap_question_with_answer'],
- data: data,
- success: function(data){
- var url_template = askbot['urls']['question_url_template'];
- new_question_url = url_template.replace(
- '{{QuestionID}}',
- data['id']
- ).replace(
- '{{questionSlug}}',
- data['slug']
- );
- window.location.href = new_question_url;
- }
- });
- break;
- }
- }
-};
-
-/**
- * @constructor
- */
-var WMD = function(){
- WrappedElement.call(this);
- this._markdown = undefined;
- this._enabled_buttons = 'bold italic link blockquote code ' +
- 'image attachment ol ul heading hr';
- this._is_previewer_enabled = true;
-};
-inherits(WMD, WrappedElement);
-
-WMD.prototype.setEnabledButtons = function(buttons){
- this._enabled_buttons = buttons;
-};
-
-WMD.prototype.setPreviewerEnabled = function(state){
- this._is_previewer_enabled = state;
- if (this._previewer){
- this._previewer.hide();
- }
-};
-
-WMD.prototype.setEscapeHandler = function(handler){
- this._escape_handler = handler;
-};
-
-WMD.prototype.createDom = function(){
- this._element = this.makeElement('div');
- var clearfix = this.makeElement('div').addClass('clearfix');
- this._element.append(clearfix);
-
- var wmd_container = this.makeElement('div');
- wmd_container.addClass('wmd-container');
- this._element.append(wmd_container);
-
- var wmd_buttons = this.makeElement('div')
- .attr('id', 'wmd-button-bar')
- .addClass('wmd-panel');
- wmd_container.append(wmd_buttons);
-
- var editor = this.makeElement('textarea')
- .attr('id', 'editor');
- wmd_container.append(editor);
- this._textarea = editor;
-
- if (this._markdown){
- editor.val(this._markdown);
- }
-
- var previewer = this.makeElement('div')
- .attr('id', 'previewer')
- .addClass('wmd-preview');
- wmd_container.append(previewer);
- this._previewer = previewer;
- if (this._is_previewer_enabled === false) {
- previewer.hide();
- }
-};
-
-WMD.prototype.setMarkdown = function(text){
- this._markdown = text;
- if (this._textarea){
- this._textarea.val(text);
- }
-};
-
-WMD.prototype.getMarkdown = function(){
- return this._textarea.val();
-};
-
-WMD.prototype.start = function(){
- Attacklab.Util.startEditor(true, this._enabled_buttons);
- this._textarea.keyup(makeKeyHandler(27, this._escape_handler));
-};
-
-/**
- * @constructor
- */
-var TagWikiEditor = function(){
- WrappedElement.call(this);
- this._state = 'display';//'edit' or 'display'
- this._content_backup = '';
- this._is_editor_loaded = false;
- this._enabled_editor_buttons = null;
- this._is_previewer_enabled = false;
-};
-inherits(TagWikiEditor, WrappedElement);
-
-TagWikiEditor.prototype.backupContent = function(){
- this._content_backup = this._content_box.contents();
-};
-
-TagWikiEditor.prototype.setEnabledEditorButtons = function(buttons){
- this._enabled_editor_buttons = buttons;
-};
-
-TagWikiEditor.prototype.setPreviewerEnabled = function(state){
- this._is_previewer_enabled = state;
- if (this.isEditorLoaded()){
- this._editor.setPreviewerEnabled(this._is_previewer_enabled);
- }
-};
-
-TagWikiEditor.prototype.setContent = function(content){
- this._content_box.empty();
- this._content_box.append(content);
-};
-
-TagWikiEditor.prototype.setState = function(state){
- if (state === 'edit'){
- this._state = state;
- this._edit_btn.hide();
- this._cancel_btn.show();
- this._save_btn.show();
- this._cancel_sep.show();
- } else if (state === 'display'){
- this._state = state;
- this._edit_btn.show();
- this._cancel_btn.hide();
- this._cancel_sep.hide();
- this._save_btn.hide();
- }
-};
-
-TagWikiEditor.prototype.restoreContent = function(){
- var content_box = this._content_box;
- content_box.empty();
- $.each(this._content_backup, function(idx, element){
- content_box.append(element);
- });
-};
-
-TagWikiEditor.prototype.getTagId = function(){
- return this._tag_id;
-};
-
-TagWikiEditor.prototype.isEditorLoaded = function(){
- return this._is_editor_loaded;
-};
-
-TagWikiEditor.prototype.setEditorLoaded = function(){
- return this._is_editor_loaded = true;
-};
-
-/**
- * loads initial data for the editor input and activates
- * the editor
- */
-TagWikiEditor.prototype.startActivatingEditor = function(){
- var editor = this._editor;
- var me = this;
- $.ajax({
- type: 'GET',
- url: askbot['urls']['load_tag_wiki_text'],
- data: {tag_id: me.getTagId()},
- cache: false,
- success: function(data){
- me.backupContent();
- editor.setMarkdown(data);
- me.setContent(editor.getElement());
- me.setState('edit');
- if (me.isEditorLoaded() === false){
- editor.start();
- me.setEditorLoaded();
- }
- }
- });
-};
-
-TagWikiEditor.prototype.saveData = function(){
- var me = this;
- var text = this._editor.getMarkdown();
- $.ajax({
- type: 'POST',
- dataType: 'json',
- url: askbot['urls']['save_tag_wiki_text'],
- data: {tag_id: me.getTagId(), text: text},
- cache: false,
- success: function(data){
- if (data['success']){
- me.setState('display');
- me.setContent(data['html']);
- } else {
- showMessage(me.getElement(), data['message']);
- }
- }
- });
-};
-
-TagWikiEditor.prototype.cancelEdit = function(){
- this.restoreContent();
- this.setState('display');
-};
-
-TagWikiEditor.prototype.decorate = function(element){
- //expect <div id='group-wiki-{{id}}'><div class="content"/><a class="edit"/></div>
- this._element = element;
- var edit_btn = element.find('.edit-description');
- this._edit_btn = edit_btn;
-
- //adding two buttons...
- var save_btn = this.makeElement('a');
- save_btn.html(gettext('save'));
- edit_btn.after(save_btn);
- save_btn.hide();
- this._save_btn = save_btn;
-
- var cancel_btn = this.makeElement('a');
- cancel_btn.html(gettext('cancel'));
- save_btn.after(cancel_btn);
- cancel_btn.hide();
- this._cancel_btn = cancel_btn;
-
- this._cancel_sep = $('<span> | </span>');
- cancel_btn.before(this._cancel_sep);
- this._cancel_sep.hide();
-
- this._content_box = element.find('.content');
- this._tag_id = element.attr('id').split('-').pop();
-
- var me = this;
- var editor = new WMD();
- if (this._enabled_editor_buttons){
- editor.setEnabledButtons(this._enabled_editor_buttons);
- }
- editor.setPreviewerEnabled(this._is_previewer_enabled);
- editor.setEscapeHandler(function(){me.cancelEdit()});
- this._editor = editor;
- setupButtonEventHandlers(edit_btn, function(){ me.startActivatingEditor() });
- setupButtonEventHandlers(cancel_btn, function(){me.cancelEdit()});
- setupButtonEventHandlers(save_btn, function(){me.saveData()});
-};
-
-var ImageChanger = function(){
- WrappedElement.call(this);
- this._image_element = undefined;
- this._delete_button = undefined;
- this._save_url = undefined;
- this._delete_url = undefined;
- this._messages = undefined;
-};
-inherits(ImageChanger, WrappedElement);
-
-ImageChanger.prototype.setImageElement = function(image_element){
- this._image_element = image_element;
-};
-
-ImageChanger.prototype.setMessages = function(messages){
- this._messages = messages;
-};
-
-ImageChanger.prototype.setDeleteButton = function(delete_button){
- this._delete_button = delete_button;
-};
-
-ImageChanger.prototype.setSaveUrl = function(url){
- this._save_url = url;
-};
-
-ImageChanger.prototype.setDeleteUrl = function(url){
- this._delete_url = url;
-};
-
-ImageChanger.prototype.setAjaxData = function(data){
- this._ajax_data = data;
-};
-
-ImageChanger.prototype.showImage = function(image_url){
- this._image_element.attr('src', image_url);
- this._image_element.show();
-};
-
-ImageChanger.prototype.deleteImage = function(){
- this._image_element.attr('src', '');
- this._image_element.css('display', 'none');
-
- var me = this;
- var delete_url = this._delete_url;
- var data = this._ajax_data;
- $.ajax({
- type: 'POST',
- dataType: 'json',
- url: delete_url,
- data: data,
- cache: false,
- success: function(data){
- if (data['success'] === true){
- showMessage(me.getElement(), data['message'], 'after');
- }
- }
- });
-};
-
-ImageChanger.prototype.saveImageUrl = function(image_url){
- var me = this;
- var data = this._ajax_data;
- data['image_url'] = image_url;
- var save_url = this._save_url;
- $.ajax({
- type: 'POST',
- dataType: 'json',
- url: save_url,
- data: data,
- cache: false,
- success: function(data){
- if (!data['success']){
- showMessage(me.getElement(), data['message'], 'after');
- }
- }
- });
-};
-
-ImageChanger.prototype.startDialog = function(){
- //reusing the wmd's file uploader
- var me = this;
- var change_image_text = this._messages['change_image'];
- var change_image_button = this._element;
- Attacklab.Util.prompt(
- "<h3>" + gettext('Enter the logo url or upload an image') + '</h3>',
- 'http://',
- function(image_url){
- if (image_url){
- me.saveImageUrl(image_url);
- me.showImage(image_url);
- change_image_button.html(change_image_text);
- me.showDeleteButton();
- }
- },
- 'image'
- );
-};
-
-ImageChanger.prototype.showDeleteButton = function(){
- this._delete_button.show();
- this._delete_button.prev().show();
-};
-
-ImageChanger.prototype.hideDeleteButton = function(){
- this._delete_button.hide();
- this._delete_button.prev().hide();
-};
-
-
-ImageChanger.prototype.startDeleting = function(){
- if (confirm(gettext('Do you really want to remove the image?'))){
- this.deleteImage();
- this._element.html(this._messages['add_image']);
- this.hideDeleteButton();
- this._delete_button.hide();
- var sep = this._delete_button.prev();
- sep.hide();
- };
-};
-
-/**
- * decorates an element that will serve as the image changer button
- */
-ImageChanger.prototype.decorate = function(element){
- this._element = element;
- var me = this;
- setupButtonEventHandlers(
- element,
- function(){
- me.startDialog();
- }
- );
- setupButtonEventHandlers(
- this._delete_button,
- function(){
- me.startDeleting();
- }
- )
-};
-
-var UserGroupProfileEditor = function(){
- TagWikiEditor.call(this);
-};
-inherits(UserGroupProfileEditor, TagWikiEditor);
-
-UserGroupProfileEditor.prototype.toggleEmailModeration = function(){
- var btn = this._moderate_email_btn;
- var group_id = this.getTagId();
- $.ajax({
- type: 'POST',
- dataType: 'json',
- cache: false,
- data: {group_id: group_id},
- url: askbot['urls']['toggle_group_email_moderation'],
- success: function(data){
- if (data['success']){
- btn.html(data['new_button_text']);
- } else {
- showMessage(btn, data['message']);
- }
- }
- });
-};
-
-UserGroupProfileEditor.prototype.decorate = function(element){
- this.setEnabledEditorButtons('bold italic link ol ul');
- this.setPreviewerEnabled(false);
- UserGroupProfileEditor.superClass_.decorate.call(this, element);
- var change_logo_btn = element.find('.change-logo');
- this._change_logo_btn = change_logo_btn;
-
- var moderate_email_toggle = new TwoStateToggle();
- moderate_email_toggle.setPostData({
- group_id: this.getTagId(),
- property_name: 'moderate_email'
- });
- var moderate_email_btn = element.find('#moderate-email');
- this._moderate_email_btn = moderate_email_btn;
- moderate_email_toggle.decorate(moderate_email_btn);
-
- var open_group_toggle = new TwoStateToggle();
- open_group_toggle.setPostData({
- group_id: this.getTagId(),
- property_name: 'is_open'
- });
- var open_group_btn = element.find('#open-or-close-group');
- open_group_toggle.decorate(open_group_btn);
-
- var email_editor = new TextPropertyEditor();
- email_editor.decorate(element.find('#preapproved-emails'));
-
- var domain_editor = new TextPropertyEditor();
- domain_editor.decorate(element.find('#preapproved-email-domains'));
-
- var logo_changer = new ImageChanger();
- logo_changer.setImageElement(element.find('.group-logo'));
- logo_changer.setAjaxData({
- group_id: this.getTagId()
- });
- logo_changer.setSaveUrl(askbot['urls']['save_group_logo_url']);
- logo_changer.setDeleteUrl(askbot['urls']['delete_group_logo_url']);
- logo_changer.setMessages({
- change_image: gettext('change logo'),
- add_image: gettext('add logo')
- });
- var delete_logo_btn = element.find('.delete-logo');
- logo_changer.setDeleteButton(delete_logo_btn);
- logo_changer.decorate(change_logo_btn);
-};
-
-var GroupJoinButton = function(){
- TwoStateToggle.call(this);
-};
-inherits(GroupJoinButton, TwoStateToggle);
-
-GroupJoinButton.prototype.getPostData = function(){
- return { group_id: this._group_id };
-};
-
-GroupJoinButton.prototype.getHandler = function(){
- var me = this;
- return function(){
- $.ajax({
- type: 'POST',
- dataType: 'json',
- cache: false,
- data: me.getPostData(),
- url: askbot['urls']['join_or_leave_group'],
- success: function(data){
- if (data['success']){
- var new_state = data['is_member'] ? 'on-state':'off-state';
- me.setState(new_state);
- } else {
- showMessage(me.getElement(), data['message']);
- }
- }
- });
- };
-};
-
-GroupJoinButton.prototype.decorate = function(elem) {
- GroupJoinButton.superClass_.decorate.call(this, elem);
- this._group_id = this._element.data('groupId');
-};
-
-$(document).ready(function() {
- $('[id^="comments-for-"]').each(function(index, element){
- var comments = new PostCommentsWidget();
- comments.decorate(element);
- });
- $('[id^="swap-question-with-answer-"]').each(function(idx, element){
- var swapper = new QASwapper();
- swapper.decorate($(element));
- });
- $('[id^="post-id-"]').each(function(idx, element){
- var deleter = new DeletePostLink();
- //confusingly .question-delete matches the answers too need rename
- var post_id = element.id.split('-').pop();
- deleter.setPostId(post_id);
- deleter.decorate($(element).find('.question-delete'));
- });
- questionRetagger.init();
- socialSharing.init();
-});
-
-
-/*
-Prettify
-http://www.apache.org/licenses/LICENSE-2.0
-*/
-var PR_SHOULD_USE_CONTINUATION = true; var PR_TAB_WIDTH = 8; var PR_normalizedHtml; var PR; var prettyPrintOne; var prettyPrint; function _pr_isIE6() { var isIE6 = navigator && navigator.userAgent && /\bMSIE 6\./.test(navigator.userAgent); _pr_isIE6 = function() { return isIE6; }; return isIE6; } (function() { function wordSet(words) { words = words.split(/ /g); var set = {}; for (var i = words.length; --i >= 0; ) { var w = words[i]; if (w) { set[w] = null; } } return set; } var FLOW_CONTROL_KEYWORDS = "break continue do else for if return while "; var C_KEYWORDS = FLOW_CONTROL_KEYWORDS + "auto case char const default " + "double enum extern float goto int long register short signed sizeof " + "static struct switch typedef union unsigned void volatile "; var COMMON_KEYWORDS = C_KEYWORDS + "catch class delete false import " + "new operator private protected public this throw true try "; var CPP_KEYWORDS = COMMON_KEYWORDS + "alignof align_union asm axiom bool " + "concept concept_map const_cast constexpr decltype " + "dynamic_cast explicit export friend inline late_check " + "mutable namespace nullptr reinterpret_cast static_assert static_cast " + "template typeid typename typeof using virtual wchar_t where "; var JAVA_KEYWORDS = COMMON_KEYWORDS + "boolean byte extends final finally implements import instanceof null " + "native package strictfp super synchronized throws transient "; var CSHARP_KEYWORDS = JAVA_KEYWORDS + "as base by checked decimal delegate descending event " + "fixed foreach from group implicit in interface internal into is lock " + "object out override orderby params readonly ref sbyte sealed " + "stackalloc string select uint ulong unchecked unsafe ushort var "; var JSCRIPT_KEYWORDS = COMMON_KEYWORDS + "debugger eval export function get null set undefined var with " + "Infinity NaN "; var PERL_KEYWORDS = "caller delete die do dump elsif eval exit foreach for " + "goto if import last local my next no our print package redo require " + "sub undef unless until use wantarray while BEGIN END "; var PYTHON_KEYWORDS = FLOW_CONTROL_KEYWORDS + "and as assert class def del " + "elif except exec finally from global import in is lambda " + "nonlocal not or pass print raise try with yield " + "False True None "; var RUBY_KEYWORDS = FLOW_CONTROL_KEYWORDS + "alias and begin case class def" + " defined elsif end ensure false in module next nil not or redo rescue " + "retry self super then true undef unless until when yield BEGIN END "; var SH_KEYWORDS = FLOW_CONTROL_KEYWORDS + "case done elif esac eval fi " + "function in local set then until "; var ALL_KEYWORDS = (CPP_KEYWORDS + CSHARP_KEYWORDS + JSCRIPT_KEYWORDS + PERL_KEYWORDS + PYTHON_KEYWORDS + RUBY_KEYWORDS + SH_KEYWORDS); var PR_STRING = 'str'; var PR_KEYWORD = 'kwd'; var PR_COMMENT = 'com'; var PR_TYPE = 'typ'; var PR_LITERAL = 'lit'; var PR_PUNCTUATION = 'pun'; var PR_PLAIN = 'pln'; var PR_TAG = 'tag'; var PR_DECLARATION = 'dec'; var PR_SOURCE = 'src'; var PR_ATTRIB_NAME = 'atn'; var PR_ATTRIB_VALUE = 'atv'; var PR_NOCODE = 'nocode'; function isWordChar(ch) { return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); } function spliceArrayInto(inserted, container, containerPosition, countReplaced) { inserted.unshift(containerPosition, countReplaced || 0); try { container.splice.apply(container, inserted); } finally { inserted.splice(0, 2); } } var REGEXP_PRECEDER_PATTERN = function() { var preceders = ["!", "!=", "!==", "#", "%", "%=", "&", "&&", "&&=", "&=", "(", "*", "*=", "+=", ",", "-=", "->", "/", "/=", ":", "::", ";", "<", "<<", "<<=", "<=", "=", "==", "===", ">", ">=", ">>", ">>=", ">>>", ">>>=", "?", "@", "[", "^", "^=", "^^", "^^=", "{", "|", "|=", "||", "||=", "~", "break", "case", "continue", "delete", "do", "else", "finally", "instanceof", "return", "throw", "try", "typeof"]; var pattern = '(?:' + '(?:(?:^|[^0-9.])\\.{1,3})|' + '(?:(?:^|[^\\+])\\+)|' + '(?:(?:^|[^\\-])-)'; for (var i = 0; i < preceders.length; ++i) { var preceder = preceders[i]; if (isWordChar(preceder.charAt(0))) { pattern += '|\\b' + preceder; } else { pattern += '|' + preceder.replace(/([^=<>:&])/g, '\\$1'); } } pattern += '|^)\\s*$'; return new RegExp(pattern); } (); var pr_amp = /&/g; var pr_lt = /</g; var pr_gt = />/g; var pr_quot = /\"/g; function attribToHtml(str) { return str.replace(pr_amp, '&amp;').replace(pr_lt, '&lt;').replace(pr_gt, '&gt;').replace(pr_quot, '&quot;'); } function textToHtml(str) { return str.replace(pr_amp, '&amp;').replace(pr_lt, '&lt;').replace(pr_gt, '&gt;'); } var pr_ltEnt = /&lt;/g; var pr_gtEnt = /&gt;/g; var pr_aposEnt = /&apos;/g; var pr_quotEnt = /&quot;/g; var pr_ampEnt = /&amp;/g; var pr_nbspEnt = /&nbsp;/g; function htmlToText(html) { var pos = html.indexOf('&'); if (pos < 0) { return html; } for (--pos; (pos = html.indexOf('&#', pos + 1)) >= 0; ) { var end = html.indexOf(';', pos); if (end >= 0) { var num = html.substring(pos + 3, end); var radix = 10; if (num && num.charAt(0) === 'x') { num = num.substring(1); radix = 16; } var codePoint = parseInt(num, radix); if (!isNaN(codePoint)) { html = (html.substring(0, pos) + String.fromCharCode(codePoint) + html.substring(end + 1)); } } } return html.replace(pr_ltEnt, '<').replace(pr_gtEnt, '>').replace(pr_aposEnt, "'").replace(pr_quotEnt, '"').replace(pr_ampEnt, '&').replace(pr_nbspEnt, ' '); } function isRawContent(node) { return 'XMP' === node.tagName; } function normalizedHtml(node, out) { switch (node.nodeType) { case 1: var name = node.tagName.toLowerCase(); out.push('<', name); for (var i = 0; i < node.attributes.length; ++i) { var attr = node.attributes[i]; if (!attr.specified) { continue; } out.push(' '); normalizedHtml(attr, out); } out.push('>'); for (var child = node.firstChild; child; child = child.nextSibling) { normalizedHtml(child, out); } if (node.firstChild || !/^(?:br|link|img)$/.test(name)) { out.push('<\/', name, '>'); } break; case 2: out.push(node.name.toLowerCase(), '="', attribToHtml(node.value), '"'); break; case 3: case 4: out.push(textToHtml(node.nodeValue)); break; } } var PR_innerHtmlWorks = null; function getInnerHtml(node) { if (null === PR_innerHtmlWorks) { var testNode = document.createElement('PRE'); testNode.appendChild(document.createTextNode('<!DOCTYPE foo PUBLIC "foo bar">\n<foo />')); PR_innerHtmlWorks = !/</.test(testNode.innerHTML); } if (PR_innerHtmlWorks) { var content = node.innerHTML; if (isRawContent(node)) { content = textToHtml(content); } return content; } var out = []; for (var child = node.firstChild; child; child = child.nextSibling) { normalizedHtml(child, out); } return out.join(''); } function makeTabExpander(tabWidth) { var SPACES = ' '; var charInLine = 0; return function(plainText) { var out = null; var pos = 0; for (var i = 0, n = plainText.length; i < n; ++i) { var ch = plainText.charAt(i); switch (ch) { case '\t': if (!out) { out = []; } out.push(plainText.substring(pos, i)); var nSpaces = tabWidth - (charInLine % tabWidth); charInLine += nSpaces; for (; nSpaces >= 0; nSpaces -= SPACES.length) { out.push(SPACES.substring(0, nSpaces)); } pos = i + 1; break; case '\n': charInLine = 0; break; default: ++charInLine; } } if (!out) { return plainText; } out.push(plainText.substring(pos)); return out.join(''); }; } var pr_chunkPattern = /(?:[^<]+|<!--[\s\S]*?-->|<!\[CDATA\[([\s\S]*?)\]\]>|<\/?[a-zA-Z][^>]*>|<)/g; var pr_commentPrefix = /^<!--/; var pr_cdataPrefix = /^<\[CDATA\[/; var pr_brPrefix = /^<br\b/i; var pr_tagNameRe = /^<(\/?)([a-zA-Z]+)/; function extractTags(s) { var matches = s.match(pr_chunkPattern); var sourceBuf = []; var sourceBufLen = 0; var extractedTags = []; if (matches) { for (var i = 0, n = matches.length; i < n; ++i) { var match = matches[i]; if (match.length > 1 && match.charAt(0) === '<') { if (pr_commentPrefix.test(match)) { continue; } if (pr_cdataPrefix.test(match)) { sourceBuf.push(match.substring(9, match.length - 3)); sourceBufLen += match.length - 12; } else if (pr_brPrefix.test(match)) { sourceBuf.push('\n'); ++sourceBufLen; } else { if (match.indexOf(PR_NOCODE) >= 0 && isNoCodeTag(match)) { var name = match.match(pr_tagNameRe)[2]; var depth = 1; end_tag_loop: for (var j = i + 1; j < n; ++j) { var name2 = matches[j].match(pr_tagNameRe); if (name2 && name2[2] === name) { if (name2[1] === '/') { if (--depth === 0) { break end_tag_loop; } } else { ++depth; } } } if (j < n) { extractedTags.push(sourceBufLen, matches.slice(i, j + 1).join('')); i = j; } else { extractedTags.push(sourceBufLen, match); } } else { extractedTags.push(sourceBufLen, match); } } } else { var literalText = htmlToText(match); sourceBuf.push(literalText); sourceBufLen += literalText.length; } } } return { source: sourceBuf.join(''), tags: extractedTags }; } function isNoCodeTag(tag) { return !!tag.replace(/\s(\w+)\s*=\s*(?:\"([^\"]*)\"|'([^\']*)'|(\S+))/g, ' $1="$2$3$4"').match(/[cC][lL][aA][sS][sS]=\"[^\"]*\bnocode\b/); } function createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns) { var shortcuts = {}; (function() { var allPatterns = shortcutStylePatterns.concat(fallthroughStylePatterns); for (var i = allPatterns.length; --i >= 0; ) { var patternParts = allPatterns[i]; var shortcutChars = patternParts[3]; if (shortcutChars) { for (var c = shortcutChars.length; --c >= 0; ) { shortcuts[shortcutChars.charAt(c)] = patternParts; } } } })(); var nPatterns = fallthroughStylePatterns.length; var notWs = /\S/; return function(sourceCode, opt_basePos) { opt_basePos = opt_basePos || 0; var decorations = [opt_basePos, PR_PLAIN]; var lastToken = ''; var pos = 0; var tail = sourceCode; while (tail.length) { var style; var token = null; var match; var patternParts = shortcuts[tail.charAt(0)]; if (patternParts) { match = tail.match(patternParts[1]); token = match[0]; style = patternParts[0]; } else { for (var i = 0; i < nPatterns; ++i) { patternParts = fallthroughStylePatterns[i]; var contextPattern = patternParts[2]; if (contextPattern && !contextPattern.test(lastToken)) { continue; } match = tail.match(patternParts[1]); if (match) { token = match[0]; style = patternParts[0]; break; } } if (!token) { style = PR_PLAIN; token = tail.substring(0, 1); } } decorations.push(opt_basePos + pos, style); pos += token.length; tail = tail.substring(token.length); if (style !== PR_COMMENT && notWs.test(token)) { lastToken = token; } } return decorations; }; } var PR_MARKUP_LEXER = createSimpleLexer([], [[PR_PLAIN, /^[^<]+/, null], [PR_DECLARATION, /^<!\w[^>]*(?:>|$)/, null], [PR_COMMENT, /^<!--[\s\S]*?(?:-->|$)/, null], [PR_SOURCE, /^<\?[\s\S]*?(?:\?>|$)/, null], [PR_SOURCE, /^<%[\s\S]*?(?:%>|$)/, null], [PR_SOURCE, /^<(script|style|xmp)\b[^>]*>[\s\S]*?<\/\1\b[^>]*>/i, null], [PR_TAG, /^<\/?\w[^<>]*>/, null]]); var PR_SOURCE_CHUNK_PARTS = /^(<[^>]*>)([\s\S]*)(<\/[^>]*>)$/; function tokenizeMarkup(source) { var decorations = PR_MARKUP_LEXER(source); for (var i = 0; i < decorations.length; i += 2) { if (decorations[i + 1] === PR_SOURCE) { var start, end; start = decorations[i]; end = i + 2 < decorations.length ? decorations[i + 2] : source.length; var sourceChunk = source.substring(start, end); var match = sourceChunk.match(PR_SOURCE_CHUNK_PARTS); if (match) { decorations.splice(i, 2, start, PR_TAG, start + match[1].length, PR_SOURCE, start + match[1].length + (match[2] || '').length, PR_TAG); } } } return decorations; } var PR_TAG_LEXER = createSimpleLexer([[PR_ATTRIB_VALUE, /^\'[^\']*(?:\'|$)/, null, "'"], [PR_ATTRIB_VALUE, /^\"[^\"]*(?:\"|$)/, null, '"'], [PR_PUNCTUATION, /^[<>\/=]+/, null, '<>/=']], [[PR_TAG, /^[\w:\-]+/, /^</], [PR_ATTRIB_VALUE, /^[\w\-]+/, /^=/], [PR_ATTRIB_NAME, /^[\w:\-]+/, null], [PR_PLAIN, /^\s+/, null, ' \t\r\n']]); function splitTagAttributes(source, decorations) { for (var i = 0; i < decorations.length; i += 2) { var style = decorations[i + 1]; if (style === PR_TAG) { var start, end; start = decorations[i]; end = i + 2 < decorations.length ? decorations[i + 2] : source.length; var chunk = source.substring(start, end); var subDecorations = PR_TAG_LEXER(chunk, start); spliceArrayInto(subDecorations, decorations, i, 2); i += subDecorations.length - 2; } } return decorations; } function sourceDecorator(options) { var shortcutStylePatterns = [], fallthroughStylePatterns = []; if (options.tripleQuotedStrings) { shortcutStylePatterns.push([PR_STRING, /^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/, null, '\'"']); } else if (options.multiLineStrings) { shortcutStylePatterns.push([PR_STRING, /^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/, null, '\'"`']); } else { shortcutStylePatterns.push([PR_STRING, /^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/, null, '"\'']); } fallthroughStylePatterns.push([PR_PLAIN, /^(?:[^\'\"\`\/\#]+)/, null, ' \r\n']); if (options.hashComments) { shortcutStylePatterns.push([PR_COMMENT, /^#[^\r\n]*/, null, '#']); } if (options.cStyleComments) { fallthroughStylePatterns.push([PR_COMMENT, /^\/\/[^\r\n]*/, null]); fallthroughStylePatterns.push([PR_COMMENT, /^\/\*[\s\S]*?(?:\*\/|$)/, null]); } if (options.regexLiterals) { var REGEX_LITERAL = ('^/(?=[^/*])' + '(?:[^/\\x5B\\x5C]' + '|\\x5C[\\s\\S]' + '|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+' + '(?:/|$)'); fallthroughStylePatterns.push([PR_STRING, new RegExp(REGEX_LITERAL), REGEXP_PRECEDER_PATTERN]); } var keywords = wordSet(options.keywords); options = null; var splitStringAndCommentTokens = createSimpleLexer(shortcutStylePatterns, fallthroughStylePatterns); var styleLiteralIdentifierPuncRecognizer = createSimpleLexer([], [[PR_PLAIN, /^\s+/, null, ' \r\n'], [PR_PLAIN, /^[a-z_$@][a-z_$@0-9]*/i, null], [PR_LITERAL, /^0x[a-f0-9]+[a-z]/i, null], [PR_LITERAL, /^(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d+)(?:e[+\-]?\d+)?[a-z]*/i, null, '123456789'], [PR_PUNCTUATION, /^[^\s\w\.$@]+/, null]]); function splitNonStringNonCommentTokens(source, decorations) { for (var i = 0; i < decorations.length; i += 2) { var style = decorations[i + 1]; if (style === PR_PLAIN) { var start, end, chunk, subDecs; start = decorations[i]; end = i + 2 < decorations.length ? decorations[i + 2] : source.length; chunk = source.substring(start, end); subDecs = styleLiteralIdentifierPuncRecognizer(chunk, start); for (var j = 0, m = subDecs.length; j < m; j += 2) { var subStyle = subDecs[j + 1]; if (subStyle === PR_PLAIN) { var subStart = subDecs[j]; var subEnd = j + 2 < m ? subDecs[j + 2] : chunk.length; var token = source.substring(subStart, subEnd); if (token === '.') { subDecs[j + 1] = PR_PUNCTUATION; } else if (token in keywords) { subDecs[j + 1] = PR_KEYWORD; } else if (/^@?[A-Z][A-Z$]*[a-z][A-Za-z$]*$/.test(token)) { subDecs[j + 1] = token.charAt(0) === '@' ? PR_LITERAL : PR_TYPE; } } } spliceArrayInto(subDecs, decorations, i, 2); i += subDecs.length - 2; } } return decorations; } return function(sourceCode) { var decorations = splitStringAndCommentTokens(sourceCode); decorations = splitNonStringNonCommentTokens(sourceCode, decorations); return decorations; }; } var decorateSource = sourceDecorator({ keywords: ALL_KEYWORDS, hashComments: true, cStyleComments: true, multiLineStrings: true, regexLiterals: true }); function splitSourceNodes(source, decorations) { for (var i = 0; i < decorations.length; i += 2) { var style = decorations[i + 1]; if (style === PR_SOURCE) { var start, end; start = decorations[i]; end = i + 2 < decorations.length ? decorations[i + 2] : source.length; var subDecorations = decorateSource(source.substring(start, end)); for (var j = 0, m = subDecorations.length; j < m; j += 2) { subDecorations[j] += start; } spliceArrayInto(subDecorations, decorations, i, 2); i += subDecorations.length - 2; } } return decorations; } function splitSourceAttributes(source, decorations) { var nextValueIsSource = false; for (var i = 0; i < decorations.length; i += 2) { var style = decorations[i + 1]; var start, end; if (style === PR_ATTRIB_NAME) { start = decorations[i]; end = i + 2 < decorations.length ? decorations[i + 2] : source.length; nextValueIsSource = /^on|^style$/i.test(source.substring(start, end)); } else if (style === PR_ATTRIB_VALUE) { if (nextValueIsSource) { start = decorations[i]; end = i + 2 < decorations.length ? decorations[i + 2] : source.length; var attribValue = source.substring(start, end); var attribLen = attribValue.length; var quoted = (attribLen >= 2 && /^[\"\']/.test(attribValue) && attribValue.charAt(0) === attribValue.charAt(attribLen - 1)); var attribSource; var attribSourceStart; var attribSourceEnd; if (quoted) { attribSourceStart = start + 1; attribSourceEnd = end - 1; attribSource = attribValue; } else { attribSourceStart = start + 1; attribSourceEnd = end - 1; attribSource = attribValue.substring(1, attribValue.length - 1); } var attribSourceDecorations = decorateSource(attribSource); for (var j = 0, m = attribSourceDecorations.length; j < m; j += 2) { attribSourceDecorations[j] += attribSourceStart; } if (quoted) { attribSourceDecorations.push(attribSourceEnd, PR_ATTRIB_VALUE); spliceArrayInto(attribSourceDecorations, decorations, i + 2, 0); } else { spliceArrayInto(attribSourceDecorations, decorations, i, 2); } } nextValueIsSource = false; } } return decorations; } function decorateMarkup(sourceCode) { var decorations = tokenizeMarkup(sourceCode); decorations = splitTagAttributes(sourceCode, decorations); decorations = splitSourceNodes(sourceCode, decorations); decorations = splitSourceAttributes(sourceCode, decorations); return decorations; } function recombineTagsAndDecorations(sourceText, extractedTags, decorations) { var html = []; var outputIdx = 0; var openDecoration = null; var currentDecoration = null; var tagPos = 0; var decPos = 0; var tabExpander = makeTabExpander(PR_TAB_WIDTH); var adjacentSpaceRe = /([\r\n ]) /g; var startOrSpaceRe = /(^| ) /gm; var newlineRe = /\r\n?|\n/g; var trailingSpaceRe = /[ \r\n]$/; var lastWasSpace = true; function emitTextUpTo(sourceIdx) { if (sourceIdx > outputIdx) { if (openDecoration && openDecoration !== currentDecoration) { html.push('</span>'); openDecoration = null; } if (!openDecoration && currentDecoration) { openDecoration = currentDecoration; html.push('<span class="', openDecoration, '">'); } var htmlChunk = textToHtml(tabExpander(sourceText.substring(outputIdx, sourceIdx))).replace(lastWasSpace ? startOrSpaceRe : adjacentSpaceRe, '$1&nbsp;'); lastWasSpace = trailingSpaceRe.test(htmlChunk); html.push(htmlChunk.replace(newlineRe, '<br />')); outputIdx = sourceIdx; } } while (true) { var outputTag; if (tagPos < extractedTags.length) { if (decPos < decorations.length) { outputTag = extractedTags[tagPos] <= decorations[decPos]; } else { outputTag = true; } } else { outputTag = false; } if (outputTag) { emitTextUpTo(extractedTags[tagPos]); if (openDecoration) { html.push('</span>'); openDecoration = null; } html.push(extractedTags[tagPos + 1]); tagPos += 2; } else if (decPos < decorations.length) { emitTextUpTo(decorations[decPos]); currentDecoration = decorations[decPos + 1]; decPos += 2; } else { break; } } emitTextUpTo(sourceText.length); if (openDecoration) { html.push('</span>'); } return html.join(''); } var langHandlerRegistry = {}; function registerLangHandler(handler, fileExtensions) { for (var i = fileExtensions.length; --i >= 0; ) { var ext = fileExtensions[i]; if (!langHandlerRegistry.hasOwnProperty(ext)) { langHandlerRegistry[ext] = handler; } else if ('console' in window) { console.log('cannot override language handler %s', ext); } } } registerLangHandler(decorateSource, ['default-code']); registerLangHandler(decorateMarkup, ['default-markup', 'html', 'htm', 'xhtml', 'xml', 'xsl']); registerLangHandler(sourceDecorator({ keywords: CPP_KEYWORDS, hashComments: true, cStyleComments: true }), ['c', 'cc', 'cpp', 'cs', 'cxx', 'cyc']); registerLangHandler(sourceDecorator({ keywords: JAVA_KEYWORDS, cStyleComments: true }), ['java']); registerLangHandler(sourceDecorator({ keywords: SH_KEYWORDS, hashComments: true, multiLineStrings: true }), ['bsh', 'csh', 'sh']); registerLangHandler(sourceDecorator({ keywords: PYTHON_KEYWORDS, hashComments: true, multiLineStrings: true, tripleQuotedStrings: true }), ['cv', 'py']); registerLangHandler(sourceDecorator({ keywords: PERL_KEYWORDS, hashComments: true, multiLineStrings: true, regexLiterals: true }), ['perl', 'pl', 'pm']); registerLangHandler(sourceDecorator({ keywords: RUBY_KEYWORDS, hashComments: true, multiLineStrings: true, regexLiterals: true }), ['rb']); registerLangHandler(sourceDecorator({ keywords: JSCRIPT_KEYWORDS, cStyleComments: true, regexLiterals: true }), ['js']); function prettyPrintOne(sourceCodeHtml, opt_langExtension) { try { var sourceAndExtractedTags = extractTags(sourceCodeHtml); var source = sourceAndExtractedTags.source; var extractedTags = sourceAndExtractedTags.tags; if (!langHandlerRegistry.hasOwnProperty(opt_langExtension)) { opt_langExtension = /^\s*</.test(source) ? 'default-markup' : 'default-code'; } var decorations = langHandlerRegistry[opt_langExtension].call({}, source); return recombineTagsAndDecorations(source, extractedTags, decorations); } catch (e) { if ('console' in window) { console.log(e); console.trace(); } return sourceCodeHtml; } } function prettyPrint(opt_whenDone) { var isIE6 = _pr_isIE6(); var codeSegments = [document.getElementsByTagName('pre'), document.getElementsByTagName('code'), document.getElementsByTagName('xmp')]; var elements = []; for (var i = 0; i < codeSegments.length; ++i) { for (var j = 0; j < codeSegments[i].length; ++j) { elements.push(codeSegments[i][j]); } } codeSegments = null; var k = 0; function doWork() { var endTime = (PR_SHOULD_USE_CONTINUATION ? new Date().getTime() + 250 : Infinity); for (; k < elements.length && new Date().getTime() < endTime; k++) { var cs = elements[k]; if (cs.className && cs.className.indexOf('prettyprint') >= 0) { var langExtension = cs.className.match(/\blang-(\w+)\b/); if (langExtension) { langExtension = langExtension[1]; } var nested = false; for (var p = cs.parentNode; p; p = p.parentNode) { if ((p.tagName === 'pre' || p.tagName === 'code' || p.tagName === 'xmp') && p.className && p.className.indexOf('prettyprint') >= 0) { nested = true; break; } } if (!nested) { var content = getInnerHtml(cs); content = content.replace(/(?:\r\n?|\n)$/, ''); var newContent = prettyPrintOne(content, langExtension); if (!isRawContent(cs)) { cs.innerHTML = newContent; } else { var pre = document.createElement('PRE'); for (var i = 0; i < cs.attributes.length; ++i) { var a = cs.attributes[i]; if (a.specified) { var aname = a.name.toLowerCase(); if (aname === 'class') { pre.className = a.value; } else { pre.setAttribute(a.name, a.value); } } } pre.innerHTML = newContent; cs.parentNode.replaceChild(pre, cs); cs = pre; } if (isIE6 && cs.tagName === 'PRE') { var lineBreaks = cs.getElementsByTagName('br'); for (var j = lineBreaks.length; --j >= 0; ) { var lineBreak = lineBreaks[j]; lineBreak.parentNode.replaceChild(document.createTextNode('\r\n'), lineBreak); } } } } } if (k < elements.length) { setTimeout(doWork, 250); } else if (opt_whenDone) { opt_whenDone(); } } doWork(); } window['PR_normalizedHtml'] = normalizedHtml; window['prettyPrintOne'] = prettyPrintOne; window['prettyPrint'] = prettyPrint; window['PR'] = { 'createSimpleLexer': createSimpleLexer, 'registerLangHandler': registerLangHandler, 'sourceDecorator': sourceDecorator, 'PR_ATTRIB_NAME': PR_ATTRIB_NAME, 'PR_ATTRIB_VALUE': PR_ATTRIB_VALUE, 'PR_COMMENT': PR_COMMENT, 'PR_DECLARATION': PR_DECLARATION, 'PR_KEYWORD': PR_KEYWORD, 'PR_LITERAL': PR_LITERAL, 'PR_NOCODE': PR_NOCODE, 'PR_PLAIN': PR_PLAIN, 'PR_PUNCTUATION': PR_PUNCTUATION, 'PR_SOURCE': PR_SOURCE, 'PR_STRING': PR_STRING, 'PR_TAG': PR_TAG, 'PR_TYPE': PR_TYPE }; })();
diff --git a/askbot/skins/common/media/js/tag_selector.js b/askbot/skins/common/media/js/tag_selector.js
deleted file mode 100644
index be79a9b6..00000000
--- a/askbot/skins/common/media/js/tag_selector.js
+++ /dev/null
@@ -1,394 +0,0 @@
-var TagDetailBox = function(box_type){
- WrappedElement.call(this);
- this.box_type = box_type;
- this._is_blank = true;
- this._tags = new Array();
- this.wildcard = undefined;
-};
-inherits(TagDetailBox, WrappedElement);
-
-TagDetailBox.prototype.createDom = function(){
- this._element = this.makeElement('div');
- this._element.addClass('wildcard-tags');
- this._headline = this.makeElement('p');
- this._headline.html(gettext('Tag "<span></span>" matches:'));
- this._element.append(this._headline);
- this._tag_list_element = this.makeElement('ul');
- this._tag_list_element.addClass('tags');
- this._element.append(this._tag_list_element);
- this._footer = this.makeElement('p');
- this._footer.css('clear', 'left');
- this._element.append(this._footer);
- this._element.hide();
-};
-
-TagDetailBox.prototype.belongsTo = function(wildcard){
- return (this.wildcard === wildcard);
-};
-
-TagDetailBox.prototype.isBlank = function(){
- return this._is_blank;
-};
-
-TagDetailBox.prototype.clear = function(){
- if (this.isBlank()){
- return;
- }
- this._is_blank = true;
- this.getElement().hide();
- this.wildcard = null;
- $.each(this._tags, function(idx, item){
- item.dispose();
- });
- this._tags = new Array();
-};
-
-TagDetailBox.prototype.loadTags = function(wildcard, callback){
- var me = this;
- $.ajax({
- type: 'GET',
- dataType: 'json',
- cache: false,
- url: askbot['urls']['get_tags_by_wildcard'],
- data: { wildcard: wildcard },
- success: callback,
- failure: function(){ me._loading = false; }
- });
-};
-
-TagDetailBox.prototype.renderFor = function(wildcard){
- var me = this;
- if (this._loading === true){
- return;
- }
- this._loading = true;
- this.loadTags(
- wildcard,
- function(data, text_status, xhr){
- me._tag_names = data['tag_names'];
- if (data['tag_count'] > 0){
- var wildcard_display = wildcard.replace(/\*$/, '&#10045;');
- me._headline.find('span').html(wildcard_display);
- $.each(me._tag_names, function(idx, name){
- var tag = new Tag();
- tag.setName(name);
- tag.setUrlParams(name)
- //tag.setLinkable(false);
- me._tags.push(tag);
- me._tag_list_element.append(tag.getElement());
- });
- me._is_blank = false;
- me.wildcard = wildcard;
- var tag_count = data['tag_count'];
- if (tag_count > 20){
- var fmts = gettext('and %s more, not shown...');
- var footer_text = interpolate(fmts, [tag_count - 20]);
- me._footer.html(footer_text);
- me._footer.show();
- } else {
- me._footer.hide();
- }
- me._element.show();
- } else {
- me.clear();
- }
- me._loading = false;
- }
- );
-}
-
-function pickedTags(){
-
- var interestingTags = {};
- var ignoredTags = {};
- var subscribedTags = {};
- var interestingTagDetailBox = new TagDetailBox('interesting');
- var ignoredTagDetailBox = new TagDetailBox('ignored');
- var subscribedTagDetailBox = new TagDetailBox('subscribed');
-
- var sendAjax = function(tagnames, reason, action, callback){
- var url = '';
- if (action == 'add') {
- if (reason == 'good') {
- url = askbot['urls']['mark_interesting_tag'];
- } else if (reason == 'bad') {
- url = askbot['urls']['mark_ignored_tag'];
- } else {
- url = askbot['urls']['mark_subscribed_tag'];
- }
- }
- else {
- url = askbot['urls']['unmark_tag'];
- }
-
- var call_settings = {
- type:'POST',
- url:url,
- data: JSON.stringify({tagnames: tagnames}),
- dataType: 'json'
- };
- if (callback !== false){
- call_settings.success = callback;
- }
- $.ajax(call_settings);
- };
-
- var unpickTag = function(from_target, tagname, reason, send_ajax){
- //send ajax request to delete tag
- var deleteTagLocally = function(){
- from_target[tagname].remove();
- delete from_target[tagname];
- };
- if (send_ajax){
- sendAjax(
- [tagname],
- reason,
- 'remove',
- function(){
- deleteTagLocally();
- liveSearch.refresh();
- }
- );
- }
- else {
- deleteTagLocally();
- }
- };
-
- var getTagList = function(reason){
- var base_selector = '.marked-tags';
- if (reason === 'good') {
- var extra_selector = '.interesting';
- } else if (reason === 'bad') {
- var extra_selector = '.ignored';
- } else if (reason === 'subscribed') {
- var extra_selector = '.subscribed';
- }
- return $(base_selector + extra_selector);
- };
-
- var getWildcardTagDetailBox = function(reason){
- if (reason === 'good') {
- return interestingTagDetailBox;
- } else if (reason === 'bad') {
- return ignoredTagDetailBox;
- } else if (reason === 'subscribed') {
- return subscribedTagDetailBox;
- }
- };
-
- var handleWildcardTagClick = function(tag_name, reason){
- var detail_box = getWildcardTagDetailBox(reason);
- var tag_box = getTagList(reason);
- if (detail_box.isBlank()){
- detail_box.renderFor(tag_name);
- } else if (detail_box.belongsTo(tag_name)){
- detail_box.clear();//toggle off
- } else {
- detail_box.clear();//redraw with new data
- detail_box.renderFor(tag_name);
- }
- if (!detail_box.inDocument()){
- tag_box.after(detail_box.getElement());
- detail_box.enterDocument();
- }
- };
-
- var renderNewTags = function(
- clean_tag_names,
- reason,
- to_target,
- to_tag_container
- ){
- $.each(clean_tag_names, function(idx, tag_name){
- var tag = new Tag();
- tag.setName(tag_name);
- tag.setDeletable(true);
-
- if (/\*$/.test(tag_name)){
- tag.setLinkable(false);
- var detail_box = getWildcardTagDetailBox(reason);
- tag.setHandler(function(){
- handleWildcardTagClick(tag_name, reason);
- if (detail_box.belongsTo(tag_name)){
- detail_box.clear();
- }
- });
- var delete_handler = function(){
- unpickTag(to_target, tag_name, reason, true);
- if (detail_box.belongsTo(tag_name)){
- detail_box.clear();
- }
- }
- } else {
- var delete_handler = function(){
- unpickTag(to_target, tag_name, reason, true);
- }
- }
-
- tag.setDeleteHandler(delete_handler);
- var tag_element = tag.getElement();
- to_tag_container.append(tag_element);
- to_target[tag_name] = tag_element;
- });
- };
-
- var handlePickedTag = function(reason){
- var to_target = interestingTags;
- var from_target = ignoredTags;
- var to_tag_container;
- if (reason === 'bad') {
- var input_sel = '#ignoredTagInput';
- to_target = ignoredTags;
- from_target = interestingTags;
- to_tag_container = $('div .tags.ignored');
- } else if (reason === 'good') {
- var input_sel = '#interestingTagInput';
- to_tag_container = $('div .tags.interesting');
- } else if (reason === 'subscribed') {
- var input_sel = '#subscribedTagInput';
- to_target = subscribedTags;
- to_tag_container = $('div .tags.subscribed');
- } else {
- return;
- }
-
- var tagnames = getUniqueWords($(input_sel).attr('value'));
-
- if (reason !== 'subscribed') {//for "subscribed" we do not remove
- $.each(tagnames, function(idx, tagname) {
- if (tagname in from_target) {
- unpickTag(from_target, tagname, reason, false);
- }
- });
- }
-
- var clean_tagnames = [];
- $.each(tagnames, function(idx, tagname){
- if (!(tagname in to_target)){
- clean_tagnames.push(tagname);
- }
- });
-
- if (clean_tagnames.length > 0){
- //send ajax request to pick this tag
-
- sendAjax(
- clean_tagnames,
- reason,
- 'add',
- function(){
- renderNewTags(
- clean_tagnames,
- reason,
- to_target,
- to_tag_container
- );
- $(input_sel).val('');
- liveSearch.refresh();
- }
- );
- }
- };
-
- var collectPickedTags = function(section){
- if (section === 'interesting') {
- var reason = 'good';
- var tag_store = interestingTags;
- } else if (section === 'ignored') {
- var reason = 'bad';
- var tag_store = ignoredTags;
- } else if (section === 'subscribed') {
- var reason = 'subscribed';
- var tag_store = subscribedTags;
- } else {
- return;
- }
- $('.' + section + '.tags.marked-tags .tag-left').each(
- function(i,item){
- var tag = new Tag();
- tag.decorate($(item));
- tag.setDeleteHandler(function(){
- unpickTag(
- tag_store,
- tag.getName(),
- reason,
- true
- )
- });
- if (tag.isWildcard()){
- tag.setHandler(function(){
- handleWildcardTagClick(tag.getName(), reason)
- });
- }
- tag_store[tag.getName()] = $(item);
- }
- );
- };
-
- var setupTagFilterControl = function(control_type){
- $('#' + control_type + 'TagFilterControl input')
- .unbind('click')
- .click(function(){
- $.ajax({
- type: 'POST',
- dataType: 'json',
- cache: false,
- url: askbot['urls']['set_tag_filter_strategy'],
- data: {
- filter_type: control_type,
- filter_value: $(this).val()
- },
- success: function(){
- liveSearch.refresh();
- }
- });
- });
- };
-
- var getResultCallback = function(reason){
- return function(){
- handlePickedTag(reason);
- };
- };
-
- return {
- init: function(){
- collectPickedTags('interesting');
- collectPickedTags('ignored');
- collectPickedTags('subscribed');
- setupTagFilterControl('display');
- setupTagFilterControl('email');
- var ac = new AutoCompleter({
- url: askbot['urls']['get_tag_list'],
- preloadData: true,
- minChars: 1,
- useCache: true,
- matchInside: true,
- maxCacheLength: 100,
- delay: 10
- });
-
-
- var interestingTagAc = $.extend(true, {}, ac);
- interestingTagAc.decorate($('#interestingTagInput'));
- interestingTagAc.setOption('onItemSelect', getResultCallback('good'));
-
- var ignoredTagAc = $.extend(true, {}, ac);
- ignoredTagAc.decorate($('#ignoredTagInput'));
- ignoredTagAc.setOption('onItemSelect', getResultCallback('bad'));
-
- var subscribedTagAc = $.extend(true, {}, ac);
- subscribedTagAc.decorate($('#subscribedTagInput'));
- subscribedTagAc.setOption('onItemSelect', getResultCallback('subscribed'));
-
- $("#interestingTagAdd").click(getResultCallback('good'));
- $("#ignoredTagAdd").click(getResultCallback('bad'));
- $("#subscribedTagAdd").click(getResultCallback('subscribed'));
- }
- };
-}
-
-$(document).ready( function(){
- pickedTags().init();
-});
diff --git a/askbot/skins/common/media/js/user.js b/askbot/skins/common/media/js/user.js
deleted file mode 100644
index ad0b8365..00000000
--- a/askbot/skins/common/media/js/user.js
+++ /dev/null
@@ -1,854 +0,0 @@
-var setup_inbox = function(){
-
- var getSelected = function(){
-
- var id_list = new Array();
- var elements = $('#responses input:checked').parent();
-
- elements.each(function(index, element){
- var id = $(element).attr('id').replace(/^re_/,'');
- id_list.push(id);
- });
-
- if (id_list.length === 0){
- alert(gettext('Please select at least one item'));
- }
-
- return {id_list: id_list, elements: elements};
- };
-
- var submit = function(id_list, elements, action_type){
- if (action_type == 'delete' || action_type == 'mark_new' || action_type == 'mark_seen' || action_type == 'remove_flag' || action_type == 'delete_post'){
- $.ajax({
- type: 'POST',
- cache: false,
- dataType: 'json',
- data: JSON.stringify({memo_list: id_list, action_type: action_type}),
- url: askbot['urls']['manageInbox'],
- success: function(response_data){
- if (response_data['success'] == true){
- if (action_type == 'delete' || action_type == 'remove_flag' || action_type == 'delete_post'){
- elements.remove();
- }
- else if (action_type == 'mark_new'){
- elements.addClass('highlight');
- elements.addClass('new');
- elements.removeClass('seen');
- }
- else if (action_type == 'mark_seen'){
- elements.removeClass('highlight');
- elements.addClass('seen');
- elements.removeClass('new');
- }
- }
- else {
- showMessage($('#responses'), response_data['message']);
- }
- }
- });
- }
- };
-
- var startAction = function(action_type){
- var data = getSelected();
- if (data['id_list'].length === 0){
- return;
- }
- if (action_type == 'delete'){
- msg = ngettext('Delete this notification?',
- 'Delete these notifications?', data['id_list'].length);
- if (confirm(msg) === false){
- return;
- }
- }
- if (action_type == 'close'){
- msg = ngettext('Close this entry?',
- 'Close these entries?', data['id_list'].length);
- if (confirm(msg) === false){
- return;
- }
- }
- if (action_type == 'remove_flag'){
- msg = ngettext(
- 'Remove all flags and approve this entry?',
- 'Remove all flags and approve these entries?',
- data['id_list'].length
- );
- if (confirm(msg) === false){
- return;
- }
- }
- submit(data['id_list'], data['elements'], action_type);
- };
- setupButtonEventHandlers($('#re_mark_seen'), function(){startAction('mark_seen')});
- setupButtonEventHandlers($('#re_mark_new'), function(){startAction('mark_new')});
- setupButtonEventHandlers($('#re_dismiss'), function(){startAction('delete')});
- setupButtonEventHandlers($('#re_remove_flag'), function(){startAction('remove_flag')});
- //setupButtonEventHandlers($('#re_close'), function(){startAction('close')});
- setupButtonEventHandlers(
- $('#sel_all'),
- function(){
- setCheckBoxesIn('#responses .new', true);
- setCheckBoxesIn('#responses .seen', true);
- }
- );
- setupButtonEventHandlers(
- $('#sel_seen'),
- function(){
- setCheckBoxesIn('#responses .seen', true);
- }
- );
- setupButtonEventHandlers(
- $('#sel_new'),
- function(){
- setCheckBoxesIn('#responses .new', true);
- }
- );
- setupButtonEventHandlers(
- $('#sel_none'),
- function(){
- setCheckBoxesIn('#responses .new', false);
- setCheckBoxesIn('#responses .seen', false);
- }
- );
-
- var reject_post_dialog = new RejectPostDialog();
- reject_post_dialog.decorate($('#reject-edit-modal'));
- setupButtonEventHandlers(
- $('#re_delete_post'),
- function(){
- var data = getSelected();
- if (data['id_list'].length === 0){
- return;
- }
- reject_post_dialog.setSelectedEditData(data);
- reject_post_dialog.show();
- }
- );
- //setupButtonEventHandlers($('.re_expand'),
- // function(e){
- // e.preventDefault();
- // var re_snippet = $(this).find(".re_snippet:first")
- // var re_content = $(this).find(".re_content:first")
- // $(re_snippet).slideToggle();
- // $(re_content).slideToggle();
- // }
- //);
-};
-
-var setup_badge_details_toggle = function(){
- $('.badge-context-toggle').each(function(idx, elem){
- var context_list = $(elem).parent().next('ul');
- if (context_list.children().length > 0){
- $(elem).addClass('active');
- var toggle_display = function(){
- if (context_list.css('display') == 'none'){
- $('.badge-context-list').hide();
- context_list.show();
- } else {
- context_list.hide();
- }
- };
- $(elem).click(toggle_display);
- }
- });
-};
-
-/**
- * @constructor
- * manages post/edit reject reasons
- * in the post moderation view
- */
-var RejectPostDialog = function(){
- WrappedElement.call(this);
- this._selected_edit_ids = null;
- this._selected_reason_id = null;
- this._state = null;//'select', 'preview', 'add-new'
-};
-inherits(RejectPostDialog, WrappedElement);
-
-RejectPostDialog.prototype.setSelectedEditData = function(data){
- this._selected_edit_data = data;
-};
-
-RejectPostDialog.prototype.setState = function(state){
- this._state = state;
- this.clearErrors();
- if (this._element){
- this._selector.hide();
- this._adder.hide();
- this._previewer.hide();
- if (state === 'select'){
- this._selector.show();
- } else if (state === 'preview'){
- this._previewer.show();
- } else if (state === 'add-new'){
- this._adder.show();
- }
- }
-};
-
-RejectPostDialog.prototype.show = function(){
- $(this._element).modal('show');
-};
-
-RejectPostDialog.prototype.hide = function(){
- $(this._element).modal('hide');
-};
-
-RejectPostDialog.prototype.resetInputs = function(){
- if (this._title_input){
- this._title_input.reset();
- }
- if (this._details_input){
- this._details_input.reset();
- }
- var selected = this._element.find('.selected');
- selected.removeClass('selected');
-};
-
-RejectPostDialog.prototype.clearErrors = function(){
- var error = this._element.find('.alert');
- error.remove();
-};
-
-RejectPostDialog.prototype.makeAlertBox = function(errors){
- //construct the alert box
- var alert_box = new AlertBox();
- alert_box.setClass('alert-error');
- if (typeof errors === "string"){
- alert_box.setText(errors);
- } else if (errors.constructor === [].constructor){
- if (errors.length > 1){
- alert_box.setContent(
- '<div>' +
- gettext('Looks there are some things to fix:') +
- '</div>'
- )
- var list = this.makeElement('ul');
- $.each(errors, function(idx, item){
- list.append('<li>' + item + '</li>');
- });
- alert_box.addContent(list);
- } else if (errors.length == 1){
- alert_box.setContent(errors[0]);
- } else if (errors.length == 0){
- return;
- }
- } else if ('html' in errors){
- alert_box.setContent(errors);
- } else {
- return;//don't know what to do
- }
- return alert_box;
-};
-
-RejectPostDialog.prototype.setAdderErrors = function(errors){
- //clear previous errors
- this.clearErrors();
- var alert_box = this.makeAlertBox(errors);
- this._element
- .find('#reject-edit-modal-add-new .modal-body')
- .prepend(alert_box.getElement());
-};
-
-RejectPostDialog.prototype.setSelectorErrors = function(errors){
- this.clearErrors();
- var alert_box = this.makeAlertBox(errors);
- this._element
- .find('#reject-edit-modal-select .modal-body')
- .prepend(alert_box.getElement());
-};
-
-RejectPostDialog.prototype.setErrors = function(errors){
- this.clearErrors();
- var alert_box = this.makeAlertBox(errors);
- var current_state = this._state;
- this._element
- .find('#reject-edit-modal-' + current_state + ' .modal-body')
- .prepend(alert_box.getElement());
-};
-
-RejectPostDialog.prototype.addSelectableReason = function(data){
- var id = data['reason_id'];
- var title = data['title'];
- var details = data['details'];
- this._select_box.addItem(id, title, details);
-};
-
-RejectPostDialog.prototype.startSavingReason = function(callback){
-
- var title_input = this._title_input;
- var details_input = this._details_input;
-
- var errors = [];
- if (title_input.isBlank()){
- errors.push(gettext('Please provide description.'));
- }
- if (details_input.isBlank()){
- errors.push(gettext('Please provide details.'));
- }
-
- if (errors.length > 0){
- this.setAdderErrors(errors);
- return;//just show errors and quit
- }
-
- var data = {
- title: title_input.getVal(),
- details: details_input.getVal()
- };
- if (this._selected_reason_id){
- data['reason_id'] = this._selected_reason_id;
- }
-
- var me = this;
-
- $.ajax({
- type: 'POST',
- dataType: 'json',
- cache: false,
- url: askbot['urls']['save_post_reject_reason'],
- data: data,
- success: function(data){
- if (data['success']){
- //show current reason data and focus on it
- if (callback){
- callback(data);
- } else {
- me.addSelectableReason(data);
- me.setState('select');
- }
- } else {
- me.setAdderErrors(data['message']);
- }
- }
- });
-};
-
-RejectPostDialog.prototype.rejectPost = function(reason_id){
- var me = this;
- var memos = this._selected_edit_data['elements'];
- var memo_ids = this._selected_edit_data['id_list'];
- var data = {
- reject_reason_id: reason_id,
- memo_list: memo_ids,
- action_type: 'delete_post'
- }
- $.ajax({
- type: 'POST',
- dataType: 'json',
- cache: false,
- data: JSON.stringify(data),
- url: askbot['urls']['manageInbox'],
- success: function(data){
- if (data['success']){
- memos.remove();
- me.hide();
- } else {
- //only fatal errors here
- me.setErrors(data['message']);
- }
- }
- });
-};
-
-RejectPostDialog.prototype.setPreviewerData = function(data){
- this._selected_reason_id = data['id'];
- this._element.find('.selected-reason-title').html(data['title']);
- this._element.find('.selected-reason-details').html(data['details']);
-};
-
-RejectPostDialog.prototype.startEditingReason = function(){
- var title = this._element.find('.selected-reason-title').html();
- var details = this._element.find('.selected-reason-details').html();
- this._title_input.setVal(title);
- this._details_input.setVal(details);
- this.setState('add-new');
-};
-
-RejectPostDialog.prototype.resetSelectedReasonId = function(){
- this._selected_reason_id = null;
-};
-
-RejectPostDialog.prototype.getSelectedReasonId = function(){
- return this._selected_reason_id;
-};
-
-RejectPostDialog.prototype.startDeletingReason = function(){
- var select_box = this._select_box;
- var data = select_box.getSelectedItemData();
- var reason_id = data['id'];
- var me = this;
- if (data['id']){
- $.ajax({
- type: 'POST',
- dataType: 'json',
- cache: false,
- url: askbot['urls']['delete_post_reject_reason'],
- data: {reason_id: reason_id},
- success: function(data){
- if (data['success']){
- select_box.removeItem(reason_id);
- } else {
- me.setSelectorErrors(data['message']);
- }
- }
- });
- } else {
- me.setSelectorErrors(
- gettext('A reason must be selected to delete one.')
- )
- }
-};
-
-RejectPostDialog.prototype.decorate = function(element){
- this._element = element;
- //set default state according to the # of available reasons
- this._selector = $(element).find('#reject-edit-modal-select');
- this._adder = $(element).find('#reject-edit-modal-add-new');
- this._previewer = $(element).find('#reject-edit-modal-preview');
- if (this._selector.find('li').length > 0){
- this.setState('select');
- this.resetInputs();
- } else {
- this.setState('add-new');
- this.resetInputs();
- }
-
- $(this._element).find('.dropdown-toggle').dropdown();
-
- var select_box = new SelectBox();
- select_box.decorate($(this._selector.find('.select-box')));
- this._select_box = select_box;
-
- //setup tipped-inputs
- var reject_title_input = $(this._element).find('input');
- var title_input = new TippedInput();
- title_input.decorate($(reject_title_input));
- this._title_input = title_input;
-
- var reject_details_input = $(this._element)
- .find('textarea.reject-reason-details');
-
- var details_input = new TippedInput();
- details_input.decorate($(reject_details_input));
- this._details_input = details_input;
-
- var me = this;
- setupButtonEventHandlers(
- element.find('.cancel, .modal-header .close'),
- function() {
- me.hide();
- me.clearErrors();
- me.resetInputs();
- me.resetSelectedReasonId();
- me.setState('select');
- }
- );
-
- setupButtonEventHandlers(
- $(this._element).find('.save-reason'),
- function(){ me.startSavingReason() }
- );
-
- setupButtonEventHandlers(
- $(this._element).find('.save-reason-and-reject'),
- function(){
- me.startSavingReason(
- function(data){
- me.rejectPost(data['reason_id']);
- }
- );
- }
- );
-
- setupButtonEventHandlers(
- $(this._element).find('.reject'),
- function(){
- me.rejectPost(me.getSelectedReasonId());
- }
- );
-
- setupButtonEventHandlers(
- element.find('.select-other-reason'),
- function(){
- me.resetInputs();
- me.setState('select');
- }
- )
-
- setupButtonEventHandlers(
- element.find('.add-new-reason'),
- function(){
- me.resetSelectedReasonId();
- me.resetInputs();
- me.setState('add-new')
- }
- );
-
- setupButtonEventHandlers(
- element.find('.select-this-reason'),
- function(){
- var data = select_box.getSelectedItemData();
- if (data['id']){
- me.setState('preview');
- me.setPreviewerData(data);
- } else {
- me.setSelectorErrors(
- gettext('A reason must be selected to reject post.')
- )
- }
- }
- );
-
- setupButtonEventHandlers(
- element.find('.edit-reason'),
- function(){
- me.startEditingReason();
- }
- );
-
- setupButtonEventHandlers(
- element.find('.delete-this-reason'),
- function(){
- me.startDeletingReason();
- }
- )
-};
-
-/**
- * @constructor
- * allows to follow/unfollow users
- */
-var FollowUser = function(){
- WrappedElement.call(this);
- this._user_id = null;
- this._user_name = null;
-};
-inherits(FollowUser, WrappedElement);
-
-/**
- * @param {string} user_name
- */
-FollowUser.prototype.setUserName = function(user_name){
- this._user_name = user_name;
-};
-
-FollowUser.prototype.decorate = function(element){
- this._element = element;
- this._user_id = parseInt(element.attr('id').split('-').pop());
- this._available_action = element.children().hasClass('follow') ? 'follow':'unfollow';
- var me = this;
- setupButtonEventHandlers(this._element, function(){ me.go() });
-};
-
-FollowUser.prototype.go = function(){
- if (askbot['data']['userIsAuthenticated'] === false){
- var message = gettext('Please <a href="%(signin_url)s">signin</a> to follow %(username)s');
- var message_data = {
- signin_url: askbot['urls']['user_signin'] + '?next=' + window.location.href,
- username: this._user_name
- }
- message = interpolate(message, message_data, true);
- showMessage(this._element, message);
- return;
- }
- var user_id = this._user_id;
- if (this._available_action === 'follow'){
- var url = askbot['urls']['follow_user'];
- } else {
- var url = askbot['urls']['unfollow_user'];
- }
- var me = this;
- $.ajax({
- type: 'POST',
- cache: false,
- dataType: 'json',
- url: url.replace('{{userId}}', user_id),
- success: function(){ me.toggleState() }
- });
-};
-
-FollowUser.prototype.toggleState = function(){
- if (this._available_action === 'follow'){
- this._available_action = 'unfollow';
- var unfollow_div = document.createElement('div');
- unfollow_div.setAttribute('class', 'unfollow');
- var red_div = document.createElement('div');
- red_div.setAttribute('class', 'unfollow-red');
- red_div.innerHTML = interpolate(gettext('unfollow %s'), [this._user_name]);
- var green_div = document.createElement('div');
- green_div.setAttribute('class', 'unfollow-green');
- green_div.innerHTML = interpolate(gettext('following %s'), [this._user_name]);
- unfollow_div.appendChild(red_div);
- unfollow_div.appendChild(green_div);
- this._element.html(unfollow_div);
- } else {
- var follow_div = document.createElement('div');
- follow_div.innerHTML = interpolate(gettext('follow %s'), [this._user_name]);
- follow_div.setAttribute('class', 'follow');
- this._available_action = 'follow';
- this._element.html(follow_div);
- }
-};
-
-/**
- * @constructor
- * @param {string} name
- */
-var UserGroup = function(name){
- WrappedElement.call(this);
- this._name = name;
- this._content = null;
-};
-inherits(UserGroup, WrappedElement);
-
-UserGroup.prototype.getDeleteHandler = function(){
- var group_name = this._name;
- var me = this;
- var groups_container = me._groups_container;
- return function(){
- var data = {
- user_id: askbot['data']['viewUserId'],
- group_name: group_name,
- action: 'remove'
- };
- $.ajax({
- type: 'POST',
- dataType: 'json',
- data: data,
- cache: false,
- url: askbot['urls']['edit_group_membership'],
- success: function(){
- groups_container.removeGroup(me);
- }
- });
- };
-};
-
-UserGroup.prototype.setContent = function(content){
- this._content = content;
-};
-
-UserGroup.prototype.getName = function(){
- return this._name;
-};
-
-UserGroup.prototype.setGroupsContainer = function(container){
- this._groups_container = container;
-};
-
-UserGroup.prototype.decorate = function(element){
- this._element = element;
- this._name = $.trim(element.find('a').html());
- var deleter = new DeleteIcon();
- deleter.setHandler(this.getDeleteHandler());
- deleter.setContent(gettext('Remove'));
- this._element.find('td:last').append(deleter.getElement());
- this._delete_icon = deleter;
-};
-
-UserGroup.prototype.createDom = function(){
- var element = this.makeElement('tr');
- element.html(this._content);
- this._element = element;
- this.decorate(element);
-};
-
-UserGroup.prototype.dispose = function(){
- this._delete_icon.dispose();
- this._element.remove();
-};
-
-/**
- * @constructor
- */
-var GroupsContainer = function(){
- WrappedElement.call(this);
-};
-inherits(GroupsContainer, WrappedElement);
-
-GroupsContainer.prototype.decorate = function(element){
- this._element = element;
- var groups = [];
- var group_names = [];
- var me = this;
- //collect list of groups
- $.each(element.find('tr'), function(idx, li){
- var group = new UserGroup();
- group.setGroupsContainer(me);
- group.decorate($(li));
- groups.push(group);
- group_names.push(group.getName());
- });
- this._groups = groups;
- this._group_names = group_names;
-};
-
-GroupsContainer.prototype.addGroup = function(group_data){
- var group_name = group_data['name'];
- if ($.inArray(group_name, this._group_names) > -1){
- return;
- }
- var group = new UserGroup(group_name);
- group.setContent(group_data['html']);
- group.setGroupsContainer(this);
- this._groups.push(group);
- this._group_names.push(group_name);
- this._element.append(group.getElement());
-};
-
-GroupsContainer.prototype.removeGroup = function(group){
- var idx = $.inArray(group, this._groups);
- if (idx === -1){
- return;
- }
- this._groups.splice(idx, 1);
- this._group_names.splice(idx, 1);
- group.dispose();
-};
-
-var GroupAdderWidget = function(){
- WrappedElement.call(this);
- this._state = 'display';//display or edit
-};
-inherits(GroupAdderWidget, WrappedElement);
-
-/**
- * @param {string} state
- */
-GroupAdderWidget.prototype.setState = function(state){
- if (state === 'display'){
- this._element.html(gettext('add group'));
- this._input.hide();
- this._input.val('');
- this._button.hide();
- } else if (state === 'edit'){
- this._element.html(gettext('cancel'));
- this._input.show();
- this._input.focus();
- this._button.show();
- } else {
- return;
- }
- this._state = state;
-};
-
-GroupAdderWidget.prototype.getValue = function(){
- return this._input.val();
-};
-
-GroupAdderWidget.prototype.addGroup = function(group_data){
- this._groups_container.addGroup(group_data);
-};
-
-GroupAdderWidget.prototype.getAddGroupHandler = function(){
- var me = this;
- return function(){
- var group_name = me.getValue();
- var data = {
- group_name: group_name,
- user_id: askbot['data']['viewUserId'],
- action: 'add'
- };
- $.ajax({
- type: 'POST',
- dataType: 'json',
- data: data,
- cache: false,
- url: askbot['urls']['edit_group_membership'],
- success: function(data){
- if (data['success'] == true){
- me.addGroup(data);
- me.setState('display');
- } else {
- var message = data['message'];
- showMessage(me.getElement(), message, 'after');
- }
- }
- });
- };
-};
-
-GroupAdderWidget.prototype.setGroupsContainer = function(container){
- this._groups_container = container;
-};
-
-GroupAdderWidget.prototype.toggleState = function(){
- if (this._state === 'display'){
- this.setState('edit');
- } else if (this._state === 'edit'){
- this.setState('display');
- }
-};
-
-GroupAdderWidget.prototype.decorate = function(element){
- this._element = element;
- var input = this.makeElement('input');
- this._input = input;
-
- var groupsAc = new AutoCompleter({
- url: askbot['urls']['get_groups_list'],
- preloadData: true,
- minChars: 1,
- useCache: true,
- matchInside: false,
- maxCacheLength: 100,
- delay: 10
- });
- groupsAc.decorate(input);
-
- var button = this.makeElement('button');
- button.html(gettext('add'));
- this._button = button;
- element.before(input);
- input.after(button);
- this.setState('display');
- setupButtonEventHandlers(button, this.getAddGroupHandler());
- var me = this;
- setupButtonEventHandlers(
- element,
- function(){ me.toggleState() }
- );
-};
-
-/**
- * @constructor
- * allows editing user groups
- */
-var UserGroupsEditor = function(){
- WrappedElement.call(this);
-};
-inherits(UserGroupsEditor, WrappedElement);
-
-UserGroupsEditor.prototype.decorate = function(element){
- this._element = element;
- var add_link = element.find('#add-group');
- var adder = new GroupAdderWidget();
- adder.decorate(add_link);
-
- var groups_container = new GroupsContainer();
- groups_container.decorate(element.find('#groups-list'));
- adder.setGroupsContainer(groups_container);
- //todo - add group deleters
-};
-
-(function(){
- var fbtn = $('.follow-user-toggle');
- if (fbtn.length === 1){
- var follow_user = new FollowUser();
- follow_user.decorate(fbtn);
- follow_user.setUserName(askbot['data']['viewUserName']);
- }
- if (askbot['data']['userId'] !== askbot['data']['viewUserId']) {
- if (askbot['data']['userIsAdminOrMod']){
- var group_editor = new UserGroupsEditor();
- group_editor.decorate($('#user-groups'));
- } else {
- $('#add-group').remove();
- }
- } else {
- $('#add-group').remove();
- }
-})();
diff --git a/askbot/skins/common/media/js/utils.js b/askbot/skins/common/media/js/utils.js
deleted file mode 100644
index d04a3cdb..00000000
--- a/askbot/skins/common/media/js/utils.js
+++ /dev/null
@@ -1,1268 +0,0 @@
-//var $, scriptUrl, askbotSkin
-var mediaUrl = function(resource){
- return askbot['settings']['static_url'] + askbotSkin + '/' + resource;
-};
-
-var cleanUrl = function(url){
- var re = new RegExp('//', 'g');
- return url.replace(re, '/');
-};
-
-var copyAltToTitle = function(sel){
- sel.attr('title', sel.attr('alt'));
-};
-
-var animateHashes = function(){
- var id_value = window.location.hash;
- if (id_value != ""){
- var previous_color = $(id_value).css('background-color');
- $(id_value).css('backgroundColor', '#FFF8C6');
- $(id_value)
- .animate({backgroundColor: '#ff7f2a'}, 500)
- .animate({backgroundColor: '#FFF8C6'}, 500, function(){
- $(id_value).css('backgroundColor', previous_color);
- });
- }
-};
-
-var getUniqueWords = function(value){
- var words = $.trim(value).split(/\s+/);
- var uniques = new Object();
- var out = new Array();
- $.each(words, function(idx, item){
- if (!(item in uniques)){
- uniques[item] = 1;
- out.push(item);
- };
- });
- return out;
-};
-
-var showMessage = function(element, msg, where) {
- var div = $('<div class="vote-notification"><h3>' + msg + '</h3>(' +
- gettext('click to close') + ')</div>');
-
- div.click(function(event) {
- $(".vote-notification").fadeOut("fast", function() { $(this).remove(); });
- });
-
- var where = where || 'parent';
-
- if (where == 'parent'){
- element.parent().append(div);
- }
- else {
- element.after(div);
- }
-
- div.fadeIn("fast");
-};
-
-//outer html hack - https://github.com/brandonaaron/jquery-outerhtml/
-(function($){
- var div;
- $.fn.outerHTML = function() {
- var elem = this[0],
- tmp;
- return !elem ? null
- : typeof ( tmp = elem.outerHTML ) === 'string' ? tmp
- : ( div = div || $('<div/>') ).html( this.eq(0).clone() ).html();
- };
-})(jQuery);
-
-var makeKeyHandler = function(key, callback){
- return function(e){
- if ((e.which && e.which == key) || (e.keyCode && e.keyCode == key)){
- if(!e.shiftKey){
- callback();
- return false;
- }
- }
- };
-};
-
-
-var setupButtonEventHandlers = function(button, callback){
- button.keydown(makeKeyHandler(13, callback));
- button.click(callback);
-};
-
-
-var putCursorAtEnd = function(element){
- var el = element.get()[0];
- if (el.setSelectionRange){
- var len = element.val().length * 2;
- el.setSelectionRange(len, len);
- }
- else{
- element.val(element.val());
- }
- element.scrollTop = 999999;
-};
-
-var setCheckBoxesIn = function(selector, value){
- return $(selector + '> input[type=checkbox]').attr('checked', value);
-};
-
-var notify = function() {
- var visible = false;
- return {
- show: function(html) {
- if (html) {
- $("body").addClass('user-messages');
- $(".notify span").html(html);
- }
- $(".notify").fadeIn("slow");
- visible = true;
- },
- close: function(doPostback) {
- if (doPostback) {
- $.post(
- askbot['urls']['mark_read_message'],
- { formdata: "required" }
- );
- }
- $(".notify").fadeOut("fast");
- $('body').removeClass('user-messages');
- visible = false;
- },
- isVisible: function() { return visible; }
- };
-} ();
-
-/* **************************************************** */
-// Search query-string manipulation utils
-/* **************************************************** */
-
-var QSutils = QSutils || {}; // TODO: unit-test me
-
-QSutils.TAG_SEP = ','; // should match const.TAG_SEP; TODO: maybe prepopulate this in javascript.html ?
-
-QSutils.get_query_string_selector_value = function (query_string, selector) {
- var params = query_string.split('/');
- for(var i=0; i<params.length; i++) {
- var param_split = params[i].split(':');
- if(param_split[0] === selector) {
- return param_split[1];
- }
- }
- return undefined;
-};
-
-QSutils.patch_query_string = function (query_string, patch, remove) {
- var params = query_string.split('/');
- var patch_split = patch.split(':');
-
- var new_query_string = '';
- var mapping = {};
-
- if(!remove) {
- mapping[patch_split[0]] = patch_split[1]; // prepopulate the patched selector if it's not meant to be removed
- }
-
- for (var i = 0; i < params.length; i++) {
- var param_split = params[i].split(':');
- if(param_split[0] !== patch_split[0] && param_split[1]) {
- mapping[param_split[0]] = param_split[1];
- }
- }
-
- var add_selector = function(name) {
- if(name in mapping) {
- new_query_string += name + ':' + mapping[name] + '/';
- }
- };
-
- /* The order of selectors should match the Django URL */
- add_selector('scope');
- add_selector('sort');
- add_selector('query');
- add_selector('tags');
- add_selector('author');
- add_selector('page');
-
- return new_query_string;
-};
-
-QSutils.remove_search_tag = function(query_string, tag){
- var tag_string = this.get_query_string_selector_value(query_string, 'tags');
- if(!tag_string) {
- return query_string;
- }
-
- var tags = tag_string.split(this.TAG_SEP);
-
- var pos = $.inArray(encodeURIComponent(tag), tags);
- if(pos > -1) {
- tags.splice(pos, 1); /* array.splice() works in-place */
- }
-
- if(tags.length === 0) {
- return this.patch_query_string(query_string, 'tags:', true);
- } else {
- return this.patch_query_string(query_string, 'tags:' + tags.join(this.TAG_SEP));
- }
-};
-
-QSutils.add_search_tag = function(query_string, tag){
- var tag_string = this.get_query_string_selector_value(query_string, 'tags');
- tag = encodeURIComponent(tag);
- if(!tag_string) {
- tag_string = tag;
- } else {
- tag_string = [tag_string, tag].join(this.TAG_SEP);
- }
-
- return this.patch_query_string(query_string, 'tags:' + tag_string);
-};
-
-/* **************************************************** */
-
-/* some google closure-like code for the ui elements */
-var inherits = function(childCtor, parentCtor) {
- /** @constructor taken from google closure */
- function tempCtor() {};
- tempCtor.prototype = parentCtor.prototype;
- childCtor.superClass_ = parentCtor.prototype;
- childCtor.prototype = new tempCtor();
- childCtor.prototype.constructor = childCtor;
-};
-
-/* wrapper around jQuery object */
-var WrappedElement = function(){
- this._element = null;
- this._in_document = false;
-};
-WrappedElement.prototype.setElement = function(element){
- this._element = element;
-};
-WrappedElement.prototype.createDom = function(){
- this._element = $('<div></div>');
-};
-WrappedElement.prototype.decorate = function(element){
- this._element = element;
-};
-WrappedElement.prototype.getElement = function(){
- if (this._element === null){
- this.createDom();
- }
- return this._element;
-};
-WrappedElement.prototype.inDocument = function(){
- return this._in_document;
-};
-WrappedElement.prototype.enterDocument = function(){
- return this._in_document = true;
-};
-WrappedElement.prototype.hasElement = function(){
- return (this._element !== null);
-};
-WrappedElement.prototype.makeElement = function(html_tag){
- //makes jQuery element with tags
- return $('<' + html_tag + '></' + html_tag + '>');
-};
-WrappedElement.prototype.dispose = function(){
- this._element.remove();
- this._in_document = false;
-};
-
-/**
- * Can be used for an input box or textarea.
- * The original value will be treated as an instruction.
- * When user focuses on the field, the tip will be gone,
- * when the user escapes without typing anything besides
- * perhaps empty text, the instruction is restored.
- * When instruction is shown, class "blank" is present
- * in the input/textare element.
- */
-var TippedInput = function(){
- WrappedElement.call(this);
- this._instruction = null;
-};
-inherits(TippedInput, WrappedElement);
-
-TippedInput.prototype.reset = function(){
- $(this._element).val(this._instruction);
- $(this._element).addClass('blank');
-};
-
-TippedInput.prototype.isBlank = function(){
- return this.getVal() === this._instruction;
-};
-
-TippedInput.prototype.getVal = function(){
- return this._element.val();
-};
-
-TippedInput.prototype.setVal = function(value){
- if (value) {
- this._element.val(value);
- if (this.isBlank()){
- this._element.addClass('blank');
- } else {
- this._element.removeClass('blank');
- }
- }
-};
-
-TippedInput.prototype.decorate = function(element){
- this._element = element;
- var instruction_text = this.getVal();
- this._instruction = instruction_text;
- var me = this;
- $(element).focus(function(){
- if (me.isBlank()){
- $(element)
- .val('')
- .removeClass('blank');
- }
- });
- $(element).blur(function(){
- var val = $(element).val();
- if ($.trim(val) === ''){
- $(element)
- .val(instruction_text)
- .addClass('blank');
- }
- });
- makeKeyHandler(13, function(){
- $(element).blur();
- });
-};
-
-/**
- * will setup a bootstrap.js alert
- * programmatically
- */
-var AlertBox = function(){
- WrappedElement.call(this);
- this._text = null;
-};
-inherits(AlertBox, WrappedElement);
-
-AlertBox.prototype.setClass = function(classes){
- this._classes = classes;
- if (this._element){
- this._element.addClass(classes);
- }
-};
-
-AlertBox.prototype.setError = function(state){
- this._is_error = state;
- if (this._element) {
- if (state === true) {
- this._element.addClass('alert-error');
- } else {
- this._element.removeClass('alert-error');
- }
- }
-};
-
-AlertBox.prototype.setText = function(text){
- this._text = text;
- if (this._content){
- this._content.html(text);
- }
-};
-
-AlertBox.prototype.getContent = function(){
- if (this._content){
- return this._content;
- } else {
- this._content = this.makeElement('div');
- return this._content;
- }
-};
-
-AlertBox.prototype.setContent = function(content){
- var container = this.getContent();
- container.empty()
- container.append(content);
-};
-
-AlertBox.prototype.addContent = function(content){
- var container = this.getContent();
- container.append(content);
-};
-
-AlertBox.prototype.createDom = function(){
- this._element = this.makeElement('div');
- this._element.addClass('alert fade in');
-
- if (this._is_error) {
- this.setError(this._is_error);
- }
-
- if (this._classes){
- this._element.addClass(this._classes);
- }
-
- this._cancel_button = this.makeElement('button');
- this._cancel_button
- .addClass('close')
- .attr('data-dismiss', 'alert')
- .html('&times;');
- this._element.append(this._cancel_button);
-
- this._element.append(this.getContent());
- if (this._text){
- this.setText(this._text);
- }
-
- this._element.alert();//bootstrap.js alert
-};
-
-var SimpleControl = function(){
- WrappedElement.call(this);
- this._handler = null;
- this._title = null;
-};
-inherits(SimpleControl, WrappedElement);
-
-SimpleControl.prototype.setHandler = function(handler){
- this._handler = handler;
- if (this.hasElement()){
- this.setHandlerInternal();
- }
-};
-
-SimpleControl.prototype.getHandler = function(){
- return this._handler;
-};
-
-SimpleControl.prototype.setHandlerInternal = function(){
- //default internal setHandler behavior
- setupButtonEventHandlers(this._element, this._handler);
-};
-
-SimpleControl.prototype.setTitle = function(title){
- this._title = title;
-};
-
-var EditLink = function(){
- SimpleControl.call(this)
-};
-inherits(EditLink, SimpleControl);
-
-EditLink.prototype.createDom = function(){
- var element = $('<a></a>');
- element.addClass('edit');
- this.decorate(element);
-};
-
-EditLink.prototype.decorate = function(element){
- this._element = element;
- this._element.attr('title', gettext('click to edit this comment'));
- this._element.html(gettext('edit'));
- this.setHandlerInternal();
-};
-
-var DeleteIcon = function(title){
- SimpleControl.call(this);
- this._title = title;
- this._content = null;
-};
-inherits(DeleteIcon, SimpleControl);
-
-DeleteIcon.prototype.decorate = function(element){
- this._element = element;
- this._element.attr('class', 'delete-icon');
- this._element.attr('title', this._title);
- if (this._handler !== null){
- this.setHandlerInternal();
- }
-};
-
-DeleteIcon.prototype.setHandlerInternal = function(){
- setupButtonEventHandlers(this._element, this._handler);
-};
-
-DeleteIcon.prototype.createDom = function(){
- this._element = this.makeElement('span');
- this.decorate(this._element);
- if (this._content !== null){
- this.setContent(this._content);
- }
-};
-
-DeleteIcon.prototype.setContent = function(content){
- if (this._element === null){
- this._content = content;
- } else {
- this._content = content;
- this._element.html(content);
- }
-}
-
-/**
- * attaches a modal menu with a text editor
- * to a link. The modal menu is from bootstrap.js
- */
-var TextPropertyEditor = function(){
- WrappedElement.call(this);
- this._editor = null;
-};
-inherits(TextPropertyEditor, WrappedElement);
-
-TextPropertyEditor.prototype.getWidgetData = function(){
- var data = this._element.data();
- return {
- object_id: data['objectId'],
- model_name: data['modelName'],
- property_name: data['propertyName'],
- url: data['url'],
- help_text: data['helpText'],
- editor_heading: data['editorHeading']
- };
-};
-
-TextPropertyEditor.prototype.makeEditor = function(){
- if (this._editor) {
- return this._editor;
- }
- var editor = this.makeElement('div')
- .addClass('modal');
- this._editor = editor;
-
- var header = this.makeElement('div')
- .addClass('modal-header');
- editor.append(header);
-
- var close_link = this.makeElement('div')
- .addClass('close')
- .attr('data-dismiss', 'modal')
- .html('x');
- header.append(close_link);
-
- var title = this.makeElement('h3')
- .html(this.getWidgetData()['editor_heading']);
- header.append(title);
-
- var body = this.makeElement('div')
- .addClass('modal-body');
- editor.append(body);
-
- var textarea = this.makeElement('textarea')
- .addClass('tipped-input blank')
- .val(this.getWidgetData()['help_text']);
- body.append(textarea);
-
- var tipped_input = new TippedInput();
- tipped_input.decorate(textarea);
- this._text_input = tipped_input;
-
- var footer = this.makeElement('div')
- .addClass('modal-footer');
- editor.append(footer);
-
- var save_btn = this.makeElement('button')
- .addClass('btn btn-primary')
- .html(gettext('Save'));
- footer.append(save_btn);
-
- var cancel_btn = this.makeElement('button')
- .addClass('btn cancel')
- .html(gettext('Cancel'));
- footer.append(cancel_btn);
-
- var me = this;
- setupButtonEventHandlers(save_btn, function(){
- me.saveData();
- });
- setupButtonEventHandlers(cancel_btn, function(){
- editor.modal('hide');
- });
- editor.modal('hide');
-
- $(document).append(editor);
- return editor;
-};
-
-TextPropertyEditor.prototype.openEditor = function(){
- this._editor.modal('show');
-};
-
-TextPropertyEditor.prototype.clearMessages = function(){
- this._editor.find('.alert').remove();
-};
-
-TextPropertyEditor.prototype.getAlert = function(){
- var box = new AlertBox();
- var modal_body = this._editor.find('.modal-body');
- modal_body.prepend(box.getElement());
- return box;
-};
-
-TextPropertyEditor.prototype.showAlert = function(text){
- this.clearMessages();
- var box = this.getAlert();
- box.setText(text);
- return box;
-};
-
-TextPropertyEditor.prototype.showError = function(text){
- var box = this.showAlert(text);
- box.setError(true);
- return box;
-};
-
-TextPropertyEditor.prototype.setText = function(text){
- this._text_input.setVal(text);
-};
-
-TextPropertyEditor.prototype.getText = function(){
- return this._text_input.getVal();
-};
-
-TextPropertyEditor.prototype.hideDialog = function(){
- this._editor.modal('hide');
-};
-
-TextPropertyEditor.prototype.startOpeningEditor = function(){
- var me = this;
- $.ajax({
- type: 'GET',
- dataType: 'json',
- cache: false,
- url: me.getWidgetData()['url'],
- data: me.getWidgetData(),
- success: function(data){
- if (data['success']) {
- me.makeEditor();
- me.setText($.trim(data['text']));
- me.openEditor();
- } else {
- showMessage(me.getElement(), data['message']);
- }
- }
- });
-};
-
-TextPropertyEditor.prototype.saveData = function(){
- var data = this.getWidgetData();
- data['text'] = this.getText();
- var me = this;
- $.ajax({
- type: 'POST',
- dataType: 'json',
- cache: false,
- url: me.getWidgetData()['url'],
- data: data,
- success: function(data) {
- if (data['success']) {
- me.showAlert(gettext('saved'));
- setTimeout(function(){
- me.clearMessages();
- me.hideDialog();
- }, 1000);
- } else {
- me.showError(data['message']);
- }
- }
- });
-};
-
-TextPropertyEditor.prototype.decorate = function(element){
- this._element = element;
- var me = this;
- setupButtonEventHandlers(element, function(){ me.startOpeningEditor() });
-};
-
-/**
- * A button on which user can click
- * and become added to some group (followers, group members, etc.)
- * or toggle some state on/off
- * The button has four states on-prompt, off-prompt, on-state and off-state
- * on-prompt is activated on mouseover, when user is not part of group
- * off-prompt - on mouseover, when user is part of group
- * on-state - when user is part of group and mouse is not over the button
- * off-state - same as above, but when user is not part of the group
- */
-var TwoStateToggle = function(){
- SimpleControl.call(this);
- this._state = null;
- this._state_messages = {};
- this._states = [
- 'on-state',
- 'off-state',
- 'on-prompt',
- 'off-prompt'
- ];
- this._handler = this.getDefaultHandler();
- this._post_data = {};
- this.toggleUrl = '';//public property
-};
-inherits(TwoStateToggle, SimpleControl);
-
-TwoStateToggle.prototype.setPostData = function(data){
- this._post_data = data;
-};
-
-TwoStateToggle.prototype.getPostData = function(){
- return this._post_data;
-};
-
-TwoStateToggle.prototype.resetStyles = function(){
- var element = this._element;
- var states = this._states;
- $.each(states, function(idx, state){
- element.removeClass(state);
- });
- this._element.html('');
-};
-
-TwoStateToggle.prototype.isOn = function(){
- return this._element.hasClass('on');
-};
-
-TwoStateToggle.prototype.getDefaultHandler = function(){
- var me = this;
- return function(){
- var data = me.getPostData();
- data['disable'] = me.isOn();
- $.ajax({
- type: 'POST',
- dataType: 'json',
- cache: false,
- url: me.toggleUrl,
- data: data,
- success: function(data) {
- if (data['success']) {
- if ( data['is_enabled'] ) {
- me.setState('on-state');
- } else {
- me.setState('off-state');
- }
- } else {
- showMessage(me.getElement(), data['message']);
- }
- }
- });
- };
-};
-
-TwoStateToggle.prototype.isCheckBox = function(){
- var element = this._element;
- return element.attr('type') === 'checkbox';
-};
-
-TwoStateToggle.prototype.setState = function(state){
- var element = this._element;
- this._state = state;
- if (element) {
- this.resetStyles();
- element.addClass(state);
- if (state === 'on-state') {
- element.addClass('on');
- } else if (state === 'off-state') {
- element.removeClass('on');
- }
- if ( this.isCheckBox() ) {
- if (state === 'on-state') {
- element.attr('checked', true);
- } else if (state === 'off-state') {
- element.attr('checked', false);
- }
- } else {
- this._element.html(this._state_messages[state]);
- }
- }
-};
-
-TwoStateToggle.prototype.decorate = function(element){
- this._element = element;
- //read messages for all states
- var messages = {};
- messages['on-state'] =
- element.attr('data-on-state-text') || gettext('enabled');
- messages['off-state'] =
- element.attr('data-off-state-text') || gettext('disabled');
- messages['on-prompt'] =
- element.attr('data-on-prompt-text') || messages['on-state'];
- messages['off-prompt'] =
- element.attr('data-off-prompt-text') || messages['off-state'];
- this._state_messages = messages;
-
- this.toggleUrl = element.attr('data-toggle-url');
-
- //detect state and save it
- if (this.isCheckBox()) {
- this._state = element.attr('checked') ? 'state-on' : 'state-off';
- } else {
- var text = $.trim(element.html());
- for (var i = 0; i < this._states.length; i++){
- var state = this._states[i];
- if (text === messages[state]){
- this._state = state;
- break;
- }
- }
- }
-
- //set mouseover handler
- var me = this;
- element.mouseover(function(){
- var is_on = me.isOn();
- if (is_on){
- me.setState('off-prompt');
- } else {
- me.setState('on-prompt');
- }
- element.css('background-color', 'red');
- return false;
- });
- element.mouseout(function(){
- var is_on = me.isOn();
- if (is_on){
- me.setState('on-state');
- } else {
- me.setState('off-state');
- }
- element.css('background-color', 'white');
- return false;
- });
-
- setupButtonEventHandlers(element, this.getHandler());
-};
-
-/**
- * A list of items from where one can be selected
- */
-var SelectBox = function(){
- WrappedElement.call(this);
- this._items = [];
-};
-inherits(SelectBox, WrappedElement);
-
-SelectBox.prototype.removeItem = function(id){
- var item = this.getItem(id);
- item.fadeOut();
- item.remove();
-};
-
-SelectBox.prototype.getItem = function(id){
- return $(this._element.find('li[data-item-id="' + id + '"]'));
-};
-
-SelectBox.prototype.addItem = function(id, title, details){
- /*this._items.push({
- id: id,
- title: title,
- details: details
- });*/
- if (this._element){
- var li = this.getItem(id);
- var new_li = false;
- if (li.length !== 1){
- li = this.makeElement('li');
- new_li = true;
- }
- li.attr('data-item-id', id)
- .attr('data-original-title', details)
- .html(title);
- if (new_li){
- this._element.append(li);
- }
- this.selectItem($(li));
- var me = this;
- setupButtonEventHandlers(
- $(li),
- function(){
- me.selectItem($(li));
- }
- );
- }
-};
-
-SelectBox.prototype.getSelectedItemData = function(){
- var item = $(this._element.find('li.selected')[0]);
- return {
- id: item.attr('data-item-id'),
- title: item.html(),
- details: item.attr('data-original-title')
- };
-};
-
-SelectBox.prototype.selectItem = function(item){
- this._element.find('li').removeClass('selected');
- item.addClass('selected');
-};
-
-SelectBox.prototype.decorate = function(element){
- this._element = element;
- var me = this;
- this._element.find('li').each(function(itx, item){
- setupButtonEventHandlers(
- $(item),
- function(){
- me.selectItem($(item));
- }
- );
- });
-};
-
-var Tag = function(){
- SimpleControl.call(this);
- this._deletable = false;
- this._delete_handler = null;
- this._delete_icon_title = null;
- this._tag_title = null;
- this._name = null;
- this._url_params = null;
- this._inner_html_tag = 'a';
- this._html_tag = 'li';
-}
-inherits(Tag, SimpleControl);
-
-Tag.prototype.setName = function(name){
- this._name = name;
-};
-
-Tag.prototype.getName = function(){
- return this._name;
-};
-
-Tag.prototype.setHtmlTag = function(html_tag){
- this._html_tag = html_tag;
-};
-
-Tag.prototype.setDeletable = function(is_deletable){
- this._deletable = is_deletable;
-};
-
-Tag.prototype.setLinkable = function(is_linkable){
- if (is_linkable === true){
- this._inner_html_tag = 'a';
- } else {
- this._inner_html_tag = 'span';
- }
-};
-
-Tag.prototype.isLinkable = function(){
- return (this._inner_html_tag === 'a');
-};
-
-Tag.prototype.isDeletable = function(){
- return this._deletable;
-};
-
-Tag.prototype.isWildcard = function(){
- return (this.getName().substr(-1) === '*');
-};
-
-Tag.prototype.setUrlParams = function(url_params){
- this._url_params = url_params;
-};
-
-Tag.prototype.setHandlerInternal = function(){
- setupButtonEventHandlers(this._element.find('.tag'), this._handler);
-};
-
-/* delete handler will be specific to the task */
-Tag.prototype.setDeleteHandler = function(delete_handler){
- this._delete_handler = delete_handler;
- if (this.hasElement() && this.isDeletable()){
- this._delete_icon.setHandler(delete_handler);
- }
-};
-
-Tag.prototype.getDeleteHandler = function(){
- return this._delete_handler;
-};
-
-Tag.prototype.setDeleteIconTitle = function(title){
- this._delete_icon_title = title;
-};
-
-Tag.prototype.decorate = function(element){
- this._element = element;
- var del = element.find('.delete-icon');
- if (del.length === 1){
- this.setDeletable(true);
- this._delete_icon = new DeleteIcon();
- if (this._delete_icon_title != null){
- this._delete_icon.setTitle(this._delete_icon_title);
- }
- //do not set the delete handler here
- this._delete_icon.decorate(del);
- }
- this._inner_element = this._element.find('.tag');
- this._name = this.decodeTagName(
- $.trim(this._inner_element.attr('data-tag-name'))
- );
- if (this._title !== null){
- this._inner_element.attr('title', this._title);
- }
- if (this._handler !== null){
- this.setHandlerInternal();
- }
-};
-
-Tag.prototype.getDisplayTagName = function(){
- //replaces the trailing * symbol with the unicode asterisk
- return this._name.replace(/\*$/, '&#10045;');
-};
-
-Tag.prototype.decodeTagName = function(encoded_name){
- return encoded_name.replace('\u273d', '*');
-};
-
-Tag.prototype.createDom = function(){
- this._element = this.makeElement(this._html_tag);
- //render the outer element
- if (this._deletable){
- this._element.addClass('deletable-tag');
- }
- this._element.addClass('tag-left');
-
- //render the inner element
- this._inner_element = this.makeElement(this._inner_html_tag);
- if (this.isLinkable()){
- var url = askbot['urls']['questions'];
- var flag = false
- var author = ''
- if (this._url_params){
- url += QSutils.add_search_tag(this._url_params, this.getName());
- }
- this._inner_element.attr('href', url);
- }
- this._inner_element.addClass('tag tag-right');
- this._inner_element.attr('rel', 'tag');
- if (this._title === null){
- this.setTitle(
- interpolate(gettext("see questions tagged '%s'"), [this.getName()])
- );
- }
- this._inner_element.attr('title', this._title);
- this._inner_element.html(this.getDisplayTagName());
-
- this._element.append(this._inner_element);
-
- if (!this.isLinkable() && this._handler !== null){
- this.setHandlerInternal();
- }
-
- if (this._deletable){
- this._delete_icon = new DeleteIcon();
- this._delete_icon.setHandler(this.getDeleteHandler());
- if (this._delete_icon_title !== null){
- this._delete_icon.setTitle(this._delete_icon_title);
- }
- var del_icon_elem = this._delete_icon.getElement();
- del_icon_elem.text('x'); // HACK by Tomasz
- this._element.append(del_icon_elem);
- }
-};
-
-//Search Engine Keyword Highlight with Javascript
-//http://scott.yang.id.au/code/se-hilite/
-Hilite={elementid:"content",exact:true,max_nodes:1000,onload:true,style_name:"hilite",style_name_suffix:true,debug_referrer:""};Hilite.search_engines=[["local","q"],["cnprog\\.","q"],["google\\.","q"],["search\\.yahoo\\.","p"],["search\\.msn\\.","q"],["search\\.live\\.","query"],["search\\.aol\\.","userQuery"],["ask\\.com","q"],["altavista\\.","q"],["feedster\\.","q"],["search\\.lycos\\.","q"],["alltheweb\\.","q"],["technorati\\.com/search/([^\\?/]+)",1],["dogpile\\.com/info\\.dogpl/search/web/([^\\?/]+)",1,true]];Hilite.decodeReferrer=function(d){var g=null;var e=new RegExp("");for(var c=0;c<Hilite.search_engines.length;c++){var f=Hilite.search_engines[c];e.compile("^http://(www\\.)?"+f[0],"i");var b=d.match(e);if(b){var a;if(isNaN(f[1])){a=Hilite.decodeReferrerQS(d,f[1])}else{a=b[f[1]+1]}if(a){a=decodeURIComponent(a);if(f.length>2&&f[2]){a=decodeURIComponent(a)}a=a.replace(/\'|"/g,"");a=a.split(/[\s,\+\.]+/);return a}break}}return null};Hilite.decodeReferrerQS=function(f,d){var b=f.indexOf("?");var c;if(b>=0){var a=new String(f.substring(b+1));b=0;c=0;while((b>=0)&&((c=a.indexOf("=",b))>=0)){var e,g;e=a.substring(b,c);b=a.indexOf("&",c)+1;if(e==d){if(b<=0){return a.substring(c+1)}else{return a.substring(c+1,b-1)}}else{if(b<=0){return null}}}}return null};Hilite.hiliteElement=function(f,e){if(!e||f.childNodes.length==0){return}var c=new Array();for(var b=0;b<e.length;b++){e[b]=e[b].toLowerCase();if(Hilite.exact){c.push("\\b"+e[b]+"\\b")}else{c.push(e[b])}}c=new RegExp(c.join("|"),"i");var a={};for(var b=0;b<e.length;b++){if(Hilite.style_name_suffix){a[e[b]]=Hilite.style_name+(b+1)}else{a[e[b]]=Hilite.style_name}}var d=function(m){var j=c.exec(m.data);if(j){var n=j[0];var i="";var h=m.splitText(j.index);var g=h.splitText(n.length);var l=m.ownerDocument.createElement("SPAN");m.parentNode.replaceChild(l,h);l.className=a[n.toLowerCase()];l.appendChild(h);return l}else{return m}};Hilite.walkElements(f.childNodes[0],1,d)};Hilite.hilite=function(){var a=Hilite.debug_referrer?Hilite.debug_referrer:document.referrer;var b=null;a=Hilite.decodeReferrer(a);if(a&&((Hilite.elementid&&(b=document.getElementById(Hilite.elementid)))||(b=document.body))){Hilite.hiliteElement(b,a)}};Hilite.walkElements=function(d,f,e){var a=/^(script|style|textarea)/i;var c=0;while(d&&f>0){c++;if(c>=Hilite.max_nodes){var b=function(){Hilite.walkElements(d,f,e)};setTimeout(b,50);return}if(d.nodeType==1){if(!a.test(d.tagName)&&d.childNodes.length>0){d=d.childNodes[0];f++;continue}}else{if(d.nodeType==3){d=e(d)}}if(d.nextSibling){d=d.nextSibling}else{while(f>0){d=d.parentNode;f--;if(d.nextSibling){d=d.nextSibling;break}}}}};if(Hilite.onload){if(window.attachEvent){window.attachEvent("onload",Hilite.hilite)}else{if(window.addEventListener){window.addEventListener("load",Hilite.hilite,false)}else{var __onload=window.onload;window.onload=function(){Hilite.hilite();__onload()}}}};
-/* json2.js by D. Crockford */
-if(!this.JSON){this.JSON={}}(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof JSON.stringify!=="function"){JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}text=String(text);cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}}());
-//jquery fieldselection
-(function(){var a={getSelection:function(){var b=this.jquery?this[0]:this;return(("selectionStart" in b&&function(){var c=b.selectionEnd-b.selectionStart;return{start:b.selectionStart,end:b.selectionEnd,length:c,text:b.value.substr(b.selectionStart,c)}})||(document.selection&&function(){b.focus();var d=document.selection.createRange();if(d==null){return{start:0,end:b.value.length,length:0}}var c=b.createTextRange();var e=c.duplicate();c.moveToBookmark(d.getBookmark());e.setEndPoint("EndToStart",c);return{start:e.text.length,end:e.text.length+d.text.length,length:d.text.length,text:d.text}})||function(){return{start:0,end:b.value.length,length:0}})()},replaceSelection:function(){var b=this.jquery?this[0]:this;var c=arguments[0]||"";return(("selectionStart" in b&&function(){b.value=b.value.substr(0,b.selectionStart)+c+b.value.substr(b.selectionEnd,b.value.length);return this})||(document.selection&&function(){b.focus();document.selection.createRange().text=c;return this})||function(){b.value+=c;return this})()}};jQuery.each(a,function(b){jQuery.fn[b]=this})})();
-//our custom autocompleter
-var AutoCompleter=function(a){var b={autocompleteMultiple:true,multipleSeparator:" ",inputClass:"acInput",loadingClass:"acLoading",resultsClass:"acResults",selectClass:"acSelect",queryParamName:"q",limitParamName:"limit",extraParams:{},lineSeparator:"\n",cellSeparator:"|",minChars:2,maxItemsToShow:10,delay:400,useCache:true,maxCacheLength:10,matchSubset:true,matchCase:false,matchInside:true,mustMatch:false,preloadData:false,selectFirst:false,stopCharRegex:/\s+/,selectOnly:false,formatItem:null,onItemSelect:false,autoFill:false,filterResults:true,sortResults:true,sortFunction:false,onNoMatch:false};this.options=$.extend({},b,a);this.cacheData_={};this.cacheLength_=0;this.selectClass_="jquery-autocomplete-selected-item";this.keyTimeout_=null;this.lastKeyPressed_=null;this.lastProcessedValue_=null;this.lastSelectedValue_=null;this.active_=false;this.finishOnBlur_=true;this.options.minChars=parseInt(this.options.minChars,10);if(isNaN(this.options.minChars)||this.options.minChars<1){this.options.minChars=2}this.options.maxItemsToShow=parseInt(this.options.maxItemsToShow,10);if(isNaN(this.options.maxItemsToShow)||this.options.maxItemsToShow<1){this.options.maxItemsToShow=10}this.options.maxCacheLength=parseInt(this.options.maxCacheLength,10);if(isNaN(this.options.maxCacheLength)||this.options.maxCacheLength<1){this.options.maxCacheLength=10}if(this.options.preloadData===true){this.fetchRemoteData("",function(){})}};inherits(AutoCompleter,WrappedElement);AutoCompleter.prototype.decorate=function(a){this._element=a;this._element.attr("autocomplete","off");this._results=$("<div></div>").hide();if(this.options.resultsClass){this._results.addClass(this.options.resultsClass)}this._results.css({position:"absolute"});$("body").append(this._results);this.setEventHandlers()};AutoCompleter.prototype.setEventHandlers=function(){var a=this;a._element.keydown(function(b){a.lastKeyPressed_=b.keyCode;switch(a.lastKeyPressed_){case 38:b.preventDefault();if(a.active_){a.focusPrev()}else{a.activate()}return false;break;case 40:b.preventDefault();if(a.active_){a.focusNext()}else{a.activate()}return false;break;case 9:case 13:if(a.active_){b.preventDefault();a.selectCurrent();return false}break;case 27:if(a.active_){b.preventDefault();a.finish();return false}break;default:a.activate()}});a._element.blur(function(){if(a.finishOnBlur_){setTimeout(function(){a.finish()},200)}})};AutoCompleter.prototype.position=function(){var a=this._element.offset();this._results.css({top:a.top+this._element.outerHeight(),left:a.left})};AutoCompleter.prototype.cacheRead=function(d){var f,c,b,a,e;if(this.options.useCache){d=String(d);f=d.length;if(this.options.matchSubset){c=1}else{c=f}while(c<=f){if(this.options.matchInside){a=f-c}else{a=0}e=0;while(e<=a){b=d.substr(0,c);if(this.cacheData_[b]!==undefined){return this.cacheData_[b]}e++}c++}}return false};AutoCompleter.prototype.cacheWrite=function(a,b){if(this.options.useCache){if(this.cacheLength_>=this.options.maxCacheLength){this.cacheFlush()}a=String(a);if(this.cacheData_[a]!==undefined){this.cacheLength_++}return this.cacheData_[a]=b}return false};AutoCompleter.prototype.cacheFlush=function(){this.cacheData_={};this.cacheLength_=0};AutoCompleter.prototype.callHook=function(c,b){var a=this.options[c];if(a&&$.isFunction(a)){return a(b,this)}return false};AutoCompleter.prototype.activate=function(){var b=this;var a=function(){b.activateNow()};var c=parseInt(this.options.delay,10);if(isNaN(c)||c<=0){c=250}if(this.keyTimeout_){clearTimeout(this.keyTimeout_)}this.keyTimeout_=setTimeout(a,c)};AutoCompleter.prototype.activateNow=function(){var a=this.getValue();if(a!==this.lastProcessedValue_&&a!==this.lastSelectedValue_){if(a.length>=this.options.minChars){this.active_=true;this.lastProcessedValue_=a;this.fetchData(a)}}};AutoCompleter.prototype.fetchData=function(b){if(this.options.data){this.filterAndShowResults(this.options.data,b)}else{var a=this;this.fetchRemoteData(b,function(c){a.filterAndShowResults(c,b)})}};AutoCompleter.prototype.fetchRemoteData=function(c,e){var d=this.cacheRead(c);if(d){e(d)}else{var a=this;if(this._element){this._element.addClass(this.options.loadingClass)}var b=function(g){var f=false;if(g!==false){f=a.parseRemoteData(g);a.options.data=f;a.cacheWrite(c,f)}if(a._element){a._element.removeClass(a.options.loadingClass)}e(f)};$.ajax({url:this.makeUrl(c),success:b,error:function(){b(false)}})}};AutoCompleter.prototype.setOption=function(a,b){this.options[a]=b};AutoCompleter.prototype.setExtraParam=function(b,c){var a=$.trim(String(b));if(a){if(!this.options.extraParams){this.options.extraParams={}}if(this.options.extraParams[a]!==c){this.options.extraParams[a]=c;this.cacheFlush()}}};AutoCompleter.prototype.makeUrl=function(e){var a=this;var b=this.options.url;var d=$.extend({},this.options.extraParams);if(this.options.queryParamName===false){b+=encodeURIComponent(e)}else{d[this.options.queryParamName]=e}if(this.options.limitParamName&&this.options.maxItemsToShow){d[this.options.limitParamName]=this.options.maxItemsToShow}var c=[];$.each(d,function(f,g){c.push(a.makeUrlParam(f,g))});if(c.length){b+=b.indexOf("?")==-1?"?":"&";b+=c.join("&")}return b};AutoCompleter.prototype.makeUrlParam=function(a,b){return String(a)+"="+encodeURIComponent(b)};AutoCompleter.prototype.splitText=function(a){return String(a).replace(/(\r\n|\r|\n)/g,"\n").split(this.options.lineSeparator)};AutoCompleter.prototype.parseRemoteData=function(c){var h,b,f,d,g;var e=[];var b=this.splitText(c);for(f=0;f<b.length;f++){var a=b[f].split(this.options.cellSeparator);g=[];for(d=0;d<a.length;d++){g.push(unescape(a[d]))}h=g.shift();e.push({value:unescape(h),data:g})}return e};AutoCompleter.prototype.filterAndShowResults=function(a,b){this.showResults(this.filterResults(a,b),b)};AutoCompleter.prototype.filterResults=function(d,b){var f=[];var l,c,e,m,j,a;var k,h,g;for(e=0;e<d.length;e++){m=d[e];j=typeof m;if(j==="string"){l=m;c={}}else{if($.isArray(m)){l=m[0];c=m.slice(1)}else{if(j==="object"){l=m.value;c=m.data}}}l=String(l);if(l>""){if(typeof c!=="object"){c={}}if(this.options.filterResults){h=String(b);g=String(l);if(!this.options.matchCase){h=h.toLowerCase();g=g.toLowerCase()}a=g.indexOf(h);if(this.options.matchInside){a=a>-1}else{a=a===0}}else{a=true}if(a){f.push({value:l,data:c})}}}if(this.options.sortResults){f=this.sortResults(f,b)}if(this.options.maxItemsToShow>0&&this.options.maxItemsToShow<f.length){f.length=this.options.maxItemsToShow}return f};AutoCompleter.prototype.sortResults=function(c,d){var b=this;var a=this.options.sortFunction;if(!$.isFunction(a)){a=function(g,e,h){return b.sortValueAlpha(g,e,h)}}c.sort(function(f,e){return a(f,e,d)});return c};AutoCompleter.prototype.sortValueAlpha=function(d,c,e){d=String(d.value);c=String(c.value);if(!this.options.matchCase){d=d.toLowerCase();c=c.toLowerCase()}if(d>c){return 1}if(d<c){return -1}return 0};AutoCompleter.prototype.showResults=function(e,b){var k=this;var g=$("<ul></ul>");var f,l,j,a,h=false,d=false;var c=e.length;for(f=0;f<c;f++){l=e[f];j=$("<li>"+this.showResult(l.value,l.data)+"</li>");j.data("value",l.value);j.data("data",l.data);j.click(function(){var i=$(this);k.selectItem(i)}).mousedown(function(){k.finishOnBlur_=false}).mouseup(function(){k.finishOnBlur_=true});g.append(j);if(h===false){h=String(l.value);d=j;j.addClass(this.options.firstItemClass)}if(f==c-1){j.addClass(this.options.lastItemClass)}}this.position();this._results.html(g).show();a=this._results.outerWidth()-this._results.width();this._results.width(this._element.outerWidth()-a);$("li",this._results).hover(function(){k.focusItem(this)},function(){});if(this.autoFill(h,b)){this.focusItem(d)}};AutoCompleter.prototype.showResult=function(b,a){if($.isFunction(this.options.showResult)){return this.options.showResult(b,a)}else{return b}};AutoCompleter.prototype.autoFill=function(e,c){var b,a,d,f;if(this.options.autoFill&&this.lastKeyPressed_!=8){b=String(e).toLowerCase();a=String(c).toLowerCase();d=e.length;f=c.length;if(b.substr(0,f)===a){this._element.val(e);this.selectRange(f,d);return true}}return false};AutoCompleter.prototype.focusNext=function(){this.focusMove(+1)};AutoCompleter.prototype.focusPrev=function(){this.focusMove(-1)};AutoCompleter.prototype.focusMove=function(a){var b,c=$("li",this._results);a=parseInt(a,10);for(var b=0;b<c.length;b++){if($(c[b]).hasClass(this.selectClass_)){this.focusItem(b+a);return}}this.focusItem(0)};AutoCompleter.prototype.focusItem=function(b){var a,c=$("li",this._results);if(c.length){c.removeClass(this.selectClass_).removeClass(this.options.selectClass);if(typeof b==="number"){b=parseInt(b,10);if(b<0){b=0}else{if(b>=c.length){b=c.length-1}}a=$(c[b])}else{a=$(b)}if(a){a.addClass(this.selectClass_).addClass(this.options.selectClass)}}};AutoCompleter.prototype.selectCurrent=function(){var a=$("li."+this.selectClass_,this._results);if(a.length==1){this.selectItem(a)}else{this.finish()}};AutoCompleter.prototype.selectItem=function(d){var c=d.data("value");var b=d.data("data");var a=this.displayValue(c,b);this.lastProcessedValue_=a;this.lastSelectedValue_=a;this.setValue(a);this.setCaret(a.length);this.callHook("onItemSelect",{value:c,data:b});this.finish()};AutoCompleter.prototype.isContentChar=function(a){if(a.match(this.options.stopCharRegex)){return false}else{if(a===this.options.multipleSeparator){return false}else{return true}}};AutoCompleter.prototype.getValue=function(){var c=this._element.getSelection();var d=this._element.val();var f=c.start;var e=f;for(cpos=f;cpos>=0;cpos=cpos-1){if(cpos===d.length){continue}var b=d.charAt(cpos);if(!this.isContentChar(b)){break}e=cpos}var a=f;for(cpos=f;cpos<d.length;cpos=cpos+1){if(cpos===0){continue}var b=d.charAt(cpos);if(!this.isContentChar(b)){break}a=cpos}this._selection_start=e;this._selection_end=a;return d.substring(e,a)};AutoCompleter.prototype.setValue=function(b){var a=this._element.val().substring(0,this._selection_start);var c=this._element.val().substring(this._selection_end+1);this._element.val(a+b+c)};AutoCompleter.prototype.displayValue=function(b,a){if($.isFunction(this.options.displayValue)){return this.options.displayValue(b,a)}else{return b}};AutoCompleter.prototype.finish=function(){if(this.keyTimeout_){clearTimeout(this.keyTimeout_)}if(this._element.val()!==this.lastSelectedValue_){if(this.options.mustMatch){this._element.val("")}this.callHook("onNoMatch")}this._results.hide();this.lastKeyPressed_=null;this.lastProcessedValue_=null;if(this.active_){this.callHook("onFinish")}this.active_=false};AutoCompleter.prototype.selectRange=function(d,a){var c=this._element.get(0);if(c.setSelectionRange){c.focus();c.setSelectionRange(d,a)}else{if(this.createTextRange){var b=this.createTextRange();b.collapse(true);b.moveEnd("character",a);b.moveStart("character",d);b.select()}}};AutoCompleter.prototype.setCaret=function(a){this.selectRange(a,a)};
-(function($){function isRGBACapable(){var $script=$("script:first"),color=$script.css("color"),result=false;if(/^rgba/.test(color)){result=true}else{try{result=(color!=$script.css("color","rgba(0, 0, 0, 0.5)").css("color"));$script.css("color",color)}catch(e){}}return result}$.extend(true,$,{support:{rgba:isRGBACapable()}});var properties=["color","backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","outlineColor"];$.each(properties,function(i,property){$.fx.step[property]=function(fx){if(!fx.init){fx.begin=parseColor($(fx.elem).css(property));fx.end=parseColor(fx.end);fx.init=true}fx.elem.style[property]=calculateColor(fx.begin,fx.end,fx.pos)}});$.fx.step.borderColor=function(fx){if(!fx.init){fx.end=parseColor(fx.end)}var borders=properties.slice(2,6);$.each(borders,function(i,property){if(!fx.init){fx[property]={begin:parseColor($(fx.elem).css(property))}}fx.elem.style[property]=calculateColor(fx[property].begin,fx.end,fx.pos)});fx.init=true};function calculateColor(begin,end,pos){var color="rgb"+($.support.rgba?"a":"")+"("+parseInt((begin[0]+pos*(end[0]-begin[0])),10)+","+parseInt((begin[1]+pos*(end[1]-begin[1])),10)+","+parseInt((begin[2]+pos*(end[2]-begin[2])),10);if($.support.rgba){color+=","+(begin&&end?parseFloat(begin[3]+pos*(end[3]-begin[3])):1)}color+=")";return color}function parseColor(color){var match,triplet;if(match=/#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})/.exec(color)){triplet=[parseInt(match[1],16),parseInt(match[2],16),parseInt(match[3],16),1]}else{if(match=/#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])/.exec(color)){triplet=[parseInt(match[1],16)*17,parseInt(match[2],16)*17,parseInt(match[3],16)*17,1]}else{if(match=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)){triplet=[parseInt(match[1]),parseInt(match[2]),parseInt(match[3]),1]}else{if(match=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9\.]*)\s*\)/.exec(color)){triplet=[parseInt(match[1],10),parseInt(match[2],10),parseInt(match[3],10),parseFloat(match[4])]}else{if(color=="transparent"){triplet=[0,0,0,0]}}}}}return triplet}})(jQuery);
-
-/**
- * Timeago is a jQuery plugin that makes it easy to support automatically
- * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
- *
- * @name timeago
- * @version 0.11.1
- * @requires jQuery v1.2.3+
- * @author Ryan McGeary
- * @license MIT License - http://www.opensource.org/licenses/mit-license.php
- *
- * For usage and examples, visit:
- * http://timeago.yarp.com/
- *
- * Copyright (c) 2008-2011, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org)
- */
-(function($) {
- $.timeago = function(timestamp) {
- if (timestamp instanceof Date) {
- return inWords(timestamp);
- } else if (typeof timestamp === "string") {
- return inWords($.timeago.parse(timestamp));
- } else {
- return inWords($.timeago.datetime(timestamp));
- }
- };
- var $t = $.timeago;
-
- $.extend($.timeago, {
- settings: {
- refreshMillis: 60000,
- allowFuture: false,
- strings: {
- prefixAgo: null,
- prefixFromNow: null,
- suffixAgo: gettext("ago"),
- suffixFromNow: gettext("from now"),
- seconds: gettext("just now"),
- minute: gettext("about a minute"),
- minutes: gettext("%d minutes"),
- hour: gettext("about an hour"),
- hours: gettext("%d hours"),
- day: gettext("yesterday"),
- days: gettext("%d days"),
- month: gettext("about a month"),
- months: gettext("%d months"),
- year: gettext("about a year"),
- years: gettext("%d years"),
- wordSeparator: " ",
- numbers: []
- }
- },
- inWords: function(distanceMillis) {
- var $l = this.settings.strings;
- var prefix = $l.prefixAgo;
- var suffix = $l.suffixAgo;
- if (this.settings.allowFuture) {
- if (distanceMillis < 0) {
- prefix = $l.prefixFromNow;
- suffix = $l.suffixFromNow;
- }
- }
-
- var seconds = Math.abs(distanceMillis) / 1000;
- var minutes = seconds / 60;
- var hours = minutes / 60;
- var days = hours / 24;
- var years = days / 365;
-
- function substitute(stringOrFunction, number) {
- var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
- var value = ($l.numbers && $l.numbers[number]) || number;
- return string.replace(/%d/i, value);
- }
-
- var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
- seconds < 90 && substitute($l.minute, 1) ||
- minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
- minutes < 90 && substitute($l.hour, 1) ||
- hours < 24 && substitute($l.hours, Math.round(hours)) ||
- hours < 42 && substitute($l.day, 1) ||
- days < 30 && substitute($l.days, Math.round(days)) ||
- days < 45 && substitute($l.month, 1) ||
- days < 365 && substitute($l.months, Math.round(days / 30)) ||
- years < 1.5 && substitute($l.year, 1) ||
- substitute($l.years, Math.round(years));
-
- var separator = $l.wordSeparator === undefined ? " " : $l.wordSeparator;
- return $.trim([prefix, words, suffix].join(separator));
- },
- parse: function(iso8601) {
- var s = $.trim(iso8601);
- s = s.replace(/\.\d\d\d+/,""); // remove milliseconds
- s = s.replace(/-/,"/").replace(/-/,"/");
- s = s.replace(/T/," ").replace(/Z/," UTC");
- s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
- return new Date(s);
- },
- datetime: function(elem) {
- // jQuery's `is()` doesn't play well with HTML5 in IE
- var isTime = $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
- var iso8601 = isTime ? $(elem).attr("datetime") : $(elem).attr("title");
- return $t.parse(iso8601);
- }
- });
-
- $.fn.timeago = function() {
- var self = this;
- self.each(refresh);
-
- var $s = $t.settings;
- if ($s.refreshMillis > 0) {
- setInterval(function() { self.each(refresh); }, $s.refreshMillis);
- }
- return self;
- };
-
- function refresh() {
- var data = prepareData(this);
- if (!isNaN(data.datetime)) {
- $(this).text(inWords(data.datetime));
- }
- return this;
- }
-
- function prepareData(element) {
- element = $(element);
- if (!element.data("timeago")) {
- element.data("timeago", { datetime: $t.datetime(element) });
- var text = $.trim(element.text());
- if (text.length > 0) {
- element.attr("title", text);
- }
- }
- return element.data("timeago");
- }
-
- function inWords(date) {
- var distanceMillis = distance(date);
- var seconds = Math.abs(distanceMillis) / 1000;
- var minutes = seconds / 60;
- var hours = minutes / 60;
- var days = hours / 24;
- var years = days / 365;
- var months = [
- gettext('Jan'),
- gettext('Feb'),
- gettext('Mar'),
- gettext('Apr'),
- gettext('May'),
- gettext('Jun'),
- gettext('Jul'),
- gettext('Aug'),
- gettext('Sep'),
- gettext('Oct'),
- gettext('Nov'),
- gettext('Dec')
- ];
- //todo: rewrite this in javascript
- if (days > 2){
- var month_date = months[date.getMonth()] + ' ' + date.getDate()
- if (years == 0){
- //how to do this in js???
- return month_date;
- } else {
- return month_date + ' ' + "'" + date.getYear() % 20;
- }
- } else if (days == 2) {
- return gettext('2 days ago')
- } else if (days == 1) {
- return gettext('yesterday')
- } else if (minutes >= 60) {
- return interpolate(
- ngettext(
- '%s hour ago',
- '%s hours ago',
- hours
- ),
- [Math.floor(hours),]
- )
- } else if (seconds > 90){
- return interpolate(
- ngettext(
- '%s min ago',
- '%s mins ago',
- minutes
- ),
- [Math.floor(minutes),]
- )
- } else {
- return gettext('just now')
- }
- }
-
- function distance(date) {
- return (new Date() - date);
- }
-
- // fix for IE6 suckage
- document.createElement("abbr");
- document.createElement("time");
-}(jQuery));
diff --git a/askbot/skins/common/media/js/wmd/wmd.js b/askbot/skins/common/media/js/wmd/wmd.js
deleted file mode 100644
index 98af264f..00000000
--- a/askbot/skins/common/media/js/wmd/wmd.js
+++ /dev/null
@@ -1,2492 +0,0 @@
-var Attacklab = Attacklab || {};
-
-Attacklab.wmdBase = function(){
-
- // A few handy aliases for readability.
- var wmd = top.Attacklab;
- var doc = top.document;
- var re = top.RegExp;
- var nav = top.navigator;
-
- // Some namespaces.
- wmd.Util = {};
- wmd.Position = {};
- wmd.Command = {};
- wmd.Global = {};
-
- var util = wmd.Util;
- var position = wmd.Position;
- var command = wmd.Command;
- var global = wmd.Global;
-
-
- // Used to work around some browser bugs where we can't use feature testing.
- global.isIE = /msie/.test(nav.userAgent.toLowerCase());
- global.isIE_5or6 = /msie 6/.test(nav.userAgent.toLowerCase()) || /msie 5/.test(nav.userAgent.toLowerCase());
- global.isIE_7plus = global.isIE && !global.isIE_5or6;
- global.isOpera = /opera/.test(nav.userAgent.toLowerCase());
- global.isKonqueror = /konqueror/.test(nav.userAgent.toLowerCase());
-
- var toolbar_strong_label = gettext('bold') + " <strong> Ctrl-B";
- var toolbar_emphasis_label = gettext('italic') + " <em> Ctrl-I";
- var toolbar_hyperlink_label = gettext('link') + " <a> Ctrl-L";
- var toolbar_blockquote_label = gettext('quote') + " <blockquote> Ctrl-.";
- var toolbar_code_label = gettext('preformatted text') + " <pre><code> Ctrl-K";
- var toolbar_image_label = gettext('image') + " <img> Ctrl-G";
- var toolbar_attachment_label = gettext('attachment') + " Ctrl-F";
- var toolbar_numbered_label = gettext('numbered list') + " <ol> Ctrl-O";
- var toolbar_bulleted_label = gettext('bulleted list') + " <ul> Ctrl-U";
- var toolbar_heading_label = gettext('heading') + " <h1>/<h2> Ctrl-H";
- var toolbar_horizontal_label = gettext('horizontal bar') + " <hr> Ctrl-R";
- var toolbar_undo_label = gettext('undo') + " Ctrl-Z";
- var toolbar_redo_label = gettext('redo') + " Ctrl-Y";
-
- // -------------------------------------------------------------------
- // YOUR CHANGES GO HERE
- //
- // I've tried to localize the things you are likely to change to
- // this area.
- // -------------------------------------------------------------------
-
- // The text that appears on the upper part of the dialog box when
- // entering links.
- var imageDialogText = "<p style='margin-top: 0px'>" + gettext('enter image url') + '</p>';
- var linkDialogText = "<p style='margin-top: 0px'>" + gettext('enter url') + '</p>';
- var fileDialogText = "<p>" + gettext('upload file attachment') + '</p>';
- // The default text that appears in the dialog input box when entering
- // links.
- var imageDefaultText = "http://";
- var linkDefaultText = "http://";
-
- // The location of your button images relative to the base directory.
- var imageDirectory = "images/";
-
- // Some intervals in ms. These can be adjusted to reduce the control's load.
- var previewPollInterval = 500;
- var pastePollInterval = 100;
-
- // The link and title for the help button
- var helpLink = "http://wmd-editor.com/";
- var helpHoverTitle = "WMD website";
- var helpTarget = "_blank";
- var localUploadFileName = null;
-
- // -------------------------------------------------------------------
- // END OF YOUR CHANGES
- // -------------------------------------------------------------------
-
- // A collection of the important regions on the page.
- // Cached so we don't have to keep traversing the DOM.
- wmd.PanelCollection = function(){
- this.buttonBar = doc.getElementById("wmd-button-bar");
- this.preview = doc.getElementById("previewer");
- this.output = doc.getElementById("wmd-output");
- this.input = doc.getElementById("editor");
- };
-
- // This PanelCollection object can't be filled until after the page
- // has loaded.
- wmd.panels = undefined;
-
- // Internet explorer has problems with CSS sprite buttons that use HTML
- // lists. When you click on the background image "button", IE will
- // select the non-existent link text and discard the selection in the
- // textarea. The solution to this is to cache the textarea selection
- // on the button's mousedown event and set a flag. In the part of the
- // code where we need to grab the selection, we check for the flag
- // and, if it's set, use the cached area instead of querying the
- // textarea.
- //
- // This ONLY affects Internet Explorer (tested on versions 6, 7
- // and 8) and ONLY on button clicks. Keyboard shortcuts work
- // normally since the focus never leaves the textarea.
- wmd.ieCachedRange = null; // cached textarea selection
- wmd.ieRetardedClick = false; // flag
-
- // Returns true if the DOM element is visible, false if it's hidden.
- // Checks if display is anything other than none.
- util.isVisible = function (elem) {
-
- if (window.getComputedStyle) {
- // Most browsers
- return window.getComputedStyle(elem, null).getPropertyValue("display") !== "none";
- }
- else if (elem.currentStyle) {
- // IE
- return elem.currentStyle.display !== "none";
- }
- };
-
-
- // Adds a listener callback to a DOM element which is fired on a specified
- // event.
- util.addEvent = function(elem, event, listener){
- if (elem.attachEvent) {
- // IE only. The "on" is mandatory.
- elem.attachEvent("on" + event, listener);
- }
- else {
- // Other browsers.
- elem.addEventListener(event, listener, false);
- }
- };
-
-
- // Removes a listener callback from a DOM element which is fired on a specified
- // event.
- util.removeEvent = function(elem, event, listener){
- if (elem.detachEvent) {
- // IE only. The "on" is mandatory.
- elem.detachEvent("on" + event, listener);
- }
- else {
- // Other browsers.
- elem.removeEventListener(event, listener, false);
- }
- };
-
- // Converts \r\n and \r to \n.
- util.fixEolChars = function(text){
- text = text.replace(/\r\n/g, "\n");
- text = text.replace(/\r/g, "\n");
- return text;
- };
-
- // Extends a regular expression. Returns a new RegExp
- // using pre + regex + post as the expression.
- // Used in a few functions where we have a base
- // expression and we want to pre- or append some
- // conditions to it (e.g. adding "$" to the end).
- // The flags are unchanged.
- //
- // regex is a RegExp, pre and post are strings.
- util.extendRegExp = function(regex, pre, post){
-
- if (pre === null || pre === undefined)
- {
- pre = "";
- }
- if(post === null || post === undefined)
- {
- post = "";
- }
-
- var pattern = regex.toString();
- var flags;
-
- // Replace the flags with empty space and store them.
- pattern = pattern.replace(/\/([gim]*)$/, "");
- flags = re.$1;
-
- // Remove the slash delimiters on the regular expression.
- pattern = pattern.replace(/(^\/|\/$)/g, "");
- pattern = pre + pattern + post;
-
- return new re(pattern, flags);
- };
-
-
- // Sets the image for a button passed to the WMD editor.
- // Returns a new element with the image attached.
- // Adds several style properties to the image.
- util.createImage = function(img){
-
- var imgPath = imageDirectory + img;
-
- var elem = doc.createElement("img");
- elem.className = "wmd-button";
- elem.src = imgPath;
-
- return elem;
- };
-
-
-// This simulates a modal dialog box and asks for the URL when you
-// click the hyperlink or image buttons.
-//
-// text: The html for the input box.
-// defaultInputText: The default value that appears in the input box.
-// makeLinkMarkdown: The function which is executed when the prompt is dismissed, either via OK or Cancel
-util.prompt = function(text, defaultInputText, makeLinkMarkdown, dialogType){
-
- // These variables need to be declared at this level since they are used
- // in multiple functions.
- var dialog;// The dialog box.
- var background;// The background beind the dialog box.
- var input;// The text box where you enter the hyperlink.
-
- if (defaultInputText === undefined) {
- defaultInputText = "";
- }
-
- // Used as a keydown event handler. Esc dismisses the prompt.
- // Key code 27 is ESC.
- var checkEscape = function(key){
- var code = (key.charCode || key.keyCode);
- if (code === 27) {
- close(true);
- }
- };
-
- // Dismisses the hyperlink input box.
- // isCancel is true if we don't care about the input text.
- // isCancel is false if we are going to keep the text.
- var close = function(isCancel){
- util.removeEvent(doc.body, "keydown", checkEscape);
- var text = input.value;
-
- if (isCancel){
- text = null;
- }
- else{
- // Fixes common pasting errors.
- text = text.replace('http://http://', 'http://');
- text = text.replace('http://https://', 'https://');
- text = text.replace('http://ftp://', 'ftp://');
-
- if (text.indexOf('http://') === -1 && text.indexOf('ftp://') === -1 && text.indexOf('https://') === -1) {
- if (dialogType == 'link'){
- //add http only to urls
- text = 'http://' + text;
- }
- }
- }
-
- dialog.parentNode.removeChild(dialog);
- background.parentNode.removeChild(background);
- makeLinkMarkdown(text);
- return false;
- };
-
- // Creates the background behind the hyperlink text entry box.
- // Most of this has been moved to CSS but the div creation and
- // browser-specific hacks remain here.
- var createBackground = function(){
-
- background = doc.createElement("div");
- background.className = "wmd-prompt-background";
- style = background.style;
- style.position = "absolute";
- style.top = "0";
-
- style.zIndex = "1000";
-
- // Some versions of Konqueror don't support transparent colors
- // so we make the whole window transparent.
- //
- // Is this necessary on modern konqueror browsers?
- if (global.isKonqueror){
- style.backgroundColor = "transparent";
- }
- else if (global.isIE){
- style.filter = "alpha(opacity=50)";
- }
- else {
- style.opacity = "0.5";
- }
-
- var pageSize = position.getPageSize();
- style.height = pageSize[1] + "px";
-
- if(global.isIE){
- style.left = doc.documentElement.scrollLeft;
- style.width = doc.documentElement.clientWidth;
- }
- else {
- style.left = "0";
- style.width = "100%";
- }
-
- doc.body.appendChild(background);
- };
-
- // Create the text input box form/window.
- var createDialog = function(){
-
- // The main dialog box.
- dialog = doc.createElement("div");
- dialog.className = "wmd-prompt-dialog";
- dialog.style.padding = "10px;";
- dialog.style.position = "fixed";
- dialog.style.width = "400px";
- dialog.style.zIndex = "1001";
-
- // The dialog text.
- var question = doc.createElement("div");
- question.innerHTML = text;
- question.style.padding = "5px";
- dialog.appendChild(question);
-
- // The web form container for the text box and buttons.
- var form = doc.createElement("form");
- form.onsubmit = function(){ return close(false); };
- style = form.style;
- style.padding = "0";
- style.margin = "0";
- style.cssFloat = "left";
- style.width = "100%";
- style.textAlign = "center";
- style.position = "relative";
- dialog.appendChild(form);
-
- // The input text box
- input = doc.createElement("input");
- if(dialogType == 'image' || dialogType == 'file'){
- input.id = "image-url";
- }
- input.type = "text";
- if (dialogType == 'file'){
- input.disabled = "disabled";
- };
-
- input.value = defaultInputText;
- style = input.style;
- style.display = "block";
- style.width = "80%";
- style.marginLeft = style.marginRight = "auto";
- form.appendChild(input);
-
- //EF. fucus at the end of the input box
- //putCursorAtEnd($(input));
-
- // The upload file input
- if(dialogType == 'image' || dialogType == 'file'){
- var upload_container = $('<div></div>');
- var upload_input = $('<input type="file" />');
- upload_input.attr('name', 'file-upload');
- upload_input.attr('id', 'file-upload');
- upload_input.attr('size', 26);
-
- var startUploadHandler = function(){
- localUploadFileName = $(this).val();
- return ajaxFileUpload($('#image-url'), startUploadHandler);
- };
-
- upload_input.change(startUploadHandler);
-
- upload_container.append(upload_input);
- upload_container.append($('<br/>'));
-
- var spinner = $('<img />');
- spinner.attr('id', 'loading');
- spinner.attr('src', mediaUrl("media/images/indicator.gif"));
- spinner.css('display', 'none');
-
- upload_container.append(spinner);
- upload_container.css('padding', '5px');
- $(form).append(upload_container);
- }
-
- // The ok button
- var okButton = doc.createElement("input");
- okButton.type = "button";
- okButton.onclick = function(){
- var isCancel = false;
- if ($.trim($(input).val()) === ''){
- isCancel = true;
- }
- return close(isCancel);
- };
- okButton.value = "OK";
- style = okButton.style;
- style.margin = "10px";
- style.display = "inline";
- style.width = "7em";
-
- // The cancel button
- var cancelButton = doc.createElement("input");
- cancelButton.type = "button";
- cancelButton.onclick = function(){ return close(true); };
- cancelButton.value = "Cancel";
- style = cancelButton.style;
- style.margin = "10px";
- style.display = "inline";
- style.width = "7em";
-
- // The order of these buttons is different on macs.
- if (/mac/.test(nav.platform.toLowerCase())) {
- form.appendChild(cancelButton);
- form.appendChild(okButton);
- }
- else {
- form.appendChild(okButton);
- form.appendChild(cancelButton);
- }
-
- util.addEvent(doc.body, "keydown", checkEscape);
- dialog.style.top = "50%";
- dialog.style.left = "50%";
- dialog.style.display = "block";
- if(global.isIE_5or6){
- dialog.style.position = "absolute";
- dialog.style.top = doc.documentElement.scrollTop + 200 + "px";
- dialog.style.left = "50%";
- }
- doc.body.appendChild(dialog);
-
- // This has to be done AFTER adding the dialog to the form if you
- // want it to be centered.
- dialog.style.marginTop = -(position.getHeight(dialog) / 2) + "px";
- dialog.style.marginLeft = -(position.getWidth(dialog) / 2) + "px";
-
- };
-
- createBackground();
-
- // Why is this in a zero-length timeout?
- // Is it working around a browser bug?
- top.setTimeout(function(){
- createDialog();
- var defTextLen = defaultInputText.length;
- if (input.type == 'text' && input.selectionStart !== undefined) {
- input.selectionStart = 0;
- input.selectionEnd = defTextLen;
- }
- else if (input.createTextRange) {
- var range = input.createTextRange();
- range.collapse(false);
- range.moveStart("character", -defTextLen);
- range.moveEnd("character", defTextLen);
- range.select();
- }
-
- input.focus();
- }, 0);
-};
-
-
- // UNFINISHED
- // The assignment in the while loop makes jslint cranky.
- // I'll change it to a better loop later.
- position.getTop = function(elem, isInner){
- var result = elem.offsetTop;
- if (!isInner) {
- while (elem.offsetParent) {
- elem = elem.offsetParent;
- result += elem.offsetTop;
- }
- }
- return result;
- };
-
- position.getHeight = function (elem) {
- return elem.offsetHeight || elem.scrollHeight;
- };
-
- position.getWidth = function (elem) {
- return elem.offsetWidth || elem.scrollWidth;
- };
-
- position.getPageSize = function(){
-
- var scrollWidth, scrollHeight;
- var innerWidth, innerHeight;
-
- // It's not very clear which blocks work with which browsers.
- if(self.innerHeight && self.scrollMaxY){
- scrollWidth = doc.body.scrollWidth;
- scrollHeight = self.innerHeight + self.scrollMaxY;
- }
- else if(doc.body.scrollHeight > doc.body.offsetHeight){
- scrollWidth = doc.body.scrollWidth;
- scrollHeight = doc.body.scrollHeight;
- }
- else{
- scrollWidth = doc.body.offsetWidth;
- scrollHeight = doc.body.offsetHeight;
- }
-
- if(self.innerHeight){
- // Non-IE browser
- innerWidth = self.innerWidth;
- innerHeight = self.innerHeight;
- }
- else if(doc.documentElement && doc.documentElement.clientHeight){
- // Some versions of IE (IE 6 w/ a DOCTYPE declaration)
- innerWidth = doc.documentElement.clientWidth;
- innerHeight = doc.documentElement.clientHeight;
- }
- else if(doc.body){
- // Other versions of IE
- innerWidth = doc.body.clientWidth;
- innerHeight = doc.body.clientHeight;
- }
-
- var maxWidth = Math.max(scrollWidth, innerWidth);
- var maxHeight = Math.max(scrollHeight, innerHeight);
- return [maxWidth, maxHeight, innerWidth, innerHeight];
- };
-
- // Watches the input textarea, polling at an interval and runs
- // a callback function if anything has changed.
- wmd.inputPoller = function(callback, interval){
-
- var pollerObj = this;
- var inputArea = wmd.panels.input;
-
- // Stored start, end and text. Used to see if there are changes to the input.
- var lastStart;
- var lastEnd;
- var markdown;
-
- var killHandle; // Used to cancel monitoring on destruction.
- // Checks to see if anything has changed in the textarea.
- // If so, it runs the callback.
- this.tick = function(){
-
- if (!util.isVisible(inputArea)) {
- return;
- }
-
- // Update the selection start and end, text.
- if (inputArea.selectionStart || inputArea.selectionStart === 0) {
- var start = inputArea.selectionStart;
- var end = inputArea.selectionEnd;
- if (start != lastStart || end != lastEnd) {
- lastStart = start;
- lastEnd = end;
-
- if (markdown != inputArea.value) {
- markdown = inputArea.value;
- return true;
- }
- }
- }
- return false;
- };
-
-
- var doTickCallback = function(){
-
- if (!util.isVisible(inputArea)) {
- return;
- }
-
- // If anything has changed, call the function.
- if (pollerObj.tick()) {
- callback();
- }
- };
-
- // Set how often we poll the textarea for changes.
- var assignInterval = function(){
- // previewPollInterval is set at the top of the namespace.
- killHandle = top.setInterval(doTickCallback, interval);
- };
-
- this.destroy = function(){
- top.clearInterval(killHandle);
- };
-
- assignInterval();
- };
-
- // Handles pushing and popping TextareaStates for undo/redo commands.
- // I should rename the stack variables to list.
- wmd.undoManager = function(callback){
-
- var undoObj = this;
- var undoStack = []; // A stack of undo states
- var stackPtr = 0; // The index of the current state
- var mode = "none";
- var lastState; // The last state
- var poller;
- var timer; // The setTimeout handle for cancelling the timer
- var inputStateObj;
-
- // Set the mode for later logic steps.
- var setMode = function(newMode, noSave){
-
- if (mode != newMode) {
- mode = newMode;
- if (!noSave) {
- saveState();
- }
- }
-
- if (!global.isIE || mode != "moving") {
- timer = top.setTimeout(refreshState, 1);
- }
- else {
- inputStateObj = null;
- }
- };
-
- var refreshState = function(){
- inputStateObj = new wmd.TextareaState();
- poller.tick();
- timer = undefined;
- };
-
- this.setCommandMode = function(){
- mode = "command";
- saveState();
- timer = top.setTimeout(refreshState, 0);
- };
-
- this.canUndo = function(){
- return stackPtr > 1;
- };
-
- this.canRedo = function(){
- if (undoStack[stackPtr + 1]) {
- return true;
- }
- return false;
- };
-
- // Removes the last state and restores it.
- this.undo = function(){
-
- if (undoObj.canUndo()) {
- if (lastState) {
- // What about setting state -1 to null or checking for undefined?
- lastState.restore();
- lastState = null;
- }
- else {
- undoStack[stackPtr] = new wmd.TextareaState();
- undoStack[--stackPtr].restore();
-
- if (callback) {
- callback();
- }
- }
- }
-
- mode = "none";
- wmd.panels.input.focus();
- refreshState();
- };
-
- // Redo an action.
- this.redo = function(){
-
- if (undoObj.canRedo()) {
-
- undoStack[++stackPtr].restore();
-
- if (callback) {
- callback();
- }
- }
-
- mode = "none";
- wmd.panels.input.focus();
- refreshState();
- };
-
- // Push the input area state to the stack.
- var saveState = function(){
-
- var currState = inputStateObj || new wmd.TextareaState();
-
- if (!currState) {
- return false;
- }
- if (mode == "moving") {
- if (!lastState) {
- lastState = currState;
- }
- return;
- }
- if (lastState) {
- if (undoStack[stackPtr - 1].text != lastState.text) {
- undoStack[stackPtr++] = lastState;
- }
- lastState = null;
- }
- undoStack[stackPtr++] = currState;
- undoStack[stackPtr + 1] = null;
- if (callback) {
- callback();
- }
- };
-
- var handleCtrlYZ = function(event){
-
- var handled = false;
-
- if (event.ctrlKey || event.metaKey) {
-
- // IE and Opera do not support charCode.
- var keyCode = event.charCode || event.keyCode;
- var keyCodeChar = String.fromCharCode(keyCode);
-
- switch (keyCodeChar) {
-
- case "y":
- undoObj.redo();
- handled = true;
- break;
-
- case "z":
- if (!event.shiftKey) {
- undoObj.undo();
- }
- else {
- undoObj.redo();
- }
- handled = true;
- break;
- }
- }
-
- if (handled) {
- if (event.preventDefault) {
- event.preventDefault();
- }
- if (top.event) {
- top.event.returnValue = false;
- }
- return;
- }
- };
-
- // Set the mode depending on what is going on in the input area.
- var handleModeChange = function(event){
-
- if (!event.ctrlKey && !event.metaKey) {
-
- var keyCode = event.keyCode;
-
- if ((keyCode >= 33 && keyCode <= 40) || (keyCode >= 63232 && keyCode <= 63235)) {
- // 33 - 40: page up/dn and arrow keys
- // 63232 - 63235: page up/dn and arrow keys on safari
- setMode("moving");
- }
- else if (keyCode == 8 || keyCode == 46 || keyCode == 127) {
- // 8: backspace
- // 46: delete
- // 127: delete
- setMode("deleting");
- }
- else if (keyCode == 13) {
- // 13: Enter
- setMode("newlines");
- }
- else if (keyCode == 27) {
- // 27: escape
- setMode("escape");
- }
- else if ((keyCode < 16 || keyCode > 20) && keyCode != 91) {
- // 16-20 are shift, etc.
- // 91: left window key
- // I think this might be a little messed up since there are
- // a lot of nonprinting keys above 20.
- setMode("typing");
- }
- }
- };
-
- var setEventHandlers = function(){
-
- util.addEvent(wmd.panels.input, "keypress", function(event){
- // keyCode 89: y
- // keyCode 90: z
- if ((event.ctrlKey || event.metaKey) && (event.keyCode == 89 || event.keyCode == 90)) {
- event.preventDefault();
- }
- });
-
- var handlePaste = function(){
- if (global.isIE || (inputStateObj && inputStateObj.text != wmd.panels.input.value)) {
- if (timer === undefined) {
- mode = "paste";
- saveState();
- refreshState();
- }
- }
- };
-
- // pastePollInterval is specified at the beginning of this namespace.
- poller = new wmd.inputPoller(handlePaste, pastePollInterval);
-
- util.addEvent(wmd.panels.input, "keydown", handleCtrlYZ);
- util.addEvent(wmd.panels.input, "keydown", handleModeChange);
-
- util.addEvent(wmd.panels.input, "mousedown", function(){
- setMode("moving");
- });
- wmd.panels.input.onpaste = handlePaste;
- wmd.panels.input.ondrop = handlePaste;
- };
-
- var init = function(){
- setEventHandlers();
- refreshState();
- saveState();
- };
-
- this.destroy = function(){
- if (poller) {
- poller.destroy();
- }
- };
-
- init();
- };
-
- // I think my understanding of how the buttons and callbacks are stored in the array is incomplete.
- wmd.editor = function(previewRefreshCallback){
-
- if (!previewRefreshCallback) {
- previewRefreshCallback = function(){};
- }
-
- var inputBox = wmd.panels.input;
-
- var offsetHeight = 0;
-
- var editObj = this;
-
- var mainDiv;
- var mainSpan;
-
- var div; // This name is pretty ambiguous. I should rename this.
-
- // Used to cancel recurring events from setInterval.
- var creationHandle;
-
- var undoMgr; // The undo manager
-
- var isButtonUsed = function(button){
- var buttons = $.trim(wmd.wmd_env.buttons).split(/\s+/);
- return $.inArray(button, buttons) !== -1;
- };
-
- // Perform the button's action.
- var doClick = function(button){
-
- inputBox.focus();
-
- if (button.textOp) {
-
- if (undoMgr) {
- undoMgr.setCommandMode();
- }
-
- var state = new wmd.TextareaState();
-
- if (!state) {
- return;
- }
-
- var chunks = state.getChunks();
-
- // Some commands launch a "modal" prompt dialog. Javascript
- // can't really make a modal dialog box and the WMD code
- // will continue to execute while the dialog is displayed.
- // This prevents the dialog pattern I'm used to and means
- // I can't do something like this:
- //
- // var link = CreateLinkDialog();
- // makeMarkdownLink(link);
- //
- // Instead of this straightforward method of handling a
- // dialog I have to pass any code which would execute
- // after the dialog is dismissed (e.g. link creation)
- // in a function parameter.
- //
- // Yes this is awkward and I think it sucks, but there's
- // no real workaround. Only the image and link code
- // create dialogs and require the function pointers.
- var fixupInputArea = function(){
-
- inputBox.focus();
-
- if (chunks) {
- state.setChunks(chunks);
- }
-
- state.restore();
- previewRefreshCallback();
- };
-
- var noCleanup = button.textOp(chunks, fixupInputArea);
-
- if(!noCleanup) {
- fixupInputArea();
- }
-
- }
-
- if (button.execute) {
- button.execute(editObj);
- }
- };
-
- var setUndoRedoButtonStates = function(){
- if(undoMgr){
- setupButton(document.getElementById("wmd-undo-button"), undoMgr.canUndo());
- setupButton(document.getElementById("wmd-redo-button"), undoMgr.canRedo());
- }
- };
-
- var setupButton = function(button, isEnabled) {
-
- var normalYShift = "0px";
- var disabledYShift = "-20px";
- var highlightYShift = "-40px";
-
- if(isEnabled) {
- button.style.backgroundPosition = button.XShift + " " + normalYShift;
- button.onmouseover = function(){
- this.style.backgroundPosition = this.XShift + " " + highlightYShift;
- };
-
- button.onmouseout = function(){
- this.style.backgroundPosition = this.XShift + " " + normalYShift;
- };
-
- // IE tries to select the background image "button" text (it's
- // implemented in a list item) so we have to cache the selection
- // on mousedown.
- if(global.isIE) {
- button.onmousedown = function() {
- wmd.ieRetardedClick = true;
- wmd.ieCachedRange = document.selection.createRange();
- };
- }
-
- if (!button.isHelp)
- {
- button.onclick = function() {
- if (this.onmouseout) {
- this.onmouseout();
- }
- doClick(this);
- return false;
- };
- }
- }
- else {
- button.style.backgroundPosition = button.XShift + " " + disabledYShift;
- button.onmouseover = button.onmouseout = button.onclick = function(){};
- }
- };
-
- var makeSpritedButtonRow = function(){
- var buttonBar = document.getElementById("wmd-button-bar");
- var normalYShift = "0px";
- var disabledYShift = "-20px";
- var highlightYShift = "-40px";
-
- var buttonRow = document.createElement("ul");
- buttonRow.id = "wmd-button-row";
- buttonRow = buttonBar.appendChild(buttonRow);
-
- if (isButtonUsed('bold')){
- var boldButton = document.createElement("li");
- boldButton.className = "wmd-button";
- boldButton.id = "wmd-bold-button";
- boldButton.title = toolbar_strong_label;
- boldButton.XShift = "0px";
- boldButton.textOp = command.doBold;
- setupButton(boldButton, true);
- buttonRow.appendChild(boldButton);
- }
-
- if (isButtonUsed('italic')){
- var italicButton = document.createElement("li");
- italicButton.className = "wmd-button";
- italicButton.id = "wmd-italic-button";
- italicButton.title = toolbar_emphasis_label;
- italicButton.XShift = "-20px";
- italicButton.textOp = command.doItalic;
- setupButton(italicButton, true);
- buttonRow.appendChild(italicButton);
- }
-
- if (
- isButtonUsed('link') ||
- isButtonUsed('blockquote') ||
- isButtonUsed('code') ||
- isButtonUsed('image') ||
- isButtonUsed('attachment')
- ) {
- var spacer1 = document.createElement("li");
- spacer1.className = "wmd-spacer";
- spacer1.id = "wmd-spacer1";
- buttonRow.appendChild(spacer1);
- }
-
- if (isButtonUsed('link')){
- var linkButton = document.createElement("li");
- linkButton.className = "wmd-button";
- linkButton.id = "wmd-link-button";
- linkButton.title = toolbar_hyperlink_label;
- linkButton.XShift = "-40px";
- linkButton.textOp = function(chunk, postProcessing){
- return command.doLinkOrImage(chunk, postProcessing, 'link');
- };
- setupButton(linkButton, true);
- buttonRow.appendChild(linkButton);
- }
-
- if (isButtonUsed('blockquote')){
- var quoteButton = document.createElement("li");
- quoteButton.className = "wmd-button";
- quoteButton.id = "wmd-quote-button";
- quoteButton.title = toolbar_blockquote_label;
- quoteButton.XShift = "-60px";
- quoteButton.textOp = command.doBlockquote;
- setupButton(quoteButton, true);
- buttonRow.appendChild(quoteButton);
- }
-
- if (isButtonUsed('code')){
- var codeButton = document.createElement("li");
- codeButton.className = "wmd-button";
- codeButton.id = "wmd-code-button";
- codeButton.title = toolbar_code_label;
- codeButton.XShift = "-80px";
- codeButton.textOp = command.doCode;
- setupButton(codeButton, true);
- buttonRow.appendChild(codeButton);
- }
-
- if (isButtonUsed('image')){
- var imageButton = document.createElement("li");
- imageButton.className = "wmd-button";
- imageButton.id = "wmd-image-button";
- imageButton.title = toolbar_image_label;
- imageButton.XShift = "-100px";
- imageButton.textOp = function(chunk, postProcessing){
- return command.doLinkOrImage(chunk, postProcessing, 'image');
- };
- setupButton(imageButton, true);
- buttonRow.appendChild(imageButton);
- }
-
- if (isButtonUsed('attachment')){
- var attachmentButton = document.createElement("li");
- attachmentButton.className = "wmd-button";
- attachmentButton.id = "wmd-attachment-button";
- attachmentButton.title = toolbar_attachment_label;
- attachmentButton.XShift = "-120px";
- attachmentButton.textOp = function(chunk, postProcessing){
- return command.doLinkOrImage(chunk, postProcessing, 'file');
- };
- setupButton(attachmentButton, true);
- buttonRow.appendChild(attachmentButton);
- }
-
- if (
- isButtonUsed('ol') ||
- isButtonUsed('ul') ||
- isButtonUsed('heading') ||
- isButtonUsed('hr')
- ) {
- var spacer2 = document.createElement("li");
- spacer2.className = "wmd-spacer";
- spacer2.id = "wmd-spacer2";
- buttonRow.appendChild(spacer2);
- }
-
- if (isButtonUsed('ol')) {
- var olistButton = document.createElement("li");
- olistButton.className = "wmd-button";
- olistButton.id = "wmd-olist-button";
- olistButton.title = toolbar_numbered_label;
- olistButton.XShift = "-140px";
- olistButton.textOp = function(chunk, postProcessing){
- command.doList(chunk, postProcessing, true);
- };
- setupButton(olistButton, true);
- buttonRow.appendChild(olistButton);
- }
-
- if (isButtonUsed('ul')) {
- var ulistButton = document.createElement("li");
- ulistButton.className = "wmd-button";
- ulistButton.id = "wmd-ulist-button";
- ulistButton.title = toolbar_bulleted_label;
- ulistButton.XShift = "-160px";
- ulistButton.textOp = function(chunk, postProcessing){
- command.doList(chunk, postProcessing, false);
- };
- setupButton(ulistButton, true);
- buttonRow.appendChild(ulistButton);
- }
-
- if (isButtonUsed('heading')) {
- var headingButton = document.createElement("li");
- headingButton.className = "wmd-button";
- headingButton.id = "wmd-heading-button";
- headingButton.title = toolbar_heading_label;
- headingButton.XShift = "-180px";
- headingButton.textOp = command.doHeading;
- setupButton(headingButton, true);
- buttonRow.appendChild(headingButton);
- }
-
- if (isButtonUsed('hr')) {
- var hrButton = document.createElement("li");
- hrButton.className = "wmd-button";
- hrButton.id = "wmd-hr-button";
- hrButton.title = toolbar_horizontal_label;
- hrButton.XShift = "-200px";
- hrButton.textOp = command.doHorizontalRule;
- setupButton(hrButton, true);
- buttonRow.appendChild(hrButton);
- }
-
- if (isButtonUsed('undo')){
- var spacer3 = document.createElement("li");
- spacer3.className = "wmd-spacer";
- spacer3.id = "wmd-spacer3";
- buttonRow.appendChild(spacer3);
-
- var undoButton = document.createElement("li");
- undoButton.className = "wmd-button";
- undoButton.id = "wmd-undo-button";
- undoButton.title = toolbar_undo_label;
- undoButton.XShift = "-220px";
- undoButton.execute = function(manager){
- manager.undo();
- };
- setupButton(undoButton, true);
- buttonRow.appendChild(undoButton);
-
- var redoButton = document.createElement("li");
- redoButton.className = "wmd-button";
- redoButton.id = "wmd-redo-button";
- redoButton.title = toolbar_redo_label;
- if (/win/.test(nav.platform.toLowerCase())) {
- redoButton.title = toolbar_redo_label;
- }
- else {
- // mac and other non-Windows platforms
- redoButton.title = gettext('redo') + " - Ctrl+Shift+Z";
- }
- redoButton.XShift = "-240px";
- redoButton.execute = function(manager){
- manager.redo();
- };
- setupButton(redoButton, true);
- buttonRow.appendChild(redoButton);
- setUndoRedoButtonStates();
- }
- /*
- var helpButton = document.createElement("li");
- helpButton.className = "wmd-button";
- helpButton.id = "wmd-help-button";
- helpButton.XShift = "-240px";
- helpButton.isHelp = true;
-
- var helpAnchor = document.createElement("a");
- helpAnchor.href = helpLink;
- helpAnchor.target = helpTarget
- helpAnchor.title = helpHoverTitle;
- helpButton.appendChild(helpAnchor);
-
- setupButton(helpButton, true);
- buttonRow.appendChild(helpButton);
- */
- };
-
- var setupEditor = function(){
-
- if (/\?noundo/.test(doc.location.href)) {
- wmd.nativeUndo = true;
- }
-
- if (!wmd.nativeUndo && isButtonUsed('undo')) {
- undoMgr = new wmd.undoManager(function(){
- previewRefreshCallback();
- setUndoRedoButtonStates();
- });
- }
-
- makeSpritedButtonRow();
-
-
- var keyEvent = "keydown";
- if (global.isOpera) {
- keyEvent = "keypress";
- }
-
- util.addEvent(inputBox, keyEvent, function(key){
-
- // Check to see if we have a button key and, if so execute the callback.
- if (key.ctrlKey || key.metaKey) {
-
- var keyCode = key.charCode || key.keyCode;
- var keyCodeStr = String.fromCharCode(keyCode).toLowerCase();
-
- // Bugfix for messed up DEL and .
- if (keyCode === 46) {
- keyCodeStr = "";
- }
- if (keyCode === 190) {
- keyCodeStr = ".";
- }
-
- switch(keyCodeStr) {
- case "b":
- doClick(document.getElementById("wmd-bold-button"));
- break;
- case "i":
- doClick(document.getElementById("wmd-italic-button"));
- break;
- case "l":
- doClick(document.getElementById("wmd-link-button"));
- break;
- case ".":
- doClick(document.getElementById("wmd-quote-button"));
- break;
- case "k":
- doClick(document.getElementById("wmd-code-button"));
- break;
- case "g":
- doClick(document.getElementById("wmd-image-button"));
- break;
- case "o":
- doClick(document.getElementById("wmd-olist-button"));
- break;
- case "u":
- doClick(document.getElementById("wmd-ulist-button"));
- break;
- case "h":
- doClick(document.getElementById("wmd-heading-button"));
- break;
- case "r":
- doClick(document.getElementById("wmd-hr-button"));
- break;
- case "y":
- doClick(document.getElementById("wmd-redo-button"));
- break;
- case "z":
- if(key.shiftKey) {
- doClick(document.getElementById("wmd-redo-button"));
- }
- else {
- doClick(document.getElementById("wmd-undo-button"));
- }
- break;
- default:
- return;
- }
-
-
- if (key.preventDefault) {
- key.preventDefault();
- }
-
- if (top.event) {
- top.event.returnValue = false;
- }
- }
- });
-
- // Auto-indent on shift-enter
- util.addEvent(inputBox, "keyup", function(key){
- if (key.shiftKey && !key.ctrlKey && !key.metaKey) {
- var keyCode = key.charCode || key.keyCode;
- // Character 13 is Enter
- if (keyCode === 13) {
- fakeButton = {};
- fakeButton.textOp = command.doAutoindent;
- doClick(fakeButton);
- }
- }
- });
-
- if (inputBox.form) {
- var submitCallback = inputBox.form.onsubmit;
- inputBox.form.onsubmit = function(){
- convertToHtml();
- if (submitCallback) {
- return submitCallback.apply(this, arguments);
- }
- };
- }
- };
-
- // Convert the contents of the input textarea to HTML in the output/preview panels.
- var convertToHtml = function(){
-
- if (wmd.showdown) {
- var markdownConverter = new wmd.showdown.converter();
- }
- var text = inputBox.value;
-
- var callback = function(){
- inputBox.value = text;
- //value is assigned here
- };
-
- if (!/markdown/.test(wmd.wmd_env.output.toLowerCase())) {
- if (markdownConverter) {
- inputBox.value = markdownConverter.makeHtml(text);
- //value is assigned here
- top.setTimeout(callback, 0);
- }
- }
- return true;
- };
-
-
- this.undo = function(){
- if (undoMgr) {
- undoMgr.undo();
- }
- };
-
- this.redo = function(){
- if (undoMgr) {
- undoMgr.redo();
- }
- };
-
- // This is pretty useless. The setupEditor function contents
- // should just be copied here.
- var init = function(){
- setupEditor();
- };
-
- this.destroy = function(){
- if (undoMgr) {
- undoMgr.destroy();
- }
- if (div.parentNode) {
- div.parentNode.removeChild(div);
- }
- if (inputBox) {
- inputBox.style.marginTop = "";
- }
- top.clearInterval(creationHandle);
- };
-
- init();
- };
-
- // The input textarea state/contents.
- // This is used to implement undo/redo by the undo manager.
- wmd.TextareaState = function(){
-
- // Aliases
- var stateObj = this;
- var inputArea = wmd.panels.input;
-
- this.init = function() {
-
- if (!util.isVisible(inputArea)) {
- return;
- }
-
- this.setInputAreaSelectionStartEnd();
- this.scrollTop = inputArea.scrollTop;
- if (!this.text && inputArea.selectionStart || inputArea.selectionStart === 0) {
- this.text = inputArea.value;
- }
-
- };
-
- // Sets the selected text in the input box after we've performed an
- // operation.
- this.setInputAreaSelection = function(){
-
- if (!util.isVisible(inputArea)) {
- return;
- }
-
- if (inputArea.selectionStart !== undefined && !global.isOpera) {
-
- inputArea.focus();
- inputArea.selectionStart = stateObj.start;
- inputArea.selectionEnd = stateObj.end;
- inputArea.scrollTop = stateObj.scrollTop;
- }
- else if (doc.selection) {
-
- if (doc.activeElement && doc.activeElement !== inputArea) {
- return;
- }
-
- inputArea.focus();
- var range = inputArea.createTextRange();
- range.moveStart("character", -inputArea.value.length);
- range.moveEnd("character", -inputArea.value.length);
- range.moveEnd("character", stateObj.end);
- range.moveStart("character", stateObj.start);
- range.select();
- }
- };
-
- this.setInputAreaSelectionStartEnd = function(){
-
- if (inputArea.selectionStart || inputArea.selectionStart === 0) {
-
- stateObj.start = inputArea.selectionStart;
- stateObj.end = inputArea.selectionEnd;
- }
- else if (doc.selection) {
-
- stateObj.text = util.fixEolChars(inputArea.value);
-
- // IE loses the selection in the textarea when buttons are
- // clicked. On IE we cache the selection and set a flag
- // which we check for here.
- var range;
- if(wmd.ieRetardedClick && wmd.ieCachedRange) {
- range = wmd.ieCachedRange;
- wmd.ieRetardedClick = false;
- }
- else {
- range = doc.selection.createRange();
- }
-
- var fixedRange = util.fixEolChars(range.text);
- var marker = "\x07";
- var markedRange = marker + fixedRange + marker;
- range.text = markedRange;
- var inputText = util.fixEolChars(inputArea.value);
-
- range.moveStart("character", -markedRange.length);
- range.text = fixedRange;
-
- stateObj.start = inputText.indexOf(marker);
- stateObj.end = inputText.lastIndexOf(marker) - marker.length;
-
- var len = stateObj.text.length - util.fixEolChars(inputArea.value).length;
-
- if (len) {
- range.moveStart("character", -fixedRange.length);
- while (len--) {
- fixedRange += "\n";
- stateObj.end += 1;
- }
- range.text = fixedRange;
- }
-
- this.setInputAreaSelection();
- }
- };
-
- // Restore this state into the input area.
- this.restore = function(){
-
- if (stateObj.text !== undefined && stateObj.text != inputArea.value) {
- inputArea.value = stateObj.text;
- //value is assigned here
- }
- this.setInputAreaSelection();
- inputArea.scrollTop = stateObj.scrollTop;
- };
-
- // Gets a collection of HTML chunks from the inptut textarea.
- this.getChunks = function(){
-
- var chunk = new wmd.Chunks();
-
- chunk.before = util.fixEolChars(stateObj.text.substring(0, stateObj.start));
- chunk.startTag = "";
- chunk.selection = util.fixEolChars(stateObj.text.substring(stateObj.start, stateObj.end));
- chunk.endTag = "";
- chunk.after = util.fixEolChars(stateObj.text.substring(stateObj.end));
- chunk.scrollTop = stateObj.scrollTop;
-
- return chunk;
- };
-
- // Sets the TextareaState properties given a chunk of markdown.
- this.setChunks = function(chunk){
-
- chunk.before = chunk.before + chunk.startTag;
- chunk.after = chunk.endTag + chunk.after;
-
- if (global.isOpera) {
- chunk.before = chunk.before.replace(/\n/g, "\r\n");
- chunk.selection = chunk.selection.replace(/\n/g, "\r\n");
- chunk.after = chunk.after.replace(/\n/g, "\r\n");
- }
-
- this.start = chunk.before.length;
- this.end = chunk.before.length + chunk.selection.length;
- this.text = chunk.before + chunk.selection + chunk.after;
- this.scrollTop = chunk.scrollTop;
- };
-
- this.init();
- };
-
- // before: contains all the text in the input box BEFORE the selection.
- // after: contains all the text in the input box AFTER the selection.
- wmd.Chunks = function(){
- };
-
- // startRegex: a regular expression to find the start tag
- // endRegex: a regular expresssion to find the end tag
- wmd.Chunks.prototype.findTags = function(startRegex, endRegex){
-
- var chunkObj = this;
- var regex;
-
- if (startRegex) {
-
- regex = util.extendRegExp(startRegex, "", "$");
-
- this.before = this.before.replace(regex,
- function(match){
- chunkObj.startTag = chunkObj.startTag + match;
- return "";
- });
-
- regex = util.extendRegExp(startRegex, "^", "");
-
- this.selection = this.selection.replace(regex,
- function(match){
- chunkObj.startTag = chunkObj.startTag + match;
- return "";
- });
- }
-
- if (endRegex) {
-
- regex = util.extendRegExp(endRegex, "", "$");
-
- this.selection = this.selection.replace(regex,
- function(match){
- chunkObj.endTag = match + chunkObj.endTag;
- return "";
- });
-
- regex = util.extendRegExp(endRegex, "^", "");
-
- this.after = this.after.replace(regex,
- function(match){
- chunkObj.endTag = match + chunkObj.endTag;
- return "";
- });
- }
- };
-
- // If remove is false, the whitespace is transferred
- // to the before/after regions.
- //
- // If remove is true, the whitespace disappears.
- wmd.Chunks.prototype.trimWhitespace = function(remove){
-
- this.selection = this.selection.replace(/^(\s*)/, "");
-
- if (!remove) {
- this.before += re.$1;
- }
-
- this.selection = this.selection.replace(/(\s*)$/, "");
-
- if (!remove) {
- this.after = re.$1 + this.after;
- }
- };
-
-
- wmd.Chunks.prototype.skipLines = function(nLinesBefore, nLinesAfter, findExtraNewlines){
-
- if (nLinesBefore === undefined) {
- nLinesBefore = 1;
- }
-
- if (nLinesAfter === undefined) {
- nLinesAfter = 1;
- }
-
- nLinesBefore++;
- nLinesAfter++;
-
- var regexText;
- var replacementText;
-
- this.selection = this.selection.replace(/(^\n*)/, "");
- this.startTag = this.startTag + re.$1;
- this.selection = this.selection.replace(/(\n*$)/, "");
- this.endTag = this.endTag + re.$1;
- this.startTag = this.startTag.replace(/(^\n*)/, "");
- this.before = this.before + re.$1;
- this.endTag = this.endTag.replace(/(\n*$)/, "");
- this.after = this.after + re.$1;
-
- if (this.before) {
-
- regexText = replacementText = "";
-
- while (nLinesBefore--) {
- regexText += "\\n?";
- replacementText += "\n";
- }
-
- if (findExtraNewlines) {
- regexText = "\\n*";
- }
- this.before = this.before.replace(new re(regexText + "$", ""), replacementText);
- }
-
- if (this.after) {
-
- regexText = replacementText = "";
-
- while (nLinesAfter--) {
- regexText += "\\n?";
- replacementText += "\n";
- }
- if (findExtraNewlines) {
- regexText = "\\n*";
- }
-
- this.after = this.after.replace(new re(regexText, ""), replacementText);
- }
- };
-
- // The markdown symbols - 4 spaces = code, > = blockquote, etc.
- command.prefixes = "(?:\\s{4,}|\\s*>|\\s*-\\s+|\\s*\\d+\\.|=|\\+|-|_|\\*|#|\\s*\\[[^\n]]+\\]:)";
-
- // Remove markdown symbols from the chunk selection.
- command.unwrap = function(chunk){
- var txt = new re("([^\\n])\\n(?!(\\n|" + command.prefixes + "))", "g");
- chunk.selection = chunk.selection.replace(txt, "$1 $2");
- };
-
- command.wrap = function(chunk, len){
- command.unwrap(chunk);
- var regex = new re("(.{1," + len + "})( +|$\\n?)", "gm");
-
- chunk.selection = chunk.selection.replace(regex, function(line, marked){
- if (new re("^" + command.prefixes, "").test(line)) {
- return line;
- }
- return marked + "\n";
- });
-
- chunk.selection = chunk.selection.replace(/\s+$/, "");
- };
-
- command.doBold = function(chunk, postProcessing){
- return command.doBorI(chunk, postProcessing, 2, "strong text");
- };
-
- command.doItalic = function(chunk, postProcessing){
- return command.doBorI(chunk, postProcessing, 1, "emphasized text");
- };
-
- // chunk: The selected region that will be enclosed with */**
- // nStars: 1 for italics, 2 for bold
- // insertText: If you just click the button without highlighting text, this gets inserted
- command.doBorI = function(chunk, postProcessing, nStars, insertText){
-
- // Get rid of whitespace and fixup newlines.
- chunk.trimWhitespace();
- chunk.selection = chunk.selection.replace(/\n{2,}/g, "\n");
-
- // Look for stars before and after. Is the chunk already marked up?
- chunk.before.search(/(\**$)/);
- var starsBefore = re.$1;
-
- chunk.after.search(/(^\**)/);
- var starsAfter = re.$1;
-
- var prevStars = Math.min(starsBefore.length, starsAfter.length);
-
- // Remove stars if we have to since the button acts as a toggle.
- if ((prevStars >= nStars) && (prevStars != 2 || nStars != 1)) {
- chunk.before = chunk.before.replace(re("[*]{" + nStars + "}$", ""), "");
- chunk.after = chunk.after.replace(re("^[*]{" + nStars + "}", ""), "");
- }
- else if (!chunk.selection && starsAfter) {
- // It's not really clear why this code is necessary. It just moves
- // some arbitrary stuff around.
- chunk.after = chunk.after.replace(/^([*_]*)/, "");
- chunk.before = chunk.before.replace(/(\s?)$/, "");
- var whitespace = re.$1;
- chunk.before = chunk.before + starsAfter + whitespace;
- }
- else {
-
- // In most cases, if you don't have any selected text and click the button
- // you'll get a selected, marked up region with the default text inserted.
- if (!chunk.selection && !starsAfter) {
- chunk.selection = insertText;
- }
-
- // Add the true markup.
- var markup = nStars <= 1 ? "*" : "**"; // shouldn't the test be = ?
- chunk.before = chunk.before + markup;
- chunk.after = markup + chunk.after;
- }
-
- return;
- };
-
- command.stripLinkDefs = function(text, defsToAdd){
-
- text = text.replace(/^[ ]{0,3}\[(\d+)\]:[ \t]*\n?[ \t]*<?(\S+?)>?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|$)/gm,
- function(totalMatch, id, link, newlines, title){
- defsToAdd[id] = totalMatch.replace(/\s*$/, "");
- if (newlines) {
- // Strip the title and return that separately.
- defsToAdd[id] = totalMatch.replace(/["(](.+?)[")]$/, "");
- return newlines + title;
- }
- return "";
- });
-
- return text;
- };
-
- command.addLinkDef = function(chunk, linkDef){
-
- var refNumber = 0; // The current reference number
- var defsToAdd = {}; //
- // Start with a clean slate by removing all previous link definitions.
- chunk.before = command.stripLinkDefs(chunk.before, defsToAdd);
- chunk.selection = command.stripLinkDefs(chunk.selection, defsToAdd);
- chunk.after = command.stripLinkDefs(chunk.after, defsToAdd);
-
- var defs = "";
- var regex = /(\[(?:\[[^\]]*\]|[^\[\]])*\][ ]?(?:\n[ ]*)?\[)(\d+)(\])/g;
-
- var addDefNumber = function(def){
- refNumber++;
- def = def.replace(/^[ ]{0,3}\[(\d+)\]:/, " [" + refNumber + "]:");
- defs += "\n" + def;
- };
-
- var getLink = function(wholeMatch, link, id, end){
-
- if (defsToAdd[id]) {
- addDefNumber(defsToAdd[id]);
- return link + refNumber + end;
-
- }
- return wholeMatch;
- };
-
- chunk.before = chunk.before.replace(regex, getLink);
-
- if (linkDef) {
- addDefNumber(linkDef);
- }
- else {
- chunk.selection = chunk.selection.replace(regex, getLink);
- }
-
- var refOut = refNumber;
-
- chunk.after = chunk.after.replace(regex, getLink);
-
- if (chunk.after) {
- chunk.after = chunk.after.replace(/\n*$/, "");
- }
- if (!chunk.after) {
- chunk.selection = chunk.selection.replace(/\n*$/, "");
- }
-
- chunk.after += "\n\n" + defs;
-
- return refOut;
- };
-
- command.doLinkOrImage = function(chunk, postProcessing, itemType){
-
- chunk.trimWhitespace();
- chunk.findTags(/\s*!?\[/, /\][ ]?(?:\n[ ]*)?(\[.*?\])?/);
-
- if (chunk.endTag.length > 1) {
-
- chunk.startTag = chunk.startTag.replace(/!?\[/, "");
- chunk.endTag = "";
- command.addLinkDef(chunk, null);
-
- }
- else {
-
- if (/\n\n/.test(chunk.selection)) {
- command.addLinkDef(chunk, null);
- return;
- }
-
- // The function to be executed when you enter a link and press OK or Cancel.
- // Marks up the link and adds the ref.
- var makeLinkMarkdown = function(link){
-
- if (link !== null) {
-
- chunk.startTag = chunk.endTag = "";
- //var linkDef = " [999]: " + link;
-
- //var num = command.addLinkDef(chunk, linkDef);
- chunk.startTag = (itemType == 'image') ? "![" : "[";
- chunk.endTag = "](" + link + ")";
-
- if (!chunk.selection) {
- if (itemType == 'image') {
- chunk.selection = gettext("image description");
- }
- else if (itemType == 'file'){
- chunk.selection = localUploadFileName || gettext("file name");
- localUploadFileName = null;
- }
- else {
- chunk.selection = gettext("link text");
- }
- }
- }
- else {
- if (itemType == 'image' || itemType == 'file'){
- return;
- }
- }
- postProcessing();
- };
-
- if (itemType == 'image') {
- // add forth param to identify image window
- util.prompt(imageDialogText, imageDefaultText, makeLinkMarkdown, 'image');
- }
- else if (itemType == 'file'){
- util.prompt(fileDialogText, '', makeLinkMarkdown, 'file');
- }
- else {
- util.prompt(linkDialogText, linkDefaultText, makeLinkMarkdown, 'link');
- }
- return true;
- }
-};
-
- util.makeAPI = function(){
- wmd.wmd = {};
- wmd.wmd.editor = wmd.editor;
- wmd.wmd.previewManager = wmd.previewManager;
- };
-
- util.startEditor = function(start_now, buttons){
-
- if (wmd.wmd_env.autostart === false) {
- util.makeAPI();
- return;
- }
-
- if (buttons){
- wmd.wmd_env.buttons = buttons;
- }
-
- var edit; // The editor (buttons + input + outputs) - the main object.
- var previewMgr; // The preview manager.
-
- // Fired after the page has fully loaded.
- var loadListener = function(){
-
- wmd.panels = new wmd.PanelCollection();
-
- previewMgr = new wmd.previewManager();
- var previewRefreshCallback = previewMgr.refresh;
-
- edit = new wmd.editor(previewRefreshCallback);
-
- previewMgr.refresh(true);
-
- };
-
- if (start_now){
- loadListener();
- } else {
- util.addEvent(top, "load", loadListener);
- }
- };
-
- wmd.previewManager = function(){
-
- var managerObj = this;
- var converter;
- var poller;
- var timeout;
- var elapsedTime;
- var oldInputText;
- var htmlOut;
- var maxDelay = 3000;
- var startType = "delayed"; // The other legal value is "manual"
-
- // Adds event listeners to elements and creates the input poller.
- var setupEvents = function(inputElem, listener){
-
- util.addEvent(inputElem, "input", listener);
- inputElem.onpaste = listener;
- inputElem.ondrop = listener;
-
- util.addEvent(inputElem, "keypress", listener);
- util.addEvent(inputElem, "keydown", listener);
- // previewPollInterval is set at the top of this file.
- poller = new wmd.inputPoller(listener, previewPollInterval);
- };
-
- var getDocScrollTop = function(){
-
- var result = 0;
-
- if (top.innerHeight) {
- result = top.pageYOffset;
- }
- else
- if (doc.documentElement && doc.documentElement.scrollTop) {
- result = doc.documentElement.scrollTop;
- }
- else
- if (doc.body) {
- result = doc.body.scrollTop;
- }
-
- return result;
- };
-
- var makePreviewHtml = function(){
-
- // If there are no registered preview and output panels
- // there is nothing to do.
- if (!wmd.panels.preview && !wmd.panels.output) {
- return;
- }
-
- var text = wmd.panels.input.value;
- if (text && text == oldInputText) {
- return; // Input text hasn't changed.
- }
- else {
- oldInputText = text;
- }
-
- var prevTime = new Date().getTime();
-
- if (!converter && wmd.showdown) {
- converter = new wmd.showdown.converter();
- }
-
- if (converter) {
- text = converter.makeHtml(text);
- }
-
- // Calculate the processing time of the HTML creation.
- // It's used as the delay time in the event listener.
- var currTime = new Date().getTime();
- elapsedTime = currTime - prevTime;
-
- pushPreviewHtml(text);
- htmlOut = text;
- };
-
- // setTimeout is already used. Used as an event listener.
- var applyTimeout = function(){
-
- if (timeout) {
- top.clearTimeout(timeout);
- timeout = undefined;
- }
-
- if (startType !== "manual") {
-
- var delay = 0;
-
- if (startType === "delayed") {
- delay = elapsedTime;
- }
-
- if (delay > maxDelay) {
- delay = maxDelay;
- }
- timeout = top.setTimeout(makePreviewHtml, delay);
- }
- };
-
- var getScaleFactor = function(panel){
- if (panel.scrollHeight <= panel.clientHeight) {
- return 1;
- }
- return panel.scrollTop / (panel.scrollHeight - panel.clientHeight);
- };
-
- var setPanelScrollTops = function(){
-
- if (wmd.panels.preview) {
- wmd.panels.preview.scrollTop = (wmd.panels.preview.scrollHeight - wmd.panels.preview.clientHeight) * getScaleFactor(wmd.panels.preview);
- }
-
- if (wmd.panels.output) {
- wmd.panels.output.scrollTop = (wmd.panels.output.scrollHeight - wmd.panels.output.clientHeight) * getScaleFactor(wmd.panels.output);
- }
- };
-
- this.refresh = function(requiresRefresh){
-
- if (requiresRefresh) {
- oldInputText = "";
- makePreviewHtml();
- }
- else {
- applyTimeout();
- }
- };
-
- this.processingTime = function(){
- return elapsedTime;
- };
-
- // The output HTML
- this.output = function(){
- return htmlOut;
- };
-
- // The mode can be "manual" or "delayed"
- this.setUpdateMode = function(mode){
- startType = mode;
- managerObj.refresh();
- };
-
- var isFirstTimeFilled = true;
-
- var pushPreviewHtml = function(text){
-
- var emptyTop = position.getTop(wmd.panels.input) - getDocScrollTop();
-
- // Send the encoded HTML to the output textarea/div.
- if (wmd.panels.output) {
- // The value property is only defined if the output is a textarea.
- if (wmd.panels.output.value !== undefined) {
- wmd.panels.output.value = text;
- //value is assigned here
- wmd.panels.output.readOnly = true;
- }
- // Otherwise we are just replacing the text in a div.
- // Send the HTML wrapped in <pre><code>
- else {
- var newText = text.replace(/&/g, "&amp;");
- newText = newText.replace(/</g, "&lt;");
- wmd.panels.output.innerHTML = "<pre><code>" + newText + "</code></pre>";
- }
- }
-
- if (wmd.panels.preview) {
- wmd.panels.preview.innerHTML = text;
- }
-
- setPanelScrollTops();
-
- if (isFirstTimeFilled) {
- isFirstTimeFilled = false;
- return;
- }
-
- var fullTop = position.getTop(wmd.panels.input) - getDocScrollTop();
-
- if (global.isIE) {
- top.setTimeout(function(){
- top.scrollBy(0, fullTop - emptyTop);
- }, 0);
- }
- else {
- top.scrollBy(0, fullTop - emptyTop);
- }
- };
-
- var init = function(){
-
- setupEvents(wmd.panels.input, applyTimeout);
- makePreviewHtml();
-
- if (wmd.panels.preview) {
- wmd.panels.preview.scrollTop = 0;
- }
- if (wmd.panels.output) {
- wmd.panels.output.scrollTop = 0;
- }
- };
-
- this.destroy = function(){
- if (poller) {
- poller.destroy();
- }
- };
-
- init();
- };
-
- // When making a list, hitting shift-enter will put your cursor on the next line
- // at the current indent level.
- command.doAutoindent = function(chunk, postProcessing){
-
- chunk.before = chunk.before.replace(/(\n|^)[ ]{0,3}([*+-]|\d+[.])[ \t]*\n$/, "\n\n");
- chunk.before = chunk.before.replace(/(\n|^)[ ]{0,3}>[ \t]*\n$/, "\n\n");
- chunk.before = chunk.before.replace(/(\n|^)[ \t]+\n$/, "\n\n");
-
- if(/(\n|^)[ ]{0,3}([*+-]|\d+[.])[ \t]+.*\n$/.test(chunk.before)){
- if(command.doList){
- command.doList(chunk);
- }
- }
- if(/(\n|^)[ ]{0,3}>[ \t]+.*\n$/.test(chunk.before)){
- if(command.doBlockquote){
- command.doBlockquote(chunk);
- }
- }
- if(/(\n|^)(\t|[ ]{4,}).*\n$/.test(chunk.before)){
- if(command.doCode){
- command.doCode(chunk);
- }
- }
- };
-
- command.doBlockquote = function(chunk, postProcessing){
-
- chunk.selection = chunk.selection.replace(/^(\n*)([^\r]+?)(\n*)$/,
- function(totalMatch, newlinesBefore, text, newlinesAfter){
- chunk.before += newlinesBefore;
- chunk.after = newlinesAfter + chunk.after;
- return text;
- });
-
- chunk.before = chunk.before.replace(/(>[ \t]*)$/,
- function(totalMatch, blankLine){
- chunk.selection = blankLine + chunk.selection;
- return "";
- });
-
- chunk.selection = chunk.selection.replace(/^(\s|>)+$/ ,"");
- chunk.selection = chunk.selection || "Blockquote";
-
- if(chunk.before){
- chunk.before = chunk.before.replace(/\n?$/,"\n");
- }
- if(chunk.after){
- chunk.after = chunk.after.replace(/^\n?/,"\n");
- }
-
- chunk.before = chunk.before.replace(/(((\n|^)(\n[ \t]*)*>(.+\n)*.*)+(\n[ \t]*)*$)/,
- function(totalMatch){
- chunk.startTag = totalMatch;
- return "";
- });
-
- chunk.after = chunk.after.replace(/^(((\n|^)(\n[ \t]*)*>(.+\n)*.*)+(\n[ \t]*)*)/,
- function(totalMatch){
- chunk.endTag = totalMatch;
- return "";
- });
-
- var replaceBlanksInTags = function(useBracket){
-
- var replacement = useBracket ? "> " : "";
-
- if(chunk.startTag){
- chunk.startTag = chunk.startTag.replace(/\n((>|\s)*)\n$/,
- function(totalMatch, markdown){
- return "\n" + markdown.replace(/^[ ]{0,3}>?[ \t]*$/gm, replacement) + "\n";
- });
- }
- if(chunk.endTag){
- chunk.endTag = chunk.endTag.replace(/^\n((>|\s)*)\n/,
- function(totalMatch, markdown){
- return "\n" + markdown.replace(/^[ ]{0,3}>?[ \t]*$/gm, replacement) + "\n";
- });
- }
- };
-
- if(/^(?![ ]{0,3}>)/m.test(chunk.selection)){
- command.wrap(chunk, wmd.wmd_env.lineLength - 2);
- chunk.selection = chunk.selection.replace(/^/gm, "> ");
- replaceBlanksInTags(true);
- chunk.skipLines();
- }
- else{
- chunk.selection = chunk.selection.replace(/^[ ]{0,3}> ?/gm, "");
- command.unwrap(chunk);
- replaceBlanksInTags(false);
-
- if(!/^(\n|^)[ ]{0,3}>/.test(chunk.selection) && chunk.startTag){
- chunk.startTag = chunk.startTag.replace(/\n{0,2}$/, "\n\n");
- }
-
- if(!/(\n|^)[ ]{0,3}>.*$/.test(chunk.selection) && chunk.endTag){
- chunk.endTag=chunk.endTag.replace(/^\n{0,2}/, "\n\n");
- }
- }
-
- if(!/\n/.test(chunk.selection)){
- chunk.selection = chunk.selection.replace(/^(> *)/,
- function(wholeMatch, blanks){
- chunk.startTag += blanks;
- return "";
- });
- }
- };
-
- command.doCode = function(chunk, postProcessing){
-
- var hasTextBefore = /\S[ ]*$/.test(chunk.before);
- var hasTextAfter = /^[ ]*\S/.test(chunk.after);
-
- // Use 'four space' markdown if the selection is on its own
- // line or is multiline.
- if((!hasTextAfter && !hasTextBefore) || /\n/.test(chunk.selection)){
-
- chunk.before = chunk.before.replace(/[ ]{4}$/,
- function(totalMatch){
- chunk.selection = totalMatch + chunk.selection;
- return "";
- });
-
- var nLinesBack = 1;
- var nLinesForward = 1;
-
- if(/\n(\t|[ ]{4,}).*\n$/.test(chunk.before)){
- nLinesBack = 0;
- }
- if(/^\n(\t|[ ]{4,})/.test(chunk.after)){
- nLinesForward = 0;
- }
-
- chunk.skipLines(nLinesBack, nLinesForward);
-
- if(!chunk.selection){
- chunk.startTag = " ";
- chunk.selection = "enter code here";
- }
- else {
- if(/^[ ]{0,3}\S/m.test(chunk.selection)){
- chunk.selection = chunk.selection.replace(/^/gm, " ");
- }
- else{
- chunk.selection = chunk.selection.replace(/^[ ]{4}/gm, "");
- }
- }
- }
- else{
- // Use backticks (`) to delimit the code block.
-
- chunk.trimWhitespace();
- chunk.findTags(/`/, /`/);
-
- if(!chunk.startTag && !chunk.endTag){
- chunk.startTag = chunk.endTag="`";
- if(!chunk.selection){
- chunk.selection = "enter code here";
- }
- }
- else if(chunk.endTag && !chunk.startTag){
- chunk.before += chunk.endTag;
- chunk.endTag = "";
- }
- else{
- chunk.startTag = chunk.endTag="";
- }
- }
- };
-
- command.doList = function(chunk, postProcessing, isNumberedList){
-
- // These are identical except at the very beginning and end.
- // Should probably use the regex extension function to make this clearer.
- var previousItemsRegex = /(\n|^)(([ ]{0,3}([*+-]|\d+[.])[ \t]+.*)(\n.+|\n{2,}([*+-].*|\d+[.])[ \t]+.*|\n{2,}[ \t]+\S.*)*)\n*$/;
- var nextItemsRegex = /^\n*(([ ]{0,3}([*+-]|\d+[.])[ \t]+.*)(\n.+|\n{2,}([*+-].*|\d+[.])[ \t]+.*|\n{2,}[ \t]+\S.*)*)\n*/;
-
- // The default bullet is a dash but others are possible.
- // This has nothing to do with the particular HTML bullet,
- // it's just a markdown bullet.
- var bullet = "-";
-
- // The number in a numbered list.
- var num = 1;
-
- // Get the item prefix - e.g. " 1. " for a numbered list, " - " for a bulleted list.
- var getItemPrefix = function(){
- var prefix;
- if(isNumberedList){
- prefix = " " + num + ". ";
- num++;
- }
- else{
- prefix = " " + bullet + " ";
- }
- return prefix;
- };
-
- // Fixes the prefixes of the other list items.
- var getPrefixedItem = function(itemText){
-
- // The numbering flag is unset when called by autoindent.
- if(isNumberedList === undefined){
- isNumberedList = /^\s*\d/.test(itemText);
- }
-
- // Renumber/bullet the list element.
- itemText = itemText.replace(/^[ ]{0,3}([*+-]|\d+[.])\s/gm,
- function( _ ){
- return getItemPrefix();
- });
-
- return itemText;
- };
-
- chunk.findTags(/(\n|^)*[ ]{0,3}([*+-]|\d+[.])\s+/, null);
-
- if(chunk.before && !/\n$/.test(chunk.before) && !/^\n/.test(chunk.startTag)){
- chunk.before += chunk.startTag;
- chunk.startTag = "";
- }
-
- if(chunk.startTag){
-
- var hasDigits = /\d+[.]/.test(chunk.startTag);
- chunk.startTag = "";
- chunk.selection = chunk.selection.replace(/\n[ ]{4}/g, "\n");
- command.unwrap(chunk);
- chunk.skipLines();
-
- if(hasDigits){
- // Have to renumber the bullet points if this is a numbered list.
- chunk.after = chunk.after.replace(nextItemsRegex, getPrefixedItem);
- }
- if(isNumberedList == hasDigits){
- return;
- }
- }
-
- var nLinesUp = 1;
-
- chunk.before = chunk.before.replace(previousItemsRegex,
- function(itemText){
- if(/^\s*([*+-])/.test(itemText)){
- bullet = re.$1;
- }
- nLinesUp = /[^\n]\n\n[^\n]/.test(itemText) ? 1 : 0;
- return getPrefixedItem(itemText);
- });
-
- if(!chunk.selection){
- chunk.selection = "List item";
- }
-
- var prefix = getItemPrefix();
-
- var nLinesDown = 1;
-
- chunk.after = chunk.after.replace(nextItemsRegex,
- function(itemText){
- nLinesDown = /[^\n]\n\n[^\n]/.test(itemText) ? 1 : 0;
- return getPrefixedItem(itemText);
- });
-
- chunk.trimWhitespace(true);
- chunk.skipLines(nLinesUp, nLinesDown, true);
- chunk.startTag = prefix;
- var spaces = prefix.replace(/./g, " ");
- command.wrap(chunk, wmd.wmd_env.lineLength - spaces.length);
- chunk.selection = chunk.selection.replace(/\n/g, "\n" + spaces);
-
- };
-
- command.doHeading = function(chunk, postProcessing){
-
- // Remove leading/trailing whitespace and reduce internal spaces to single spaces.
- chunk.selection = chunk.selection.replace(/\s+/g, " ");
- chunk.selection = chunk.selection.replace(/(^\s+|\s+$)/g, "");
-
- // If we clicked the button with no selected text, we just
- // make a level 2 hash header around some default text.
- if(!chunk.selection){
- chunk.startTag = "## ";
- chunk.selection = "Heading";
- chunk.endTag = " ##";
- return;
- }
-
- var headerLevel = 0; // The existing header level of the selected text.
-
- // Remove any existing hash heading markdown and save the header level.
- chunk.findTags(/#+[ ]*/, /[ ]*#+/);
- if(/#+/.test(chunk.startTag)){
- headerLevel = re.lastMatch.length;
- }
- chunk.startTag = chunk.endTag = "";
-
- // Try to get the current header level by looking for - and = in the line
- // below the selection.
- chunk.findTags(null, /\s?(-+|=+)/);
- if(/=+/.test(chunk.endTag)){
- headerLevel = 1;
- }
- if(/-+/.test(chunk.endTag)){
- headerLevel = 2;
- }
-
- // Skip to the next line so we can create the header markdown.
- chunk.startTag = chunk.endTag = "";
- chunk.skipLines(1, 1);
-
- // We make a level 2 header if there is no current header.
- // If there is a header level, we substract one from the header level.
- // If it's already a level 1 header, it's removed.
- var headerLevelToCreate = headerLevel == 0 ? 2 : headerLevel - 1;
-
- if(headerLevelToCreate > 0){
-
- // The button only creates level 1 and 2 underline headers.
- // Why not have it iterate over hash header levels? Wouldn't that be easier and cleaner?
- var headerChar = headerLevelToCreate >= 2 ? "-" : "=";
- var len = chunk.selection.length;
- if(len > wmd.wmd_env.lineLength){
- len = wmd.wmd_env.lineLength;
- }
- chunk.endTag = "\n";
- while(len--){
- chunk.endTag += headerChar;
- }
- }
- };
-
- command.doHorizontalRule = function(chunk, postProcessing){
- chunk.startTag = "----------\n";
- chunk.selection = "";
- chunk.skipLines(2, 1, true);
- }
-};
-
-
-Attacklab.wmd_env = {};
-Attacklab.account_options = {};
-Attacklab.wmd_defaults = {version:1, output:"Markdown", lineLength:40, delayLoad:false};
-
-if(!Attacklab.wmd)
-{
- Attacklab.wmd = function()
- {
- Attacklab.loadEnv = function()
- {
- var mergeEnv = function(env)
- {
- if(!env)
- {
- return;
- }
-
- for(var key in env)
- {
- Attacklab.wmd_env[key] = env[key];
- }
- };
-
- mergeEnv(Attacklab.wmd_defaults);
- mergeEnv(Attacklab.account_options);
- mergeEnv(top["wmd_options"]);
- Attacklab.full = true;
-
- var defaultButtons = "bold italic link blockquote code image attachment ol ul heading hr";
- Attacklab.wmd_env.buttons = Attacklab.wmd_env.buttons || defaultButtons;
- };
- Attacklab.loadEnv();
-
- };
-
- Attacklab.wmd();
- Attacklab.wmdBase();
- Attacklab.Util.startEditor();
-};
-
diff --git a/askbot/skins/common/media/style/jquery.autocomplete.css b/askbot/skins/common/media/style/jquery.autocomplete.css
deleted file mode 100644
index b3d7b759..00000000
--- a/askbot/skins/common/media/style/jquery.autocomplete.css
+++ /dev/null
@@ -1,37 +0,0 @@
-.acInput {
- width: 200px;
-}
-.acResults {
- padding: 0px;
- border: 1px solid WindowFrame;
- background-color: Window;
- overflow: hidden;
-}
-
-.acResults ul {
- width: 100%;
- list-style-position: outside;
- list-style: none;
- padding: 0;
- margin: 0;
-}
-
-.acResults li {
- margin: 0px;
- padding: 2px 5px;
- cursor: pointer;
- display: block;
- width: 100%;
- font: menu;
- font-size: 12px;
- overflow: hidden;
-}
-
-.acLoading {
- background : url('../images/indicator.gif') right center no-repeat;
-}
-
-.acSelect {
- background-color: Highlight;
- color: HighlightText;
-}
diff --git a/askbot/skins/common/media/style/lib_style.less b/askbot/skins/common/media/style/lib_style.less
deleted file mode 100644
index d1424137..00000000
--- a/askbot/skins/common/media/style/lib_style.less
+++ /dev/null
@@ -1,38 +0,0 @@
-/* General Predifined classes, read more in lesscss.org */
-
-/* Variables for Colors*/
-
-@header-color:#16160f;
-
-@link:#1b79bd;
-@question-link:#464646;
-@button-label:#4a757f;
-
-/* Receive exactly positions for background Sprite */
-
-.sprites(@hor,@vert,@back:url(../images/sprites.png)){
- background:@hor @vert @back;
-}
-
-
-/* CSS3 Elements */
-
-.box-shadow (@hor: 0px, @vert: 0px, @blur: 5px, @shadow: #929292){
- -webkit-box-shadow: @arguments;
- -moz-box-shadow: @arguments;
- box-shadow: @arguments;
-}
-
-.text-shadow(@hor: 0px, @vert: 0px, @blur: 5px, @shadow: #929292){
- text-shadow: @arguments;
- -moz-text-shadow: @arguments;
- -webkit-text-shadow: @arguments;
-}
-
-.rounded-corners(@radio: 5px){
- border-radius: @radio;
- -ms-border-radius: @radio;
- -moz-border-radius: @radio;
- -webkit-border-radius: @radio;
- -khtml-border-radius: @radio;
-}
diff --git a/askbot/skins/common/media/style/prettify.css b/askbot/skins/common/media/style/prettify.css
deleted file mode 100644
index 10a37577..00000000
--- a/askbot/skins/common/media/style/prettify.css
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Pretty printing styles. Used with prettify.js. */
-
-.str { color: #080; }
-.kwd { color: #008; }
-.com { color: #800; }
-.typ { color: #606; }
-.lit { color: #066; }
-.pun { color: #660; }
-.pln { color: #000; }
-.tag { color: #008; }
-.atn { color: #606; }
-.atv { color: #080; }
-.dec { color: #606; }
-pre.prettyprint { padding: 3px; border: 0px solid #888; }
-
-@media print {
- .str { color: #060; }
- .kwd { color: #006; font-weight: bold; }
- .com { color: #600; font-style: italic; }
- .typ { color: #404; font-weight: bold; }
- .lit { color: #044; }
- .pun { color: #440; }
- .pln { color: #000; }
- .tag { color: #006; font-weight: bold; }
- .atn { color: #404; }
- .atv { color: #060; }
-}
diff --git a/askbot/skins/common/media/style/style.css b/askbot/skins/common/media/style/style.css
deleted file mode 100644
index 82a812d4..00000000
--- a/askbot/skins/common/media/style/style.css
+++ /dev/null
@@ -1,2616 +0,0 @@
-@import url(jquery.autocomplete.css);
-@import "lib_style.less"; /* Library of predifined less functions styles */
-
-/* ----- General HTML Styles----- */
-
-body {
- background: #FFF;
- font-size: 14px;
- line-height: 150%;
- margin: 0;
- padding: 0;
- color: #000;
- font-family: 'Yanone Kaffeesatz', sans-serif;
-}
-
-div {
- margin: 0 auto;
- padding: 0;
-}
-
-h1, h2, h3, h4, h5, h6, ul, li, dl, dt, dd, form, img, p {
- margin: 0;
- padding: 0;
- border: none;
-}
-
-label {
- vertical-align: middle;
-}
-
-hr {
- border: none;
- border-top: 1px dashed #ccccce;
-}
-
-input, select {
- vertical-align: middle;
- font-family: Trebuchet MS, "segoe ui", Helvetica, Tahoma, Verdana, MingLiu, PMingLiu, Arial, sans-serif;
-}
-
-p {
- font-size: 14px;
- line-height: 140%;
- margin-bottom: 6px;
- padding-left: 5px;
-}
-
-a {
- color:@link;
- text-decoration: none;
- cursor: pointer;
-}
-
-h2 {
- font-size: 140%;
- padding: 3px 0 3px 5px;
-}
-
-h3 {
- font-size: 120%;
- padding: 3px 0 3px 5px;
-}
-
-ul {
- list-style: disc;
- margin-left: 20px;
- padding-left: 0px;
- margin-bottom: 1em;
-}
-
-ol {
- list-style: decimal;
- margin-left: 30px;
- margin-bottom: 1em;
- padding-left: 0px;
-}
-
-td ul {
- vertical-align: middle;
-}
-
-li input {
- margin: 3px 3px 4px 3px;
-}
-
-pre {
- font-family: Consolas, Monaco, Liberation Mono, Lucida Console, Monospace;
- font-size: 100%;
- margin-bottom: 10px;
- /*overflow: auto;*/
- background-color: #F5F5F5;
- padding-left: 5px;
- padding-top: 5px;
- /*width: 671px;*/
- padding-bottom: 20px ! ie7;
-}
-
-code {
- font-family: Consolas, Monaco, Liberation Mono, Lucida Console, Monospace;
- font-size: 100%;
-
-}
-
-blockquote {
- margin-bottom: 10px;
- margin-right: 15px;
- padding: 10px 0px 1px 10px;
- background-color: #F5F5F5;
-}
-
-/* http://pathfindersoftware.com/2007/09/developers-note-2/ */
-* html .clearfix,
-* html .paginator {
- height: 1;
- overflow: visible;
-}
-+ html .clearfix,
-+ html .paginator {
- min-height: 1%;
-}
-.clearfix:after,
-.paginator:after {
- clear: both;
- content:".";
- display:block;
- height: 0;
- visibility: hidden;
-}
-
-.badges a {
- color: #763333;
- text-decoration: underline;
-}
-
-a:hover {
- text-decoration: underline;
-}
-
-.badge-context-toggle.active {
- cursor: pointer;
- text-decoration: underline;
-}
-
-h1 {
- font-size: 160%;
- padding: 10px 0 5px 5px;
-}
-
-/* ----- Custom positions ----- */
-
-.left{float:left}
-.right{float:right}
-.clean{clear:both}
-
-
-/* ----- Notify message bar ----- */
-
-.notify {
- position: fixed;
- top: 0px;
- left: 0px;
- width: 100%;
- z-index: 100;
- padding: 0;
- text-align: center;
- background-color: #f5dd69;
- border-top:#fff 1px solid;
-
- p {
- margin-top: 6px;
- margin-bottom: 6px;
- font-size: 16px;
- color:#424242
- }
-}
-
-#close-notify {
- position: absolute;
- right: 5px;
- top: 7px;
- color: #735005;
- text-decoration: none;
- line-height: 18px;
- .sprites(-6px,-5px);
- cursor: pointer;
- width:20px;
- height:20px;
-}
-
-#close-notify:hover {
- .sprites(-26px,-5px);
-}
-
-/* ----- Header ----- */
-
-#header {
- margin-top: 0px;
- background: @header-color;
-}
-
-.content-wrapper {/* wrapper positioning class */
- width: 960px;
- margin: auto;
- position:relative;
-}
-
-#logo img{
- padding: 5px 0px 5px 0px;
-}
-
-#user-tools-nav {
- height: 20px;
- position:absolute;
- bottom: 0;
- right:0px;
- padding-bottom:5px;
-
- a {
- height: 35px;
- text-align: right;
- margin-left: 20px;
- text-decoration: underline;
- color:#d0e296;
- font-size:16px;
- }
-
- a:first-child {
- margin-left: 0;
- }
-
- a#ab-responses {
- margin-left: 3px;
- }
-
- .user-info,.user-micro-info{
- color:#b5b593;
- }
-
- a img {
- vertical-align:middle;
- margin-bottom:2px;
- }
-
- .user-info a {
- margin: 0;
- text-decoration: none;
- }
-}
-
-#meta-nav {
- float:right;
-
- a {
- color: #e2e2ae;
- padding: 0px 0px 0px 35px;
- height: 25px;
- line-height: 30px;
- margin:5px 0px 0px 10px;
- font-size: 18px;
- font-weight: 100;
- text-decoration: none;
- display: block;
- float: left;
- }
-
- a:hover {
- text-decoration: underline;
- }
-
- a.on {
- font-weight:bold;
- color: #FFF;
- text-decoration: none;
- }
-
- a.special {
- font-size: 18px;
- color: #B02B2C;
- font-weight: bold;
- text-decoration: none;
- }
-
- a.special:hover {
- text-decoration: underline;
- }
-
- #nav_tags{
- .sprites(-50px,-5px)
- }
-
- #nav_users{
- .sprites(-125px,-5px)
- }
-
- #nav_badges{
- .sprites(-210px,-5px)
- }
-}
-
-#secundary-header{
- height:55px;
- background:#e9e9e1;
- border-bottom:#d3d3c2 1px solid;
- margin-bottom:10px;
-
- #home-button{
- border-right:#afaf9e 1px solid;
- .sprites(-6px,-36px);
- height:55px;
- width:43px;
- display:block;
- float:left;
- }
-
- #home-button:hover{
- .sprites(-6px-45,-36px);
- }
-
- #scope-wrapper{
- width:688px;
- float:left;
-
- a{
- display:block;
- float:left;
- }
-
- .scope-selector{
- font-size:21px;
- color:#5a5a4b;
- height:55px;
- line-height:55px;
- margin-left:24px
- }
- .on{
- background:url(../images/scopearrow.png) no-repeat center bottom;
- }
- }
-}
-
-#searchBar {
- display:inline-block;
- background-color: #fff;
- width:412px;
- border: 1px solid #c9c9b5;
- float:right;
- height:42px;
- margin:6px 0px 0px 15px;
-
- .searchInput, .searchInputCancelable {
- font-size: 18px;
- height: 40px;
- background:#FFF;
- border:0px;
- color:#c2c2c2;
- padding-left:10px;
- font-family: 'Yanone Kaffeesatz', sans-serif;
- }
-
- .searchInput, .searchInputCancelable {
- width: 352px;
- }
-
- .searchInputCancelable {
- width: 317px;
- }
-
- .searchBtn {
- font-size: 10px;
- color: #666;
- background-color: #eee;
- height: 42px;
- border:#FFF 1px solid;
- line-height: 22px;
- text-align: center;
- float:right;
- margin: 0px;
- width:48px;
- .sprites(-98px,-36px);
- cursor:pointer;
- }
-
- .searchBtn:hover {
- .sprites(-98px-48,-36px);
- }
-
- .cancelSearchBtn {
- font-size: 30px;
- color: #ce8888;
- background:#fff;
- height: 42px;
- border:0px;
- border-left:#deded0 1px solid;
- text-align: center;
- width: 35px;
- cursor:pointer;
- }
-
- .cancelSearchBtn:hover {
- color: #d84040;
- }
-}
-
-#ask-button{
- background: url(../images/bigbutton.png) repeat-x bottom;
- line-height:44px;
- text-align:center;
- width:200px;
- height:42px;
- font-size:23px;
- color:@button-label;
- margin-top:7px;
- float:right;
- text-transform:uppercase;
- .rounded-corners(5px);
- .box-shadow(1px, 1px, 2px, #636363)
-}
-
-#ask-button:hover{
- text-decoration:none;
- background: url(../images/bigbutton.png) repeat-x top;
- .text-shadow(0px, 1px, 0px, #c6d9dd)
-}
-
-/* ----- Content layout ----- */
-
-#ContentLeft {
- width: 730px;
- float: left;
- position: relative;
-}
-
-#ContentRight {
- width: 200px;
- float: right;
- padding: 0 0px 10px 0px;
-}
-
-#ContentFull {
- float: left;
- width: 950px;
-}
-
-/* ----- Sidebar Widgets Box ----- */
-
-.box {
- background: #fff;
- padding: 10px 0px 0px 0px;
-
-
- p {
- margin-bottom: 4px;
- }
-
- p.info-box-follow-up-links {
- text-align: right;
- margin: 0;
- }
-
- h2 {
- padding-left: 0;
- background:#eceeeb;
- height:30px;
- line-height:30px;
- text-align:right;
- font-size:24px;
- font-weight:normal;
- color:#656565;
- padding-right:10px;
- margin-bottom:10px;
- }
- h3{
- color:#4a757f;
- font-size:18px;
- text-align:left;
- font-weight:normal;
- }
- .contributorback{
- background: #eceeeb url(../images/contributorsback.png) no-repeat center left;
- }
-
- label {
- color: #333;
- }
-
- ul {
- margin-left: 15px;
- }
-
- li {
- list-style-type: disc;
- font-size: 13px;
- line-height: 20px;
- margin-bottom: 10px;
- }
- ul.tags {
- list-style: none;
- margin: 0;
- padding: 0;
- line-height: 170%;
- display: block;
- }
-}
-
-img.gravatar {
- margin:1px;
-}
-
-/* ----- Tags Styles ----- */
-
-/* tag formatting is also copy-pasted in template
- because it must be the same in the emails
- askbot/models/__init__.py:format_instant_notification_email()
-*/
-
-/* tag cloud */
-
-.tag-size-1 {
- font-size:12px;
-}
-.tag-size-2 {
- font-size:13px;
-}
-.tag-size-3 {
- font-size:14px;
-}
-.tag-size-4 {
- font-size:15px;
-}
-.tag-size-5 {
- font-size:16px;
-}
-.tag-size-6 {
- font-size:17px;
-}
-.tag-size-7 {
- font-size:18px;
-}
-.tag-size-8 {
- font-size:19px;
-}
-.tag-size-9 {
- font-size:20px;
-}
-.tag-size-10 {
- font-size:21px;
-}
-
-ul.tags,
-ul.tags.marked-tags,
-ul#related-tags {
- list-style: none;
- margin: 0;
- padding: 0;
- line-height: 170%;
- display: block;
-}
-
-ul.tags li {
- float:left;
- display: block;
- margin: 0 5px 0 0;
- padding: 0;
-}
-
-.wildcard-tags {
- clear: both;
-}
-
-ul.tags.marked-tags li,
-.wildcard-tags ul.tags li {
- margin-bottom: 5px;
-}
-
-#tagSelector div.inputs {
- clear: both;
- float: none;
- margin-bottom:10px;
-}
-
-.tags-page ul.tags li,
-ul#ab-user-tags li {
- width: 160px;
-}
-
-ul#related-tags li {
- margin: 0 5px 3px 0;
- float: left;
- clear: left;
-}
-
-/* .tag-left and .tag-right are for the sliding doors decoration of tags */
-.tag-left {
- background: url(../images/tag-right.png) no-repeat right center;
- border: none;
- cursor: pointer;
- display: block;
- float: left;
- height: 18px;
- margin: 0 5px 0 0;
- padding: 0;
-}
-
-.tag-right {
- background: url(../images/tag-left.png) no-repeat left center;
- border: none;
- display: block;
- float: left;
- height: 18px;
- line-height: 20px;
- font-weight: normal;
- font-size: 11px;
- padding: 0px 7px 0px 15px;
- text-decoration: none;
- text-align: center;
- white-space: nowrap;
- vertical-align: middle;
-}
-
-.deletable-tag {
- margin-right: 3px;
- white-space: nowrap;
-}
-
-.deletable-tag .tag-right {
- padding-right: 0px;
- float: left;
-}
-.deletable-tag.tag-left {
- padding-right: 3px;
-}
-
-.tags a.tag-right,
-.tags span.tag-right {
- color: #333;
- text-decoration: none;
-}
-
-
-.users-page h1, .tags-page h1 {
- float: left;
-}
-
-.main-page h1 {
- margin-right: 5px;
-}
-
-#ground {
- width: 100%;
- clear: both;
- border-top: 1px solid #000;
- padding: 6px 0 0 0;
- text-align: center;
- background: #777;
-}
-
-#ground p {
- margin-bottom:0;
-}
-
-
-
-img.license-logo {
- margin: 6px 0 10px 0;
-}
-
-
-#askFormBar {
- display:inline-block;
- background-color: #e3e3e3;/*888a85; /*#e9b96e;*/
- border: 1px solid #aaaaaa;
- padding: 4px 7px 5px 5px;
-}
-#askFormBar p {
- width: 685px;
- margin:0 0 5px 0;
-}
-#askFormBar .questionTitleInput {
- font-size: 24px;
- line-height: 24px;
- height: 36px;
- width: 680px;
- margin: 0px;
- padding: 5px 0 0 5px;
-}
-
-#question-list {
- float: left;
- position: relative;
- background-color: #FFF;
- padding: 0;
- width: 100%;
-}
-
-.ask-page div#question-list {
- float: none;
- width: 706px;
-}
-.ask-page div#question-list h2 {
- font-size: 14px;
- padding-bottom: 0;
-}
-.ask-page div#question-list span {
- padding: 3px 7px;
- margin-right: 5px;
- background: #ccc;
-}
-
-
-
-span.delete-icon {
- padding-left: 13px;
- vertical-align: bottom;
- background: url(../images/close-small-dark.png) no-repeat;
- cursor: default;
-}
-span.delete-icon:hover {
- background: url(../images/close-small-hover.png) no-repeat;
-}
-
-.tags span.delete-icon {
- float: left;
- height: 15px;
- margin: 2px 0 0 1px;
- display: block;
-}
-
-.tag-number {
- font-weight: 700;
- display: block;
- float: left;
- font-family: sans-serif;
-}
-
-.badges .tag-number {
- float: none;
- display: inline;
- padding-right: 15px;
-}
-
-ul#search-tags {
- padding-top: 3px;
-}
-
-/* ----- Sorting top Tab ------*/
-
-.tabBar {
- background-color: #eff5f6;
- height: 30px;
- width: 412px;
- clear: both;
- margin-bottom: 3px;
- margin-top: 3px;
- float:right;
- font-family:Georgia;
- font-size:16px;
- .rounded-corners(5px);
-}
-
-.tabBar h2 {
- float: left;
-}
-
-.tabsA, .tabsC {
- float: right;
- position: relative;
- display: block;
- height: 20px;
-}
-
-/* tabsA - used for sorting */
-.tabsA { float: right; }
-.tabsC { float: left; }
-
-.tabsA a, .tabsC a{
-
- border-left: 1px solid #d0e1e4;
- color: #8b1717;
- display: block;
- float: left;
- height: 20px;
- line-height: 20px;
- padding:4px 7px 4px 7px;
- text-decoration: none;
-}
-
-.tabsA a.on, .tabsC a.on, .tabsA a:hover, .tabsC a:hover {
- color: #C22828;
-}
-
-.tabsA a.rev.on, tabsA a.rev.on:hover {
-}
-
-
-
-.tabsA .label, .tabsC .label {
- float: left;
- color: #646464;
- margin-top:4px;
- margin-right:5px;
-}
-
-.tabsB a {
- background: #eee;
- border: 1px solid #eee;
- color: #777;
- display: block;
- float: left;
- height: 22px;
- line-height: 28px;
- margin: 5px 0px 0 4px;
- padding: 0 11px 0 11px;
- text-decoration: none;
-}
-
-.rss {
- float: right;
- font-size: 16px;
- color: #f57900 !important;
- margin: 1px 8px 0 0;
- width:45px;
- padding-left: 16px;
- padding-top:3px;
- background: url(../images/feed-icon-small.png) no-repeat center right;
-}
-
-.rss:hover {
- color: #F4A731 !important;
-}
-
-
-/* ----- Question list ----- */
-
-.short-summary {
- position: relative;
- filter: inherit;
- padding: 10px;
- border-bottom: 1px solid #DDDBCE;
- margin-bottom:1px;
- overflow: hidden;
- width: 710px;
- float: left;
- background: url(../images/summary-background.png) repeat-x;
-}
-
-.short-summary h2 {
- font-size: 22px;
- font-weight:normal;
-}
-
-.short-summary a {
- color:@question-link;
-}
-
-
-.short-summary .userinfo .relativetime,
-.short-summary .userinfo a,
-.short-summary span.anonymous {
- font-size: 11px;
- clear:both;
- font-weight: normal;
- color: #555;
-}
-
-
-.short-summary .userinfo {
- text-align:center;
- line-height:16px;
-}
-
-.short-summary .counts {
- float: right;
- margin: 2px 0 0 5px;
-}
-
-.short-summary .counts .item-count {
- border:1px solid #cccccc;
- -moz-border-radius:5px;
- -webkit-border-radius:5px;
- padding:0px 5px 0px 5px;
- font-size: 17px;
- font-weight: 800;
-}
-
-.short-summary .counts .votes div,
-.short-summary .counts .views div,
-.short-summary .counts .answers div,
-.short-summary .counts .favorites div
-{
- font-size: 12px;
- line-height:14px;
- color: #555;
-}
-
-.short-summary .tags {
- margin-top: 0;
-}
-
-.no-votes .item-count {
- background: white;
- color: gray;
-}
-.some-votes .item-count {
- background: #a3d0ff;
- color: #4a4a4a;
-}
-.no-answers .item-count {
- background: #b63333;
- color: yellow;
-}
-.no-favorites .item-count {
- background: #b63333;
- color: yellow;
-}
-.some-answers .item-count {
- background: #ffed9c;
- color: #a4a4a4;
-}
-.some-favorites .item-count {
- background:#338333;
- color:#d0f5a9;
-}
-.accepted .item-count {
- background:#338333;
- color:#d0f5a9;
-}
-.no-views .item-count {
- background: gray;
- color: white;
-}
-.some-views .item-count {
- background: #ff8c8c;
- color: #4a4a4a;
-}
-
-.short-summary .votes,
-.short-summary .answers,
-.short-summary .favorites,
-.short-summary .views {
- text-align: center;
- margin: 0 3px;
- padding: 4px 2px 0px 2px;
- width: 46px;
- float: right;
- -moz-border-radius: 5px;
- -khtml-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.short-summary .views {
- width: 36px;
- padding-right: 0;
-}
-
-.short-summary h2 {
- padding-left: 0;
-}
-
-#question-table,
-.answer-table {
- margin: 2px 0 10px 0;
- border-spacing: 0px;
-}
-
-.answer-table {
- border-bottom: 1px solid #bbb;
- clear: both;
-}
-
-.evenMore {
- font-size: 14px;
- font-weight: 800;
-}
-
-.evenMore a {
- text-decoration: underline;
-}
-
-
-
-.pager {
- clear:both;
- border-top: 1px solid #777;
- margin-top: 10px;
- margin-bottom: 16px;
-}
-
-.pagesize {
- margin-top: 10px;
- margin-bottom: 16px;
- float: right;
-}
-
-/** PAGINATOR **/
-.paginator {
- padding: 5px 0 10px 0;
- font: normal 12px sans-serif;
-}
-
-.paginator .prev a, .paginator .prev a:visited,
-.paginator .next a, .paginator .next a:visited {
- border: 1px solid #fff;
- background-color: #fff;
- color: #777;
- padding: 2px 4px 3px 4px;
- font: bold 100% sans-serif;
-}
-
-.paginator .prev {
- margin-right: .5em;
-}
-
-.paginator .next {
- margin-left: .5em;
-}
-
-.paginator .page a, .paginator .page a:visited, .paginator .curr {
- padding: .25em;
- font: normal .875em verdana;
- border: 1px solid #ccc;
- background-color: #fff;
- margin: 0em .25em;
- color: #777;
-}
-
-.paginator .curr {
- background-color: #777;
- color: #fff;
- border: 1px solid #777;
- font-weight: bold;
-}
-
-.paginator .page a:hover,
-.paginator .curr a:hover,
-.paginator .prev a:hover,
-.paginator .next a:hover {
- color: #fff;
- background-color: #777;
- border: 1px solid #777;
- text-decoration: none;
-}
-
-.paginator .text {
- color: #777;
- padding: .3em;
- font: bold 100% sans-serif;
-}
-
-.paginator-container-left {
- padding: 5px 0 10px 0;
-}
-
-
-.question-page p.rss {
- float:none;
- clear:both;
- padding: 3px 0 0 1px;
- font-size: 14px;
-}
-
-.question-page p.rss a {
- padding-left: 18px;
- vertical-align: top;
-}
-
-/* badges */
-a.medal {
- font-size: 14px;
- line-height: 250%;
- font-weight: 800;
- color: #333;
- text-decoration: none;
- background: url(../images/medala.gif) no-repeat;
- border-left: 1px solid #EEE;
- border-top: 1px solid #EEE;
- border-bottom: 1px solid #CCC;
- border-right: 1px solid #CCC;
- padding: 4px 12px 4px 6px;
-}
-
-a:hover.medal {
- color: #333;
- text-decoration: none;
- background: url(../images/medala_on.gif) no-repeat;
- border-left: 1px solid #E7E296;
- border-top: 1px solid #E7E296;
- border-bottom: 1px solid #D1CA3D;
- border-right: 1px solid #D1CA3D;
-}
-
-.questions-related {
- font-weight: 700;
- word-wrap: break-word;
-}
-
-.questions-related p {
- line-height: 20px;
- margin-bottom: 10px;
- font-size: 100%;
-}
-
-.question-status {
- margin-top: 10px;
- padding: 20px;
- background-color: #F5F5F5;
- text-align: center;
-}
-
-.question-status h3 {
- font-size: 125%;
-}
-.question-body, .answer-body {
- min-height: 39px;
- line-height: 20px;
- overflow: auto;
- width: 660px;
-}
-.question-body IMG, .answer-body IMG {
- max-width: 600px;
-}
-
-.vote-buttons {
- float: left;
- text-align: center;
- padding-top: 2px;
-}
-
-.vote-buttons IMG {
- cursor: pointer;
-}
-
-.vote-buttons .button{
- -moz-border-radius: 10px;
- margin-top: 20px;
- border-radius: 10px;
- height: 20px;
- width: 80px;
- border-style: solid;
- border-width: 1px;
- padding: 8px;
- float:left;
-}
-
-.vote-buttons .followed{
- font-color: #000;
- font-style:normal;
- background: #cccccc;
-}
-
-.vote-buttons .followed div{
- font-weight: normal;
-}
-
-.vote-buttons .followed div.unfollow{
- display:none;
-}
-
-.vote-buttons .followed:hover{
- color: #fff;
- background: #8b0000;
-}
-
-.vote-buttons .followed:hover div{
- display:none;
-}
-
-.vote-buttons .followed:hover div.unfollow{
- display:inline;
- font-weight: bold;
-}
-
-.vote-buttons .follow{
- background: #cccccc;
-}
-
-.vote-buttons .follow:hover{
- background: #234f32;
- color: #fff;
- font-weight: bold;
-}
-
-.vote-number {
- font-family: Arial;
- padding: 0px 0 3px 0;
- font-size: 140%;
- font-weight: bold;
- color: #777;
-}
-
-.vote-buttons .notify-sidebar {
- text-align: left;
-}
-.vote-buttons .notify-sidebar label {
- vertical-align: top;
-}
-
-.question-img-upvote:hover {
- background: url(../images/vote-arrow-up-on.png)
-}
-
-.question-img-downvote:hover {
- background: url(../images/vote-arrow-down-on.png)
-}
-
-.question-img-favorite:hover {
- background: url(../images/vote-favorite-on.png)
-}
-
-.favorite-number {
- padding: 5px 0 0 10px;
- font-size: 100%;
- font-family: Arial;
- font-weight: bold;
- color: #777;
- text-align: left;
-}
-
-.notify-me {
- float: left;
-}
-
-.offensive-flag a {
- color: #777;
- padding: 3px;
- cursor: pointer;
-}
-
-.offensive-flag a:hover {
- background-color: #777;
- text-decoration: none;
- color: #fff;
-}
-
-.linksopt a {
- color: #777;
- padding: 3px;
- cursor: pointer;
-}
-
-.linksopt a:hover {
- background-color: #777;
- text-decoration: none;
- color: #fff;
-}
-
-.post-controls a {
- color: #777;
- padding: 3px;
- cursor: pointer;
- border: none;
- background: none;
- text-decoration: none;
-}
-
-.post-controls a:hover {
- background-color: #777;
- color: #fff;
-}
-
-.post-controls .sep {
- color: #ccc;
-}
-
-.comments {
- font-size: 12px;
- width: 650px;
- clear: both;
-}
-
-.comments .comment {
- border-top: 1px dotted #cccccc;
- margin: 0;
- overflow: auto;
-}
-
-.comments .content {
- margin-bottom: 7px;
-}
-
-.comments div.comment {
- min-height: 25px;
-}
-
-.comments div.comment:hover {
- background-color: #eee;
-}
-
-div.comment .comment-votes {
- float: left;
- width: 37px;
- line-height: 130%;
- padding: 6px 5px 6px 3px;
-}
-
-div.comment .comment-body {
- line-height: 140%;
- margin: 3px 26px 0 46px;
- padding: 5px 3px;
- color: #666;
-}
-
-div.comment .comment-body p{
- font-size:inherit;
- margin-bottom: 3px;
- padding: 0;
-}
-
-div.comment .comment-delete {
- float: right;
- width: 14px;
- line-height: 130%;
- padding: 8px 6px;
-}
-
-div.comment .upvote {
- margin: 0px;
- padding-right: 17px;
- padding-top: 2px;
- text-align: right;
- height: 20px;
- font-size: 13px;
- font-weight: bold;
- color: #777;
-}
-
-div.comment .upvote.upvoted {
- color: #d64000;
-}
-
-div.comment .upvote.hover {
- background: url(../images/go-up-grey.png) no-repeat;
- background-position: right 1px;
-}
-
-div.comment .upvote:hover {
- background: url(../images/go-up-orange.png) no-repeat;
- background-position: right 1px;
-}
-
-.comments div.controls {
- clear: both;
- background: url(../images/gray-up-arrow-h18px.png) no-repeat;
- width: 100%;
- padding-left: 12px;
- margin: 3px 0 20px 5px;
-}
-
-.comments form.post-comments {
- width: 560px;
- margin: 3px 30px 4px 45px;
-}
-
-.comments textarea {
- display: block;
- height: 42px;
- width: 572px;
- margin: 6px 0 5px 1px;
- font-family: sans-serif;
- outline: none;
- overflow:auto;
- font-size: 12px;
- line-height: 140%;
- padding-left:2px;
-}
-
-.comments input {
- margin-left: 10px;
- margin-top: 1px;
- vertical-align: top;
- width: 100px;
-}
-
-.comments .counter {
- display: inline-block;
- width: 245px;
- vertical-align: top;
-}
-
-.comments .controls a {
- color: #888888;
- padding: 0 3px 2px;
-}
-
-.comments .controls a:hover {
- background-color: #777777;
- color: white;
- text-decoration: none;
-}
-
-.comments .help-text{
- float: right;
- text-align:right;
- color: gray;
- margin-bottom: 0px;
- margin-top: 0px;
- line-height: 50%;
-}
-
-span.text-counter {
- margin-right: 20px;
-}
-
-span.form-error {
- color: #990000;
- font-weight: normal;
- margin-left: 5px;
-}
-
-p.form-item {
- margin: 0px;
-}
-
-div.comments {
- padding: 0;
-}
-
-.comments .button {
- color: black;
- font-size: 11px;
- background: #eeeeee;
- padding: 3px;
- cursor: pointer;
-}
-
-.comment a {
- background-color: inherit;
- color: blue;
- padding: 0;
-}
-
-.comment a.author, a.author:hover {
- background-color: inherit;
- color: blue;
- padding: 0;
-}
-
-.comment a.author:hover {
- text-decoration: underline;
-}
-
-.accepted-answer {
- background-color: #EBFFE6;
- border-bottom-color: #9BD59B;
-}
-
-.accepted-answer .comments .button {
- background-color: #CCFFBF;
-}
-
-.accepted-answer .comments {
- background-color: #CCFFBF;
-}
-
-.answered {
- background: #CCC;
- color: #999;
-}
-
-.answered-accepted {
- background: #CCC;
- color: #763333;
-}
-
-.answered-by-owner {
- background: #E9E9FF;
-}
-
-.answered-by-owner .comments .button {
- background-color: #E6ECFF;
-}
-
-.answered-by-owner .comments {
- background-color: #E6ECFF;
-}
-
-.answered-accepted strong {
- color: #E1E818;
-}
-
-.answer-img-accept:hover {
- background: url(../images/vote-accepted-on.png)
-}
-
-.deleted {
- background: #F4E7E7 none repeat scroll 0 0;
-}
-
-
-
-
-/* openid styles */
-.form-row {
- line-height: 25px;
-}
-
-table.form-as-table {
- margin-top: 5px;
-}
-
-table.form-as-table ul {
- list-style-type: none;
- display: inline;
-}
-
-table.form-as-table li {
- display: inline;
-}
-
-table.form-as-table td {
- text-align: right;
-}
-
-table.form-as-table th {
- text-align: left;
- font-weight: normal;
-}
-
-table.ab-subscr-form {
- width: 45em;
-}
-
-table.ab-tag-filter-form {
- width: 45em;
-}
-
-.submit-row {
- line-height: 30px;
- padding-top: 10px;
- display: block;
- clear: both;
-}
-
-.errors {
- line-height: 20px;
- color: red;
-}
-
-.error {
- color: darkred;
- margin: 0;
- font-size: 10px;
-}
-
-label.retag-error {
- color: darkred;
- padding-left: 5px;
- font-size: 10px;
-}
-
-.fieldset {
- border: none;
- margin-top: 10px;
- padding: 10px;
-}
-
-.openid-input {
- background: url(../images/openid.gif) no-repeat;
- padding-left: 15px;
- cursor: pointer;
-}
-
-.openid-login-input {
- background-position: center left;
- background: url(../images/openid.gif) no-repeat 0% 50%;
- padding: 5px 5px 5px 15px;
- cursor: pointer;
- font-family: Trebuchet MS;
- font-weight: 300;
- font-size: 150%;
- width: 500px;
-}
-
-.openid-login-submit {
- height: 40px;
- width: 80px;
- line-height: 40px;
- cursor: pointer;
- border: 1px solid #777;
- font-weight: bold;
- font-size: 120%;
-}
-
-span.form-error {
- color: #990000;
- font-size: 90%;
- font-weight: normal;
- margin-left: 5px;
-}
-
-.title-desc {
- color: #666666;
- font-size: 90%;
-}
-
-/*adjustment for editor preview*/
-#editor {
- font-size: 100%;
- min-height: 200px;
- line-height: 18px;
- width: 702px;
- margin:0;
-}
-
-#id_title {
- width: 100%;
-}
-
-.wmd-preview {
- margin: 3px 0 5px 0;
- padding: 6px;
- width: 691px;
- background-color: #F5F5F5;
- min-height: 20px;
- overflow: auto;
-}
-
-.wmd-preview pre {
- background-color: #E7F1F8;
-
-}
-
-.wmd-preview blockquote {
- background-color: #eee;
-}
-
-.wmd-preview IMG {
- max-width: 600px;
-}
-
-.preview-toggle {
- width: 100%;
- color: #666; /*letter-spacing:1px;*/
- text-align: left;
-}
-
-.preview-toggle span:hover {
- cursor: pointer;
-}
-
-.after-editor {
- margin-top: 10px;
-}
-
-.checkbox {
- margin-left:5px;
- font-weight:normal;
- cursor:help
-}
-
-.question-options {
- margin-top: 1px;
- float: left;
- color: #666;
- line-height: 13px;
-}
-.question-options label {
- vertical-align: text-bottom;
-}
-
-.ask-page input.submit,
-.edit-question-page input.submit {
- float: left;
-}
-
-.edit-content-html {
- border-top: 1px dotted #D8D2A9;
- border-bottom: 1px dotted #D8D2A9;
- margin: 5px 0 5px 0;
-}
-
-.revision {
- margin: 10px 0 10px 0;
- width: 100%;
- font-size: 13px;
-}
-
-.revision .header {
- background-color: #eee;
- padding: 5px;
- cursor: pointer;
-}
-
-.revision .author {
- background-color: #E9E9FF;
-}
-
-.revision .summary {
- padding: 5px 0 10px 0;
-}
-
-.revision .summary span {
- background-color: yellow;
- padding-left: 3px;
- padding-right: 3px;
- display: inline;
-}
-
-.revision h1 {
- font-size: 130%;
- font-weight: 600;
- padding: 15px 0 15px 0;
-}
-
-.revision-mark {
- width: 200px;
- text-align: left;
- display: inline-block;
- font-size: 90%;
- overflow: hidden;
-}
-
-.revision-number {
- font-size: 300%;
- font-weight: bold;
- font-family: sans-serif;
-}
-
-.revision .answerbody {
- padding: 10px 0 5px 10px;
-}
-
-/* Revision pages */
-del {
- color: #FF5F5F;
-}
-
-del .post-tag {
- color: #FF5F5F;
-}
-
-ins {
- background-color: #97ff97;
-}
-
-ins p{
- background-color: #97ff97;
-}
-
-ins .post-tag {
- background-color: #97ff97;
-}
-
-/*用户资料页é¢*/
-.count {
- font-family: Arial;
- font-size: 200%;
- font-weight: 700;
- color: #777
-}
-
-.scoreNumber {
- font-family: Arial;
- font-size: 35px;
- font-weight: 800;
- color: #777;
- line-height: 40px; /*letter-spacing:0px*/
- margin-top: 3px;
-}
-
-.user-details {
- font-size: 13px;
-}
-
-.user-about {
- background-color: #EEEEEE;
- height: 200px;
- line-height: 20px;
- overflow: auto;
- padding: 10px;
- width: 90%;
-}
-
-/*
-.favorites-count-off {
- color: #919191;
- float: left;
- text-align: center;
-}
-
-.favorites-count {
- color: #D4A849;
- float: left;
- text-align: center;
-}
-*/
-
-/* todo: get rid of this in html */
-.favorites-empty {
- width: 32px;
- height: 45px;
- float: left;
-}
-
-.user-info-table {
- margin-bottom: 10px;
- border-spacing: 0;
-}
-
-/* todo: remove this hack? */
-.user-stats-table .narrow {
- width: 660px;
-}
-
-.narrow .summary h3 {
- padding: 0px;
- margin: 0px;
-}
-
-.relativetime {
- font-weight: bold;
- text-decoration: none;
-}
-
-.narrow .tags {
- float: left;
-}
-
-.answer-summary {
- display: block;
- clear: both;
- padding: 3px;
-}
-
-.answer-votes {
- background-color: #EEEEEE;
- color: #555555;
- float: left;
- font-family: Arial;
- font-size: 110%;
- font-weight: bold;
- height: 15px;
- padding: 4px 4px 5px;
- text-align: center;
- text-decoration: none;
- width: 20px;
- margin-right: 10px;
-}
-
-.vote-count {
- font-family: Arial;
- font-size: 160%;
- font-weight: 700;
- color: #777;
-}
-
-/* todo: make these more semantic */
-.user-action-1 {
- font-weight: bold;
- color: #333;
-}
-
-.user-action-2 {
- font-weight: bold;
- color: #CCC;
-}
-
-.user-action-3 {
- color: #333;
-}
-
-.user-action-4 {
- color: #333;
-}
-
-.user-action-5 {
- color: darkred;
-}
-
-.user-action-6 {
- color: darkred;
-}
-
-.user-action-7 {
- color: #333;
-}
-
-.user-action-8 {
- padding: 3px;
- font-weight: bold;
- background-color: #CCC;
- color: #763333;
-}
-
-.revision-summary {
- background-color: #FFFE9B;
- padding: 2px;
-}
-
-.question-title-link a {
- font-weight: bold;
- color: #0077CC;
-}
-
-.answer-title-link a {
- color: #333;
-}
-
-/* todo: make these more semantic */
-.post-type-1 a {
- font-weight: bold;
-
-}
-
-.post-type-3 a {
- font-weight: bold;
-
-}
-
-.post-type-5 a {
- font-weight: bold;
-}
-
-.post-type-2 a {
- color: #333;
-}
-
-.post-type-4 a {
- color: #333;
-}
-
-.post-type-6 a {
- color: #333;
-}
-
-.post-type-8 a {
- color: #333;
-}
-
-.hilite {
- background-color: #ff0;
-}
-
-.hilite1 {
- background-color: #ff0;
-}
-
-.hilite2 {
- background-color: #f0f;
-}
-
-.hilite3 {
- background-color: #0ff;
-}
-
-.gold, .badge1 {
- color: #FFCC00;
-}
-
-.silver, .badge2 {
- color: #CCCCCC;
-}
-
-.bronze, .badge3 {
- color: #CC9933;
-}
-
-.score {
- font-weight: 800;
- color: #333;
-}
-
-.footerLinks {
- color: #EEE;
- font-size: 13px; /* letter-spacing:1px;*/
-}
-
-.footerLinks a {
- color: #FFF;
- font-size: 13px;
-}
-
-a.comment {
- background: #EEE;
- color: #993300;
- padding: 5px;
-}
-
-a.offensive {
- color: #999;
-}
-
-.user {
- padding: 5px;
- line-height: 140%;
- width: 170px;
-}
-
-.user ul {
- margin: 0;
- list-style-type: none;
-}
-
-.user .thumb {
- clear: both;
- float: left;
- margin-right: 4px;
- display: inline;
-}
-
-.message {
- padding: 5px;
- margin: 10px 0 10px 0;
- background-color: #eee;
- border: 1px solid #aaaaaa;
-}
-
-.message h1 {
- padding-top: 0px;
- font-size: 15px;
-}
-
-.message p {
- margin-bottom: 0px;
-}
-
-p.space-above {
- margin-top: 10px;
-}
-
-.warning {
- color: red;
-}
-
-
-
-button::-moz-focus-inner {
- padding:0;
- border:none;
-}
-.submit {
- cursor: pointer; /*letter-spacing:1px;*/
- background-color: #D4D0C8;
- height: 30px;
- border: 1px solid #777777; /* width:100px; */
- font-weight: bold;
- font-size: 120%;
-}
-
-.submit:hover {
- text-decoration: underline;
-}
-
-.submit.small {
- margin-right:5px;
- height:20px;
- font-weight:normal;
- font-size:12px;
- padding:1px 5px;
-}
-.submit.small:hover {
- text-decoration:none;
-}
-.question-page a.submit {
- display: -moz-inline-stack;
- display: inline-block;
- line-height: 30px;
- padding: 0 5px;
- *display: inline;
-}
-
-.ask-body {
- padding-right: 10px;
-}
-
-
-.noscript {
- position: fixed;
- top: 0px;
- left: 0px;
- width: 100%;
- z-index: 100;
- padding: 5px 0;
- text-align: center;
- font-family: sans-serif;
- font-size: 120%;
- font-weight: Bold;
- color: #FFFFFF;
- background-color: #AE0000;
-}
-
-.big {
- font-size: 15px;
-}
-
-.strong {
- font-weight: bold;
-}
-
-.orange {/* used in django.po */
- color: #d64000;
- font-weight: bold;
-}
-
-.grey {
- color: #808080;
-}
-
-.about div {
- padding: 10px 5px 10px 5px;
- border-top: 1px dashed #aaaaaa;
-}
-
-.highlight {
- background-color: #FFF8C6;
-}
-
-.nomargin {
- margin: 0;
-}
-
-.margin-bottom {
- margin-bottom: 10px;
-}
-
-.margin-top {
- margin-top: 10px;
-}
-
-.inline-block {
- display: inline-block;
-}
-
-.action-status {
- margin: 0;
- border: none;
- text-align: center;
- line-height: 10px;
- font-size: 12px;
- padding: 0;
-}
-
-.action-status span {
- padding: 3px 5px 3px 5px;
- background-color: #fff380; /* nice yellow */
- font-weight: normal;
- -moz-border-radius: 5px;
- -khtml-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.list-table td {
- vertical-align: top;
-}
-
-/* these need to go */
-table.form-as-table .errorlist {
- display: block;
- margin: 0;
- padding: 0 0 0 5px;
- text-align: left;
- font-size: 10px;
- color: darkred;
-}
-
-table.form-as-table input {
- display: inline;
- margin-left: 4px;
-}
-
-table.form-as-table th {
- vertical-align: bottom;
- padding-bottom: 4px;
-}
-
-.form-row-vertical {
- margin-top: 8px;
- display: block;
-}
-
-.form-row-vertical label {
- margin-bottom: 3px;
- display: block;
-}
-
-/* above stuff needs to go */
-.text-align-right {
- text-align: center;
-}
-
-ul.form-horizontal-rows {
- list-style: none;
- margin: 0;
-}
-
-ul.form-horizontal-rows li {
- position: relative;
- height: 40px;
-}
-
-ul.form-horizontal-rows label {
- display: inline-block;
-}
-
-ul.form-horizontal-rows ul.errorlist {
- list-style: none;
- color: darkred;
- font-size: 10px;
- line-height: 10px;
- position: absolute;
- top: 2px;
- left: 180px;
- text-align: left;
- margin: 0;
-}
-
-ul.form-horizontal-rows ul.errorlist li {
- height: 10px;
-}
-
-ul.form-horizontal-rows label {
- position: absolute;
- left: 0px;
- bottom: 6px;
- margin: 0px;
- line-height: 12px;
- font-size: 12px;
-}
-
-ul.form-horizontal-rows li input {
- position: absolute;
- bottom: 0px;
- left: 180px;
- margin: 0px;
-}
-
-.narrow .summary {
- float: left;
-}
-
-.user-profile-tool-links {
- font-weight: bold;
- vertical-align: top;
-}
-
-.post-controls, .post-tags {
- font-size: 11px;
- line-height: 12px;
- min-width: 200px;
- padding-left: 5px;
- margin-bottom: 5px;
-}
-
-.post-controls {
- clear: left;
- float: left;
-}
-
-ul.post-tags {
- margin-left: 7px;
-}
-ul.post-tags li {
- margin-top: 4px;
- margin-bottom: 3px;
-}
-
-ul.post-retag {
- margin-bottom:0px;
- margin-left:5px;
-}
-
-#question-controls .tags {
- margin: 0 0 3px 0;
-}
-
-.post-update-info-container {
- float: right;
- min-width: 85px;
-}
-
-.post-update-info {
- display: inline-block;
- float: right;
- font-size: 11px;
- width: 190px;
- margin-bottom: 5px;
- line-height: 14px
-}
-
-.post-update-info p {
- line-height: 13px;
- font-size: 11px;
- margin: 0 0 2px 1px;
- padding: 0;
-}
-
-.post-update-info .gravatar {
- float: left;
- margin-right: 4px;
-}
-
-
-.post-update-info p.tip {
- color: #444;
-}
-
-#tagSelector {
- padding-bottom: 2px;
- margin-bottom: 0;
-}
-
-#related-tags {
- padding-left: 3px;
-}
-
-#hideIgnoredTagsControl {
- margin: 5px 0 0 0;
-}
-
-#hideIgnoredTagsControl label {
- font-size: 12px;
- color: #666;
-}
-
-#hideIgnoredTagsCb {
- margin: 0 2px 0 1px;
-}
-
-#recaptcha_widget_div {
- width: 318px;
- float: left;
- clear: both;
-}
-
-p.signup_p {
- margin: 20px 0px 0px 0px;
-}
-
-.simple-subscribe-options ul {
- list-style: none;
- list-style-position: outside;
- margin: 0;
-}
-
-/* a workaround to set link colors correctly */
-.answer-body a {
- color:#0000ff;
-}
-.question-body a {
- color:#0000ff;
-}
-.question-body li {
- margin-bottom:0.7em;
-}
-.answer-body li {
- margin-bottom:0.7em;
-}
-.wmd-preview a {
- color:#0000ff;
-}
-.wmd-preview li {
- margin-bottom:0.7em;
-}
-
-.karma-summary {
- padding:5px;
- font-size:13px;
-}
-
-.karma-summary h3 {
- text-align: center;
- font-weight: bold;
- padding:5px;
-}
-
-.karma-diagram {
- width:377px;
- height:300px;
- float:left;
- margin-right:10px;
-}
-
-.karma-details {
- float:right;
- width:300px;
- height:250px;
- overflow-y:auto;
- word-wrap:break-word;
-}
-
-.karma-gained {
- font-weight:bold;
- background:#eee;
- width:20px;
- color:green;
- padding:5px;
-}
-
-.karma-lost {
- font-weight:bold;
- background:#eee;
- width:20px;
- color:red;
- padding:5px;
-}
-
-.search-result-summary {
- font-weight: bold;
- font-size:18px;
- line-height:22px;
- margin:0px 0px 0px 0px;
- padding:2px 0 0 0;
- float: left;
-}
-.search-tips {
- font-size:12px;
- line-height:12px;
- color: #555;
- margin:0 0 5px 0;
- padding:0px;
- clear:both;
-}
-.search-tips a {
- text-decoration: underline;
- color: #555;
-}
-
-.faq-rep-item {
- text-align:right;
- padding-right:5px;
-}
-
-
-.user-info-table .gravatar {
- margin:0;
-}
-
-.vote-notification {
- z-index: 1;
- cursor: pointer;
- display: none;
- position: absolute;
- padding: 15px;
- color: white;
- background-color: darkred;
- text-align: center;
-}
-
-.vote-notification a {
- color: white;
- text-decoration: underline;
-}
-
-#responses {
- clear:both;
- line-height:18px;
- margin-bottom:15px;
-}
-
-#responses div.face {
- float:left;
- text-align: center;
- width: 54px;
- padding: 3px;
- overflow:hidden;
-}
-
-.response-parent {
- margin-top: 18px;
-}
-
-.response-parent strong{
- font-size: 20px;
-}
-
-.re {
- min-height: 57px;
- clear: both;
- margin-top: 10px;
-}
-
-#responses input {
- float:left;
-}
-#re_tools {
- margin-bottom:10px;
-}
-#re_sections {
- margin-bottom:6px;
-}
-#re_sections .on {
- font-weight:bold;
-}
-
-.avatar-page ul {
- list-style: none;
-}
-.avatar-page li {
- display: inline;
-}
-.user-profile-page .avatar p {
- margin-bottom: 0px;
-}
-.user-profile-page .tabBar a#stats {
- margin-left: 0;
-}
-.user-profile-page img.gravatar {
- margin: 2px 0 3px 0;
-}
-.user-profile-page h3 {
- padding: 0;
- margin-top: -3px;
-}
-.userList {
- font-size: 13px;
-}
-
-img.flag {
- border: 1px solid #eee;
- vertical-align: text-top;
-}
-
-.main-page img.flag {
- vertical-align: text-bottom;
-}
-
-.facebook-share.icon, .twitter-share.icon, .linkedin-share.icon, .identica-share.icon {
- background: url(../images/sprite.png) no-repeat;
- display:block;
- text-indent:-100em;
- height:25px;
- width:25px;
-}
-.facebook-share.icon {
- background-position: -25px 0px;
-}
-.identica-share.icon {
- background-position: -85px 0px;
-}
-.twitter-share.icon {
- margin-top:10px;
- background-position: 0px 0px;
-}
-.linkedin-share.icon {
- background-position: -55px 0px;
-}
-/* Pretty printing styles. Used with prettify.js. */
-
-a.edit {
- padding-left:3px;
- color: #145bff;
-}
-
-.str { color: #080; }
-.kwd { color: #008; }
-.com { color: #800; }
-.typ { color: #606; }
-.lit { color: #066; }
-.pun { color: #660; }
-.pln { color: #000; }
-.tag { color: #008; }/* name conflict here */
-.atn { color: #606; }
-.atv { color: #080; }
-.dec { color: #606; }
-pre.prettyprint { padding: 3px; border: 0px solid #888; }
-
-@media print {
- .str { color: #060; }
- .kwd { color: #006; font-weight: bold; }
- .com { color: #600; font-style: italic; }
- .typ { color: #404; font-weight: bold; }
- .lit { color: #044; }
- .pun { color: #440; }
- .pln { color: #000; }
- .tag { color: #006; font-weight: bold; }
- .atn { color: #404; }
- .atv { color: #060; }
-}
-
-.follow-toggle {
- border: 2px solid;
- -moz-border-radius:5px;
- -webkit-border-radius:5px;
- border-radius: 5px;
- height: auto;
- width: 200px;
- float:left;
- padding: 0;
- margin-right:100%;
- margin-bottom: 10px;
-}
-
-.follow-toggle .follow{
- font-color: #000;
- font-style:normal;
- background: #4cd46f;
-}
-
-.follow-toggle .follow:hover{
- font-weight: bold;
-}
-
-.follow-toggle .unfollow{
- background: #4cd46f;
-}
-
-.follow-toggle .unfollow:hover{
- background: #d94849;
-}
-
-.follow-toggle .unfollow div.unfollow-red{
- display:none;
-}
-
-.follow-toggle .unfollow div.unfollow-green{
- background: #4cd46f;
-}
-
-.follow-toggle .unfollow:hover div.unfollow-red{
- display:inline;
- color:#fff;
- font-weight:bold;
-}
-
-.follow-toggle .unfollow:hover div.unfollow-green{
- display:none;
-}
diff --git a/askbot/skins/common/templates/authopenid/complete.html b/askbot/skins/common/templates/authopenid/complete.html
deleted file mode 100644
index 6408c8b4..00000000
--- a/askbot/skins/common/templates/authopenid/complete.html
+++ /dev/null
@@ -1,71 +0,0 @@
-{% extends "one_column_body.html" %}
-<!-- complete.html -->
-{#
-views calling this template:
-* django_authopenid.views.register with login_type='openid'
-* django_authopenid.views.signin - with login_type='legacy'
-
-purpose of this template is to allow user enter his/her name
-email and sign up for email alerts at the initial registratio
-
-parameters:
-* provider
-* login_type openid|legacy
-* username (same as screen name or username in the models, and nickname in openid sreg)
-* openid_register_form
-* openid_verify_form - not clear what this form is supposed to do, not used for legacy
-* email_feeds_form forum.forms.SimpleEmailSubscribeForm
-* openid_username_exists
-#}
-{% block head %}{% endblock %}
-{% block title %}{% spaceless %}{% trans %}Registration{% endtrans %}{% endspaceless %}{% endblock %}
-{% block content %}
- <h1>{% trans %}User registration{% endtrans %}</h1>
- {% if openid_register_form.errors %}
- <ul class="errorlist">
- {% for error in openid_register_form.non_field_errors() %}
- <li>{{error}}</li>
- {% endfor %}
- </ul>
- {% endif %}
- <div class="login">
- {% if login_type=='openid' %}
- <form name="fregister" action="{% url user_register %}" method="POST">{% csrf_token %}
- {% elif login_type=='facebook' %}
- <form name="fregister" action="" method="POST">{% csrf_token %}
- {% else %}
- <form name="fregister" action="{{ settings.LOGIN_URL }}" method="POST">{% csrf_token %}
- {% endif %}
- {{ openid_register_form.next }}
- <div class="form-row-vertical">
- <label for="id_username">
- {%- trans %}<strong>Screen Name</strong> (<i>will be shown to others</i>){% endtrans %}
- </label>
- {% if openid_register_form.username.errors %}
- <p class="error">{{ openid_register_form.username.errors|join(", ") }}</p>
- {% endif %}
- {{ openid_register_form.username }}
- </div>
- <div class="form-row-vertical margin-bottom">
- <label for="id_email">
- {%- trans %}<strong>Email Address</strong> (<i>will <strong>not</strong> be shared with
-anyone, must be valid</i>)
- {% endtrans -%}
- </label>
- {% if openid_register_form.email.errors %}
- <p class="error">{{ openid_register_form.email.errors|join(", ") }}</p>
- {% endif %}
- {{ openid_register_form.email }}
- </div>
- <p>{% trans %}<strong>Receive forum updates by email</strong>{% endtrans %}</p>
- <div class='simple-subscribe-options'>
- {{email_feeds_form.subscribe}}
- {% if email_feeds_form.errors %}
- <p class="error">{% trans %}please select one of the options above{% endtrans %}</p>
- {% endif %}
- </div>
- <div class="submit-row"><input type="submit" class="submit" name="bnewaccount" value="{% trans %}Signup{% endtrans %}"/></div>
- </form>
- </div>
-{% endblock %}
-<!-- end complete.html -->
diff --git a/askbot/skins/common/templates/authopenid/signin.html b/askbot/skins/common/templates/authopenid/signin.html
deleted file mode 100644
index f9c0cfea..00000000
--- a/askbot/skins/common/templates/authopenid/signin.html
+++ /dev/null
@@ -1,227 +0,0 @@
-{% extends "two_column_body.html" %}
-{% import "authopenid/authopenid_macros.html" as login_macros %}
-{% from "macros.html" import timeago %}
-<!-- signin.html -->
-{% block title %}{% spaceless %}{% trans %}User login{% endtrans %}{% endspaceless %}{% endblock %}
-{% block forestyle %}
- <link rel="stylesheet" type="text/css" media="screen" href="{{"/jquery-openid/openid.css"|media}}"/>
-{% endblock %}
-{% block content %}
-{% if have_buttons or view_subtype == 'email_sent' %}
- <h1 class="section-title">{{page_title}}</h1>
-{% endif %}
- {% if answer %}
- <div class="message">
- {% trans title=answer.question.title|escape, summary=answer.summary|escape %}
- Your answer to {{title}} {{summary}} will be posted once you log in
- {% endtrans %}
- </div>
- {% endif %}
- {% if question %}
- <div class="message">
- {% trans title=question.title|escape, summary=question.summary|escape %}Your question
- {{title}} {{summary}} will be posted once you log in
- {% endtrans %}
- </div>
- {% endif %}
- <p id='login-intro'>
- {% if view_subtype == 'default' and have_buttons %}
- {% trans %}Choose your favorite service below to sign in using secure OpenID or similar technology. Your external service password always stays confidential and you don't have to rememeber or create another one.{% endtrans %}
- {% elif view_subtype == 'add_openid' and have_buttons %}
- {% if existing_login_methods %}
- {% trans %}It's a good idea to make sure that your existing login methods still work, or add a new one. Please click any of the icons below to check/change or add new login methods.{% endtrans %}
- {% else %}
- {% trans %}Please add a more permanent login method by clicking one of the icons below, to avoid logging in via email each time.{% endtrans %}
- {% endif %}
- {% elif view_subtype == 'change_openid' and have_buttons %}
- {% if existing_login_methods %}
- {% trans %}Click on one of the icons below to add a new login method or re-validate an existing one.{% endtrans %}
- {% else %}
- {% trans %}You don't have a method to log in right now, please add one or more by clicking any of the icons below.{% endtrans %}
- {% endif %}
- {% elif view_subtype == 'email_sent' %}
- {% trans %}Please check your email and visit the enclosed link to re-connect to your account{% endtrans %}
- {% endif %}
- </p>
- {% if openid_error_message %}
- <p class="warning">{{ openid_error_message }}</p>
- {% endif %}
- {% if view_subtype != 'email_sent' and view_subtype != 'bad_key' %}
- <form id="signin-form" method="post" action="{{ settings.LOGIN_URL }}">{% csrf_token %}
- {# in this branch - the real signin view we display the login icons
- here we hide the local login button only if admin
- wants to always show the password login form - then
- the button is useless.
- #}
- {{ login_form.login_provider_name }}
- {{ login_form.next }}
- {{
- login_macros.provider_buttons(
- login_form = login_form,
- major_login_providers = major_login_providers,
- minor_login_providers = minor_login_providers,
- hide_local_login = settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN,
- settings = settings,
- logged_in = user.is_authenticated(),
- show_buttons = have_buttons
- )
- }}
- {% if use_password_login == True %}
- <fieldset
- id="password-fs"
- {% if user.is_anonymous() %}
- {% if not login_form.username.errors and not login_form.password_login_failed %}
- {% if not settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN %}
- style="display:none;"
- {%endif%}
- {% endif %}
- {% else %}
- {% if not login_form.new_password.errors and not login_form.new_password_retyped.errors %}
- {% if not settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN %}
- style="display:none;"
- {% endif%}
- {% endif %}
- {% endif %}
- >
- {{login_form.password_action}}
- {% if user.is_anonymous() %}
- {% if have_buttons %}
- <h2 id="password-heading">
- {% trans %}or enter your <span>user name and password</span>, then sign in{% endtrans %}
- </h2>
- {% else %}
- <h1 class="section-title">
- {% trans %}Please, sign in{% endtrans %}
- </h1>
- {% endif %}
- {% if have_buttons %}
- <p class="hint">{% trans %}(or select another login method above){% endtrans %}</p>
- {% endif %}
- {% if login_form.password_login_failed %}
- <p class="error">{% trans %}Login failed, please try again{% endtrans %}</p>
- {% endif %}
- <table class="login">
- <tr>
- <td><label for="id_username">{% trans %}Login or email{% endtrans %}</label></td>
- <td>{{login_form.username}}</td>
- </tr>
- <tr>
- <td><label for="id_password">{% trans %}Password{% endtrans %}</label></td>
- <td>{{login_form.password}}</td>
- </tr>
- </table>
- <p id="local_login_buttons">
- <input class="submit-b" name="login_with_password" type="submit" value="{% trans %}Sign in{% endtrans %}" />
- {% if settings.USE_LDAP_FOR_PASSWORD_LOGIN == False %}
- <a class="create-password-account" style="vertical-align:middle" href="{% url user_signup_with_password %}?login_provider=local">{% trans %}Create a password-protected account{% endtrans %}</a>
- {% endif %}
- </p>
- {% elif settings.USE_LDAP_FOR_PASSWORD_LOGIN == False %}
- <h2 id="password-heading">
- {% trans %}To change your password - please enter the new one twice, then submit{% endtrans %}
- </h2>
- <table class="login">
- <tr>
- <td><label for="id_new_password">{% trans %}New password{% endtrans %}</label></td>
- <td>
- {{login_form.new_password}}
- </td>
- <td>
- <span class="error">{{login_form.new_password.errors[0]}}</span>
- </td>
- </tr>
- <tr>
- <td><label for="id_new_password_retyped">{% trans %}Please, retype{% endtrans %}</label></td>
- <td>
- {{login_form.new_password_retyped}}
- </td>
- <td>
- <span class="error">{{login_form.new_password_retyped.errors[0]}}</span>
- </td>
- </tr>
- </table>
- <p id="local_login_buttons">
- <input class="submit-b" name="change_password" type="submit" value="{% trans %}Change password{% endtrans %}" />
- </p>
- {% endif %}
- </fieldset>
- {% endif %}
- </form>
- {% if user.is_authenticated() and existing_login_methods and settings.ALLOW_ADD_REMOVE_LOGIN_METHODS %}
- <div
- id='existing-login-methods'
- {% if login_form.password_change_failed %}
- style="display:none";
- {% endif %}
- >
- <h2 id='ab-show-login-methods'>
- {% trans %}Here are your current login methods{% endtrans %}
- </h2>
- <table id='ab-existing-login-methods'>
- <tr>
- <th>{% trans %}provider{% endtrans %}</th>
- <th>{% trans %}last used{% endtrans %}</th>
- <th>{% trans %}delete, if you like{% endtrans %}</th>
- </tr>
- {% for login_method in existing_login_methods %}
- <tr class="ab-provider-row">
- <td class="ab-provider-name">
- {{login_method.provider_name}}
- </td>
- <td>
- {% if login_method.last_used_timestamp %}
- {{ timeago(login_method.last_used_timestamp) }}
- {% endif %}
- </td>
- <td>
- {% if login_method.is_deletable %}
- <button>{% trans %}delete{% endtrans %}</button>
- {% else %}
- {% trans %}cannot be deleted{% endtrans %}
- {% endif %}
- </td>
- </tr>
- {% endfor %}
- </table>
- </div>
- {% endif %}
- {% endif %}
- {% if view_subtype != 'email_sent' or view_subtype == 'bad_key' %}
- {% if user.is_anonymous() and settings.ALLOW_ACCOUNT_RECOVERY_BY_EMAIL %}
- <form id="account-recovery-form" action="{% url user_account_recover %}" method="post">{% csrf_token %}
- {% if view_subtype != 'bad_key' %}
- <h2 id='account-recovery-heading'>{% trans %}Still have trouble signing in?{% endtrans %}</h2>
- {% endif %}
- <p class="hint">
- <span class="text">
- {% if view_subtype == 'bad_key' %}
- {% trans %}Please, enter your email address below and obtain a new key{% endtrans %}
- {% else %}
- {% trans %}Please, enter your email address below to recover your account{% endtrans %}
- {% endif %}
- </span>
- <span style="display:none" class="link"> - <a href="#">{% trans %}recover your account via email{% endtrans %}</a></span>
- </p>
- <fieldset id='email-input-fs'>
- {% if account_recovery_form.email.errors %}
- <p class="error">{{account_recovery_form.email.errors[0]}}</p>
- {% endif %}
- {{ account_recovery_form.email }}
- <input
- class="submit-b"
- type="submit"
- {% if view_subtype == 'bad_key' %}
- value="{% trans %}Send a new recovery key{% endtrans %}"
- {% else %}
- value="{% trans %}Recover your account via email{% endtrans %}"
- {% endif %}
- />
- </fieldset>
- </form>
- {% endif %}
- {% endif %}
-{% endblock %}
-{% block endjs %}
-{% include "authopenid/providers_javascript.html" %}
-{% endblock %}
-<!-- end signin.html -->
diff --git a/askbot/skins/common/templates/authopenid/signup_with_password.html b/askbot/skins/common/templates/authopenid/signup_with_password.html
deleted file mode 100644
index e65cd518..00000000
--- a/askbot/skins/common/templates/authopenid/signup_with_password.html
+++ /dev/null
@@ -1,64 +0,0 @@
-{% extends "one_column_body.html" %}
-{% import "authopenid/authopenid_macros.html" as login_macros %}
-<!--signup.html-->
-{% block title %}{% spaceless %}{% trans %}Signup{% endtrans %}{% endspaceless %}{% endblock %}
-{% block forestyle %}
- <link rel="stylesheet" type="text/css" media="screen" href="{{"/jquery-openid/openid.css"|media}}"/>
-{% endblock %}
-{% block content %}
-{% if settings.PASSWORD_REGISTER_SHOW_PROVIDER_BUTTONS == True %}
- <h1 class="section-title">{% trans %}Please register by clicking on any of the icons below{% endtrans %}</h1>
- <form id="signin-form" method="post" action="{{ settings.LOGIN_URL }}">{% csrf_token %}
- {# hide_local_login == True because it is password reg form #}
- {{
- login_macros.provider_buttons(
- login_form = login_form,
- major_login_providers = major_login_providers,
- minor_login_providers = minor_login_providers,
- hide_local_login = True,
- settings = settings
- )
- }}
- </form>
- <h2>{% trans %}or create a new user name and password here{% endtrans %}</h2>
-{% else %}
- <h1 class="section-title">{% trans %}Create login name and password{% endtrans %}</h1>
- <!--p class="message">{% trans %}<span class='strong big'>If you prefer, create your forum login name and
-password here. However</span>, please keep in mind that we also support
-<strong>OpenID</strong> login method. With <strong>OpenID</strong> you can
-simply reuse your external login (e.g. Gmail or AOL) without ever sharing
-your login details with anyone and having to remember yet another password.{% endtrans %}</p-->
-{%endif%}
-<form action="{% url user_signup_with_password %}" method="post" accept-charset="utf-8">{% csrf_token %}
- {{form.login_provider}}
- <ul class="form-horizontal-rows">
- <li><label for="usename_id">{{form.username.label}}</label>{{form.username}}{{form.username.errors}}</li>
- <li><label for="email_id">{{form.email.label}}</label>{{form.email}}{{form.email.errors}}</li>
- <li><label for="password1_id">{{form.password1.label}}</label>{{form.password1}}{{form.password1.errors}}</li>
- <li><label for="password2_id">{{form.password2.label}}</label>{{form.password2}}{{form.password2.errors}}</li>
- </ul>
- <p style="margin-top: 10px">
- {% trans %}<strong>Receive periodic updates by email</strong>{% endtrans %}
- </p>
- <div class='simple-subscribe-options'>
- {{email_feeds_form.subscribe}}
- {% if email_feeds_form.errors %}
- <p class="error">{% trans %}please select one of the options above{% endtrans %}</p>
- {% endif %}
- </div>
- {% if settings.USE_RECAPTCHA %}
- <p class="signup_p">{% trans %}Please read and type in the two words below to help us prevent automated account creation.{% endtrans %}</p>
- {{form.recaptcha}}
- {% endif %}
- <div class="submit-row"><input type="submit" class="submit" value="{% trans %}Signup{% endtrans %}" />
- {% if settings.PASSWORD_REGISTER_SHOW_PROVIDER_BUTTONS == False %}
- <strong>{% trans %}or{% endtrans %}
- <a href="{{ settings.LOGIN_URL }}">{% trans %}return to OpenID login{% endtrans %}</a></strong>
- {% endif %}
- </div>
-</form>
-{% endblock %}
-{%block endjs%}
-{%include "authopenid/providers_javascript.html" %}
-{%endblock%}
-<!--end signup.html-->
diff --git a/askbot/skins/common/templates/question/answer_controls.html b/askbot/skins/common/templates/question/answer_controls.html
deleted file mode 100644
index 50f40144..00000000
--- a/askbot/skins/common/templates/question/answer_controls.html
+++ /dev/null
@@ -1,45 +0,0 @@
-{#<span class="action-link swap-qa">
- <a id="swap-question-with-answer-{{answer.id}}">{% trans %}swap with question{% endtrans %}</a>
-</span>uncomment if needed#}
-<span class="action-link">
- <a class="permant-link"
- href="{{ answer.get_absolute_url(question_post=question) }}"
- title="{% trans %}permanent link{% endtrans %}">
- {% trans %}link{% endtrans %}
- </a>
-</span>
-<span id='post-{{answer.id}}-delete' class="action-link delete-post">
- <a class="question-delete"
- >{% if answer.deleted %}{% trans %}undelete{% endtrans %}{% else %}{% trans %}delete{% endtrans %}{% endif %}</a>
-</span>
-{% if answer.offensive_flag_count > 0 %}
-<span
- id="answer-offensive-remove-flag-{{ answer.id }}"
- class="action-link offensive-flag"
- title="{% trans %}remove offensive flag{% endtrans %}"
->
- <a class="question-flag">{% trans %}remove flag{% endtrans %}</a>
-</span>
-<span
- id="answer-offensive-flag-{{ answer.id }}"
- class="action-link offensive-flag"
- title="{% trans %}report as offensive (i.e containing spam, advertising, malicious text, etc.){% endtrans %}"
->
- <a class="question-flag">{% trans %}flag offensive{% endtrans %} ({{ answer.offensive_flag_count }})</a>
- </a>
-</span>
-{% else %}
-<span
- id="answer-offensive-flag-{{ answer.id }}"
- class="action-link offensive-flag"
- title="{% trans %}report as offensive (i.e containing spam, advertising, malicious text, etc.){% endtrans %}"
->
- <a class="question-flag">{% trans %}flag offensive{% endtrans %}</a>
-</span>
-{% endif %}
-<span id='post-{{answer.id}}-edit' class="action-link">
- <a class="question-edit" href="{% url edit_answer answer.id %}">{% trans %}edit{% endtrans %}</a>
-</span>
-<script type="text/javascript">
- askbot['functions']['renderPostControls']('{{answer.id}}');
-</script>
diff --git a/askbot/skins/common/templates/widgets/edit_post.html b/askbot/skins/common/templates/widgets/edit_post.html
deleted file mode 100644
index 66f79237..00000000
--- a/askbot/skins/common/templates/widgets/edit_post.html
+++ /dev/null
@@ -1,65 +0,0 @@
-{% if edit_title %}
- <div class="form-item">
- <label for="id_title" ><strong>{{ post_form.title.label_tag() }}:</strong></label> <span class="form-error"></span><br/>
- {{ post_form.title }} {{ post_form.title.errors }}
- <div class="title-desc">
- {{ post_form.title.help_text }}
- </div>
- </div>
-{% endif %}
-<div class='wmd-container'>
- <div id="wmd-button-bar" class="wmd-panel"></div>
- {{ post_form.text }}{# this element is resizable and will be wrapped by js #}
-</div>
-<div class="form-item">
- <label for="editor" class="form-error">{{ post_form.text.errors }}</label>
-</div>
-{# need label element for resizable input, b/c form validation won't find span #}
-{% if post_type == 'question' %}
- <div class="form-item">
- {% if tags_are_required %}
- <label for=id_tags">
- {% if mandatory_tags %}
- <strong>{% trans %}tags{% endtrans %}</strong>
- {% trans %}, one of these is required{% endtrans %}
- {{
- tag_list_widget(
- mandatory_tags,
- make_links = False,
- css_class = 'clearfix'
- )
- }}
- {% else %}
- <strong>{% trans %}tags:{% endtrans %}</strong>
- {% trans %}(required){% endtrans %}
- {% endif %}
- </label>
- {% else %}
- <strong>{% trans %}tags:{% endtrans %}</strong>
- {% endif %}
- <span class="form-error">{{ post_form.tags.errors }}</span><br/>
- {{ post_form.tags }}
- <div class="title-desc">
- {{ post_form.tags.help_text }}
- </div>
- </div>
-{% endif %}
-{% if 'summary' in post_form['fields'] %}
- <div class="form-item">
- <strong>{{ post_form.summary.label_tag() }}</strong> <br/>
- {{ post_form.summary }}
- <div class="title-desc">
- {{ post_form.summary.help_text }}
- </div>
- <div class="form-error" >{{ post_form.summary.errors }}</div>
- </div>
-{% endif %}
-<div class="preview-toggle">
- <span
- id="pre-collapse"
- title="{% trans %}Toggle the real time Markdown editor preview{% endtrans %}"
- >
- [{% trans %}hide preview{% endtrans %}]
- </span>
-</div>
-<div id="previewer" class="wmd-preview"></div>
diff --git a/askbot/skins/default/media/bootstrap/css/bootstrap.css b/askbot/skins/default/media/bootstrap/css/bootstrap.css
deleted file mode 100644
index 3e829732..00000000
--- a/askbot/skins/default/media/bootstrap/css/bootstrap.css
+++ /dev/null
@@ -1,4635 +0,0 @@
-/*!
- * Bootstrap v2.0.2
- *
- * Copyright 2012 Twitter, Inc
- * Licensed under the Apache License v2.0
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Designed and built with all the love in the world @twitter by @mdo and @fat.
- */
-.clearfix {
- *zoom: 1;
-}
-.clearfix:before,
-.clearfix:after {
- display: table;
- content: "";
-}
-.clearfix:after {
- clear: both;
-}
-.hide-text {
- overflow: hidden;
- text-indent: 100%;
- white-space: nowrap;
-}
-.input-block-level {
- display: block;
- width: 100%;
- min-height: 28px;
- /* Make inputs at least the height of their button counterpart */
-
- /* Makes inputs behave like true block-level elements */
-
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- -ms-box-sizing: border-box;
- box-sizing: border-box;
-}
-article,
-aside,
-details,
-figcaption,
-figure,
-footer,
-header,
-hgroup,
-nav,
-section {
- display: block;
-}
-audio,
-canvas,
-video {
- display: inline-block;
- *display: inline;
- *zoom: 1;
-}
-audio:not([controls]) {
- display: none;
-}
-html {
- font-size: 100%;
- -webkit-text-size-adjust: 100%;
- -ms-text-size-adjust: 100%;
-}
-a:focus {
- outline: thin dotted #333;
- outline: 5px auto -webkit-focus-ring-color;
- outline-offset: -2px;
-}
-a:hover,
-a:active {
- outline: 0;
-}
-sub,
-sup {
- position: relative;
- font-size: 75%;
- line-height: 0;
- vertical-align: baseline;
-}
-sup {
- top: -0.5em;
-}
-sub {
- bottom: -0.25em;
-}
-img {
- height: auto;
- border: 0;
- -ms-interpolation-mode: bicubic;
- vertical-align: middle;
-}
-button,
-input,
-select,
-textarea {
- margin: 0;
- font-size: 100%;
- vertical-align: middle;
-}
-button,
-input {
- *overflow: visible;
- line-height: normal;
-}
-button::-moz-focus-inner,
-input::-moz-focus-inner {
- padding: 0;
- border: 0;
-}
-button,
-input[type="button"],
-input[type="reset"],
-input[type="submit"] {
- cursor: pointer;
- -webkit-appearance: button;
-}
-input[type="search"] {
- -webkit-appearance: textfield;
- -webkit-box-sizing: content-box;
- -moz-box-sizing: content-box;
- box-sizing: content-box;
-}
-input[type="search"]::-webkit-search-decoration,
-input[type="search"]::-webkit-search-cancel-button {
- -webkit-appearance: none;
-}
-textarea {
- overflow: auto;
- vertical-align: top;
-}
-body {
- margin: 0;
- font-family: Arial, sans-serif;
- font-size: 13px;
- line-height: 18px;
- color: #333333;
- background-color: #ffffff;
-}
-a {
- color: #0088cc;
- text-decoration: none;
-}
-a:hover {
- color: #005580;
- text-decoration: underline;
-}
-.row {
- margin-left: -20px;
- *zoom: 1;
-}
-.row:before,
-.row:after {
- display: table;
- content: "";
-}
-.row:after {
- clear: both;
-}
-[class*="span"] {
- float: left;
- margin-left: 20px;
-}
-.container,
-.navbar-fixed-top .container,
-.navbar-fixed-bottom .container {
- width: 940px;
-}
-.span12 {
- width: 940px;
-}
-.span11 {
- width: 860px;
-}
-.span10 {
- width: 780px;
-}
-.span9 {
- width: 700px;
-}
-.span8 {
- width: 620px;
-}
-.span7 {
- width: 540px;
-}
-.span6 {
- width: 460px;
-}
-.span5 {
- width: 380px;
-}
-.span4 {
- width: 300px;
-}
-.span3 {
- width: 220px;
-}
-.span2 {
- width: 140px;
-}
-.span1 {
- width: 60px;
-}
-.offset12 {
- margin-left: 980px;
-}
-.offset11 {
- margin-left: 900px;
-}
-.offset10 {
- margin-left: 820px;
-}
-.offset9 {
- margin-left: 740px;
-}
-.offset8 {
- margin-left: 660px;
-}
-.offset7 {
- margin-left: 580px;
-}
-.offset6 {
- margin-left: 500px;
-}
-.offset5 {
- margin-left: 420px;
-}
-.offset4 {
- margin-left: 340px;
-}
-.offset3 {
- margin-left: 260px;
-}
-.offset2 {
- margin-left: 180px;
-}
-.offset1 {
- margin-left: 100px;
-}
-.row-fluid {
- width: 100%;
- *zoom: 1;
-}
-.row-fluid:before,
-.row-fluid:after {
- display: table;
- content: "";
-}
-.row-fluid:after {
- clear: both;
-}
-.row-fluid > [class*="span"] {
- float: left;
- margin-left: 2.127659574%;
-}
-.row-fluid > [class*="span"]:first-child {
- margin-left: 0;
-}
-.row-fluid > .span12 {
- width: 99.99999998999999%;
-}
-.row-fluid > .span11 {
- width: 91.489361693%;
-}
-.row-fluid > .span10 {
- width: 82.97872339599999%;
-}
-.row-fluid > .span9 {
- width: 74.468085099%;
-}
-.row-fluid > .span8 {
- width: 65.95744680199999%;
-}
-.row-fluid > .span7 {
- width: 57.446808505%;
-}
-.row-fluid > .span6 {
- width: 48.93617020799999%;
-}
-.row-fluid > .span5 {
- width: 40.425531911%;
-}
-.row-fluid > .span4 {
- width: 31.914893614%;
-}
-.row-fluid > .span3 {
- width: 23.404255317%;
-}
-.row-fluid > .span2 {
- width: 14.89361702%;
-}
-.row-fluid > .span1 {
- width: 6.382978723%;
-}
-.container {
- margin-left: auto;
- margin-right: auto;
- *zoom: 1;
-}
-.container:before,
-.container:after {
- display: table;
- content: "";
-}
-.container:after {
- clear: both;
-}
-.container-fluid {
- padding-left: 20px;
- padding-right: 20px;
- *zoom: 1;
-}
-.container-fluid:before,
-.container-fluid:after {
- display: table;
- content: "";
-}
-.container-fluid:after {
- clear: both;
-}
-p {
- margin: 0 0 9px;
- font-family: Arial, sans-serif;
- font-size: 13px;
- line-height: 18px;
-}
-p small {
- font-size: 11px;
- color: #999999;
-}
-.lead {
- margin-bottom: 18px;
- font-size: 20px;
- font-weight: 200;
- line-height: 27px;
-}
-h1,
-h2,
-h3,
-h4,
-h5,
-h6 {
- margin: 0;
- font-family: inherit;
- font-weight: bold;
- color: inherit;
- text-rendering: optimizelegibility;
-}
-h1 small,
-h2 small,
-h3 small,
-h4 small,
-h5 small,
-h6 small {
- font-weight: normal;
- color: #999999;
-}
-h1 {
- font-size: 30px;
- line-height: 36px;
-}
-h1 small {
- font-size: 18px;
-}
-h2 {
- font-size: 24px;
- line-height: 36px;
-}
-h2 small {
- font-size: 18px;
-}
-h3 {
- line-height: 27px;
- font-size: 18px;
-}
-h3 small {
- font-size: 14px;
-}
-h4,
-h5,
-h6 {
- line-height: 18px;
-}
-h4 {
- font-size: 14px;
-}
-h4 small {
- font-size: 12px;
-}
-h5 {
- font-size: 12px;
-}
-h6 {
- font-size: 11px;
- color: #999999;
- text-transform: uppercase;
-}
-.page-header {
- padding-bottom: 17px;
- margin: 18px 0;
- border-bottom: 1px solid #eeeeee;
-}
-.page-header h1 {
- line-height: 1;
-}
-ul,
-ol {
- padding: 0;
- margin: 0 0 9px 25px;
-}
-ul ul,
-ul ol,
-ol ol,
-ol ul {
- margin-bottom: 0;
-}
-ul {
- list-style: disc;
-}
-ol {
- list-style: decimal;
-}
-li {
- line-height: 18px;
-}
-ul.unstyled,
-ol.unstyled {
- margin-left: 0;
- list-style: none;
-}
-dl {
- margin-bottom: 18px;
-}
-dt,
-dd {
- line-height: 18px;
-}
-dt {
- font-weight: bold;
- line-height: 17px;
-}
-dd {
- margin-left: 9px;
-}
-.dl-horizontal dt {
- float: left;
- clear: left;
- width: 120px;
- text-align: right;
-}
-.dl-horizontal dd {
- margin-left: 130px;
-}
-hr {
- margin: 18px 0;
- border: 0;
- border-top: 1px solid #eeeeee;
- border-bottom: 1px solid #ffffff;
-}
-strong {
- font-weight: bold;
-}
-em {
- font-style: italic;
-}
-.muted {
- color: #999999;
-}
-abbr[title] {
- border-bottom: 1px dotted #ddd;
- cursor: help;
-}
-abbr.initialism {
- font-size: 90%;
- text-transform: uppercase;
-}
-blockquote {
- padding: 0 0 0 15px;
- margin: 0 0 18px;
- border-left: 5px solid #eeeeee;
-}
-blockquote p {
- margin-bottom: 0;
- font-size: 16px;
- font-weight: 300;
- line-height: 22.5px;
-}
-blockquote small {
- display: block;
- line-height: 18px;
- color: #999999;
-}
-blockquote small:before {
- content: '\2014 \00A0';
-}
-blockquote.pull-right {
- float: right;
- padding-left: 0;
- padding-right: 15px;
- border-left: 0;
- border-right: 5px solid #eeeeee;
-}
-blockquote.pull-right p,
-blockquote.pull-right small {
- text-align: right;
-}
-q:before,
-q:after,
-blockquote:before,
-blockquote:after {
- content: "";
-}
-address {
- display: block;
- margin-bottom: 18px;
- line-height: 18px;
- font-style: normal;
-}
-small {
- font-size: 100%;
-}
-cite {
- font-style: normal;
-}
-code,
-pre {
- padding: 0 3px 2px;
- font-family: Menlo, Monaco, "Courier New", monospace;
- font-size: 12px;
- color: #333333;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
-}
-code {
- padding: 2px 4px;
- color: #d14;
- background-color: #f7f7f9;
- border: 1px solid #e1e1e8;
-}
-pre {
- display: block;
- padding: 8.5px;
- margin: 0 0 9px;
- font-size: 12.025px;
- line-height: 18px;
- background-color: #f5f5f5;
- border: 1px solid #ccc;
- border: 1px solid rgba(0, 0, 0, 0.15);
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- white-space: pre;
- white-space: pre-wrap;
- word-break: break-all;
- word-wrap: break-word;
-}
-pre.prettyprint {
- margin-bottom: 18px;
-}
-pre code {
- padding: 0;
- color: inherit;
- background-color: transparent;
- border: 0;
-}
-.pre-scrollable {
- max-height: 340px;
- overflow-y: scroll;
-}
-/*.label {
- padding: 1px 4px 2px;
- font-size: 10.998px;
- font-weight: bold;
- line-height: 13px;
- color: #ffffff;
- vertical-align: middle;
- white-space: nowrap;
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
- background-color: #999999;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
-}
-.label:hover {
- color: #ffffff;
- text-decoration: none;
-}*/
-.label-important {
- background-color: #b94a48;
-}
-.label-important:hover {
- background-color: #953b39;
-}
-.label-warning {
- background-color: #f89406;
-}
-.label-warning:hover {
- background-color: #c67605;
-}
-.label-success {
- background-color: #468847;
-}
-.label-success:hover {
- background-color: #356635;
-}
-.label-info {
- background-color: #3a87ad;
-}
-.label-info:hover {
- background-color: #2d6987;
-}
-.label-inverse {
- background-color: #333333;
-}
-.label-inverse:hover {
- background-color: #1a1a1a;
-}
-.badge {
- padding: 1px 9px 2px;
- font-size: 12.025px;
- font-weight: bold;
- white-space: nowrap;
- color: #ffffff;
- background-color: #999999;
- -webkit-border-radius: 9px;
- -moz-border-radius: 9px;
- border-radius: 9px;
-}
-.badge:hover {
- color: #ffffff;
- text-decoration: none;
- cursor: pointer;
-}
-.badge-error {
- background-color: #b94a48;
-}
-.badge-error:hover {
- background-color: #953b39;
-}
-.badge-warning {
- background-color: #f89406;
-}
-.badge-warning:hover {
- background-color: #c67605;
-}
-.badge-success {
- background-color: #468847;
-}
-.badge-success:hover {
- background-color: #356635;
-}
-.badge-info {
- background-color: #3a87ad;
-}
-.badge-info:hover {
- background-color: #2d6987;
-}
-.badge-inverse {
- background-color: #333333;
-}
-.badge-inverse:hover {
- background-color: #1a1a1a;
-}
-table {
- max-width: 100%;
- border-collapse: collapse;
- border-spacing: 0;
- background-color: transparent;
-}
-.table {
- width: 100%;
- margin-bottom: 18px;
-}
-.table th,
-.table td {
- padding: 8px;
- line-height: 18px;
- text-align: left;
- vertical-align: top;
- border-top: 1px solid #dddddd;
-}
-.table th {
- font-weight: bold;
-}
-.table thead th {
- vertical-align: bottom;
-}
-.table colgroup + thead tr:first-child th,
-.table colgroup + thead tr:first-child td,
-.table thead:first-child tr:first-child th,
-.table thead:first-child tr:first-child td {
- border-top: 0;
-}
-.table tbody + tbody {
- border-top: 2px solid #dddddd;
-}
-.table-condensed th,
-.table-condensed td {
- padding: 4px 5px;
-}
-.table-bordered {
- border: 1px solid #dddddd;
- border-left: 0;
- border-collapse: separate;
- *border-collapse: collapsed;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
-}
-.table-bordered th,
-.table-bordered td {
- border-left: 1px solid #dddddd;
-}
-.table-bordered thead:first-child tr:first-child th,
-.table-bordered tbody:first-child tr:first-child th,
-.table-bordered tbody:first-child tr:first-child td {
- border-top: 0;
-}
-.table-bordered thead:first-child tr:first-child th:first-child,
-.table-bordered tbody:first-child tr:first-child td:first-child {
- -webkit-border-radius: 4px 0 0 0;
- -moz-border-radius: 4px 0 0 0;
- border-radius: 4px 0 0 0;
-}
-.table-bordered thead:first-child tr:first-child th:last-child,
-.table-bordered tbody:first-child tr:first-child td:last-child {
- -webkit-border-radius: 0 4px 0 0;
- -moz-border-radius: 0 4px 0 0;
- border-radius: 0 4px 0 0;
-}
-.table-bordered thead:last-child tr:last-child th:first-child,
-.table-bordered tbody:last-child tr:last-child td:first-child {
- -webkit-border-radius: 0 0 0 4px;
- -moz-border-radius: 0 0 0 4px;
- border-radius: 0 0 0 4px;
-}
-.table-bordered thead:last-child tr:last-child th:last-child,
-.table-bordered tbody:last-child tr:last-child td:last-child {
- -webkit-border-radius: 0 0 4px 0;
- -moz-border-radius: 0 0 4px 0;
- border-radius: 0 0 4px 0;
-}
-.table-striped tbody tr:nth-child(odd) td,
-.table-striped tbody tr:nth-child(odd) th {
- background-color: #f9f9f9;
-}
-.table tbody tr:hover td,
-.table tbody tr:hover th {
- background-color: #f5f5f5;
-}
-table .span1 {
- float: none;
- width: 44px;
- margin-left: 0;
-}
-table .span2 {
- float: none;
- width: 124px;
- margin-left: 0;
-}
-table .span3 {
- float: none;
- width: 204px;
- margin-left: 0;
-}
-table .span4 {
- float: none;
- width: 284px;
- margin-left: 0;
-}
-table .span5 {
- float: none;
- width: 364px;
- margin-left: 0;
-}
-table .span6 {
- float: none;
- width: 444px;
- margin-left: 0;
-}
-table .span7 {
- float: none;
- width: 524px;
- margin-left: 0;
-}
-table .span8 {
- float: none;
- width: 604px;
- margin-left: 0;
-}
-table .span9 {
- float: none;
- width: 684px;
- margin-left: 0;
-}
-table .span10 {
- float: none;
- width: 764px;
- margin-left: 0;
-}
-table .span11 {
- float: none;
- width: 844px;
- margin-left: 0;
-}
-table .span12 {
- float: none;
- width: 924px;
- margin-left: 0;
-}
-table .span13 {
- float: none;
- width: 1004px;
- margin-left: 0;
-}
-table .span14 {
- float: none;
- width: 1084px;
- margin-left: 0;
-}
-table .span15 {
- float: none;
- width: 1164px;
- margin-left: 0;
-}
-table .span16 {
- float: none;
- width: 1244px;
- margin-left: 0;
-}
-table .span17 {
- float: none;
- width: 1324px;
- margin-left: 0;
-}
-table .span18 {
- float: none;
- width: 1404px;
- margin-left: 0;
-}
-table .span19 {
- float: none;
- width: 1484px;
- margin-left: 0;
-}
-table .span20 {
- float: none;
- width: 1564px;
- margin-left: 0;
-}
-table .span21 {
- float: none;
- width: 1644px;
- margin-left: 0;
-}
-table .span22 {
- float: none;
- width: 1724px;
- margin-left: 0;
-}
-table .span23 {
- float: none;
- width: 1804px;
- margin-left: 0;
-}
-table .span24 {
- float: none;
- width: 1884px;
- margin-left: 0;
-}
-form {
- margin: 0 0 18px;
-}
-fieldset {
- padding: 0;
- margin: 0;
- border: 0;
-}
-legend {
- display: block;
- width: 100%;
- padding: 0;
- margin-bottom: 27px;
- font-size: 19.5px;
- line-height: 36px;
- color: #333333;
- border: 0;
- border-bottom: 1px solid #eee;
-}
-legend small {
- font-size: 13.5px;
- color: #999999;
-}
-label,
-input,
-button,
-select,
-textarea {
- font-size: 13px;
- font-weight: normal;
- line-height: 18px;
-}
-input,
-button,
-select,
-textarea {
- font-family: Arial, sans-serif;
-}
-label {
- display: block;
- margin-bottom: 5px;
- color: #333333;
-}
-input,
-textarea,
-select,
-.uneditable-input {
-}
-.uneditable-textarea {
- width: auto;
- height: auto;
-}
-label input,
-label textarea,
-label select {
- display: block;
-}
-input[type="image"],
-input[type="checkbox"],
-input[type="radio"] {
- width: auto;
- height: auto;
- padding: 0;
- margin: 3px 0;
- *margin-top: 0;
- /* IE7 */
-
- line-height: normal;
- cursor: pointer;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
- border: 0 \9;
- /* IE9 and down */
-
-}
-input[type="image"] {
- border: 0;
-}
-input[type="file"] {
- width: auto;
- padding: initial;
- line-height: initial;
- border: initial;
- background-color: #ffffff;
- background-color: initial;
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none;
-}
-input[type="button"],
-input[type="reset"],
-input[type="submit"] {
- width: auto;
- height: auto;
-}
-select,
-input[type="file"] {
- height: 28px;
- /* In IE7, the height of the select element cannot be changed by height, only font-size */
-
- *margin-top: 4px;
- /* For IE7, add top margin to align select with labels */
-
- line-height: 28px;
-}
-input[type="file"] {
- line-height: 18px \9;
-}
-select {
- width: 220px;
- background-color: #ffffff;
-}
-select[multiple],
-select[size] {
- height: auto;
-}
-input[type="image"] {
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none;
-}
-textarea {
- height: auto;
-}
-input[type="hidden"] {
- display: none;
-}
-.radio,
-.checkbox {
- padding-left: 18px;
-}
-.radio input[type="radio"],
-.checkbox input[type="checkbox"] {
- float: left;
- margin-left: -18px;
-}
-.controls > .radio:first-child,
-.controls > .checkbox:first-child {
- padding-top: 5px;
-}
-.radio.inline,
-.checkbox.inline {
- display: inline-block;
- padding-top: 5px;
- margin-bottom: 0;
- vertical-align: middle;
-}
-.radio.inline + .radio.inline,
-.checkbox.inline + .checkbox.inline {
- margin-left: 10px;
-}
-input,
-textarea {
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
- -webkit-transition: border linear 0.2s, box-shadow linear 0.2s;
- -moz-transition: border linear 0.2s, box-shadow linear 0.2s;
- -ms-transition: border linear 0.2s, box-shadow linear 0.2s;
- -o-transition: border linear 0.2s, box-shadow linear 0.2s;
- transition: border linear 0.2s, box-shadow linear 0.2s;
-}
-input:focus,
-textarea:focus {
- border-color: rgba(82, 168, 236, 0.8);
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
- outline: 0;
- outline: thin dotted \9;
- /* IE6-9 */
-
-}
-input[type="file"]:focus,
-input[type="radio"]:focus,
-input[type="checkbox"]:focus,
-select:focus {
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none;
- outline: thin dotted #333;
- outline: 5px auto -webkit-focus-ring-color;
- outline-offset: -2px;
-}
-.input-mini {
- width: 60px;
-}
-.input-small {
- width: 90px;
-}
-.input-medium {
- width: 150px;
-}
-.input-large {
- width: 210px;
-}
-.input-xlarge {
- width: 270px;
-}
-.input-xxlarge {
- width: 530px;
-}
-input[class*="span"],
-select[class*="span"],
-textarea[class*="span"],
-.uneditable-input {
- float: none;
- margin-left: 0;
-}
-input,
-textarea,
-.uneditable-input {
- margin-left: 0;
-}
-input.span12, textarea.span12, .uneditable-input.span12 {
- width: 930px;
-}
-input.span11, textarea.span11, .uneditable-input.span11 {
- width: 850px;
-}
-input.span10, textarea.span10, .uneditable-input.span10 {
- width: 770px;
-}
-input.span9, textarea.span9, .uneditable-input.span9 {
- width: 690px;
-}
-input.span8, textarea.span8, .uneditable-input.span8 {
- width: 610px;
-}
-input.span7, textarea.span7, .uneditable-input.span7 {
- width: 530px;
-}
-input.span6, textarea.span6, .uneditable-input.span6 {
- width: 450px;
-}
-input.span5, textarea.span5, .uneditable-input.span5 {
- width: 370px;
-}
-input.span4, textarea.span4, .uneditable-input.span4 {
- width: 290px;
-}
-input.span3, textarea.span3, .uneditable-input.span3 {
- width: 210px;
-}
-input.span2, textarea.span2, .uneditable-input.span2 {
- width: 130px;
-}
-input.span1, textarea.span1, .uneditable-input.span1 {
- width: 50px;
-}
-input[disabled],
-select[disabled],
-textarea[disabled],
-input[readonly],
-select[readonly],
-textarea[readonly] {
- background-color: #eeeeee;
- border-color: #ddd;
- cursor: not-allowed;
-}
-.control-group.warning > label,
-.control-group.warning .help-block,
-.control-group.warning .help-inline {
- color: #c09853;
-}
-.control-group.warning input,
-.control-group.warning select,
-.control-group.warning textarea {
- color: #c09853;
- border-color: #c09853;
-}
-.control-group.warning input:focus,
-.control-group.warning select:focus,
-.control-group.warning textarea:focus {
- border-color: #a47e3c;
- -webkit-box-shadow: 0 0 6px #dbc59e;
- -moz-box-shadow: 0 0 6px #dbc59e;
- box-shadow: 0 0 6px #dbc59e;
-}
-.control-group.warning .input-prepend .add-on,
-.control-group.warning .input-append .add-on {
- color: #c09853;
- background-color: #fcf8e3;
- border-color: #c09853;
-}
-.control-group.error > label,
-.control-group.error .help-block,
-.control-group.error .help-inline {
- color: #b94a48;
-}
-.control-group.error input,
-.control-group.error select,
-.control-group.error textarea {
- color: #b94a48;
- border-color: #b94a48;
-}
-.control-group.error input:focus,
-.control-group.error select:focus,
-.control-group.error textarea:focus {
- border-color: #953b39;
- -webkit-box-shadow: 0 0 6px #d59392;
- -moz-box-shadow: 0 0 6px #d59392;
- box-shadow: 0 0 6px #d59392;
-}
-.control-group.error .input-prepend .add-on,
-.control-group.error .input-append .add-on {
- color: #b94a48;
- background-color: #f2dede;
- border-color: #b94a48;
-}
-.control-group.success > label,
-.control-group.success .help-block,
-.control-group.success .help-inline {
- color: #468847;
-}
-.control-group.success input,
-.control-group.success select,
-.control-group.success textarea {
- color: #468847;
- border-color: #468847;
-}
-.control-group.success input:focus,
-.control-group.success select:focus,
-.control-group.success textarea:focus {
- border-color: #356635;
- -webkit-box-shadow: 0 0 6px #7aba7b;
- -moz-box-shadow: 0 0 6px #7aba7b;
- box-shadow: 0 0 6px #7aba7b;
-}
-.control-group.success .input-prepend .add-on,
-.control-group.success .input-append .add-on {
- color: #468847;
- background-color: #dff0d8;
- border-color: #468847;
-}
-input:focus:required:invalid,
-textarea:focus:required:invalid,
-select:focus:required:invalid {
- color: #b94a48;
- border-color: #ee5f5b;
-}
-input:focus:required:invalid:focus,
-textarea:focus:required:invalid:focus,
-select:focus:required:invalid:focus {
- border-color: #e9322d;
- -webkit-box-shadow: 0 0 6px #f8b9b7;
- -moz-box-shadow: 0 0 6px #f8b9b7;
- box-shadow: 0 0 6px #f8b9b7;
-}
-.form-actions {
- padding: 17px 20px 18px;
- margin-top: 18px;
- margin-bottom: 18px;
- background-color: #eeeeee;
- border-top: 1px solid #ddd;
- *zoom: 1;
-}
-.form-actions:before,
-.form-actions:after {
- display: table;
- content: "";
-}
-.form-actions:after {
- clear: both;
-}
-.uneditable-input {
- display: block;
- background-color: #ffffff;
- border-color: #eee;
- -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
- -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
- box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025);
- cursor: not-allowed;
-}
-:-moz-placeholder {
- color: #999999;
-}
-::-webkit-input-placeholder {
- color: #999999;
-}
-.help-block,
-.help-inline {
- color: #555555;
-}
-.help-block {
- display: block;
- margin-bottom: 9px;
-}
-.help-inline {
- display: inline-block;
- *display: inline;
- /* IE7 inline-block hack */
-
- *zoom: 1;
- vertical-align: middle;
- padding-left: 5px;
-}
-.input-prepend,
-.input-append {
- margin-bottom: 5px;
-}
-.input-prepend input,
-.input-append input,
-.input-prepend select,
-.input-append select,
-.input-prepend .uneditable-input,
-.input-append .uneditable-input {
- *margin-left: 0;
- -webkit-border-radius: 0 3px 3px 0;
- -moz-border-radius: 0 3px 3px 0;
- border-radius: 0 3px 3px 0;
-}
-.input-prepend input:focus,
-.input-append input:focus,
-.input-prepend select:focus,
-.input-append select:focus,
-.input-prepend .uneditable-input:focus,
-.input-append .uneditable-input:focus {
- position: relative;
- z-index: 2;
-}
-.input-prepend .uneditable-input,
-.input-append .uneditable-input {
- border-left-color: #ccc;
-}
-.input-prepend .add-on,
-.input-append .add-on {
- display: inline-block;
- width: auto;
- min-width: 16px;
- height: 18px;
- padding: 4px 5px;
- font-weight: normal;
- line-height: 18px;
- text-align: center;
- text-shadow: 0 1px 0 #ffffff;
- vertical-align: middle;
- background-color: #eeeeee;
- border: 1px solid #ccc;
-}
-.input-prepend .add-on,
-.input-append .add-on,
-.input-prepend .btn,
-.input-append .btn {
- -webkit-border-radius: 3px 0 0 3px;
- -moz-border-radius: 3px 0 0 3px;
- border-radius: 3px 0 0 3px;
-}
-.input-prepend .active,
-.input-append .active {
- background-color: #a9dba9;
- border-color: #46a546;
-}
-.input-prepend .add-on,
-.input-prepend .btn {
- margin-right: -1px;
-}
-.input-append input,
-.input-append select .uneditable-input {
- -webkit-border-radius: 3px 0 0 3px;
- -moz-border-radius: 3px 0 0 3px;
- border-radius: 3px 0 0 3px;
-}
-.input-append .uneditable-input {
- border-left-color: #eee;
- border-right-color: #ccc;
-}
-.input-append .add-on,
-.input-append .btn {
- margin-left: -1px;
- -webkit-border-radius: 0 3px 3px 0;
- -moz-border-radius: 0 3px 3px 0;
- border-radius: 0 3px 3px 0;
-}
-.input-prepend.input-append input,
-.input-prepend.input-append select,
-.input-prepend.input-append .uneditable-input {
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
-}
-.input-prepend.input-append .add-on:first-child,
-.input-prepend.input-append .btn:first-child {
- margin-right: -1px;
- -webkit-border-radius: 3px 0 0 3px;
- -moz-border-radius: 3px 0 0 3px;
- border-radius: 3px 0 0 3px;
-}
-.input-prepend.input-append .add-on:last-child,
-.input-prepend.input-append .btn:last-child {
- margin-left: -1px;
- -webkit-border-radius: 0 3px 3px 0;
- -moz-border-radius: 0 3px 3px 0;
- border-radius: 0 3px 3px 0;
-}
-.search-query {
- padding-left: 14px;
- padding-right: 14px;
- margin-bottom: 0;
- -webkit-border-radius: 14px;
- -moz-border-radius: 14px;
- border-radius: 14px;
-}
-.form-search input,
-.form-inline input,
-.form-horizontal input,
-.form-search textarea,
-.form-inline textarea,
-.form-horizontal textarea,
-.form-search select,
-.form-inline select,
-.form-horizontal select,
-.form-search .help-inline,
-.form-inline .help-inline,
-.form-horizontal .help-inline,
-.form-search .uneditable-input,
-.form-inline .uneditable-input,
-.form-horizontal .uneditable-input,
-.form-search .input-prepend,
-.form-inline .input-prepend,
-.form-horizontal .input-prepend,
-.form-search .input-append,
-.form-inline .input-append,
-.form-horizontal .input-append {
- display: inline-block;
- margin-bottom: 0;
-}
-.form-search .hide,
-.form-inline .hide,
-.form-horizontal .hide {
- display: none;
-}
-.form-search label,
-.form-inline label {
- display: inline-block;
-}
-.form-search .input-append,
-.form-inline .input-append,
-.form-search .input-prepend,
-.form-inline .input-prepend {
- margin-bottom: 0;
-}
-.form-search .radio,
-.form-search .checkbox,
-.form-inline .radio,
-.form-inline .checkbox {
- padding-left: 0;
- margin-bottom: 0;
- vertical-align: middle;
-}
-.form-search .radio input[type="radio"],
-.form-search .checkbox input[type="checkbox"],
-.form-inline .radio input[type="radio"],
-.form-inline .checkbox input[type="checkbox"] {
- float: left;
- margin-left: 0;
- margin-right: 3px;
-}
-.control-group {
- margin-bottom: 9px;
-}
-legend + .control-group {
- margin-top: 18px;
- -webkit-margin-top-collapse: separate;
-}
-.form-horizontal .control-group {
- margin-bottom: 18px;
- *zoom: 1;
-}
-.form-horizontal .control-group:before,
-.form-horizontal .control-group:after {
- display: table;
- content: "";
-}
-.form-horizontal .control-group:after {
- clear: both;
-}
-.form-horizontal .control-label {
- float: left;
- width: 140px;
- padding-top: 5px;
- text-align: right;
-}
-.form-horizontal .controls {
- margin-left: 160px;
- /* Super jank IE7 fix to ensure the inputs in .input-append and input-prepend don't inherit the margin of the parent, in this case .controls */
-
- *display: inline-block;
- *margin-left: 0;
- *padding-left: 20px;
-}
-.form-horizontal .help-block {
- margin-top: 9px;
- margin-bottom: 0;
-}
-.form-horizontal .form-actions {
- padding-left: 160px;
-}
-.btn {
- display: inline-block;
- *display: inline;
- /* IE7 inline-block hack */
-
- *zoom: 1;
- padding: 4px 10px 4px;
- margin-bottom: 0;
- font-size: 13px;
- line-height: 18px;
- color: #333333;
- text-align: center;
- text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
- vertical-align: middle;
- background-color: #f5f5f5;
- background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
- background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
- background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
- background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
- background-image: linear-gradient(top, #ffffff, #e6e6e6);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);
- border-color: #e6e6e6 #e6e6e6 #bfbfbf;
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:dximagetransform.microsoft.gradient(enabled=false);
- border: 1px solid #cccccc;
- border-bottom-color: #b3b3b3;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
- cursor: pointer;
- *margin-left: .3em;
-}
-.btn:hover,
-.btn:active,
-.btn.active,
-.btn.disabled,
-.btn[disabled] {
- background-color: #e6e6e6;
-}
-.btn:active,
-.btn.active {
- background-color: #cccccc \9;
-}
-.btn:first-child {
- *margin-left: 0;
-}
-.btn:hover {
- color: #333333;
- text-decoration: none;
- background-color: #e6e6e6;
- background-position: 0 -15px;
- -webkit-transition: background-position 0.1s linear;
- -moz-transition: background-position 0.1s linear;
- -ms-transition: background-position 0.1s linear;
- -o-transition: background-position 0.1s linear;
- transition: background-position 0.1s linear;
-}
-.btn:focus {
- outline: thin dotted #333;
- outline: 5px auto -webkit-focus-ring-color;
- outline-offset: -2px;
-}
-.btn.active,
-.btn:active {
- background-image: none;
- -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
- box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
- background-color: #e6e6e6;
- background-color: #d9d9d9 \9;
- outline: 0;
-}
-.btn.disabled,
-.btn[disabled] {
- cursor: default;
- background-image: none;
- background-color: #e6e6e6;
- opacity: 0.65;
- filter: alpha(opacity=65);
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none;
-}
-.btn-large {
- padding: 9px 14px;
- font-size: 15px;
- line-height: normal;
- -webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px;
-}
-.btn-large [class^="icon-"] {
- margin-top: 1px;
-}
-.btn-small {
- padding: 5px 9px;
- font-size: 11px;
- line-height: 16px;
-}
-.btn-small [class^="icon-"] {
- margin-top: -1px;
-}
-.btn-mini {
- padding: 2px 6px;
- font-size: 11px;
- line-height: 14px;
-}
-.btn-primary,
-.btn-primary:hover,
-.btn-warning,
-.btn-warning:hover,
-.btn-danger,
-.btn-danger:hover,
-.btn-success,
-.btn-success:hover,
-.btn-info,
-.btn-info:hover,
-.btn-inverse,
-.btn-inverse:hover {
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
- color: #ffffff;
-}
-.btn-primary.active,
-.btn-warning.active,
-.btn-danger.active,
-.btn-success.active,
-.btn-info.active,
-.btn-inverse.active {
- color: rgba(255, 255, 255, 0.75);
-}
-.btn-primary {
- background-color: #0074cc;
- background-image: -moz-linear-gradient(top, #0088cc, #0055cc);
- background-image: -ms-linear-gradient(top, #0088cc, #0055cc);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0055cc));
- background-image: -webkit-linear-gradient(top, #0088cc, #0055cc);
- background-image: -o-linear-gradient(top, #0088cc, #0055cc);
- background-image: linear-gradient(top, #0088cc, #0055cc);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0055cc', GradientType=0);
- border-color: #0055cc #0055cc #003580;
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:dximagetransform.microsoft.gradient(enabled=false);
-}
-.btn-primary:hover,
-.btn-primary:active,
-.btn-primary.active,
-.btn-primary.disabled,
-.btn-primary[disabled] {
- background-color: #0055cc;
-}
-.btn-primary:active,
-.btn-primary.active {
- background-color: #004099 \9;
-}
-.btn-warning {
- background-color: #faa732;
- background-image: -moz-linear-gradient(top, #fbb450, #f89406);
- background-image: -ms-linear-gradient(top, #fbb450, #f89406);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
- background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
- background-image: -o-linear-gradient(top, #fbb450, #f89406);
- background-image: linear-gradient(top, #fbb450, #f89406);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);
- border-color: #f89406 #f89406 #ad6704;
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:dximagetransform.microsoft.gradient(enabled=false);
-}
-.btn-warning:hover,
-.btn-warning:active,
-.btn-warning.active,
-.btn-warning.disabled,
-.btn-warning[disabled] {
- background-color: #f89406;
-}
-.btn-warning:active,
-.btn-warning.active {
- background-color: #c67605 \9;
-}
-.btn-danger {
- background-color: #da4f49;
- background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f);
- background-image: -ms-linear-gradient(top, #ee5f5b, #bd362f);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));
- background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f);
- background-image: -o-linear-gradient(top, #ee5f5b, #bd362f);
- background-image: linear-gradient(top, #ee5f5b, #bd362f);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);
- border-color: #bd362f #bd362f #802420;
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:dximagetransform.microsoft.gradient(enabled=false);
-}
-.btn-danger:hover,
-.btn-danger:active,
-.btn-danger.active,
-.btn-danger.disabled,
-.btn-danger[disabled] {
- background-color: #bd362f;
-}
-.btn-danger:active,
-.btn-danger.active {
- background-color: #942a25 \9;
-}
-.btn-success {
- background-color: #5bb75b;
- background-image: -moz-linear-gradient(top, #62c462, #51a351);
- background-image: -ms-linear-gradient(top, #62c462, #51a351);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));
- background-image: -webkit-linear-gradient(top, #62c462, #51a351);
- background-image: -o-linear-gradient(top, #62c462, #51a351);
- background-image: linear-gradient(top, #62c462, #51a351);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);
- border-color: #51a351 #51a351 #387038;
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:dximagetransform.microsoft.gradient(enabled=false);
-}
-.btn-success:hover,
-.btn-success:active,
-.btn-success.active,
-.btn-success.disabled,
-.btn-success[disabled] {
- background-color: #51a351;
-}
-.btn-success:active,
-.btn-success.active {
- background-color: #408140 \9;
-}
-.btn-info {
- background-color: #49afcd;
- background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4);
- background-image: -ms-linear-gradient(top, #5bc0de, #2f96b4);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));
- background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4);
- background-image: -o-linear-gradient(top, #5bc0de, #2f96b4);
- background-image: linear-gradient(top, #5bc0de, #2f96b4);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);
- border-color: #2f96b4 #2f96b4 #1f6377;
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:dximagetransform.microsoft.gradient(enabled=false);
-}
-.btn-info:hover,
-.btn-info:active,
-.btn-info.active,
-.btn-info.disabled,
-.btn-info[disabled] {
- background-color: #2f96b4;
-}
-.btn-info:active,
-.btn-info.active {
- background-color: #24748c \9;
-}
-.btn-inverse {
- background-color: #414141;
- background-image: -moz-linear-gradient(top, #555555, #222222);
- background-image: -ms-linear-gradient(top, #555555, #222222);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222));
- background-image: -webkit-linear-gradient(top, #555555, #222222);
- background-image: -o-linear-gradient(top, #555555, #222222);
- background-image: linear-gradient(top, #555555, #222222);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0);
- border-color: #222222 #222222 #000000;
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:dximagetransform.microsoft.gradient(enabled=false);
-}
-.btn-inverse:hover,
-.btn-inverse:active,
-.btn-inverse.active,
-.btn-inverse.disabled,
-.btn-inverse[disabled] {
- background-color: #222222;
-}
-.btn-inverse:active,
-.btn-inverse.active {
- background-color: #080808 \9;
-}
-button.btn,
-input[type="submit"].btn {
- *padding-top: 2px;
- *padding-bottom: 2px;
-}
-button.btn::-moz-focus-inner,
-input[type="submit"].btn::-moz-focus-inner {
- padding: 0;
- border: 0;
-}
-button.btn.btn-large,
-input[type="submit"].btn.btn-large {
- *padding-top: 7px;
- *padding-bottom: 7px;
-}
-button.btn.btn-small,
-input[type="submit"].btn.btn-small {
- *padding-top: 3px;
- *padding-bottom: 3px;
-}
-button.btn.btn-mini,
-input[type="submit"].btn.btn-mini {
- *padding-top: 1px;
- *padding-bottom: 1px;
-}
-[class^="icon-"],
-[class*=" icon-"] {
- display: inline-block;
- width: 14px;
- height: 14px;
- line-height: 14px;
- vertical-align: text-top;
- background-image: url("../img/glyphicons-halflings.png");
- background-position: 14px 14px;
- background-repeat: no-repeat;
- *margin-right: .3em;
-}
-[class^="icon-"]:last-child,
-[class*=" icon-"]:last-child {
- *margin-left: 0;
-}
-.icon-white {
- background-image: url("../img/glyphicons-halflings-white.png");
-}
-.icon-glass {
- background-position: 0 0;
-}
-.icon-music {
- background-position: -24px 0;
-}
-.icon-search {
- background-position: -48px 0;
-}
-.icon-envelope {
- background-position: -72px 0;
-}
-.icon-heart {
- background-position: -96px 0;
-}
-.icon-star {
- background-position: -120px 0;
-}
-.icon-star-empty {
- background-position: -144px 0;
-}
-.icon-user {
- background-position: -168px 0;
-}
-.icon-film {
- background-position: -192px 0;
-}
-.icon-th-large {
- background-position: -216px 0;
-}
-.icon-th {
- background-position: -240px 0;
-}
-.icon-th-list {
- background-position: -264px 0;
-}
-.icon-ok {
- background-position: -288px 0;
-}
-.icon-remove {
- background-position: -312px 0;
-}
-.icon-zoom-in {
- background-position: -336px 0;
-}
-.icon-zoom-out {
- background-position: -360px 0;
-}
-.icon-off {
- background-position: -384px 0;
-}
-.icon-signal {
- background-position: -408px 0;
-}
-.icon-cog {
- background-position: -432px 0;
-}
-.icon-trash {
- background-position: -456px 0;
-}
-.icon-home {
- background-position: 0 -24px;
-}
-.icon-file {
- background-position: -24px -24px;
-}
-.icon-time {
- background-position: -48px -24px;
-}
-.icon-road {
- background-position: -72px -24px;
-}
-.icon-download-alt {
- background-position: -96px -24px;
-}
-.icon-download {
- background-position: -120px -24px;
-}
-.icon-upload {
- background-position: -144px -24px;
-}
-.icon-inbox {
- background-position: -168px -24px;
-}
-.icon-play-circle {
- background-position: -192px -24px;
-}
-.icon-repeat {
- background-position: -216px -24px;
-}
-.icon-refresh {
- background-position: -240px -24px;
-}
-.icon-list-alt {
- background-position: -264px -24px;
-}
-.icon-lock {
- background-position: -287px -24px;
-}
-.icon-flag {
- background-position: -312px -24px;
-}
-.icon-headphones {
- background-position: -336px -24px;
-}
-.icon-volume-off {
- background-position: -360px -24px;
-}
-.icon-volume-down {
- background-position: -384px -24px;
-}
-.icon-volume-up {
- background-position: -408px -24px;
-}
-.icon-qrcode {
- background-position: -432px -24px;
-}
-.icon-barcode {
- background-position: -456px -24px;
-}
-.icon-tag {
- background-position: 0 -48px;
-}
-.icon-tags {
- background-position: -25px -48px;
-}
-.icon-book {
- background-position: -48px -48px;
-}
-.icon-bookmark {
- background-position: -72px -48px;
-}
-.icon-print {
- background-position: -96px -48px;
-}
-.icon-camera {
- background-position: -120px -48px;
-}
-.icon-font {
- background-position: -144px -48px;
-}
-.icon-bold {
- background-position: -167px -48px;
-}
-.icon-italic {
- background-position: -192px -48px;
-}
-.icon-text-height {
- background-position: -216px -48px;
-}
-.icon-text-width {
- background-position: -240px -48px;
-}
-.icon-align-left {
- background-position: -264px -48px;
-}
-.icon-align-center {
- background-position: -288px -48px;
-}
-.icon-align-right {
- background-position: -312px -48px;
-}
-.icon-align-justify {
- background-position: -336px -48px;
-}
-.icon-list {
- background-position: -360px -48px;
-}
-.icon-indent-left {
- background-position: -384px -48px;
-}
-.icon-indent-right {
- background-position: -408px -48px;
-}
-.icon-facetime-video {
- background-position: -432px -48px;
-}
-.icon-picture {
- background-position: -456px -48px;
-}
-.icon-pencil {
- background-position: 0 -72px;
-}
-.icon-map-marker {
- background-position: -24px -72px;
-}
-.icon-adjust {
- background-position: -48px -72px;
-}
-.icon-tint {
- background-position: -72px -72px;
-}
-.icon-edit {
- background-position: -96px -72px;
-}
-.icon-share {
- background-position: -120px -72px;
-}
-.icon-check {
- background-position: -144px -72px;
-}
-.icon-move {
- background-position: -168px -72px;
-}
-.icon-step-backward {
- background-position: -192px -72px;
-}
-.icon-fast-backward {
- background-position: -216px -72px;
-}
-.icon-backward {
- background-position: -240px -72px;
-}
-.icon-play {
- background-position: -264px -72px;
-}
-.icon-pause {
- background-position: -288px -72px;
-}
-.icon-stop {
- background-position: -312px -72px;
-}
-.icon-forward {
- background-position: -336px -72px;
-}
-.icon-fast-forward {
- background-position: -360px -72px;
-}
-.icon-step-forward {
- background-position: -384px -72px;
-}
-.icon-eject {
- background-position: -408px -72px;
-}
-.icon-chevron-left {
- background-position: -432px -72px;
-}
-.icon-chevron-right {
- background-position: -456px -72px;
-}
-.icon-plus-sign {
- background-position: 0 -96px;
-}
-.icon-minus-sign {
- background-position: -24px -96px;
-}
-.icon-remove-sign {
- background-position: -48px -96px;
-}
-.icon-ok-sign {
- background-position: -72px -96px;
-}
-.icon-question-sign {
- background-position: -96px -96px;
-}
-.icon-info-sign {
- background-position: -120px -96px;
-}
-.icon-screenshot {
- background-position: -144px -96px;
-}
-.icon-remove-circle {
- background-position: -168px -96px;
-}
-.icon-ok-circle {
- background-position: -192px -96px;
-}
-.icon-ban-circle {
- background-position: -216px -96px;
-}
-.icon-arrow-left {
- background-position: -240px -96px;
-}
-.icon-arrow-right {
- background-position: -264px -96px;
-}
-.icon-arrow-up {
- background-position: -289px -96px;
-}
-.icon-arrow-down {
- background-position: -312px -96px;
-}
-.icon-share-alt {
- background-position: -336px -96px;
-}
-.icon-resize-full {
- background-position: -360px -96px;
-}
-.icon-resize-small {
- background-position: -384px -96px;
-}
-.icon-plus {
- background-position: -408px -96px;
-}
-.icon-minus {
- background-position: -433px -96px;
-}
-.icon-asterisk {
- background-position: -456px -96px;
-}
-.icon-exclamation-sign {
- background-position: 0 -120px;
-}
-.icon-gift {
- background-position: -24px -120px;
-}
-.icon-leaf {
- background-position: -48px -120px;
-}
-.icon-fire {
- background-position: -72px -120px;
-}
-.icon-eye-open {
- background-position: -96px -120px;
-}
-.icon-eye-close {
- background-position: -120px -120px;
-}
-.icon-warning-sign {
- background-position: -144px -120px;
-}
-.icon-plane {
- background-position: -168px -120px;
-}
-.icon-calendar {
- background-position: -192px -120px;
-}
-.icon-random {
- background-position: -216px -120px;
-}
-.icon-comment {
- background-position: -240px -120px;
-}
-.icon-magnet {
- background-position: -264px -120px;
-}
-.icon-chevron-up {
- background-position: -288px -120px;
-}
-.icon-chevron-down {
- background-position: -313px -119px;
-}
-.icon-retweet {
- background-position: -336px -120px;
-}
-.icon-shopping-cart {
- background-position: -360px -120px;
-}
-.icon-folder-close {
- background-position: -384px -120px;
-}
-.icon-folder-open {
- background-position: -408px -120px;
-}
-.icon-resize-vertical {
- background-position: -432px -119px;
-}
-.icon-resize-horizontal {
- background-position: -456px -118px;
-}
-.btn-group {
- position: relative;
- *zoom: 1;
- *margin-left: .3em;
-}
-.btn-group:before,
-.btn-group:after {
- display: table;
- content: "";
-}
-.btn-group:after {
- clear: both;
-}
-.btn-group:first-child {
- *margin-left: 0;
-}
-.btn-group + .btn-group {
- margin-left: 5px;
-}
-.btn-toolbar {
- margin-top: 9px;
- margin-bottom: 9px;
-}
-.btn-toolbar .btn-group {
- display: inline-block;
- *display: inline;
- /* IE7 inline-block hack */
-
- *zoom: 1;
-}
-.btn-group .btn {
- position: relative;
- float: left;
- margin-left: -1px;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
-}
-.btn-group .btn:first-child {
- margin-left: 0;
- -webkit-border-top-left-radius: 4px;
- -moz-border-radius-topleft: 4px;
- border-top-left-radius: 4px;
- -webkit-border-bottom-left-radius: 4px;
- -moz-border-radius-bottomleft: 4px;
- border-bottom-left-radius: 4px;
-}
-.btn-group .btn:last-child,
-.btn-group .dropdown-toggle {
- -webkit-border-top-right-radius: 4px;
- -moz-border-radius-topright: 4px;
- border-top-right-radius: 4px;
- -webkit-border-bottom-right-radius: 4px;
- -moz-border-radius-bottomright: 4px;
- border-bottom-right-radius: 4px;
-}
-.btn-group .btn.large:first-child {
- margin-left: 0;
- -webkit-border-top-left-radius: 6px;
- -moz-border-radius-topleft: 6px;
- border-top-left-radius: 6px;
- -webkit-border-bottom-left-radius: 6px;
- -moz-border-radius-bottomleft: 6px;
- border-bottom-left-radius: 6px;
-}
-.btn-group .btn.large:last-child,
-.btn-group .large.dropdown-toggle {
- -webkit-border-top-right-radius: 6px;
- -moz-border-radius-topright: 6px;
- border-top-right-radius: 6px;
- -webkit-border-bottom-right-radius: 6px;
- -moz-border-radius-bottomright: 6px;
- border-bottom-right-radius: 6px;
-}
-.btn-group .btn:hover,
-.btn-group .btn:focus,
-.btn-group .btn:active,
-.btn-group .btn.active {
- z-index: 2;
-}
-.btn-group .dropdown-toggle:active,
-.btn-group.open .dropdown-toggle {
- outline: 0;
-}
-.btn-group .dropdown-toggle {
- padding-left: 8px;
- padding-right: 8px;
- -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
- box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
- *padding-top: 3px;
- *padding-bottom: 3px;
-}
-.btn-group .btn-mini.dropdown-toggle {
- padding-left: 5px;
- padding-right: 5px;
- *padding-top: 1px;
- *padding-bottom: 1px;
-}
-.btn-group .btn-small.dropdown-toggle {
- *padding-top: 4px;
- *padding-bottom: 4px;
-}
-.btn-group .btn-large.dropdown-toggle {
- padding-left: 12px;
- padding-right: 12px;
-}
-.btn-group.open {
- *z-index: 1000;
-}
-.btn-group.open .dropdown-menu {
- display: block;
- margin-top: 1px;
- -webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px;
-}
-.btn-group.open .dropdown-toggle {
- background-image: none;
- -webkit-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
- box-shadow: inset 0 1px 6px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
-}
-.btn .caret {
- margin-top: 7px;
- margin-left: 0;
-}
-.btn:hover .caret,
-.open.btn-group .caret {
- opacity: 1;
- filter: alpha(opacity=100);
-}
-.btn-mini .caret {
- margin-top: 5px;
-}
-.btn-small .caret {
- margin-top: 6px;
-}
-.btn-large .caret {
- margin-top: 6px;
- border-left: 5px solid transparent;
- border-right: 5px solid transparent;
- border-top: 5px solid #000000;
-}
-.btn-primary .caret,
-.btn-warning .caret,
-.btn-danger .caret,
-.btn-info .caret,
-.btn-success .caret,
-.btn-inverse .caret {
- border-top-color: #ffffff;
- border-bottom-color: #ffffff;
- opacity: 0.75;
- filter: alpha(opacity=75);
-}
-.nav {
- margin-left: 0;
- margin-bottom: 18px;
- list-style: none;
-}
-.nav > li > a {
- display: block;
-}
-.nav > li > a:hover {
- text-decoration: none;
- background-color: #eeeeee;
-}
-.nav .nav-header {
- display: block;
- padding: 3px 15px;
- font-size: 11px;
- font-weight: bold;
- line-height: 18px;
- color: #999999;
- text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
- text-transform: uppercase;
-}
-.nav li + .nav-header {
- margin-top: 9px;
-}
-.nav-list {
- padding-left: 15px;
- padding-right: 15px;
- margin-bottom: 0;
-}
-.nav-list > li > a,
-.nav-list .nav-header {
- margin-left: -15px;
- margin-right: -15px;
- text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
-}
-.nav-list > li > a {
- padding: 3px 15px;
-}
-.nav-list > .active > a,
-.nav-list > .active > a:hover {
- color: #ffffff;
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
- background-color: #0088cc;
-}
-.nav-list [class^="icon-"] {
- margin-right: 2px;
-}
-.nav-list .divider {
- height: 1px;
- margin: 8px 1px;
- overflow: hidden;
- background-color: #e5e5e5;
- border-bottom: 1px solid #ffffff;
- *width: 100%;
- *margin: -5px 0 5px;
-}
-.nav-tabs,
-.nav-pills {
- *zoom: 1;
-}
-.nav-tabs:before,
-.nav-pills:before,
-.nav-tabs:after,
-.nav-pills:after {
- display: table;
- content: "";
-}
-.nav-tabs:after,
-.nav-pills:after {
- clear: both;
-}
-.nav-tabs > li,
-.nav-pills > li {
- float: left;
-}
-.nav-tabs > li > a,
-.nav-pills > li > a {
- padding-right: 12px;
- padding-left: 12px;
- margin-right: 2px;
- line-height: 14px;
-}
-.nav-tabs {
- border-bottom: 1px solid #ddd;
-}
-.nav-tabs > li {
- margin-bottom: -1px;
-}
-.nav-tabs > li > a {
- padding-top: 8px;
- padding-bottom: 8px;
- line-height: 18px;
- border: 1px solid transparent;
- -webkit-border-radius: 4px 4px 0 0;
- -moz-border-radius: 4px 4px 0 0;
- border-radius: 4px 4px 0 0;
-}
-.nav-tabs > li > a:hover {
- border-color: #eeeeee #eeeeee #dddddd;
-}
-.nav-tabs > .active > a,
-.nav-tabs > .active > a:hover {
- color: #555555;
- background-color: #ffffff;
- border: 1px solid #ddd;
- border-bottom-color: transparent;
- cursor: default;
-}
-.nav-pills > li > a {
- padding-top: 8px;
- padding-bottom: 8px;
- margin-top: 2px;
- margin-bottom: 2px;
- -webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px;
-}
-.nav-pills > .active > a,
-.nav-pills > .active > a:hover {
- color: #ffffff;
- background-color: #0088cc;
-}
-.nav-stacked > li {
- float: none;
-}
-.nav-stacked > li > a {
- margin-right: 0;
-}
-.nav-tabs.nav-stacked {
- border-bottom: 0;
-}
-.nav-tabs.nav-stacked > li > a {
- border: 1px solid #ddd;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
-}
-.nav-tabs.nav-stacked > li:first-child > a {
- -webkit-border-radius: 4px 4px 0 0;
- -moz-border-radius: 4px 4px 0 0;
- border-radius: 4px 4px 0 0;
-}
-.nav-tabs.nav-stacked > li:last-child > a {
- -webkit-border-radius: 0 0 4px 4px;
- -moz-border-radius: 0 0 4px 4px;
- border-radius: 0 0 4px 4px;
-}
-.nav-tabs.nav-stacked > li > a:hover {
- border-color: #ddd;
- z-index: 2;
-}
-.nav-pills.nav-stacked > li > a {
- margin-bottom: 3px;
-}
-.nav-pills.nav-stacked > li:last-child > a {
- margin-bottom: 1px;
-}
-.nav-tabs .dropdown-menu,
-.nav-pills .dropdown-menu {
- margin-top: 1px;
- border-width: 1px;
-}
-.nav-pills .dropdown-menu {
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
-}
-.nav-tabs .dropdown-toggle .caret,
-.nav-pills .dropdown-toggle .caret {
- border-top-color: #0088cc;
- border-bottom-color: #0088cc;
- margin-top: 6px;
-}
-.nav-tabs .dropdown-toggle:hover .caret,
-.nav-pills .dropdown-toggle:hover .caret {
- border-top-color: #005580;
- border-bottom-color: #005580;
-}
-.nav-tabs .active .dropdown-toggle .caret,
-.nav-pills .active .dropdown-toggle .caret {
- border-top-color: #333333;
- border-bottom-color: #333333;
-}
-.nav > .dropdown.active > a:hover {
- color: #000000;
- cursor: pointer;
-}
-.nav-tabs .open .dropdown-toggle,
-.nav-pills .open .dropdown-toggle,
-.nav > .open.active > a:hover {
- color: #ffffff;
- background-color: #999999;
- border-color: #999999;
-}
-.nav .open .caret,
-.nav .open.active .caret,
-.nav .open a:hover .caret {
- border-top-color: #ffffff;
- border-bottom-color: #ffffff;
- opacity: 1;
- filter: alpha(opacity=100);
-}
-.tabs-stacked .open > a:hover {
- border-color: #999999;
-}
-.tabbable {
- *zoom: 1;
-}
-.tabbable:before,
-.tabbable:after {
- display: table;
- content: "";
-}
-.tabbable:after {
- clear: both;
-}
-.tab-content {
- display: table;
- width: 100%;
-}
-.tabs-below .nav-tabs,
-.tabs-right .nav-tabs,
-.tabs-left .nav-tabs {
- border-bottom: 0;
-}
-.tab-content > .tab-pane,
-.pill-content > .pill-pane {
- display: none;
-}
-.tab-content > .active,
-.pill-content > .active {
- display: block;
-}
-.tabs-below .nav-tabs {
- border-top: 1px solid #ddd;
-}
-.tabs-below .nav-tabs > li {
- margin-top: -1px;
- margin-bottom: 0;
-}
-.tabs-below .nav-tabs > li > a {
- -webkit-border-radius: 0 0 4px 4px;
- -moz-border-radius: 0 0 4px 4px;
- border-radius: 0 0 4px 4px;
-}
-.tabs-below .nav-tabs > li > a:hover {
- border-bottom-color: transparent;
- border-top-color: #ddd;
-}
-.tabs-below .nav-tabs .active > a,
-.tabs-below .nav-tabs .active > a:hover {
- border-color: transparent #ddd #ddd #ddd;
-}
-.tabs-left .nav-tabs > li,
-.tabs-right .nav-tabs > li {
- float: none;
-}
-.tabs-left .nav-tabs > li > a,
-.tabs-right .nav-tabs > li > a {
- min-width: 74px;
- margin-right: 0;
- margin-bottom: 3px;
-}
-.tabs-left .nav-tabs {
- float: left;
- margin-right: 19px;
- border-right: 1px solid #ddd;
-}
-.tabs-left .nav-tabs > li > a {
- margin-right: -1px;
- -webkit-border-radius: 4px 0 0 4px;
- -moz-border-radius: 4px 0 0 4px;
- border-radius: 4px 0 0 4px;
-}
-.tabs-left .nav-tabs > li > a:hover {
- border-color: #eeeeee #dddddd #eeeeee #eeeeee;
-}
-.tabs-left .nav-tabs .active > a,
-.tabs-left .nav-tabs .active > a:hover {
- border-color: #ddd transparent #ddd #ddd;
- *border-right-color: #ffffff;
-}
-.tabs-right .nav-tabs {
- float: right;
- margin-left: 19px;
- border-left: 1px solid #ddd;
-}
-.tabs-right .nav-tabs > li > a {
- margin-left: -1px;
- -webkit-border-radius: 0 4px 4px 0;
- -moz-border-radius: 0 4px 4px 0;
- border-radius: 0 4px 4px 0;
-}
-.tabs-right .nav-tabs > li > a:hover {
- border-color: #eeeeee #eeeeee #eeeeee #dddddd;
-}
-.tabs-right .nav-tabs .active > a,
-.tabs-right .nav-tabs .active > a:hover {
- border-color: #ddd #ddd #ddd transparent;
- *border-left-color: #ffffff;
-}
-.navbar {
- *position: relative;
- *z-index: 2;
- overflow: visible;
- margin-bottom: 18px;
-}
-.navbar-inner {
- padding-left: 20px;
- padding-right: 20px;
- background-color: #2c2c2c;
- background-image: -moz-linear-gradient(top, #333333, #222222);
- background-image: -ms-linear-gradient(top, #333333, #222222);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));
- background-image: -webkit-linear-gradient(top, #333333, #222222);
- background-image: -o-linear-gradient(top, #333333, #222222);
- background-image: linear-gradient(top, #333333, #222222);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
- -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), inset 0 -1px 0 rgba(0, 0, 0, 0.1);
-}
-.navbar .container {
- width: auto;
-}
-.btn-navbar {
- display: none;
- float: right;
- padding: 7px 10px;
- margin-left: 5px;
- margin-right: 5px;
- background-color: #2c2c2c;
- background-image: -moz-linear-gradient(top, #333333, #222222);
- background-image: -ms-linear-gradient(top, #333333, #222222);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));
- background-image: -webkit-linear-gradient(top, #333333, #222222);
- background-image: -o-linear-gradient(top, #333333, #222222);
- background-image: linear-gradient(top, #333333, #222222);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);
- border-color: #222222 #222222 #000000;
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
- filter: progid:dximagetransform.microsoft.gradient(enabled=false);
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075);
-}
-.btn-navbar:hover,
-.btn-navbar:active,
-.btn-navbar.active,
-.btn-navbar.disabled,
-.btn-navbar[disabled] {
- background-color: #222222;
-}
-.btn-navbar:active,
-.btn-navbar.active {
- background-color: #080808 \9;
-}
-.btn-navbar .icon-bar {
- display: block;
- width: 18px;
- height: 2px;
- background-color: #f5f5f5;
- -webkit-border-radius: 1px;
- -moz-border-radius: 1px;
- border-radius: 1px;
- -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
- -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
-}
-.btn-navbar .icon-bar + .icon-bar {
- margin-top: 3px;
-}
-.nav-collapse.collapse {
- height: auto;
-}
-.navbar {
- color: #999999;
-}
-.navbar .brand:hover {
- text-decoration: none;
-}
-.navbar .brand {
- float: left;
- display: block;
- padding: 8px 20px 12px;
- margin-left: -20px;
- font-size: 20px;
- font-weight: 200;
- line-height: 1;
- color: #ffffff;
-}
-.navbar .navbar-text {
- margin-bottom: 0;
- line-height: 40px;
-}
-.navbar .btn,
-.navbar .btn-group {
- margin-top: 5px;
-}
-.navbar .btn-group .btn {
- margin-top: 0;
-}
-.navbar-form {
- margin-bottom: 0;
- *zoom: 1;
-}
-.navbar-form:before,
-.navbar-form:after {
- display: table;
- content: "";
-}
-.navbar-form:after {
- clear: both;
-}
-.navbar-form input,
-.navbar-form select,
-.navbar-form .radio,
-.navbar-form .checkbox {
- margin-top: 5px;
-}
-.navbar-form input,
-.navbar-form select {
- display: inline-block;
- margin-bottom: 0;
-}
-.navbar-form input[type="image"],
-.navbar-form input[type="checkbox"],
-.navbar-form input[type="radio"] {
- margin-top: 3px;
-}
-.navbar-form .input-append,
-.navbar-form .input-prepend {
- margin-top: 6px;
- white-space: nowrap;
-}
-.navbar-form .input-append input,
-.navbar-form .input-prepend input {
- margin-top: 0;
-}
-.navbar-search {
- position: relative;
- float: left;
- margin-top: 6px;
- margin-bottom: 0;
-}
-.navbar-search .search-query {
- padding: 4px 9px;
- font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
- font-size: 13px;
- font-weight: normal;
- line-height: 1;
- color: #ffffff;
- background-color: #626262;
- border: 1px solid #151515;
- -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15);
- -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15);
- box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0px rgba(255, 255, 255, 0.15);
- -webkit-transition: none;
- -moz-transition: none;
- -ms-transition: none;
- -o-transition: none;
- transition: none;
-}
-.navbar-search .search-query:-moz-placeholder {
- color: #cccccc;
-}
-.navbar-search .search-query::-webkit-input-placeholder {
- color: #cccccc;
-}
-.navbar-search .search-query:focus,
-.navbar-search .search-query.focused {
- padding: 5px 10px;
- color: #333333;
- text-shadow: 0 1px 0 #ffffff;
- background-color: #ffffff;
- border: 0;
- -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
- -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
- box-shadow: 0 0 3px rgba(0, 0, 0, 0.15);
- outline: 0;
-}
-.navbar-fixed-top,
-.navbar-fixed-bottom {
- position: fixed;
- right: 0;
- left: 0;
- z-index: 1030;
- margin-bottom: 0;
-}
-.navbar-fixed-top .navbar-inner,
-.navbar-fixed-bottom .navbar-inner {
- padding-left: 0;
- padding-right: 0;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
-}
-.navbar-fixed-top .container,
-.navbar-fixed-bottom .container {
- width: 940px;
-}
-.navbar-fixed-top {
- top: 0;
-}
-.navbar-fixed-bottom {
- bottom: 0;
-}
-.navbar .nav {
- position: relative;
- left: 0;
- display: block;
- float: left;
- margin: 0 10px 0 0;
-}
-.navbar .nav.pull-right {
- float: right;
-}
-.navbar .nav > li {
- display: block;
- float: left;
-}
-.navbar .nav > li > a {
- float: none;
- padding: 10px 10px 11px;
- line-height: 19px;
- color: #999999;
- text-decoration: none;
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
-}
-.navbar .nav > li > a:hover {
- background-color: transparent;
- color: #ffffff;
- text-decoration: none;
-}
-.navbar .nav .active > a,
-.navbar .nav .active > a:hover {
- color: #ffffff;
- text-decoration: none;
- background-color: #222222;
-}
-.navbar .divider-vertical {
- height: 40px;
- width: 1px;
- margin: 0 9px;
- overflow: hidden;
- background-color: #222222;
- border-right: 1px solid #333333;
-}
-.navbar .nav.pull-right {
- margin-left: 10px;
- margin-right: 0;
-}
-.navbar .dropdown-menu {
- margin-top: 1px;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
-}
-.navbar .dropdown-menu:before {
- content: '';
- display: inline-block;
- border-left: 7px solid transparent;
- border-right: 7px solid transparent;
- border-bottom: 7px solid #ccc;
- border-bottom-color: rgba(0, 0, 0, 0.2);
- position: absolute;
- top: -7px;
- left: 9px;
-}
-.navbar .dropdown-menu:after {
- content: '';
- display: inline-block;
- border-left: 6px solid transparent;
- border-right: 6px solid transparent;
- border-bottom: 6px solid #ffffff;
- position: absolute;
- top: -6px;
- left: 10px;
-}
-.navbar-fixed-bottom .dropdown-menu:before {
- border-top: 7px solid #ccc;
- border-top-color: rgba(0, 0, 0, 0.2);
- border-bottom: 0;
- bottom: -7px;
- top: auto;
-}
-.navbar-fixed-bottom .dropdown-menu:after {
- border-top: 6px solid #ffffff;
- border-bottom: 0;
- bottom: -6px;
- top: auto;
-}
-.navbar .nav .dropdown-toggle .caret,
-.navbar .nav .open.dropdown .caret {
- border-top-color: #ffffff;
- border-bottom-color: #ffffff;
-}
-.navbar .nav .active .caret {
- opacity: 1;
- filter: alpha(opacity=100);
-}
-.navbar .nav .open > .dropdown-toggle,
-.navbar .nav .active > .dropdown-toggle,
-.navbar .nav .open.active > .dropdown-toggle {
- background-color: transparent;
-}
-.navbar .nav .active > .dropdown-toggle:hover {
- color: #ffffff;
-}
-.navbar .nav.pull-right .dropdown-menu,
-.navbar .nav .dropdown-menu.pull-right {
- left: auto;
- right: 0;
-}
-.navbar .nav.pull-right .dropdown-menu:before,
-.navbar .nav .dropdown-menu.pull-right:before {
- left: auto;
- right: 12px;
-}
-.navbar .nav.pull-right .dropdown-menu:after,
-.navbar .nav .dropdown-menu.pull-right:after {
- left: auto;
- right: 13px;
-}
-.breadcrumb {
- padding: 7px 14px;
- margin: 0 0 18px;
- list-style: none;
- background-color: #fbfbfb;
- background-image: -moz-linear-gradient(top, #ffffff, #f5f5f5);
- background-image: -ms-linear-gradient(top, #ffffff, #f5f5f5);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));
- background-image: -webkit-linear-gradient(top, #ffffff, #f5f5f5);
- background-image: -o-linear-gradient(top, #ffffff, #f5f5f5);
- background-image: linear-gradient(top, #ffffff, #f5f5f5);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);
- border: 1px solid #ddd;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
- -webkit-box-shadow: inset 0 1px 0 #ffffff;
- -moz-box-shadow: inset 0 1px 0 #ffffff;
- box-shadow: inset 0 1px 0 #ffffff;
-}
-.breadcrumb li {
- display: inline-block;
- *display: inline;
- /* IE7 inline-block hack */
-
- *zoom: 1;
- text-shadow: 0 1px 0 #ffffff;
-}
-.breadcrumb .divider {
- padding: 0 5px;
- color: #999999;
-}
-.breadcrumb .active a {
- color: #333333;
-}
-.pagination {
- height: 36px;
- margin: 18px 0;
-}
-.pagination ul {
- display: inline-block;
- *display: inline;
- /* IE7 inline-block hack */
-
- *zoom: 1;
- margin-left: 0;
- margin-bottom: 0;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
- -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
-}
-.pagination li {
- display: inline;
-}
-.pagination a {
- float: left;
- padding: 0 14px;
- line-height: 34px;
- text-decoration: none;
- border: 1px solid #ddd;
- border-left-width: 0;
-}
-.pagination a:hover,
-.pagination .active a {
- background-color: #f5f5f5;
-}
-.pagination .active a {
- color: #999999;
- cursor: default;
-}
-.pagination .disabled span,
-.pagination .disabled a,
-.pagination .disabled a:hover {
- color: #999999;
- background-color: transparent;
- cursor: default;
-}
-.pagination li:first-child a {
- border-left-width: 1px;
- -webkit-border-radius: 3px 0 0 3px;
- -moz-border-radius: 3px 0 0 3px;
- border-radius: 3px 0 0 3px;
-}
-.pagination li:last-child a {
- -webkit-border-radius: 0 3px 3px 0;
- -moz-border-radius: 0 3px 3px 0;
- border-radius: 0 3px 3px 0;
-}
-.pagination-centered {
- text-align: center;
-}
-.pagination-right {
- text-align: right;
-}
-.pager {
- margin-left: 0;
- margin-bottom: 18px;
- list-style: none;
- text-align: center;
- *zoom: 1;
-}
-.pager:before,
-.pager:after {
- display: table;
- content: "";
-}
-.pager:after {
- clear: both;
-}
-.pager li {
- display: inline;
-}
-.pager a {
- display: inline-block;
- padding: 5px 14px;
- background-color: #fff;
- /*border: 1px solid #ddd;
- -webkit-border-radius: 15px;
- -moz-border-radius: 15px;
- border-radius: 15px;*/
-}
-.pager a:hover {
- text-decoration: none;
- background-color: #f5f5f5;
-}
-.pager .next a {
- float: right;
-}
-.pager .previous a {
- float: left;
-}
-.pager .disabled a,
-.pager .disabled a:hover {
- color: #999999;
- background-color: #fff;
- cursor: default;
-}
-.thumbnails {
- margin-left: -20px;
- list-style: none;
- *zoom: 1;
-}
-.thumbnails:before,
-.thumbnails:after {
- display: table;
- content: "";
-}
-.thumbnails:after {
- clear: both;
-}
-.thumbnails > li {
- float: left;
- margin: 0 0 18px 20px;
-}
-.thumbnail {
- display: block;
- padding: 4px;
- line-height: 1;
- border: 1px solid #ddd;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);
- -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);
- box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075);
-}
-a.thumbnail:hover {
- border-color: #0088cc;
- -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
- -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
- box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25);
-}
-.thumbnail > img {
- display: block;
- max-width: 100%;
- margin-left: auto;
- margin-right: auto;
-}
-.thumbnail .caption {
- padding: 9px;
-}
-.alert {
- padding: 8px 35px 8px 14px;
- margin-bottom: 18px;
- text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
- background-color: #fcf8e3;
- border: 1px solid #fbeed5;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- color: #c09853;
-}
-.alert-heading {
- color: inherit;
-}
-.alert .close {
- position: relative;
- top: -2px;
- right: -21px;
- line-height: 18px;
-}
-.alert-success {
- background-color: #dff0d8;
- border-color: #d6e9c6;
- color: #468847;
-}
-.alert-danger,
-.alert-error {
- background-color: #f2dede;
- border-color: #eed3d7;
- color: #b94a48;
-}
-.alert-info {
- background-color: #d9edf7;
- border-color: #bce8f1;
- color: #3a87ad;
-}
-.alert-block {
- padding-top: 14px;
- padding-bottom: 14px;
-}
-.alert-block > p,
-.alert-block > ul {
- margin-bottom: 0;
-}
-.alert-block p + p {
- margin-top: 5px;
-}
-@-webkit-keyframes progress-bar-stripes {
- from {
- background-position: 0 0;
- }
- to {
- background-position: 40px 0;
- }
-}
-@-moz-keyframes progress-bar-stripes {
- from {
- background-position: 0 0;
- }
- to {
- background-position: 40px 0;
- }
-}
-@-ms-keyframes progress-bar-stripes {
- from {
- background-position: 0 0;
- }
- to {
- background-position: 40px 0;
- }
-}
-@keyframes progress-bar-stripes {
- from {
- background-position: 0 0;
- }
- to {
- background-position: 40px 0;
- }
-}
-.progress {
- overflow: hidden;
- height: 18px;
- margin-bottom: 18px;
- background-color: #f7f7f7;
- background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);
- background-image: -ms-linear-gradient(top, #f5f5f5, #f9f9f9);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));
- background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9);
- background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);
- background-image: linear-gradient(top, #f5f5f5, #f9f9f9);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);
- -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
- -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
- box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
-}
-.progress .bar {
- width: 0%;
- height: 18px;
- color: #ffffff;
- font-size: 12px;
- text-align: center;
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
- background-color: #0e90d2;
- background-image: -moz-linear-gradient(top, #149bdf, #0480be);
- background-image: -ms-linear-gradient(top, #149bdf, #0480be);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));
- background-image: -webkit-linear-gradient(top, #149bdf, #0480be);
- background-image: -o-linear-gradient(top, #149bdf, #0480be);
- background-image: linear-gradient(top, #149bdf, #0480be);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);
- -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
- -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
- box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- -ms-box-sizing: border-box;
- box-sizing: border-box;
- -webkit-transition: width 0.6s ease;
- -moz-transition: width 0.6s ease;
- -ms-transition: width 0.6s ease;
- -o-transition: width 0.6s ease;
- transition: width 0.6s ease;
-}
-.progress-striped .bar {
- background-color: #149bdf;
- background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
- background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- -webkit-background-size: 40px 40px;
- -moz-background-size: 40px 40px;
- -o-background-size: 40px 40px;
- background-size: 40px 40px;
-}
-.progress.active .bar {
- -webkit-animation: progress-bar-stripes 2s linear infinite;
- -moz-animation: progress-bar-stripes 2s linear infinite;
- animation: progress-bar-stripes 2s linear infinite;
-}
-.progress-danger .bar {
- background-color: #dd514c;
- background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35);
- background-image: -ms-linear-gradient(top, #ee5f5b, #c43c35);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));
- background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35);
- background-image: -o-linear-gradient(top, #ee5f5b, #c43c35);
- background-image: linear-gradient(top, #ee5f5b, #c43c35);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);
-}
-.progress-danger.progress-striped .bar {
- background-color: #ee5f5b;
- background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
- background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-}
-.progress-success .bar {
- background-color: #5eb95e;
- background-image: -moz-linear-gradient(top, #62c462, #57a957);
- background-image: -ms-linear-gradient(top, #62c462, #57a957);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));
- background-image: -webkit-linear-gradient(top, #62c462, #57a957);
- background-image: -o-linear-gradient(top, #62c462, #57a957);
- background-image: linear-gradient(top, #62c462, #57a957);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);
-}
-.progress-success.progress-striped .bar {
- background-color: #62c462;
- background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
- background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-}
-.progress-info .bar {
- background-color: #4bb1cf;
- background-image: -moz-linear-gradient(top, #5bc0de, #339bb9);
- background-image: -ms-linear-gradient(top, #5bc0de, #339bb9);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));
- background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9);
- background-image: -o-linear-gradient(top, #5bc0de, #339bb9);
- background-image: linear-gradient(top, #5bc0de, #339bb9);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);
-}
-.progress-info.progress-striped .bar {
- background-color: #5bc0de;
- background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
- background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-}
-.progress-warning .bar {
- background-color: #faa732;
- background-image: -moz-linear-gradient(top, #fbb450, #f89406);
- background-image: -ms-linear-gradient(top, #fbb450, #f89406);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
- background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
- background-image: -o-linear-gradient(top, #fbb450, #f89406);
- background-image: linear-gradient(top, #fbb450, #f89406);
- background-repeat: repeat-x;
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);
-}
-.progress-warning.progress-striped .bar {
- background-color: #fbb450;
- background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
- background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
- background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
-}
-.hero-unit {
- padding: 60px;
- margin-bottom: 30px;
- background-color: #eeeeee;
- -webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- border-radius: 6px;
-}
-.hero-unit h1 {
- margin-bottom: 0;
- font-size: 60px;
- line-height: 1;
- color: inherit;
- letter-spacing: -1px;
-}
-.hero-unit p {
- font-size: 18px;
- font-weight: 200;
- line-height: 27px;
- color: inherit;
-}
-.tooltip {
- position: absolute;
- z-index: 1020;
- display: block;
- visibility: visible;
- padding: 5px;
- font-size: 11px;
- opacity: 0;
- filter: alpha(opacity=0);
-}
-.tooltip.in {
- opacity: 0.8;
- filter: alpha(opacity=80);
-}
-.tooltip.top {
- margin-top: -2px;
-}
-.tooltip.right {
- margin-left: 2px;
-}
-.tooltip.bottom {
- margin-top: 2px;
-}
-.tooltip.left {
- margin-left: -2px;
-}
-.tooltip.top .tooltip-arrow {
- bottom: 0;
- left: 50%;
- margin-left: -5px;
- border-left: 5px solid transparent;
- border-right: 5px solid transparent;
- border-top: 5px solid #000000;
-}
-.tooltip.left .tooltip-arrow {
- top: 50%;
- right: 0;
- margin-top: -5px;
- border-top: 5px solid transparent;
- border-bottom: 5px solid transparent;
- border-left: 5px solid #000000;
-}
-.tooltip.bottom .tooltip-arrow {
- top: 0;
- left: 50%;
- margin-left: -5px;
- border-left: 5px solid transparent;
- border-right: 5px solid transparent;
- border-bottom: 5px solid #000000;
-}
-.tooltip.right .tooltip-arrow {
- top: 50%;
- left: 0;
- margin-top: -5px;
- border-top: 5px solid transparent;
- border-bottom: 5px solid transparent;
- border-right: 5px solid #000000;
-}
-.tooltip-inner {
- max-width: 200px;
- padding: 3px 8px;
- color: #ffffff;
- text-align: center;
- text-decoration: none;
- background-color: #000000;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
-}
-.tooltip-arrow {
- position: absolute;
- width: 0;
- height: 0;
-}
-.popover {
- position: absolute;
- top: 0;
- left: 0;
- z-index: 1010;
- display: none;
- padding: 5px;
-}
-.popover.top {
- margin-top: -5px;
-}
-.popover.right {
- margin-left: 5px;
-}
-.popover.bottom {
- margin-top: 5px;
-}
-.popover.left {
- margin-left: -5px;
-}
-.popover.top .arrow {
- bottom: 0;
- left: 50%;
- margin-left: -5px;
- border-left: 5px solid transparent;
- border-right: 5px solid transparent;
- border-top: 5px solid #000000;
-}
-.popover.right .arrow {
- top: 50%;
- left: 0;
- margin-top: -5px;
- border-top: 5px solid transparent;
- border-bottom: 5px solid transparent;
- border-right: 5px solid #000000;
-}
-.popover.bottom .arrow {
- top: 0;
- left: 50%;
- margin-left: -5px;
- border-left: 5px solid transparent;
- border-right: 5px solid transparent;
- border-bottom: 5px solid #000000;
-}
-.popover.left .arrow {
- top: 50%;
- right: 0;
- margin-top: -5px;
- border-top: 5px solid transparent;
- border-bottom: 5px solid transparent;
- border-left: 5px solid #000000;
-}
-.popover .arrow {
- position: absolute;
- width: 0;
- height: 0;
-}
-.popover-inner {
- padding: 3px;
- width: 280px;
- overflow: hidden;
- background: #000000;
- background: rgba(0, 0, 0, 0.8);
- -webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- border-radius: 6px;
- -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
- -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
- box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
-}
-.popover-title {
- padding: 9px 15px;
- line-height: 1;
- background-color: #f5f5f5;
- border-bottom: 1px solid #eee;
- -webkit-border-radius: 3px 3px 0 0;
- -moz-border-radius: 3px 3px 0 0;
- border-radius: 3px 3px 0 0;
-}
-.popover-content {
- padding: 14px;
- background-color: #ffffff;
- -webkit-border-radius: 0 0 3px 3px;
- -moz-border-radius: 0 0 3px 3px;
- border-radius: 0 0 3px 3px;
- -webkit-background-clip: padding-box;
- -moz-background-clip: padding-box;
- background-clip: padding-box;
-}
-.popover-content p,
-.popover-content ul,
-.popover-content ol {
- margin-bottom: 0;
-}
-.modal-open .dropdown-menu {
- z-index: 2050;
-}
-.modal-open .dropdown.open {
- *z-index: 2050;
-}
-.modal-open .popover {
- z-index: 2060;
-}
-.modal-open .tooltip {
- z-index: 2070;
-}
-.modal-backdrop {
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- z-index: 1040;
- background-color: #000000;
-}
-.modal-backdrop.fade {
- opacity: 0;
-}
-.modal-backdrop,
-.modal-backdrop.fade.in {
- opacity: 0.8;
- filter: alpha(opacity=80);
-}
-.modal {
- position: fixed;
- top: 50%;
- left: 50%;
- z-index: 1050;
- overflow: auto;
- width: 560px;
- margin: -250px 0 0 -280px;
- background-color: #ffffff;
- border: 1px solid #999;
- border: 1px solid rgba(0, 0, 0, 0.3);
- *border: 1px solid #999;
- /* IE6-7 */
-
- -webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- border-radius: 6px;
- -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
- -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
- box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
- -webkit-background-clip: padding-box;
- -moz-background-clip: padding-box;
- background-clip: padding-box;
-}
-.modal.fade {
- -webkit-transition: opacity .3s linear, top .3s ease-out;
- -moz-transition: opacity .3s linear, top .3s ease-out;
- -ms-transition: opacity .3s linear, top .3s ease-out;
- -o-transition: opacity .3s linear, top .3s ease-out;
- transition: opacity .3s linear, top .3s ease-out;
- top: -25%;
-}
-.modal.fade.in {
- top: 50%;
-}
-.modal-header {
- padding: 9px 15px;
- border-bottom: 1px solid #eee;
-}
-.modal-header .close {
- margin-top: 2px;
-}
-.modal-body {
- overflow-y: auto;
- max-height: 400px;
- padding: 15px;
-}
-.modal-form {
- margin-bottom: 0;
-}
-.modal-footer {
- padding: 14px 15px 15px;
- margin-bottom: 0;
- text-align: right;
- background-color: #f5f5f5;
- border-top: 1px solid #ddd;
- -webkit-border-radius: 0 0 6px 6px;
- -moz-border-radius: 0 0 6px 6px;
- border-radius: 0 0 6px 6px;
- -webkit-box-shadow: inset 0 1px 0 #ffffff;
- -moz-box-shadow: inset 0 1px 0 #ffffff;
- box-shadow: inset 0 1px 0 #ffffff;
- *zoom: 1;
-}
-.modal-footer:before,
-.modal-footer:after {
- display: table;
- content: "";
-}
-.modal-footer:after {
- clear: both;
-}
-.modal-footer .btn + .btn {
- margin-left: 5px;
- margin-bottom: 0;
-}
-.modal-footer .btn-group .btn + .btn {
- margin-left: -1px;
-}
-.dropdown {
- position: relative;
-}
-.dropdown-toggle {
- *margin-bottom: -3px;
-}
-.dropdown-toggle:active,
-.open .dropdown-toggle {
- outline: 0;
-}
-.caret {
- display: inline-block;
- width: 0;
- height: 0;
- vertical-align: top;
- border-left: 4px solid transparent;
- border-right: 4px solid transparent;
- border-top: 4px solid #000000;
- opacity: 0.3;
- filter: alpha(opacity=30);
- content: "";
-}
-.dropdown .caret {
- margin-top: 8px;
- margin-left: 2px;
-}
-.dropdown:hover .caret,
-.open.dropdown .caret {
- opacity: 1;
- filter: alpha(opacity=100);
-}
-.dropdown-menu {
- position: absolute;
- top: 100%;
- left: 0;
- z-index: 1000;
- float: left;
- display: none;
- min-width: 160px;
- padding: 4px 0;
- margin: 0;
- list-style: none;
- background-color: #ffffff;
- border-color: #ccc;
- border-color: rgba(0, 0, 0, 0.2);
- border-style: solid;
- border-width: 1px;
- -webkit-border-radius: 0 0 5px 5px;
- -moz-border-radius: 0 0 5px 5px;
- border-radius: 0 0 5px 5px;
- -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
- -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
- box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
- -webkit-background-clip: padding-box;
- -moz-background-clip: padding;
- background-clip: padding-box;
- *border-right-width: 2px;
- *border-bottom-width: 2px;
-}
-.dropdown-menu.pull-right {
- right: 0;
- left: auto;
-}
-.dropdown-menu .divider {
- height: 1px;
- margin: 8px 1px;
- overflow: hidden;
- background-color: #e5e5e5;
- border-bottom: 1px solid #ffffff;
- *width: 100%;
- *margin: -5px 0 5px;
-}
-.dropdown-menu a {
- display: block;
- padding: 3px 15px;
- clear: both;
- font-weight: normal;
- line-height: 18px;
- color: #333333;
- white-space: nowrap;
-}
-.dropdown-menu li > a:hover,
-.dropdown-menu .active > a,
-.dropdown-menu .active > a:hover {
- color: #ffffff;
- text-decoration: none;
- background-color: #0088cc;
-}
-.dropdown.open {
- *z-index: 1000;
-}
-.dropdown.open .dropdown-toggle {
- color: #ffffff;
- background: #ccc;
- background: rgba(0, 0, 0, 0.3);
-}
-.dropdown.open .dropdown-menu {
- display: block;
-}
-.pull-right .dropdown-menu {
- left: auto;
- right: 0;
-}
-.dropup .caret,
-.navbar-fixed-bottom .dropdown .caret {
- border-top: 0;
- border-bottom: 4px solid #000000;
- content: "\2191";
-}
-.dropup .dropdown-menu,
-.navbar-fixed-bottom .dropdown .dropdown-menu {
- top: auto;
- bottom: 100%;
- margin-bottom: 1px;
-}
-.typeahead {
- margin-top: 2px;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
-}
-.accordion {
- margin-bottom: 18px;
-}
-.accordion-group {
- margin-bottom: 2px;
- border: 1px solid #e5e5e5;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
-}
-.accordion-heading {
- border-bottom: 0;
-}
-.accordion-heading .accordion-toggle {
- display: block;
- padding: 8px 15px;
-}
-.accordion-inner {
- padding: 9px 15px;
- border-top: 1px solid #e5e5e5;
-}
-.carousel {
- position: relative;
- margin-bottom: 18px;
- line-height: 1;
-}
-.carousel-inner {
- overflow: hidden;
- width: 100%;
- position: relative;
-}
-.carousel .item {
- display: none;
- position: relative;
- -webkit-transition: 0.6s ease-in-out left;
- -moz-transition: 0.6s ease-in-out left;
- -ms-transition: 0.6s ease-in-out left;
- -o-transition: 0.6s ease-in-out left;
- transition: 0.6s ease-in-out left;
-}
-.carousel .item > img {
- display: block;
- line-height: 1;
-}
-.carousel .active,
-.carousel .next,
-.carousel .prev {
- display: block;
-}
-.carousel .active {
- left: 0;
-}
-.carousel .next,
-.carousel .prev {
- position: absolute;
- top: 0;
- width: 100%;
-}
-.carousel .next {
- left: 100%;
-}
-.carousel .prev {
- left: -100%;
-}
-.carousel .next.left,
-.carousel .prev.right {
- left: 0;
-}
-.carousel .active.left {
- left: -100%;
-}
-.carousel .active.right {
- left: 100%;
-}
-.carousel-control {
- position: absolute;
- top: 40%;
- left: 15px;
- width: 40px;
- height: 40px;
- margin-top: -20px;
- font-size: 60px;
- font-weight: 100;
- line-height: 30px;
- color: #ffffff;
- text-align: center;
- background: #222222;
- border: 3px solid #ffffff;
- -webkit-border-radius: 23px;
- -moz-border-radius: 23px;
- border-radius: 23px;
- opacity: 0.5;
- filter: alpha(opacity=50);
-}
-.carousel-control.right {
- left: auto;
- right: 15px;
-}
-.carousel-control:hover {
- color: #ffffff;
- text-decoration: none;
- opacity: 0.9;
- filter: alpha(opacity=90);
-}
-.carousel-caption {
- position: absolute;
- left: 0;
- right: 0;
- bottom: 0;
- padding: 10px 15px 5px;
- background: #333333;
- background: rgba(0, 0, 0, 0.75);
-}
-.carousel-caption h4,
-.carousel-caption p {
- color: #ffffff;
-}
-.well {
- min-height: 20px;
- padding: 19px;
- margin-bottom: 20px;
- background-color: #f5f5f5;
- border: 1px solid #eee;
- border: 1px solid rgba(0, 0, 0, 0.05);
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05);
-}
-.well blockquote {
- border-color: #ddd;
- border-color: rgba(0, 0, 0, 0.15);
-}
-.well-large {
- padding: 24px;
- -webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- border-radius: 6px;
-}
-.well-small {
- padding: 9px;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
-}
-.close {
- float: right;
- font-size: 20px;
- font-weight: bold;
- line-height: 18px;
- color: #000000;
- text-shadow: 0 1px 0 #ffffff;
- opacity: 0.2;
- filter: alpha(opacity=20);
-}
-.close:hover {
- color: #000000;
- text-decoration: none;
- opacity: 0.4;
- filter: alpha(opacity=40);
- cursor: pointer;
-}
-.pull-right {
- float: right;
-}
-.pull-left {
- float: left;
-}
-.hide {
- display: none;
-}
-.show {
- display: block;
-}
-.invisible {
- visibility: hidden;
-}
-.fade {
- -webkit-transition: opacity 0.15s linear;
- -moz-transition: opacity 0.15s linear;
- -ms-transition: opacity 0.15s linear;
- -o-transition: opacity 0.15s linear;
- transition: opacity 0.15s linear;
- opacity: 0;
-}
-.fade.in {
- opacity: 1;
-}
-.collapse {
- -webkit-transition: height 0.35s ease;
- -moz-transition: height 0.35s ease;
- -ms-transition: height 0.35s ease;
- -o-transition: height 0.35s ease;
- transition: height 0.35s ease;
- position: relative;
- overflow: hidden;
- height: 0;
-}
-.collapse.in {
- height: auto;
-}
-/*!
- * Bootstrap Responsive v2.0.2
- *
- * Copyright 2012 Twitter, Inc
- * Licensed under the Apache License v2.0
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Designed and built with all the love in the world @twitter by @mdo and @fat.
- */
-.hidden {
- display: none;
- visibility: hidden;
-}
-.visible-phone {
- display: none;
-}
-.visible-tablet {
- display: none;
-}
-.visible-desktop {
- display: block;
-}
-.hidden-phone {
- display: block;
-}
-.hidden-tablet {
- display: block;
-}
-.hidden-desktop {
- display: none;
-}
-@media (max-width: 767px) {
- .visible-phone {
- display: block;
- }
- .hidden-phone {
- display: none;
- }
- .hidden-desktop {
- display: block;
- }
- .visible-desktop {
- display: none;
- }
-}
-@media (min-width: 768px) and (max-width: 979px) {
- .visible-tablet {
- display: block;
- }
- .hidden-tablet {
- display: none;
- }
- .hidden-desktop {
- display: block;
- }
- .visible-desktop {
- display: none;
- }
-}
-@media (max-width: 480px) {
- .nav-collapse {
- -webkit-transform: translate3d(0, 0, 0);
- }
- .page-header h1 small {
- display: block;
- line-height: 18px;
- }
- input[type="checkbox"],
- input[type="radio"] {
- border: 1px solid #ccc;
- }
- .form-horizontal .control-group > label {
- float: none;
- width: auto;
- padding-top: 0;
- text-align: left;
- }
- .form-horizontal .controls {
- margin-left: 0;
- }
- .form-horizontal .control-list {
- padding-top: 0;
- }
- .form-horizontal .form-actions {
- padding-left: 10px;
- padding-right: 10px;
- }
- .modal {
- position: absolute;
- top: 10px;
- left: 10px;
- right: 10px;
- width: auto;
- margin: 0;
- }
- .modal.fade.in {
- top: auto;
- }
- .modal-header .close {
- padding: 10px;
- margin: -10px;
- }
- .carousel-caption {
- position: static;
- }
-}
-@media (max-width: 767px) {
- body {
- padding-left: 20px;
- padding-right: 20px;
- }
- .navbar-fixed-top {
- margin-left: -20px;
- margin-right: -20px;
- }
- .container {
- width: auto;
- }
- .row-fluid {
- width: 100%;
- }
- .row {
- margin-left: 0;
- }
- .row > [class*="span"],
- .row-fluid > [class*="span"] {
- float: none;
- display: block;
- width: auto;
- margin: 0;
- }
- .thumbnails [class*="span"] {
- width: auto;
- }
- input[class*="span"],
- select[class*="span"],
- textarea[class*="span"],
- .uneditable-input {
- display: block;
- width: 100%;
- min-height: 28px;
- /* Make inputs at least the height of their button counterpart */
-
- /* Makes inputs behave like true block-level elements */
-
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- -ms-box-sizing: border-box;
- box-sizing: border-box;
- }
- .input-prepend input[class*="span"],
- .input-append input[class*="span"] {
- width: auto;
- }
-}
-@media (min-width: 768px) and (max-width: 979px) {
- .row {
- margin-left: -20px;
- *zoom: 1;
- }
- .row:before,
- .row:after {
- display: table;
- content: "";
- }
- .row:after {
- clear: both;
- }
- [class*="span"] {
- float: left;
- margin-left: 20px;
- }
- .container,
- .navbar-fixed-top .container,
- .navbar-fixed-bottom .container {
- width: 724px;
- }
- .span12 {
- width: 724px;
- }
- .span11 {
- width: 662px;
- }
- .span10 {
- width: 600px;
- }
- .span9 {
- width: 538px;
- }
- .span8 {
- width: 476px;
- }
- .span7 {
- width: 414px;
- }
- .span6 {
- width: 352px;
- }
- .span5 {
- width: 290px;
- }
- .span4 {
- width: 228px;
- }
- .span3 {
- width: 166px;
- }
- .span2 {
- width: 104px;
- }
- .span1 {
- width: 42px;
- }
- .offset12 {
- margin-left: 764px;
- }
- .offset11 {
- margin-left: 702px;
- }
- .offset10 {
- margin-left: 640px;
- }
- .offset9 {
- margin-left: 578px;
- }
- .offset8 {
- margin-left: 516px;
- }
- .offset7 {
- margin-left: 454px;
- }
- .offset6 {
- margin-left: 392px;
- }
- .offset5 {
- margin-left: 330px;
- }
- .offset4 {
- margin-left: 268px;
- }
- .offset3 {
- margin-left: 206px;
- }
- .offset2 {
- margin-left: 144px;
- }
- .offset1 {
- margin-left: 82px;
- }
- .row-fluid {
- width: 100%;
- *zoom: 1;
- }
- .row-fluid:before,
- .row-fluid:after {
- display: table;
- content: "";
- }
- .row-fluid:after {
- clear: both;
- }
- .row-fluid > [class*="span"] {
- float: left;
- margin-left: 2.762430939%;
- }
- .row-fluid > [class*="span"]:first-child {
- margin-left: 0;
- }
- .row-fluid > .span12 {
- width: 99.999999993%;
- }
- .row-fluid > .span11 {
- width: 91.436464082%;
- }
- .row-fluid > .span10 {
- width: 82.87292817100001%;
- }
- .row-fluid > .span9 {
- width: 74.30939226%;
- }
- .row-fluid > .span8 {
- width: 65.74585634900001%;
- }
- .row-fluid > .span7 {
- width: 57.182320438000005%;
- }
- .row-fluid > .span6 {
- width: 48.618784527%;
- }
- .row-fluid > .span5 {
- width: 40.055248616%;
- }
- .row-fluid > .span4 {
- width: 31.491712705%;
- }
- .row-fluid > .span3 {
- width: 22.928176794%;
- }
- .row-fluid > .span2 {
- width: 14.364640883%;
- }
- .row-fluid > .span1 {
- width: 5.801104972%;
- }
- input,
- textarea,
- .uneditable-input {
- margin-left: 0;
- }
- input.span12, textarea.span12, .uneditable-input.span12 {
- width: 714px;
- }
- input.span11, textarea.span11, .uneditable-input.span11 {
- width: 652px;
- }
- input.span10, textarea.span10, .uneditable-input.span10 {
- width: 590px;
- }
- input.span9, textarea.span9, .uneditable-input.span9 {
- width: 528px;
- }
- input.span8, textarea.span8, .uneditable-input.span8 {
- width: 466px;
- }
- input.span7, textarea.span7, .uneditable-input.span7 {
- width: 404px;
- }
- input.span6, textarea.span6, .uneditable-input.span6 {
- width: 342px;
- }
- input.span5, textarea.span5, .uneditable-input.span5 {
- width: 280px;
- }
- input.span4, textarea.span4, .uneditable-input.span4 {
- width: 218px;
- }
- input.span3, textarea.span3, .uneditable-input.span3 {
- width: 156px;
- }
- input.span2, textarea.span2, .uneditable-input.span2 {
- width: 94px;
- }
- input.span1, textarea.span1, .uneditable-input.span1 {
- width: 32px;
- }
-}
-@media (max-width: 979px) {
- body {
- padding-top: 0;
- }
- .navbar-fixed-top {
- position: static;
- margin-bottom: 18px;
- }
- .navbar-fixed-top .navbar-inner {
- padding: 5px;
- }
- .navbar .container {
- width: auto;
- padding: 0;
- }
- .navbar .brand {
- padding-left: 10px;
- padding-right: 10px;
- margin: 0 0 0 -5px;
- }
- .navbar .nav-collapse {
- clear: left;
- }
- .navbar .nav {
- float: none;
- margin: 0 0 9px;
- }
- .navbar .nav > li {
- float: none;
- }
- .navbar .nav > li > a {
- margin-bottom: 2px;
- }
- .navbar .nav > .divider-vertical {
- display: none;
- }
- .navbar .nav .nav-header {
- color: #999999;
- text-shadow: none;
- }
- .navbar .nav > li > a,
- .navbar .dropdown-menu a {
- padding: 6px 15px;
- font-weight: bold;
- color: #999999;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
- }
- .navbar .dropdown-menu li + li a {
- margin-bottom: 2px;
- }
- .navbar .nav > li > a:hover,
- .navbar .dropdown-menu a:hover {
- background-color: #222222;
- }
- .navbar .dropdown-menu {
- position: static;
- top: auto;
- left: auto;
- float: none;
- display: block;
- max-width: none;
- margin: 0 15px;
- padding: 0;
- background-color: transparent;
- border: none;
- -webkit-border-radius: 0;
- -moz-border-radius: 0;
- border-radius: 0;
- -webkit-box-shadow: none;
- -moz-box-shadow: none;
- box-shadow: none;
- }
- .navbar .dropdown-menu:before,
- .navbar .dropdown-menu:after {
- display: none;
- }
- .navbar .dropdown-menu .divider {
- display: none;
- }
- .navbar-form,
- .navbar-search {
- float: none;
- padding: 9px 15px;
- margin: 9px 0;
- border-top: 1px solid #222222;
- border-bottom: 1px solid #222222;
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
- }
- .navbar .nav.pull-right {
- float: none;
- margin-left: 0;
- }
- .navbar-static .navbar-inner {
- padding-left: 10px;
- padding-right: 10px;
- }
- .btn-navbar {
- display: block;
- }
- .nav-collapse {
- overflow: hidden;
- height: 0;
- }
-}
-@media (min-width: 980px) {
- .nav-collapse.collapse {
- height: auto !important;
- overflow: visible !important;
- }
-}
-@media (min-width: 1200px) {
- .row {
- margin-left: -30px;
- *zoom: 1;
- }
- .row:before,
- .row:after {
- display: table;
- content: "";
- }
- .row:after {
- clear: both;
- }
- [class*="span"] {
- float: left;
- margin-left: 30px;
- }
- .container,
- .navbar-fixed-top .container,
- .navbar-fixed-bottom .container {
- width: 1170px;
- }
- .span12 {
- width: 1170px;
- }
- .span11 {
- width: 1070px;
- }
- .span10 {
- width: 970px;
- }
- .span9 {
- width: 870px;
- }
- .span8 {
- width: 770px;
- }
- .span7 {
- width: 670px;
- }
- .span6 {
- width: 570px;
- }
- .span5 {
- width: 470px;
- }
- .span4 {
- width: 370px;
- }
- .span3 {
- width: 270px;
- }
- .span2 {
- width: 170px;
- }
- .span1 {
- width: 70px;
- }
- .offset12 {
- margin-left: 1230px;
- }
- .offset11 {
- margin-left: 1130px;
- }
- .offset10 {
- margin-left: 1030px;
- }
- .offset9 {
- margin-left: 930px;
- }
- .offset8 {
- margin-left: 830px;
- }
- .offset7 {
- margin-left: 730px;
- }
- .offset6 {
- margin-left: 630px;
- }
- .offset5 {
- margin-left: 530px;
- }
- .offset4 {
- margin-left: 430px;
- }
- .offset3 {
- margin-left: 330px;
- }
- .offset2 {
- margin-left: 230px;
- }
- .offset1 {
- margin-left: 130px;
- }
- .row-fluid {
- width: 100%;
- *zoom: 1;
- }
- .row-fluid:before,
- .row-fluid:after {
- display: table;
- content: "";
- }
- .row-fluid:after {
- clear: both;
- }
- .row-fluid > [class*="span"] {
- float: left;
- margin-left: 2.564102564%;
- }
- .row-fluid > [class*="span"]:first-child {
- margin-left: 0;
- }
- .row-fluid > .span12 {
- width: 100%;
- }
- .row-fluid > .span11 {
- width: 91.45299145300001%;
- }
- .row-fluid > .span10 {
- width: 82.905982906%;
- }
- .row-fluid > .span9 {
- width: 74.358974359%;
- }
- .row-fluid > .span8 {
- width: 65.81196581200001%;
- }
- .row-fluid > .span7 {
- width: 57.264957265%;
- }
- .row-fluid > .span6 {
- width: 48.717948718%;
- }
- .row-fluid > .span5 {
- width: 40.170940171000005%;
- }
- .row-fluid > .span4 {
- width: 31.623931624%;
- }
- .row-fluid > .span3 {
- width: 23.076923077%;
- }
- .row-fluid > .span2 {
- width: 14.529914530000001%;
- }
- .row-fluid > .span1 {
- width: 5.982905983%;
- }
- input,
- textarea,
- .uneditable-input {
- margin-left: 0;
- }
- input.span12, textarea.span12, .uneditable-input.span12 {
- width: 1160px;
- }
- input.span11, textarea.span11, .uneditable-input.span11 {
- width: 1060px;
- }
- input.span10, textarea.span10, .uneditable-input.span10 {
- width: 960px;
- }
- input.span9, textarea.span9, .uneditable-input.span9 {
- width: 860px;
- }
- input.span8, textarea.span8, .uneditable-input.span8 {
- width: 760px;
- }
- input.span7, textarea.span7, .uneditable-input.span7 {
- width: 660px;
- }
- input.span6, textarea.span6, .uneditable-input.span6 {
- width: 560px;
- }
- input.span5, textarea.span5, .uneditable-input.span5 {
- width: 460px;
- }
- input.span4, textarea.span4, .uneditable-input.span4 {
- width: 360px;
- }
- input.span3, textarea.span3, .uneditable-input.span3 {
- width: 260px;
- }
- input.span2, textarea.span2, .uneditable-input.span2 {
- width: 160px;
- }
- input.span1, textarea.span1, .uneditable-input.span1 {
- width: 60px;
- }
- .thumbnails {
- margin-left: -30px;
- }
- .thumbnails > li {
- margin-left: 30px;
- }
-}
diff --git a/askbot/skins/default/media/images/anon.png b/askbot/skins/default/media/images/anon.png
deleted file mode 100644
index a2041590..00000000
--- a/askbot/skins/default/media/images/anon.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/bigbutton.png b/askbot/skins/default/media/images/bigbutton.png
deleted file mode 100644
index 2a7c0f05..00000000
--- a/askbot/skins/default/media/images/bigbutton.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/bigbuttonhover.png b/askbot/skins/default/media/images/bigbuttonhover.png
deleted file mode 100644
index cf4bacca..00000000
--- a/askbot/skins/default/media/images/bigbuttonhover.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/blue-up-arrow-h18px.png b/askbot/skins/default/media/images/blue-up-arrow-h18px.png
deleted file mode 100755
index e1f29e86..00000000
--- a/askbot/skins/default/media/images/blue-up-arrow-h18px.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/box-arrow.gif b/askbot/skins/default/media/images/box-arrow.gif
deleted file mode 100755
index 89dcf5b3..00000000
--- a/askbot/skins/default/media/images/box-arrow.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/bullet_green.gif b/askbot/skins/default/media/images/bullet_green.gif
deleted file mode 100755
index fa530910..00000000
--- a/askbot/skins/default/media/images/bullet_green.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/cc-88x31.png b/askbot/skins/default/media/images/cc-88x31.png
deleted file mode 100755
index 0f2a0f10..00000000
--- a/askbot/skins/default/media/images/cc-88x31.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/cc-by-sa.png b/askbot/skins/default/media/images/cc-by-sa.png
deleted file mode 100644
index f0a944e0..00000000
--- a/askbot/skins/default/media/images/cc-by-sa.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/close-small-hover.png b/askbot/skins/default/media/images/close-small-hover.png
deleted file mode 100755
index 7899aec7..00000000
--- a/askbot/skins/default/media/images/close-small-hover.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/close-small.png b/askbot/skins/default/media/images/close-small.png
deleted file mode 100755
index 5a99d31f..00000000
--- a/askbot/skins/default/media/images/close-small.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/contributorsback.png b/askbot/skins/default/media/images/contributorsback.png
deleted file mode 100644
index dd728383..00000000
--- a/askbot/skins/default/media/images/contributorsback.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/dash.gif b/askbot/skins/default/media/images/dash.gif
deleted file mode 100755
index d1ddc507..00000000
--- a/askbot/skins/default/media/images/dash.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/dialog-warning-off.png b/askbot/skins/default/media/images/dialog-warning-off.png
deleted file mode 100644
index 258e4d86..00000000
--- a/askbot/skins/default/media/images/dialog-warning-off.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/dialog-warning.png b/askbot/skins/default/media/images/dialog-warning.png
deleted file mode 100644
index a9e4ff39..00000000
--- a/askbot/skins/default/media/images/dialog-warning.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/djangomade124x25_grey.gif b/askbot/skins/default/media/images/djangomade124x25_grey.gif
deleted file mode 100755
index d34bb311..00000000
--- a/askbot/skins/default/media/images/djangomade124x25_grey.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/dot-g.gif b/askbot/skins/default/media/images/dot-g.gif
deleted file mode 100755
index 5d6bb28e..00000000
--- a/askbot/skins/default/media/images/dot-g.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/dot-list.gif b/askbot/skins/default/media/images/dot-list.gif
deleted file mode 100755
index f6a6b865..00000000
--- a/askbot/skins/default/media/images/dot-list.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/edit.png b/askbot/skins/default/media/images/edit.png
deleted file mode 100755
index dcb09be0..00000000
--- a/askbot/skins/default/media/images/edit.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/expander-arrow-hide.gif b/askbot/skins/default/media/images/expander-arrow-hide.gif
deleted file mode 100755
index feb6a618..00000000
--- a/askbot/skins/default/media/images/expander-arrow-hide.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/expander-arrow-show.gif b/askbot/skins/default/media/images/expander-arrow-show.gif
deleted file mode 100755
index 6825c56e..00000000
--- a/askbot/skins/default/media/images/expander-arrow-show.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/favicon.gif b/askbot/skins/default/media/images/favicon.gif
deleted file mode 100644
index f7f9061b..00000000
--- a/askbot/skins/default/media/images/favicon.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/favicon.ico b/askbot/skins/default/media/images/favicon.ico
deleted file mode 100644
index 51a57bed..00000000
--- a/askbot/skins/default/media/images/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/feed-icon-small.png b/askbot/skins/default/media/images/feed-icon-small.png
deleted file mode 100644
index 2794b0f5..00000000
--- a/askbot/skins/default/media/images/feed-icon-small.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/go-up-grey.png b/askbot/skins/default/media/images/go-up-grey.png
deleted file mode 100644
index 763bb799..00000000
--- a/askbot/skins/default/media/images/go-up-grey.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/go-up-orange.png b/askbot/skins/default/media/images/go-up-orange.png
deleted file mode 100644
index eca3579d..00000000
--- a/askbot/skins/default/media/images/go-up-orange.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/gray-up-arrow-h18px.png b/askbot/skins/default/media/images/gray-up-arrow-h18px.png
deleted file mode 100755
index 78767445..00000000
--- a/askbot/skins/default/media/images/gray-up-arrow-h18px.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/grippie.png b/askbot/skins/default/media/images/grippie.png
deleted file mode 100755
index 6524d416..00000000
--- a/askbot/skins/default/media/images/grippie.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/indicator.gif b/askbot/skins/default/media/images/indicator.gif
deleted file mode 100755
index 1c72ebb5..00000000
--- a/askbot/skins/default/media/images/indicator.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/logo.png b/askbot/skins/default/media/images/logo.png
deleted file mode 100644
index 10559161..00000000
--- a/askbot/skins/default/media/images/logo.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/logo1.png b/askbot/skins/default/media/images/logo1.png
deleted file mode 100755
index d79a6271..00000000
--- a/askbot/skins/default/media/images/logo1.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/logo2.png b/askbot/skins/default/media/images/logo2.png
deleted file mode 100755
index bd3cccd9..00000000
--- a/askbot/skins/default/media/images/logo2.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/mail-envelope-empty.png b/askbot/skins/default/media/images/mail-envelope-empty.png
deleted file mode 100644
index 0fde87dc..00000000
--- a/askbot/skins/default/media/images/mail-envelope-empty.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/mail-envelope-full.png b/askbot/skins/default/media/images/mail-envelope-full.png
deleted file mode 100644
index 2277e919..00000000
--- a/askbot/skins/default/media/images/mail-envelope-full.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/medala.gif b/askbot/skins/default/media/images/medala.gif
deleted file mode 100755
index 93dd1a39..00000000
--- a/askbot/skins/default/media/images/medala.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/medala_on.gif b/askbot/skins/default/media/images/medala_on.gif
deleted file mode 100755
index a18f9e85..00000000
--- a/askbot/skins/default/media/images/medala_on.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/new.gif b/askbot/skins/default/media/images/new.gif
deleted file mode 100755
index 8a220b53..00000000
--- a/askbot/skins/default/media/images/new.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/nophoto.png b/askbot/skins/default/media/images/nophoto.png
deleted file mode 100755
index 2daf0ffd..00000000
--- a/askbot/skins/default/media/images/nophoto.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/openid.gif b/askbot/skins/default/media/images/openid.gif
deleted file mode 100755
index 8540e12b..00000000
--- a/askbot/skins/default/media/images/openid.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/print.png b/askbot/skins/default/media/images/print.png
deleted file mode 100644
index 37bf88af..00000000
--- a/askbot/skins/default/media/images/print.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/pw-login.gif b/askbot/skins/default/media/images/pw-login.gif
deleted file mode 100644
index f88b1bcf..00000000
--- a/askbot/skins/default/media/images/pw-login.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/quest-bg.gif b/askbot/skins/default/media/images/quest-bg.gif
deleted file mode 100755
index b7540238..00000000
--- a/askbot/skins/default/media/images/quest-bg.gif
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/scopearrow.png b/askbot/skins/default/media/images/scopearrow.png
deleted file mode 100644
index 73dc6744..00000000
--- a/askbot/skins/default/media/images/scopearrow.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/sprite.png b/askbot/skins/default/media/images/sprite.png
deleted file mode 100644
index 1a0fbc78..00000000
--- a/askbot/skins/default/media/images/sprite.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/sprites.png b/askbot/skins/default/media/images/sprites.png
deleted file mode 100644
index 8c513508..00000000
--- a/askbot/skins/default/media/images/sprites.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/sprites_source/sprites.svg b/askbot/skins/default/media/images/sprites_source/sprites.svg
deleted file mode 100644
index 585e578f..00000000
--- a/askbot/skins/default/media/images/sprites_source/sprites.svg
+++ /dev/null
@@ -1,507 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="600"
- height="207"
- id="svg3448"
- version="1.1"
- inkscape:version="0.48.1 r9760"
- sodipodi:docname="sprites.svg"
- inkscape:export-filename="/home/bcorrales/personal/askbot/sprites.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90">
- <defs
- id="defs3450">
- <linearGradient
- inkscape:collect="always"
- id="linearGradient3819">
- <stop
- style="stop-color:#000000;stop-opacity:1"
- offset="0"
- id="stop3821" />
- <stop
- style="stop-color:#deded0;stop-opacity:0;"
- offset="1"
- id="stop3823" />
- </linearGradient>
- <linearGradient
- inkscape:collect="always"
- id="linearGradient3029">
- <stop
- style="stop-color:#525252;stop-opacity:1"
- offset="0"
- id="stop3031" />
- <stop
- style="stop-color:#020202;stop-opacity:1"
- offset="1"
- id="stop3033" />
- </linearGradient>
- <radialGradient
- r="11.136931"
- fy="161.02299"
- fx="222.6344"
- cy="161.02299"
- cx="222.6344"
- gradientTransform="matrix(0.25937215,-1.0764281,1.4011863,0.30094439,-58.042568,347.29527)"
- gradientUnits="userSpaceOnUse"
- id="radialGradient3838-8"
- xlink:href="#linearGradient3865-1"
- inkscape:collect="always" />
- <linearGradient
- id="linearGradient3865-1"
- inkscape:collect="always">
- <stop
- id="stop3867-7"
- offset="0"
- style="stop-color:#0975cf;stop-opacity:1" />
- <stop
- id="stop3869-7"
- offset="1"
- style="stop-color:#14b3de;stop-opacity:0" />
- </linearGradient>
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3824-7"
- id="radialGradient3822-9"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(0.58002994,0.69397701,-0.72276743,0.59013931,3613.278,1050.6132)"
- cx="-2600.8416"
- cy="2819.7468"
- fx="-2600.8416"
- fy="2819.7468"
- r="16.18819" />
- <linearGradient
- id="linearGradient3824-7"
- inkscape:collect="always">
- <stop
- id="stop3826-9"
- offset="0"
- style="stop-color:#9f9f8d;stop-opacity:1" />
- <stop
- id="stop3828-8"
- offset="1"
- style="stop-color:#44443a;stop-opacity:1" />
- </linearGradient>
- <radialGradient
- r="16.18819"
- fy="2819.7468"
- fx="-2600.8416"
- cy="2819.7468"
- cx="-2600.8416"
- gradientTransform="matrix(0.58002994,0.69397701,-0.72276743,0.59013931,3568.2975,1050.6132)"
- gradientUnits="userSpaceOnUse"
- id="radialGradient5712-8"
- xlink:href="#linearGradient5675-9"
- inkscape:collect="always" />
- <linearGradient
- inkscape:collect="always"
- id="linearGradient5675-9">
- <stop
- style="stop-color:#9f9f8d;stop-opacity:1"
- offset="0"
- id="stop5677-8" />
- <stop
- style="stop-color:#757563;stop-opacity:1"
- offset="1"
- id="stop5679-0" />
- </linearGradient>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient7944-2"
- id="linearGradient6226-5"
- gradientUnits="userSpaceOnUse"
- x1="-1656.4215"
- y1="3870.6523"
- x2="-1656.4216"
- y2="3887.7998" />
- <linearGradient
- inkscape:collect="always"
- id="linearGradient7944-2">
- <stop
- style="stop-color:#ffffff;stop-opacity:1;"
- offset="0"
- id="stop7946-0" />
- <stop
- style="stop-color:#e4e4e4;stop-opacity:1"
- offset="1"
- id="stop7948-2" />
- </linearGradient>
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient7944-2"
- id="linearGradient6228-4"
- gradientUnits="userSpaceOnUse"
- x1="-1656.4215"
- y1="3870.6523"
- x2="-1656.4216"
- y2="3887.7998" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient7944-2"
- id="linearGradient7950-3"
- x1="-1656.4215"
- y1="3870.6523"
- x2="-1656.4216"
- y2="3887.7998"
- gradientUnits="userSpaceOnUse" />
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3029"
- id="radialGradient3037"
- cx="107.38955"
- cy="37.76292"
- fx="107.38955"
- fy="37.76292"
- r="10.875"
- gradientTransform="matrix(1.8448978,1.1954022,-0.56343271,0.76622296,-66.658636,-116.22519)"
- gradientUnits="userSpaceOnUse" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3819"
- id="linearGradient3825"
- x1="112.05391"
- y1="29.484962"
- x2="113.33555"
- y2="54.66436"
- gradientUnits="userSpaceOnUse" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3819"
- id="linearGradient3832"
- gradientUnits="userSpaceOnUse"
- x1="112.05391"
- y1="29.484962"
- x2="113.33555"
- y2="54.66436" />
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3029"
- id="radialGradient3834"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(1.8448978,1.1954022,-0.56343271,0.76622296,-66.658636,-116.22519)"
- cx="107.38955"
- cy="37.76292"
- fx="107.38955"
- fy="37.76292"
- r="10.875" />
- <linearGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3819"
- id="linearGradient3846"
- gradientUnits="userSpaceOnUse"
- x1="112.05391"
- y1="29.484962"
- x2="113.33555"
- y2="54.66436" />
- <radialGradient
- inkscape:collect="always"
- xlink:href="#linearGradient3029"
- id="radialGradient3848"
- gradientUnits="userSpaceOnUse"
- gradientTransform="matrix(1.8448978,1.1954022,-0.56343271,0.76622296,-66.658636,-116.22519)"
- cx="107.38955"
- cy="37.76292"
- fx="107.38955"
- fy="37.76292"
- r="10.875" />
- </defs>
- <sodipodi:namedview
- id="base"
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0.0"
- inkscape:pageshadow="2"
- inkscape:zoom="1"
- inkscape:cx="-14.220783"
- inkscape:cy="199.46611"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- inkscape:window-width="1316"
- inkscape:window-height="744"
- inkscape:window-x="50"
- inkscape:window-y="24"
- inkscape:window-maximized="1" />
- <metadata
- id="metadata3453">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Capa 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(0,-845.36218)">
- <path
- transform="matrix(1.0191083,0,0,0.98765432,1704.4089,-2965.0039)"
- d="m -1647,3873.8623 c 0,5.2467 -4.2533,9.5 -9.5,9.5 -5.2467,0 -9.5,-4.2533 -9.5,-9.5 0,-5.2467 4.2533,-9.5 9.5,-9.5 5.2467,0 9.5,4.2533 9.5,9.5 z"
- sodipodi:ry="9.5"
- sodipodi:rx="9.5"
- sodipodi:cy="3873.8623"
- sodipodi:cx="-1656.5"
- id="path7928"
- style="fill:#c9a90d;fill-opacity:1;stroke:none"
- sodipodi:type="arc" />
- <path
- sodipodi:type="arc"
- style="fill:url(#linearGradient7950-3);fill-opacity:1;stroke:none"
- id="path7922"
- sodipodi:cx="-1656.5"
- sodipodi:cy="3873.8623"
- sodipodi:rx="9.5"
- sodipodi:ry="9.5"
- d="m -1647,3873.8623 c 0,5.2467 -4.2533,9.5 -9.5,9.5 -5.2467,0 -9.5,-4.2533 -9.5,-9.5 0,-5.2467 4.2533,-9.5 9.5,-9.5 5.2467,0 9.5,4.2533 9.5,9.5 z"
- transform="matrix(1.0191083,0,0,0.98765432,1703.772,-2966.2384)" />
- <text
- transform="scale(1.1035306,0.9061824)"
- xml:space="preserve"
- style="font-size:19.10287285px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#b96161;fill-opacity:1;stroke:none;font-family:Arial Rounded MT Bold;-inkscape-font-specification:Arial Rounded MT Bold"
- x="10.035251"
- y="953.7583"
- id="text7924"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan7926"
- x="10.035251"
- y="953.7583"
- style="font-size:14.30124187px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#b96161;fill-opacity:1;font-family:Trebuchet MS;-inkscape-font-specification:Trebuchet MS">X</tspan></text>
- <path
- sodipodi:type="arc"
- style="fill:#c9a90d;fill-opacity:1;stroke:none"
- id="path6208"
- sodipodi:cx="-1656.5"
- sodipodi:cy="3873.8623"
- sodipodi:rx="9.5"
- sodipodi:ry="9.5"
- d="m -1647,3873.8623 c 0,5.2467 -4.2533,9.5 -9.5,9.5 -5.2467,0 -9.5,-4.2533 -9.5,-9.5 0,-5.2467 4.2533,-9.5 9.5,-9.5 5.2467,0 9.5,4.2533 9.5,9.5 z"
- transform="matrix(1.0191083,0,0,0.98765432,1704.4089,-2965.0039)" />
- <path
- transform="matrix(1.0191083,0,0,0.98765432,1703.772,-2966.2384)"
- d="m -1647,3873.8623 c 0,5.2467 -4.2533,9.5 -9.5,9.5 -5.2467,0 -9.5,-4.2533 -9.5,-9.5 0,-5.2467 4.2533,-9.5 9.5,-9.5 5.2467,0 9.5,4.2533 9.5,9.5 z"
- sodipodi:ry="9.5"
- sodipodi:rx="9.5"
- sodipodi:cy="3873.8623"
- sodipodi:cx="-1656.5"
- id="path6210"
- style="fill:url(#linearGradient6228-4);fill-opacity:1;stroke:none"
- sodipodi:type="arc" />
- <text
- sodipodi:linespacing="125%"
- id="text6212"
- y="953.7583"
- x="10.035251"
- style="font-size:19.10287285px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#b96161;fill-opacity:1;stroke:none;font-family:Arial Rounded MT Bold;-inkscape-font-specification:Arial Rounded MT Bold"
- xml:space="preserve"
- transform="scale(1.1035306,0.9061824)"><tspan
- style="font-size:14.30124187px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#b96161;fill-opacity:1;font-family:Trebuchet MS;-inkscape-font-specification:Trebuchet MS"
- y="953.7583"
- x="10.035251"
- id="tspan6214"
- sodipodi:role="line">X</tspan></text>
- <path
- transform="matrix(1.0191083,0,0,0.98765432,1724.4089,-2965.0039)"
- d="m -1647,3873.8623 c 0,5.2467 -4.2533,9.5 -9.5,9.5 -5.2467,0 -9.5,-4.2533 -9.5,-9.5 0,-5.2467 4.2533,-9.5 9.5,-9.5 5.2467,0 9.5,4.2533 9.5,9.5 z"
- sodipodi:ry="9.5"
- sodipodi:rx="9.5"
- sodipodi:cy="3873.8623"
- sodipodi:cx="-1656.5"
- id="path6218"
- style="fill:#c9a90d;fill-opacity:1;stroke:none"
- sodipodi:type="arc" />
- <path
- sodipodi:type="arc"
- style="fill:url(#linearGradient6226-5);fill-opacity:1;stroke:none"
- id="path6220"
- sodipodi:cx="-1656.5"
- sodipodi:cy="3873.8623"
- sodipodi:rx="9.5"
- sodipodi:ry="9.5"
- d="m -1647,3873.8623 c 0,5.2467 -4.2533,9.5 -9.5,9.5 -5.2467,0 -9.5,-4.2533 -9.5,-9.5 0,-5.2467 4.2533,-9.5 9.5,-9.5 5.2467,0 9.5,4.2533 9.5,9.5 z"
- transform="matrix(1.0191083,0,0,0.98765432,1723.772,-2966.2384)" />
- <text
- transform="scale(1.1035306,0.9061824)"
- xml:space="preserve"
- style="font-size:19.10287285px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#e90f0f;fill-opacity:1;stroke:none;font-family:Arial Rounded MT Bold;-inkscape-font-specification:Arial Rounded MT Bold"
- x="28.158876"
- y="953.7583"
- id="text6222"
- sodipodi:linespacing="125%"><tspan
- sodipodi:role="line"
- id="tspan6224"
- x="28.158876"
- y="953.7583"
- style="font-size:14.30124187px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#e90f0f;fill-opacity:1;font-family:Trebuchet MS;-inkscape-font-specification:Trebuchet MS">X</tspan></text>
- <path
- inkscape:export-ydpi="90"
- inkscape:export-xdpi="90"
- inkscape:export-filename="/home/bcorrales/personal/oxfam/arte/disenoindex.png"
- id="path5443"
- d="m 60.268935,856.20911 c -1.0424,-0.85947 -2.66478,-0.61037 -3.61221,0.54899 -0.95263,1.15795 -0.86987,2.79882 0.17873,3.65569 1.0444,0.86116 2.66667,0.61206 3.61631,-0.54959 0.94503,-1.16205 0.86746,-2.79822 -0.17854,-3.65559 z m 5.88263,18.6866 -12.99549,-10.63781 c -0.44703,-0.36346 -0.64755,-0.93014 -0.58638,-1.50242 -0.05,-0.11386 -0.087,-0.2505 -0.10985,-0.41064 l -1.33739,-8.83579 c -0.14424,-0.94964 0.5206,-1.76262 1.48163,-1.8085 l 8.91926,-0.44173 c 0.38495,-0.019 1.49952,0.35486 1.78501,0.58457 l 12.99449,10.6375 c 0.74232,0.60366 0.7989,1.77001 0.12665,2.5924 l -7.71322,9.43427 c -0.66824,0.82178 -1.8207,0.99492 -2.56061,0.38925 z"
- clip-rule="evenodd"
- style="fill:#e7e8a8;fill-opacity:1;fill-rule:evenodd;stroke:none"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- style="fill:#16160f;fill-opacity:1;fill-rule:evenodd"
- clip-rule="evenodd"
- d="m 60.685375,857.34507 c -0.92055,-0.75811 -2.28652,-0.61896 -3.04183,0.30448 -0.75951,0.92235 -0.62036,2.28942 0.30498,3.04553 0.92224,0.7595 2.28822,0.62046 3.04513,-0.30508 0.75321,-0.92595 0.61866,-2.28902 -0.30479,-3.04533 z m 5.77547,15.77522 -11.47288,-9.38529 c -0.39445,-0.32067 -0.58837,-0.79999 -0.56038,-1.27301 -0.047,-0.097 -0.084,-0.21191 -0.11056,-0.34586 l -1.50572,-7.39855 c -0.16224,-0.79519 0.36786,-1.44284 1.18105,-1.44084 l 7.54948,0.01 c 0.32578,4e-4 1.28701,0.35796 1.53911,0.56048 l 11.47158,9.38508 c 0.65525,0.53279 0.75211,1.50442 0.21612,2.15966 l -6.14833,7.51602 c -0.5325,0.65474 -1.50312,0.75031 -2.15627,0.21591 z"
- id="path5445"
- inkscape:export-filename="/home/bcorrales/personal/oxfam/arte/disenoindex.png"
- inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- inkscape:transform-center-x="0.5180824"
- inkscape:transform-center-y="-0.28622416" />
- <path
- inkscape:connector-curvature="0"
- id="path5457"
- d="m 143.74707,850.88647 c -5.0386,0.15973 -7.45306,6.82507 -4.44845,10.23363 -5.35784,2.62945 -3.73419,8.64761 -3.90826,13.70497 6.23105,0 12.46221,0 18.69326,0 -0.0342,-5.17704 1.38659,-11.61813 -4.44823,-13.9621 3.5491,-4.27537 -0.52838,-10.73631 -5.88832,-9.9765 z"
- style="fill:#e7e8a8;fill-opacity:1;stroke:none" />
- <path
- sodipodi:type="arc"
- style="fill:#16160f;fill-opacity:1;stroke:none"
- id="path5461"
- sodipodi:cx="-1766"
- sodipodi:cy="1210.3622"
- sodipodi:rx="20.875"
- sodipodi:ry="19.875"
- d="m -1746.6683,1217.8622 c -4.3506,10.1651 -16.5325,15.0477 -27.209,10.9056 -10.6766,-4.1422 -15.8049,-15.7405 -11.4544,-25.9056 4.3506,-10.1651 16.5325,-15.0477 27.209,-10.9056 10.6563,4.1342 15.789,15.6991 11.4755,25.8559"
- sodipodi:start="0.38694167"
- sodipodi:end="6.6674319"
- sodipodi:open="true"
- transform="matrix(0.23246322,0,0,0.23246322,554.98367,575.74893)" />
- <path
- style="fill:#16160f;fill-opacity:1;stroke:none"
- d="m 142.46627,862.02883 c -2.77296,0 -5.03938,2.03973 -5.40307,4.70966 l -0.021,0 0,0.11384 c -0.0243,0.20805 -0.0408,0.42712 -0.0408,0.64178 0,0.21103 0.0177,0.41632 0.0408,0.62106 l 0,5.0718 15.40196,0 0,-5.0718 c 0.0232,-0.20474 0.0408,-0.41003 0.0408,-0.62106 0,-0.21466 -0.0177,-0.43373 -0.0408,-0.64178 l 0,-0.11384 -0.021,0 c -0.3638,-2.66993 -2.63021,-4.70966 -5.40306,-4.70966 l -1.03504,0 -1.35592,2.81554 -1.36629,-2.81554 -0.79699,0 z"
- id="path5463"
- inkscape:connector-curvature="0" />
- <path
- style="opacity:0.95734594;fill:#e7e8a8;fill-opacity:1;stroke:none"
- d="m 230.09729,852.03013 c -1.6542,0.0555 -2.75231,2.08638 -1.97699,3.52883 -0.63135,1.02386 -1.18707,3.28768 -2.84533,2.51282 -1.58254,0.6738 -2.41713,-1.60371 -3.98172,-0.91457 -2.15656,0.50838 -2.50044,3.95528 -0.28646,4.60984 0.66658,0.11836 1.38854,0.19214 1.38577,1.01628 1.32012,1.04282 0.20536,3.35241 -1.27491,3.51052 -2.03524,0.99474 -1.52604,4.44609 0.79456,4.64674 1.48119,0.14147 2.53871,-1.5326 4.09258,-0.89608 1.17551,0.24938 1.76747,1.60242 2.05078,2.54048 -1.0087,1.8897 1.18605,4.16804 3.10405,3.20566 1.39067,-0.4601 1.85188,-2.07121 1.37652,-3.31653 0.41369,-0.83912 1.05271,-1.65965 1.6075,-2.34648 1.24643,-0.35941 2.55425,-0.14896 3.50119,0.71142 2.08378,0.88286 4.38154,-1.75378 2.95628,-3.63073 -0.53953,-1.15942 -2.19299,-0.66667 -2.50358,-1.94916 -0.82635,-1.06372 -0.34544,-2.40575 0.47111,-3.2519 0.51485,-0.51216 1.80066,-0.20231 2.15249,-1.1363 1.70737,-1.91245 -1.15266,-5.07734 -3.21491,-3.54741 -0.69552,1.09312 -1.98439,0.81045 -3.03932,0.8406 -0.98808,-0.56654 -1.66816,-1.89082 -1.84763,-2.90081 0.49774,-1.68564 -0.70875,-3.40169 -2.52198,-3.23322 z"
- id="path5491"
- inkscape:connector-curvature="0" />
- <path
- id="path5404"
- d="m 230.30968,853.20332 c -0.69043,0 -1.25641,0.56589 -1.25641,1.25632 0,0.41517 0.20601,0.77958 0.51734,1.00695 l -2.22628,3.81547 -4.22185,-0.009 c 0,0 0,-0.009 0,-0.009 -0.11993,-0.56552 -0.62747,-0.98854 -1.22877,-0.98854 -0.69034,0 -1.24707,0.55663 -1.24707,1.24716 0,0.69044 0.55673,1.24708 1.24707,1.24708 0.21813,0 0.4221,-0.0582 0.60056,-0.15692 l 2.01389,3.51967 -1.85688,3.19642 c -0.13232,-0.0472 -0.27629,-0.0841 -0.42497,-0.0841 -0.69044,0 -1.24717,0.55674 -1.24717,1.24727 0,0.69052 0.55673,1.25641 1.24717,1.25641 0.54915,0 1.01452,-0.35784 1.18244,-0.84994 l 3.88926,-0.0185 2.19872,3.72291 c -0.28692,0.22904 -0.48036,0.57421 -0.48036,0.96996 0,0.69053 0.55664,1.24726 1.24717,1.24726 0.69044,0 1.25641,-0.55673 1.25641,-1.24726 0,-0.37153 -0.16764,-0.70403 -0.42497,-0.93297 l 2.24487,-3.7599 4.02786,-0.009 c 0.13796,0.54037 0.62682,0.94231 1.21018,0.94231 0.69053,0 1.24717,-0.55673 1.24717,-1.24716 0,-0.69053 -0.55664,-1.25643 -1.24717,-1.25643 -0.18003,0 -0.3534,0.0425 -0.5081,0.11087 l -1.95849,-3.4089 2.05087,-3.53826 c 0.18262,0.10449 0.38447,0.16634 0.60971,0.16634 0.69053,0 1.25641,-0.55663 1.25641,-1.24707 0,-0.69062 -0.56588,-1.24726 -1.25641,-1.24726 -0.63921,0 -1.15415,0.48026 -1.22867,1.09941 l -4.13864,0.0185 -2.32808,-3.83387 c 0.28794,-0.22904 0.48045,-0.57347 0.48045,-0.96996 0,-0.69053 -0.55673,-1.25641 -1.24726,-1.25641 z"
- style="opacity:0.95734594;fill:#16160f;fill-opacity:1;stroke:none"
- inkscape:connector-curvature="0" />
- <path
- transform="matrix(0.05048908,0,0,0.04995915,374.93399,727.37564)"
- d="m -2780.5,2735.8623 c 0,45.5635 -37.3842,82.5 -83.5,82.5 -46.1158,0 -83.5,-36.9365 -83.5,-82.5 0,-45.5635 37.3842,-82.5 83.5,-82.5 46.1158,0 83.5,36.9365 83.5,82.5 z"
- sodipodi:ry="82.5"
- sodipodi:rx="83.5"
- sodipodi:cy="2735.8623"
- sodipodi:cx="-2864"
- id="path5754"
- style="opacity:0.95734594;fill:#e7e8a8;fill-opacity:1;stroke:none"
- sodipodi:type="arc" />
- <path
- style="fill:url(#radialGradient5712-8);fill-opacity:1"
- d="m 9.7549531,922.45495 c -0.094,-0.046 -0.2146,-0.1465 -0.2675,-0.2235 -0.092,-0.1328 -0.097,-0.507 -0.1104,-7.2852 l -0.014,-7.1451 5.5932999,-4.8985 c 3.0763,-2.6941 5.6262,-4.9108 5.6664,-4.9262 0.044,-0.017 2.291499,1.9154 5.694699,4.8961 l 5.6214,4.9239 -0.014,7.1474 c -0.013,6.7953 -0.019,7.1546 -0.1108,7.2883 -0.2172,0.3162 -0.1184,0.3086 -4.0168,0.3086 l -3.5623,0 -6e-4,-3.0266 c -6e-4,-1.6648 -0.016,-3.1187 -0.035,-3.2313 -0.022,-0.1319 -0.098,-0.2677 -0.2151,-0.3832 l -0.1811,-0.1789 -3.152299,0 -3.1523,0 -0.181,0.1789 c -0.1168,0.1155 -0.1931,0.2513 -0.2152,0.3832 -0.019,0.1126 -0.034,1.5665 -0.035,3.2313 l -5e-4,3.0266 -3.5704,0 c -3.1432,0 -3.5909999,-0.012 -3.7417999,-0.085 z m -4.3178,-15.0177 c -0.4595,-0.5139 -0.8170004,-0.9502 -0.7943004,-0.9695 0.023,-0.019 3.6131004,-3.1609 7.9784003,-6.9811 4.3654,-3.82019 7.9797,-6.94589 8.0317,-6.94589 0.052,0 3.651199,3.11599 7.998399,6.92429 4.3473,3.8085 7.9377,6.949 7.9789,6.9791 0.059,0.043 -0.096,0.24591 -0.764,0.9929 -0.7293,0.8159 -0.8498,0.9293 -0.9245,0.8704 -0.047,-0.038 -3.2709,-2.8571 -7.1641,-6.26639 -3.8931,-3.40961 -7.098499,-6.1989 -7.123099,-6.1989 -0.025,0 -3.2475,2.8051 -7.1619,6.23339 -3.9143999,3.4285 -7.1400999,6.2475 -7.1684999,6.2648 -0.028,0.018 -0.4273,-0.3892 -0.887,-0.9031 z m 3.9274,-9.9518 0,-2.96499 2.0325999,0 2.0326,0 0,0.9707 c 0,1.5539 0.2495,1.16 -2.0161,3.1826 -1.0729,0.95779 -1.9728999,1.74949 -1.9998999,1.75909 -0.03,0.011 -0.048,-1.1677 -0.048,-2.9474 z"
- id="path5673"
- inkscape:connector-curvature="0" />
- <path
- inkscape:connector-curvature="0"
- id="path3820"
- d="m 54.735425,922.45495 c -0.094,-0.046 -0.2146,-0.1465 -0.2675,-0.2235 -0.092,-0.1328 -0.097,-0.507 -0.1104,-7.2852 l -0.014,-7.1451 5.5933,-4.8985 c 3.0763,-2.6941 5.6262,-4.9108 5.6664,-4.9262 0.044,-0.017 2.2915,1.9154 5.6947,4.8961 l 5.6214,4.9239 -0.014,7.1474 c -0.013,6.7953 -0.019,7.1546 -0.1108,7.2883 -0.2172,0.3162 -0.1184,0.3086 -4.0168,0.3086 l -3.5623,0 -6e-4,-3.0266 c -6e-4,-1.6648 -0.016,-3.1187 -0.035,-3.2313 -0.022,-0.1319 -0.098,-0.2677 -0.2151,-0.3832 l -0.1811,-0.1789 -3.1523,0 -3.1523,0 -0.181,0.1789 c -0.1168,0.1155 -0.1931,0.2513 -0.2152,0.3832 -0.019,0.1126 -0.034,1.5665 -0.035,3.2313 l -5e-4,3.0266 -3.5704,0 c -3.1432,0 -3.591,-0.012 -3.7418,-0.085 z m -4.3178,-15.0177 c -0.4595,-0.5139 -0.817,-0.9502 -0.7943,-0.9695 0.023,-0.019 3.6131,-3.1609 7.9784,-6.9811 4.3654,-3.82019 7.9797,-6.94589 8.0317,-6.94589 0.052,0 3.6512,3.11599 7.9984,6.92429 4.3473,3.8085 7.9377,6.949 7.9789,6.9791 0.059,0.043 -0.096,0.24591 -0.764,0.9929 -0.7293,0.8159 -0.8498,0.9293 -0.9245,0.8704 -0.047,-0.038 -3.2709,-2.8571 -7.1641,-6.26639 -3.8931,-3.40961 -7.0985,-6.1989 -7.1231,-6.1989 -0.025,0 -3.2475,2.8051 -7.1619,6.23339 -3.9144,3.4285 -7.1401,6.2475 -7.1685,6.2648 -0.028,0.018 -0.4273,-0.3892 -0.887,-0.9031 z m 3.9274,-9.9518 0,-2.96499 2.0326,0 2.0326,0 0,0.9707 c 0,1.5539 0.2495,1.16 -2.0161,3.1826 -1.0729,0.95779 -1.9729,1.74949 -1.9999,1.75909 -0.03,0.011 -0.048,-1.1677 -0.048,-2.9474 z"
- style="fill:url(#radialGradient3822-9);fill-opacity:1" />
- <rect
- style="opacity:0.79620852;fill:#deded0;fill-opacity:1;stroke:none"
- id="rect4547"
- width="48"
- height="40"
- x="97.232117"
- y="882.21423" />
- <g
- id="g3827"
- transform="translate(-3.8890873,-41.012193)">
- <path
- sodipodi:type="arc"
- style="opacity:0.6956522;fill:url(#linearGradient3832);fill-opacity:1;stroke:none"
- id="path3815"
- sodipodi:cx="113.25"
- sodipodi:cy="45.375"
- sodipodi:rx="10.875"
- sodipodi:ry="10.125"
- d="m 124.125,45.375 c 0,5.591883 -4.8689,10.125 -10.875,10.125 -6.0061,0 -10.875,-4.533117 -10.875,-10.125 0,-5.591883 4.8689,-10.125 10.875,-10.125 6.0061,0 10.875,4.533117 10.875,10.125 z"
- transform="matrix(1.621439,0,0,1.7273288,-57.807891,865.70481)" />
- <path
- transform="matrix(1.408046,0,0,1.5,-33.48691,876.19302)"
- d="m 124.125,45.375 c 0,5.591883 -4.8689,10.125 -10.875,10.125 -6.0061,0 -10.875,-4.533117 -10.875,-10.125 0,-5.591883 4.8689,-10.125 10.875,-10.125 6.0061,0 10.875,4.533117 10.875,10.125 z"
- sodipodi:ry="10.125"
- sodipodi:rx="10.875"
- sodipodi:cy="45.375"
- sodipodi:cx="113.25"
- id="path3027"
- style="fill:url(#radialGradient3834);fill-opacity:1;stroke:none"
- sodipodi:type="arc" />
- <path
- inkscape:connector-curvature="0"
- id="path3807"
- d="m 123.65073,934.32167 c -4.50646,0 -8.15625,3.67292 -8.15625,8.1875 0,4.51459 3.64979,8.15625 8.15625,8.15625 1.78681,0 3.4379,-0.55881 4.78125,-1.53125 l 3.8125,3.53125 1.65625,-1.78125 -3.75,-3.5 c 1.02086,-1.36157 1.65625,-3.03756 1.65625,-4.875 0,-4.51458 -3.64979,-8.1875 -8.15625,-8.1875 z m 0.0312,2.21875 c 3.35929,0 6.09375,2.7284 6.09375,6.09375 0,3.36535 -2.73446,6.09375 -6.09375,6.09375 -3.35929,0 -6.0625,-2.7284 -6.0625,-6.09375 0,-3.36535 2.70321,-6.09375 6.0625,-6.09375 z"
- style="fill:#ffffff;fill-opacity:1;stroke:none" />
- </g>
- <rect
- y="882.21423"
- x="145.23212"
- height="40"
- width="48"
- id="rect3836"
- style="opacity:0.79620852;fill:#deded0;fill-opacity:1;stroke:none" />
- <g
- transform="translate(44.110913,-41.012193)"
- id="g3838">
- <path
- transform="matrix(1.621439,0,0,1.7273288,-57.807891,865.70481)"
- d="m 124.125,45.375 c 0,5.591883 -4.8689,10.125 -10.875,10.125 -6.0061,0 -10.875,-4.533117 -10.875,-10.125 0,-5.591883 4.8689,-10.125 10.875,-10.125 6.0061,0 10.875,4.533117 10.875,10.125 z"
- sodipodi:ry="10.125"
- sodipodi:rx="10.875"
- sodipodi:cy="45.375"
- sodipodi:cx="113.25"
- id="path3840"
- style="opacity:0.6956522;fill:url(#linearGradient3846);fill-opacity:1;stroke:none"
- sodipodi:type="arc" />
- <path
- sodipodi:type="arc"
- style="fill:url(#radialGradient3848);fill-opacity:1;stroke:none"
- id="path3842"
- sodipodi:cx="113.25"
- sodipodi:cy="45.375"
- sodipodi:rx="10.875"
- sodipodi:ry="10.125"
- d="m 124.125,45.375 c 0,5.591883 -4.8689,10.125 -10.875,10.125 -6.0061,0 -10.875,-4.533117 -10.875,-10.125 0,-5.591883 4.8689,-10.125 10.875,-10.125 6.0061,0 10.875,4.533117 10.875,10.125 z"
- transform="matrix(1.408046,0,0,1.5,-33.48691,876.19302)" />
- <path
- style="fill:#ffffff;fill-opacity:1;stroke:none"
- d="m 123.65073,934.32167 c -4.50646,0 -8.15625,3.67292 -8.15625,8.1875 0,4.51459 3.64979,8.15625 8.15625,8.15625 1.78681,0 3.4379,-0.55881 4.78125,-1.53125 l 3.8125,3.53125 1.65625,-1.78125 -3.75,-3.5 c 1.02086,-1.36157 1.65625,-3.03756 1.65625,-4.875 0,-4.51458 -3.64979,-8.1875 -8.15625,-8.1875 z m 0.0312,2.21875 c 3.35929,0 6.09375,2.7284 6.09375,6.09375 0,3.36535 -2.73446,6.09375 -6.09375,6.09375 -3.35929,0 -6.0625,-2.7284 -6.0625,-6.09375 0,-3.36535 2.70321,-6.09375 6.0625,-6.09375 z"
- id="path3844"
- inkscape:connector-curvature="0" />
- </g>
- <path
- sodipodi:type="arc"
- style="fill:url(#radialGradient3838-8);fill-opacity:1;stroke:none"
- id="path3813"
- sodipodi:cx="223.62251"
- sodipodi:cy="147.08873"
- sodipodi:rx="11.136931"
- sodipodi:ry="9.0156116"
- d="m 234.75944,147.08873 a 11.136931,9.0156116 0 1 1 -22.27386,0 11.136931,9.0156116 0 1 1 22.27386,0 z"
- transform="matrix(1.2054549,0,0,1.1341085,-99.371969,741.25595)" />
- </g>
-</svg>
diff --git a/askbot/skins/default/media/images/vote-accepted-on.png b/askbot/skins/default/media/images/vote-accepted-on.png
deleted file mode 100755
index 2026f3bc..00000000
--- a/askbot/skins/default/media/images/vote-accepted-on.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/vote-accepted.png b/askbot/skins/default/media/images/vote-accepted.png
deleted file mode 100755
index ecd18551..00000000
--- a/askbot/skins/default/media/images/vote-accepted.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/vote-arrow-down-on.png b/askbot/skins/default/media/images/vote-arrow-down-on.png
deleted file mode 100755
index 048dbb44..00000000
--- a/askbot/skins/default/media/images/vote-arrow-down-on.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/vote-arrow-down.png b/askbot/skins/default/media/images/vote-arrow-down.png
deleted file mode 100755
index e4fdec0a..00000000
--- a/askbot/skins/default/media/images/vote-arrow-down.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/vote-arrow-up-on.png b/askbot/skins/default/media/images/vote-arrow-up-on.png
deleted file mode 100755
index 56ad0c25..00000000
--- a/askbot/skins/default/media/images/vote-arrow-up-on.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/vote-arrow-up.png b/askbot/skins/default/media/images/vote-arrow-up.png
deleted file mode 100755
index 6e9a51c7..00000000
--- a/askbot/skins/default/media/images/vote-arrow-up.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/vote-favorite-off.png b/askbot/skins/default/media/images/vote-favorite-off.png
deleted file mode 100755
index c1bef074..00000000
--- a/askbot/skins/default/media/images/vote-favorite-off.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/vote-favorite-on.png b/askbot/skins/default/media/images/vote-favorite-on.png
deleted file mode 100755
index 1f9c14ab..00000000
--- a/askbot/skins/default/media/images/vote-favorite-on.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/images/wiki.png b/askbot/skins/default/media/images/wiki.png
deleted file mode 100644
index 06d487f3..00000000
--- a/askbot/skins/default/media/images/wiki.png
+++ /dev/null
Binary files differ
diff --git a/askbot/skins/default/media/style/auth.css b/askbot/skins/default/media/style/auth.css
deleted file mode 100644
index 33702758..00000000
--- a/askbot/skins/default/media/style/auth.css
+++ /dev/null
@@ -1,48 +0,0 @@
-#bigicon_providers, #smallicon_providers {
- display: block;
- padding: 0px;
- width:600px;
- margin:0px 0px 5px 0px;
-}
-
-.provider_logo {
- display: inline-block;
- padding: 4px;
- border: 1px solid #DDD;
- text-align: center;
- vertical-align: middle;
-}
-
-.provider_logo.big {
- height: 40px;
- width: 90px;
-}
-
-.provider_logo.small {
- height: 32px;
- width: 32px;
-}
-
-.provider_logo.selected {
- outline: 2px solid #FFF8C6;
-}
-
-.provider_logo .provider_url {
- display: none;
-}
-
-.signin_form input[type="text"], .signin_form input[type="password"], .signin_form input[type="submit"] {
- height: 28px;
- line-height: 22px;
- font-size: 140%;
- border: 1px solid #999;
-}
-
-.signin_form .icon_input {
- padding-left: 20px;
-}
-
-.or_label {
- margin-top: 20px;
- margin-bottom: 10px;
-} \ No newline at end of file
diff --git a/askbot/skins/default/media/style/lib_style.less b/askbot/skins/default/media/style/lib_style.less
deleted file mode 100644
index 63389526..00000000
--- a/askbot/skins/default/media/style/lib_style.less
+++ /dev/null
@@ -1,102 +0,0 @@
-/* General Predifined classes, read more in lesscss.org */
-
-/* Variables for Colors*/
-
-@header-color:#16160f;
-@link:#1b79bd;
-@question-link:#464646;
-@button-label:#4a757f;
-@section-title:#7ea9b3;
-@info-text:#707070;
-@info-text-dark:#525252;
-
-/* Variables for fonts*/
-
-@body-font:Arial; /* "Trebuchet MS", sans-serif;*/
-@sort-font:Georgia, serif;
-@main-font:'Yanone Kaffeesatz', Arial, sans-serif;
-@secondary-font:Arial;
-
-/* Buttons */
-
-.button-style(@w:100px ,@h:20px, @f:14px){
- width:@w;
- height:@h;
- font-size:@f;
- text-align:center;
- text-decoration:none;
- cursor:pointer;
- color:@button-label;
- font-family:@main-font;
- .text-shadow(0px,1px,0px,#c6d9dd);
- border-top:#eaf2f3 1px solid;
- .linear-gradient(#d1e2e5,#a9c2c7);
- .rounded-corners(4px);
- .box-shadow(1px, 1px, 2px, #636363)
-}
-
-.button-style-hover{
- .linear-gradient(#cde5e9,#94b3ba);
- text-decoration:none;
- .text-shadow(0px, 1px, 0px, #c6d9dd);
-}
-
-/* General styles for gradients */
-
-.linear-gradient(@start:#eee,@end:#fff,@stop:25%){
- background-color: @start;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@start), color-stop(@stop, @start), to(@end));
- background-image: -webkit-linear-gradient(@start, @start @stop, @end);
- background-image: -moz-linear-gradient(top, @start, @start @stop, @end);
- background-image: -ms-linear-gradient(@start, @start @stop, @end);
- background-image: -o-linear-gradient(@start, @start @stop, @end);
- background-image: linear-gradient(@start, @start @stop, @end);
-}
-
-/* Receive exactly positions for background Sprite */
-
-.sprites(@hor,@vert,@back:url(../images/sprites.png)){
- background:@hor @vert @back no-repeat;
-}
-
-/* CSS3 Elements */
-
-.box-shadow (@hor: 0px, @vert: 0px, @blur: 5px, @shadow: #929292){
- -webkit-box-shadow: @arguments ;
- -moz-box-shadow: @arguments;
- box-shadow: @arguments;
-}
-
-.text-shadow(@hor: 0px, @vert: 0px, @blur: 5px, @shadow: #929292){
- text-shadow: @arguments;
- -moz-text-shadow: @arguments;
- -webkit-text-shadow: @arguments;
-}
-
-.rounded-corners(@radio: 5px){
- border-radius: @radio;
- -ms-border-radius: @radio;
- -moz-border-radius: @radio;
- -webkit-border-radius: @radio;
- -khtml-border-radius: @radio;
-}
-
-.rounded-corners-top(@radio:5px){
- border-top-right-radius:@radio;
- border-top-left-radius:@radio;
- -moz-border-radius-topright:@radio;
- -moz-border-radius-topleft:@radio;
- -webkit-border-top-left-radius:@radio;
- -webkit-border-top-right-radius:@radio;
-}
-
-.rounded-corners-right(@radio:5px){
- border-top-right-radius:@radio;
- border-bottom-right-radius:@radio;
- -moz-border-radius-topright:@radio;
- -moz-border-radius-bottomright:@radio;
- -webkit-border-bottom-right-radius:@radio;
- -webkit-border-top-right-radius:@radio;
-}
-
diff --git a/askbot/skins/default/media/style/openid.css b/askbot/skins/default/media/style/openid.css
deleted file mode 100644
index 0d201df2..00000000
--- a/askbot/skins/default/media/style/openid.css
+++ /dev/null
@@ -1,45 +0,0 @@
-#openid_form {
- width: 470px;
-}
- #openid_form legend {
- font-weight: bold;
- }
-#openid_choice {
- display: none;
-}
-#openid_input_area {
- clear: both;
- padding: 10px;
-}
-#openid_btns, #openid_btns br {
- clear: both;
-}
- #openid_highlight {
- padding: 3px;
- background-color: #FFFCC9;
- float: left;
- }
- .openid_large_btn {
- width: 100px;
- height: 60px;
- border: 1px solid #DDD;
- margin: 3px;
- float: left;
- }
- .openid_small_btn {
- width: 24px;
- height: 24px;
- border: 1px solid #DDD;
- margin: 3px;
- float: left;
- }
- a.openid_large_btn:focus {
- outline: none;
- }
- a.openid_large_btn:focus
- {
- -moz-outline-style: none;
- }
- .openid_selected {
- border: 4px solid #DDD;
- }
diff --git a/askbot/skins/default/media/style/prettify.css b/askbot/skins/default/media/style/prettify.css
deleted file mode 100644
index 10a37577..00000000
--- a/askbot/skins/default/media/style/prettify.css
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Pretty printing styles. Used with prettify.js. */
-
-.str { color: #080; }
-.kwd { color: #008; }
-.com { color: #800; }
-.typ { color: #606; }
-.lit { color: #066; }
-.pun { color: #660; }
-.pln { color: #000; }
-.tag { color: #008; }
-.atn { color: #606; }
-.atv { color: #080; }
-.dec { color: #606; }
-pre.prettyprint { padding: 3px; border: 0px solid #888; }
-
-@media print {
- .str { color: #060; }
- .kwd { color: #006; font-weight: bold; }
- .com { color: #600; font-style: italic; }
- .typ { color: #404; font-weight: bold; }
- .lit { color: #044; }
- .pun { color: #440; }
- .pln { color: #000; }
- .tag { color: #006; font-weight: bold; }
- .atn { color: #404; }
- .atv { color: #060; }
-}
diff --git a/askbot/skins/default/media/style/style.css b/askbot/skins/default/media/style/style.css
deleted file mode 100644
index 348eb6b2..00000000
--- a/askbot/skins/default/media/style/style.css
+++ /dev/null
@@ -1,3591 +0,0 @@
-@import url(jquery.autocomplete.css);
-/* General Predifined classes, read more in lesscss.org */
-/* Variables for Colors*/
-/* Variables for fonts*/
-/* "Trebuchet MS", sans-serif;*/
-/* Buttons */
-.button-style-hover {
- background-color: #cde5e9;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
- background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- text-decoration: none;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
-}
-/* General styles for gradients */
-/* Receive exactly positions for background Sprite */
-/* CSS3 Elements */
-/* Library of predifined less functions styles */
-/* ----- General HTML Styles----- */
-body {
- background: #FFF;
- font-size: 14px;
- line-height: 150%;
- margin: 0;
- padding: 0;
- color: #000;
- font-family: Arial;
-}
-div {
- margin: 0 auto;
- padding: 0;
-}
-h1,
-h2,
-h3,
-h4,
-h5,
-h6,
-ul,
-li,
-dl,
-dt,
-dd,
-form,
-img,
-p {
- margin: 0;
- padding: 0;
- border: none;
-}
-label {
- vertical-align: middle;
-}
-hr {
- border: none;
- border-top: 1px dashed #ccccce;
-}
-input,
-select {
- vertical-align: middle;
- font-family: Trebuchet MS, "segoe ui", Helvetica, Tahoma, Verdana, MingLiu, PMingLiu, Arial, sans-serif;
- margin-left: 0px;
-}
-textarea:focus,
-input:focus {
- outline: none;
-}
-iframe {
- border: none;
-}
-p {
- font-size: 14px;
- line-height: 140%;
- margin-bottom: 6px;
-}
-a {
- color: #1b79bd;
- text-decoration: none;
- cursor: pointer;
-}
-h2 {
- font-size: 21px;
- padding: 3px 0 3px 5px;
-}
-h3 {
- font-size: 19px;
- padding: 3px 0 3px 5px;
-}
-ul {
- list-style: disc;
- margin-left: 20px;
- padding-left: 0px;
- margin-bottom: 1em;
-}
-ol {
- list-style: decimal;
- margin-left: 30px;
- margin-bottom: 1em;
- padding-left: 0px;
-}
-td ul {
- vertical-align: middle;
-}
-li input {
- margin: 3px 3px 4px 3px;
-}
-pre {
- font-family: Consolas, Monaco, Liberation Mono, Lucida Console, Monospace;
- font-size: 100%;
- margin-bottom: 10px;
- /*overflow: auto;*/
-
- background-color: #F5F5F5;
- padding-left: 5px;
- padding-top: 5px;
- /*width: 671px;*/
-
- padding-bottom: 20px ! ie7;
-}
-code {
- font-family: Consolas, Monaco, Liberation Mono, Lucida Console, Monospace;
- font-size: 100%;
-}
-blockquote {
- margin-bottom: 10px;
- margin-right: 15px;
- padding: 10px 0px 1px 10px;
- background-color: #F5F5F5;
-}
-/* http://pathfindersoftware.com/2007/09/developers-note-2/ */
-* html .clearfix,
-* html .paginator {
- height: 1;
- overflow: visible;
-}
-+ html .clearfix,
-+ html .paginator {
- min-height: 1%;
-}
-.clearfix:after,
-.paginator:after {
- clear: both;
- content: ".";
- display: block;
- height: 0;
- visibility: hidden;
-}
-.badges a {
- color: #763333;
- text-decoration: underline;
-}
-a:hover {
- text-decoration: underline;
-}
-.badge-context-toggle.active {
- cursor: pointer;
- text-decoration: underline;
-}
-h1 {
- font-size: 24px;
- padding: 0px 0 5px 0px;
-}
-/* ----- Extra space above for messages ----- */
-body.user-messages {
- margin-top: 2.4em;
-}
-/* ----- Custom positions ----- */
-.left {
- float: left;
-}
-.right {
- float: right;
-}
-.clean {
- clear: both;
-}
-.center {
- margin: 0 auto;
- padding: 0;
-}
-/* ----- Notify message bar , check blocks/system_messages.html ----- */
-.notify {
- position: fixed;
- top: 0px;
- left: 0px;
- width: 100%;
- z-index: 100;
- padding: 0;
- text-align: center;
- background-color: #f5dd69;
- border-top: #fff 1px solid;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
-}
-.notify p.notification {
- margin-top: 6px;
- margin-bottom: 6px;
- font-size: 16px;
- color: #424242;
-}
-#closeNotify {
- position: absolute;
- right: 5px;
- top: 7px;
- color: #735005;
- text-decoration: none;
- line-height: 18px;
- background: -6px -5px url(../images/sprites.png) no-repeat;
- cursor: pointer;
- width: 20px;
- height: 20px;
-}
-#closeNotify:hover {
- background: -26px -5px url(../images/sprites.png) no-repeat;
-}
-/* ----- Header, check blocks/header.html ----- */
-#header {
- margin-top: 0px;
- background: #16160f;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
-}
-.content-wrapper {
- /* wrapper positioning class */
-
- width: 960px;
- margin: auto;
- position: relative;
-}
-#logo img {
- padding: 5px 0px 5px 0px;
- height: 75px;
- width: auto;
- float: left;
-}
-#userToolsNav {
- /* Navigation bar containing login link or user information, check widgets/user_navigation.html*/
-
- height: 20px;
- padding-bottom: 5px;
-}
-#userToolsNav a {
- height: 35px;
- text-align: right;
- margin-left: 20px;
- text-decoration: underline;
- color: #d0e296;
- font-size: 16px;
-}
-#userToolsNav a:first-child {
- margin-left: 0;
-}
-#userToolsNav a#ab-responses {
- margin-left: 3px;
-}
-#userToolsNav .user-info,
-#userToolsNav .user-micro-info {
- color: #b5b593;
-}
-#userToolsNav a img {
- vertical-align: middle;
- margin-bottom: 2px;
-}
-#userToolsNav .user-info a {
- margin: 0;
- text-decoration: none;
-}
-#metaNav {
- /* Top Navigation bar containing links for tags, people and badges, check widgets/header.html */
-
- float: right;
- /* for #header.with-logo it is modified */
-
-}
-#metaNav a {
- color: #e2e2ae;
- padding: 0px 0px 0px 35px;
- height: 25px;
- line-height: 30px;
- margin: 5px 0px 0px 10px;
- font-size: 18px;
- font-weight: 100;
- text-decoration: none;
- display: block;
- float: left;
-}
-#metaNav a:hover {
- text-decoration: underline;
-}
-#metaNav a.on {
- font-weight: bold;
- color: #FFF;
- text-decoration: none;
-}
-#metaNav a.special {
- font-size: 18px;
- color: #B02B2C;
- font-weight: bold;
- text-decoration: none;
-}
-#metaNav a.special:hover {
- text-decoration: underline;
-}
-#metaNav #navTags {
- background: -50px -5px url(../images/sprites.png) no-repeat;
-}
-#metaNav #navUsers {
- background: -125px -5px url(../images/sprites.png) no-repeat;
-}
-#metaNav #navGroups {
- background: -125px -5px url(../images/sprites.png) no-repeat;
-}
-#metaNav #navBadges {
- background: -210px -5px url(../images/sprites.png) no-repeat;
-}
-#header.with-logo #userToolsNav {
- position: absolute;
- bottom: 0;
- right: 0px;
-}
-#header.without-logo #userToolsNav {
- float: left;
- margin-top: 7px;
-}
-#header.without-logo #metaNav {
- margin-bottom: 7px;
-}
-#secondaryHeader {
- /* Div containing Home button, scope navigation, search form and ask button, check blocks/secondary_header.html */
-
- height: 55px;
- background: #e9e9e1;
- border-bottom: #d3d3c2 1px solid;
- border-top: #fcfcfc 1px solid;
- margin-bottom: 10px;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
-}
-#secondaryHeader #homeButton {
- border-right: #afaf9e 1px solid;
- background: -6px -36px url(../images/sprites.png) no-repeat;
- height: 55px;
- width: 43px;
- display: block;
- float: left;
-}
-#secondaryHeader #homeButton:hover {
- background: -51px -36px url(../images/sprites.png) no-repeat;
-}
-#secondaryHeader #scopeWrapper {
- width: 688px;
- float: left;
-}
-#secondaryHeader #scopeWrapper a {
- display: block;
- float: left;
-}
-#secondaryHeader #scopeWrapper .scope-selector {
- font-size: 21px;
- color: #5a5a4b;
- height: 55px;
- line-height: 55px;
- margin-left: 24px;
-}
-#secondaryHeader #scopeWrapper .on {
- background: url(../images/scopearrow.png) no-repeat center bottom;
-}
-#secondaryHeader #scopeWrapper .ask-message {
- font-size: 24px;
-}
-#searchBar {
- /* Main search form , check widgets/search_bar.html */
-
- display: inline-block;
- background-color: #fff;
- width: 412px;
- border: 1px solid #c9c9b5;
- float: right;
- height: 42px;
- margin: 6px 0px 0px 15px;
-}
-#searchBar .searchInput,
-#searchBar .searchInputCancelable {
- font-size: 30px;
- height: 40px;
- font-weight: 300;
- background: #FFF;
- border: 0px;
- color: #484848;
- padding-left: 10px;
- font-family: Arial;
- vertical-align: middle;
-}
-#searchBar .searchInput {
- width: 352px;
-}
-#searchBar .searchInputCancelable {
- width: 317px;
-}
-#searchBar .logoutsearch {
- width: 337px;
-}
-#searchBar .searchBtn {
- font-size: 10px;
- color: #666;
- background-color: #eee;
- height: 42px;
- border: #FFF 1px solid;
- line-height: 22px;
- text-align: center;
- float: right;
- margin: 0px;
- width: 48px;
- background: -98px -36px url(../images/sprites.png) no-repeat;
- cursor: pointer;
-}
-#searchBar .searchBtn:hover {
- background: -146px -36px url(../images/sprites.png) no-repeat;
-}
-#searchBar .cancelSearchBtn {
- font-size: 30px;
- color: #ce8888;
- background: #fff;
- height: 42px;
- border: 0px;
- border-left: #deded0 1px solid;
- text-align: center;
- width: 35px;
- cursor: pointer;
-}
-#searchBar .cancelSearchBtn:hover {
- color: #d84040;
-}
-body.anon #searchBar {
- width: 500px;
-}
-body.anon #searchBar .searchInput {
- width: 440px;
-}
-body.anon #searchBar .searchInputCancelable {
- width: 405px;
-}
-#askButton {
- /* check blocks/secondary_header.html and widgets/ask_button.html*/
-
- line-height: 44px;
- margin-top: 6px;
- float: right;
- text-transform: uppercase;
- width: 200px;
- height: 42px;
- font-size: 23px;
- text-align: center;
- text-decoration: none;
- cursor: pointer;
- color: #4a757f;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
- border-top: #eaf2f3 1px solid;
- background-color: #d1e2e5;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
- background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- border-radius: 4px;
- -ms-border-radius: 4px;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- -khtml-border-radius: 4px;
- -webkit-box-shadow: 1px 1px 2px #636363;
- -moz-box-shadow: 1px 1px 2px #636363;
- box-shadow: 1px 1px 2px #636363;
-}
-#askButton:hover {
- background-color: #cde5e9;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
- background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- text-decoration: none;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
-}
-/* ----- Content layout, check two_column_body.html or one_column_body.html ----- */
-#ContentLeft {
- width: 730px;
- float: left;
- position: relative;
- padding-bottom: 10px;
-}
-#ContentRight {
- width: 200px;
- float: right;
- padding: 0 0px 10px 0px;
-}
-#ContentFull {
- float: left;
- width: 960px;
-}
-/* ----- Sidebar Widgets Box, check main_page/sidebar.html or question/sidebar.html ----- */
-.box {
- background: #fff;
- padding: 4px 0px 10px 0px;
- width: 200px;
- /* widgets for question template */
-
- /* notify by email box */
-
-}
-.box p {
- margin-bottom: 4px;
- color: #707070;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
-}
-.box p.info-box-follow-up-links {
- text-align: right;
- margin: 0;
-}
-.box h2 {
- padding-left: 0;
- background: #eceeeb;
- height: 30px;
- line-height: 30px;
- text-align: right;
- font-size: 18px !important;
- font-weight: normal;
- color: #656565;
- padding-right: 10px;
- margin-bottom: 10px;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- width: 190px;
-}
-.box h3 {
- color: #4a757f;
- font-size: 18px;
- text-align: left;
- font-weight: normal;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- padding-left: 0px;
-}
-.box .contributorback {
- background: #eceeeb url(../images/contributorsback.png) no-repeat center left;
-}
-.box label {
- color: #707070;
- font-size: 15px;
- display: block;
- float: right;
- text-align: left;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- width: 80px;
- margin-right: 18px;
-}
-.box #displayTagFilterControl label,
-.box #emailTagFilterControl label {
- /*Especial width just for the tag filter boxes in index page*/
-
- width: 160px;
-}
-.box ul {
- margin-left: 22px;
-}
-.box li {
- list-style-type: disc;
- font-size: 13px;
- line-height: 20px;
- margin-bottom: 10px;
- color: #707070;
-}
-.box ul.tags {
- list-style: none;
- margin: 0;
- padding: 0;
- line-height: 170%;
- display: block;
-}
-.box #displayTagFilterControl p label {
- color: #707070;
- font-size: 15px;
-}
-.box .inputs #interestingTagInput,
-.box .inputs #ignoredTagInput,
-.box .inputs #subscribedTagInput,
-.box .inputs #ab-tag-search {
- width: 156px;
- padding-left: 5px;
- border: #c9c9b5 1px solid;
- height: 25px;
-}
-.box .inputs #ab-tag-search {
- width: 138px;
-}
-.box .inputs #interestingTagAdd,
-.box .inputs #ignoredTagAdd,
-.box .inputs #subscribedTagAdd,
-.box .inputs #ab-tag-search-add {
- border: 0;
- font-weight: bold;
- margin-top: -2px;
- width: 30px;
- height: 27px;
- font-size: 14px;
- text-align: center;
- text-decoration: none;
- cursor: pointer;
- color: #4a757f;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
- border-top: #eaf2f3 1px solid;
- background-color: #d1e2e5;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
- background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- border-radius: 4px;
- -ms-border-radius: 4px;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- -khtml-border-radius: 4px;
- -webkit-box-shadow: 1px 1px 2px #636363;
- -moz-box-shadow: 1px 1px 2px #636363;
- box-shadow: 1px 1px 2px #636363;
- border-radius: 4px;
- -ms-border-radius: 4px;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- -khtml-border-radius: 4px;
-}
-.box .inputs #interestingTagAdd:hover,
-.box .inputs #ignoredTagAdd:hover,
-.box .inputs #ab-tag-search-add:hover {
- background-color: #cde5e9;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
- background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- text-decoration: none;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
-}
-.box .inputs #ab-tag-search-add {
- width: 47px;
-}
-.box img.gravatar {
- margin: 1px;
-}
-.box a.followed,
-.box a.follow {
- line-height: 34px;
- border: 0;
- font-weight: normal;
- margin-top: 3px;
- display: block;
- width: 120px;
- height: 34px;
- font-size: 21px;
- text-align: center;
- text-decoration: none;
- cursor: pointer;
- color: #4a757f;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
- border-top: #eaf2f3 1px solid;
- background-color: #d1e2e5;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
- background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- border-radius: 4px;
- -ms-border-radius: 4px;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- -khtml-border-radius: 4px;
- -webkit-box-shadow: 1px 1px 2px #636363;
- -moz-box-shadow: 1px 1px 2px #636363;
- box-shadow: 1px 1px 2px #636363;
- margin: 0 auto;
- padding: 0;
-}
-.box a.followed:hover,
-.box a.follow:hover {
- background-color: #cde5e9;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
- background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- text-decoration: none;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
-}
-.box a.followed div.unfollow {
- display: none;
-}
-.box a.followed:hover div {
- display: none;
-}
-.box a.followed:hover div.unfollow {
- display: inline;
- color: #a05736;
-}
-.box .favorite-number {
- padding: 5px 0 0 5px;
- font-size: 100%;
- font-family: Arial;
- font-weight: bold;
- color: #777;
- text-align: center;
-}
-.box .notify-sidebar #question-subscribe-sidebar {
- margin: 7px 0 0 3px;
-}
-.users-page .box label {
- display: inline;
- float: none;
-}
-.statsWidget p {
- color: #707070;
- font-size: 16px;
- border-bottom: #cccccc 1px solid;
- font-size: 13px;
-}
-.statsWidget p strong {
- float: right;
- padding-right: 10px;
-}
-.questions-related {
- word-wrap: break-word;
-}
-.questions-related p {
- line-height: 20px;
- padding: 4px 0px 4px 0px;
- font-size: 16px;
- font-weight: normal;
- border-bottom: #cccccc 1px solid;
-}
-.questions-related a {
- font-size: 13px;
-}
-/* tips and markdown help are widgets for ask template */
-#tips li {
- color: #707070;
- font-size: 13px;
- list-style-image: url(../images/tips.png);
-}
-#tips a {
- font-size: 16px;
-}
-#markdownHelp li {
- color: #707070;
- font-size: 13px;
-}
-#markdownHelp a {
- font-size: 16px;
-}
-/* ----- Sorting top Tab, check main_page/tab_bar.html ------*/
-.tabBar {
- background-color: #eff5f6;
- height: 30px;
- margin-bottom: 3px;
- margin-top: 3px;
- float: right;
- font-family: Georgia, serif;
- font-size: 16px;
- border-radius: 5px;
- -ms-border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
- -khtml-border-radius: 5px;
-}
-.tabBar h2 {
- float: left;
-}
-.tabsA,
-.tabsC {
- float: right;
- position: relative;
- display: block;
- height: 20px;
-}
-/* tabsA - used for sorting */
-.tabsA {
- float: right;
-}
-.tabsC {
- float: left;
-}
-.tabsA a,
-.tabsC a {
- border-left: 1px solid #d0e1e4;
- color: #7ea9b3;
- display: block;
- float: left;
- height: 20px;
- line-height: 20px;
- padding: 4px 7px 4px 7px;
- text-decoration: none;
-}
-.tabsA a.on,
-.tabsC a.on,
-.tabsA a:hover,
-.tabsC a:hover {
- color: #4a757f;
-}
-.tabsA .label,
-.tabsC .label {
- float: left;
- color: #646464;
- margin: 4px 5px 0px 8px;
-}
-.main-page .tabsA .label {
- margin-left: 8px;
-}
-.tabsB a {
- background: #eee;
- border: 1px solid #eee;
- color: #777;
- display: block;
- float: left;
- height: 22px;
- line-height: 28px;
- margin: 5px 0px 0 4px;
- padding: 0 11px 0 11px;
- text-decoration: none;
-}
-.tabsC .first {
- border: none;
-}
-.rss {
- float: right;
- font-size: 16px;
- color: #f57900;
- margin: 5px 0px 3px 7px;
- width: 52px;
- padding-left: 2px;
- padding-top: 3px;
- background: #ffffff url(../images/feed-icon-small.png) no-repeat center right;
- float: right;
- font-family: Georgia, serif;
- font-size: 16px;
-}
-.rss:hover {
- color: #F4A731 !important;
-}
-/* ----- Headline, containing number of questions and tags selected, check main_page/headline.html ----- */
-#questionCount {
- font-weight: bold;
- font-size: 23px;
- color: #7ea9b3;
- width: 200px;
- float: left;
- margin-bottom: 8px;
- padding-top: 6px;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
-}
-#listSearchTags {
- float: left;
- margin-top: 3px;
- color: #707070;
- font-size: 16px;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
-}
-ul#searchTags {
- margin-left: 10px;
- float: right;
- padding-top: 2px;
-}
-.search-tips {
- font-size: 16px;
- line-height: 17px;
- color: #707070;
- margin: 5px 0 10px 0;
- padding: 0px;
- float: left;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
-}
-.search-tips a {
- text-decoration: underline;
- color: #1b79bd;
-}
-/* ----- Question list , check main_page/content.html and macros/macros.html----- */
-#question-list {
- float: left;
- position: relative;
- background-color: #FFF;
- padding: 0;
- width: 100%;
-}
-.main-page #question-list {
- margin-top: 10px;
-}
-.short-summary {
- position: relative;
- filter: inherit;
- padding: 10px;
- border-bottom: 1px solid #DDDBCE;
- margin-bottom: 1px;
- overflow: hidden;
- width: 710px;
- float: left;
- background: url(../images/summary-background.png) repeat-x;
-}
-.short-summary h2 {
- font-size: 24px;
- font-weight: normal;
- line-height: 26px;
- padding-left: 0;
- margin-bottom: 6px;
- display: block;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
-}
-.short-summary a {
- color: #464646;
-}
-.short-summary .userinfo {
- text-align: right;
- line-height: 16px;
- font-family: Arial;
- padding-right: 4px;
-}
-.short-summary .userinfo .timeago,
-.short-summary span.anonymous {
- font-size: 11px;
- clear: both;
- font-weight: normal;
- color: #555;
-}
-.short-summary .userinfo a {
- font-weight: bold;
- font-size: 11px;
-}
-.short-summary .counts {
- float: right;
- margin: 4px 0 0 5px;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
-}
-.short-summary .counts .item-count {
- padding: 0px 5px 0px 5px;
- font-size: 25px;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
-}
-.short-summary .counts .votes div,
-.short-summary .counts .views div,
-.short-summary .counts .answers div,
-.short-summary .counts .favorites div {
- margin-top: 3px;
- font-size: 14px;
- line-height: 14px;
- color: #646464;
-}
-.short-summary .tags {
- margin-top: 0;
-}
-.short-summary .votes,
-.short-summary .answers,
-.short-summary .favorites,
-.short-summary .views {
- text-align: center;
- margin: 0 3px;
- padding: 8px 2px 0px 2px;
- width: 51px;
- float: right;
- height: 44px;
- border: #dbdbd4 1px solid;
-}
-.short-summary .votes {
- background: url(../images/vote-background.png) repeat-x;
-}
-.short-summary .answers {
- background: url(../images/answers-background.png) repeat-x;
-}
-.short-summary .views {
- background: url(../images/view-background.png) repeat-x;
-}
-.short-summary .no-votes .item-count {
- color: #b1b5b6;
-}
-.short-summary .some-votes .item-count {
- color: #4a757f;
-}
-.short-summary .no-answers .item-count {
- color: #b1b5b6;
-}
-.short-summary .some-answers .item-count {
- color: #eab243;
-}
-.short-summary .no-views .item-count {
- color: #b1b5b6;
-}
-.short-summary .some-views .item-count {
- color: #d33f00;
-}
-.short-summary .accepted .item-count {
- background: url(../images/accept.png) no-repeat top right;
- display: block;
- text-align: center;
- width: 40px;
- color: #eab243;
-}
-.short-summary .some-favorites .item-count {
- background: #338333;
- color: #d0f5a9;
-}
-.short-summary .no-favorites .item-count {
- background: #eab243;
- color: yellow;
-}
-/* ----- Question list Paginator , check main_content/pager.html and macros/utils_macros.html----- */
-.evenMore {
- font-size: 13px;
- color: #707070;
- padding: 15px 0px 10px 0px;
- clear: both;
-}
-.evenMore a {
- text-decoration: underline;
- color: #1b79bd;
-}
-.pager {
- margin-top: 10px;
- margin-bottom: 16px;
-}
-.pagesize {
- margin-top: 10px;
- margin-bottom: 16px;
- float: right;
-}
-.paginator {
- padding: 5px 0 10px 0;
- font-size: 13px;
- margin-bottom: 10px;
-}
-.paginator .prev a,
-.paginator .prev a:visited,
-.paginator .next a,
-.paginator .next a:visited {
- background-color: #fff;
- color: #777;
- padding: 2px 4px 3px 4px;
-}
-.paginator a {
- color: #7ea9b3;
-}
-.paginator .prev {
- margin-right: .5em;
-}
-.paginator .next {
- margin-left: .5em;
-}
-.paginator .page a,
-.paginator .page a:visited,
-.paginator .curr {
- padding: .25em;
- background-color: #fff;
- margin: 0em .25em;
- color: #ff;
-}
-.paginator .curr {
- background-color: #8ebcc7;
- color: #fff;
- font-weight: bold;
-}
-.paginator .next a,
-.paginator .prev a {
- color: #7ea9b3;
-}
-.paginator .page a:hover,
-.paginator .curr a:hover,
-.paginator .prev a:hover,
-.paginator .next a:hover {
- color: #8C8C8C;
- background-color: #E1E1E1;
- text-decoration: none;
-}
-.paginator .text {
- color: #777;
- padding: .3em;
-}
-.paginator .paginator-container-left {
- padding: 5px 0 10px 0;
-}
-/* ----- Tags Styles ----- */
-/* tag formatting is also copy-pasted in template
- because it must be the same in the emails
- askbot/models/__init__.py:format_instant_notification_email()
-*/
-/* tag cloud */
-.tag-size-1 {
- font-size: 12px;
-}
-.tag-size-2 {
- font-size: 13px;
-}
-.tag-size-3 {
- font-size: 14px;
-}
-.tag-size-4 {
- font-size: 15px;
-}
-.tag-size-5 {
- font-size: 16px;
-}
-.tag-size-6 {
- font-size: 17px;
-}
-.tag-size-7 {
- font-size: 18px;
-}
-.tag-size-8 {
- font-size: 19px;
-}
-.tag-size-9 {
- font-size: 20px;
-}
-.tag-size-10 {
- font-size: 21px;
-}
-ul.tags,
-ul.tags.marked-tags,
-ul#related-tags {
- list-style: none;
- margin: 0;
- padding: 0;
- line-height: 170%;
- display: block;
-}
-ul.tags li {
- float: left;
- display: block;
- margin: 0 8px 8px 0;
- padding: 0;
- height: 20px;
-}
-.wildcard-tags {
- clear: both;
-}
-ul.tags.marked-tags li,
-.wildcard-tags ul.tags li {
- margin-bottom: 5px;
-}
-#tagSelector div.inputs {
- clear: both;
- float: none;
- margin-bottom: 10px;
-}
-.tags-page ul.tags li,
-ul#ab-user-tags li {
- width: 160px;
- margin: 5px;
-}
-ul#related-tags li {
- margin: 0 5px 8px 0;
- float: left;
- clear: left;
-}
-/* .tag-left and .tag-right are for the sliding doors decoration of tags */
-.tag-left {
- cursor: pointer;
- display: block;
- float: left;
- height: 17px;
- margin: 0 5px 0 0;
- padding: 0;
- -webkit-box-shadow: 0px 0px 5px #d3d6d7;
- -moz-box-shadow: 0px 0px 5px #d3d6d7;
- box-shadow: 0px 0px 5px #d3d6d7;
-}
-.tag-right {
- background: #f3f6f6;
- border: #fff 1px solid ;
- border-top: #fff 2px solid;
- outline: #cfdbdb 1px solid;
- /* .box-shadow(0px,1px,0px,#88a8a8);*/
-
- display: block;
- float: left;
- height: 17px;
- line-height: 17px;
- font-weight: normal;
- font-size: 11px;
- padding: 0px 8px 0px 8px;
- text-decoration: none;
- text-align: center;
- white-space: nowrap;
- vertical-align: middle;
- font-family: Arial;
- color: #717179;
-}
-.deletable-tag {
- margin-right: 3px;
- white-space: nowrap;
- border-top-right-radius: 4px;
- border-bottom-right-radius: 4px;
- -moz-border-radius-topright: 4px;
- -moz-border-radius-bottomright: 4px;
- -webkit-border-bottom-right-radius: 4px;
- -webkit-border-top-right-radius: 4px;
-}
-.tags a.tag-right,
-.tags span.tag-right {
- color: #585858;
- text-decoration: none;
-}
-.tags a:hover {
- color: #1A1A1A;
-}
-.users-page h1,
-.tags-page h1,
-.groups-page h1 {
- float: left;
-}
-.main-page h1 {
- margin-right: 5px;
-}
-.delete-icon {
- margin-top: -1px;
- float: left;
- height: 21px;
- width: 18px;
- display: block;
- line-height: 20px;
- text-align: center;
- background: #bbcdcd;
- cursor: default;
- color: #fff;
- border-top: #cfdbdb 1px solid;
- font-family: Arial;
- border-top-right-radius: 4px;
- border-bottom-right-radius: 4px;
- -moz-border-radius-topright: 4px;
- -moz-border-radius-bottomright: 4px;
- -webkit-border-bottom-right-radius: 4px;
- -webkit-border-top-right-radius: 4px;
- text-shadow: 0px 1px 0px #7ea0a0;
- -moz-text-shadow: 0px 1px 0px #7ea0a0;
- -webkit-text-shadow: 0px 1px 0px #7ea0a0;
-}
-.delete-icon:hover {
- background: #b32f2f;
-}
-.tag-number {
- font-weight: normal;
- float: left;
- font-size: 16px;
- color: #5d5d5d;
-}
-.badges .tag-number {
- float: none;
- display: inline;
- padding-right: 15px;
-}
-/* ----- Ask and Edit Question Form template----- */
-.section-title {
- color: #7ea9b3;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- font-weight: bold;
- font-size: 24px;
-}
-#fmask {
- margin-bottom: 30px;
- width: 100%;
-}
-#askFormBar {
- display: inline-block;
- padding: 4px 7px 0px 0px;
- margin-top: 0px;
-}
-#askFormBar p {
- margin: 0 0 5px 0;
- font-size: 14px;
- color: #525252;
- line-height: 1.4;
-}
-#askFormBar .questionTitleInput {
- font-size: 24px;
- line-height: 24px;
- height: 36px;
- margin: 0px;
- padding: 0px 0 0 5px;
- border: #cce6ec 3px solid;
- width: 719px;
-}
-.ask-page div#question-list,
-.edit-question-page div#question-list {
- border-bottom: #f0f0ec 1px solid;
- float: none;
-}
-.ask-page div#question-list a,
-.edit-question-page div#question-list a {
- line-height: 30px;
-}
-.ask-page div#question-list h2,
-.edit-question-page div#question-list h2 {
- font-size: 13px;
- padding-bottom: 0;
- color: #1b79bd;
- border-top: #f0f0ec 1px solid;
- border-left: #f0f0ec 1px solid;
- height: 30px;
- line-height: 30px;
- font-weight: normal;
-}
-.ask-page div#question-list span,
-.edit-question-page div#question-list span {
- width: 28px;
- height: 26px;
- line-height: 26px;
- text-align: center;
- margin-right: 10px;
- float: left;
- display: block;
- color: #fff;
- background: #b8d0d5;
- border-radius: 3px;
- -ms-border-radius: 3px;
- -moz-border-radius: 3px;
- -webkit-border-radius: 3px;
- -khtml-border-radius: 3px;
-}
-.ask-page label,
-.edit-question-page label {
- color: #525252;
- font-size: 13px;
-}
-.ask-page #id_tags,
-.edit-question-page #id_tags {
- border: #cce6ec 3px solid;
- height: 25px;
- padding-left: 5px;
- width: 395px;
- font-size: 14px;
-}
-.title-desc {
- color: #707070;
- font-size: 13px;
- margin-bottom: 5px;
-}
-#fmanswer input.submit,
-.ask-page input.submit,
-.edit-question-page input.submit {
- float: left;
- font-weight: normal;
- margin-top: 3px;
- width: 160px;
- height: 34px;
- font-size: 21px;
- text-align: center;
- text-decoration: none;
- cursor: pointer;
- color: #4a757f;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
- border-top: #eaf2f3 1px solid;
- background-color: #d1e2e5;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
- background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- border-radius: 4px;
- -ms-border-radius: 4px;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- -khtml-border-radius: 4px;
- -webkit-box-shadow: 1px 1px 2px #636363;
- -moz-box-shadow: 1px 1px 2px #636363;
- box-shadow: 1px 1px 2px #636363;
- margin-right: 7px;
-}
-#fmanswer input.submit:hover,
-.ask-page input.submit:hover,
-.edit-question-page input.submit:hover {
- background-color: #cde5e9;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
- background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- text-decoration: none;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
-}
-.wmd-container {
- border: #cce6ec 3px solid;
-}
-.users-page .wmd-container {
- width: 200px;
-}
-.ask-page .wmd-container,
-.question-page .wmd-container,
-.edit-question-page .wmd-container,
-.edit-answer-page .wmd-container {
- width: 723px;
-}
-.ask-page #editor,
-.question-page #editor,
-.edit-question-page #editor,
-.edit-answer-page #editor {
- width: 710px;
- padding: 6px;
-}
-#editor {
- /* adjustment for editor preview */
-
- display: block;
- font-size: 100%;
- min-height: 200px;
- line-height: 18px;
- margin: 0;
- border: 0;
-}
-.users-page #editor {
- width: 192px;
-}
-#id_title {
- width: 100%;
-}
-.wmd-preview {
- margin: 0;
- padding: 5px;
- background-color: #F5F5F5;
- min-height: 20px;
- overflow: auto;
- font-size: 13px;
- font-family: Arial;
-}
-.wmd-preview p {
- margin-bottom: 14px;
- line-height: 1.4;
- font-size: 14px;
-}
-.wmd-preview p:last-child {
- margin-bottom: 0;
-}
-.wmd-preview pre {
- background-color: #E7F1F8;
-}
-.wmd-preview blockquote {
- background-color: #eee;
-}
-.wmd-preview IMG {
- max-width: 600px;
-}
-.user-page .wmd-buttons {
- width: 725px;
-}
-.preview-toggle {
- width: 100%;
- color: #b6a475;
- /*letter-spacing:1px;*/
-
- text-align: left;
-}
-.preview-toggle span:hover {
- cursor: pointer;
-}
-.after-editor {
- margin-top: 15px;
- margin-bottom: 15px;
-}
-.checkbox {
- margin-left: 5px;
- font-weight: normal;
- cursor: help;
-}
-.question-options {
- margin-top: 1px;
- color: #666;
- line-height: 13px;
- margin-bottom: 5px;
-}
-.question-options label {
- vertical-align: text-bottom;
-}
-.edit-content-html {
- border-top: 1px dotted #D8D2A9;
- border-bottom: 1px dotted #D8D2A9;
- margin: 5px 0 5px 0;
-}
-.edit-question-page,
-#fmedit,
-.wmd-preview {
- color: #525252;
-}
-.edit-question-page #id_revision,
-#fmedit #id_revision,
-.wmd-preview #id_revision {
- font-size: 14px;
- margin-top: 5px;
- margin-bottom: 5px;
-}
-.edit-question-page #id_title,
-#fmedit #id_title,
-.wmd-preview #id_title {
- font-size: 24px;
- line-height: 24px;
- height: 36px;
- margin: 0px;
- padding: 0px 0 0 5px;
- border: #cce6ec 3px solid;
- width: 719px;
- margin-bottom: 10px;
-}
-.edit-question-page #id_summary,
-#fmedit #id_summary,
-.wmd-preview #id_summary {
- border: #cce6ec 3px solid;
- height: 25px;
- padding-left: 5px;
- width: 395px;
- font-size: 14px;
-}
-.edit-question-page .title-desc,
-#fmedit .title-desc,
-.wmd-preview .title-desc {
- margin-bottom: 10px;
-}
-/* ----- Question template ----- */
-.question-page h1 {
- padding-top: 0px;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
-}
-.question-page h1 a {
- color: #464646;
- font-size: 30px;
- font-weight: normal;
- line-height: 1;
-}
-.question-page p.rss {
- float: none;
- clear: both;
- padding: 3px 0 0 23px;
- font-size: 15px;
- width: 110px;
- background-position: center left;
- margin-left: 0px !important;
-}
-.question-page p.rss a {
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- vertical-align: top;
-}
-.question-page .question-content {
- float: right;
- width: 682px;
- margin-bottom: 10px;
-}
-.question-page #question-table {
- float: left;
- border-top: #f0f0f0 1px solid;
-}
-.question-page #question-table,
-.question-page .answer-table {
- margin: 6px 0 6px 0;
- border-spacing: 0px;
- width: 670px;
- padding-right: 10px;
-}
-.question-page .answer-table {
- margin-top: 0px;
- border-bottom: 1px solid #D4D4D4;
- float: right;
-}
-.question-page .answer-table td,
-.question-page #question-table td {
- width: 20px;
- vertical-align: top;
-}
-.question-page .question-body,
-.question-page .answer-body {
- overflow: auto;
- margin-top: 10px;
- font-family: Arial;
- color: #4b4b4b;
-}
-.question-page .question-body p,
-.question-page .answer-body p {
- margin-bottom: 14px;
- line-height: 1.4;
- font-size: 14px;
- padding: 0px 5px 5px 0px;
-}
-.question-page .question-body a,
-.question-page .answer-body a {
- color: #1b79bd;
-}
-.question-page .question-body li,
-.question-page .answer-body li {
- margin-bottom: 7px;
-}
-.question-page .question-body IMG,
-.question-page .answer-body IMG {
- max-width: 600px;
-}
-.question-page .post-update-info-container {
- float: right;
- width: 175px;
-}
-.question-page .post-update-info {
- background: #ffffff url(../images/background-user-info.png) repeat-x bottom;
- float: right;
- font-size: 9px;
- font-family: Arial;
- width: 158px;
- padding: 4px;
- margin: 0px 0px 5px 5px;
- line-height: 14px;
- border-radius: 4px;
- -ms-border-radius: 4px;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- -khtml-border-radius: 4px;
- -webkit-box-shadow: 0px 2px 1px #bfbfbf;
- -moz-box-shadow: 0px 2px 1px #bfbfbf;
- box-shadow: 0px 2px 1px #bfbfbf;
-}
-.question-page .post-update-info p {
- line-height: 13px;
- font-size: 11px;
- margin: 0 0 2px 1px;
- padding: 0;
-}
-.question-page .post-update-info a {
- color: #444;
-}
-.question-page .post-update-info .gravatar {
- float: left;
- margin-right: 4px;
-}
-.question-page .post-update-info p.tip {
- color: #444;
- line-height: 13px;
- font-size: 10px;
-}
-.question-page .post-controls {
- font-size: 11px;
- line-height: 12px;
- min-width: 200px;
- padding-left: 5px;
- text-align: right;
- clear: left;
- float: right;
- margin-top: 10px;
- margin-bottom: 8px;
-}
-.question-page .post-controls a {
- color: #777;
- padding: 0px 7px 3px 18px;
- cursor: pointer;
- border: none;
- font-size: 12px;
- font-family: Arial;
- text-decoration: none;
- height: 18px;
- display: block;
- float: right;
- line-height: 18px;
- margin-top: -2px;
- margin-left: 4px;
-}
-.question-page .post-controls a:hover {
- background-color: #f5f0c9;
- border-radius: 3px;
- -ms-border-radius: 3px;
- -moz-border-radius: 3px;
- -webkit-border-radius: 3px;
- -khtml-border-radius: 3px;
-}
-.question-page .post-controls .sep {
- color: #ccc;
- float: right;
- height: 18px;
- font-size: 18px;
-}
-.question-page .post-controls .question-delete,
-.question-page .answer-controls .question-delete {
- background: url(../images/delete.png) no-repeat center left;
- padding-left: 11px;
-}
-.question-page .post-controls .question-flag,
-.question-page .answer-controls .question-flag {
- background: url(../images/flag.png) no-repeat center left;
-}
-.question-page .post-controls .question-edit,
-.question-page .answer-controls .question-edit {
- background: url(../images/edit2.png) no-repeat center left;
-}
-.question-page .post-controls .question-retag,
-.question-page .answer-controls .question-retag {
- background: url(../images/retag.png) no-repeat center left;
-}
-.question-page .post-controls .question-close,
-.question-page .answer-controls .question-close {
- background: url(../images/close.png) no-repeat center left;
-}
-.question-page .post-controls .permant-link,
-.question-page .answer-controls .permant-link {
- background: url(../images/link.png) no-repeat center left;
-}
-.question-page .tabBar {
- width: 100%;
-}
-.question-page #questionCount {
- float: left;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- line-height: 15px;
-}
-.question-page .question-img-upvote,
-.question-page .question-img-downvote,
-.question-page .answer-img-upvote,
-.question-page .answer-img-downvote {
- width: 25px;
- height: 20px;
- cursor: pointer;
-}
-.question-page .question-img-upvote,
-.question-page .answer-img-upvote {
- background: url(../images/vote-arrow-up-new.png) no-repeat;
-}
-.question-page .question-img-downvote,
-.question-page .answer-img-downvote {
- background: url(../images/vote-arrow-down-new.png) no-repeat;
-}
-.question-page .question-img-upvote:hover,
-.question-page .question-img-upvote.on,
-.question-page .answer-img-upvote:hover,
-.question-page .answer-img-upvote.on {
- background: url(../images/vote-arrow-up-on-new.png) no-repeat;
-}
-.question-page .question-img-downvote:hover,
-.question-page .question-img-downvote.on,
-.question-page .answer-img-downvote:hover,
-.question-page .answer-img-downvote.on {
- background: url(../images/vote-arrow-down-on-new.png) no-repeat;
-}
-.question-page #fmanswer_button {
- margin: 8px 0px;
-}
-.question-page #fmanswer_button.answer-own-question {
- width: 150px;
-}
-.question-page .question-img-favorite:hover {
- background: url(../images/vote-favorite-on.png);
-}
-.question-page div.comments {
- padding: 0;
-}
-.question-page #comment-title {
- font-weight: bold;
- font-size: 23px;
- color: #7ea9b3;
- width: 200px;
- float: left;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
-}
-.question-page .comments {
- font-size: 12px;
- clear: both;
-}
-.question-page .comments div.controls {
- clear: both;
- float: left;
- width: 100%;
- margin: 3px 0 20px 5px;
-}
-.question-page .comments .controls a {
- color: #988e4c;
- padding: 0 3px 2px 22px;
- font-family: Arial;
- font-size: 13px;
- background: url(../images/comment.png) no-repeat center left;
-}
-.question-page .comments .controls a:hover {
- background-color: #f5f0c9;
- text-decoration: none;
-}
-.question-page .comments .button {
- color: #988e4c;
- font-size: 11px;
- padding: 3px;
- cursor: pointer;
-}
-.question-page .comments a {
- background-color: inherit;
- color: #1b79bd;
- padding: 0;
-}
-.question-page .comments form.post-comments {
- margin: 3px 26px 0 42px;
-}
-.question-page .comments form.post-comments textarea {
- font-size: 13px;
- line-height: 1.3;
-}
-.question-page .comments textarea {
- height: 42px;
- width: 100%;
- margin: 7px 0 5px 1px;
- font-family: Arial;
- outline: none;
- overflow: auto;
- font-size: 12px;
- line-height: 140%;
- padding-left: 2px;
- padding-top: 3px;
- border: #cce6ec 3px solid;
-}
-.question-page .comments input {
- margin-left: 10px;
- margin-top: 1px;
- vertical-align: top;
- width: 100px;
-}
-.question-page .comments button {
- line-height: 25px;
- margin-bottom: 5px;
- width: 100px;
- height: 27px;
- font-size: 12px;
- text-align: center;
- text-decoration: none;
- cursor: pointer;
- color: #4a757f;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
- border-top: #eaf2f3 1px solid;
- background-color: #d1e2e5;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
- background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- border-radius: 4px;
- -ms-border-radius: 4px;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- -khtml-border-radius: 4px;
- -webkit-box-shadow: 1px 1px 2px #636363;
- -moz-box-shadow: 1px 1px 2px #636363;
- box-shadow: 1px 1px 2px #636363;
- font-family: Arial;
- font-weight: bold;
-}
-.question-page .comments button:hover {
- background-color: #cde5e9;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
- background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- text-decoration: none;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
-}
-.question-page .comments .counter {
- display: inline-block;
- width: 245px;
- float: right;
- color: #b6a475 !important;
- vertical-align: top;
- font-family: Arial;
- float: right;
- text-align: right;
-}
-.question-page .comments .comment {
- border-bottom: 1px solid #edeeeb;
- clear: both;
- margin: 0;
- margin-top: 8px;
- padding-bottom: 4px;
- overflow: auto;
- font-family: Arial;
- font-size: 11px;
- min-height: 25px;
- background: #ffffff url(../images/comment-background.png) bottom repeat-x;
- border-radius: 5px;
- -ms-border-radius: 5px;
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
- -khtml-border-radius: 5px;
-}
-.question-page .comments div.comment:hover {
- background-color: #efefef;
-}
-.question-page .comments a.author {
- background-color: inherit;
- color: #1b79bd;
- padding: 0;
-}
-.question-page .comments a.author:hover {
- text-decoration: underline;
-}
-.question-page .comments span.delete-icon {
- background: url(../images/close-small.png) no-repeat;
- border: 0;
- width: 14px;
- height: 14px;
-}
-.question-page .comments span.delete-icon:hover {
- border: #BC564B 2px solid;
- border-radius: 10px;
- -ms-border-radius: 10px;
- -moz-border-radius: 10px;
- -webkit-border-radius: 10px;
- -khtml-border-radius: 10px;
- margin: -3px 0px 0px -2px;
-}
-.question-page .comments .content {
- margin-bottom: 7px;
-}
-.question-page .comments .comment-votes {
- float: left;
- width: 37px;
- line-height: 130%;
- padding: 6px 5px 6px 3px;
-}
-.question-page .comments .comment-body {
- line-height: 1.3;
- margin: 3px 26px 0 46px;
- padding: 5px 3px;
- color: #666;
- font-size: 13px;
-}
-.question-page .comments .comment-body .edit {
- padding-left: 6px;
-}
-.question-page .comments .comment-body p {
- font-size: 13px;
- line-height: 1.3;
- margin-bottom: 3px;
- padding: 0;
-}
-.question-page .comments .comment-delete {
- float: right;
- width: 14px;
- line-height: 130%;
- padding: 8px 6px;
-}
-.question-page .comments .upvote {
- margin: 0px;
- padding-right: 17px;
- padding-top: 2px;
- text-align: right;
- height: 20px;
- font-size: 13px;
- font-weight: bold;
- color: #777;
-}
-.question-page .comments .upvote.upvoted {
- color: #d64000;
-}
-.question-page .comments .upvote.hover {
- background: url(../images/go-up-grey.png) no-repeat;
- background-position: right 1px;
-}
-.question-page .comments .upvote:hover {
- background: url(../images/go-up-orange.png) no-repeat;
- background-position: right 1px;
-}
-.question-page .comments .help-text {
- float: right;
- text-align: right;
- color: gray;
- margin-bottom: 0px;
- margin-top: 0px;
- line-height: 50%;
-}
-.question-page #questionTools {
- font-size: 22px;
- margin-top: 11px;
- text-align: left;
-}
-.question-page .question-status {
- margin-top: 10px;
- margin-bottom: 15px;
- padding: 20px;
- background-color: #fef7cc;
- text-align: center;
- border: #e1c04a 1px solid;
-}
-.question-page .question-status h3 {
- font-size: 20px;
- color: #707070;
- font-weight: normal;
-}
-.question-page .vote-buttons {
- float: left;
- text-align: center;
- padding-top: 2px;
- margin: 10px 10px 0px 3px;
- /* smalls IE fixes */
-
- *margin: 0;
- *height: 210px;
- *width: 30px;
-}
-.question-page .vote-buttons IMG {
- cursor: pointer;
-}
-.question-page .vote-number {
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- padding: 0px 0 5px 0;
- font-size: 25px;
- font-weight: bold;
- color: #777;
-}
-.question-page .vote-buttons .notify-sidebar {
- text-align: left;
- width: 120px;
-}
-.question-page .vote-buttons .notify-sidebar label {
- vertical-align: top;
-}
-.question-page .tabBar-answer {
- margin-bottom: 15px;
- padding-left: 7px;
- width: 723px;
- margin-top: 10px;
-}
-.question-page .answer .vote-buttons {
- float: left;
-}
-.question-page .accepted-answer {
- background-color: #f7fecc;
- border-bottom-color: #9BD59B;
-}
-.question-page .accepted-answer .vote-buttons {
- width: 27px;
- margin-right: 10px;
- margin-top: 10px;
-}
-.question-page .answer .post-update-info a {
- color: #444444;
-}
-.question-page .answered {
- background: #CCC;
- color: #999;
-}
-.question-page .answered-accepted {
- background: #DCDCDC;
- color: #763333;
-}
-.question-page .answered-accepted strong {
- color: #E1E818;
-}
-.question-page .answered-by-owner {
- background: #F1F1FF;
-}
-.question-page .answered-by-owner .comments .button {
- background-color: #E6ECFF;
-}
-.question-page .answered-by-owner .comments {
- background-color: #E6ECFF;
-}
-.question-page .answered-by-owner .vote-buttons {
- margin-right: 10px;
-}
-.question-page .answer-img-accept {
- background: url(../images/vote-accepted.png);
- width: 23px;
- height: 23px;
-}
-.question-page .accepted-answer .answer-img-accept,
-.question-page .answer-img-accept:hover {
- background: url(../images/vote-accepted-on.png);
-}
-.question-page .answer-body a {
- color: #1b79bd;
-}
-.question-page .answer-body li {
- margin-bottom: 0.7em;
-}
-.question-page #fmanswer {
- color: #707070;
- line-height: 1.2;
- margin-top: 10px;
-}
-.question-page #fmanswer h2 {
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- color: #7ea9b3;
- font-size: 24px;
-}
-.question-page #fmanswer label {
- font-size: 13px;
-}
-.question-page .message {
- padding: 5px;
- margin: 0px 0 10px 0;
-}
-.facebook-share.icon,
-.twitter-share.icon,
-.linkedin-share.icon,
-.identica-share.icon {
- background: url(../images/socialsprite.png) no-repeat;
- display: block;
- text-indent: -100em;
- height: 25px;
- width: 25px;
- margin-bottom: 3px;
-}
-.facebook-share.icon:hover,
-.twitter-share.icon:hover,
-.linkedin-share.icon:hover,
-.identica-share.icon:hover {
- opacity: 0.8;
- filter: alpha(opacity=80);
-}
-.facebook-share.icon {
- background-position: -26px 0px;
-}
-.identica-share.icon {
- background-position: -78px 0px;
-}
-.twitter-share.icon {
- margin-top: 10px;
- background-position: 0px 0px;
-}
-.linkedin-share.icon {
- background-position: -52px 0px;
-}
-/* -----Content pages, Login, About, FAQ, Users----- */
-.openid-signin,
-.meta,
-.user-profile-edit-page {
- font-size: 13px;
- line-height: 1.3;
- color: #525252;
-}
-.openid-signin p,
-.meta p,
-.user-profile-edit-page p {
- font-size: 13px;
- color: #707070;
- line-height: 1.3;
- font-family: Arial;
- color: #525252;
- margin-bottom: 12px;
-}
-.openid-signin h2,
-.meta h2,
-.user-profile-edit-page h2 {
- color: #525252;
- padding-left: 0px;
- font-size: 16px;
-}
-.openid-signin form,
-.meta form,
-.users-page form,
-.user-profile-edit-page form,
-.user-profile-page form {
- margin-bottom: 15px;
-}
-.openid-signin input[type="text"],
-.meta input[type="text"],
-.users-page input[type="text"],
-.user-profile-edit-page input[type="text"],
-.user-profile-page input[type="text"],
-.openid-signin input[type="password"],
-.meta input[type="password"],
-.users-page input[type="password"],
-.user-profile-edit-page input[type="password"],
-.user-profile-page input[type="password"],
-.openid-signin select,
-.meta select,
-.users-page select,
-.user-profile-edit-page select,
-.user-profile-page select {
- border: #cce6ec 3px solid;
- height: 25px;
- padding-left: 5px;
- width: 395px;
- font-size: 14px;
-}
-.openid-signin select,
-.meta select,
-.users-page select,
-.user-profile-edit-page select,
-.user-profile-page select {
- width: 405px;
- height: 30px;
-}
-.openid-signin textarea,
-.meta textarea,
-.users-page textarea,
-.user-profile-edit-page textarea,
-.user-profile-page textarea {
- border: #cce6ec 3px solid;
- padding-left: 5px;
- padding-top: 5px;
- width: 395px;
- font-size: 14px;
-}
-.openid-signin input.submit,
-.meta input.submit,
-.users-page input.submit,
-.user-profile-edit-page input.submit,
-.user-profile-page input.submit {
- font-weight: normal;
- margin: 5px 0px;
- width: 100px;
- height: 26px;
- font-size: 15px;
- text-align: center;
- text-decoration: none;
- cursor: pointer;
- color: #4a757f;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
- border-top: #eaf2f3 1px solid;
- background-color: #d1e2e5;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
- background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- border-radius: 4px;
- -ms-border-radius: 4px;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- -khtml-border-radius: 4px;
- -webkit-box-shadow: 1px 1px 2px #636363;
- -moz-box-shadow: 1px 1px 2px #636363;
- box-shadow: 1px 1px 2px #636363;
- font-family: Arial;
-}
-.openid-signin input.submit:hover,
-.meta input.submit:hover,
-.users-page input.submit:hover,
-.user-profile-edit-page input.submit:hover,
-.user-profile-page input.submit:hover {
- background-color: #cde5e9;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
- background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- text-decoration: none;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
-}
-.openid-signin .cancel,
-.meta .cancel,
-.users-page .cancel,
-.user-profile-edit-page .cancel,
-.user-profile-page .cancel {
- background: url(../images/small-button-cancel.png) repeat-x top !important;
- color: #525252 !important;
-}
-.openid-signin .cancel:hover,
-.meta .cancel:hover,
-.users-page .cancel:hover,
-.user-profile-edit-page .cancel:hover,
-.user-profile-page .cancel:hover {
- background: url(../images/small-button-cancel.png) repeat-x bottom !important;
-}
-.openid-signin form {
- margin-bottom: 5px;
-}
-#email-input-fs,
-#local_login_buttons,
-#password-fs,
-#openid-fs {
- margin-top: 10px;
-}
-#email-input-fs #id_email,
-#local_login_buttons #id_email,
-#password-fs #id_email,
-#openid-fs #id_email,
-#email-input-fs #id_username,
-#local_login_buttons #id_username,
-#password-fs #id_username,
-#openid-fs #id_username,
-#email-input-fs #id_password,
-#local_login_buttons #id_password,
-#password-fs #id_password,
-#openid-fs #id_password {
- font-size: 12px;
- line-height: 20px;
- height: 20px;
- margin: 0px;
- padding: 0px 0 0 5px;
- border: #cce6ec 3px solid;
- width: 200px;
-}
-#email-input-fs .submit-b,
-#local_login_buttons .submit-b,
-#password-fs .submit-b,
-#openid-fs .submit-b {
- width: 100px;
- height: 24px;
- font-size: 15px;
- text-align: center;
- text-decoration: none;
- cursor: pointer;
- color: #4a757f;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
- border-top: #eaf2f3 1px solid;
- background-color: #d1e2e5;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
- background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- border-radius: 4px;
- -ms-border-radius: 4px;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- -khtml-border-radius: 4px;
- -webkit-box-shadow: 1px 1px 2px #636363;
- -moz-box-shadow: 1px 1px 2px #636363;
- box-shadow: 1px 1px 2px #636363;
- font-family: Arial;
- font-weight: bold;
- padding-right: 10px;
- border: 0;
-}
-#email-input-fs .submit-b:hover,
-#local_login_buttons .submit-b:hover,
-#password-fs .submit-b:hover,
-#openid-fs .submit-b:hover {
- background-color: #cde5e9;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
- background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- text-decoration: none;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
-}
-.openid-input {
- background: url(../images/openid.gif) no-repeat;
- padding-left: 15px;
- cursor: pointer;
-}
-.openid-login-input {
- background-position: center left;
- background: url(../images/openid.gif) no-repeat 0% 50%;
- padding: 5px 5px 5px 15px;
- cursor: pointer;
- font-family: Trebuchet MS;
- font-weight: 300;
- font-size: 150%;
- width: 500px;
-}
-.openid-login-submit {
- height: 40px;
- width: 80px;
- line-height: 40px;
- cursor: pointer;
- border: 1px solid #777;
- font-weight: bold;
- font-size: 120%;
-}
-/* People page */
-/*.users-page .tabBar{
- width:375px;
-}*/
-.user {
- padding: 5px 10px 5px 0;
- line-height: 140%;
- width: 166px;
- height: 32px;
- margin-bottom: 5px;
-}
-.user .user-micro-info {
- color: #525252;
-}
-.user ul {
- margin: 0;
- list-style-type: none;
-}
-.user .thumb {
- clear: both;
- float: left;
- margin-right: 4px;
- display: inline;
-}
-/* tags page */
-.tabBar-tags {
- width: 270px;
- margin-bottom: 15px;
-}
-/* badges page */
-a.medal {
- font-size: 17px;
- line-height: 250%;
- margin-right: 5px;
- color: #333;
- text-decoration: none;
- background: url(../images/medala.gif) no-repeat;
- border-left: 1px solid #EEE;
- border-top: 1px solid #EEE;
- border-bottom: 1px solid #CCC;
- border-right: 1px solid #CCC;
- padding: 4px 12px 4px 6px;
-}
-a:hover.medal {
- color: #333;
- text-decoration: none;
- background: url(../images/medala_on.gif) no-repeat;
- border-left: 1px solid #E7E296;
- border-top: 1px solid #E7E296;
- border-bottom: 1px solid #D1CA3D;
- border-right: 1px solid #D1CA3D;
-}
-#award-list .user {
- float: left;
- margin: 5px;
-}
-/* profile page */
-.tabBar-profile {
- width: 100%;
- margin-bottom: 15px;
- float: left;
-}
-.user-profile-page {
- font-size: 13px;
- color: #525252;
-}
-.user-profile-page p {
- font-size: 13px;
- line-height: 1.3;
- color: #525252;
-}
-.user-profile-page .avatar img {
- border: #eee 1px solid;
- padding: 5px;
-}
-.user-profile-page h2 {
- padding: 10px 0px 10px 0px;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
-}
-.user-details {
- font-size: 13px;
-}
-.user-details h3 {
- font-size: 16px;
-}
-.user-about {
- background-color: #EEEEEE;
- height: 200px;
- line-height: 20px;
- overflow: auto;
- padding: 10px;
- width: 90%;
-}
-.user-about p {
- font-size: 13px;
-}
-.follow-toggle,
-.submit {
- border: 0 !important;
- font-weight: bold;
- line-height: 26px;
- margin-top: -2px;
- width: 100px;
- height: 26px;
- font-size: 14px;
- text-align: center;
- text-decoration: none;
- cursor: pointer;
- color: #4a757f;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
- border-top: #eaf2f3 1px solid;
- background-color: #d1e2e5;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d1e2e5), color-stop(25%, #d1e2e5), to(#a9c2c7));
- background-image: -webkit-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -moz-linear-gradient(top, #d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -ms-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: -o-linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- background-image: linear-gradient(#d1e2e5, #d1e2e5 25%, #a9c2c7);
- border-radius: 4px;
- -ms-border-radius: 4px;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- -khtml-border-radius: 4px;
- -webkit-box-shadow: 1px 1px 2px #636363;
- -moz-box-shadow: 1px 1px 2px #636363;
- box-shadow: 1px 1px 2px #636363;
-}
-.follow-toggle:hover,
-.submit:hover {
- background-color: #cde5e9;
- background-repeat: no-repeat;
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#cde5e9), color-stop(25%, #cde5e9), to(#94b3ba));
- background-image: -webkit-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -moz-linear-gradient(top, #cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -ms-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: -o-linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- background-image: linear-gradient(#cde5e9, #cde5e9 25%, #94b3ba);
- text-decoration: none;
- text-shadow: 0px 1px 0px #c6d9dd;
- -moz-text-shadow: 0px 1px 0px #c6d9dd;
- -webkit-text-shadow: 0px 1px 0px #c6d9dd;
- text-decoration: none !important;
-}
-.follow-toggle .follow {
- font-color: #000;
- font-style: normal;
-}
-.follow-toggle .unfollow div.unfollow-red {
- display: none;
-}
-.follow-toggle .unfollow:hover div.unfollow-red {
- display: inline;
- color: #fff;
- font-weight: bold;
- color: #A05736;
-}
-.follow-toggle .unfollow:hover div.unfollow-green {
- display: none;
-}
-.count {
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- font-size: 200%;
- font-weight: 700;
- color: #777777;
-}
-.scoreNumber {
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- font-size: 35px;
- font-weight: 800;
- color: #777;
- line-height: 40px;
- /*letter-spacing:0px*/
-
- margin-top: 3px;
-}
-.vote-count {
- font-family: Arial;
- font-size: 160%;
- font-weight: 700;
- color: #777;
-}
-.answer-summary {
- display: block;
- clear: both;
- padding: 3px;
-}
-.answer-votes {
- background-color: #EEEEEE;
- color: #555555;
- float: left;
- font-family: Arial;
- font-size: 15px;
- font-weight: bold;
- height: 17px;
- padding: 2px 4px 5px;
- text-align: center;
- text-decoration: none;
- width: 20px;
- margin-right: 10px;
- border-radius: 4px;
- -ms-border-radius: 4px;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- -khtml-border-radius: 4px;
-}
-.karma-summary {
- padding: 5px;
- font-size: 13px;
-}
-.karma-summary h3 {
- text-align: center;
- font-weight: bold;
- padding: 5px;
-}
-.karma-diagram {
- width: 477px;
- height: 300px;
- float: left;
- margin-right: 10px;
-}
-.karma-details {
- float: right;
- width: 450px;
- height: 250px;
- overflow-y: auto;
- word-wrap: break-word;
-}
-.karma-details p {
- margin-bottom: 10px;
-}
-.karma-gained {
- font-weight: bold;
- background: #eee;
- width: 25px;
- margin-right: 5px;
- color: green;
- padding: 3px;
- display: block;
- float: left;
- text-align: center;
- border-radius: 3px;
- -ms-border-radius: 3px;
- -moz-border-radius: 3px;
- -webkit-border-radius: 3px;
- -khtml-border-radius: 3px;
-}
-.karma-lost {
- font-weight: bold;
- background: #eee;
- width: 25px;
- color: red;
- padding: 3px;
- display: block;
- margin-right: 5px;
- float: left;
- text-align: center;
- border-radius: 3px;
- -ms-border-radius: 3px;
- -moz-border-radius: 3px;
- -webkit-border-radius: 3px;
- -khtml-border-radius: 3px;
-}
-.submit-row {
- margin-bottom: 10px;
-}
-/*----- Revision pages ----- */
-.revision {
- margin: 10px 0 10px 0;
- font-size: 13px;
- color: #525252;
-}
-.revision p {
- font-size: 13px;
- line-height: 1.3;
- color: #525252;
-}
-.revision h3 {
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
- font-size: 21px;
- padding-left: 0px;
-}
-.revision .header {
- background-color: #F5F5F5;
- padding: 5px;
- cursor: pointer;
-}
-.revision .author {
- background-color: #e9f3f5;
-}
-.revision .summary {
- padding: 5px 0 10px 0;
-}
-.revision .summary span {
- background-color: #fde785;
- padding: 6px;
- border-radius: 4px;
- -ms-border-radius: 4px;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- -khtml-border-radius: 4px;
- display: inline;
- -webkit-box-shadow: 1px 1px 4px #cfb852;
- -moz-box-shadow: 1px 1px 4px #cfb852;
- box-shadow: 1px 1px 4px #cfb852;
-}
-.revision .answerbody {
- padding: 10px 0 5px 10px;
-}
-.revision .revision-mark {
- width: 150px;
- text-align: left;
- display: inline-block;
- font-size: 11px;
- overflow: hidden;
-}
-.revision .revision-mark .gravatar {
- float: left;
- margin-right: 4px;
- padding-top: 5px;
-}
-.revision .revision-number {
- font-size: 300%;
- font-weight: bold;
- font-family: sans-serif;
-}
-del,
-del .post-tag {
- color: #C34719;
-}
-ins .post-tag,
-ins p,
-ins {
- background-color: #E6F0A2;
-}
-/* ----- Red Popup notification ----- */
-.vote-notification {
- z-index: 1;
- cursor: pointer;
- display: none;
- position: absolute;
- font-family: Arial;
- font-size: 14px;
- font-weight: normal;
- color: white;
- background-color: #8e0000;
- text-align: center;
- padding-bottom: 10px;
- -webkit-box-shadow: 0px 2px 4px #370000;
- -moz-box-shadow: 0px 2px 4px #370000;
- box-shadow: 0px 2px 4px #370000;
- border-radius: 4px;
- -ms-border-radius: 4px;
- -moz-border-radius: 4px;
- -webkit-border-radius: 4px;
- -khtml-border-radius: 4px;
-}
-.vote-notification h3 {
- background: url(../images/notification.png) repeat-x top;
- padding: 10px 10px 10px 10px;
- font-size: 13px;
- margin-bottom: 5px;
- border-top: #8e0000 1px solid;
- color: #fff;
- font-weight: normal;
- border-top-right-radius: 4px;
- border-top-left-radius: 4px;
- -moz-border-radius-topright: 4px;
- -moz-border-radius-topleft: 4px;
- -webkit-border-top-left-radius: 4px;
- -webkit-border-top-right-radius: 4px;
-}
-.vote-notification a {
- color: #fb7321;
- text-decoration: underline;
- font-weight: bold;
-}
-/* ----- Footer links , check blocks/footer.html----- */
-#ground {
- width: 100%;
- clear: both;
- border-top: 1px solid #000;
- padding: 6px 0 0 0;
- background: #16160f;
- font-size: 16px;
- font-family: 'Yanone Kaffeesatz', Arial, sans-serif;
-}
-#ground p {
- margin-bottom: 0;
-}
-.footer-links {
- color: #EEE;
- text-align: left;
- width: 500px;
- float: left;
-}
-.footer-links a {
- color: #e7e8a8;
-}
-.powered-link {
- width: 500px;
- float: left;
- text-align: left;
-}
-.powered-link a {
- color: #8ebcc7;
-}
-.copyright {
- color: #616161;
- width: 450px;
- float: right;
- text-align: right;
-}
-.copyright a {
- color: #8ebcc7;
-}
-.copyright img.license-logo {
- margin: 6px 0px 20px 10px;
- float: right;
-}
-.notify-me {
- float: left;
-}
-span.text-counter {
- margin-right: 20px;
-}
-span.form-error {
- color: #990000;
- font-weight: normal;
- margin-left: 5px;
-}
-ul.errorlist {
- margin-bottom: 0;
-}
-p.form-item {
- margin: 0px;
-}
-.deleted {
- background: #F4E7E7 none repeat scroll 0 0;
-}
-/* openid styles */
-.form-row {
- line-height: 25px;
-}
-table.form-as-table {
- margin-top: 5px;
-}
-table.form-as-table ul {
- list-style-type: none;
- display: inline;
-}
-table.form-as-table li {
- display: inline;
-}
-table.form-as-table td {
- text-align: right;
-}
-table.form-as-table th {
- text-align: left;
- font-weight: normal;
-}
-table.ab-subscr-form {
- width: 45em;
-}
-table.ab-tag-filter-form {
- width: 45em;
-}
-.submit-row {
- line-height: 30px;
- padding-top: 10px;
- display: block;
- clear: both;
-}
-.errors {
- line-height: 20px;
- color: red;
-}
-.error {
- color: darkred;
- margin: 0;
- font-size: 10px;
-}
-label.retag-error {
- color: darkred;
- padding-left: 5px;
- font-size: 10px;
-}
-.fieldset {
- border: none;
- margin-top: 10px;
- padding: 10px;
-}
-span.form-error {
- color: #990000;
- font-size: 90%;
- font-weight: normal;
- margin-left: 5px;
-}
-/*
-.favorites-count-off {
- color: #919191;
- float: left;
- text-align: center;
-}
-
-.favorites-count {
- color: #D4A849;
- float: left;
- text-align: center;
-}
-*/
-/* todo: get rid of this in html */
-.favorites-empty {
- width: 32px;
- height: 45px;
- float: left;
-}
-.user-info-table {
- margin-bottom: 10px;
- border-spacing: 0;
-}
-/* todo: remove this hack? */
-.user-stats-table .narrow {
- width: 660px;
-}
-.narrow .summary h3 {
- padding: 0px;
- margin: 0px;
-}
-.timeago {
- font-weight: bold;
- text-decoration: none;
-}
-.narrow .tags {
- float: left;
-}
-/* todo: make these more semantic */
-.user-action-1 {
- font-weight: bold;
- color: #333;
-}
-.user-action-2 {
- font-weight: bold;
- color: #CCC;
-}
-.user-action-3 {
- color: #333;
-}
-.user-action-4 {
- color: #333;
-}
-.user-action-5 {
- color: darkred;
-}
-.user-action-6 {
- color: darkred;
-}
-.user-action-7 {
- color: #333;
-}
-.user-action-8 {
- padding: 3px;
- font-weight: bold;
- background-color: #CCC;
- color: #763333;
-}
-.revision-summary {
- background-color: #FFFE9B;
- padding: 2px;
-}
-.question-title-link a {
- font-weight: bold;
- color: #0077CC;
-}
-.answer-title-link a {
- color: #333;
-}
-/* todo: make these more semantic */
-.post-type-1 a {
- font-weight: bold;
-}
-.post-type-3 a {
- font-weight: bold;
-}
-.post-type-5 a {
- font-weight: bold;
-}
-.post-type-2 a {
- color: #333;
-}
-.post-type-4 a {
- color: #333;
-}
-.post-type-6 a {
- color: #333;
-}
-.post-type-8 a {
- color: #333;
-}
-.hilite {
- background-color: #ff0;
-}
-.hilite1 {
- background-color: #ff0;
-}
-.hilite2 {
- background-color: #f0f;
-}
-.hilite3 {
- background-color: #0ff;
-}
-.gold,
-.badge1 {
- color: #FFCC00;
-}
-.silver,
-.badge2 {
- color: #CCCCCC;
-}
-.bronze,
-.badge3 {
- color: #CC9933;
-}
-.score {
- font-weight: 800;
- color: #333;
-}
-a.comment {
- background: #EEE;
- color: #993300;
- padding: 5px;
-}
-a.offensive {
- color: #999;
-}
-.message h1 {
- padding-top: 0px;
- font-size: 15px;
-}
-.message p {
- margin-bottom: 0px;
-}
-p.space-above {
- margin-top: 10px;
-}
-.warning {
- color: red;
-}
-button::-moz-focus-inner {
- padding: 0;
- border: none;
-}
-.submit {
- cursor: pointer;
- /*letter-spacing:1px;*/
-
- background-color: #D4D0C8;
- height: 30px;
- border: 1px solid #777777;
- /* width:100px; */
-
- font-weight: bold;
- font-size: 120%;
-}
-.submit:hover {
- text-decoration: underline;
-}
-.submit.small {
- margin-right: 5px;
- height: 20px;
- font-weight: normal;
- font-size: 12px;
- padding: 1px 5px;
-}
-.submit.small:hover {
- text-decoration: none;
-}
-.question-page a.submit {
- display: -moz-inline-stack;
- display: inline-block;
- line-height: 30px;
- padding: 0 5px;
- *display: inline;
-}
-.noscript {
- position: fixed;
- top: 0px;
- left: 0px;
- width: 100%;
- z-index: 100;
- padding: 5px 0;
- text-align: center;
- font-family: sans-serif;
- font-size: 120%;
- font-weight: Bold;
- color: #FFFFFF;
- background-color: #AE0000;
-}
-.big {
- font-size: 14px;
-}
-.strong {
- font-weight: bold;
-}
-.orange {
- /* used in django.po */
-
- color: #d64000;
- font-weight: bold;
-}
-.grey {
- color: #808080;
-}
-.about div {
- padding: 10px 5px 10px 5px;
- border-top: 1px dashed #aaaaaa;
-}
-.highlight {
- background-color: #FFF8C6;
-}
-.nomargin {
- margin: 0;
-}
-.margin-bottom {
- margin-bottom: 10px;
-}
-.margin-top {
- margin-top: 10px;
-}
-.inline-block {
- display: inline-block;
-}
-.action-status {
- margin: 0;
- border: none;
- text-align: center;
- line-height: 10px;
- font-size: 12px;
- padding: 0;
-}
-.action-status span {
- padding: 3px 5px 3px 5px;
- background-color: #fff380;
- /* nice yellow */
-
- font-weight: normal;
- -moz-border-radius: 5px;
- -khtml-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-.list-table {
- border-spacing: 0;
-}
-.list-table td {
- vertical-align: top;
-}
-/* these need to go */
-table.form-as-table .errorlist {
- display: block;
- margin: 0;
- padding: 0 0 0 5px;
- text-align: left;
- font-size: 10px;
- color: darkred;
-}
-table.form-as-table input {
- display: inline;
- margin-left: 4px;
-}
-table.form-as-table th {
- vertical-align: bottom;
- padding-bottom: 4px;
-}
-.form-row-vertical {
- margin-top: 8px;
- display: block;
-}
-.form-row-vertical label {
- margin-bottom: 3px;
- display: block;
-}
-/* above stuff needs to go */
-.text-align-right {
- text-align: center;
-}
-ul.form-horizontal-rows {
- list-style: none;
- margin: 0;
-}
-ul.form-horizontal-rows li {
- position: relative;
- height: 40px;
-}
-ul.form-horizontal-rows label {
- display: inline-block;
-}
-ul.form-horizontal-rows ul.errorlist {
- list-style: none;
- color: darkred;
- font-size: 10px;
- line-height: 10px;
- position: absolute;
- top: 2px;
- left: 180px;
- text-align: left;
- margin: 0;
-}
-ul.form-horizontal-rows ul.errorlist li {
- height: 10px;
-}
-ul.form-horizontal-rows label {
- position: absolute;
- left: 0px;
- bottom: 6px;
- margin: 0px;
- line-height: 12px;
- font-size: 12px;
-}
-ul.form-horizontal-rows li input {
- position: absolute;
- bottom: 0px;
- left: 180px;
- margin: 0px;
-}
-.narrow .summary {
- float: left;
-}
-.user-profile-tool-links {
- font-weight: bold;
- vertical-align: top;
-}
-ul.post-tags {
- margin-left: 3px;
-}
-ul.post-tags li {
- margin-top: 4px;
- margin-bottom: 3px;
-}
-ul.post-retag {
- margin-bottom: 0px;
- margin-left: 5px;
-}
-ul.post-retag input {
- width: 400px;
- height: 1.5em;
- margin: 3px 0 0 -3px;
-}
-#question-controls .tags {
- margin: 0 0 3px 0;
-}
-#tagSelector {
- padding-bottom: 2px;
- margin-bottom: 0;
-}
-#related-tags {
- padding-left: 3px;
-}
-#hideIgnoredTagsControl {
- margin: 5px 0 0 0;
-}
-#hideIgnoredTagsControl label {
- font-size: 12px;
- color: #666;
-}
-#hideIgnoredTagsCb {
- margin: 0 2px 0 1px;
-}
-#recaptcha_widget_div {
- width: 318px;
- float: left;
- clear: both;
-}
-p.signup_p {
- margin: 20px 0px 0px 0px;
-}
-.simple-subscribe-options ul {
- list-style: none;
- list-style-position: outside;
- margin: 0;
-}
-/* a workaround to set link colors correctly */
-.wmd-preview a {
- color: #1b79bd;
-}
-.wmd-preview li {
- margin-bottom: 7px;
- font-size: 14px;
-}
-.search-result-summary {
- font-weight: bold;
- font-size: 18px;
- line-height: 22px;
- margin: 0px 0px 0px 0px;
- padding: 2px 0 0 0;
- float: left;
-}
-.faq-rep-item {
- text-align: right;
- padding-right: 5px;
-}
-.user-info-table .gravatar {
- margin: 0;
-}
-#responses {
- clear: both;
- line-height: 18px;
- margin-bottom: 15px;
-}
-#responses div.face {
- float: left;
- text-align: center;
- width: 54px;
- padding: 3px;
- overflow: hidden;
-}
-.response-parent {
- margin-top: 18px;
-}
-.response-parent strong {
- font-size: 20px;
-}
-.re {
- min-height: 57px;
- clear: both;
- margin-top: 10px;
-}
-#responses input {
- float: left;
-}
-#re_tools {
- margin-bottom: 10px;
-}
-#re_sections {
- margin-bottom: 6px;
-}
-#re_sections .on {
- font-weight: bold;
-}
-.avatar-page ul {
- list-style: none;
-}
-.avatar-page li {
- display: inline;
-}
-.user-profile-page .avatar p {
- margin-bottom: 0px;
-}
-.user-profile-page .tabBar a#stats {
- margin-left: 0;
-}
-.user-profile-page img.gravatar {
- margin: 2px 0 3px 0;
-}
-.user-profile-page h3 {
- padding: 0;
- margin-top: -3px;
-}
-.userList {
- font-size: 13px;
-}
-img.flag {
- border: 1px solid #eee;
- vertical-align: text-top;
-}
-.main-page img.flag {
- vertical-align: text-bottom;
-}
-/* Pretty printing styles. Used with prettify.js. */
-a.edit {
- padding-left: 3px;
- color: #145bff;
-}
-.str {
- color: #080;
-}
-.kwd {
- color: #008;
-}
-.com {
- color: #800;
-}
-.typ {
- color: #606;
-}
-.lit {
- color: #066;
-}
-.pun {
- color: #660;
-}
-.pln {
- color: #000;
-}
-.tag {
- color: #008;
-}
-/* name conflict here */
-.atn {
- color: #606;
-}
-.atv {
- color: #080;
-}
-.dec {
- color: #606;
-}
-pre.prettyprint {
- clear: both;
- padding: 3px;
- border: 0px solid #888;
-}
-@media print {
- .str {
- color: #060;
- }
- .kwd {
- color: #006;
- font-weight: bold;
- }
- .com {
- color: #600;
- font-style: italic;
- }
- .typ {
- color: #404;
- font-weight: bold;
- }
- .lit {
- color: #044;
- }
- .pun {
- color: #440;
- }
- .pln {
- color: #000;
- }
- .tag {
- color: #006;
- font-weight: bold;
- }
- .atn {
- color: #404;
- }
- .atv {
- color: #060;
- }
-}
-#leading-sidebar {
- float: left;
-}
-/* language-specific fixes */
-body.lang-es #searchBar {
- width: 398px;
-}
-body.lang-es #searchBar .searchInput {
- width: 337px;
-}
-body.lang-es #searchBar .searchInputCancelable {
- width: 302px;
-}
-body.anon.lang-es #searchBar {
- width: 485px;
-}
-body.anon.lang-es #searchBar .searchInput {
- width: 425px;
-}
-body.anon.lang-es #searchBar .searchInputCancelable {
- width: 390px;
-}
-/* user groups */
-#user-groups ul {
- margin-bottom: 0px;
-}
-#user-groups .delete-icon {
- float: none;
- display: inline;
- color: #525252;
- padding: 0 3px 0 3px;
- background: #ccc;
- border-radius: 4px;
- line-height: inherit;
- -moz-border-radius: 4px;
- -khtml-border-radius: 4px;
- -webkit-border-radius: 4px;
-}
-#user-groups .delete-icon:hover {
- color: white;
- background: #b32f2f;
-}
-.users-page .wmd-prompt-dialog {
- background: #ccc;
-}
-.group-wiki .content > p:last-child {
- margin-bottom: 5px;
-}
-.group-wiki .group-logo {
- float: left;
- margin: 0 5px 3px 0;
-}
-.group-wiki .follow-toggle.group-join-btn {
- width: 150px;
- margin: 4px auto 10px auto;
- display: block;
-}
-.group-wiki .controls {
- margin: 0 0 10px 0;
-}
-img.group-logo {
- height: 60px;
- /* important to align with the line spacing */
-
-}
-#groups-list {
- margin-left: 0px;
-}
-#groups-list .group-name {
- padding-right: 20px;
-}
-#groups-list td {
- padding-bottom: 5px;
-}
-#reject-edit-modal input,
-#reject-edit-modal textarea {
- width: 514px;
-}
-input.tipped-input,
-textarea.tipped-input {
- padding-left: 5px;
-}
-.tipped-input.blank {
- color: #707070;
-}
-.select-box {
- margin: 0;
-}
-.select-box li {
- list-style-type: none;
- list-style-position: inside;
- padding-left: 7px;
- font-size: 14px;
- line-height: 25px;
-}
-.select-box li.selected,
-.select-box li.selected:hover {
- background-color: #fcf8e3;
- color: #c09853;
-}
-.select-box li:hover {
- background-color: #cecece;
- color: white;
-}
-/* fixes for bootstrap */
-.caret {
- margin-bottom: 7px;
-}
-.btn-group {
- text-align: left;
-}
-.btn-toolbar {
- margin: 0;
-}
-.modal-footer {
- text-align: left;
-}
-.modal p {
- font-size: 14px;
-}
-.modal-body > textarea {
- width: 515px;
- margin-bottom: 0px;
-}
diff --git a/askbot/skins/default/media/style/style.less b/askbot/skins/default/media/style/style.less
deleted file mode 100644
index ea404391..00000000
--- a/askbot/skins/default/media/style/style.less
+++ /dev/null
@@ -1,3513 +0,0 @@
-@import url(jquery.autocomplete.css);
-@import "lib_style.less"; /* Library of predifined less functions styles */
-
-/* ----- General HTML Styles----- */
-
-body {
- background: #FFF;
- font-size: 14px;
- line-height: 150%;
- margin: 0;
- padding: 0;
- color: #000;
- font-family:@body-font;
-}
-
-div {
- margin: 0 auto;
- padding: 0;
-}
-
-h1, h2, h3, h4, h5, h6, ul, li, dl, dt, dd, form, img, p {
- margin: 0;
- padding: 0;
- border: none;
-}
-
-label {
- vertical-align: middle;
-}
-
-hr {
- border: none;
- border-top: 1px dashed #ccccce;
-}
-
-input, select {
- vertical-align: middle;
- font-family: Trebuchet MS, "segoe ui", Helvetica, Tahoma, Verdana, MingLiu, PMingLiu, Arial, sans-serif;
- margin-left:0px;
-}
-
-textarea:focus, input:focus{
- outline: none;
-}
-
-iframe {
- border: none;
-}
-
-p {
- font-size: 14px;
- line-height: 140%;
- margin-bottom: 6px;
-}
-
-a {
- color:@link;
- text-decoration: none;
- cursor: pointer;
-}
-
-h2 {
- font-size: 21px;
- padding: 3px 0 3px 5px;
-}
-
-h3 {
- font-size: 19px;
- padding: 3px 0 3px 5px;
-}
-
-ul {
- list-style: disc;
- margin-left: 20px;
- padding-left: 0px;
- margin-bottom: 1em;
-}
-
-ol {
- list-style: decimal;
- margin-left: 30px;
- margin-bottom: 1em;
- padding-left: 0px;
-}
-
-td ul {
- vertical-align: middle;
-}
-
-li input {
- margin: 3px 3px 4px 3px;
-}
-
-pre {
- font-family: Consolas, Monaco, Liberation Mono, Lucida Console, Monospace;
- font-size: 100%;
- margin-bottom: 10px;
- /*overflow: auto;*/
- background-color: #F5F5F5;
- padding-left: 5px;
- padding-top: 5px;
- /*width: 671px;*/
- padding-bottom: 20px ! ie7;
-}
-
-code {
- font-family: Consolas, Monaco, Liberation Mono, Lucida Console, Monospace;
- font-size: 100%;
-
-}
-
-blockquote {
- margin-bottom: 10px;
- margin-right: 15px;
- padding: 10px 0px 1px 10px;
- background-color: #F5F5F5;
-}
-
-/* http://pathfindersoftware.com/2007/09/developers-note-2/ */
-* html .clearfix,
-* html .paginator {
- height: 1;
- overflow: visible;
-}
-+ html .clearfix,
-+ html .paginator {
- min-height: 1%;
-}
-.clearfix:after,
-.paginator:after {
- clear: both;
- content:".";
- display:block;
- height: 0;
- visibility: hidden;
-}
-
-.badges a {
- color: #763333;
- text-decoration: underline;
-}
-
-a:hover {
- text-decoration: underline;
-}
-
-.badge-context-toggle.active {
- cursor: pointer;
- text-decoration: underline;
-}
-
-h1 {
- font-size: 24px;
- padding: 0px 0 5px 0px;
-}
-
-
-/* ----- Extra space above for messages ----- */
-
-body.user-messages {
- margin-top: 2.4em;
-}
-
-/* ----- Custom positions ----- */
-
-.left{float:left}
-.right{float:right}
-.clean{clear:both}
-.center{
- margin: 0 auto;
- padding: 0;
-}
-
-
-/* ----- Notify message bar , check blocks/system_messages.html ----- */
-
-.notify {
- position: fixed;
- top: 0px;
- left: 0px;
- width: 100%;
- z-index: 100;
- padding: 0;
- text-align: center;
- background-color: #f5dd69;
- border-top:#fff 1px solid;
- font-family:@main-font;
-
- p.notification {
- margin-top: 6px;
- margin-bottom: 6px;
- font-size: 16px;
- color:#424242
- }
-}
-
-#closeNotify {
- position: absolute;
- right: 5px;
- top: 7px;
- color: #735005;
- text-decoration: none;
- line-height: 18px;
- .sprites(-6px,-5px);
- cursor: pointer;
- width:20px;
- height:20px;
-}
-
-#closeNotify:hover {
- .sprites(-26px,-5px);
-}
-
-/* ----- Header, check blocks/header.html ----- */
-
-#header {
- margin-top: 0px;
- background: @header-color;
- font-family:@main-font;
-}
-
-.content-wrapper {/* wrapper positioning class */
- width: 960px;
- margin: auto;
- position:relative;
-}
-
-#logo img{
- padding: 5px 0px 5px 0px;
- height: 75px;
- width: auto;
- float: left;
-}
-
-#userToolsNav {/* Navigation bar containing login link or user information, check widgets/user_navigation.html*/
- height: 20px;
- padding-bottom:5px;
-
- a {
- height: 35px;
- text-align: right;
- margin-left: 20px;
- text-decoration: underline;
- color:#d0e296;
- font-size:16px;
- }
-
- a:first-child {
- margin-left: 0;
- }
-
- a#ab-responses {
- margin-left: 3px;
- }
-
- .user-info,.user-micro-info{
- color:#b5b593;
- }
-
- a img {
- vertical-align:middle;
- margin-bottom:2px;
- }
-
- .user-info a {
- margin: 0;
- text-decoration: none;
- }
-}
-
-#metaNav {/* Top Navigation bar containing links for tags, people and badges, check widgets/header.html */
- float: right;/* for #header.with-logo it is modified */
-
- a {
- color: #e2e2ae;
- padding: 0px 0px 0px 35px;
- height: 25px;
- line-height: 30px;
- margin:5px 0px 0px 10px;
- font-size: 18px;
- font-weight: 100;
- text-decoration: none;
- display: block;
- float: left;
- }
-
- a:hover {
- text-decoration: underline;
- }
-
- a.on {
- font-weight:bold;
- color: #FFF;
- text-decoration: none;
- }
-
- a.special {
- font-size: 18px;
- color: #B02B2C;
- font-weight: bold;
- text-decoration: none;
- }
-
- a.special:hover {
- text-decoration: underline;
- }
-
- #navTags{
- .sprites(-50px,-5px)
- }
-
- #navUsers{
- .sprites(-125px,-5px)
- }
-
- #navGroups{
- .sprites(-125px,-5px)
- }
-
- #navBadges{
- .sprites(-210px,-5px)
- }
-}
-
-#header.with-logo #userToolsNav {
- position:absolute;
- bottom: 0;
- right:0px;
-}
-
-#header.without-logo #userToolsNav {
- float:left;
- margin-top: 7px;
-}
-
-#header.without-logo #metaNav {
- margin-bottom: 7px;
-}
-
-#secondaryHeader{ /* Div containing Home button, scope navigation, search form and ask button, check blocks/secondary_header.html */
- height:55px;
- background:#e9e9e1;
- border-bottom:#d3d3c2 1px solid;
- border-top:#fcfcfc 1px solid;
- margin-bottom:10px;
- font-family:@main-font;
-
- #homeButton{
- border-right:#afaf9e 1px solid;
- .sprites(-6px,-36px);
- height:55px;
- width:43px;
- display:block;
- float:left;
- }
-
- #homeButton:hover{
- .sprites(-6px-45,-36px);
- }
-
- #scopeWrapper{
- width:688px;
- float:left;
-
- a{
- display:block;
- float:left;
- }
-
- .scope-selector{
- font-size:21px;
- color:#5a5a4b;
- height:55px;
- line-height:55px;
- margin-left:24px
- }
- .on{
- background:url(../images/scopearrow.png) no-repeat center bottom;
- }
-
- .ask-message{
- font-size:24px;
- }
- }
-}
-
-#searchBar { /* Main search form , check widgets/search_bar.html */
- display:inline-block;
- background-color: #fff;
- width:412px;
- border: 1px solid #c9c9b5;
- float:right;
- height:42px;
- margin:6px 0px 0px 15px;
-
- .searchInput, .searchInputCancelable{
- font-size: 30px;
- height: 40px;
- font-weight:300;
- background:#FFF;
- border:0px;
- color:#484848;
- padding-left:10px;
- font-family:@body-font;
- vertical-align: middle;
- }
-
- .searchInput,{
- width: 352px;
- }
-
- .searchInputCancelable {
- width: 317px;
- }
-
- .logoutsearch {
- width: 337px;
- }
-
- .searchBtn {
- font-size: 10px;
- color: #666;
- background-color: #eee;
- height: 42px;
- border:#FFF 1px solid;
- line-height: 22px;
- text-align: center;
- float:right;
- margin: 0px;
- width:48px;
- .sprites(-98px,-36px);
- cursor:pointer;
- }
-
- .searchBtn:hover {
- .sprites(-98px-48,-36px);
- }
-
- .cancelSearchBtn {
- font-size: 30px;
- color: #ce8888;
- background:#fff;
- height: 42px;
- border:0px;
- border-left:#deded0 1px solid;
- text-align: center;
- width: 35px;
- cursor:pointer;
- }
-
- .cancelSearchBtn:hover {
- color: #d84040;
- }
-}
-
-body.anon {
- #searchBar {
- width: 500px;
- .searchInput {
- width: 440px;
- }
-
- .searchInputCancelable {
- width: 405px;
- }
- }
-}
-
-
-#askButton{ /* check blocks/secondary_header.html and widgets/ask_button.html*/
- line-height:44px;
- margin-top:6px;
- float:right;
- text-transform:uppercase;
- .button-style(200px, 42px, 23px);
-}
-
-#askButton:hover{
- .button-style-hover;
-}
-
-/* ----- Content layout, check two_column_body.html or one_column_body.html ----- */
-
-#ContentLeft {
- width: 730px;
- float: left;
- position: relative;
- padding-bottom:10px;
-}
-
-#ContentRight {
- width: 200px;
- float: right;
- padding: 0 0px 10px 0px;
-}
-
-#ContentFull {
- float: left;
- width: 960px;
-}
-
-/* ----- Sidebar Widgets Box, check main_page/sidebar.html or question/sidebar.html ----- */
-
-.box {
- background: #fff;
- padding: 4px 0px 10px 0px;
- width:200px;
-
- p {
- margin-bottom: 4px;
- color: @info-text;
- font-family:@main-font;
- }
-
- p.info-box-follow-up-links {
- text-align: right;
- margin: 0;
- }
-
- h2 {
- padding-left: 0;
- background:#eceeeb;
- height:30px;
- line-height:30px;
- text-align:right;
- font-size:18px !important;
- font-weight:normal;
- color:#656565;
- padding-right:10px;
- margin-bottom:10px;
- font-family:@main-font;
- width:190px;
- }
- h3{
- color:#4a757f;
- font-size:18px;
- text-align:left;
- font-weight:normal;
- font-family:@main-font;
- padding-left:0px;
- }
- .contributorback{
- background: #eceeeb url(../images/contributorsback.png) no-repeat center left;
- }
-
- label {
- color: @info-text;
- font-size:15px;
- display: block;
- float: right;
- text-align:left;
- font-family:@main-font;
- width:80px;
- margin-right:18px;
- }
-
- #displayTagFilterControl label,
- #emailTagFilterControl label { /*Especial width just for the tag filter boxes in index page*/
- width:160px;
- }
-
- ul {
- margin-left: 22px;
- }
-
- li {
- list-style-type: disc;
- font-size: 13px;
- line-height: 20px;
- margin-bottom: 10px;
- color:@info-text;
- }
- ul.tags {
- list-style: none;
- margin: 0;
- padding: 0;
- line-height: 170%;
- display: block;
- }
- #displayTagFilterControl p label{
- color:@info-text;
- font-size:15px;
- }
-
- .inputs{
- #interestingTagInput,
- #ignoredTagInput,
- #subscribedTagInput,
- #ab-tag-search {
- width:156px;
- padding-left:5px;
- border:#c9c9b5 1px solid;
- height:25px;
- }
- #ab-tag-search {
- width: 138px;
- }
- #interestingTagAdd,
- #ignoredTagAdd,
- #subscribedTagAdd,
- #ab-tag-search-add {
- border:0;
- font-weight:bold;
- margin-top:-2px;
- .button-style(30px, 27px, 14px);
- .rounded-corners(4px);
- }
- #interestingTagAdd:hover,
- #ignoredTagAdd:hover,
- #ab-tag-search-add:hover {
- .button-style-hover;
- }
- #ab-tag-search-add {
- width: 47px;
- }
- }
-
- img.gravatar {
- margin:1px;
- }
-
-/* widgets for question template */
-
- a.followed, a.follow{
- line-height:34px;
- border:0;
- font-weight:normal;
- margin-top:3px;
- display:block;
- .button-style(120px,34px,21px);
- .center;
- }
-
- a.followed:hover, a.follow:hover{
- .button-style-hover;
- .text-shadow(0px, 1px, 0px, #c6d9dd);
- }
-
- a.followed div.unfollow{
- display:none;
- }
-
- a.followed:hover div{
- display:none;
- }
- a.followed:hover div.unfollow{
- display:inline;
- color:#a05736;
- }
-
- .favorite-number {
- padding: 5px 0 0 5px;
- font-size: 100%;
- font-family: Arial;
- font-weight: bold;
- color: #777;
- text-align:center;
- }
-
- /* notify by email box */
- .notify-sidebar #question-subscribe-sidebar {
- margin: 7px 0 0 3px;
- }
-}
-
-.users-page .box label {
- display: inline;
- float: none;
-}
-
-.statsWidget p{
- color:@info-text;
- font-size:16px;
- border-bottom:#cccccc 1px solid;
- font-size:13px;
-
- strong{
- float:right;
- padding-right:10px;
- }
-}
-.questions-related {
- word-wrap: break-word;
-
- p {
- line-height: 20px;
- padding: 4px 0px 4px 0px;
- font-size: 16px;
- font-weight:normal;
- border-bottom:#cccccc 1px solid;
- }
- a{
- font-size:13px;
- }
-}
-/* tips and markdown help are widgets for ask template */
-
-#tips{
- li{
- color:@info-text;
- font-size:13px;
- list-style-image: url(../images/tips.png);
- }
- a{
- font-size:16px;
- }
-}
-
-#markdownHelp{
- li{
- color:@info-text;
- font-size:13px;
- }
- a{
- font-size:16px;
- }
-}
-
-
-/* ----- Sorting top Tab, check main_page/tab_bar.html ------*/
-
-.tabBar {
- background-color: #eff5f6;
- height: 30px;
- margin-bottom: 3px;
- margin-top: 3px;
- float:right;
- font-family:@sort-font;
- font-size:16px;
- .rounded-corners(5px);
-}
-
-.tabBar h2 {
- float: left;
-}
-
-.tabsA, .tabsC {
- float: right;
- position: relative;
- display: block;
- height: 20px;
-}
-
-/* tabsA - used for sorting */
-.tabsA { float: right; }
-.tabsC { float: left; }
-
-.tabsA a, .tabsC a{
-
- border-left: 1px solid #d0e1e4;
- color: @section-title;
- display: block;
- float: left;
- height: 20px;
- line-height: 20px;
- padding:4px 7px 4px 7px;
- text-decoration: none;
-}
-
-.tabsA a.on, .tabsC a.on, .tabsA a:hover, .tabsC a:hover {
- color: @button-label;
-}
-
-.tabsA a.rev.on, tabsA a.rev.on:hover {
-}
-
-.tabsA .label, .tabsC .label {
- float: left;
- color: #646464;
- margin:4px 5px 0px 8px;
-}
-
-.main-page .tabsA .label {
- margin-left: 8px;
-}
-
-.tabsB a {
- background: #eee;
- border: 1px solid #eee;
- color: #777;
- display: block;
- float: left;
- height: 22px;
- line-height: 28px;
- margin: 5px 0px 0 4px;
- padding: 0 11px 0 11px;
- text-decoration: none;
-}
-
-.tabsC .first{
- border:none;
-}
-
-.rss {
- float: right;
- font-size: 16px;
- color: #f57900;
- margin: 5px 0px 3px 7px;
- width:52px;
- padding-left: 2px;
- padding-top:3px;
- background:#fff url(../images/feed-icon-small.png) no-repeat center right;
- float:right;
- font-family:@sort-font;
- font-size:16px;
-}
-
-.rss:hover {
- color: #F4A731 !important;
-}
-
-/* ----- Headline, containing number of questions and tags selected, check main_page/headline.html ----- */
-
-#questionCount{
- font-weight:bold;
- font-size:23px;
- color:@section-title;
- width:200px;
- float:left;
- margin-bottom:8px;
- padding-top:6px;
- font-family:@main-font;
-}
-
-#listSearchTags{
- float:left;
- margin-top:3px;
- color:@info-text;
- font-size:16px;
- font-family:@main-font;
-}
-
-ul#searchTags {
- margin-left:10px;
- float:right;
- padding-top:2px;
-}
-
-.search-tips {
- font-size:16px;
- line-height:17px;
- color: @info-text;
- margin:5px 0 10px 0;
- padding:0px;
- float:left;
- font-family:@main-font;
-
- a {
- text-decoration: underline;
- color: @link;
- }
-}
-
-/* ----- Question list , check main_page/content.html and macros/macros.html----- */
-
-#question-list {
- float: left;
- position: relative;
- background-color: #FFF;
- padding: 0;
- width: 100%;
-}
-
-.main-page #question-list {
- margin-top: 10px;
-}
-
-.short-summary {
- position: relative;
- filter: inherit;
- padding: 10px;
- border-bottom: 1px solid #DDDBCE;
- margin-bottom:1px;
- overflow: hidden;
- width: 710px;
- float: left;
- background: url(../images/summary-background.png) repeat-x;
-
- h2 {
- font-size: 24px;
- font-weight:normal;
- line-height: 26px;
- padding-left: 0;
- margin-bottom:6px;
- display:block;
- font-family:@main-font;
- }
-
- a {
- color:@question-link;
- }
-
- .userinfo {
- text-align:right;
- line-height:16px;
- font-family:@body-font;
- padding-right:4px;
- }
-
-
- .userinfo .timeago, span.anonymous
- {
- font-size: 11px;
- clear:both;
- font-weight: normal;
- color: #555;
- }
-
- .userinfo a{
- font-weight:bold;
- font-size:11px;
- }
-
- .counts {
- float: right;
- margin: 4px 0 0 5px;
- font-family:@main-font;
- }
-
- .counts .item-count {
- padding:0px 5px 0px 5px;
- font-size: 25px;
- font-family:@main-font;
- }
-
- .counts .votes div,
- .counts .views div,
- .counts .answers div,
- .counts .favorites div
- {
- margin-top:3px;
- font-size: 14px;
- line-height:14px;
- color: #646464;
- }
-
- .tags {
- margin-top: 0;
- }
-
- .votes, .answers, .favorites, .views {
- text-align: center;
- margin: 0 3px;
- padding: 8px 2px 0px 2px;
- width: 51px;
- float: right;
- height:44px;
- border:#dbdbd4 1px solid;
- }
-
- .votes{
- background: url(../images/vote-background.png) repeat-x;
- }
-
- .answers{
- background:url(../images/answers-background.png) repeat-x;
- }
-
- .views {
- background:url(../images/view-background.png) repeat-x;
- }
-
- .no-votes .item-count {
- color: #b1b5b6;
- }
- .some-votes .item-count {
- color: #4a757f;
- }
-
- .no-answers .item-count {
- color: #b1b5b6;
- }
- .some-answers .item-count {
- color: #eab243;
- }
-
- .no-views .item-count {
- color: #b1b5b6;
- }
- .some-views .item-count {
- color: #d33f00;
- }
-
- .accepted .item-count {
- background:url(../images/accept.png) no-repeat top right;
- display: block;
- text-align: center;
- width: 40px;
- color: #eab243;
- }
-
- .some-favorites .item-count {
- background:#338333;
- color:#d0f5a9;
- }
- .no-favorites .item-count {
- background: #eab243;
- color: yellow;
- }
-
-}
-
-/* ----- Question list Paginator , check main_content/pager.html and macros/utils_macros.html----- */
-
-.evenMore {
- font-size: 13px;
- color:@info-text;
- padding:15px 0px 10px 0px;
- clear:both;
-}
-
-.evenMore a {
- text-decoration: underline;
- color:@link;
-}
-
-.pager {
- margin-top: 10px;
- margin-bottom: 16px;
-}
-
-.pagesize {
- margin-top: 10px;
- margin-bottom: 16px;
- float: right;
-}
-
-.paginator {
- padding: 5px 0 10px 0;
- font-size:13px;
- margin-bottom:10px;
-
- .prev a, .prev a:visited,
- .next a, .next a:visited {
- background-color: #fff;
- color: #777;
- padding: 2px 4px 3px 4px;
- }
- a{
- color:@section-title;
- }
- .prev {
- margin-right: .5em;
- }
-
- .next {
- margin-left: .5em;
- }
-
- .page a, .page a:visited, .curr {
- padding: .25em;
- background-color: #fff;
- margin: 0em .25em;
- color: #ff;
- }
-
- .curr {
- background-color: #8ebcc7;
- color: #fff;
- font-weight: bold;
- }
- .next a, .prev a{
- color:@section-title
- }
- .page a:hover,
- .curr a:hover,
- .prev a:hover,
- .next a:hover {
- color: #8C8C8C;
- background-color: #E1E1E1;
- text-decoration: none;
- }
-
- .text {
- color: #777;
- padding: .3em;
- }
-
- .paginator-container-left {
- padding: 5px 0 10px 0;
- }
-
-}
-
-/* ----- Tags Styles ----- */
-
-/* tag formatting is also copy-pasted in template
- because it must be the same in the emails
- askbot/models/__init__.py:format_instant_notification_email()
-*/
-
-/* tag cloud */
-
-.tag-size-1 {
- font-size:12px;
-}
-.tag-size-2 {
- font-size:13px;
-}
-.tag-size-3 {
- font-size:14px;
-}
-.tag-size-4 {
- font-size:15px;
-}
-.tag-size-5 {
- font-size:16px;
-}
-.tag-size-6 {
- font-size:17px;
-}
-.tag-size-7 {
- font-size:18px;
-}
-.tag-size-8 {
- font-size:19px;
-}
-.tag-size-9 {
- font-size:20px;
-}
-.tag-size-10 {
- font-size:21px;
-}
-
-ul.tags,
-ul.tags.marked-tags,
-ul#related-tags {
- list-style: none;
- margin: 0;
- padding: 0;
- line-height: 170%;
- display: block;
-}
-
-ul.tags li {
- float:left;
- display: block;
- margin: 0 8px 8px 0;
- padding: 0;
- height:20px;
-}
-
-.wildcard-tags {
- clear: both;
-}
-
-ul.tags.marked-tags li,
-.wildcard-tags ul.tags li {
- margin-bottom: 5px;
-}
-
-#tagSelector div.inputs {
- clear: both;
- float: none;
- margin-bottom:10px;
-}
-
-.tags-page ul.tags li,
-ul#ab-user-tags li {
- width: 160px;
- margin:5px;
- margin-left: 0;
-}
-.tags-page ul.tags {
- margin-left: 5px;
-}
-
-ul#related-tags li {
- margin: 0 5px 8px 0;
- float: left;
- clear: left;
-}
-
-/* .tag-left and .tag-right are for the sliding doors decoration of tags */
-
-.tag-left {
- cursor: pointer;
- display: block;
- float: left;
- height: 17px;
- margin: 0 5px 0 0;
- padding: 0;
- .box-shadow(0px,0px,5px,#d3d6d7);
-}
-
-.tag-right {
- background: #f3f6f6;
- border:#fff 1px solid ;
- border-top:#fff 2px solid;
- outline:#cfdbdb 1px solid;
- /* .box-shadow(0px,1px,0px,#88a8a8);*/
- display: block;
- float: left;
- height: 17px;
- line-height: 17px;
- font-weight: normal;
- font-size: 11px;
- padding: 0px 8px 0px 8px;
- text-decoration: none;
- text-align: center;
- white-space: nowrap;
- vertical-align: middle;
- font-family:@body-font;
- color:#717179;
-}
-.deletable-tag {
- margin-right: 3px;
- white-space: nowrap;
- .rounded-corners-right(4px);
-}
-
-.tags a.tag-right,
-.tags span.tag-right {
- color: #585858;
- text-decoration: none;
-
-}
-.tags a:hover{
- color: #1A1A1A;
-}
-
-.users-page h1,
-.tags-page h1,
-.groups-page h1 {
- float: left;
-}
-
-.main-page h1 {
- margin-right: 5px;
-}
-
-.delete-icon {
- margin-top:-1px;
- float: left;
- height: 21px;
- width:18px;
- display: block;
- line-height:20px;
- text-align:center;
- background: #bbcdcd;
- cursor: default;
- color:#fff;
- border-top:#cfdbdb 1px solid;
- font-family:@body-font;
- .rounded-corners-right(4px);
- .text-shadow(0px,1px,0px,#7ea0a0)
-
-}
-.delete-icon:hover {
- background: #b32f2f;
-}
-
-
-
-.tag-number {
- font-weight: normal;
- float: left;
- font-size:16px;
- color:#5d5d5d;
-}
-
-.badges .tag-number {
- float: none;
- display: inline;
- padding-right: 15px;
-}
-
-/* ----- Ask and Edit Question Form template----- */
-
-.section-title{
- color:@section-title;
- font-family:@main-font;
- font-weight:bold;
- font-size:24px;
-}
-
-#fmask{
- margin-bottom:30px;
- width:100%;
-}
-
-#askFormBar {
- display:inline-block;
- padding: 4px 7px 0px 0px;
- margin-top:0px;
-
- p{
- margin:0 0 5px 0;
- font-size:14px;
- color:@info-text-dark;
- line-height:1.4;
- }
- .questionTitleInput {
- font-size: 24px;
- line-height: 24px;
- height: 36px;
- margin: 0px;
- padding: 0px 0 0 5px;
- border:#cce6ec 3px solid;
- width:719px;
- }
-}
-
-.ask-page, .edit-question-page {
-
- div#question-list {
- border-bottom:#f0f0ec 1px solid;
- float: none;
- a{
- line-height:30px;
- }
-
- }
-
- div#question-list h2 {
- font-size: 13px;
- padding-bottom: 0;
- color:@link;
- border-top:#f0f0ec 1px solid;
- border-left:#f0f0ec 1px solid;
- height:30px;
- line-height:30px;
- font-weight:normal;
- }
-
- div#question-list span {
- width:28px;
- height:26px;
- line-height:26px;
- text-align:center;
- margin-right: 10px;
- float:left;
- display:block;
- color:#fff;
- background: #b8d0d5;
- .rounded-corners(3px);
- }
- label{
- color:@info-text-dark;
- font-size:13px;
- }
-
- #id_tags{
- border:#cce6ec 3px solid;
- height:25px;
- padding-left:5px;
- width:395px;
- font-size:14px;
- }
-}
-
-.title-desc {
- color: @info-text;
- font-size: 13px;
- margin-bottom: 5px;
-}
-
-#fmanswer input.submit,
-.ask-page input.submit,
-.edit-question-page input.submit {
- float: left;
- font-weight:normal;
- margin-top:3px;
- .button-style(160px,34px,21px);
- margin-right:7px;
-}
-
-#fmanswer input.submit:hover,
-.ask-page input.submit:hover,
-.edit-question-page input.submit:hover{
- .button-style-hover;
- .text-shadow(0px, 1px, 0px, #c6d9dd)
-}
-
-.wmd-container {
- border:#cce6ec 3px solid;
-}
-.users-page .wmd-container {
- width: 200px;
-}
-.ask-page,
-.question-page,
-.edit-question-page,
-.edit-answer-page {
- .wmd-container {
- width: 723px;
- }
- #editor {
- width: 710px;
- padding: 6px;
- }
-}
-
-#editor { /* adjustment for editor preview */
- display: block;
- font-size: 100%;
- min-height: 200px;
- line-height: 18px;
- margin: 0;
- border: 0;
-}
-
-.users-page #editor {
- width: 192px;
-}
-
-#id_title {
- width: 100%;
-}
-
-.wmd-preview {
- margin: 0;
- padding: 5px;
- background-color: #F5F5F5;
- min-height: 20px;
- overflow: auto;
- font-size:13px;
- font-family:@body-font;
-
- p{
- margin-bottom: 14px;
- line-height: 1.4;
- font-size: 14px;
- }
-
- p:last-child{
- margin-bottom: 0;
- }
-}
-
-.wmd-preview pre {
- background-color: #E7F1F8;
-
-}
-
-.wmd-preview blockquote {
- background-color: #eee;
-}
-
-.wmd-preview IMG {
- max-width: 600px;
-}
-
-.user-page .wmd-buttons {
- width: 725px;
-}
-
-.preview-toggle {
- width: 100%;
- color: #b6a475; /*letter-spacing:1px;*/
- text-align: left;
-}
-
-.preview-toggle span:hover {
- cursor: pointer;
-}
-
-.after-editor {
- margin-top: 15px;
- margin-bottom: 15px;
-}
-
-.checkbox {
- margin-left:5px;
- font-weight:normal;
- cursor:help
-}
-
-.question-options {
- margin-top: 1px;
- color: #666;
- line-height: 13px;
- margin-bottom:5px;
-}
-.question-options label {
- vertical-align: text-bottom;
-}
-
-.edit-content-html {
- border-top: 1px dotted #D8D2A9;
- border-bottom: 1px dotted #D8D2A9;
- margin: 5px 0 5px 0;
-}
-
-.edit-question-page, #fmedit, .wmd-preview{
- color:@info-text-dark;
-
- #id_revision{
- font-size:14px;
- margin-top:5px;
- margin-bottom:5px;
- }
- #id_title{
- font-size: 24px;
- line-height: 24px;
- height: 36px;
- margin: 0px;
- padding: 0px 0 0 5px;
- border:#cce6ec 3px solid;
- width: 719px;
- margin-bottom:10px;
- }
- #id_summary{
- border:#cce6ec 3px solid;
- height:25px;
- padding-left:5px;
- width:395px;
- font-size:14px;
- }
- .title-desc{
- margin-bottom:10px;
- }
-}
-
-/* ----- Question template ----- */
-
-.question-page{
-
- h1{
- padding-top:0px;
- font-family:@main-font;
- }
-
- h1 a{
- color:@question-link;
- font-size:30px;
- font-weight:normal;
- line-height:1;
- }
-
- p.rss {
- float:none;
- clear:both;
- padding: 3px 0 0 23px;
- font-size: 15px;
- width:110px;
- background-position:center left;
- margin-left:0px !important;
- }
-
- p.rss a {
- font-family:@main-font;
- vertical-align: top;
- }
-
- .question-content{
- float:right;
- width:682px;
- margin-bottom:10px;
- }
-
- #question-table{
- float:left;
- border-top:#f0f0f0 1px solid;
- }
-
- #question-table,
- .answer-table {
- margin: 6px 0 6px 0;
- border-spacing: 0px;
- width: 670px;
- padding-right:10px;
- }
-
- .answer-table {
- margin-top:0px;
- border-bottom: 1px solid #D4D4D4;
- float:right;
- }
-
- .answer-table td,
- #question-table td {
- width:20px;
- vertical-align:top;
- }
- .question-body, .answer-body {
- overflow: auto;
- margin-top:10px;
- font-family:@body-font;
- color:#4b4b4b;
-
- p{
- margin-bottom:14px;
- line-height:1.4;
- font-size:14px;
- padding:0px 5px 5px 0px;
- }
-
- a {
- color:@link;
- }
-
- li {
- margin-bottom:7px;
- }
- }
-
- .question-body IMG, .answer-body IMG {
- max-width: 600px;
- }
-
- .post-update-info-container {
- float: right;
- width: 175px;
- }
-
- .post-update-info {
- background: #fff url(../images/background-user-info.png) repeat-x bottom;
- float: right;
- font-size: 9px;
- font-family:@secondary-font;
- width: 158px;
- padding:4px;
- margin:0px 0px 5px 5px;
- line-height: 14px;
- .rounded-corners(4px);
- .box-shadow (0px, 2px,1px,#bfbfbf);
-
- p {
- line-height: 13px;
- font-size: 11px;
- margin: 0 0 2px 1px;
- padding: 0;
- }
- a{
- color:#444;
- }
- .gravatar {
- float: left;
- margin-right: 4px;
- }
-
- p.tip {
- color: #444;
- line-height: 13px;
- font-size: 10px;
- }
- }
-
- .post-controls{
- font-size: 11px;
- line-height: 12px;
- min-width: 200px;
- padding-left: 5px;
- text-align:right;
- clear: left;
- float: right;
- margin-top:10px;
- margin-bottom:8px;
-
- a {
- color: #777;
- padding: 0px 7px 3px 18px;
- cursor: pointer;
- border: none;
- font-size:12px;
- font-family:@body-font;
- text-decoration: none;
- height:18px;
- display:block;
- float:right;
- line-height:18px;
- margin-top:-2px;
- margin-left:4px;
- }
-
- a:hover {
- background-color: #f5f0c9;
- .rounded-corners(3px);
-
- }
- .sep {
- color: #ccc;
- float:right;
- height:18px;
- font-size:18px;
- }
- }
- .post-controls, .answer-controls{
- .question-delete{
- background: url(../images/delete.png) no-repeat center left;
- padding-left:11px;
- }
- .question-flag{
- background: url(../images/flag.png) no-repeat center left;
- }
- .question-edit{
- background: url(../images/edit2.png) no-repeat center left;
- }
- .question-retag{
- background: url(../images/retag.png) no-repeat center left;
- }
- .question-close{
- background: url(../images/close.png) no-repeat center left;
- }
- .permant-link{
- background: url(../images/link.png) no-repeat center left;
- }
- }
- .tabBar{
- width:100%;
- }
-
- #questionCount{
- float:left;
- font-family:@main-font;
- line-height:15px;
- }
-
- .question-img-upvote, .question-img-downvote,
- .answer-img-upvote, .answer-img-downvote {
- width: 25px;
- height: 20px;
- cursor:pointer;
- }
-
- .question-img-upvote, .answer-img-upvote {
- background: url(../images/vote-arrow-up-new.png) no-repeat;
- }
-
- .question-img-downvote, .answer-img-downvote {
- background: url(../images/vote-arrow-down-new.png) no-repeat;
- }
-
- .question-img-upvote:hover, .question-img-upvote.on,
- .answer-img-upvote:hover, .answer-img-upvote.on {
- background: url(../images/vote-arrow-up-on-new.png) no-repeat;
- }
-
- .question-img-downvote:hover, .question-img-downvote.on,
- .answer-img-downvote:hover, .answer-img-downvote.on {
- background: url(../images/vote-arrow-down-on-new.png) no-repeat;
- }
-
- #fmanswer_button{
- margin:8px 0px;
- }
- #fmanswer_button.answer-own-question {
- width: 150px;
- }
- .question-img-favorite:hover {
- background: url(../images/vote-favorite-on.png)
- }
- div.comments {
- padding: 0;
- }
- #comment-title{
- font-weight:bold;
- font-size:23px;
- color:@section-title;
- width:200px;
- float:left;
- font-family:@main-font;
- }
- .comments {
- font-size: 12px;
- clear: both;
-
- div.controls {
- clear: both;
- float:left;
- width: 100%;
- margin: 3px 0 20px 5px;
- }
-
- .controls a {
- color: #988e4c;
- padding: 0 3px 2px 22px;
- font-family:@body-font;
- font-size:13px;
- background:url(../images/comment.png) no-repeat center left;
- }
-
- .controls a:hover {
- background-color: #f5f0c9;
- text-decoration: none;
- }
-
- .button {
- color: #988e4c;
- font-size: 11px;
- padding: 3px;
- cursor: pointer;
- }
- a {
- background-color: inherit;
- color: @link;
- padding: 0;
- }
-
- form.post-comments {
- margin: 3px 26px 0 42px;
- textarea{
- font-size: 13px;
- line-height: 1.3;
-
- }
- }
-
- textarea {
- height: 42px;
- width:100%;
- margin: 7px 0 5px 1px;
- font-family: @body-font;
- outline: none;
- overflow:auto;
- font-size: 12px;
- line-height: 140%;
- padding-left:2px;
- padding-top:3px;
- border:#cce6ec 3px solid;
- }
-
- input {
- margin-left: 10px;
- margin-top: 1px;
- vertical-align: top;
- width: 100px;
- }
- button{
- line-height:25px;
- margin-bottom:5px;
- .button-style(100px, 27px, 12px);
- font-family:@body-font;
- font-weight:bold;
- }
- button:hover{
- .button-style-hover;
- }
- .counter {
- display: inline-block;
- width: 245px;
- float:right;
- color:#b6a475 !important;
- vertical-align: top;
- font-family:@body-font;
- float:right;
- text-align:right;
- }
- .comment {
- border-bottom: 1px solid #edeeeb;
- clear:both;
- margin: 0;
- margin-top:8px;
- padding-bottom:4px;
- overflow: auto;
- font-family:@body-font;
- font-size:11px;
- min-height: 25px;
- background:#fff url(../images/comment-background.png) bottom repeat-x;
- .rounded-corners(5px);
- }
- div.comment:hover {
- background-color: #efefef;
- }
- a.author{
- background-color: inherit;
- color: @link;
- padding: 0;
- }
-
- a.author:hover {
- text-decoration: underline;
- }
- span.delete-icon{
- background:url(../images/close-small.png) no-repeat;
- border:0;
- width:14px;
- height:14px;
- }
- span.delete-icon:hover{
- border:#BC564B 2px solid;
- .rounded-corners(10px);
- margin: -3px 0px 0px -2px;
- }
- .content {
- margin-bottom: 7px;
- }
-
- .comment-votes {
- float: left;
- width: 37px;
- line-height: 130%;
- padding: 6px 5px 6px 3px;
- }
-
- .comment-body {
- line-height: 1.3;
- margin: 3px 26px 0 46px;
- padding: 5px 3px;
- color: #666;
- font-size:13px;
-
- .edit{
- padding-left:6px;
- }
- }
-
- .comment-body p{
- font-size:13px;
- line-height:1.3;
- margin-bottom: 3px;
- padding: 0;
- }
-
- .comment-delete {
- float: right;
- width: 14px;
- line-height: 130%;
- padding: 8px 6px;
- }
-
- .upvote {
- margin: 0px;
- padding-right: 17px;
- padding-top: 2px;
- text-align: right;
- height: 20px;
- font-size: 13px;
- font-weight: bold;
- color: #777;
- }
-
- .upvote.upvoted {
- color: #d64000;
- }
-
- .upvote.hover {
- background: url(../images/go-up-grey.png) no-repeat;
- background-position: right 1px;
- }
-
- .upvote:hover {
- background: url(../images/go-up-orange.png) no-repeat;
- background-position: right 1px;
- }
-
- .help-text{
- float: right;
- text-align:right;
- color: gray;
- margin-bottom: 0px;
- margin-top: 0px;
- line-height: 50%;
- }
- }
- #questionTools {
- font-size: 22px;
- margin-top: 11px;
- text-align: left;
- }
-
- .question-status {
- margin-top: 10px;
- margin-bottom:15px;
- padding: 20px;
- background-color: #fef7cc;
- text-align: center;
- border:#e1c04a 1px solid;
- }
-
- .question-status h3 {
- font-size: 20px;
- color:@info-text;
- font-weight:normal;
- }
-
- .vote-buttons {
- float: left;
- text-align: center;
- padding-top: 2px;
- margin:0px 10px 0px 3px;
- /* small IE fixes */
- *margin:0;
- *height:210px;
- *width:30px;
- }
-
- .vote-buttons IMG {
- cursor: pointer;
- }
-
- .vote-number {
- font-family: @main-font;
- padding: 0px 0 5px 0;
- font-size: 25px;
- font-weight: bold;
- color: #777;
- }
-
- .vote-buttons .notify-sidebar {
- text-align: left;
- width:120px;
- }
- .vote-buttons .notify-sidebar label {
- vertical-align: top;
- }
-
- .tabBar-answer{
- margin-bottom:15px;
- padding-left:7px;
- width:723px;
- margin-top:10px;
- }
- .answer{
- .vote-buttons {
- float:left;
- }
- }
- .accepted-answer {
- background-color: #f7fecc;
- border-bottom-color: #9BD59B;
-
- .vote-buttons {
- width:27px;
- margin-right:10px;
- margin-top:10px;
- }
- }
-
- .answer .post-update-info a{
- color:#444444;
- }
-
- .answered {
- background: #CCC;
- color: #999;
- }
-
- .answered-accepted {
- background: #DCDCDC;
- color: #763333;
-
- strong {
- color: #E1E818;
- }
- }
-
- .answered-by-owner {
- background: #F1F1FF;
-
- .comments .button {
- background-color: #E6ECFF;
- }
- .comments {
- background-color: #E6ECFF;
- }
- .vote-buttons {
- margin-right:10px;
- }
- }
-
- .answer-img-accept {
- background: url(../images/vote-accepted.png);
- width: 23px;
- height: 23px;
- }
-
- .accepted-answer .answer-img-accept,
- .answer-img-accept:hover {
- background: url(../images/vote-accepted-on.png)
- }
-
- .answer-body a {
- color:@link;
- }
- .answer-body li {
- margin-bottom:0.7em;
- }
-
- #fmanswer{
- color:@info-text;
- line-height:1.2;
- margin-top:10px;
-
- h2{
- font-family:@main-font;
- color:@section-title;
- font-size:24px;
- }
- label{
- font-size:13px;
- }
- }
- .message {
- padding: 5px;
- margin: 0px 0 10px 0;
-
- }
-
-}
-
-.facebook-share.icon, .twitter-share.icon, .linkedin-share.icon, .identica-share.icon {
- background: url(../images/socialsprite.png) no-repeat;
- display:block;
- text-indent:-100em;
- height:25px;
- width:25px;
- margin-bottom:3px;
-}
-
-.facebook-share.icon:hover, .twitter-share.icon:hover, .linkedin-share.icon:hover, .identica-share.icon:hover{
- opacity:0.8;
- filter: alpha(opacity=80);
-}
-
-.facebook-share.icon {
- background-position: -26px 0px;
-}
-.identica-share.icon {
- background-position: -78px 0px;
-}
-.twitter-share.icon {
- margin-top:10px;
- background-position: 0px 0px;
-}
-.linkedin-share.icon {
- background-position: -52px 0px;
-}
-
-/* -----Content pages, Login, About, FAQ, Users----- */
-
-.openid-signin,
-.meta,
-.user-profile-edit-page,
-{
- font-size:13px;
- line-height:1.3;
- color:@info-text-dark;
- p{
- font-size:13px;
- color:@info-text;
- line-height:1.3;
- font-family:@body-font;
- color:@info-text-dark;
- margin-bottom:12px;
- }
- h2{
- color:@info-text-dark;
- padding-left:0px;
- font-size:16px;
- }
-}
-
-.openid-signin,
-.meta,
-.users-page,
-.user-profile-edit-page,
-.user-profile-page,
-{
- form{
- margin-bottom:15px;
- }
- input[type="text"],input[type="password"],select{
- border:#cce6ec 3px solid;
- height:25px;
- padding-left:5px;
- width:395px;
- font-size:14px;
- }
- select{
- width:405px;
- height:30px;
- }
- textarea{
- border:#cce6ec 3px solid;
- padding-left:5px;
- padding-top:5px;
- width:395px;
- font-size:14px;
- }
- input.submit{
- font-weight:normal;
- margin:5px 0px;
- .button-style(100px,26px,15px);
- font-family:@body-font;
- }
- input.submit:hover{
- .button-style-hover;
- }
- .cancel{
- background:url(../images/small-button-cancel.png) repeat-x top !important;
- color:#525252 !important;
- }
- .cancel:hover{
- background:url(../images/small-button-cancel.png) repeat-x bottom !important;
- }
-}
-
-.openid-signin form {
- margin-bottom: 5px;
-}
-
-#email-input-fs,#local_login_buttons,#password-fs,#openid-fs{
- margin-top:10px;
- #id_email,#id_username,#id_password{
- font-size: 12px;
- line-height: 20px;
- height: 20px;
- margin: 0px;
- padding: 0px 0 0 5px;
- border:#cce6ec 3px solid;
- width:200px;
- }
- .submit-b{
- .button-style(100px,24px,15px);
- font-family:@body-font;
- font-weight:bold;
- padding-right:10px;
- border:0;
- }
-
- .submit-b:hover{
- .button-style-hover;
- }
-}
-
-
-.openid-input {
- background: url(../images/openid.gif) no-repeat;
- padding-left: 15px;
- cursor: pointer;
-}
-
-.openid-login-input {
- background-position: center left;
- background: url(../images/openid.gif) no-repeat 0% 50%;
- padding: 5px 5px 5px 15px;
- cursor: pointer;
- font-family: Trebuchet MS;
- font-weight: 300;
- font-size: 150%;
- width: 500px;
-}
-
-.openid-login-submit {
- height: 40px;
- width: 80px;
- line-height: 40px;
- cursor: pointer;
- border: 1px solid #777;
- font-weight: bold;
- font-size: 120%;
-}
-
-/* People page */
-
-/*.users-page .tabBar{
- width:375px;
-}*/
-
-.user {
- padding: 5px 10px 5px 0;
- line-height: 140%;
- width: 166px;
- height: 32px;
- margin-bottom:5px;
- .user-micro-info{
- color:@info-text-dark;
- }
-
-}
-
-.user ul {
- margin: 0;
- list-style-type: none;
-}
-
-.user .thumb {
- clear: both;
- float: left;
- margin-right: 4px;
- display: inline;
-}
-
-/* tags page */
-
-.tabBar-tags{
- width:270px;
- margin-bottom:15px;
-}
-
-/* badges page */
-
-a.medal {
- font-size: 17px;
- line-height: 250%;
- margin-right:5px;
- color: #333;
- text-decoration: none;
- background: url(../images/medala.gif) no-repeat;
- border-left: 1px solid #EEE;
- border-top: 1px solid #EEE;
- border-bottom: 1px solid #CCC;
- border-right: 1px solid #CCC;
- padding: 4px 12px 4px 6px;
-}
-
-a:hover.medal {
- color: #333;
- text-decoration: none;
- background: url(../images/medala_on.gif) no-repeat;
- border-left: 1px solid #E7E296;
- border-top: 1px solid #E7E296;
- border-bottom: 1px solid #D1CA3D;
- border-right: 1px solid #D1CA3D;
-}
-
-#award-list{
- .user{
- float:left;
- margin:5px;
- }
-}
-
-/* profile page */
-
-.tabBar-profile{
- width:100%;
- margin-bottom:15px;
- float:left;
-}
-
-.user-profile-page{
- font-size:13px;
- color:@info-text-dark;
-
- p{
- font-size:13px;
- line-height:1.3;
- color:@info-text-dark;
- }
- .avatar img{
- border:#eee 1px solid;
- padding:5px;
- }
- h2{
- padding:10px 0px 10px 0px;
- font-family:@main-font;
- }
-}
-
-.user-details {
- font-size: 13px;
- h3{
- font-size:16px;
- }
-}
-
-.user-about {
- background-color: #EEEEEE;
- height: 200px;
- line-height: 20px;
- overflow: auto;
- padding: 10px;
- width: 90%;
- p{font-size:13px;}
-}
-
-.follow-toggle,.submit {
- border:0 !important;
- font-weight:bold;
- line-height:26px;
- margin-top:-2px;
- .button-style(100px,26px,14px);
-}
-
-.follow-toggle:hover, .submit:hover {
- .button-style-hover;
- text-decoration:none !important;
-}
-
-.follow-toggle .follow{
- font-color: #000;
- font-style:normal;
-}
-
-.follow-toggle .unfollow div.unfollow-red{
- display:none;
-}
-
-.follow-toggle .unfollow:hover div.unfollow-red{
- display:inline;
- color:#fff;
- font-weight:bold;
- color:#A05736;
-}
-
-.follow-toggle .unfollow:hover div.unfollow-green{
- display:none;
-}
-
-.count {
- font-family: @main-font;
- font-size: 200%;
- font-weight: 700;
- color: #777
-}
-
-.scoreNumber {
- font-family: @main-font;
- font-size: 35px;
- font-weight: 800;
- color: #777;
- line-height: 40px; /*letter-spacing:0px*/
- margin-top: 3px;
-}
-
-.vote-count {
- font-family: Arial;
- font-size: 160%;
- font-weight: 700;
- color: #777;
-}
-
-.answer-summary {
- display: block;
- clear: both;
- padding: 3px;
-}
-
-.answer-votes {
- background-color: #EEEEEE;
- color: #555555;
- float: left;
- font-family: Arial;
- font-size: 15px;
- font-weight: bold;
- height: 17px;
- padding: 2px 4px 5px;
- text-align: center;
- text-decoration: none;
- width: 20px;
- margin-right: 10px;
- .rounded-corners(4px);
-}
-
-.karma-summary {
- padding:5px;
- font-size:13px;
-}
-
-.karma-summary h3 {
- text-align: center;
- font-weight: bold;
- padding:5px;
-}
-
-.karma-diagram {
- width:477px;
- height:300px;
- float:left;
- margin-right:10px;
-}
-
-.karma-details {
- float:right;
- width:450px;
- height:250px;
- overflow-y:auto;
- word-wrap:break-word;
- p{margin-bottom:10px;}
-}
-
-.karma-gained {
- font-weight:bold;
- background:#eee;
- width:25px;
- margin-right:5px;
- color:green;
- padding:3px;
- display:block;
- float:left;
- text-align:center;
- .rounded-corners(3px);
-}
-
-.karma-lost {
- font-weight:bold;
- background:#eee;
- width:25px;
- color:red;
- padding:3px;
- display:block;
- margin-right:5px;
- float:left;
- text-align:center;
- .rounded-corners(3px);
-}
-
-.submit-row{
- margin-bottom:10px;
-}
-
-/*----- Revision pages ----- */
-
-.revision {
- margin: 10px 0 10px 0;
- font-size: 13px;
- color:@info-text-dark;
-
- p{
- font-size:13px;
- line-height:1.3;
- color:@info-text-dark;
- }
-
- h3{
- font-family:@main-font;
- font-size:21px;
- padding-left:0px;
- }
-
- .header {
- background-color: #F5F5F5;
- padding: 5px;
- cursor: pointer;
- }
-
- .author {
- background-color: #e9f3f5;
- }
-
- .summary {
- padding: 5px 0 10px 0;
- }
-
- .summary span {
- background-color:#fde785;
- padding:6px;
- .rounded-corners(4px);
- display: inline;
- .box-shadow(1px, 1px, 4px, #cfb852);
- }
-
- .answerbody {
- padding: 10px 0 5px 10px;
- }
-
- .revision-mark {
- width: 150px;
- text-align: left;
- display: inline-block;
- font-size: 11px;
- overflow: hidden;
-
- .gravatar{
- float:left;
- margin-right:4px;
- padding-top:5px;
- }
- }
-
- .revision-number {
- font-size: 300%;
- font-weight: bold;
- font-family: sans-serif;
- }
-}
-
-del, del .post-tag {
- color: #C34719;
-}
-
-ins .post-tag, ins p, ins {
- background-color: #E6F0A2;
-}
-
-/* ----- Red Popup notification ----- */
-
-.vote-notification {
- z-index: 1;
- cursor: pointer;
- display: none;
- position: absolute;
- font-family:@secondary-font;
- font-size:14px;
- font-weight:normal;
- color: white;
- background-color: #8e0000;
- text-align: center;
- padding-bottom:10px;
- .box-shadow(0px, 2px, 4px, #370000);
- .rounded-corners(4px);
-
- h3{
- background:url(../images/notification.png) repeat-x top;
- padding:10px 10px 10px 10px;
- font-size:13px;
- margin-bottom:5px;
- border-top:#8e0000 1px solid;
- color:#fff;
- font-weight:normal;
- .rounded-corners-top(4px);
- }
- a {
- color: #fb7321;
- text-decoration: underline;
- font-weight:bold;
- }
-
-}
-
-
-/* ----- Footer links , check blocks/footer.html----- */
-
-#ground {
- width: 100%;
- clear: both;
- border-top: 1px solid #000;
- padding: 6px 0 0 0;
- background: @header-color;
- font-size:16px;
- font-family:@main-font;
-
- p {
- margin-bottom:0;
- }
-}
-
-.footer-links {
- color: #EEE;
- text-align:left;
- width:500px;
- float:left;
- a {
- color: #e7e8a8;
- }
-}
-
-.powered-link{
- width:500px;
- float:left;
- text-align:left;
- a{
- color:#8ebcc7;
- }
-}
-
-.copyright{
- color:#616161;
- width:450px;
- float:right;
- text-align:right;
-
- a{
- color:#8ebcc7;
- }
- img.license-logo {
- margin: 6px 0px 20px 10px;
- float:right;
- }
-}
-
-
-.notify-me {
- float: left;
-}
-
-
-span.text-counter {
- margin-right: 20px;
-}
-
-span.form-error {
- color: #990000;
- font-weight: normal;
- margin-left: 5px;
-}
-
-ul.errorlist {
- margin-bottom: 0;
-}
-
-p.form-item {
- margin: 0px;
-}
-
-
-
-
-.deleted {
- background: #F4E7E7 none repeat scroll 0 0;
-}
-
-
-/* openid styles */
-.form-row {
- line-height: 25px;
-}
-
-table.form-as-table {
- margin-top: 5px;
-}
-
-table.form-as-table ul {
- list-style-type: none;
- display: inline;
-}
-
-table.form-as-table li {
- display: inline;
-}
-
-table.form-as-table td {
- text-align: right;
-}
-
-table.form-as-table th {
- text-align: left;
- font-weight: normal;
-}
-
-table.ab-subscr-form {
- width: 45em;
-}
-
-table.ab-tag-filter-form {
- width: 45em;
-}
-
-.submit-row {
- line-height: 30px;
- padding-top: 10px;
- display: block;
- clear: both;
-}
-
-.errors {
- line-height: 20px;
- color: red;
-}
-
-.error {
- color: darkred;
- margin: 0;
- font-size: 10px;
-}
-
-label.retag-error {
- color: darkred;
- padding-left: 5px;
- font-size: 10px;
-}
-
-.fieldset {
- border: none;
- margin-top: 10px;
- padding: 10px;
-}
-
-
-span.form-error {
- color: #990000;
- font-size: 90%;
- font-weight: normal;
- margin-left: 5px;
-}
-
-
-/*
-.favorites-count-off {
- color: #919191;
- float: left;
- text-align: center;
-}
-
-.favorites-count {
- color: #D4A849;
- float: left;
- text-align: center;
-}
-*/
-
-/* todo: get rid of this in html */
-.favorites-empty {
- width: 32px;
- height: 45px;
- float: left;
-}
-
-.user-info-table {
- margin-bottom: 10px;
- border-spacing: 0;
-}
-
-/* todo: remove this hack? */
-.user-stats-table .narrow {
- width: 660px;
-}
-
-.narrow .summary h3 {
- padding: 0px;
- margin: 0px;
-}
-
-.timeago {
- font-weight: bold;
- text-decoration: none;
-}
-
-.narrow .tags {
- float: left;
-}
-
-
-
-
-/* todo: make these more semantic */
-.user-action-1 {
- font-weight: bold;
- color: #333;
-}
-
-.user-action-2 {
- font-weight: bold;
- color: #CCC;
-}
-
-.user-action-3 {
- color: #333;
-}
-
-.user-action-4 {
- color: #333;
-}
-
-.user-action-5 {
- color: darkred;
-}
-
-.user-action-6 {
- color: darkred;
-}
-
-.user-action-7 {
- color: #333;
-}
-
-.user-action-8 {
- padding: 3px;
- font-weight: bold;
- background-color: #CCC;
- color: #763333;
-}
-
-.revision-summary {
- background-color: #FFFE9B;
- padding: 2px;
-}
-
-.question-title-link a {
- font-weight: bold;
- color: #0077CC;
-}
-
-.answer-title-link a {
- color: #333;
-}
-
-/* todo: make these more semantic */
-.post-type-1 a {
- font-weight: bold;
-
-}
-
-.post-type-3 a {
- font-weight: bold;
-
-}
-
-.post-type-5 a {
- font-weight: bold;
-}
-
-.post-type-2 a {
- color: #333;
-}
-
-.post-type-4 a {
- color: #333;
-}
-
-.post-type-6 a {
- color: #333;
-}
-
-.post-type-8 a {
- color: #333;
-}
-
-.hilite {
- background-color: #ff0;
-}
-
-.hilite1 {
- background-color: #ff0;
-}
-
-.hilite2 {
- background-color: #f0f;
-}
-
-.hilite3 {
- background-color: #0ff;
-}
-
-.gold, .badge1 {
- color: #FFCC00;
-}
-
-.silver, .badge2 {
- color: #CCCCCC;
-}
-
-.bronze, .badge3 {
- color: #CC9933;
-}
-
-.score {
- font-weight: 800;
- color: #333;
-}
-
-
-a.comment {
- background: #EEE;
- color: #993300;
- padding: 5px;
-}
-
-a.offensive {
- color: #999;
-}
-
-.message h1 {
- padding-top: 0px;
- font-size: 15px;
-}
-
-.message p {
- margin-bottom: 0px;
-}
-
-p.space-above {
- margin-top: 10px;
-}
-
-.warning {
- color: red;
-}
-
-
-
-button::-moz-focus-inner {
- padding:0;
- border:none;
-}
-.submit {
- cursor: pointer; /*letter-spacing:1px;*/
- background-color: #D4D0C8;
- height: 30px;
- border: 1px solid #777777; /* width:100px; */
- font-weight: bold;
- font-size: 120%;
-}
-
-.submit:hover {
- text-decoration: underline;
-}
-
-.submit.small {
- margin-right:5px;
- height:20px;
- font-weight:normal;
- font-size:12px;
- padding:1px 5px;
-}
-.submit.small:hover {
- text-decoration:none;
-}
-.question-page a.submit {
- display: -moz-inline-stack;
- display: inline-block;
- line-height: 30px;
- padding: 0 5px;
- *display: inline;
-}
-
-.noscript {
- position: fixed;
- top: 0px;
- left: 0px;
- width: 100%;
- z-index: 100;
- padding: 5px 0;
- text-align: center;
- font-family: sans-serif;
- font-size: 120%;
- font-weight: Bold;
- color: #FFFFFF;
- background-color: #AE0000;
-}
-
-.big {
- font-size: 14px;
-}
-
-.strong {
- font-weight: bold;
-}
-
-.orange {/* used in django.po */
- color: #d64000;
- font-weight: bold;
-}
-
-.grey {
- color: #808080;
-}
-
-.about div {
- padding: 10px 5px 10px 5px;
- border-top: 1px dashed #aaaaaa;
-}
-
-.highlight {
- background-color: #FFF8C6;
-}
-
-.nomargin {
- margin: 0;
-}
-
-.margin-bottom {
- margin-bottom: 10px;
-}
-
-.margin-top {
- margin-top: 10px;
-}
-
-.inline-block {
- display: inline-block;
-}
-
-.action-status {
- margin: 0;
- border: none;
- text-align: center;
- line-height: 10px;
- font-size: 12px;
- padding: 0;
-}
-
-.action-status span {
- padding: 3px 5px 3px 5px;
- background-color: #fff380; /* nice yellow */
- font-weight: normal;
- -moz-border-radius: 5px;
- -khtml-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.list-table {
- td {
- vertical-align: top;
- }
- border-spacing: 0;
-}
-
-/* these need to go */
-table.form-as-table .errorlist {
- display: block;
- margin: 0;
- padding: 0 0 0 5px;
- text-align: left;
- font-size: 10px;
- color: darkred;
-}
-
-table.form-as-table input {
- display: inline;
- margin-left: 4px;
-}
-
-table.form-as-table th {
- vertical-align: bottom;
- padding-bottom: 4px;
-}
-
-.form-row-vertical {
- margin-top: 8px;
- display: block;
-}
-
-.form-row-vertical label {
- margin-bottom: 3px;
- display: block;
-}
-
-/* above stuff needs to go */
-.text-align-right {
- text-align: center;
-}
-
-ul.form-horizontal-rows {
- list-style: none;
- margin: 0;
-}
-
-ul.form-horizontal-rows li {
- position: relative;
- height: 40px;
-}
-
-ul.form-horizontal-rows label {
- display: inline-block;
-}
-
-ul.form-horizontal-rows ul.errorlist {
- list-style: none;
- color: darkred;
- font-size: 10px;
- line-height: 10px;
- position: absolute;
- top: 2px;
- left: 180px;
- text-align: left;
- margin: 0;
-}
-
-ul.form-horizontal-rows ul.errorlist li {
- height: 10px;
-}
-
-ul.form-horizontal-rows label {
- position: absolute;
- left: 0px;
- bottom: 6px;
- margin: 0px;
- line-height: 12px;
- font-size: 12px;
-}
-
-ul.form-horizontal-rows li input {
- position: absolute;
- bottom: 0px;
- left: 180px;
- margin: 0px;
-}
-
-.narrow .summary {
- float: left;
-}
-
-.user-profile-tool-links {
- font-weight: bold;
- vertical-align: top;
-}
-
-
-ul.post-tags {
- margin-left: 3px;
-}
-ul.post-tags li {
- margin-top: 4px;
- margin-bottom: 3px;
-}
-
-ul.post-retag {
- margin-bottom:0px;
- margin-left:5px;
- input {
- width: 400px;
- height: 1.5em;
- margin: 3px 0 0 -3px;
- }
-}
-
-#question-controls .tags {
- margin: 0 0 3px 0;
-}
-
-#tagSelector {
- padding-bottom: 2px;
- margin-bottom: 0;
-}
-
-#related-tags {
- padding-left: 3px;
-}
-
-#hideIgnoredTagsControl {
- margin: 5px 0 0 0;
-}
-
-#hideIgnoredTagsControl label {
- font-size: 12px;
- color: #666;
-}
-
-#hideIgnoredTagsCb {
- margin: 0 2px 0 1px;
-}
-
-#recaptcha_widget_div {
- width: 318px;
- float: left;
- clear: both;
-}
-
-p.signup_p {
- margin: 20px 0px 0px 0px;
-}
-
-.simple-subscribe-options ul {
- list-style: none;
- list-style-position: outside;
- margin: 0;
-}
-
-/* a workaround to set link colors correctly */
-
-.wmd-preview a {
- color:@link;
-}
-
-.wmd-preview li {
- margin-bottom:7px;
- font-size:14px;
-}
-
-.search-result-summary {
- font-weight: bold;
- font-size:18px;
- line-height:22px;
- margin:0px 0px 0px 0px;
- padding:2px 0 0 0;
- float: left;
-}
-
-.faq-rep-item {
- text-align:right;
- padding-right:5px;
-}
-
-
-.user-info-table .gravatar {
- margin:0;
-}
-
-#responses {
- clear:both;
- line-height:18px;
- margin-bottom:15px;
-}
-
-#responses div.face {
- float:left;
- text-align: center;
- width: 54px;
- padding: 3px;
- overflow:hidden;
-}
-
-.response-parent {
- margin-top: 18px;
-}
-
-.response-parent strong{
- font-size: 20px;
-}
-
-.re {
- min-height: 57px;
- clear: both;
- margin-top: 10px;
-}
-
-#responses input {
- float:left;
-}
-#re_tools {
- margin-bottom:10px;
-}
-#re_sections {
- margin-bottom:6px;
-}
-#re_sections .on {
- font-weight:bold;
-}
-
-.avatar-page ul {
- list-style: none;
-}
-.avatar-page li {
- display: inline;
-}
-
-.user-profile-page {
- .avatar p {
- margin-bottom: 0px;
- }
- .tabBar a#stats {
- margin-left: 0;
- }
- img.gravatar {
- margin: 2px 0 3px 0;
- }
- h3 {
- padding: 0;
- margin-top: -3px;
- }
- ul.tags {
- margin-left: 5px;
- }
-}
-
-.userList {
- font-size: 13px;
-}
-
-img.flag {
- border: 1px solid #eee;
- vertical-align: text-top;
-}
-
-.main-page img.flag {
- vertical-align: text-bottom;
-}
-
-
-/* Pretty printing styles. Used with prettify.js. */
-
-a.edit {
- padding-left:3px;
- color: #145bff;
-}
-
-.str { color: #080; }
-.kwd { color: #008; }
-.com { color: #800; }
-.typ { color: #606; }
-.lit { color: #066; }
-.pun { color: #660; }
-.pln { color: #000; }
-.tag { color: #008; }/* name conflict here */
-.atn { color: #606; }
-.atv { color: #080; }
-.dec { color: #606; }
-pre.prettyprint { clear:both;padding: 3px; border: 0px solid #888; }
-
-@media print {
- .str { color: #060; }
- .kwd { color: #006; font-weight: bold; }
- .com { color: #600; font-style: italic; }
- .typ { color: #404; font-weight: bold; }
- .lit { color: #044; }
- .pun { color: #440; }
- .pln { color: #000; }
- .tag { color: #006; font-weight: bold; }
- .atn { color: #404; }
- .atv { color: #060; }
-}
-
-#leading-sidebar {
- float: left;
-}
-
-/* language-specific fixes */
-body.lang-es {
- #searchBar {
- width: 398px;
- .searchInput {
- width: 337px;
- }
- .searchInputCancelable {
- width: 302px;
- }
- }
-}
-body.anon.lang-es {
- #searchBar {
- width: 485px;
- .searchInput {
- width: 425px;
- }
- .searchInputCancelable {
- width: 390px;
- }
- }
-}
-
-/* user groups */
-#user-groups ul {
- margin-bottom: 0px;
-}
-#user-groups .delete-icon {
- float: none;
- display: inline;
- color: #525252;
- padding: 0 3px 0 3px;
- background: #ccc;
- border-radius: 4px;
- line-height:inherit;
- -moz-border-radius: 4px;
- -khtml-border-radius: 4px;
- -webkit-border-radius: 4px;
-}
-#user-groups .delete-icon:hover {
- color: white;
- background: #b32f2f;
-}
-
-.users-page {
- .wmd-prompt-dialog {
- background: #ccc;
- }
-}
-
-.group-wiki {
- .content {
- > p:last-child {
- margin-bottom: 5px;
- }
- }
- .group-logo {
- float: left;
- margin: 0 5px 3px 0;
- }
- .follow-toggle.group-join-btn {
- width: 150px;
- margin: 4px auto 10px auto;
- display: block;
- }
- .controls {
- margin: 0 0 10px 0;
- }
-}
-
-img.group-logo {
- height: 60px;/* important to align with the line spacing */
-}
-
-#groups-list {
- margin-left: 0px;
- .group-name {
- padding-right: 20px;
- }
- td {
- padding-bottom: 5px;
- }
-}
-
-#reject-edit-modal {
- input, textarea {
- width: 514px;
- }
-}
-
-input.tipped-input,
-textarea.tipped-input {
- padding-left: 5px;
-}
-
-.tipped-input.blank {
- color: @info-text;
-}
-
-.select-box {
-
- margin: 0;
-
- li {
- list-style-type: none;
- list-style-position: inside;
- padding-left: 7px;
- font-size: 14px;
- line-height: 25px;
- }
- li.selected,
- li.selected:hover {
- background-color: #fcf8e3;
- color: #c09853;
- }
-
- li:hover {
- background-color: #cecece;
- color: white;
- }
-}
-
-/* fixes for bootstrap */
-.caret {
- margin-bottom: 7px;
-}
-.btn-group {
- text-align: left;
-}
-.btn-toolbar {
- margin: 0;
-}
-.modal-footer {
- text-align: left;
-}
-.modal p {
- font-size: 14px;
-}
-.modal-body > textarea {
- width: 515px;
- margin-bottom: 0px;
-}
diff --git a/askbot/skins/default/templates/500.html b/askbot/skins/default/templates/500.html
deleted file mode 100644
index 8ec1bce4..00000000
--- a/askbot/skins/default/templates/500.html
+++ /dev/null
@@ -1,5 +0,0 @@
-{% load extra_tags %}
-{% include_jinja "500.jinja.html" request %}
-{% comment %}this template must be django
-because of the use of default handler500
-{% endcomment %}
diff --git a/askbot/skins/default/templates/answer_edit.html b/askbot/skins/default/templates/answer_edit.html
deleted file mode 100644
index bbc00420..00000000
--- a/askbot/skins/default/templates/answer_edit.html
+++ /dev/null
@@ -1,85 +0,0 @@
-{% extends "two_column_body.html" %}
-{% import "macros.html" as macros %}
-<!-- template answer_edit.html -->
-{% block title %}{% spaceless %}{% trans %}Edit answer{% endtrans %}{% endspaceless %}{% endblock %}
-{% block forestyle %}
- <link rel="stylesheet" type="text/css" href="{{"/js/wmd/wmd.css"|media}}" />
-{% endblock %}
-{% block content %}
-<h1 class="section-title">
- {% trans %}Edit answer{% endtrans %} [<a href="{{ answer.thread._question_post().get_absolute_url() }}#{{ answer.id }}">{% trans %}back{% endtrans %}</a>]
-</h1>
-<div id="main-body" class="ask-body">
- <form id="fmedit" action="{% url edit_answer answer.id %}" method="post" >{% csrf_token %}
- <label for="id_revision" >{% trans %}revision{% endtrans %}:</label> <br/>
- {% if revision_form.revision.errors %}{{ revision_form.revision.errors.as_ul() }}{% endif %}
- <div style="vertical-align:middle">
- {{ revision_form.revision }} <input type="submit" style="display:none" id="select_revision" name="select_revision" value="{% trans %}select revision{% endtrans %}">
- </div>
- {{ macros.edit_post(form) }}
- {% if settings.WIKI_ON and answer.wiki == False %}
- {{ macros.checkbox_in_div(form.wiki) }}
- {% endif %}
- <div class="after-editor">
- <input type="submit" value="{% trans %}Save edit{% endtrans %}" class="submit" />&nbsp;
- <input type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" onclick="history.back(-1);" />
- </div>
-
- </form>
-</div>
-{% endblock %}
-
-{% block sidebar %}
- {% include "widgets/answer_edit_tips.html" %}
-{% endblock %}
-
-{% block endjs %}
- {% include "meta/editor_data.html" %}
- <script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/post.js"|media}}'></script>
- <script type='text/javascript'>
- {% if settings.ENABLE_MATHJAX or settings.MARKUP_CODE_FRIENDLY %}
- var codeFriendlyMarkdown = true;
- {% else %}
- var codeFriendlyMarkdown = false;
- {% endif %}
- </script>
- <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script>
- <script type="text/javascript">
- $().ready(function(){
- $("#nav_questions").attr('className',"on");
- $('#editor').TextAreaResizer();
-
- //highlight code synctax when editor has new text
- $("#editor").typeWatch({highlight: false, wait: 3000,
- captureLength: 5, callback: lanai.highlightSyntax});
-
- //toggle preview of editor
- var display = true;
- var txt = "{% trans %}hide preview{% endtrans %}";
- $('#pre-collapse').text(txt);
- $('#pre-collapse').bind('click', function(){
- txt = display ? "{% trans %}show preview{% endtrans %}" : "{% trans %}hide preview{% endtrans %}";
- display = !display;
- $('#previewer').toggle();
- $('#pre-collapse').text(txt);
- });
-
- setupFormValidation(
- $("#fmedit"),
- CPValidator.getAnswerFormRules(),
- CPValidator.getAnswerFormMessages()
- );
-
- $('#id_revision').unbind().change(function(){
- $("#select_revision").click();
- });
-
- lanai.highlightSyntax();
-
- });
- </script>
-{% endblock %}
-<!-- end template answer_edit.html -->
diff --git a/askbot/skins/default/templates/ask.html b/askbot/skins/default/templates/ask.html
deleted file mode 100644
index 8bec61b7..00000000
--- a/askbot/skins/default/templates/ask.html
+++ /dev/null
@@ -1,67 +0,0 @@
-{% extends "two_column_body.html" %}
-{% import "macros.html" as macros %}
-<!-- template ask.html -->
-{% block title %}{% spaceless %}{% trans %}Ask Your Question{% endtrans %}{% endspaceless %}{% endblock %}
-{% block forestyle %}
- <link rel="stylesheet" type="text/css" href="{{"/js/wmd/wmd.css"|media}}" />
-{% endblock %}
-{# main contents of ask form is in the template input_bar #}
-{% block sidebar %}
-{% include "widgets/question_edit_tips.html" %}
-{% endblock %}
-{% block content %}
- {% include "widgets/ask_form.html" %}
-{% endblock %}
-{% block endjs %}
- <script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/jquery.validate.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/post.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script>
- <script type='text/javascript'>
- var sortMethod = undefined;//need for live_search
- var minSearchWordLength = {{settings.MIN_SEARCH_WORD_LENGTH}};
- </script>
- <script type='text/javascript' src='{{"/js/live_search_new_thread.js"|media}}'></script>
- {% include "meta/editor_data.html" %}
- {% if mandatory_tags %}
- {% include "meta/mandatory_tags_js.html" %}
- {% endif %}
- <script type='text/javascript'>
- askbot['urls']['api_get_questions'] = '{% url api_get_questions %}';
- {% if settings.ENABLE_MATHJAX or settings.MARKUP_CODE_FRIENDLY %}
- var codeFriendlyMarkdown = true;
- {% else %}
- var codeFriendlyMarkdown = false;
- {% endif %}
- $().ready(function(){
- liveSearchNewThreadInit();
- //set current module button style
- $('#editor').TextAreaResizer();
-
- //highlight code synctax when editor has new text
- $("#editor").typeWatch({highlight: false, wait: 3000,
- captureLength: 5, callback: lanai.highlightSyntax});
-
- //toggle preview of editor
- //todo remove copy-paste
- var display = true;
- var txt = "[{% trans %}hide preview{% endtrans %}]";
- $('#pre-collapse').text(txt);
- $('#pre-collapse').bind('click', function(){
- txt = display ? "[{% trans %}show preview{% endtrans %}]" : "[{% trans %}hide preview{% endtrans %}]";
- display = !display;
- $('#previewer').toggle();
- $('#pre-collapse').text(txt);
- });
- //Tags autocomplete
-
- {{ macros.tag_autocomplete_js(id = '#id_tags') }}
-
- setupFormValidation($("#fmask"), CPValidator.getQuestionFormRules(), CPValidator.getQuestionFormMessages());
- lanai.highlightSyntax();
- });
- </script>
-{% endblock %}
-
-<!-- end template ask.html -->
diff --git a/askbot/skins/default/templates/base.html b/askbot/skins/default/templates/base.html
deleted file mode 100644
index da771a41..00000000
--- a/askbot/skins/default/templates/base.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<!-- template base.html -->
-<html xmlns="http://www.w3.org/1999/xhtml">
- {% spaceless %}
- <head>
- <title>{% block title %}{% endblock %} - {{ settings.APP_TITLE|escape }}</title>
- {% include "meta/html_head_meta.html" %}
- <link rel="shortcut icon" href="{{ settings.SITE_FAVICON|media }}" />
- {% block before_css %}{% endblock %}
- {% include "meta/html_head_stylesheets.html" %}
- {% block forestyle %}{% endblock %}
- {% include "meta/html_head_javascript.html" %}
- {% block forejs %}{% endblock %}
- {% if settings.USE_CUSTOM_HTML_HEAD %}
- {{ settings.CUSTOM_HTML_HEAD }}
- {% endif %}
- </head>
- {% endspaceless %}
- <body class="{% block body_class %}{% endblock %}{% if user_messages %} user-messages{% endif %}{% if page_class %} {{page_class}}{% endif %}{% if request.user.is_anonymous() %} anon{% endif %} lang-{{settings.LANGUAGE_CODE}}">
- {% include "widgets/system_messages.html" %}
- {% include "debug_header.html" %}
- {% include "custom_header.html" ignore missing %}
- {% if settings.CUSTOM_HEADER|trim != '' %}
- <div id="custom-header">
- {{settings.CUSTOM_HEADER}}
- </div>
- {% endif %}
- {% include "widgets/header.html" %} {# Logo, user tool navigation and meta navitation #}
- {% include "widgets/secondary_header.html" %} {# Scope selector, search input and ask button #}
- {% if settings.ENABLE_LEADING_SIDEBAR %}
- <div id="leading-sidebar">
- {{ settings.LEADING_SIDEBAR }}
- </div>
- {% endif %}
- <div class="content-wrapper">
- {% block body %}
- {% endblock %}
- </div>
- {% if settings.FOOTER_MODE == 'default' %}
- {% include "widgets/footer.html" %}
- {% elif settings.FOOTER_MODE == 'customize' %}
- {{ settings.CUSTOM_FOOTER }}
- {% endif %}
- {% include "custom_footer.html" ignore missing %}
- {% include "meta/bottom_scripts.html" %}
- {% block endjs %}
- {% endblock %}
- <script type="text/javascript">
- for (url_name in askbot['urls']){
- askbot['urls'][url_name] = cleanUrl(askbot['urls'][url_name]);
- }
- </script>
- </body>
-</html>
-<!-- end template base.html -->
diff --git a/askbot/skins/default/templates/email/ask_for_signature.html b/askbot/skins/default/templates/email/ask_for_signature.html
deleted file mode 100644
index cafeee2b..00000000
--- a/askbot/skins/default/templates/email/ask_for_signature.html
+++ /dev/null
@@ -1,11 +0,0 @@
-{% import "email/macros.html" as macros %}
-<p style="{{ macros.heading_style() }}">
- {% trans user=username|escape %}{{ user }}, please reply to this message.{% endtrans %}
-</p>
-<p>
- {% trans %}Your post could not be published, because we could not detect signature in your email.{% endtrans %}<br/>
- {% trans %}Please make a simple response, without editing this message.{% endtrans %}<br/>
- {% trans %}We will then attempt to detect the signature in your response and you should be able to post.{% endtrans %}
-</p>
-{% include "email/footer.html" %}
-<p style="{{ macros.fine_print_style() }}">{{ footer_code }}</p>
diff --git a/askbot/skins/default/templates/email/insufficient_rep_to_post_by_email.html b/askbot/skins/default/templates/email/insufficient_rep_to_post_by_email.html
deleted file mode 100644
index 284cc1b0..00000000
--- a/askbot/skins/default/templates/email/insufficient_rep_to_post_by_email.html
+++ /dev/null
@@ -1,15 +0,0 @@
-{% import "email/macros.html" as macros %}
-{# parameters:
- * min_upvotes
- * username
- * site_name - for the footer
- * site_link - html for the link
-#}
-<p style="{{ macros.heading_style() }}">
- {% trans user=username|escape %}{{ username }}, your question could not be posted by email just yet.{% endtrans %}
-</p>
-<p>
- {% trans %}To make posts by email, you need to receive about {{min_upvotes}} upvotes.{% endtrans %}<br/>
- {% trans link=site_link|safe %}At this time, please post your question at {{link}}{% endtrans %}
-</p>
-{% include "email/footer.html" %}
diff --git a/askbot/skins/default/templates/email/macros.html b/askbot/skins/default/templates/email/macros.html
deleted file mode 100644
index d7817bf9..00000000
--- a/askbot/skins/default/templates/email/macros.html
+++ /dev/null
@@ -1,96 +0,0 @@
-{% macro quoted_post(
- post = None,
- quote_level = 0,
- format = None,
- is_leaf_post = False
- )
-%}
- {% spaceless %}
- {{ start_quote(quote_level) }}
- {% set author = post.author.username|escape %}
- {% if post.post_type == 'question' %}
- <p>
- {% if format == 'parent_subthread' %}
- {% if is_leaf_post %}
- {% trans %}Question by {{ author }}:{% endtrans %}
- {% else %}
- {% trans -%}
- In reply to {{ author }}'s question:
- {%- endtrans %}
- {% endif %}
- {% else %}
- {% trans %}Question :{% endtrans %}
- {% endif %}
- {{ post.thread.title }}
- </p>
- <p>
- {% if format != 'parent_subthread' %}
- {% trans %}Asked by {{ author }}:{% endtrans %}
- {% endif %}
- </p>
- {% set tag_names = post.get_tag_names() %}
- {% if tag_names %}
- <p>
- {% trans %}Tags:{% endtrans %}
- {{ tag_names|join(', ') }}.
- </p>
- {% endif %}
- {% elif post.post_type == 'answer' %}
- <p>
- {% if format == 'parent_subthread' %}
- {% if is_leaf_post %}
- {% trans -%}
- {{ author }}'s answer:
- {%- endtrans %}
- {% else %}
- {% trans -%}
- In reply to {{ author }}'s answer:
- {%- endtrans %}
- {% endif %}
- {% else %}
- {% trans %}Answered by {{ author }}:{% endtrans %}
- {% endif %}
- </p>
- {% else %}
- <p>
- {% if format == 'parent_subthread' %}
- {% if is_leaf_post %}
- {% trans -%}
- {{ author }}'s comment:
- {%- endtrans %}
- {% else %}
- {% trans -%}
- In reply to {{ author }}'s comment:
- {%- endtrans %}
- {% endif %}
- {% else %}
- {% trans author -%}
- Commented by {{ author }}:
- {%- endtrans %}
- {% endif %}
- </p>
- {% endif %}
- {{ post.html }}
- {{ end_quote(quote_level) }}
- {% endspaceless %}
-{% endmacro %}
-
-{% macro start_quote(level = 0) %}
- {% for number in range(level) %}
- <div style="padding-left:5px; border-left: 2px solid #aaa;">
- {% endfor %}
-{% endmacro %}
-
-{% macro end_quote(level = 0) %}
- {% for number in range(level) %}
- </div>
- {% endfor %}
-{% endmacro %}
-
-{% macro heading_style() %}
-font-size:14px;font-weight:bold;margin-bottom:0px;
-{% endmacro %}
-
-{% macro fine_print_style() %}
-font-size:8px;color:#aaa;margin-bottom:0px;
-{% endmacro %}
diff --git a/askbot/skins/default/templates/email/notify_author_about_approved_post.html b/askbot/skins/default/templates/email/notify_author_about_approved_post.html
deleted file mode 100644
index 085141d9..00000000
--- a/askbot/skins/default/templates/email/notify_author_about_approved_post.html
+++ /dev/null
@@ -1,21 +0,0 @@
-{#
- parameters:
- * reply_separator_line
- * replace_content_address
- * mailto_link_subject
- * post
- * reply_code (comma-separated list of emails to respond to this message)
-#}
-{{ reply_separator_line }}
-<p>{% trans
- post_text = post.text|safe_urlquote,
- subject = mailto_link_subject|safe_urlquote,
- author_email_signature = author_email_signature|safe_urlquote
-%}If you would like to edit by email, please
-<a href="mailto:{{ replace_content_address }}?body={{ post_text }}{{ author_email_signature}}&subject={{ subject }}">click here</a>{% endtrans %}</p>
-<p>{% trans %}Below is a copy of your post:{% endtrans %}</p>
-{% if post.post_type == 'question' %}
- <p style="font-size:16px">{{ post.thread.title }}</p>
-{% endif %}
-{{ post.html }}
-<p style="font-size:8px;color:#aaa;">{{ reply_code }}</p>
diff --git a/askbot/skins/default/templates/email/post_as_subthread.html b/askbot/skins/default/templates/email/post_as_subthread.html
deleted file mode 100644
index 9b6eb728..00000000
--- a/askbot/skins/default/templates/email/post_as_subthread.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{% from "email/macros.html" import quoted_post %}
-{% if post.post_type in ('question', 'answer') %}
- {{ quoted_post(post) }}
- {% set comments = post.get_cached_comments() %}
- {% if comments %}
- <p>
- {% trans count=comments|length -%}
- {{ comment }} comment:
- {%- pluralize -%}
- {{ count }} comments:
- {%- endtrans -%}
- </p>
- {% for comment in comments %}
- {{ quoted_post(comment, quote_level = 1) }}
- {% endfor %}
- {% endif %}
-{% endif %}
diff --git a/askbot/skins/default/templates/email/re_welcome_lamson_on.html b/askbot/skins/default/templates/email/re_welcome_lamson_on.html
deleted file mode 100644
index 412fede8..00000000
--- a/askbot/skins/default/templates/email/re_welcome_lamson_on.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<p style="font-size:16px;font-weight:bold;">
- {% trans %}Great, you are ready to use {{ site_name }}!{% endtrans %}
-</p>
-<p>{% trans %}You can post questions by emailing them at {{ ask_address }}.{% endtrans %}</p>
-<p>{% trans %}When you receive update notifications, you will be able to respond to them, also by email.{% endtrans %}</p>
-<p>{% trans %}Of course, you can always visit the {{ site_name }} at <a href="{{ site_url }}">{{ site_url }}</a>{% endtrans %}</p>
-{% include "email/footer.html" %}
diff --git a/askbot/skins/default/templates/email/welcome_lamson_on.html b/askbot/skins/default/templates/email/welcome_lamson_on.html
deleted file mode 100644
index 0efa7096..00000000
--- a/askbot/skins/default/templates/email/welcome_lamson_on.html
+++ /dev/null
@@ -1,15 +0,0 @@
-{% import "email/macros.html" as macros %}
-{# site_name - is short name of the site, email_code - address portion
-of the reply email used for this message, we scan to the last appearance
-of the email code to detect the response signature that will appear under #}
-<p style="{{ macros.heading_style() }}">
- {% trans %}Welcome to {{ site_name }}!{% endtrans %}
-</p>
-<p>
- {% trans %}Important: <em>Please reply</em> to this message, without editing it. We need this to determine your email signature and that the email address is valid and was typed correctly.{% endtrans %}
-</p>
-<p>
- {% trans %}Until we receive the response from you, you will not be able ask or answer questions on {{ site_name }} by email.{% endtrans %}
-</p>
-{% include "email/footer.html" %}
-<p style="{{ macros.fine_print_style() }}">{{ email_code }}</p>{# important #}
diff --git a/askbot/skins/default/templates/groups.html b/askbot/skins/default/templates/groups.html
deleted file mode 100644
index 2499ac9f..00000000
--- a/askbot/skins/default/templates/groups.html
+++ /dev/null
@@ -1,48 +0,0 @@
-{% import "macros.html" as macros %}
-{% extends 'two_column_body.html' %}
-{% block title %}{% trans %}Groups{% endtrans %}{% endblock %}
-{% block content %}
- <div id="content-header">
- <h1 class="section-title">{% trans %}Groups{% endtrans %}</h1>
- {% if request.user.is_authenticated() %}
- <div class="tabBar">
- <div class="tabsC">
- <a id="all-groups" class="first{% if tab_name=="all-groups" %} on{% endif %}"
- title="{% trans %}All groups{% endtrans %}"
- href="{% url groups %}?sort=all-groups"
- ><span>{% trans %}all groups{% endtrans %}</span></a>
- <a id="my-groups" {% if tab_name=="my-groups" %}class="on"{% endif %}
- title="{% trans %}My groups{% endtrans %}"
- href="{% url groups %}?sort=my-groups"
- ><span>{% trans %}my groups{% endtrans %}</span></a>
- </div>
- </div>
- {% endif %}
- <div class="clearfix"></div>
- </div>
- {% if user_can_add_groups %}
- <p id="group-add-tip">
- {% trans %}Tip: to create a new group - please go to some user profile and add the new group there. That user will be the first member of the group{% endtrans %}
- </p>
- {% endif %}
- <table id="groups-list">
- {% for group in groups %}
- <tr>
- {{ macros.user_group(group, groups_membership_info[group.id]) }}
- </tr>
- {% endfor %}
- </table>
-{% endblock %}
-{% block endjs %}
- <script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
- <script src='{{"/js/post.js"|media}}' type='text/javascript'></script>
- {% if request.user.is_authenticated() %}
- <script type="text/javascript">
- askbot['urls']['join_or_leave_group'] = '{% url join_or_leave_group %}';
- $.each($('.group-join-btn'), function(idx, elem){
- var group_join_btn = new GroupJoinButton();
- group_join_btn.decorate($(elem));
- });
- </script>
- {% endif %}
-{% endblock %}
diff --git a/askbot/skins/default/templates/help.html b/askbot/skins/default/templates/help.html
deleted file mode 100644
index 204fc086..00000000
--- a/askbot/skins/default/templates/help.html
+++ /dev/null
@@ -1,33 +0,0 @@
-{% extends "two_column_body.html" %}
-{% block title %}{% trans %}Help{% endtrans %}{% endblock %}
-{% block content %}
-<h1 class='section-title'>{% trans %}Help{% endtrans %}</h1>
-<p>
- {% if request.user.is_authenticated() %}
- {% trans username = request.user.username|escape %}Welcome {{username}},{% endtrans %}
- {% else %}
- {% trans %}Welcome,{% endtrans %}
- {% endif %}
-</p>
-<p>
- {% trans %}Thank you for using {{app_name}}, here is how it works.{% endtrans %}
-</p>
-<p>
- {% trans %}This site is for asking and answering questions, not for open-ended discussions.{% endtrans %}
- {% trans %}We encourage everyone to use “question†space for asking and “answer†for answering.{% endtrans %}
-</p>
-<p>
- {% trans %}Despite that, each question and answer can be commented –
- the comments are good for the limited discussions.{% endtrans %}
-</p>
-<p>
- {% trans %}Voting in {{app_name}} helps to select best answers and thank most helpful users.{% endtrans %}
-</p>
- {% trans %}Please vote when you find helpful information,
- it really helps the {{app_name}} community.{% endtrans %}
-
- {% trans %}Besides, you can @mention users anywhere in the text to point their attention,
- follow users and conversations and report inappropriate content by flagging it.{% endtrans %}
-</p>
-<p>{% trans %}Enjoy.{% endtrans %}</p>
-{% endblock %}
diff --git a/askbot/skins/default/templates/instant_notification.html b/askbot/skins/default/templates/instant_notification.html
deleted file mode 100644
index cd6e5427..00000000
--- a/askbot/skins/default/templates/instant_notification.html
+++ /dev/null
@@ -1,7 +0,0 @@
-{{ reply_separator }}
-<div>{{ content_preview }}</div>
-{% trans %}
-<p>Please note - you can easily <a href="{{user_subscriptions_url}}">change</a>
-how often you receive these notifications or unsubscribe. Thank you for your interest in our forum!</p>
-{% endtrans %}
-{% trans %}<p>Sincerely,<br/>Forum Administrator</p>{% endtrans %}
diff --git a/askbot/skins/default/templates/macros.html b/askbot/skins/default/templates/macros.html
deleted file mode 100644
index 3e463c1c..00000000
--- a/askbot/skins/default/templates/macros.html
+++ /dev/null
@@ -1,753 +0,0 @@
-{% load extra_filters_jinja %}
-
-{%- macro share(site = None, site_label = None, icon = False) -%}
- <a class="{{ site }}-share{% if icon == True %} icon{% endif %}"
- title="{% trans %}Share this question on {{site}}{% endtrans %}"
- >{% if icon == False %}{% if site_label %}{{ site_label }}{% else %}{{ site }}{% endif %}{% endif %}</a>
-{%- endmacro -%}
-
-{%- macro follow_toggle(follow, name, alias, id) -%}
- {# follow - boolean; name - object type name; alias - e.g. users name; id - object id #}
- <div
- class="follow-toggle follow-user-toggle"
- id="follow-{{ name|escape }}-{{ id }}"
- >
- {% if follow %}
- <div class="follow">{% trans %}follow {{alias}}{% endtrans %}</div>
- {% else %}
- <div class="unfollow">
- <div class="unfollow-red">{% trans %}unfollow {{alias}}{% endtrans %}</div>
- <div class="unfollow-green">{% trans %}following {{alias}}{% endtrans %}</div>
- </div>
- {% endif %}
- </div>
-{%- endmacro -%}
-
-{%- macro inbox_post_snippet(response, inbox_section) -%}
-<div id="re_{{response.id}}" class="re{% if response.is_new %} new highlight{% else %} seen{% endif %}">
- <input type="checkbox" />
- <div class="face">
- {{ gravatar(response.user, 48) }}
- </div>
- <a style="font-size:12px" href="{{ response.user.get_absolute_url() }}">{{ response.user.username|escape }}</a>
- <a style="text-decoration:none;" href="{{ response.response_url }}">
- {{ response.response_type }}
- ({{ timeago(response.timestamp) }}):<br/>
- {% if inbox_section != 'flags' %}
- {{ response.response_snippet|escape }}
- {% endif %}
- </a>
- {% if inbox_section == 'flags' %}
- <a class="re_expand" href="{{ response.response_url }}">
- <!--div class="re_snippet">{{ response.response_snippet|escape }}</div-->
- <div class="re_content">{{ response.response_content|escape }}</div>
- </a>
- {% endif %}
-</div>
-{%- endmacro -%}
-
-{%- macro post_vote_buttons(post = None) -%}
-<div id="{{post.post_type}}-img-upvote-{{ post.id }}"
- class="{{post.post_type}}-img-upvote post-vote">
-</div>
-<div
- id="{{post.post_type}}-vote-number-{{ post.id }}"
- class="vote-number"
- title="{% trans %}current number of votes{% endtrans %}"
->{{ post.score }}</div>
-<div
- id="{{post.post_type}}-img-downvote-{{ post.id }}"
- class="{{post.post_type}}-img-downvote post-vote">
-</div>
-<script type="text/javascript">
- askbot['functions']['renderPostVoteButtons']('{{post.post_type}}', '{{post.id}}');
-</script>
-{%- endmacro -%}
-
-{%- macro post_contributor_avatar_and_credentials(post, user, karma_mode = None, badges_mode = None) -%}
- {% if post.is_anonymous %}
- <img alt="{% trans %}anonymous user{% endtrans %}" src="{{ '/images/anon.png'|media }} " class="gravatar" width="32" height="32" />
- <p>{{ user.get_anonymous_name() }}</p>
- {% else %}
- {{ gravatar(user, 32) }}
- {{ user.get_profile_link()}}{{ user_country_flag(user) }}<br/>
- {{ user_score_and_badge_summary(user, karma_mode = karma_mode, badges_mode = badges_mode) }}<br/>
- {{ user_website_link(user) }}
- {% endif %}
-{%- endmacro -%}
-
-{%- macro post_last_updater_and_creator_info(
- post, min_rep_to_edit_wiki, karma_mode = None, badges_mode = None
- ) -%}
- {{ post_contributor_info(
- post, "original_author", post.wiki, min_rep_to_edit_wiki,
- karma_mode = karma_mode, badges_mode = badges_mode
- )
- }}
- {{ post_contributor_info(
- post, "last_updater", post.wiki, min_rep_to_edit_wiki,
- karma_mode = karma_mode, badges_mode = badges_mode
- )
- }}
-{%- endmacro -%}
-
-{%- macro post_contributor_info(
- post, contributor_type, is_wiki, wiki_min_rep,
- karma_mode = None, badges_mode = None
- ) -%}
-{# there is a whole bunch of trickery here, probably indicative of
-poor design of the data or methods on data objects #}
-{% if contributor_type=="original_author" %}
- <div class='post-update-info'>
- {% if is_wiki %}
- <p>
- {%- if post.post_type == 'question' -%}
- {%- trans %}asked{% endtrans %}
- {% elif post.post_type == 'answer' %}
- {%- trans %}answered{% endtrans %}
- {% else %}
- {%- trans %}posted{% endtrans %}
- {% endif %}
- <strong>{{ timeago(post.added_at) }}</strong>
- </p>
- <img width="35" height="35"
- src="{{'/images/wiki.png'|media}}"
- alt="{% trans %}this post is marked as community wiki{% endtrans %}"
- style="float:left"
- />
- <p class="tip">{% trans %}This post is a wiki.
- Anyone with karma &gt;{{wiki_min_rep}} is welcome to improve it.{% endtrans %}</p>
- {% else %}
- <p style="line-height:12px;">
- {# todo: access to class names needs to be removed here #}
- {% if post.post_type == 'question' %}
- {% trans %}asked{% endtrans %}
- {% elif post.post_type == 'answer' %}
- {% trans %}answered{% endtrans %}
- {% else %}
- {% trans %}posted{% endtrans %}
- {% endif %}
- {% if post.__class__.__name__ == 'PostRevision' %}
- <strong>{{ timeago(post.revised_at) }}</strong>
- {% else %}
- <strong>{{ timeago(post.added_at) }}</strong>
- {% endif %}
- </p>
- {{ post_contributor_avatar_and_credentials(
- post, post.author, karma_mode = karma_mode, badges_mode = badges_mode
- ) }}
- {% endif %}
- </div>
-{% elif contributor_type=="last_updater" %}
- {% if post.post_type in ('question', 'answer') %}
- {% set last_edited_at = post.last_edited_at %}
- {% set original_author = post.author %}
- {% set update_author = post.last_edited_by %}
- {% elif post.__class__.__name__ == 'PostRevision' %}
- {% set last_edited_at = post.revised_at %}
- {% set original_author = None %}{# fake value to force display widget in the revision views #}
- {% set update_author = post.author %}
- {% endif %}
- {% if last_edited_at %}
- <div class='post-update-info'>
- <p style="line-height:12px;">
- <a
- {% if post.post_type == 'question' %}
- href="{% url question_revisions post.id %}"
- {% else %}
- href="{% url answer_revisions post.id %}"
- {% endif %}
- >{% trans %}updated{% endtrans %} <strong>{{ timeago(last_edited_at) }}</strong></a>
- </p>
- {% if original_author != update_author or is_wiki %}
- {{
- post_contributor_avatar_and_credentials(
- post, update_author,
- karma_mode = karma_mode, badges_mode = badges_mode
- )
- }}
- {% endif %}
- </div>
- {% endif %}
-{% endif %}
-{%- endmacro -%}
-
-{%- macro if_else(condition, if_true, if_false) -%}
- {%- if condition == True -%}
- {{if_true}}
- {%- else -%}
- {{if_false}}
- {%- endif -%}
-{%- endmacro -%}
-
-{%- macro tag_cloud(tags = None, font_sizes = None, search_state = None) -%}
- {% for tag in tags %}
- <span class="tag-size-{{ font_sizes[tag.name] }}">
- <a
- class="link-typeA"
- title="Number of entries: {{ tag.used_count }}"
- href="{{ search_state.add_tag(tag.name).full_url() }}"
- >{{ tag.name }}</a>
- </span>
- {% endfor %}
-{%- endmacro -%}
-
-{%- macro tag_list_widget(
- tags,
- id = None,
- deletable = False,
- make_links = True,
- search_state = None,
- css_class = None,
- tag_css_class = None,
- tag_html_tag = 'li',
- truncate_long_tags = False
- )
--%}
-<ul {% if id %}id="{{ id }}"{% endif %}
- class="tags{% if css_class %} {{css_class}}{% endif %}"
->
- {% if tags %}
- {% for tag in tags %}
- {{ tag_widget(
- tag,
- css_class = tag_css_class,
- deletable = deletable,
- is_link = make_links,
- search_state = search_state,
- html_tag = tag_html_tag,
- truncate_long_tag = False
- )}}
- {% endfor %}
- {% endif %}
-</ul>
-{%- endmacro -%}
-
-{%- macro user_group(group, membership_info) -%}
- <td>
- <a class="group-name"
- href="{% url users_by_group group.id, group.name|replace('-', ' ')|slugify %}"
- >{{ group.name|escape }}</a>
- </td>
- <td>
- <span class="group-description">
- {% if group.tag_wiki %}
- {{ group.tag_wiki.summary }}
- {% endif %}
- </span>
- </td>
- <td>
- {% if membership_info %}
- {{ group_join_button(
- group_id = group.id,
- can_join = membership_info['can_join'],
- is_member = membership_info['is_member']
- )
- }}
- {% endif %}
- </td>
-{%- endmacro -%}
-
-{%- macro group_join_button(group_id = None, can_join = False, is_member = False) -%}
- {% if can_join or is_member %}
- <button
- class="group-join-btn follow-toggle {% if is_member %}on on-state{% endif %}"
- data-group-id="{{group_id}}"
- data-off-prompt-text="{% trans %}Leave this group{% endtrans %}"
- data-on-prompt-text="{% trans %}Join this group{% endtrans %}"
- data-on-state-text="{% trans %}You are a member{% endtrans %}"
- data-off-state-text="{% trans %}Join this group{% endtrans %}"
- >
- {% if is_member %}
- {% trans %}You are a member{% endtrans %}
- {% else %}
- {% if can_join %}
- {% trans %}Join this group{% endtrans %}
- {% endif %}
- {% endif %}
- </button>
- {% endif %}
-{%- endmacro -%}
-
-{# todo: remove the extra content argument to make its usage more explicit #}
-{%- macro tag_widget(
- tag,
- deletable = False,
- is_link = True,
- delete_link_title = None,
- css_class = None,
- search_state = None,
- html_tag = 'div',
- extra_content = '',
- truncate_long_tag = False
- )
--%}
- {% if not search_state %} {# get empty SearchState() if there's none; CAUTION: for some reason this doesn't work inside `spaceless` tag below! #}
- {% set search_state=search_state|get_empty_search_state %}
- {% endif %}
- {% spaceless %}
- <{{ html_tag }} class="tag-left{% if deletable %} deletable-tag{% endif %}">
- <{% if not is_link or tag[-1] == '*' %}span{% else %}a{% endif %}
- class="tag tag-right{% if css_class %} {{ css_class }}{% endif %}"
- {% if is_link %}
- href="{{ search_state.add_tag(tag).full_url() }}"
- title="{% trans tag=tag|escape %}see questions tagged '{{ tag }}'{% endtrans %}"
- {% endif %}
- rel="tag"
- data-tag-name="{{ tag|replace('*', '&#10045;')|escape }}"
- >{% if truncate_long_tag -%}
- {{ tag|replace('*', '&#10045;')|truncate(17, True)|escape }}
- {%- else -%}
- {{ tag|replace('*', '&#10045;')|escape }}
- {%- endif %}</{% if not is_link or tag[-1] == '*' %}span{% else %}a{% endif %}>
- {% if deletable %}
- <div class="delete-icon"
- {% if delete_link_title %}
- title="{{ delete_link_title }}"
- {% endif %}
- >x</div>
- {% endif %}
- </{{ html_tag }}>
- {{ extra_content }}
- {% endspaceless %}
-{%- endmacro -%}
-
-{%- macro radio_select(name = None, value = None, choices = None) -%}
- {% for choice in choices %}
- <p class="choice">
- {% set id = "id_" ~ name ~ "_" ~ choice[0] %}
- <input
- id="{{ id }}"
- name="{{ name }}"
- value="{{ choice[0] }}"
- type="radio"
- {% if value == choice[0] %}
- checked="checked"
- {% endif %}
- />
- <label for="{{ id }}">{{ choice[1] }}</label>
- </p>
- {% endfor %}
-{%- endmacro -%}
-
-{%- macro question_summary(thread, question, extra_class=None, search_state=None) -%}
-{%include "widgets/question_summary.html" %}
-{%- endmacro -%}
-
-{# Warning! Any changes to the comment markup here must be duplicated in post.js
-for the purposes of the AJAX comment editor #}
-
-{%- macro add_or_show_comments_button(post = None, max_comments = None, widget_id = None) -%}
- {% if post.comment_count > max_comments %}
- {% set remaining_comment_count = post.comment_count - max_comments %}
- {% else %}
- {% set remaining_comment_count = 0 %}
- {% endif %}
- <a id="add-comment-to-post-{{post.id}}" class="button"></a>
- <script type="text/javascript">
- askbot['data']['{{widget_id}}'] = {
- truncated: {% if post.comment_count > max_comments %}true{% else %}false{% endif %}
- };
- askbot['functions']['renderAddCommentButton'](
- '{{post.id}}',
- {{remaining_comment_count}}
- );
- </script>
-{%- endmacro -%}
-
-{%- macro post_comments_widget(
- post=None,
- show_post = None,
- show_comment = None,
- show_comment_position = None,
- user=None,
- max_comments=None
- )
--%}
- {% spaceless %}
- {% if post.comment_count > 0 %}
- <h2 id="comment-title">Comments</h2>
- <div class="clean"></div>
- {% endif %}
- {% set widget_id = 'comments-for-' + post.post_type + '-' + post.id|string %}
- <div class="comments" id="{{widget_id}}">
- <div class="content">
- {% if show_post == post and show_comment and show_comment_position > max_comments %}
- {% set comments = post.get_cached_comments()[:show_comment_position] %}
- {% else %}
- {% set comments = post.get_cached_comments()[:max_comments] %}
- {% endif %}
- {% for comment in comments %}
- {# Warning! Any changes to the comment markup IN THIS `FOR` LOOP must be duplicated in post.js
- for the purposes of the AJAX comment editor #}
- <div class="comment" id="comment-{{comment.id}}">
- <div class="comment-votes">
- {% if comment.score > 0 %}
- <div
- id="comment-img-upvote-{{comment.id}}"
- class="upvote"
- >{{comment.score}}</div>
- <script type="text/javascript">
- askbot['functions']['renderPostVoteButtons']('comment', '{{comment.id}}');
- </script>
- {% else %}
- <div class="upvote"></div>
- {% endif %}
- </div>
- <div
- id="post-{{comment.id}}-delete"
- class="comment-delete"
- >
- <span class="delete-icon" title="{% trans %}delete this comment{% endtrans %}"></span>
- </div>
- <div class="comment-body">
- {{comment.html}}
- <a class="author" href="{{comment.author.get_profile_url()}}">{{comment.author.username|escape}}</a>
- <span class="age">&nbsp;({{ timeago(comment.added_at) }})</span>
- <a id="post-{{comment.id}}-edit"
- class="edit">{% trans %}edit{% endtrans %}</a>
- </div>
- </div>
- <script type="text/javascript">
- askbot['functions']['renderPostControls']('{{comment.id}}');
- </script>
- {% endfor %}
- </div>
- <div class="controls">
- {% if show_post == post and show_comment %}
- {% if show_comment_position > max_comments %}
- {{
- add_or_show_comments_button(
- post = post,
- max_comments = show_comment_position,
- widget_id = widget_id
- )
- }}
- {% else %}
- {{
- add_or_show_comments_button(
- post = post,
- max_comments = max_comments,
- widget_id = widget_id
- )
- }}
- {% endif %}
- {% else %}
- {{
- add_or_show_comments_button(
- post = post,
- max_comments = max_comments,
- widget_id = widget_id
- )
- }}
- {% endif %}
- </div>
- </div>
- {% endspaceless %}
-{%- endmacro -%}
-
-{%- macro reversible_sort_button(button_sort_criterium=None, asc_tooltip=None,
- desc_tooltip=None, label=None, current_sort_method=None, search_state=None) -%}
-{#
- sort button where descending sort is default
- and the search method is togglable between ascending and descending
- buttons are rendered as links with id constructed as
- "by_" + button_sort_criterium
- class "on" is added when current_sort_method is one of
- button_sort_criterium + "asc" or "desc"
-#}
- {% set key_name = button_sort_criterium %}
- {% if current_sort_method == key_name + "-asc" %}{# "worst" first #}
- <a id="by_{{key_name}}"
- href="{{ search_state.change_sort(key_name+"-desc").full_url() }}"
- class="rev on"
- title="{{desc_tooltip}}"><span>{{label}} &#9650;</span></a>
- {% elif current_sort_method == key_name + "-desc" %}{# "best first" #}
- <a id="by_{{key_name}}"
- href="{{ search_state.change_sort(key_name+"-asc").full_url() }}"
- class="rev on"
- title="{{asc_tooltip}}"><span>{{label}} &#9660;</span></a>
- {% else %}{# default, when other button is active #}
- <a id="by_{{key_name}}"
- href="{{ search_state.change_sort(key_name+"-desc").full_url() }}"
- class="off"
- title="{{desc_tooltip}}"><span>{{label}}</span></a>
- {% endif %}
- <script type="text/javascript">{# need to pass on text translations to js #}
- var sortButtonData = sortButtonData || {};
- sortButtonData["{{key_name}}"] = {
- label: "{{label}}",
- asc_tooltip: "{{asc_tooltip}}",
- desc_tooltip: "{{desc_tooltip}}"
- };
- </script>
-{%- endmacro %}
-
-{%- macro checkbox_in_div(checkbox_field, class = 'checkbox') -%}
- <div{% if class %} class="{{class}}"{% endif %}
- title="{{checkbox_field.help_text}}">
- {{ checkbox_field }}
- {{ checkbox_field.label_tag() }}
- {{ checkbox_field.errors }}
- </div>
-{%- endmacro -%}
-
-{%- macro edit_post(
- post_form,
- post_type = None,
- mandatory_tags = None,
- edit_title = False
- )
--%}
-{%include "widgets/edit_post.html" %}
-{%- endmacro -%}
-
-{%- macro tag_autocomplete_js(id = '#id_tags') -%}
- var tagAc = new AutoCompleter({
- url: '{% url "get_tag_list" %}',
- preloadData: true,
- minChars: 1,
- useCache: true,
- matchInside: true,
- maxCacheLength: 100,
- delay: 10
- });
- tagAc.decorate($("{{ id }}"));
-{%- endmacro -%}
-
-{%- macro answer_classes(answer, question) -%}
-answer {% if answer.accepted() %}accepted-answer{% endif %} {% if answer.author_id==question.author_id %} answered-by-owner{% endif %} {% if answer.deleted %}deleted{% endif -%}
-{%- endmacro -%}
-
-{%- macro user_score_and_badge_summary(
- user,
- karma_mode = None,
- badges_mode = None
-) -%}
- {%include "widgets/user_score_and_badge_summary.html"%}
-{%- endmacro -%}
-
-{%- macro follow_toggle(follow, name, alias, id) -%}
- {# follow - boolean; name - object type name; alias - e.g. users name; id - object id #}
- <div
- class="follow-toggle"
- id="follow-{{ name }}-{{ id }}"
- >
- {% if follow %}
- <div class="follow">{% trans %}follow {{alias}}{% endtrans %}</div>
- {% else %}
- <div class="unfollow">
- <div class="unfollow-red">{% trans %}unfollow {{alias}}{% endtrans %}</div>
- <div class="unfollow-green">{% trans %}following {{alias}}{% endtrans %}</div>
- </div>
- {% endif %}
- </div>
-{%- endmacro -%}
-
-{%- macro follow_user_toggle(visitor = None, subject = None) -%}
- {% if visitor.is_anonymous() %}
- {{ follow_toggle(True, 'user', subject.username|escape, subject.id) }}
- {% else %}
- {% if visitor != subject %}
- {% if visitor.is_following(subject) %}
- {{ follow_toggle(False, 'user', subject.username|escape, subject.id) }}
- {% else %}
- {{ follow_toggle(True, 'user', subject.username|escape, subject.id) }}
- {% endif %}
- {% endif %}
- {% endif %}
-{%- endmacro -%}
-
-{%- macro user_long_score_and_badge_summary(user, badges_mode = None) -%}
- {%- include "widgets/user_long_score_and_badge_summary.html" -%}
-{%- endmacro -%}
-
-{%- macro user_country_flag(user) -%}
- {% if user.country and user.show_country %}
- <img class="flag"
- src="{{ ('/images/flags/' ~ user.country.code|lower ~ '.gif')|media }}"
- alt="{% trans
- country=user.country.name
- %}flag of {{country}}{%
- endtrans %}"
- title="{% trans
- country=user.country.name,
- person=user.username|escape %}{{person}} is from {{country}}{%
- endtrans %}"
- />
- {% endif %}
-{%- endmacro -%}
-
-{%- macro user_country_name_and_flag(user) -%}
- {% if user.country and user.show_country %}
- {{ user.country.name }}
- {{ user_country_flag(user) }}
- {% endif %}
-{%- endmacro -%}
-
-{%- macro user_full_location(user) -%}
- {% if user.location %}
- {{ user.location }},
- {% endif %}
- {{ user_country_name_and_flag(user) }}
-{%- endmacro -%}
-
-{%- macro user_list(
- users, profile_section = None, karma_mode = None, badges_mode = None
- )
--%}
-{% include "widgets/user_list.html"%}
-{%- endmacro -%}
-
-{#todo: rename this to avatar #}
-{%- macro gravatar(user, size) -%}
-{% spaceless %}
-<a style="text-decoration:none"
- href="{{ user.get_absolute_url() }}"
-><img class="gravatar"
- width="{{size}}" height="{{size}}"
- src="{{ user.get_avatar_url(size) }}"
- title="{{user.username|escape}}"
- alt="{% trans username=user.username|escape %}{{username}} gravatar image{% endtrans %}"
-/></a>
-{% endspaceless %}
-{%- endmacro -%}
-
-{%- macro user_website_link(user, max_display_length=25) -%}
- {% if user.website and (not user.is_blocked()) %}
- <a
- href="{{user.website}}"
- title="{% trans username=user.username|escape, url=user.website %}{{username}}'s website is {{url}}{% endtrans %}"
- {% if user.can_have_strong_url() == False %}
- rel="nofollow"
- {% endif %}
- >
- {{user.website|truncate(length=max_display_length, killwords=True, end='...')}}
- </a>
- {% endif %}
-{%- endmacro -%}
-
-{%- macro paginator(p, position='left', anchor='') -%}{# p is paginator context dictionary #}
-{% spaceless %}
- {% if p.is_paginated %}
- <div class="paginator" style="float:{{position}}">
- {% if p.has_previous %}
- <span class="prev"><a href="{{p.base_url}}page={{ p.previous }}{{ anchor }}" title="{% trans %}previous{% endtrans %}">
- &laquo; {% trans %}previous{% endtrans %}</a></span>
- {% endif %}
- {% if not p.in_leading_range %}
- {% for num in p.pages_outside_trailing_range %}
- <span class="page"><a href="{{p.base_url}}page={{ num }}{{ anchor }}" >{{ num }}</a></span>
- {% endfor %}
- ...
- {% endif %}
-
- {% for num in p.page_numbers %}
- {% if num == p.page and p.pages != 1%}
- <span class="curr" title="{% trans %}current page{% endtrans %}">{{ num }}</span>
- {% else %}
- <span class="page"><a href="{{p.base_url}}page={{ num }}{{ anchor }}" title="{% trans %}page {{num}}{% endtrans %}">{{ num }}</a></span>
- {% endif %}
- {% endfor %}
-
- {% if not p.in_trailing_range %}
- ...
- {% for num in p.pages_outside_leading_range|reverse %}
- <span class="page"><a href="{{p.base_url}}page={{ num }}{{ anchor }}" title="{% trans %}page {{ num }}{% endtrans %}">{{ num }}</a></span>
- {% endfor %}
- {% endif %}
- {% if p.has_next %}
- <span class="next"><a href="{{p.base_url}}page={{ p.next }}{{ anchor }}" title="{% trans %}next page{% endtrans %}">{% trans %}next page{% endtrans %} &raquo;</a></span>
- {% endif %}
- </div>
- {% endif %}
-{% endspaceless %}
-{%- endmacro -%}
-
-
-
-{%- macro paginator_main_page(p, position, search_state) -%} {# p is paginator context dictionary #}
- {% spaceless %}
- {% if p.is_paginated %}
- <div class="paginator" style="float:{{position}}">
- {% if p.has_previous %}
- <span class="prev"><a href="{{ search_state.change_page(p.previous).full_url() }}" title="{% trans %}previous{% endtrans %}">
- &laquo; {% trans %}previous{% endtrans %}</a></span>
- {% endif %}
- {% if not p.in_leading_range %}
- {% for num in p.pages_outside_trailing_range %}
- <span class="page"><a href="{{ search_state.change_page(num).full_url() }}" >{{ num }}</a></span>
- {% endfor %}
- ...
- {% endif %}
-
- {% for num in p.page_numbers %}
- {% if num == p.page and p.pages != 1%}
- <span class="curr" title="{% trans %}current page{% endtrans %}">{{ num }}</span>
- {% else %}
- <span class="page"><a href="{{ search_state.change_page(num).full_url() }}" title="{% trans %}page {{num}}{% endtrans %}">{{ num }}</a></span>
- {% endif %}
- {% endfor %}
-
- {% if not p.in_trailing_range %}
- ...
- {% for num in p.pages_outside_leading_range|reverse %}
- <span class="page"><a href="{{ search_state.change_page(num).full_url() }}" title="{% trans %}page {{ num }}{% endtrans %}">{{ num }}</a></span>
- {% endfor %}
- {% endif %}
- {% if p.has_next %}
- <span class="next"><a href="{{ search_state.change_page(p.next).full_url() }}" title="{% trans %}next page{% endtrans %}">{% trans %}next page{% endtrans %} &raquo;</a></span>
- {% endif %}
- </div>
- {% endif %}
- {% endspaceless %}
-{%- endmacro -%}
-
-
-{%- macro inbox_link(user) -%}
- {% if user.new_response_count > 0 or user.seen_response_count > 0 %}
- <a id='ab-responses' href="{{user.get_absolute_url()}}?sort=inbox&section=forum">
- <img
- alt="{% trans username=user.username|escape %}responses for {{username}}{% endtrans %}"
- {% if user.new_response_count > 0 %}
- src="{{ "/images/mail-envelope-full.png"|media }}"
- title="{% trans response_count=user.new_response_count %}you have {{response_count}} new response{% pluralize %}you have {{response_count}} new responses{% endtrans %}"
- {% elif user.seen_response_count > 0 %}
- src="{{ "/images/mail-envelope-empty.png"|media }}"
- title="{% trans %}no new responses yet{% endtrans %}"
- {% endif %}
- />
- </a>
- {% endif %}
-{%- endmacro -%}
-
-{%- macro moderation_items_link(user, moderation_items) -%}
- {% if moderation_items %}
- <a id="ab-responses"
- href="{{user.get_absolute_url()}}?sort=inbox&section=flags"
- >
- {% if moderation_items['new_count'] > 0 %}
- <img src="{{'/images/dialog-warning.png'|media}}"
- {% if moderation_items['seen_count'] > 0 %}
- alt="{% trans new=moderation_items['new_count'], seen=moderation_items['seen_count']%}{{new}} new flagged posts and {{seen}} previous{% endtrans %}"
- title="{% trans new=moderation_items['new_count'], seen=moderation_items['seen_count']%}{{new}} new flagged posts and {{seen}} previous{% endtrans %}"
- {% else %}
- alt="{% trans new=moderation_items['new_count'] %}{{new}} new flagged posts{% endtrans %}"
- title="{% trans new=moderation_items['new_count'] %}{{new}} new flagged posts{% endtrans %}"
- {% endif %}
- />
- {% elif moderation_items['seen_count'] > 0 %}
- <img src={{'/images/dialog-warning-off.png'|media}}
- alt="{% trans seen=moderation_items['seen_count'] %}{{seen}} flagged posts{% endtrans %}"
- title="{% trans seen=moderation_items['seen_count'] %}{{seen}} flagged posts{% endtrans %}"
- />
- {% endif %}
- </a>
- {% endif %}
-{%- endmacro -%}
-
-{%- macro timeago(datetime_object) -%}
- <abbr class="timeago" title="{{datetime_object.replace(microsecond=0)|add_tz_offset}}">
- {{datetime_object.replace(microsecond=0)|add_tz_offset}}
- </abbr>
-{%- endmacro -%}
diff --git a/askbot/skins/default/templates/main_page/headline.html b/askbot/skins/default/templates/main_page/headline.html
deleted file mode 100644
index cc6f47a5..00000000
--- a/askbot/skins/default/templates/main_page/headline.html
+++ /dev/null
@@ -1,43 +0,0 @@
-{% import "macros.html" as macros %}
-{% if questions_count > 0 %}
- <h1 id="questionCount" class="search-result-summary">
- {% trans cnt=questions_count, q_num=questions_count|intcomma %}{{q_num}} question{% pluralize %}{{q_num}} questions{% endtrans %}
- {% if author_name %}
- {% trans %}with {{author_name}}'s contributions{% endtrans %}
- {% endif %}
- </h1>
- <div class="clearfix"></div>
- {% if search_tags %}
- <div id="listSearchTags">
- <span class="left">{% trans %}Tagged{% endtrans %}</span>
- {{ macros.tag_list_widget(
- search_tags,
- id = 'searchTags',
- deletable = True,
- make_links = False,
- search_state = search_state
- )
- }}
- </div>
- {% endif %}
- {#% if author_name or search_tags or query %}
- <p class="search-tips"><b>{% trans %}Search tips:{% endtrans %}</b>
- {% if reset_method_count > 1 %}
- {% if author_name %}
- <a href="{{ search_state.remove_author().full_url() }}">{% trans %}reset author{% endtrans %}</a>
- {% endif %}
- {% if search_tags %}{% if author_name and query %}, {% elif author_name %}{% trans %} or {% endtrans %}{% endif %}
- <a href="{{ search_state.remove_tags().full_url() }}">{% trans %}reset tags{% endtrans %}</a>
- {% endif %}
- {% if query %}{% trans %} or {% endtrans %}
- <a href="{% url questions %}">{% trans %}start over{% endtrans %}</a>
- {% endif %}
- {% else %}
- <a href="{% url questions %}">{% trans %}start over{% endtrans %}</a>
- {% endif %}
- {% trans %} - to expand, or dig in by adding more tags and revising the query.{% endtrans %}
- </p>
- {% else %}
- <p class="search-tips"><b>{% trans %}Search tip:{% endtrans %}</b> {% trans %}add tags and a query to focus your search{% endtrans %}</p>
- {% endif %#}
-{% endif %}
diff --git a/askbot/skins/default/templates/main_page/javascript.html b/askbot/skins/default/templates/main_page/javascript.html
deleted file mode 100644
index 10f8ede2..00000000
--- a/askbot/skins/default/templates/main_page/javascript.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<script type="text/javascript">
- var sortMethod = '{{sort}}';
- var showSortByRelevance = {% if show_sort_by_relevance %}true{% else %}false{% endif %};
- var minSearchWordLength = {{settings.MIN_SEARCH_WORD_LENGTH}};
- $(document).ready(function(){
- /*var on_tab = '#nav_questions';
- $(on_tab).attr('className','on');*/
- liveSearch('{{ search_state.query_string()|escapejs }}');
- Hilite.exact = false;
- Hilite.elementid = "question-list";
- Hilite.debug_referrer = location.href;
- {% if update_avatar_data == True %}
- var today = new Date();{#add timestamp to prevent browser caching #}
- $.getJSON('{% url user_update_has_custom_avatar %}?t=' + today.getTime());
- {% endif %}
- });
-
- askbot['urls']['mark_interesting_tag'] = '{% url mark_interesting_tag %}';
- askbot['urls']['mark_ignored_tag'] = '{% url mark_ignored_tag %}';
- askbot['urls']['mark_subscribed_tag'] = '{% url mark_subscribed_tag %}';
- askbot['urls']['unmark_tag'] = '{% url unmark_tag %}';
- askbot['urls']['set_tag_filter_strategy'] = '{% url "set_tag_filter_strategy" %}';
- askbot['urls']['questions'] = '{% url "questions" %}';
- askbot['urls']['question_url_template'] = scriptUrl + '{{'question/'|transurl}}{{ "{{QuestionID}}/" }}';
-</script>
-<script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
-{% if request.user.is_authenticated() %}
-<script type='text/javascript' src='{{"/js/tag_selector.js"|media}}'></script>
-{% endif %}
-<script type="text/javascript" src='{{"/js/live_search.js"|media}}'></script>
diff --git a/askbot/skins/default/templates/main_page/questions_loop.html b/askbot/skins/default/templates/main_page/questions_loop.html
deleted file mode 100644
index 6a5e5e3d..00000000
--- a/askbot/skins/default/templates/main_page/questions_loop.html
+++ /dev/null
@@ -1,15 +0,0 @@
-{% import "macros.html" as macros %}
-{# cache 0 "questions" questions search_tags scope sort query context.page language_code #}
-{% for thread in threads.object_list %}
- {# {{macros.question_summary(thread, thread._question_post(), search_state=search_state)}} #}
- {{ thread.get_summary_html(search_state=search_state) }}
-{% endfor %}
-{% if threads.object_list|length == 0 %}
- {% include "main_page/nothing_found.html" %}
-{% else %}
- <div class="evenMore">
- {% trans %}Did not find what you were looking for?{% endtrans %}
- <a href="{% url ask %}">{% trans %}Please, post your question!{% endtrans %}</a>
- </div>
-{% endif %}
-
diff --git a/askbot/skins/default/templates/meta/bottom_scripts.html b/askbot/skins/default/templates/meta/bottom_scripts.html
deleted file mode 100644
index 2603ec31..00000000
--- a/askbot/skins/default/templates/meta/bottom_scripts.html
+++ /dev/null
@@ -1,95 +0,0 @@
-{# most, if not all javascripts should go here
- this template is included at the very bottow of the
- main template "base.html"
-#}
-<div id="no-javascript">
- <noscript class="noscript">
- {% trans app_name = settings.APP_SHORT_NAME %}Please note: {{app_name}} requires javascript to work properly, please enable javascript in your browser, <a href="{{noscript_url}}">here is how</a>{% endtrans %}
- </noscript>
-</div>
-<script type="text/javascript">
- var i18nLang = '{{settings.LANGUAGE_CODE}}';
- var scriptUrl = '/{{settings.ASKBOT_URL}}'
- var askbotSkin = '{{settings.ASKBOT_DEFAULT_SKIN}}';
- var enableMathJax = {% if settings.ENABLE_MATHJAX %}true{% else %}false{% endif %};
- askbot['urls']['mark_read_message'] = '{% url "read_message" %}';
- askbot['urls']['get_tags_by_wildcard'] = '{% url "get_tags_by_wildcard" %}';
- askbot['urls']['get_tag_list'] = '{% url "get_tag_list" %}';
- askbot['urls']['follow_user'] = '/followit/follow/user/{{'{{'}}userId{{'}}'}}/';
- askbot['urls']['unfollow_user'] = '/followit/unfollow/user/{{'{{'}}userId{{'}}'}}/';
- askbot['urls']['user_signin'] = '{{ settings.LOGIN_URL }}';
- askbot['settings']['static_url'] = '{{ settings.STATIC_URL }}';
-</script>
-<script
- type="text/javascript"
- {% if settings.DEBUG %}
- src="{{"/js/jquery-1.7.2.min.js"|media}}"
- {% else %}
- src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"
- {% endif %}
-></script>
-<!-- History.js -->
-<script type='text/javascript' src="{{"/js/jquery.history.js"|media }}"></script>
-<script type="text/javascript" src="{% url django.views.i18n.javascript_catalog %}"></script>
-<script type='text/javascript' src="{{"/js/utils.js"|media }}"></script>
-{% if settings.ENABLE_MATHJAX %}
- <script type='text/javascript' src="{{settings.MATHJAX_BASE_URL}}/MathJax.js">
- MathJax.Hub.Config({
- extensions: ["tex2jax.js"],
- jax: ["input/TeX","output/HTML-CSS"],
- tex2jax: {inlineMath: [["$","$"],["\\(","\\)"]]}
- });
- </script>
-{% endif %}
-<script type="text/javascript">
-{% if active_tab != "tags" and active_tab != "users" %}
- $(document).ready(function(){
- if (Modernizr.history) {
- // history management works!
- } else {
- // no history support :(
- //hash = unescape(window.location.hash).replace('#','').split("?")[0]
- hash = History.unescapeHash(window.location.hash).replace('#','').split("?")[0]
- if (hash.substring(0,11)==askbot['urls']['questions']){
- url = hash
- }else{
- url = askbot['urls']['questions']+hash
- }
- if (hash !== ''){
- window.location = 'http://'+window.location.host+url
- }
- }
-
- // focus input on the search bar endcomment
- {% if active_tab != "ask" %}
- $('#keywords').focus();
- {% else %}
- $('#id_title').focus();
- {% endif %}
- animateHashes();
- });
-{% endif %}
-{% if user_messages %}
- $('#validate_email_alert').click(function(){notify.close(true)})
- notify.show();
-{% endif %}
- $('abbr.timeago').timeago();
-</script>
-{% if settings.USE_CUSTOM_JS %}
-<script
- src="{% url "custom_js"%}?v={{ settings.MEDIA_RESOURCE_REVISION }}"
- type="text/javascript"
-></script>
-{% endif %}
-{% if settings.GOOGLE_ANALYTICS_KEY %}
-<script type="text/javascript">
- var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
- document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
- </script>
- <script type="text/javascript">
- try {
- var pageTracker = _gat._getTracker('{{ settings.GOOGLE_ANALYTICS_KEY }}');
- pageTracker._trackPageview();
- } catch(err) {}
-</script>
-{% endif %}
diff --git a/askbot/skins/default/templates/meta/editor_data.html b/askbot/skins/default/templates/meta/editor_data.html
deleted file mode 100644
index 2363281c..00000000
--- a/askbot/skins/default/templates/meta/editor_data.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<script type="text/javascript">
- {# data necessary for the post editor, goes into endjs block #}
- askbot['settings']['tagsAreRequired'] =
- {% if settings.TAGS_ARE_REQUIRED %}true{% else %}false{% endif %};
- askbot['settings']['maxTagLength'] = {{settings.MAX_TAG_LENGTH}};
- 'each tag must be shorter than %(max_chars)d characters',
- askbot['messages']['maxTagLength'] = '{% trans max_chars = settings.MAX_TAG_LENGTH %}each tag must be shorter that {{max_chars}} character{% pluralize %}each tag must be shorter than {{max_chars}} characters{% endtrans %}';
- askbot['settings']['maxTagsPerPost'] = {{settings.MAX_TAGS_PER_POST}};
- askbot['messages']['maxTagsPerPost'] = '{% trans tag_count = settings.MAX_TAGS_PER_POST %}please use {{tag_count}} tag{% pluralize %}please use {{tag_count}} tags or less{% endtrans %}';
- askbot['messages']['tagLimits'] = '{% trans tag_count=settings.MAX_TAGS_PER_POST, max_chars=settings.MAX_TAG_LENGTH %}please use up to {{tag_count}} tags, less than {{max_chars}} characters each{% endtrans %}';
- askbot['urls']['upload'] = '{% url "upload" %}';
- askbot['settings']['minTitleLength'] = {{settings.MIN_TITLE_LENGTH}}
- askbot['settings']['minQuestionBodyLength'] = {{settings.MIN_QUESTION_BODY_LENGTH}}
- askbot['settings']['minAnswerBodyLength'] = {{settings.MIN_ANSWER_BODY_LENGTH}}
-</script>
diff --git a/askbot/skins/default/templates/meta/fonts.html b/askbot/skins/default/templates/meta/fonts.html
deleted file mode 100644
index f55d567c..00000000
--- a/askbot/skins/default/templates/meta/fonts.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<style type="text/css">
-@font-face {
- font-family: 'Yanone Kaffeesatz';
- font-style: normal;
- font-weight: 400;
- src: url('{{"/images/YanoneKaffeesatz-Regular.ttf"|media}}');
-}
-@font-face {
- font-family: 'Yanone Kaffeesatz';
- font-style: normal;
- font-weight: 700;
- src: url('{{"/images/YanoneKaffeesatz-Bold.ttf"|media}}');
-}
-@font-face {
- font-family: 'Yanone Kaffeesatz';
- font-style: normal;
- font-weight: 300;
- src: url('{{"/images/YanoneKaffeesatz-Light.ttf"|media}}');
-}
-</style>
diff --git a/askbot/skins/default/templates/meta/html_head_javascript.html b/askbot/skins/default/templates/meta/html_head_javascript.html
deleted file mode 100644
index 65d0bdce..00000000
--- a/askbot/skins/default/templates/meta/html_head_javascript.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<script src="{{"/js/modernizr.custom.js"|media }}"></script>
-<script type="text/javascript">
- var askbot = {};
- askbot['data'] = {};
- {% if request.user.is_authenticated() %}
- askbot['data']['userIsAuthenticated'] = true;
- askbot['data']['userId'] = {{request.user.id}};
- askbot['data']['userIsAdminOrMod'] = {% if
- request.user.is_administrator()
- or request.user.is_moderator()
- %}true{% else %}false{% endif %};
- askbot['data']['userReputation'] = {{request.user.reputation}};
- {% else %}
- askbot['data']['userIsAuthenticated'] = false;
- askbot['data']['userReputation'] = 0;
- {% endif %}
- askbot['urls'] = {};
- askbot['settings'] = {};
- askbot['messages'] = {};
-</script>
-{# avoid adding javascript here so that pages load faster #}
diff --git a/askbot/skins/default/templates/meta/html_head_meta.html b/askbot/skins/default/templates/meta/html_head_meta.html
deleted file mode 100644
index 352ffb53..00000000
--- a/askbot/skins/default/templates/meta/html_head_meta.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
-{% block meta_description %}
-<meta name="description" content="{{settings.APP_DESCRIPTION|escape}}" />
-{% endblock %}
-<meta name="keywords" content="{%block keywords%}{%endblock%},{{settings.APP_KEYWORDS|escape}}" />
-{% if settings.GOOGLE_SITEMAP_CODE %}
-<meta name="google-site-verification" content="{{settings.GOOGLE_SITEMAP_CODE}}" />
-{% endif %}
diff --git a/askbot/skins/default/templates/meta/html_head_stylesheets.html b/askbot/skins/default/templates/meta/html_head_stylesheets.html
deleted file mode 100644
index 0d2ba463..00000000
--- a/askbot/skins/default/templates/meta/html_head_stylesheets.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{% if settings.ASKBOT_CSS_DEVEL == False %}
-<link href="{{"/style/style.css"|media }}" rel="stylesheet" type="text/css" />
-{% else %}
-<link href="{{"/style/style.less"|media }}" rel="stylesheet/less" type="text/css" />
-<script type="text/javascript" src="{{"/js/less.min.js"|media}}"></script>
-{% endif %}
-{% if settings.USE_LOCAL_FONTS %}
- {% include "meta/fonts.html" %}
-{% else %}
- <link href='http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:300,400,700' rel='stylesheet' type='text/css'>
-{% endif %}
-{{ skin.get_extra_css_link() }}
-{% if settings.USE_CUSTOM_CSS %}
- <link
- href="{% url "custom_css" %}?v={{settings.MEDIA_RESOURCE_REVISION}}"
- rel="stylesheet"
- type="text/css"
- />
-{% endif %}
diff --git a/askbot/skins/default/templates/question.html b/askbot/skins/default/templates/question.html
deleted file mode 100644
index bb74db33..00000000
--- a/askbot/skins/default/templates/question.html
+++ /dev/null
@@ -1,194 +0,0 @@
-{% extends "two_column_body.html" %}
-<!-- question.html -->
-{% block title %}{% spaceless %}{{ question.get_question_title()|escape }}{% endspaceless %}{% endblock %}
-{% block meta_description %}
- <meta name="description" content="{{question.summary|striptags|escape}}" />
-{% endblock %}
-{% block keywords %}{{thread.tagname_meta_generator()}}{% endblock %}
-{% block forestyle %}
- <link rel="canonical" href="{{settings.APP_URL|strip_path}}{{question.get_absolute_url()}}" />
- <link rel="stylesheet" type="text/css" href="{{'/js/wmd/wmd.css'|media}}" />
-{% endblock %}
-{% block forejs %}
- <script type="text/javascript">
- //below is pure cross-browser javascript, no jQuery
- (function(){
- var data = askbot['data'];
- if (data['userIsAuthenticated']){
- var votes = {};
- {% for post_id in user_votes %}
- votes['{{post_id}}'] = {{user_votes[post_id]}};
- {% endfor %}
- data['user_votes'] = votes;
- var posts = {};
- {% for post_id in user_post_id_list %}
- posts['{{post_id}}'] = 1;
- {% endfor %}
- data['user_posts'] = posts;
- }
-
- function render_vote_buttons(post_type, post_id){
- var upvote_btn = document.getElementById(
- post_type + '-img-upvote-' + post_id
- );
- var downvote_btn = document.getElementById(
- post_type + '-img-downvote-' + post_id
- );
- if (data['userIsAuthenticated']){
- if (post_id in data['user_votes']){
- var vote = data['user_votes'][post_id];
- if (vote == -1){
- var btn = downvote_btn;
- } else if (vote == 1){
- var btn = upvote_btn;
- } else {
- return;
- }
- if (post_type == 'comment'){
- btn.className = btn.className + ' upvoted';
- } else {
- btn.className = btn.className + ' on';
- }
- }
- }
- }
- function render_post_controls(post_id){
- if (data['userIsAdminOrMod']){
- return;//all functions on
- }
- if (post_id in data['user_posts']){
- //todo: remove edit button from older comments
- return;//same here
- }
- if (//maybe remove "delete" button
- data['userReputation'] <
- {{settings.MIN_REP_TO_DELETE_OTHERS_COMMENTS}}
- ) {
- var delete_btn = document.getElementById(
- 'post-' + post_id + '-delete'
- );
- delete_btn.parentNode.removeChild(delete_btn);
- }
- if (//maybe remove "edit" button
- data['userReputation'] <
- {{settings.MIN_REP_TO_EDIT_OTHERS_POSTS}}
- ){
- var edit_btn = document.getElementById(
- 'post-' + post_id + '-edit'
- )
- edit_btn.parentNode.removeChild(edit_btn);
- }
- if (//maybe remove retag button
- data['userReputation'] <
- {{settings.MIN_REP_TO_RETAG_OTHERS_QUESTIONS}}
- ){
- var retag_btn = document.getElementById('retag');
- retag_btn.parentNode.removeChild(retag_btn);
- }
- }
- function render_add_comment_button(post_id, extra_comment_count){
- var can_add = false;
- {% if user_can_post_comment %}
- can_add = true;
- {% else %}
- if (post_id in data['user_posts']){
- can_add = true;
- }
- {% endif %}
- var add_comment_btn = document.getElementById(
- 'add-comment-to-post-' + post_id
- );
- if (can_add === false){
- add_comment_btn.parentNode.removeChild(add_comment_btn);
- return;
- }
-
- var text = '';
- if (extra_comment_count > 0){
- if (can_add){
- text =
- "{% trans %}post a comment / <strong>some</strong> more{% endtrans %}";
- } else {
- text =
- "{% trans %}see <strong>some</strong> more{% endtrans%}";
- }
- } else {
- if (can_add){
- text = "{% trans %}post a comment{% endtrans %}";
- }
- }
- add_comment_btn.innerHTML = text;
- //add the count
- for (node in add_comment_btn.childNodes){
- if (node.nodeName === 'strong'){
- node.innerHTML = extra_comment_count;
- break;
- }
- }
- }
- function render_add_answer_button(){
- var add_answer_btn = document.getElementById('add-answer-btn');
- if (askbot['data']['userIsAuthenticated']){
- if (askbot['data']['userId'] == {{question.author_id}}){
- add_answer_btn.className += ' answer-own-question';
- add_answer_btn.setAttribute(
- 'value',
- '{% trans %}Answer Your Own Question{% endtrans %}'
- )
- } else {
- add_answer_btn.setAttribute(
- 'value',
- '{% trans %}Post Your Answer{% endtrans %}'
- )
- }
- } else {
- add_answer_btn.setAttribute(
- 'value',
- '{% trans %}Login/Signup to Post{% endtrans %}'
- );
- }
- }
- askbot['functions'] = askbot['functions'] || {};
- askbot['functions']['renderPostVoteButtons'] = render_vote_buttons;
- askbot['functions']['renderPostControls'] = render_post_controls;
- askbot['functions']['renderAddCommentButton'] = render_add_comment_button;
- askbot['functions']['renderAddAnswerButton'] = render_add_answer_button;
- })();
- </script>
-{% endblock %}
-{% block content %}
- <div>
- {{ settings.QUESTION_PAGE_TOP_BANNER }}
- </div>
- {% if is_cacheable %}
- {% cache long_time "thread-content-html" thread.id %}
- {% include "question/content.html" %}
- {% endcache %}
- {% else %}
- {% include "question/content.html" %}
- {% endif %}
-{% endblock %}
-{% block sidebar %}
- {% include "question/sidebar.html" %}
-{% endblock %}
-{% block endjs %}
- {% include "question/javascript.html" %}
- {#
- <script type="text/javascript">
- var messages = askbot['messages'];
- messages['upvote_question'] = gettext(
- 'I like this question (click again to cancel)'
- );
- messages['upvote_answer'] = gettext(
- 'I like this answer (click again to cancel)'
- );
- messages['downvote_question'] = gettext(
- "I don't like this question (click again to cancel)"
- );
- messages['downvote_answer'] = gettext(
- "I don't like this answer (click again to cancel)"
- );
- </script>
- #}
-{% endblock %}
-
diff --git a/askbot/skins/default/templates/question/answer_card.html b/askbot/skins/default/templates/question/answer_card.html
deleted file mode 100644
index 7161c186..00000000
--- a/askbot/skins/default/templates/question/answer_card.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<a name="{{ answer.id }}"></a>
-{% if answer.old_answer_id %}
- {# Make old URL anchors/hashes work #}
- <a class="old_answer_id_anchor" name="{{ answer.old_answer_id }}"></a>
-{% endif %}
-<div
- id="post-id-{{ answer.id }}"
- class="{{ macros.answer_classes(answer, question) }}">
- <div class="vote-buttons">
- {% include "question/answer_vote_buttons.html" %}
- </div>
- <div class="answer-table">
-
- <div class="item-right">
- <div class="answer-body">
- <div class="post-update-info-container">
- {% include "question/answer_author_info.html" %}
- </div>
- {{ answer.html }}
- </div>
- <div class="answer-controls post-controls">
- {% include "question/answer_controls.html" %}
- </div>
- {% include "question/answer_comments.html" %}
- </div>
- </div>
- <div class="clean"></div>
-</div>
-<div class="clean"></div>
diff --git a/askbot/skins/default/templates/question/content.html b/askbot/skins/default/templates/question/content.html
deleted file mode 100644
index 58b1bcca..00000000
--- a/askbot/skins/default/templates/question/content.html
+++ /dev/null
@@ -1,41 +0,0 @@
-{% import "macros.html" as macros %}
-
-{# ==== BEGIN: question/question_card.html ==== #}
-{% include "question/question_card.html" %}
-{# ==== END: question/question_card.html ==== #}
-{% if thread.closed %}
- {# ==== START: question/closed_question_info.html ==== #}
- {% include "question/closed_question_info.html" %}
- {# ==== END: question/closed_question_info.html ==== #}
-{% endif %}
-
-{% if answers %}
- <div class="clean"></div>
-
- {# ==== START: question/answer_tab_bar.html ==== #}
- {% include "question/answer_tab_bar.html" %}
- {# ==== END: question/answer_tab_bar.html ==== #}
-
- <div class="clean"></div>
- {{ macros.paginator(paginator_context, anchor='#sort-top') }}
- <div class="clean"></div>
-
- {% for answer in answers %}
- {# ==== START: question/answer_card.html ==== #}
- {% include "question/answer_card.html" %}
- {# ==== END: question/answer_card.html ==== #}
- {% endfor %}
- {{ macros.paginator(paginator_context, anchor='#sort-top') }}
- <div class="clean"></div>
-{% else %}
- {# ==== START: question/sharing_prompt_phrase.html ==== #}
- {% include "question/sharing_prompt_phrase.html" %}
- {# ==== END: question/sharing_prompt_phrase.html ==== #}
-{% endif %}
-
-{# ==== START: question/new_answer_form.html ==== #}
-{% include "question/new_answer_form.html" %}
-{# ==== END: question/new_answer_form.html ==== #}
-{% if request.user == question.author %}{# this is outside the form on purpose #}
- <input type="button" class="submit after-editor answer-own-question" id="fmanswer_button" value="{% trans %}Answer Your Own Question{% endtrans %}"/>
-{%endif%}
diff --git a/askbot/skins/default/templates/question/javascript.html b/askbot/skins/default/templates/question/javascript.html
deleted file mode 100644
index 3a29579d..00000000
--- a/askbot/skins/default/templates/question/javascript.html
+++ /dev/null
@@ -1,100 +0,0 @@
-{% if not thread.closed %}
- <script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
- <script type='text/javascript'>
- {% if settings.ENABLE_MATHJAX or settings.MARKUP_CODE_FRIENDLY %}
- var codeFriendlyMarkdown = true;
- {% else %}
- var codeFriendlyMarkdown = false;
- {% endif %}
- var maxCommentLength = {{settings.MAX_COMMENT_LENGTH}};
- askbot['urls']['postComments'] = '{% url post_comments %}';
- askbot['urls']['editComment'] = '{% url edit_comment %}';
- askbot['urls']['deleteComment'] = '{% url delete_comment %}';
- askbot['urls']['getComment'] = '{% url get_comment %}';
- askbot['urls']['question_url_template'] = scriptUrl + '{{ 'question/'|transurl }}{{ "{{QuestionID}}/{{questionSlug}}" }}';{# yes it needs to be that whacky #}
- askbot['urls']['vote_url_template'] = scriptUrl + '{{ 'questions/'|transurl }}{{ "{{QuestionID}}/" }}{{ 'vote/'|transurl }}';
- askbot['urls']['user_signin'] = '{{ settings.LOGIN_URL }}';
- askbot['urls']['swap_question_with_answer'] = '{% url swap_question_with_answer %}';
- askbot['urls']['upvote_comment'] = '{% url upvote_comment %}';
- askbot['urls']['delete_post'] = '{% url delete_post %}';
- askbot['messages']['addComment'] = '{% trans %}post a comment{% endtrans %}';
- {% if settings.SAVE_COMMENT_ON_ENTER %}
- askbot['settings']['saveCommentOnEnter'] = true;
- {% else %}
- askbot['settings']['saveCommentOnEnter'] = false;
- {% endif %}
- </script>
- <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script>
-{% endif %}
-<script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
-<script type='text/javascript' src='{{"/js/post.js"|media}}'></script>
-<script type="text/javascript">
- // define reputation needs for comments
- var repNeededForComments = 50;
- $().ready(function(){
- {% if request.user.is_authenticated() %}
- if ($('#question-subscribe-updates')[0].checked){
- $('#question-subscribe-sidebar').attr({'checked': 'checked'});
- }
- {%endif%}
- $("#nav_questions").attr('className',"on");
- var answer_sort_tab = "{{ tab_id }}";
- $("#" + answer_sort_tab).attr('className',"on");
-
- Vote.init({{ question.id }}, '{{ thread.title|slugify }}', '{{ question.author_id }}','{{ request.user.id }}');
-
- {% if not thread.closed and request.user.is_authenticated %}initEditor();{% endif %}
-
- lanai.highlightSyntax();
- $('#btLogin').bind('click', function(){window.location.href='{{ settings.LOGIN_URL }}'; } )
- if (window.location.hash === 'fmanswer'){
- $('#fmanswer textarea').focus();
- }
- {% if settings.ENABLE_SHARING_GOOGLE %}$.getScript("http://apis.google.com/js/plusone.js"){% endif %}
-
- {% if request.user.id == question.author_id %}
- $("#fmanswer_button").click(function() {
- $("#fmanswer").show();
- $("#fmanswer_button").hide();
- });
- {%endif%}
- });
-
- $(window).bind('hashchange', animate_hashes);
-
- function animate_hashes(){
- var id_value = window.location.hash;
- if (id_value != ""){
- var previous_color = $(id_value).css('background-color');
- $(id_value).css('backgroundColor', '#FFF8C6');
- $(id_value).animate({backgroundColor: '#ff7f2a'}, 1000).animate({backgroundColor: '#FFF8C6'}, 1000, function(){
- $(id_value).css('backgroundColor', previous_color);
- });
- }
- }
-
-
- function initEditor(){
- $('#editor').TextAreaResizer();
- //highlight code synctax when editor has new text
- $("#editor").typeWatch({highlight: false, wait: 3000,
- captureLength: 5, callback: lanai.highlightSyntax});
-
- var display = true;
- var txt = "[{% trans %}hide preview{% endtrans %}]";
- $('#pre-collapse').text(txt);
- $('#pre-collapse').bind('click', function(){
- txt = display ? "[{% trans %}show preview{% endtrans %}]" : "[{% trans %}hide preview{% endtrans %}]";
- display = !display;
- $('#previewer').toggle();
- $('#pre-collapse').text(txt);
- });
- setupFormValidation(
- $("#fmanswer"),
- CPValidator.getAnswerFormRules(),
- CPValidator.getAnswerFormMessages()
- );
- }
-</script>
-{% include "meta/editor_data.html" %}
diff --git a/askbot/skins/default/templates/question/new_answer_form.html b/askbot/skins/default/templates/question/new_answer_form.html
deleted file mode 100644
index 68af8afb..00000000
--- a/askbot/skins/default/templates/question/new_answer_form.html
+++ /dev/null
@@ -1,52 +0,0 @@
-<form
- id="fmanswer"
- {% if user == question.author %}style="display:none"{% endif %}
- action="{% url answer question.id %}"
- method="post"
- >{% csrf_token %}
- {# ==== START: question/subscribe_by_email_prompt.html ==== #}
- {% include "question/subscribe_by_email_prompt.html" %}
- {# ==== END: question/subscribe_by_email_prompt.html ==== #}
- <div style="clear:both"></div>
- {% if request.user.is_anonymous() and settings.ALLOW_POSTING_BEFORE_LOGGING_IN == False %}
- {% if not thread.closed %}
- <a
- class="submit"
- href="{{settings.LOGIN_URL}}?next={% url question question.id %}"
- >{% trans %}Login/Signup to Answer{% endtrans %}</a>
- {% endif %}
- {% else %}
- {% if not thread.closed %}
- <div>
- {% spaceless %}
- <h2>
- {% if answers %}
- {% trans %}Your answer{% endtrans %}
- {% else %}
- {% trans %}Be the first one to answer this question!{% endtrans %}
- {% endif %}
- </h2>
- {% endspaceless %}
- </div>
- {% if request.user.is_anonymous() %}
- <div class="message">{% trans %}<span class='strong big'>Please start posting your answer anonymously</span> - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a <strong>substantial answer</strong>, for discussions, <strong>please use comments</strong> and <strong>please do remember to vote</strong> (after you log in)!{% endtrans %}</div>
- {% else %}
- <p class="message">
- {% if request.user==question.author %}
- {% trans %}<span class='big strong'>You are welcome to answer your own question</span>, but please make sure to give an <strong>answer</strong>. Remember that you can always <strong>revise your original question</strong>. Please <strong>use comments for discussions</strong> and <strong>please don't forget to vote :)</strong> for the answers that you liked (or perhaps did not like)!{% endtrans %}
- {% else %}
- {% trans %}<span class='big strong'>Please try to give a substantial answer</span>. If you wanted to comment on the question or answer, just <strong>use the commenting tool</strong>. Please remember that you can always <strong>revise your answers</strong> - no need to answer the same question twice. Also, please <strong>don't forget to vote</strong> - it really helps to select the best questions and answers!{% endtrans %}
- {% endif %}
- </p>
- {% endif %}
- {{ macros.edit_post(answer) }}
- <input id="add-answer-btn" type="submit" class="submit after-editor" style="float:left"/>
- <script type="text/javascript">
- askbot['functions']['renderAddAnswerButton']();
- </script>
- {% if settings.WIKI_ON %}
- {{ macros.checkbox_in_div(answer.wiki) }}
- {% endif %}
- {% endif %}
- {% endif %}
-</form>
diff --git a/askbot/skins/default/templates/question/question_card.html b/askbot/skins/default/templates/question/question_card.html
deleted file mode 100644
index dd52ea0f..00000000
--- a/askbot/skins/default/templates/question/question_card.html
+++ /dev/null
@@ -1,32 +0,0 @@
-<div class="vote-buttons">
- {% include "question/question_vote_buttons.html" %}
- {% include "question/share_buttons.html" %}
-</div>
-<div id="post-id-{{question.id}}" class="question-content{% if question.deleted %} deleted{% endif %}">
-
- <h1><a href="{{ question.get_absolute_url() }}">{{ thread.get_title(question)|escape }}</a></h1>
- {% include "question/question_tags.html" %}
-
- <div id="question-table">
- <div class="question-body">
- <div class="post-update-info-container">
- {% include "question/question_author_info.html" %}
- </div>
- {{ question.html }}
- </div>
- <div id="question-controls" class="post-controls">
- {% include "question/question_controls.html" %}
- </div>
- <script type="text/javascript">
- (function(){
- if (askbot['data']['userIsAuthenticated'] === false){
- var ctrl = document.getElementById('question-controls')
- ctrl.parentNode.removeChild(ctrl);
- }
- })();
- </script>
- {% include "question/question_comments.html" %}
- </div>
-
-</div>
-
diff --git a/askbot/skins/default/templates/question/sidebar.html b/askbot/skins/default/templates/question/sidebar.html
deleted file mode 100644
index fe3f41c1..00000000
--- a/askbot/skins/default/templates/question/sidebar.html
+++ /dev/null
@@ -1,78 +0,0 @@
-{% from "macros.html" import timeago %}
-{% if settings.SIDEBAR_QUESTION_HEADER %}
-<div class="box">
- {{ settings.SIDEBAR_QUESTION_HEADER }}
-</div>
-{% endif %}
-<div class="box vote-buttons">
- <h2 >{% trans %}Question tools{% endtrans %}</h2>
- {% if favorited %}
- <a class="button followed"
- alt="{% trans %}click to unfollow this question{% endtrans %}">
- <div>{% trans %}Following{% endtrans %}</div>
- <div class='unfollow'>{% trans %}Unfollow{% endtrans %}</div>
- </a>
- {% else %}
- <a class="button followed"
- alt="{% trans %}click to follow this question{% endtrans %}">
- {%trans %}Follow{%endtrans%}
- </a>
- {% endif %}
- <div class="clearfix"></div>
- <div id="favorite-number" class="favorite-number{% if favorited %} my-favorite-number{% endif %}">
- {% set follower_count = thread.favourite_count %}
- {% if follower_count > 0 %}
- {% trans count=follower_count %}{{count}} follower{% pluralize %}{{count}} followers{% endtrans %}
- {% endif %}
- </div>
- <div class="notify-sidebar">
- {%if request.user.is_authenticated() %}
- <input type="checkbox" id="question-subscribe-sidebar"/>
- <label for="question-subscribe-sidebar">{% trans %}email the updates{% endtrans %}</label>
- {%else%}
- <input type="checkbox" id="question-subscribe-sidebar"/>
- <label for="question-subscribe-sidebar">{% trans %}<strong>Here</strong> (once you log in) you will be able to sign up for the periodic email updates about this question.{% endtrans %}</label>
- {%endif%}
- <p class="rss">
- <a
- href="{{settings.APP_URL}}/feeds/question/{{ question.id }}"
- title="{% trans %}subscribe to this question rss feed{% endtrans %}"
- >{% trans %}subscribe to rss feed{% endtrans %}</a>
- </p>
- </div>
-</div>
-
-{% if settings.SIDEBAR_QUESTION_SHOW_META %}
-<div class="box statsWidget">
- <div class="clearfix"></div>
- <h2>{% trans %}Stats{% endtrans %}</h2>
- <p>
- {% trans %}Asked{% endtrans %}: {{ timeago(question.added_at) }}
- </p>
- <p>
- {% trans %}Seen{% endtrans %}: <strong>{{ thread.view_count|intcomma }} {% trans %}times{% endtrans %}</strong>
- </p>
- <p>
- {% trans %}Last updated{% endtrans %}: <strong title="{{ thread.last_activity_at }}">{{thread.last_activity_at|diff_date}}</strong>
- </p>
-</div>
-{% endif %}
-
-{% if similar_threads.data and settings.SIDEBAR_QUESTION_SHOW_RELATED %}
- {#% cache 1800 "related_questions" related_questions question.id language_code %#}
- <div class="box">
- <h2>{% trans %}Related questions{% endtrans %}</h2>
- <div class="questions-related">
- {% for thread_dict in similar_threads.data() %}
- <p>
- <a href="{{ thread_dict.url }}">{{ thread_dict.title|escape }}</a>
- </p>
- {% endfor %}
- </div>
- </div>
- {#% endcache %#}
-{% endif %}
-
-<div class="box">
- {{ settings.SIDEBAR_QUESTION_FOOTER }}
-</div>
diff --git a/askbot/skins/default/templates/question_edit.html b/askbot/skins/default/templates/question_edit.html
deleted file mode 100644
index 47873e0e..00000000
--- a/askbot/skins/default/templates/question_edit.html
+++ /dev/null
@@ -1,98 +0,0 @@
-{% extends "two_column_body.html" %}
-{% import "macros.html" as macros %}
-<!-- question_edit.html -->
-{% block title %}{% spaceless %}{% trans %}Edit question{% endtrans %}{% endspaceless %}{% endblock %}
-{% block forestyle %}
- <link rel="stylesheet" type="text/css" href="{{"/js/wmd/wmd.css"|media}}" />
-{% endblock %}
-{% block content %}
-<div class="section-title">{% trans %}Edit question{% endtrans %} [<a href="{{ question.get_absolute_url() }}">{% trans %}back{% endtrans %}</a>]</div>
-<form id="fmedit" action="{% url edit_question question.id %}" method="post" >{% csrf_token %}
-
- {% if revision_form.revision.errors %}{{ revision_form.revision.errors.as_ul() }}{% endif %}
- <div style="vertical-align:middle">
- {{ revision_form.revision }} <input type="submit" style="display:none"
- id="select_revision" name="select_revision"
- value="{% trans %}select revision{% endtrans %}">
- </div>
- {{
- macros.edit_post(
- form,
- post_type='question',
- edit_title=True,
- mandatory_tags = mandatory_tags
- )
- }}
- <div class="after-editor">
- <div class="question-options">
- {% if settings.WIKI_ON and question.wiki == False %}
- {{ macros.checkbox_in_div(form.wiki) }}
- {% endif %}
- {% if form.can_stay_anonymous() %}
- {{ macros.checkbox_in_div(form.reveal_identity) }}
- {% endif %}
- </div>
- <input type="submit" value="{% trans %}Save edit{% endtrans %}" class="submit" />&nbsp;
- <input type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" onclick="history.back(-1);" />
-
- </div>
-</form>
-{% endblock %}
-
-{% block sidebar %}
-{% include "widgets/question_edit_tips.html" %}
-{% endblock %}
-
-{% block endjs %}
- {% include "meta/editor_data.html" %}
- <script type='text/javascript' src='{{"/js/editor.js"|media }}'></script>
- {% if mandatory_tags %}
- {% include "meta/mandatory_tags_js.html" %}
- {% endif %}
- <script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/post.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script>
- <script type="text/javascript">
- {% if settings.ENABLE_MATHJAX or settings.MARKUP_CODE_FRIENDLY %}
- var codeFriendlyMarkdown = true;
- {% else %}
- var codeFriendlyMarkdown = false;
- {% endif %}
- //todo move javascript out
- $().ready(function(){
- $("#nav_questions").attr('className',"on");
- $('#editor').TextAreaResizer();
-
- //highlight code synctax when editor has new text
- $("#editor").typeWatch({highlight: false, wait: 3000,
- captureLength: 5, callback: lanai.highlightSyntax});
-
- //toggle preview of editor
- var display = true;
- var txt = "[{% trans %}hide preview{% endtrans %}]";
- $('#pre-collapse').text(txt);
- $('#pre-collapse').bind('click', function(){
- txt = display ? "[{% trans %}show preview{% endtrans %}]" : "[{% trans %}hide preview{% endtrans %}]";
- display = !display;
- $('#previewer').toggle();
- $('#pre-collapse').text(txt);
- });
-
- {{ macros.tag_autocomplete_js(id = '#id_tags') }}
-
- setupFormValidation(
- $("#fmedit"),
- CPValidator.getQuestionFormRules(),
- CPValidator.getQuestionFormMessages()
- );
-
- $('#id_revision').unbind().change(function(){
- $("#select_revision").click();
- });
- lanai.highlightSyntax();
-
- });
- </script>
-{% endblock %}
-<!-- end question_edit.html -->
diff --git a/askbot/skins/default/templates/question_widget.html b/askbot/skins/default/templates/question_widget.html
deleted file mode 100644
index 9d32294b..00000000
--- a/askbot/skins/default/templates/question_widget.html
+++ /dev/null
@@ -1,21 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html>
-<head>
- <style type="text/css">
- {{settings.QUESTIONS_WIDGET_CSS|safe}}
- </style>
-</head>
-<body>
- {{settings.QUESTIONS_WIDGET_HEADER|safe}}
- <div id="container">
- <ul>
- {% for thread in threads %}
- <li><a href="{{settings.APP_URL|strip_path}}{{ thread.get_absolute_url() }}">
- {{ thread.title|escape }}</a></li>
- {% endfor %}
- </ul>
- </div>
- {{settings.QUESTIONS_WIDGET_FOOTER|safe}}
-</body>
-</html>
diff --git a/askbot/skins/default/templates/reopen.html b/askbot/skins/default/templates/reopen.html
deleted file mode 100644
index 52d926ce..00000000
--- a/askbot/skins/default/templates/reopen.html
+++ /dev/null
@@ -1,39 +0,0 @@
-{% extends "two_column_body.html" %}
-{% from "macros.html" import timeago %}
-<!-- reopen.html -->
-{% block title %}{% spaceless %}{% trans %}Reopen question{% endtrans %}{% endspaceless %}{% endblock %}
-{% block content %}
-<h1>{% trans %}Reopen question{% endtrans %}</h1>
-<p>{% trans %}Title{% endtrans %}:
- <a href="{{ question.get_absolute_url() }}">
- <span class="big">{{ question.get_question_title()|escape }}</span>
- </a>
-</p>
-<p>{% trans %}This question has been closed by
- <a href="{{closed_by_profile_url}}">{{closed_by_username|escape}}</a>
-{% endtrans %}
-</p>
-<p>
- {% trans %}Close reason:{% endtrans %} "<strong>{{question.thread.get_close_reason_display()}}</strong>".
-</p>
-<p>
- {% trans %}When:{% endtrans %} {{ timeago(question.thread.closed_at) }}
-</p>
-<p>
- {% trans %}Reopen this question?{% endtrans %}
-</p>
-<form id="fmclose" action="{% url reopen question.id %}" method="post" >{% csrf_token %}
- <div id="" style="padding:20px 0 20px 0">
- <input type="submit" value="{% trans %}Reopen this question{% endtrans %}" class="submit" />&nbsp;
- <input id="btBack" type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" />
- </div>
-</form>
-{% endblock %}
-{% block endjs %}
- <script type="text/javascript">
- $().ready(function(){
- $('#btBack').bind('click', function(){ history.back(); });
- });
- </script>
-{% endblock %}
-<!-- end reopen.html -->
diff --git a/askbot/skins/default/templates/revisions.html b/askbot/skins/default/templates/revisions.html
deleted file mode 100644
index aa1996a9..00000000
--- a/askbot/skins/default/templates/revisions.html
+++ /dev/null
@@ -1,102 +0,0 @@
-{% extends "two_column_body.html" %}
-{% import "macros.html" as macros %}
-<!-- revisions.html -->
-{% block title %}{% spaceless %}{% trans %}Revision history{% endtrans %}{% endspaceless %}{% endblock %}
-{% block content %}
-<h1 class="section-title">
- {% trans %}Revision history{% endtrans %} [<a href="{{ post.get_absolute_url() }}">{% trans %}back{% endtrans %}</a>]
-</h1>
-<div id="revisions">
-{% for revision in revisions %}
- <div class="revision">
- <div
- id="rev-header-{{ revision.revision }}"
- class="header {% if post.author_id == revision.author_id %}author{% endif %}"
- >
- <div class="header-controls">
- <table width="100%">
- <tr>
- <td width="20" style="vertical-align:middle">
- <img
- id="rev-arrow-{{ revision.revision }}"
- src="{{"/images/expander-arrow-hide.gif"|media}}"
- alt="{% trans %}click to hide/show revision{% endtrans %}"
- />
- </td>
- <td width="30px" style="vertical-align:middle">
- <span
- class="revision-number"
- title="{% trans number=revision.revision %}revision {{number}}{% endtrans %}">{{ revision.revision }}</span></td>
- <td width="200px" style="vertical-align:middle">
- {% if revision.summary %}
- <div class="summary">
- <span>{{ revision.summary|escape }}</span>
- </div>
- {% endif %}
- {% if request.user|can_edit_post(post) %}
- {% if post.post_type == 'answer' %}
- <a href="{% url edit_answer post.id %}?revision={{ revision.revision }}">{% trans %}edit{% endtrans %}</a>
- {% endif %}
- {% if post.post_type == 'question' %}
- <a href="{% url edit_question post.id %}?revision={{ revision.revision }}">{% trans %}edit{% endtrans %}</a>
- {% endif %}
- {% endif %}
- </td>
- <td align="right">
- <div class="revision-mark" >
- {% if revision.revision == 1 %}
- {% set contributor_type = "original_author" %}
- {% else %}
- {% set contributor_type = "last_updater" %}
- {% endif %}
- {{ macros.post_contributor_info(
- revision.post,
- contributor_type,
- False,
- 0
- )
- }}
- </div>
- </td>
- </tr>
- </table>
- </div>
- </div>
- <div id="rev-body-{{ revision.revision }}" class="answerbody">
- {{ revision.diff }}
- </div>
- </div>
-{% endfor %}
-</div>
-{% endblock %}
-
-{% block endjs %}
- <script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/post.js"|media}}'></script>
- <script type="text/javascript">
- //todo - take this out into .js file
- $(document).ready(function(){
- $("#nav_questions").attr('className',"on");
- $('div.revision div[id^=rev-header-]').bind('click', function(){
- var revId = this.id.substr(11);
- toggleRev(revId);
-
- });
- lanai.highlightSyntax();
- });
-
- function toggleRev(id) {
- var arrow = $("#rev-arrow-" + id);
- var visible = arrow.attr("src").indexOf("hide") > -1;
- var path = mediaUrl(
- "media/images/expander-arrow-" +
- (visible ? "show" : "hide") +
- ".gif" +
- "?v={{settings.MEDIA_RESOURCE_REVISION}}"
- );
- arrow.attr("src", path);
- $("#rev-body-" + id).slideToggle("fast");
- }
-</script>
-{% endblock %}
-<!-- end revisions.html -->
diff --git a/askbot/skins/default/templates/tags.html b/askbot/skins/default/templates/tags.html
deleted file mode 100644
index 007388af..00000000
--- a/askbot/skins/default/templates/tags.html
+++ /dev/null
@@ -1,78 +0,0 @@
-{% extends "two_column_body.html" %}
-{% import "macros.html" as macros %}
-<!-- tags.html -->
-{% block title %}{% spaceless %}{% trans %}Tags{% endtrans %}{% endspaceless %}{% endblock %}
-{% block content %}
-<!-- Tabs -->
-<div id="content-header">
- {% if stag %}
- <h1 class="section-title">{% trans %}Tags, matching "{{ stag }}"{% endtrans %}</h1>
- {% else %}
- <h1 class="section-title">{% trans %}Tag list{% endtrans %}</h1>
- {% endif %}
- <div class="tabBar tabBar-tags">
- <div class="tabsA">
- <span class="label">{% trans %}Sort by &raquo;{% endtrans %}</span>
- <a
- id="sort_name"
- href="{% url tags %}?sort=name"
- {% if tab_id == 'name' %}class="on"{% endif %}
- title="{% trans %}sorted alphabetically{% endtrans %}"
- ><span>{% trans %}by name{% endtrans %}</span></a>
- <a
- id="sort_used"
- href="{% url tags %}?sort=used"
- {% if tab_id == 'used' %}class="on"{% endif %}
- title="{% trans %}sorted by frequency of tag use{% endtrans %}"
- ><span>{% trans %}by popularity{% endtrans %}</span></a>
- </div>
- </div>
-</div>
-{% if tag_list_type == 'list' %}
- {% if not tags.object_list %}
- <span>{% trans %}Nothing found{% endtrans %}</span>
- {% endif %}
- {% if tags.object_list %}
- <div class='clearfix'></div>
- <ul class='tags'>
- {% for tag in tags.object_list %}
- <li>
- {{ macros.tag_widget(
- tag = tag.name,
- html_tag = 'div',
- truncate_long_tag = True,
- extra_content = '<span class="tag-number">&#215; ' ~
- tag.used_count|intcomma ~ '</span>'
- )
- }}
- </li>
- {% endfor %}
- </ul>
- <div class="clean"></div>
- <div class="pager">
- {{macros.paginator(paginator_context)}}
- </div>
- {% endif %}
-{% else %}
- <div class="clearfix"></div>
- {% if not tags %}
- <span>{% trans %}Nothing found{% endtrans %}</span>
- {% endif %}
- {{ macros.tag_cloud(tags = tags, font_sizes = font_size, search_state = search_state) }}
-{% endif %}
-
-{% endblock %}
-{% block endjs %}
- <script type="text/javascript">
- /*<![CDATA[*/
- $().ready(function(){
- $("#ipSearchTag").focus();
- $("#type-tag").attr('checked',true);
- Hilite.exact = false;
- Hilite.elementid = "searchtags";
- Hilite.debug_referrer = location.href;
- });
- /*]]>*/
- </script>
-{% endblock %}
-<!-- end tags.html -->
diff --git a/askbot/skins/default/templates/user_profile/reject_post_dialog.html b/askbot/skins/default/templates/user_profile/reject_post_dialog.html
deleted file mode 100644
index 987c511a..00000000
--- a/askbot/skins/default/templates/user_profile/reject_post_dialog.html
+++ /dev/null
@@ -1,108 +0,0 @@
-<div class="modal" style="display:none" id="reject-edit-modal">
- <div class="modal-header">
- <a class="close" data-dismiss="modal">x</a>
- <h3>{% trans %}Reject the post(s)?{% endtrans %}</h3>
- </div>
- <div id="reject-edit-modal-add-new">{# create new reject reason #}
- <div class="modal-body">
- <input
- class="reject-reason-title tipped-input blank"
- type="text"
- value="{% trans %}1) Enter a brief description of why you are rejecting the post.{% endtrans %}"
- />
- <textarea class="reject-reason-details tipped-input blank"
- >{% trans %}2) Please enter details here. This text will be sent to the user.{% endtrans %}</textarea>
- </div>
- <div class="modal-footer">
- <div class="btn-toolbar">
- <div class="btn-group dropup">
- <button class="btn btn-danger save-reason-and-reject"
- >{% trans %}Use this reason &amp; reject{% endtrans %}</button>
- <button class="btn btn-danger dropdown-toggle" data-toggle="dropdown">
- <span class="caret"></span>
- </button>
- <ul class="dropdown-menu">
- <li>
- <a class="select-other-reason" href="#"
- >{% trans %}Use other reason{% endtrans %}</a>
- </li>
- </ul>
- </div>
- <div class="btn-group">
- <a class="btn save-reason"
- >{% trans %}Save reason, but do not reject{% endtrans %}</a>
- </div>
- <div class="btn-group">
- <a class="btn cancel">{% trans %}Cancel{% endtrans %}</a>
- </div>
- </div>
- </div>
- </div>
- <div id="reject-edit-modal-select">{# select one of existing reasons #}
- <div class="modal-body">
- <p>{% trans %}Please, choose a reason for the rejection.{% endtrans %}</p>
- <ul class="select-box">
- {% for reason in post_reject_reasons %}
- <li
- data-original-title="{{reason.details.text|escape}}"
- data-item-id="{{reason.id}}"
- >{{reason.title|escape}}</li>
- {% endfor %}
- </ul>
- </div>
- <div class="modal-footer">
- <div class="btn-toolbar">
- <div class="btn-group dropup">
- <a class="btn select-this-reason"
- >{% trans %}Select this reason{% endtrans %}</a>
- <a class="btn dropdown-toggle" data-toggle="dropdown">
- <span class="caret"></span>
- </a>
- <ul class="dropdown-menu">
- <li>
- <a class="delete-this-reason"
- >{% trans %}Delete this reason{% endtrans %}</a>
- </li>
- </ul>
- </div>
- <div class="btn-group">
- <a class="btn add-new-reason"
- >{% trans %}Add a new reason{% endtrans %}</a>
- </div>
- <div class="btn-group">
- <a class="btn cancel">{% trans %}Cancel{% endtrans %}</a>
- </div>
- </div>
- </div>
- </div>
- <div id="reject-edit-modal-preview">{# preview reject reason #}
- <div class="modal-body">
- <p>{% trans %}You have selected reason for the rejection <strong>"<span class="selected-reason-title"></span>"</strong>. The text below will be sent to the user and the post(s) will be deleted:{% endtrans %}</p>
- <textarea disabled="disabled" class="selected-reason-details"></textarea>
- </div>
- <div class="modal-footer">
- <div class="btn-toolbar">
- <div class="btn-group dropup">
- <a class="btn btn-danger reject"
- >{% trans %}Use this reason &amp; reject{% endtrans %}</a>
- <a class="btn btn-danger dropdown-toggle" data-toggle="dropdown">
- <span class="caret"></span>
- </a>
- <ul class="dropdown-menu">
- <li>
- <a class="select-other-reason"
- >{% trans %}Use other reason{% endtrans %}</a>
- </li>
- </ul>
- </div>
- <div class="btn-group">
- <a class="btn edit-reason"
- >{% trans %}Edit this reason{% endtrans %}</a>
- </div>
- <div class="btn-group">
- <a class="btn cancel">{% trans %}Cancel{% endtrans %}</a>
- </div>
- </div>
- </div>
- </div>
-</div>
diff --git a/askbot/skins/default/templates/user_profile/user.html b/askbot/skins/default/templates/user_profile/user.html
deleted file mode 100644
index 2f06a3c9..00000000
--- a/askbot/skins/default/templates/user_profile/user.html
+++ /dev/null
@@ -1,46 +0,0 @@
-{% extends "one_column_body.html" %}
-<!-- user.html -->
-{% block title %}{% spaceless %}{{ page_title }}{% endspaceless %}{% endblock %}
-{% block forestyle %}
-<style type="text/css">
- .history-table td { padding: 5px; }
-</style>
-{% endblock %}
-{% block content %}
- <h1 class="section-title">
- {% spaceless %}
- {% trans username=view_user.username|escape %}{{username}}'s profile{% endtrans %} - {% block profilesection %}{% endblock %}
- {% endspaceless %}
- </h1>
- {% include "user_profile/user_tabs.html" %}
- <div>
- {% block usercontent %}
- {% endblock %}
- </div>
-{% endblock %}<!-- end user.html -->
-{% block endjs %}
- <script type="text/javascript">
- var viewUserID = {{view_user.id}};
- askbot['data']['viewUserName'] = '{{ view_user.username|escape }}';
- askbot['data']['viewUserId'] = {{view_user.id}};
- askbot['urls']['edit_group_membership'] = '{% url edit_group_membership %}';
- askbot['urls']['get_groups_list'] = '{% url get_groups_list %}';
- </script>
- {% if request.user|can_moderate_user(view_user) %}
- <script type='text/javascript' src='{{"/js/jquery.form.js"|media}}'></script>
- {% endif %}
- <script type="text/javascript" src='{{"/js/user.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
- <script type="text/javascript" src='{{"/js/post.js"|media}}'></script>
- {% block userjs %}
- {% endblock %}
-{% endblock %}
-{% block sidebar %}
-<div class="box">
- {{ settings.SIDEBAR_PROFILE_HEADER }}
-</div>
-<div class="box">
- {{ settings.SIDEBAR_PROFILE_FOOTER }}
-</div>
-{% endblock %}
-<!-- end of user.html -->
diff --git a/askbot/skins/default/templates/user_profile/user_inbox.html b/askbot/skins/default/templates/user_profile/user_inbox.html
deleted file mode 100644
index cda45027..00000000
--- a/askbot/skins/default/templates/user_profile/user_inbox.html
+++ /dev/null
@@ -1,99 +0,0 @@
-{% extends "user_profile/user.html" %}
-{% import "macros.html" as macros %}
-{% block before_css %}
- <link href="{{'/bootstrap/css/bootstrap.css'|media}}" rel="stylesheet" type="text/css" />
-{% endblock %}
-<!-- user_responses.html -->
-{#
-This template accepts a list of response list
-they are a generalized form of any response and
-
-The following properties of response object are used:
-timestamp - when it happened
-user - user who gave response (database object)
-response_type - type of response
-response_url - link to the question
-response_title - title of the question
-response_snippet - abbreviated content of the response
-inbox_section - forum|flags
-#}
-{% block profilesection %}
- {% trans %}inbox{% endtrans %}
-{% endblock %}
-{% block usercontent %}
- <div style="padding-top:5px;font-size:13px;">
- {% set re_count = request.user.new_response_count +
- request.user.seen_response_count
- %}
- {% if moderation_items %}
- {% set flag_count = moderation_items['new_count'] +
- moderation_items['seen_count']
- %}
- {% else %}
- {% set flag_count = 0 %}
- {% endif %}
- {% if re_count > 0 and flag_count > 0 %}
- <div id="re_sections">
- {% trans %}Sections:{% endtrans %}
- <a href="{{request.user.get_absolute_url()}}?sort=inbox&section=forum"
- {% if inbox_section == 'forum' %}class="on"{% endif %}
- >
- {% trans %}forum responses ({{re_count}}){% endtrans -%}
- </a> |
- <a href="{{request.user.get_absolute_url()}}?sort=inbox&section=flags"
- {% if inbox_section == 'flags' %}class="on"{% endif %}
- >
- {% trans %}flagged items ({{flag_count}}){% endtrans %}
- </a>
- </div>
- {% endif %}
- <div id="re_tools">
- <strong>{% trans %}select:{% endtrans %}</strong>
- <a id="sel_all">{% trans %}all{% endtrans %}</a> |
- <a id="sel_seen">{% trans %}seen{% endtrans %}</a> |
- <a id="sel_new">{% trans %}new{% endtrans %}</a> |
- <a id="sel_none">{% trans %}none{% endtrans %}</a><br />
- <div class="btn-group">
- {% if inbox_section == 'forum' %}
- <a class="btn" id="re_mark_seen">{% trans %}mark as seen{% endtrans %}</a>
- <a class="btn" id="re_mark_new">{% trans %}mark as new{% endtrans %}</a>
- <a class="btn" id="re_dismiss">{% trans %}dismiss{% endtrans %}</a>
- {% else %}
- <a class="btn" id="re_remove_flag">{% trans %}remove flags/approve{% endtrans %}</a>
- <a
- class="btn"
- id="re_delete_post"
- >{% trans %}delete post{% endtrans %}</a>
- {% endif %}
- </div>
- </div>
- {% include "user_profile/reject_post_dialog.html" %}
- <div id="responses">
- {% for response in responses %}
- <div class="response-parent">
- <p class="headline">
- <strong>"{{ response.response_title.strip()|escape}}"</strong>
- </p>
- {{ macros.inbox_post_snippet(response, inbox_section) }}
- {% for nested_response in response.nested_responses %}
- {{ macros.inbox_post_snippet(nested_response, inbox_section) }}
- {%endfor%}
- </div>
- {% endfor %}
- </div>
- </div>
-{% endblock %}
-{% block userjs %}
- <script type="text/javascript">
- var askbot = askbot || {};
- askbot['urls'] = askbot['urls'] || {};
- askbot['urls']['manageInbox'] = '{% url manage_inbox %}';
- askbot['urls']['save_post_reject_reason'] = '{% url save_post_reject_reason %}';
- askbot['urls']['delete_post_reject_reason'] = '{% url delete_post_reject_reason %}';
- $(document).ready(function(){
- setup_inbox();
- });
- </script>
- <script type="text/javascript" src="{{'/bootstrap/js/bootstrap.js'|media}}" />
-<!-- end user_responses.html -->
-{% endblock %}
diff --git a/askbot/skins/default/templates/user_profile/user_info.html b/askbot/skins/default/templates/user_profile/user_info.html
deleted file mode 100644
index ad460dbc..00000000
--- a/askbot/skins/default/templates/user_profile/user_info.html
+++ /dev/null
@@ -1,105 +0,0 @@
-<!-- user_info.html -->
-{% import "macros.html" as macros %}
-<table class="user-info-table">
- <tr>
- <td style="vertical-align:top;text-align:center;">
- <div class='avatar'>
- {{ macros.gravatar(view_user, 128) }}
- {% if request.user == view_user %}
- <p><a
- {% if support_custom_avatars %}
- href="{% url avatar_change %}"
- {% else %}
- href="{% url faq %}#gravatar"
- {% endif %}
- >{% trans %}change picture{% endtrans %}</a></p>
- {% if support_custom_avatars %}
- <p><a
- href="{% url avatar_delete %}"
- >{% trans %}remove{% endtrans %}</a>
- </p>
- {% endif %}
- {% endif %}
- </div>
- {% if can_show_karma %}
- <div class="scoreNumber">{{view_user.reputation|intcomma}}</div>
- <p><b style="color:#777;">{% trans %}karma{% endtrans %}</b></p>
- {% endif %}
- {% if user_follow_feature_on %}
- {{ macros.follow_user_toggle(visitor = request.user, subject = view_user) }}
- {% endif %}
- </td>
- <td width="360" style="padding-left:5px;vertical-align: top;">
- <table class="user-details">
- {% if request.user == view_user %}
- <tr>
- <td class="user-profile-tool-links" align="left" colspan="2">
- <a href="{% url edit_user view_user.id %}">
- {% trans %}update profile{% endtrans %}
- </a>
- {% if settings.USE_ASKBOT_LOGIN_SYSTEM and request.user == view_user and settings.ALLOW_ADD_REMOVE_LOGIN_METHODS %}
- | <a href="{{ settings.LOGIN_URL }}?next={{ settings.LOGIN_URL }}">
- {% trans %}manage login methods{% endtrans %}
- </a>
- {% endif %}
- </td>
- </tr>
- {% endif %}
- <tr>
- <th colspan="2" align="left">
- <h3>{{user_status_for_display}}</h3>
- </th>
- </tr>
- {% if view_user.real_name %}
- <tr>
- <td>{% trans %}real name{% endtrans %}</td>
- <td><b>{{view_user.real_name}}</b></td>
- </tr>
- {% endif %}
- <tr>
- <td>{% trans %}member since{% endtrans %}</td>
- <td><strong>{{ macros.timeago(view_user.date_joined) }}</strong></td>
- </tr>
- {% if view_user.last_seen %}
- <tr>
- <td>{% trans %}last seen{% endtrans %}</td>
- <td><strong title="{{ view_user.last_seen }}">{{ macros.timeago(view_user.last_seen) }}</strong></td>
- </tr>
- {% endif %}
- {% if view_user.website and (not view_user.is_blocked()) %}
- <tr>
- <td>{% trans %}website{% endtrans %}</td>
- <td>{{ macros.user_website_link(view_user, max_display_length = 30) }}</td>
- </tr>
- {% endif %}
- {% if view_user.location or view_user.country %}
- <tr>
- <td>{% trans %}location{% endtrans %}</td>
- <td>{{ macros.user_full_location(view_user) }}</td>
- </tr>
- {% endif %}
- {% if view_user.date_of_birth %}
- <tr>
- <!--todo - redo this with whole sentence translation -->
- <td>{% trans %}age{% endtrans %}</td>
- <td>{{view_user.date_of_birth|get_age}} {% trans %}age unit{% endtrans %}</td>
- </tr>
- {% endif %}
- {% if votes_today_left %}
- <tr>
- <td>{% trans %}todays unused votes{% endtrans %}</td>
- <td><strong class="darkred">{{ votes_today_left }}</strong> {% trans %}votes left{% endtrans %}</td>
- </tr>
- {% endif %}
- </table>
- </td>
- <td width="380">
- <div class="user-about">
- {% if view_user.about and (not view_user.is_blocked()) %}
- {{view_user.about|linebreaks}}
- {% endif %}
- </div>
- </td>
- </tr>
-</table>
-<!-- end user_info.html -->
diff --git a/askbot/skins/default/templates/user_profile/user_stats.html b/askbot/skins/default/templates/user_profile/user_stats.html
deleted file mode 100644
index 2ccc277f..00000000
--- a/askbot/skins/default/templates/user_profile/user_stats.html
+++ /dev/null
@@ -1,182 +0,0 @@
-{% extends "user_profile/user.html" %}
-{% import "macros.html" as macros %}
-{% import "user_profile/macros.html" as user_profile_macros %}
-<!-- user_stats.html -->
-{% block profilesection %}
- {% trans %}overview{% endtrans %}
-{% endblock %}
-{% block usercontent %}
- {% include "user_profile/user_info.html" %}
- {% if settings.GROUPS_ENABLED %}
- <div id="user-groups">
- <h2>{% trans
- username = view_user.username|escape
- %}{{username}}'s groups{% endtrans %}
- </h2>
- <table id="groups-list">
- {% for group in user_groups %}
- <tr>
- {{ macros.user_group(group, groups_membership_info[group.id]) }}
- </tr>
- {% endfor %}
- </table>
- <div class="clearfix"></div>
- <a id="add-group">{% trans %}add group{% endtrans %}</a>
- </div>
- {% endif %}
- <a name="questions"></a>
- {% spaceless %}
- <h2>{% trans counter=question_count %}<span class="count">{{counter}}</span> Question{% pluralize %}<span class="count">{{counter}}</span> Questions{% endtrans %}</h2>
- {% endspaceless %}
- {% include "user_profile/users_questions.html" %}
- <a name="answers"></a>
- {% spaceless %}
- <h2 style="clear:both;"><span class="count">{{ top_answer_count }}</span> {% trans counter=top_answer_count %}Answer{% pluralize %}Answers{% endtrans %}</h2>
- {% endspaceless %}
- <div class="user-stats-table">
- {% for top_answer in top_answers %}
- <div class="answer-summary">
- <a title="{{ top_answer.summary|collapse|escape }}"
- href="{% url question top_answer.thread._question_post().id %}{{ top_answer.thread.title|slugify }}#{{ top_answer.id }}">
- <span class="answer-votes {% if top_answer.accepted() %}answered-accepted{% endif %}"
- title="{% trans answer_score=top_answer.score %}the answer has been voted for {{ answer_score }} times{% endtrans %} {% if top_answer.accepted() %}{% trans %}this answer has been selected as correct{% endtrans %}{%endif%}">
- {{ top_answer.score }}
- </span>
- </a>
- <div class="answer-link">
- {% spaceless %}
- <a href="{% url question top_answer.thread._question_post().id %}{{ top_answer.thread.title|slugify }}#{{top_answer.id}}">{{ top_answer.thread.title|escape }}</a>
- {% endspaceless %}
- {% if top_answer.comment_count > 0 %}
- <span>
- {% trans comment_count=top_answer.comment_count %}({{ comment_count }} comment){% pluralize %}the answer has been commented {{ comment_count }} times{% endtrans %}
- </span>
- {% endif %}
- </div>
- </div>
- {% endfor %}
- </div>
- <br/>
- <a name="votes"></a>
- {% spaceless %}
- <h2>{% trans cnt=total_votes %}<span class="count">{{cnt}}</span> Vote{% pluralize %}<span class="count">{{cnt}}</span> Votes {% endtrans %}</h2>
- {% endspaceless %}
- <div class="user-stats-table">
- <table>
- <tr>
- <td width="60">
- <img style="cursor: default;" src="{{"/images/vote-arrow-up-on.png"|media}}" alt="{% trans %}thumb up{% endtrans %}" />
- <span title="{% trans %}user has voted up this many times{% endtrans %}" class="vote-count">{{up_votes}}</span>
- </td>
- <td width="60">
- <img style="cursor: default;" src="{{"/images/vote-arrow-down-on.png"|media}}" alt="{% trans %}thumb down{% endtrans %}" />
- <span title="{% trans %}user voted down this many times{% endtrans %}" class="vote-count">{{down_votes}}</span>
-
- </td>
- </tr>
- </table>
- </div>
- <a name="tags"></a>
- {% spaceless %}
- <h2>{% trans counter=user_tags|length %}<span class="count">{{counter}}</span> Tag{% pluralize %}<span class="count">{{counter}}</span> Tags{% endtrans %}</h2>
- {% endspaceless %}
- <div class="user-stats-table">
- <table class="tags">
- <tr>
- <td valign="top">
- <ul id="ab-user-tags" class="tags">
- {% for tag in user_tags %}
- <li>
- {{ macros.tag_widget(
- tag.name,
- html_tag = 'div',
- search_state = search_state,
- truncate_long_tag = True,
- extra_content =
- '<span class="tag-number">&#215; ' ~
- tag.user_tag_usage_count|intcomma ~
- '</span>'
- )
- }}
- </li>
- {#
- {% if loop.index is divisibleby 10 %}
- </td>
- <td width="180" valign="top">
- {% endif %}
- #}
- {% endfor %}
- </ul>
- </td>
- </tr>
- </table>
- </div>
- {% if interesting_tag_names %}
- {{ user_profile_macros.tag_selection(interesting_tag_names, 'interesting') }}
- {% endif %}
- {% if ignored_tag_names %}
- {{ user_profile_macros.tag_selection(ignored_tag_names, 'ignored') }}
- {% endif %}
- {% if subscribed_tag_names %}
- {{ user_profile_macros.tag_selection(subscribed_tag_names, 'subscribed') }}
- {% endif %}
- {% if settings.BADGES_MODE == 'public' %}
- <a name="badges"></a>
- {% spaceless %}
- <h2>{% trans counter=total_badges %}<span class="count">{{counter}}</span> Badge{% pluralize %}<span class="count">{{counter}}</span> Badges{% endtrans %}</h2>
- {% endspaceless %}
- <div class="user-stats-table badges">
- <table>
- <tr>
- <td style="line-height:35px">
- {% for badge, badge_user_awards in badges %}
- <a
- href="{{badge.get_absolute_url()}}"
- title="{% trans description=badge.description %}{{description}}{% endtrans %}"
- class="medal"
- ><span class="{{ badge.css_class }}">&#9679;</span>&nbsp;{% trans name=badge.name %}{{name}}{% endtrans %}
- </a>&nbsp;
- <span class="tag-number">&#215;
- <span class="badge-context-toggle">{{ badge_user_awards|length|intcomma }}</span>
- </span>
- <ul id="badge-context-{{ badge.id }}" class="badge-context-list" style="display:none">
- {% for award in badge_user_awards %}
- {% if award.content_object_is_post %}
- <li>
- <a
- title="{{ award.content_object.get_snippet()|collapse }}"
- href="{{ award.content_object.get_absolute_url() }}"
- >{% if award.content_type.post_type == 'answer' %}{% trans %}Answer to:{% endtrans %}{% endif %} {{ award.content_object.thread.title|escape }}</a>
- </li>
- {% endif %}
- {% endfor %}
- </ul>
- {% if loop.index is divisibleby 3 %}
- </td></tr>
- <tr><td style="line-height:35px">
- {% endif %}
- {% endfor %}
- </td>
- </tr>
- </table>
- </div>
- {% endif %}
-{% endblock %}
-{% block endjs %}
- {{ super() }}
- <script type="text/javascript">
- askbot['urls']['join_or_leave_group'] = '{% url join_or_leave_group %}';
- $(document).ready(function(){
- setup_badge_details_toggle();
- $.each($('.group-join-btn'), function(idx, elem){
- var group_join_btn = new GroupJoinButton();
- group_join_btn.decorate($(elem));
- });
- });
- </script>
- <script type='text/javascript' src='{{"/js/tag_selector.js"|media}}'></script>
- <script type="text/javascript">
- askbot['urls']['questions'] = '{% url "questions" %}';
- </script>
-{% endblock %}
-<!-- end user_stats.html -->
diff --git a/askbot/skins/default/templates/user_profile/users_questions.html b/askbot/skins/default/templates/user_profile/users_questions.html
deleted file mode 100644
index 128c6612..00000000
--- a/askbot/skins/default/templates/user_profile/users_questions.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!-- users_questions.html -->
-{% import "macros.html" as macros %}
-<div class="user-stats-table">
- {% for question in questions %}
- {{macros.question_summary(question.thread, question, extra_class='narrow', search_state=search_state)}}
- {% endfor %}
-</div>
-<!-- end users_questions.html -->
diff --git a/askbot/skins/default/templates/users.html b/askbot/skins/default/templates/users.html
deleted file mode 100644
index 5b963399..00000000
--- a/askbot/skins/default/templates/users.html
+++ /dev/null
@@ -1,142 +0,0 @@
-{% extends "two_column_body.html" %}
-{% import "macros.html" as macros %}
-<!-- users.html -->
-{% block title %}{% spaceless %}{% trans %}Users{% endtrans %}{% endspaceless %}{% endblock %}
-{% block before_css %}
- {% if group and request.user.is_authenticated() and request.user.is_administrator() %}
- <link href="{{'/bootstrap/css/bootstrap.css'|media}}" rel="stylesheet" type="text/css" />
- {% endif %}
-{% endblock %}
-{% block forestyle %}
- <link rel="stylesheet" type="text/css" href="{{"/js/wmd/wmd.css"|media}}" />
-{% endblock %}
-{% block content %}
-<div id="content-header">
- <h1 class="section-title">
- {% if group %}
- {% trans name = group.name|replace('-', ' ')|escape %}Users in group {{name}}{% endtrans %}
- {% else %}
- {% trans %}Users{% endtrans %}
- {% endif %}
- </h1>
- <div class="tabBar">
- <div class="tabsA">
- <span class="label">{% trans %}Sort by &raquo;{% endtrans %}</span>
- {% if settings.KARMA_MODE == 'public' %}
- <a
- id="sort_reputation"
- href="{{ request.path }}?sort=reputation"
- {% if tab_id == 'reputation' %}class="on"{% endif %}
- title="{% trans %}see people with the highest reputation{% endtrans %}"
- ><span>{% trans %}karma{% endtrans %}</span></a>
- {% endif %}
- <a
- id="sort_newest"
- href="{{ request.path }}?sort=newest"
- {% if tab_id == 'newest' %}class="on"{% endif %}
- class="off" title="{% trans %}see people who joined most recently{% endtrans %}"
- ><span>{% trans %}recent{% endtrans %}</span></a>
- <a
- id="sort_last"
- href="{{ request.path }}?sort=last"
- {% if tab_id == 'last' %}class="on"{% endif %}
- class="off" title="{% trans %}see people who joined the site first{% endtrans %}"
- ><span>{% trans %}oldest{% endtrans %}<span></a>
- <a
- id="sort_user"
- href="{{ request.path }}?sort=user"
- {% if tab_id == 'user' %}class="on"{% endif %}
- title="{% trans %}see people sorted by name{% endtrans %}"
- ><span>{% trans %}by username{% endtrans %}</span></a>
- </div>
- </div>
- <div class="clearfix"></div>
-</div>
-<div class="clean"></div>
-{% if search_query %}
- <p>{% trans %}users matching query {{search_query}}:{% endtrans %}</p>
-{% endif %}
-{% if not users.object_list %}
- <p><span>{% trans %}Nothing found.{% endtrans %}</span></p>
-{% endif %}
-{{ macros.user_list(
- users.object_list,
- karma_mode = settings.KARMA_MODE, badges_mode = settings.BADGES_MODE
- )
-}}
-<div class="pager">
- {{ macros.paginator(paginator_context) }}
-</div>
-{% endblock %}
-{% block sidebar %}
- {% if group %}
- {# this widget takes variables: group, user_can_join_group, user_is_group_member #}
- {% include "widgets/group_info.html" %}
- {% endif %}
-{% endblock %}
-{% block endjs %}
- <script type='text/javascript'>
- var Attacklab = Attacklab || {};
- Attacklab.wmd = 1;{# a trick to launch wmd manually #}
- askbot['urls']['upload'] = '{% url upload %}';
- askbot['urls']['load_tag_wiki_text'] = '{% url load_tag_wiki_text %}';
- askbot['urls']['save_tag_wiki_text'] = '{% url save_tag_wiki_text %}';
- askbot['urls']['save_group_logo_url'] = '{% url save_group_logo_url %}';
- askbot['urls']['delete_group_logo_url'] = '{% url delete_group_logo %}';
- askbot['urls']['join_or_leave_group'] = '{% url join_or_leave_group %}';
- </script>
- <script type="text/javascript" src='{{"/bootstrap/js/bootstrap.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script>
- <script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
- <script src='{{"/js/post.js"|media}}' type='text/javascript'></script>
- <script type="text/javascript">
- //todo move javascript out
- {% if settings.ENABLE_MATHJAX or settings.MARKUP_CODE_FRIENDLY %}
- var codeFriendlyMarkdown = true;
- {% else %}
- var codeFriendlyMarkdown = false;
- {% endif %}
- {% if group and request.user.is_authenticated() %}
- $().ready(function(){
- var group_join_btn = new GroupJoinButton();
- group_join_btn.decorate($('.group-join-btn'));
- //setup WMD editor
- if (askbot['data']['userIsAdminOrMod'] === true){
- //todo: this is kind of Attacklab.init ... should not be here
- Attacklab.wmd = function(){
- Attacklab.loadEnv = function(){
- var mergeEnv = function(env){
- if(!env){
- return;
- }
-
- for(var key in env){
- Attacklab.wmd_env[key] = env[key];
- }
- };
-
- mergeEnv(Attacklab.wmd_defaults);
- mergeEnv(Attacklab.account_options);
- mergeEnv(top["wmd_options"]);
- Attacklab.full = true;
-
- var defaultButtons = "bold italic link blockquote code image ol ul heading hr";
- Attacklab.wmd_env.buttons = Attacklab.wmd_env.buttons || defaultButtons;
- };
- Attacklab.loadEnv();
- };
- Attacklab.wmd();
- Attacklab.wmdBase();
- var group_editor = new UserGroupProfileEditor();
- group_editor.decorate($('#group-wiki-{{group.id}}'));
- }
- Hilite.exact = false;
- Hilite.elementid = "main-body";
- Hilite.debug_referrer = location.href;
- });
- {% endif %}
- </script>
-{% endblock %}
-<!-- end users.html -->
diff --git a/askbot/skins/default/templates/widgets/answer_edit_tips.html b/askbot/skins/default/templates/widgets/answer_edit_tips.html
deleted file mode 100644
index 1c2cdc60..00000000
--- a/askbot/skins/default/templates/widgets/answer_edit_tips.html
+++ /dev/null
@@ -1,67 +0,0 @@
-<!-- template answer_edit_tips.html -->
-<div class="box">
- <h2>{% trans %}Tips{% endtrans %}</h2>
- <div id="tips">
- <ul >
- <li> <b>{% trans %}give an answer interesting to this community{% endtrans %}</b>
- </li>
- <li>
- {% trans %}try to give an answer, rather than engage into a discussion{% endtrans %}
- </li>
- <li>
- {% trans %}provide enough details{% endtrans %}
- </li>
- <li>
- {% trans %}be clear and concise{% endtrans %}
- </li>
- </ul>
- <p class='info-box-follow-up-links'>
-<!-- will be change to a popup windows
- <a href="{% url faq %}" target="_blank" title="{% trans %}see frequently asked questions{% endtrans %}">{% trans %}FAQ{% endtrans %} »</a>
--->
- </p>
- </div>
-</div>
-
-<div class="box">
- <h2>{% trans %}Markdown basics{% endtrans %}</h2>
- <ul>
- {% if settings.MARKUP_CODE_FRIENDLY or settings.ENABLE_MATHJAX %}
- <li>
- {% trans %}*italic*{% endtrans %}
- </li>
- <li>
- {% trans %}**bold**{% endtrans %}
- </li>
- {% else %}
- <li>
- {% trans %}*italic* or _italic_{% endtrans %}
- </li>
- <li>
- {% trans %}**bold** or __bold__{% endtrans %}
- </li>
- {% endif %}
- <li>
- <b>{% trans %}link{% endtrans %}</b>:[{% trans %}text{% endtrans %}](http://url.com/ "{% trans %}title{% endtrans %}")
-
- </li>
- <li>
- <b>{% trans %}image{% endtrans %}</b>:![alt {% trans %}text{% endtrans %}](/path/img.jpg "{% trans %}title{% endtrans %}")
-
- </li>
- <li>
- {% trans %}numbered list:{% endtrans %}
- 1. Foo
- 2. Bar
- </li>
- <li>
- {% trans %}basic HTML tags are also supported{% endtrans %}
- </li>
- </ul>
- <p class='info-box-follow-up-links'>
-<!-- will be change to a popup windows
- <a href="http://en.wikipedia.org/wiki/Markdown" target="_blank">{% trans %}learn more about Markdown{% endtrans %} »</a>
--->
- </p>
-</div>
-<!-- end template answer_edit_tips.html -->
diff --git a/askbot/skins/default/templates/widgets/ask_button.html b/askbot/skins/default/templates/widgets/ask_button.html
deleted file mode 100644
index 31448b73..00000000
--- a/askbot/skins/default/templates/widgets/ask_button.html
+++ /dev/null
@@ -1,6 +0,0 @@
-{% if active_tab != "ask" %}
- {% if not search_state %} {# get empty SearchState() if there's none #}
- {% set search_state=search_state|get_empty_search_state %}
- {% endif %}
- <a id="askButton" href="{{ search_state.full_ask_url() }}">{% trans %}Ask Your Question{% endtrans %}</a>
-{% endif %}
diff --git a/askbot/skins/default/templates/widgets/ask_form.html b/askbot/skins/default/templates/widgets/ask_form.html
deleted file mode 100644
index b8a5ce2c..00000000
--- a/askbot/skins/default/templates/widgets/ask_form.html
+++ /dev/null
@@ -1,46 +0,0 @@
-{% import "macros.html" as macros %}
-<form id="fmask" action="" method="post" >{% csrf_token %}
- <div class="form-item">
- <div id="askFormBar">
- {% if not request.user.is_authenticated() %}
- <p>{% trans %}login to post question info{% endtrans %}</p>
-<p>{% trans %}<span class=\"strong big\">You are welcome to start submitting your question anonymously</span>. When you submit the post, you will be redirected to the login/signup page. Your question will be saved in the current session and will be published after you log in. Login/signup process is very simple. Login takes about 30 seconds, initial signup takes a minute or less.{% endtrans %}</p>
- {% else %}
- {% if settings.EMAIL_VALIDATION %}
- {% if not request.user.email_isvalid %}
- {% trans email=request.user.email %}<span class='strong big'>Looks like your email address, %(email)s has not yet been validated.</span> To post messages you must verify your email, please see <a href='%(email_validation_faq_url)s'>more details here</a>.<br>You can submit your question now and validate email after that. Your question will saved as pending meanwhile.{% endtrans %}
- {% endif %}
- {% endif %}
- {% endif %}
- <input id="id_title" class="questionTitleInput" name="title" autocomplete="off"
- value="{% if form.initial.title %}{{form.initial.title|escape}}{% endif %}"/>
- <span class="form-error">{{ form.title.errors }}</span>
- </div>
- <div class="title-desc">
- {{ form.title.help_text }}
- </div>
- </div>
- <div id='question-list'></div>
- {{
- macros.edit_post(
- form,
- post_type = 'question',
- edit_title = False,
- mandatory_tags = mandatory_tags
- )
- }}
- <div class="question-options">
- {% if settings.WIKI_ON %}
- {{ macros.checkbox_in_div(form.wiki) }}
- {% endif %}
- {% if settings.ALLOW_ASK_ANONYMOUSLY %}
- {{ macros.checkbox_in_div(form.ask_anonymously) }}
- {% endif %}
- </div>
- {% if not request.user.is_authenticated() %}
- <input type="submit" name="post_anon" value="{% trans %}Login/Signup to Post{% endtrans %}" class="submit" />
- {% else %}
- <input type="submit" name="post" value="{% trans %}Ask Your Question{% endtrans %}" class="submit" />
- {% endif %}
- <div class="clean"></div>
-</form>
diff --git a/askbot/skins/default/templates/widgets/group_info.html b/askbot/skins/default/templates/widgets/group_info.html
deleted file mode 100644
index 5d3a4c7f..00000000
--- a/askbot/skins/default/templates/widgets/group_info.html
+++ /dev/null
@@ -1,82 +0,0 @@
-{% import "macros.html" as macros %}
-<div id="group-wiki-{{group.id}}" class="box group-wiki">
- <h2>{% trans %}Group info{% endtrans %}</h2>
- <img class="group-logo"
- {% if group.group_profile.logo_url %}
- src="{{ group.group_profile.logo_url }}"
- {% else %}
- style="display:none"
- {% endif %}
- />
- <div class="content">
- {% if group.tag_wiki %}
- {{ group.tag_wiki.html }}
- {% endif %}
- </div>
- <div class="clearfix"></div>
- {{ macros.group_join_button(
- group_id = group.id,
- can_join = user_can_join_group,
- is_member = user_is_group_member
- )
- }}
- {% if request.user.is_authenticated() and request.user.is_administrator() %}
- <div class="controls">
- <a class="edit-description"
- >{% trans %}edit description{% endtrans %}</a>
- {% if group.group_profile.logo_url %}
- <span>|</span>
- <a class="change-logo"
- >{% trans %}change logo{% endtrans %}</a>
- <span>|</span>
- <a class="delete-logo">{% trans %}delete logo{% endtrans %}</a>
- {% else %}
- <span>|</span>
- <a class="change-logo"
- >{% trans %}add logo{% endtrans %}</a>
- {% endif %}
- <br/>
- {% if group_email_moderation_enabled %}
- <input type="checkbox"
- id="moderate-email"
- {% if group.group_profile.moderate_email %}checked="checked"{% endif %}
- data-toggle-url="{% url toggle_group_profile_property %}"
- />
- <label for="moderate-email">
- {% trans %}moderate emailed questions{% endtrans %}
- </label>
- <br/>
- {% endif %}
- <input type="checkbox"
- id="open-or-close-group"
- {% if group.group_profile.is_open %}checked="checked"{% endif %}
- data-toggle-url="{% url toggle_group_profile_property %}"
- />
- <label for="open-or-close-group">
- {% trans %}anyone can join{% endtrans %}
- </label>
- <br/>
- <a
- id="preapproved-emails"
- title="{% trans %}list of email addresses of pre-approved users{% endtrans %}"
- data-object-id="{{group.group_profile.id}}"
- data-model-name="GroupProfile"
- data-property-name="preapproved_emails"
- data-url="{% url edit_object_property_text %}"
- data-editor-heading="{% trans %}List of preapproved email addresses{% endtrans %}"
- data-help-text="{% trans %}Users with these email adderesses will be added to the group automatically.{% endtrans %}"
- >{% trans %}edit preapproved emails{% endtrans %}</a>
- <br/>
- <a
- id="preapproved-email-domains"
- title="{% trans %}list of preapproved email address domain names{% endtrans %}"
- data-object-id="{{group.group_profile.id}}"
- data-model-name="GroupProfile"
- data-property-name="preapproved_email_domains"
- data-url="{% url edit_object_property_text %}"
- data-editor-heading="{% trans %}List of preapproved email domain names{% endtrans %}"
- data-help-text="{% trans %}Users whose email adderesses belong to these domains will be added to the group automatically.{% endtrans %}"
- >{% trans %}edit preapproved email domains{% endtrans %}</a>
- </div>
- {% endif %}
-</div>
diff --git a/askbot/skins/default/templates/widgets/meta_nav.html b/askbot/skins/default/templates/widgets/meta_nav.html
deleted file mode 100644
index 1b28c787..00000000
--- a/askbot/skins/default/templates/widgets/meta_nav.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<a
- id="navTags"
- href="{% url tags %}"
- {% if active_tab == 'tags' %}class="on"{% endif %}
->{% trans %}tags{% endtrans %}</a>
-<a
- id="navUsers"
- href="{% url users %}"
- {% if active_tab == 'users' %}class="on"{% endif %}
->{% trans %}users{% endtrans %}</a>
-{% if settings.GROUPS_ENABLED %}
-<a
- id="navGroups"
- href="{% url groups %}"
- {% if active_tab == 'groups' %}class="on"{% endif %}
->{% trans %}groups{% endtrans %}
-</a>
-{% endif %}
-{% if settings.BADGES_MODE == 'public' %}
-<a
- id="navBadges"
- href="{% url badges %}"
- {% if active_tab == 'badges' %}class="on"{% endif %}
->{% trans %}badges{% endtrans %}</a>
-{% endif %}
diff --git a/askbot/skins/default/templates/widgets/question_edit_tips.html b/askbot/skins/default/templates/widgets/question_edit_tips.html
deleted file mode 100644
index 842aa491..00000000
--- a/askbot/skins/default/templates/widgets/question_edit_tips.html
+++ /dev/null
@@ -1,63 +0,0 @@
-<!-- question_edit_tips.html -->
-<div id ="tips" class="box">
- <h2>{% trans %}Tips{% endtrans %}</h2>
- <ul>
- <li> <b>{% trans %}ask a question interesting to this community{% endtrans %}</b>
- </li>
- <li>
- {% trans %}provide enough details{% endtrans %}
- </li>
- <li>
- {% trans %}be clear and concise{% endtrans %}
- </li>
- </ul>
- <p class='info-box-follow-up-links'>
-<!-- will be change to a popup windows
- <a href="{% url faq %}" target="_blank" title="{% trans %}see frequently asked questions{% endtrans %}">{% trans %}FAQ{% endtrans %} »</a>
--->
- </p>
-</div>
-
-<div id="markdownHelp"class="box">
- <h2>{% trans %}Markdown basics{% endtrans %}</h2>
- <ul>
- {% if settings.MARKDUP_CODE_FRIENDLY or settings.ENABLE_MATHJAX %}
- <li>
- {% trans %}*italic*{% endtrans %}
- </li>
- <li>
- {% trans %}**bold**{% endtrans %}
- </li>
- {% else %}
- <li>
- {% trans %}*italic* or _italic_{% endtrans %}
- </li>
- <li>
- {% trans %}**bold** or __bold__{% endtrans %}
- </li>
- {% endif %}
- <li>
- <b>{% trans %}link{% endtrans %}</b>:[{% trans %}text{% endtrans %}](http://url.com/ "{% trans %}title{% endtrans %}")
-
- </li>
-
- <li>
- <b>{% trans %}image{% endtrans %}</b>:![alt {% trans %}text{% endtrans %}](/path/img.jpg "{% trans %}title{% endtrans %}")
-
- </li>
- <li>
- {% trans %}numbered list:{% endtrans %}
- 1. Foo
- 2. Bar
- </li>
- <li>
- {% trans %}basic HTML tags are also supported{% endtrans %}
- </li>
- </ul>
- <p class='info-box-follow-up-links'>
-<!-- will be change to a popup windows
- <a href="http://en.wikipedia.org/wiki/Markdown" target="_blank">{% trans %}learn more about Markdown{% endtrans %} »</a>
--->
- </p>
-</div>
-<!-- end question_edit_tips.html -->
diff --git a/askbot/skins/default/templates/widgets/question_summary.html b/askbot/skins/default/templates/widgets/question_summary.html
deleted file mode 100644
index 5fd51e08..00000000
--- a/askbot/skins/default/templates/widgets/question_summary.html
+++ /dev/null
@@ -1,57 +0,0 @@
-{% from "macros.html" import user_country_flag, tag_list_widget, timeago %}
-<div class="short-summary{% if extra_class %} {{extra_class}}{% endif %}" id="question-{{question.id}}">
- <div class="counts">
- <div class="views
- {% if thread.view_count == 0 -%}
- no-views
- {% else -%}
- some-views
- {%- endif -%}">
- <span class="item-count">{{thread.view_count|humanize_counter}}</span>
- <div>
- {% trans cnt=thread.view_count %}view{% pluralize %}views{% endtrans %}
- </div>
- </div>
- <div class="answers
- {% if thread.answer_count == 0 -%}
- no-answers
- {% else -%}
- {%- if thread.accepted_answer_id -%} {# INFO: Use _id to not fetch the whole answer post #}
- accepted
- {%- else -%}
- some-answers
- {%- endif -%}
- {%- endif -%}">
- <span
- class="item-count"
- >{{thread.answer_count|humanize_counter}}{% if thread.accepted_answer_id %}{% endif %}</span>
- <div>
- {% trans cnt=thread.answer_count %}answer{% pluralize %}answers{% endtrans %}
- </div>
- </div>
- <div class="votes
- {% if question.score == 0 -%}
- no-votes
- {% else -%}
- some-votes
- {%- endif -%}">
- <span class="item-count">{{question.score|humanize_counter}}</span>
- <div>
- {% trans cnt=question.score %}vote{% pluralize %}votes{% endtrans %}
- </div>
- </div>
- <div style="clear:both"></div>
- <div class="userinfo">
- {{ timeago(thread.last_activity_at) }}
- {% if question.is_anonymous %}
- <span class="anonymous">{{ thread.last_activity_by.get_anonymous_name() }}</span>
- {% else %}
- <a href="{% url user_profile thread.last_activity_by.id, thread.last_activity_by.username|slugify %}">{{thread.last_activity_by.username|escape}}</a> {{ user_country_flag(thread.last_activity_by) }}
- {#{user_score_and_badge_summary(thread.last_activity_by)}#}
- {% endif %}
- </div>
- </div>
- <h2><a title="{{question.summary|escape}}" href="{{ question.get_absolute_url(thread=thread) }}">{{thread.get_title(question)|escape}}</a></h2>
- {{ tag_list_widget(thread.get_tag_names(), search_state=search_state) }}
-</div>
-
diff --git a/askbot/skins/default/templates/widgets/user_list.html b/askbot/skins/default/templates/widgets/user_list.html
deleted file mode 100644
index e51abc5b..00000000
--- a/askbot/skins/default/templates/widgets/user_list.html
+++ /dev/null
@@ -1,28 +0,0 @@
-{%from "macros.html" import gravatar %}
-<div class="userList">
- <table class="list-table">
- <tr>
- <td class="list-td">
- {% for user in users %}
- <div class="user">
- <ul>
- <li class="thumb">{{ gravatar(user, 32) }}</li>
- <li><a href="{% url user_profile user.id, user.username|slugify %}{% if profile_section %}?sort={{profile_section}}{% endif %}">{{user.username|escape}}</a>{{ user_country_flag(user) }}</li>
- <li>{{
- user_score_and_badge_summary(
- user,
- karma_mode = karma_mode,
- badges_mode = badges_mode
- )
- }}</li>
- </ul>
- </div>
- {% if loop.index is divisibleby 7 %}
- </td>
- <td>
- {% endif %}
- {% endfor %}
- </td>
- </tr>
- </table>
-</div>
diff --git a/askbot/skins/default/templates/widgets/user_navigation.html b/askbot/skins/default/templates/widgets/user_navigation.html
deleted file mode 100644
index 717cd7ee..00000000
--- a/askbot/skins/default/templates/widgets/user_navigation.html
+++ /dev/null
@@ -1,25 +0,0 @@
-{%- if request.user.is_authenticated() -%}
- <a href="{{ request.user.get_absolute_url() }}">{{ request.user.username|escape }}</a>
- <span class="user-info">
- {{ macros.inbox_link(request.user) }}
- {{ macros.moderation_items_link(request.user, moderation_items) }}
- {%-
- if settings.KARMA_MODE != 'hidden' and settings.BADGES_MODE != 'hidden'
- -%}
- ({{ macros.user_long_score_and_badge_summary(
- user,
- badges_mode = settings.BADGES_MODE
- )
- }})
- {%- endif -%}
- </span>
- {% if settings.USE_ASKBOT_LOGIN_SYSTEM %}
- <a href="{{ settings.LOGOUT_URL }}?next={{ settings.LOGOUT_REDIRECT_URL }}">{% trans %}sign out{% endtrans %}</a>
- {% endif %}
-{% elif settings.USE_ASKBOT_LOGIN_SYSTEM %}
- <a href="{{ settings.LOGIN_URL }}?next={{request.path|clean_login_url}}">{% trans %}Hi, there! Please sign in{% endtrans %}</a>
-{% endif %}
-{% if request.user.is_authenticated() and request.user.is_administrator() %}
- <a href="{% url site_settings %}">{% trans %}settings{% endtrans %}</a>
-{% endif %}
- <a href="{% url "help" %}" title="{% trans %}help{% endtrans %}">{% trans %}help{% endtrans %}</a>
diff --git a/askbot/skins/loaders.py b/askbot/skins/loaders.py
index aa3188e9..fc680f00 100644
--- a/askbot/skins/loaders.py
+++ b/askbot/skins/loaders.py
@@ -34,11 +34,11 @@ def filesystem_load_template_source(name, dirs=None):
try:
#todo: move this to top after splitting out get_skin_dirs()
- tname = os.path.join(askbot_settings.ASKBOT_DEFAULT_SKIN,'templates',name)
- return filesystem.load_template_source(tname,dirs)
+ tname = os.path.join(askbot_settings.ASKBOT_DEFAULT_SKIN, 'templates', name)
+ return filesystem.load_template_source(tname, dirs)
except:
- tname = os.path.join('default','templates',name)
- return filesystem.load_template_source(tname,dirs)
+ tname = os.path.join('default', 'templates', name)
+ return filesystem.load_template_source(tname, dirs)
filesystem_load_template_source.is_usable = True
#added this for backward compatbility
load_template_source = filesystem_load_template_source
@@ -115,14 +115,20 @@ def get_template(template, request = None):
skin.set_language(request.LANGUAGE_CODE)
return skin.get_template(template)
+def render_into_skin_as_string(template, data, request):
+ context = RequestContext(request, data)
+ template = get_template(template, request)
+ return template.render(context)
+
def render_into_skin(template, data, request, mimetype = 'text/html'):
"""in the future this function will be able to
switch skin depending on the site administrator/user selection
right now only admins can switch
"""
- context = RequestContext(request, data)
- template = get_template(template, request)
- return HttpResponse(template.render(context), mimetype = mimetype)
+ return HttpResponse(
+ render_into_skin_as_string(template, data, request),
+ mimetype=mimetype
+ )
def render_text_into_skin(text, data, request):
context = RequestContext(request, data)
diff --git a/askbot/skins/utils.py b/askbot/skins/utils.py
index 0c0dba9c..f0e149d0 100644
--- a/askbot/skins/utils.py
+++ b/askbot/skins/utils.py
@@ -8,9 +8,10 @@ the lookup resolution process for templates and media works as follows:
import os
import logging
import urllib
+import askbot
+from askbot.utils import hasher
from django.conf import settings as django_settings
from django.utils.datastructures import SortedDict
-from askbot.utils import hasher
class MediaNotFound(Exception):
"""raised when media file is not found"""
@@ -28,7 +29,10 @@ def get_skins_from_dir(directory):
return skins
def get_available_skins(selected=None):
- """selected is a name of preferred skin
+ """Returns a dictionary of skin name --> directory where
+ "templates" and "media" subdirectories can be found.
+
+ selected is a name of preferred skin
if it's None, then information about all skins will be returned
otherwise, only data about selected and default skins
will be returned
@@ -39,24 +43,24 @@ def get_available_skins(selected=None):
if hasattr(django_settings, 'ASKBOT_EXTRA_SKINS_DIR'):
skins.update(get_skins_from_dir(django_settings.ASKBOT_EXTRA_SKINS_DIR))
- stock_dir = os.path.normpath(os.path.dirname(__file__))
- stock_skins = get_skins_from_dir(stock_dir)
- default_dir = stock_skins.pop('default')
- common_dir = stock_skins.pop('common')
-
- skins.update(stock_skins)
- if selected:
- if selected in skins:
- selected_dir = skins[selected]
- skins.clear()
- skins[selected] = selected_dir
- else:
- assert(selected == 'default' or selected == 'common')
- skins = SortedDict()
-
- #re-insert default as a last item
- skins['default'] = default_dir
- skins['common'] = common_dir
+ if 'default' in skins:
+ raise ValueError('"default" is not an acceptable name for a custom skin')
+
+ if selected in skins:
+ selected_dir = skins[selected]
+ skins.clear()
+ skins[selected] = selected_dir
+ elif selected == 'default':
+ skins = SortedDict()
+ elif selected:
+ raise ValueError(
+ 'skin ' + str(selected) + \
+ ' not found, please check ASKBOT_EXTRA_SKINS_DIR setting ' + \
+ 'or in the corresponding directory'
+ )
+
+ #insert default as a last item
+ skins['default'] = askbot.get_install_directory()
return skins
@@ -74,13 +78,12 @@ def get_skin_choices():
"""returns a tuple for use as a set of
choices in the form"""
available_skins = get_available_skins().keys()
- available_skins.remove('common')
skin_names = list(reversed(available_skins))
return zip(skin_names, skin_names)
def resolve_skin_for_media(media=None, preferred_skin = None):
#see if file exists, if not, try skin 'default'
- available_skins = get_available_skins(selected = preferred_skin).items()
+ available_skins = get_available_skins(selected=preferred_skin).items()
for skin_name, skin_dir in available_skins:
if os.path.isfile(os.path.join(skin_dir, 'media', media)):
return skin_name
@@ -183,7 +186,6 @@ def update_media_revision(skin = None):
media_dirs = [
os.path.join(skin_path, 'media'),
- os.path.join(get_path_to_skin('common'), 'media')#we always use common
]
if skin != 'default':
diff --git a/askbot/startup_procedures.py b/askbot/startup_procedures.py
index 544a94fb..e90bd048 100644
--- a/askbot/startup_procedures.py
+++ b/askbot/startup_procedures.py
@@ -18,6 +18,7 @@ from django.conf import settings as django_settings
from django.core.exceptions import ImproperlyConfigured
from askbot.utils.loading import load_module
from askbot.utils.functions import enumerate_string_list
+from askbot.utils.url_utils import urls_equal
from urlparse import urlparse
PREAMBLE = """\n
@@ -226,6 +227,25 @@ def test_celery():
"""
broker_backend = getattr(django_settings, 'BROKER_BACKEND', None)
broker_transport = getattr(django_settings, 'BROKER_TRANSPORT', None)
+ delay_time = getattr(django_settings, 'NOTIFICATION_DELAY_TIME', None)
+ delay_setting_info = 'The delay is in seconds - used to throttle ' + \
+ 'instant notifications note that this delay will work only if ' + \
+ 'celery daemon is running Please search about ' + \
+ '"celery daemon setup" for details'
+
+ if delay_time is None:
+ raise AskbotConfigError(
+ '\nPlease add to your settings.py\n' + \
+ 'NOTIFICATION_DELAY_TIME = 60*15\n' + \
+ delay_setting_info
+ )
+ else:
+ if not isinstance(delay_time, int):
+ raise AskbotConfigError(
+ '\nNOTIFICATION_DELAY_TIME setting must have a numeric value\n' + \
+ delay_setting_info
+ )
+
if broker_backend is None:
if broker_transport is None:
@@ -312,6 +332,19 @@ class SettingsTester(object):
'\n\n* '.join(self.messages)
)
+
+def test_new_skins():
+ """tests that there are no directories in the `askbot/skins`
+ because we've moved skin files a few levels up"""
+ askbot_root = askbot.get_install_directory()
+ for item in os.listdir(os.path.join(askbot_root, 'skins')):
+ item_path = os.path.join(askbot_root, 'skins', item)
+ if os.path.isdir(item_path):
+ raise AskbotConfigError(
+ ('Time to move skin files from %s.\n'
+ 'Now we have `askbot/templates` and `askbot/media`') % item_path
+ )
+
def test_staticfiles():
"""tests configuration of the staticfiles app"""
errors = list()
@@ -367,17 +400,33 @@ def test_staticfiles():
" ADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/'"
)
- askbot_root = os.path.dirname(askbot.__file__)
- skin_dir = os.path.abspath(os.path.join(askbot_root, 'skins'))
-
# django_settings.STATICFILES_DIRS can have strings or tuples
staticfiles_dirs = [d[1] if isinstance(d, tuple) else d
for d in django_settings.STATICFILES_DIRS]
- if skin_dir not in map(os.path.abspath, staticfiles_dirs):
- errors.append(
- 'Add to STATICFILES_DIRS list of your settings.py file:\n'
- " '%s'," % skin_dir
- )
+
+ default_skin_tuple = None
+ askbot_root = askbot.get_install_directory()
+ old_default_skin_dir = os.path.abspath(os.path.join(askbot_root, 'skins'))
+ for dir_entry in django_settings.STATICFILES_DIRS:
+ if isinstance(dir_entry, tuple):
+ if dir_entry[0] == 'default/media':
+ default_skin_tuple = dir_entry
+ elif isinstance(dir_entry, str):
+ if os.path.abspath(dir_entry) == old_default_skin_dir:
+ errors.append(
+ 'Remove from STATICFILES_DIRS in your settings.py file:\n' + dir_entry
+ )
+
+ askbot_root = os.path.dirname(askbot.__file__)
+ default_skin_media_dir = os.path.abspath(os.path.join(askbot_root, 'media'))
+ if default_skin_tuple:
+ media_dir = default_skin_tuple[1]
+ if default_skin_media_dir != os.path.abspath(media_dir):
+ errors.append(
+ 'Add to STATICFILES_DIRS the following entry: '
+ "('default/media', os.path.join(ASKBOT_ROOT, 'media')),"
+ )
+
extra_skins_dir = getattr(django_settings, 'ASKBOT_EXTRA_SKINS_DIR', None)
if extra_skins_dir is not None:
if not os.path.isdir(extra_skins_dir):
@@ -522,6 +571,117 @@ def test_custom_user_profile_tab():
footer = 'Please carefully read about adding a custom user profile tab.'
print_errors(errors, header = header, footer = footer)
+def get_tinymce_sample_config():
+ """returns the sample configuration for TinyMCE
+ as string"""
+ askbot_root = askbot.get_install_directory()
+ file_path = os.path.join(
+ askbot_root, 'setup_templates', 'tinymce_sample_config.py'
+ )
+ config_file = open(file_path, 'r')
+ sample_config = config_file.read()
+ config_file.close()
+ return sample_config
+
+def test_tinymce():
+ """tests the tinymce editor setup"""
+ errors = list()
+ if 'tinymce' not in django_settings.INSTALLED_APPS:
+ errors.append("add 'tinymce', to the INSTALLED_APPS")
+
+ required_attrs = (
+ 'TINYMCE_COMPRESSOR',
+ 'TINYMCE_JS_ROOT',
+ 'TINYMCE_URL',
+ 'TINYMCE_DEFAULT_CONFIG'
+ )
+
+ missing_attrs = list()
+ for attr in required_attrs:
+ if not hasattr(django_settings, attr):
+ missing_attrs.append(attr)
+
+ if missing_attrs:
+ errors.append('add missing settings: %s' % ', '.join(missing_attrs))
+
+ #check compressor setting
+ compressor_on = getattr(django_settings, 'TINYMCE_COMPRESSOR', False)
+ if compressor_on is False:
+ errors.append('add line: TINYMCE_COMPRESSOR = True')
+ #todo: add pointer to instructions on how to debug tinymce:
+ #1) add ('tiny_mce', os.path.join(ASKBOT_ROOT, 'media/js/tinymce')),
+ # to STATIFILES_DIRS
+ #2) add this to the main urlconf:
+ # (
+ # r'^m/(?P<path>.*)$',
+ # 'django.views.static.serve',
+ # {'document_root': static_root}
+ # ),
+ #3) set `TINYMCE_COMPRESSOR = False`
+ #4) set DEBUG = False
+ #then - tinymce compressing will be disabled and it will
+ #be possible to debug custom tinymce plugins that are used with askbot
+
+
+ config = getattr(django_settings, 'TINYMCE_DEFAULT_CONFIG', None)
+ if config:
+ if 'convert_urls' in config:
+ if config['convert_urls'] is not False:
+ message = "set 'convert_urls':False in TINYMCE_DEFAULT_CONFIG"
+ errors.append(message)
+ else:
+ message = "add to TINYMCE_DEFAULT_CONFIG\n'convert_urls': False,"
+ errors.append(message)
+
+
+ #check js root setting - before version 0.7.44 we used to have
+ #"common" skin and after we combined it into the default
+ js_root = getattr(django_settings, 'TINYMCE_JS_ROOT', '')
+ old_relative_js_path = 'common/media/js/tinymce/'
+ relative_js_path = 'default/media/js/tinymce/'
+ expected_js_root = os.path.join(django_settings.STATIC_ROOT, relative_js_path)
+ old_expected_js_root = os.path.join(django_settings.STATIC_ROOT, old_relative_js_path)
+ if os.path.normpath(js_root) != os.path.normpath(expected_js_root):
+ error_tpl = "add line: TINYMCE_JS_ROOT = os.path.join(STATIC_ROOT, '%s')"
+ if os.path.normpath(js_root) == os.path.normpath(old_expected_js_root):
+ error_tpl += '\nNote: we have moved files from "common" into "default"'
+ errors.append(error_tpl % relative_js_path)
+
+ #check url setting
+ url = getattr(django_settings, 'TINYMCE_URL', '')
+ expected_url = django_settings.STATIC_URL + relative_js_path
+ old_expected_url = django_settings.STATIC_URL + old_relative_js_path
+ if urls_equal(url, expected_url) is False:
+ error_tpl = "add line: TINYMCE_URL = STATIC_URL + '%s'"
+ if urls_equal(url, old_expected_url):
+ error_tpl += '\nNote: we have moved files from "common" into "default"'
+ errors.append(error_tpl % relative_js_path)
+
+ if errors:
+ header = 'Please add the tynymce editor configuration ' + \
+ 'to your settings.py file.'
+ footer = 'You might want to use this sample configuration ' + \
+ 'as template:\n\n' + get_tinymce_sample_config()
+ print_errors(errors, header=header, footer=footer)
+
+def test_longerusername():
+ """tests proper installation of the "longerusername" app
+ """
+ errors = list()
+ if 'longerusername' not in django_settings.INSTALLED_APPS:
+ errors.append(
+ "add 'longerusername', as the first item in the INSTALLED_APPS"
+ )
+ else:
+ index = django_settings.INSTALLED_APPS.index('longerusername')
+ if index != 0:
+ message = "move 'longerusername', to the beginning of INSTALLED_APPS"
+ raise AskbotConfigError(message)
+
+ if errors:
+ errors.append('run "python manage.py migrate longerusername"')
+ print_errors(errors)
+
def run_startup_tests():
"""function that runs
all startup tests, mainly checking settings config so far
@@ -536,7 +696,10 @@ def run_startup_tests():
test_middleware()
test_celery()
#test_csrf_cookie_domain()
+ #test_tinymce()
test_staticfiles()
+ test_new_skins()
+ test_longerusername()
test_avatar()
test_haystack()
settings_tester = SettingsTester({
diff --git a/askbot/tasks.py b/askbot/tasks.py
index da07477b..650b7aeb 100644
--- a/askbot/tasks.py
+++ b/askbot/tasks.py
@@ -19,6 +19,8 @@ That is the reason for having two types of methods here:
"""
import sys
import traceback
+import logging
+import uuid
from django.contrib.contenttypes.models import ContentType
from django.template import Context
@@ -27,9 +29,10 @@ from celery.decorators import task
from askbot.conf import settings as askbot_settings
from askbot import const
from askbot import mail
-from askbot.models import Activity, Post, Thread, User, ReplyAddress
-from askbot.models import send_instant_notifications_about_activity_in_post
+from askbot.models import Post, Thread, User, ReplyAddress
from askbot.models.badges import award_badges_signal
+from askbot.models import get_reply_to_addresses, format_instant_notification_email
+from askbot import exceptions as askbot_exceptions
# TODO: Make exceptions raised inside record_post_update_celery_task() ...
# ... propagate upwards to test runner, if only CELERY_ALWAYS_EAGER = True
@@ -95,129 +98,43 @@ def notify_author_of_published_revision_celery_task(revision):
def record_post_update_celery_task(
post_id,
post_content_type_id,
- newly_mentioned_user_id_list = None,
+ newly_mentioned_user_id_list = None,
updated_by_id = None,
timestamp = None,
created = False,
diff = None,
):
#reconstitute objects from the database
- updated_by = User.objects.get(id = updated_by_id)
- post_content_type = ContentType.objects.get(id = post_content_type_id)
- post = post_content_type.get_object_for_this_type(id = post_id)
+ updated_by = User.objects.get(id=updated_by_id)
+ post_content_type = ContentType.objects.get(id=post_content_type_id)
+ post = post_content_type.get_object_for_this_type(id=post_id)
newly_mentioned_users = User.objects.filter(
- id__in = newly_mentioned_user_id_list
+ id__in=newly_mentioned_user_id_list
)
try:
- record_post_update(
- post = post,
- updated_by = updated_by,
- newly_mentioned_users = newly_mentioned_users,
- timestamp = timestamp,
- created = created,
- diff = diff
+ notify_sets = post.get_notify_sets(
+ mentioned_users=newly_mentioned_users,
+ exclude_list=[updated_by,]
+ )
+ #todo: take into account created == True case
+ #update_object is not used
+ (activity_type, update_object) = post.get_updated_activity_data(created)
+
+ post.issue_update_notifications(
+ updated_by=updated_by,
+ notify_sets=notify_sets,
+ activity_type=activity_type,
+ timestamp=timestamp,
+ diff=diff
)
+
except Exception:
- # HACK: exceptions from Celery job don;t propagate upwards to Django test runner
- # so at least le't sprint tracebacks
+ # HACK: exceptions from Celery job don't propagate upwards
+ # to the Django test runner
+ # so at least let's print tracebacks
print >>sys.stderr, traceback.format_exc()
raise
-def record_post_update(
- post = None,
- updated_by = None,
- newly_mentioned_users = None,
- timestamp = None,
- created = False,
- diff = None
- ):
- """Called when a post is updated. Arguments:
-
- * ``newly_mentioned_users`` - users who are mentioned in the
- post for the first time
- * ``created`` - a boolean. True when ``post`` has just been created
- * remaining arguments are self - explanatory
-
- The method does two things:
-
- * records "red envelope" recipients of the post
- * sends email alerts to all subscribers to the post
- """
- #todo: take into account created == True case
- (activity_type, update_object) = post.get_updated_activity_data(created)
-
- if post.is_comment():
- #it's just a comment!
- summary = post.text
- else:
- #summary = post.get_latest_revision().summary
- summary = diff
-
- update_activity = Activity(
- user = updated_by,
- active_at = timestamp,
- content_object = post,
- activity_type = activity_type,
- question = post.get_origin_post(),
- summary = summary
- )
- update_activity.save()
-
- #what users are included depends on the post type
- #for example for question - all Q&A contributors
- #are included, for comments only authors of comments and parent
- #post are included
- recipients = post.get_response_receivers(
- exclude_list = [updated_by, ]
- )
-
- update_activity.add_recipients(recipients)
-
- #create new mentions
- for u in newly_mentioned_users:
- #todo: a hack - some users will not have record of a mention
- #may need to fix this in the future. Added this so that
- #recipients of the response who are mentioned as well would
- #not get two notifications in the inbox for the same post
- if u in recipients:
- continue
- Activity.objects.create_new_mention(
- mentioned_whom = u,
- mentioned_in = post,
- mentioned_by = updated_by,
- mentioned_at = timestamp
- )
-
- assert(updated_by not in recipients)
-
- for user in (set(recipients) | set(newly_mentioned_users)):
- user.update_response_counts()
-
- #shortcircuit if the email alerts are disabled
- if askbot_settings.ENABLE_EMAIL_ALERTS == False:
- return
-
- #todo: weird thing is that only comments need the recipients
- #todo: debug these calls and then uncomment in the repo
- #argument to this call
- notification_subscribers = post.get_instant_notification_subscribers(
- potential_subscribers = recipients,
- mentioned_users = newly_mentioned_users,
- exclude_list = [updated_by, ]
- )
- #todo: fix this temporary spam protection plug
- if created:
- if not (updated_by.is_administrator() or updated_by.is_moderator()):
- if updated_by.reputation < 15:
- notification_subscribers = \
- [u for u in notification_subscribers if u.is_administrator()]
- send_instant_notifications_about_activity_in_post(
- update_activity = update_activity,
- post = post,
- recipients = notification_subscribers,
- )
-
-
@task(ignore_result = True)
def record_question_visit(
question_post = None,
@@ -225,7 +142,7 @@ def record_question_visit(
update_view_count = False):
"""celery task which records question visit by a person
updates view counter, if necessary,
- and awards the badges associated with the
+ and awards the badges associated with the
question visit
"""
#1) maybe update the view count
diff --git a/askbot/skins/default/templates/404.html b/askbot/templates/404.html
index 158bfb94..158bfb94 100644
--- a/askbot/skins/default/templates/404.html
+++ b/askbot/templates/404.html
diff --git a/askbot/skins/default/templates/404.jinja.html b/askbot/templates/404.jinja.html
index 2da99646..2da99646 100644
--- a/askbot/skins/default/templates/404.jinja.html
+++ b/askbot/templates/404.jinja.html
diff --git a/askbot/skins/default/templates/500.jinja.html b/askbot/templates/500.jinja.html
index 297ae736..297ae736 100644
--- a/askbot/skins/default/templates/500.jinja.html
+++ b/askbot/templates/500.jinja.html
diff --git a/askbot/templates/answer_edit.html b/askbot/templates/answer_edit.html
new file mode 100644
index 00000000..8c3687f1
--- /dev/null
+++ b/askbot/templates/answer_edit.html
@@ -0,0 +1,99 @@
+{% extends "two_column_body.html" %}
+{% import "macros.html" as macros %}
+<!-- template answer_edit.html -->
+{% block title %}{% spaceless %}{% trans %}Edit answer{% endtrans %}{% endspaceless %}{% endblock %}
+{% block forestyle %}
+ <link rel="stylesheet" type="text/css" href="{{"/js/wmd/wmd.css"|media}}" />
+{% endblock %}
+{% block content %}
+<h1 class="section-title">
+ {% trans %}Edit answer{% endtrans %} [<a href="{{ answer.thread._question_post().get_absolute_url() }}#{{ answer.id }}">{% trans %}back{% endtrans %}</a>]
+</h1>
+<div id="main-body" class="ask-body">
+ <form id="fmedit" action="{% url edit_answer answer.id %}" method="post" >{% csrf_token %}
+ <label for="id_revision" >{% trans %}revision{% endtrans %}:</label> <br/>
+ {% if revision_form.revision.errors %}{{ revision_form.revision.errors.as_ul() }}{% endif %}
+ <div style="vertical-align:middle">
+ {{ revision_form.revision }} <input type="hidden"
+ id="select_revision"
+ name="select_revision"
+ value="false">
+ </div>
+ {{ macros.edit_post(
+ form,
+ post_html = revision.text,
+ editor_type = settings.EDITOR_TYPE
+ )
+ }}
+ {% if settings.WIKI_ON and answer.wiki == False %}
+ {{ macros.checkbox_in_div(form.wiki) }}
+ {% endif %}
+ {% if request.user.is_authenticated() and request.user.can_make_group_private_posts() %}
+ {{ macros.checkbox_in_div(form.post_privately) }}
+ {% endif %}
+ <div class="after-editor">
+ <input id="edit_post_form_submit_button" type="submit" value="{% trans %}Save edit{% endtrans %}" class="submit" />&nbsp;
+ <input type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" onclick="history.back(-1);" />
+ </div>
+
+ </form>
+</div>
+{% endblock %}
+
+{% block sidebar %}
+ {% include "widgets/answer_edit_tips.html" %}
+{% endblock %}
+
+{% block endjs %}
+ {% include "meta/editor_data.html" %}
+ <script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
+ <script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
+ <script type='text/javascript' src='{{"/js/post.js"|media}}'></script>
+ <script type='text/javascript'>
+ {% if settings.ENABLE_MATHJAX or settings.MARKUP_CODE_FRIENDLY %}
+ var codeFriendlyMarkdown = true;
+ {% else %}
+ var codeFriendlyMarkdown = false;
+ {% endif %}
+ </script>
+ {% if settings.EDITOR_TYPE == 'markdown' %}
+ <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script>
+ <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script>
+ {% endif %}
+ <script type="text/javascript">
+ $().ready(function(){
+ $("#nav_questions").attr('className',"on");
+ $('#editor').TextAreaResizer();
+
+ //highlight code synctax when editor has new text
+ $("#editor").typeWatch({highlight: false, wait: 3000,
+ captureLength: 5, callback: lanai.highlightSyntax});
+
+ //toggle preview of editor
+ var display = true;
+ var txt = "{% trans %}hide preview{% endtrans %}";
+ $('#pre-collapse').text(txt);
+ $('#pre-collapse').bind('click', function(){
+ txt = display ? "{% trans %}show preview{% endtrans %}" : "{% trans %}hide preview{% endtrans %}";
+ display = !display;
+ $('#previewer').toggle();
+ $('#pre-collapse').text(txt);
+ });
+
+ setupFormValidation(
+ $("#fmedit"),
+ CPValidator.getAnswerFormRules(),
+ CPValidator.getAnswerFormMessages()
+ );
+
+ $('#id_revision').unbind().change(function(){
+ $("#select_revision").val('true');
+ $('#edit_post_form_submit_button').click();
+ });
+
+ lanai.highlightSyntax();
+
+ });
+ </script>
+{% endblock %}
+<!-- end template answer_edit.html -->
diff --git a/askbot/templates/ask.html b/askbot/templates/ask.html
new file mode 100644
index 00000000..27434f83
--- /dev/null
+++ b/askbot/templates/ask.html
@@ -0,0 +1,83 @@
+{% extends "two_column_body.html" %}
+{% import "macros.html" as macros %}
+<!-- template ask.html -->
+{% block title %}{% spaceless %}{% trans %}Ask Your Question{% endtrans %}{% endspaceless %}{% endblock %}
+{% block forestyle %}
+ <link rel="stylesheet" type="text/css" href="{{"/js/wmd/wmd.css"|media}}" />
+{% endblock %}
+{# main contents of ask form is in the template input_bar #}
+{% block sidebar %}
+{% include "widgets/question_edit_tips.html" %}
+{% endblock %}
+{% block content %}
+ {% include "widgets/ask_form.html" %}
+{% endblock %}
+{% block endjs %}
+ <script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
+ <script type='text/javascript' src='{{"/js/jquery.validate.js"|media}}'></script>
+ <script type='text/javascript' src='{{"/js/post.js"|media}}'></script>
+ {% if settings.EDITOR_TYPE == 'markdown' %}
+ <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script>
+ <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script>
+ {% endif %}
+ <script type='text/javascript'>
+ var sortMethod = undefined;//need for live_search
+ var minSearchWordLength = {{settings.MIN_SEARCH_WORD_LENGTH}};
+ </script>
+ <script type='text/javascript' src='{{"/js/live_search_new_thread.js"|media}}'></script>
+ {% include "meta/editor_data.html" %}
+ {% if mandatory_tags %}
+ {% include "meta/mandatory_tags_js.html" %}
+ {% endif %}
+ {% if settings.TAG_SOURCE == 'category-tree' %}
+ {% include "meta/category_tree_js.html" %}
+ {% endif %}
+ <script type='text/javascript'>
+ askbot['urls']['api_get_questions'] = '{% url api_get_questions %}';
+ askbot['urls']['saveDraftQuestion'] = '{% url save_draft_question %}';
+ {% if settings.ENABLE_MATHJAX or settings.MARKUP_CODE_FRIENDLY %}
+ var codeFriendlyMarkdown = true;
+ {% else %}
+ var codeFriendlyMarkdown = false;
+ {% endif %}
+ $().ready(function(){
+ liveSearchNewThreadInit();
+ //set current module button style
+ $('#editor').TextAreaResizer();
+ //highlight code synctax when editor has new text
+ $("#editor").typeWatch({highlight: false, wait: 3000,
+ captureLength: 5, callback: lanai.highlightSyntax});
+
+ //toggle preview of editor
+ //todo remove copy-paste
+ var display = true;
+ var txt = "[{% trans %}hide preview{% endtrans %}]";
+ $('#pre-collapse').text(txt);
+ $('#pre-collapse').bind('click', function(){
+ txt = display ? "[{% trans %}show preview{% endtrans %}]" : "[{% trans %}hide preview{% endtrans %}]";
+ display = !display;
+ $('#previewer').toggle();
+ $('#pre-collapse').text(txt);
+ });
+ //Tags autocomplete
+
+ {{ macros.tag_autocomplete_js(id = '#id_tags') }}
+
+ setupFormValidation($("#fmask"), CPValidator.getQuestionFormRules(), CPValidator.getQuestionFormMessages());
+ lanai.highlightSyntax();
+
+ if (askbot['data']['userIsAuthenticated']) {
+ var draftHandler = new DraftQuestion();
+ draftHandler.decorate($(document));
+ window.onbeforeunload = function() {
+ var saveHandler = draftHandler.getSaveHandler();
+ saveHandler(true);
+ //var msg = gettext("%s, we've saved your draft, but...");
+ //return interpolate(msg, [askbot['data']['userName']]);
+ };
+ }
+ });
+ </script>
+{% endblock %}
+
+<!-- end template ask.html -->
diff --git a/askbot/templates/ask_by_widget.html b/askbot/templates/ask_by_widget.html
new file mode 100644
index 00000000..f700f83a
--- /dev/null
+++ b/askbot/templates/ask_by_widget.html
@@ -0,0 +1,16 @@
+{% extends "widget_base.html" %}
+{% block forestyle %}
+{%endblock%}
+
+{%block body%}
+Enter your question
+<form action="." method="POST" accept-charset="utf-8">
+ {% csrf_token %}
+ {{form.title}}
+ {% if form.ask_anonymously %}
+ {{form.ask_anonymously}}
+ {%endif%}
+ <input type="submit" value="Ask your question" />
+</form>
+{{form.errors}}
+{%endblock%}
diff --git a/askbot/templates/ask_widget_complete.html b/askbot/templates/ask_widget_complete.html
new file mode 100644
index 00000000..82fe570c
--- /dev/null
+++ b/askbot/templates/ask_widget_complete.html
@@ -0,0 +1,8 @@
+{% extends "widget_base.html" %}
+{% block forestyle %}
+{%endblock%}
+
+{%block body%}
+<a href="{{question_url}}" >Question posted</a>
+{%endblock%}
+
diff --git a/askbot/skins/common/templates/authopenid/authopenid_macros.html b/askbot/templates/authopenid/authopenid_macros.html
index 9d35ac6f..9d35ac6f 100644
--- a/askbot/skins/common/templates/authopenid/authopenid_macros.html
+++ b/askbot/templates/authopenid/authopenid_macros.html
diff --git a/askbot/skins/common/templates/authopenid/changeemail.html b/askbot/templates/authopenid/changeemail.html
index 8afa9c49..8afa9c49 100644
--- a/askbot/skins/common/templates/authopenid/changeemail.html
+++ b/askbot/templates/authopenid/changeemail.html
diff --git a/askbot/templates/authopenid/complete.html b/askbot/templates/authopenid/complete.html
new file mode 100644
index 00000000..c9afedee
--- /dev/null
+++ b/askbot/templates/authopenid/complete.html
@@ -0,0 +1,63 @@
+{% extends "one_column_body.html" %}
+<!-- complete.html -->
+{#
+views calling this template:
+* django_authopenid.views.register with login_type='openid'
+* django_authopenid.views.signin - with login_type='legacy'
+
+purpose of this template is to allow user enter his/her name
+email and sign up for email alerts at the initial registratio
+
+parameters:
+* provider
+* login_type openid|legacy
+* username (same as screen name or username in the models, and nickname in openid sreg)
+* openid_register_form
+* openid_verify_form - not clear what this form is supposed to do, not used for legacy
+* openid_username_exists
+#}
+{% block head %}{% endblock %}
+{% block title %}{% spaceless %}{% trans %}Registration{% endtrans %}{% endspaceless %}{% endblock %}
+{% block content %}
+ <h1>{% trans %}User registration{% endtrans %}</h1>
+ {% if openid_register_form.errors %}
+ <ul class="errorlist">
+ {% for error in openid_register_form.non_field_errors() %}
+ <li>{{error}}</li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+ <div class="login">
+ {% if login_type=='openid' %}
+ <form name="fregister" action="{% url user_register %}" method="POST">{% csrf_token %}
+ {% elif login_type=='facebook' %}
+ <form name="fregister" action="" method="POST">{% csrf_token %}
+ {% else %}
+ <form name="fregister" action="{{ default_form_action }}" method="POST">{% csrf_token %}
+ {% endif %}
+ {{ openid_register_form.next }}
+ <div class="form-row-vertical">
+ <label for="id_username">
+ {%- trans %}<strong>Screen Name</strong> (<i>will be shown to others</i>){% endtrans %}
+ </label>
+ {% if openid_register_form.username.errors %}
+ <p class="error">{{ openid_register_form.username.errors|join(", ") }}</p>
+ {% endif %}
+ {{ openid_register_form.username }}
+ </div>
+ <div class="form-row-vertical margin-bottom">
+ <label for="id_email">
+ {%- trans %}<strong>Email Address</strong> (<i>will <strong>not</strong> be shared with
+anyone, must be valid</i>)
+ {% endtrans -%}
+ </label>
+ {% if openid_register_form.email.errors %}
+ <p class="error">{{ openid_register_form.email.errors|join(", ") }}</p>
+ {% endif %}
+ {{ openid_register_form.email }}
+ </div>
+ <div class="submit-row"><input type="submit" class="submit" name="bnewaccount" value="{% trans %}Signup{% endtrans %}"/></div>
+ </form>
+ </div>
+{% endblock %}
+<!-- end complete.html -->
diff --git a/askbot/skins/common/templates/authopenid/confirm_email.txt b/askbot/templates/authopenid/confirm_email.txt
index 5cab7c4c..5cab7c4c 100644
--- a/askbot/skins/common/templates/authopenid/confirm_email.txt
+++ b/askbot/templates/authopenid/confirm_email.txt
diff --git a/askbot/templates/authopenid/email_validation.html b/askbot/templates/authopenid/email_validation.html
new file mode 100644
index 00000000..616b285f
--- /dev/null
+++ b/askbot/templates/authopenid/email_validation.html
@@ -0,0 +1,20 @@
+{% extends "email/base_mail.html"%}
+{% block title %}{% trans %}Greetings from the Q&A forum{% endtrans %},{%endblock%}
+{% block headline%}{% trans %}Greetings from the Q&A forum{% endtrans %},{%endblock%}
+
+{%block content%}
+
+<p>{% trans %}To make use of the Forum, please follow the link below:{% endtrans %}</p>
+
+<p><a href="{{validation_link}}" >{{validation_link}}</a></p>
+
+<p>{% trans %}Following the link above will help us verify your email address.{% endtrans %}</p>
+
+<p>{% trans %}If you believe that this message was sent in mistake -
+no further action is needed. Just ignore this email, we apologize
+for any inconvenience{% endtrans %}</p>
+{%endblock%}
+
+{%block footer %}
+{% include "email/footer.html" %}
+{% endblock %}
diff --git a/askbot/skins/common/templates/authopenid/email_validation.txt b/askbot/templates/authopenid/email_validation.txt
index bd68c61a..bd68c61a 100644
--- a/askbot/skins/common/templates/authopenid/email_validation.txt
+++ b/askbot/templates/authopenid/email_validation.txt
diff --git a/askbot/skins/common/templates/authopenid/logout.html b/askbot/templates/authopenid/logout.html
index 1ac6705c..1ac6705c 100644
--- a/askbot/skins/common/templates/authopenid/logout.html
+++ b/askbot/templates/authopenid/logout.html
diff --git a/askbot/skins/common/templates/authopenid/providers_javascript.html b/askbot/templates/authopenid/providers_javascript.html
index cd9f56b6..cd9f56b6 100644
--- a/askbot/skins/common/templates/authopenid/providers_javascript.html
+++ b/askbot/templates/authopenid/providers_javascript.html
diff --git a/askbot/templates/authopenid/signin.html b/askbot/templates/authopenid/signin.html
new file mode 100644
index 00000000..c5a5c47f
--- /dev/null
+++ b/askbot/templates/authopenid/signin.html
@@ -0,0 +1,231 @@
+{% extends "two_column_body.html" %}
+{% import "authopenid/authopenid_macros.html" as login_macros %}
+{% from "macros.html" import timeago %}
+<!-- signin.html -->
+{% block title %}{% spaceless %}{% trans %}User login{% endtrans %}{% endspaceless %}{% endblock %}
+{% block forestyle %}
+ <link rel="stylesheet" type="text/css" media="screen" href="{{"/jquery-openid/openid.css"|media}}"/>
+{% endblock %}
+{% block content %}
+{% if have_buttons or view_subtype == 'email_sent' %}
+ <h1 class="section-title">{{page_title}}</h1>
+{% endif %}
+ {% if answer %}
+ <div class="message">
+ {% trans title=answer.question.title|escape, summary=answer.summary|escape %}
+ Your answer to {{title}} {{summary}} will be posted once you log in
+ {% endtrans %}
+ </div>
+ {% endif %}
+ {% if question %}
+ <div class="message">
+ {% trans title=question.title|escape, summary=question.summary|escape %}Your question
+ {{title}} {{summary}} will be posted once you log in
+ {% endtrans %}
+ </div>
+ {% endif %}
+ {% if not (view_subtype == 'default' and have_buttons) %}
+ <p id='login-intro'>
+ {% if view_subtype == 'add_openid' and have_buttons %}
+ {% if existing_login_methods %}
+ {% trans %}It's a good idea to make sure that your existing login methods still work, or add a new one. Please click any of the icons below to check/change or add new login methods.{% endtrans %}
+ {% else %}
+ {% trans %}Please add a more permanent login method by clicking one of the icons below, to avoid logging in via email each time.{% endtrans %}
+ {% endif %}
+ {% elif view_subtype == 'change_openid' and have_buttons %}
+ {% if existing_login_methods %}
+ {% trans %}Click on one of the icons below to add a new login method or re-validate an existing one.{% endtrans %}
+ {% else %}
+ {% trans %}You don't have a method to log in right now, please add one or more by clicking any of the icons below.{% endtrans %}
+ {% endif %}
+ {% elif view_subtype == 'email_sent' %}
+ {% trans %}Please check your email and visit the enclosed link to re-connect to your account{% endtrans %}
+ {% endif %}
+ </p>
+ {% endif %}
+ {% if openid_error_message %}
+ <p class="warning">{{ openid_error_message }}</p>
+ {% endif %}
+ {% if view_subtype != 'email_sent' and view_subtype != 'bad_key' %}
+ <form id="signin-form" method="post" action="{{ settings.LOGIN_URL }}">{% csrf_token %}
+ {# in this branch - the real signin view we display the login icons
+ here we hide the local login button only if admin
+ wants to always show the password login form - then
+ the button is useless.
+ #}
+ {{ login_form.login_provider_name }}
+ {{ login_form.next }}
+ {{
+ login_macros.provider_buttons(
+ login_form = login_form,
+ major_login_providers = major_login_providers,
+ minor_login_providers = minor_login_providers,
+ hide_local_login = settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN,
+ settings = settings,
+ logged_in = user.is_authenticated(),
+ show_buttons = have_buttons
+ )
+ }}
+ {% if use_password_login == True %}
+ <fieldset
+ id="password-fs"
+ {% if user.is_anonymous() %}
+ {% if not login_form.username.errors and not login_form.password_login_failed %}
+ {% if not settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN %}
+ style="display:none;"
+ {%endif%}
+ {% endif %}
+ {% else %}
+ {% if not login_form.new_password.errors and not login_form.new_password_retyped.errors %}
+ {% if not settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN %}
+ style="display:none;"
+ {% endif%}
+ {% endif %}
+ {% endif %}
+ >
+ {{login_form.password_action}}
+ {% if user.is_anonymous() %}
+ {% if have_buttons %}
+ <h2 id="password-heading">
+ {% trans %}or enter your <span>user name and password</span>, then sign in{% endtrans %}
+ </h2>
+ {% else %}
+ <h1 class="section-title">
+ {% trans %}Please, sign in{% endtrans %}
+ </h1>
+ {% endif %}
+ {% if have_buttons %}
+ <p class="hint">{% trans %}(or select another login method above){% endtrans %}</p>
+ {% endif %}
+ <table class="login">
+ {% if login_form.password_login_failed %}
+ <tr>
+ <td colspan="2">
+ <p class="error">{% trans %}Login failed, please try again{% endtrans %}</p>
+ </td>
+ </tr>
+ {% endif %}
+ <tr>
+ <td><label for="id_username">{% trans %}Login or email{% endtrans %}</label></td>
+ <td>{{login_form.username}}</td>
+ </tr>
+ <tr>
+ <td><label for="id_password">{% trans %}Password{% endtrans %}</label></td>
+ <td>{{login_form.password}}</td>
+ </tr>
+ </table>
+ <p id="local_login_buttons">
+ <input class="submit-b" name="login_with_password" type="submit" value="{% trans %}Sign in{% endtrans %}" />
+ {% if settings.USE_LDAP_FOR_PASSWORD_LOGIN == False %}
+ <a class="create-password-account" style="vertical-align:middle" href="{% url user_signup_with_password %}?login_provider=local">{% trans %}Create a password-protected account{% endtrans %}</a>
+ {% endif %}
+ </p>
+ {% elif settings.USE_LDAP_FOR_PASSWORD_LOGIN == False %}
+ <h2 id="password-heading">
+ {% trans %}To change your password - please enter the new one twice, then submit{% endtrans %}
+ </h2>
+ <table class="login">
+ <tr>
+ <td><label for="id_new_password">{% trans %}New password{% endtrans %}</label></td>
+ <td>
+ {{login_form.new_password}}
+ </td>
+ <td>
+ <span class="error">{{login_form.new_password.errors[0]}}</span>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="id_new_password_retyped">{% trans %}Please, retype{% endtrans %}</label></td>
+ <td>
+ {{login_form.new_password_retyped}}
+ </td>
+ <td>
+ <span class="error">{{login_form.new_password_retyped.errors[0]}}</span>
+ </td>
+ </tr>
+ </table>
+ <p id="local_login_buttons">
+ <input class="submit-b" name="change_password" type="submit" value="{% trans %}Change password{% endtrans %}" />
+ </p>
+ {% endif %}
+ </fieldset>
+ {% endif %}
+ </form>
+ {% if user.is_authenticated() and existing_login_methods and settings.ALLOW_ADD_REMOVE_LOGIN_METHODS %}
+ <div
+ id='existing-login-methods'
+ {% if login_form.password_change_failed %}
+ style="display:none";
+ {% endif %}
+ >
+ <h2 id='ab-show-login-methods'>
+ {% trans %}Here are your current login methods{% endtrans %}
+ </h2>
+ <table id='ab-existing-login-methods'>
+ <tr>
+ <th>{% trans %}provider{% endtrans %}</th>
+ <th>{% trans %}last used{% endtrans %}</th>
+ <th>{% trans %}delete, if you like{% endtrans %}</th>
+ </tr>
+ {% for login_method in existing_login_methods %}
+ <tr class="ab-provider-row">
+ <td class="ab-provider-name">
+ {{login_method.provider_name}}
+ </td>
+ <td>
+ {% if login_method.last_used_timestamp %}
+ {{ timeago(login_method.last_used_timestamp) }}
+ {% endif %}
+ </td>
+ <td>
+ {% if login_method.is_deletable %}
+ <button>{% trans %}delete{% endtrans %}</button>
+ {% else %}
+ {% trans %}cannot be deleted{% endtrans %}
+ {% endif %}
+ </td>
+ </tr>
+ {% endfor %}
+ </table>
+ </div>
+ {% endif %}
+ {% endif %}
+ {% if view_subtype != 'email_sent' or view_subtype == 'bad_key' %}
+ {% if user.is_anonymous() and settings.ALLOW_ACCOUNT_RECOVERY_BY_EMAIL %}
+ <form id="account-recovery-form" action="{% url user_account_recover %}" method="post">{% csrf_token %}
+ {% if view_subtype != 'bad_key' %}
+ <h2 id='account-recovery-heading'>{% trans %}Still have trouble signing in?{% endtrans %}</h2>
+ {% endif %}
+ <p class="hint">
+ <span class="text">
+ {% if view_subtype == 'bad_key' %}
+ {% trans %}Please, enter your email address below and obtain a new key{% endtrans %}
+ {% else %}
+ {% trans %}Please, enter your email address below to recover your account{% endtrans %}
+ {% endif %}
+ </span>
+ <span style="display:none" class="link"> - <a href="#">{% trans %}recover your account via email{% endtrans %}</a></span>
+ </p>
+ <fieldset id='email-input-fs'>
+ {% if account_recovery_form.email.errors %}
+ <p class="error">{{account_recovery_form.email.errors[0]}}</p>
+ {% endif %}
+ {{ account_recovery_form.email }}
+ <input
+ class="submit-b"
+ type="submit"
+ {% if view_subtype == 'bad_key' %}
+ value="{% trans %}Send a new recovery key{% endtrans %}"
+ {% else %}
+ value="{% trans %}Recover your account via email{% endtrans %}"
+ {% endif %}
+ />
+ </fieldset>
+ </form>
+ {% endif %}
+ {% endif %}
+{% endblock %}
+{% block endjs %}
+{% include "authopenid/providers_javascript.html" %}
+{% endblock %}
+<!-- end signin.html -->
diff --git a/askbot/templates/authopenid/signup_with_password.html b/askbot/templates/authopenid/signup_with_password.html
new file mode 100644
index 00000000..e5a8f633
--- /dev/null
+++ b/askbot/templates/authopenid/signup_with_password.html
@@ -0,0 +1,55 @@
+{% extends "one_column_body.html" %}
+{% import "authopenid/authopenid_macros.html" as login_macros %}
+<!--signup.html-->
+{% block title %}{% spaceless %}{% trans %}Signup{% endtrans %}{% endspaceless %}{% endblock %}
+{% block forestyle %}
+ <link rel="stylesheet" type="text/css" media="screen" href="{{"/jquery-openid/openid.css"|media}}"/>
+{% endblock %}
+{% block content %}
+{% if settings.PASSWORD_REGISTER_SHOW_PROVIDER_BUTTONS == True %}
+ <h1 class="section-title">{% trans %}Please register by clicking on any of the icons below{% endtrans %}</h1>
+ <form id="signin-form" method="post" action="{{ settings.LOGIN_URL }}">{% csrf_token %}
+ {# hide_local_login == True because it is password reg form #}
+ {{
+ login_macros.provider_buttons(
+ login_form = login_form,
+ major_login_providers = major_login_providers,
+ minor_login_providers = minor_login_providers,
+ hide_local_login = True,
+ settings = settings
+ )
+ }}
+ </form>
+ <h2>{% trans %}or create a new user name and password here{% endtrans %}</h2>
+{% else %}
+ <h1 class="section-title">{% trans %}Create login name and password{% endtrans %}</h1>
+ <!--p class="message">{% trans %}<span class='strong big'>If you prefer, create your forum login name and
+password here. However</span>, please keep in mind that we also support
+<strong>OpenID</strong> login method. With <strong>OpenID</strong> you can
+simply reuse your external login (e.g. Gmail or AOL) without ever sharing
+your login details with anyone and having to remember yet another password.{% endtrans %}</p-->
+{%endif%}
+<form action="{% url user_signup_with_password %}" method="post" accept-charset="utf-8">{% csrf_token %}
+ {{form.login_provider}}
+ <ul class="form-horizontal-rows">
+ <li><label for="usename_id">{{form.username.label}}</label>{{form.username}}{{form.username.errors}}</li>
+ <li><label for="email_id">{{form.email.label}}</label>{{form.email}}{{form.email.errors}}</li>
+ <li><label for="password1_id">{{form.password1.label}}</label>{{form.password1}}{{form.password1.errors}}</li>
+ <li><label for="password2_id">{{form.password2.label}}</label>{{form.password2}}{{form.password2.errors}}</li>
+ </ul>
+ {% if settings.USE_RECAPTCHA %}
+ <p class="signup_p">{% trans %}Please read and type in the two words below to help us prevent automated account creation.{% endtrans %}</p>
+ {{form.recaptcha}}
+ {% endif %}
+ <div class="submit-row"><input type="submit" class="submit" value="{% trans %}Signup{% endtrans %}" />
+ {% if settings.PASSWORD_REGISTER_SHOW_PROVIDER_BUTTONS == False %}
+ <strong>{% trans %}or{% endtrans %}
+ <a href="{{ settings.LOGIN_URL }}">{% trans %}return to OpenID login{% endtrans %}</a></strong>
+ {% endif %}
+ </div>
+</form>
+{% endblock %}
+{%block endjs%}
+{%include "authopenid/providers_javascript.html" %}
+{%endblock%}
+<!--end signup.html-->
diff --git a/askbot/templates/authopenid/verify_email.html b/askbot/templates/authopenid/verify_email.html
new file mode 100644
index 00000000..613ca589
--- /dev/null
+++ b/askbot/templates/authopenid/verify_email.html
@@ -0,0 +1,14 @@
+{% extends "one_column_body.html" %}
+{% block title %}{% spaceless %}{% trans %}Confirm email address{% endtrans %}{% endspaceless %}{% endblock %}
+{% block content %}
+ <h1 class="section-title">{% trans %}Confirm email address{% endtrans %}</h1>
+ <label for="validation_code">
+ {% trans %}Validation email sent. Please find it and follow the enclosed link.<br/>
+ If the link doesn't work - enter the code below:{% endtrans %}
+ </label>
+ <form method="post">{% csrf_token %}
+ <input id="validation-code" type="text" name="validation_code" />
+ <input type="submit" class="submit" value="{% trans %}Confirm email{% endtrans %}" />
+ </form>
+{% endblock %}
+<!-- end changeemail.html -->
diff --git a/askbot/templates/authopenid/widget_signin.html b/askbot/templates/authopenid/widget_signin.html
new file mode 100644
index 00000000..c3dbcfde
--- /dev/null
+++ b/askbot/templates/authopenid/widget_signin.html
@@ -0,0 +1,231 @@
+{% extends "widget_base.html" %}
+{% import "authopenid/authopenid_macros.html" as login_macros %}
+{% from "macros.html" import timeago %}
+<!-- signin.html -->
+{% block title %}{% spaceless %}{% trans %}User login{% endtrans %}{% endspaceless %}{% endblock %}
+{% block forestyle %}
+ <link rel="stylesheet" type="text/css" media="screen" href="{{"/jquery-openid/openid.css"|media}}"/>
+{% endblock %}
+{% block forejs %}
+ {% include "meta/bottom_scripts.html" %}
+ {% include "meta/html_head_javascript.html" %}
+{% endblock %}
+{% block content %}
+{% if have_buttons or view_subtype == 'email_sent' %}
+ <h1 class="section-title">{{page_title}}</h1>
+{% endif %}
+ {% if answer %}
+ <div class="message">
+ {% trans title=answer.question.title|escape, summary=answer.summary|escape %}
+ Your answer to {{title}} {{summary}} will be posted once you log in
+ {% endtrans %}
+ </div>
+ {% endif %}
+ {% if question %}
+ <div class="message">
+ {% trans title=question.title|escape, summary=question.summary|escape %}Your question
+ {{title}} {{summary}} will be posted once you log in
+ {% endtrans %}
+ </div>
+ {% endif %}
+ <p id='login-intro'>
+ {% if view_subtype == 'default' and have_buttons %}
+ {% trans %}Choose your favorite service below to sign in using secure OpenID or similar technology. Your external service password always stays confidential and you don't have to rememeber or create another one.{% endtrans %}
+ {% elif view_subtype == 'add_openid' and have_buttons %}
+ {% if existing_login_methods %}
+ {% trans %}It's a good idea to make sure that your existing login methods still work, or add a new one. Please click any of the icons below to check/change or add new login methods.{% endtrans %}
+ {% else %}
+ {% trans %}Please add a more permanent login method by clicking one of the icons below, to avoid logging in via email each time.{% endtrans %}
+ {% endif %}
+ {% elif view_subtype == 'change_openid' and have_buttons %}
+ {% if existing_login_methods %}
+ {% trans %}Click on one of the icons below to add a new login method or re-validate an existing one.{% endtrans %}
+ {% else %}
+ {% trans %}You don't have a method to log in right now, please add one or more by clicking any of the icons below.{% endtrans %}
+ {% endif %}
+ {% elif view_subtype == 'email_sent' %}
+ {% trans %}Please check your email and visit the enclosed link to re-connect to your account{% endtrans %}
+ {% endif %}
+ </p>
+ {% if openid_error_message %}
+ <p class="warning">{{ openid_error_message }}</p>
+ {% endif %}
+ {% if view_subtype != 'email_sent' and view_subtype != 'bad_key' %}
+ <form id="signin-form" method="post" action="{% url widget_signin %}">{% csrf_token %}
+ {# in this branch - the real signin view we display the login icons
+ here we hide the local login button only if admin
+ wants to always show the password login form - then
+ the button is useless.
+ #}
+ {{ login_form.login_provider_name }}
+ {{ login_form.next }}
+ {{
+ login_macros.provider_buttons(
+ login_form = login_form,
+ major_login_providers = major_login_providers,
+ minor_login_providers = minor_login_providers,
+ hide_local_login = settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN,
+ settings = settings,
+ logged_in = user.is_authenticated(),
+ show_buttons = have_buttons
+ )
+ }}
+ {% if use_password_login == True %}
+ <fieldset
+ id="password-fs"
+ {% if user.is_anonymous() %}
+ {% if not login_form.username.errors and not login_form.password_login_failed %}
+ {% if not settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN %}
+ style="display:none;"
+ {%endif%}
+ {% endif %}
+ {% else %}
+ {% if not login_form.new_password.errors and not login_form.new_password_retyped.errors %}
+ {% if not settings.SIGNIN_ALWAYS_SHOW_LOCAL_LOGIN %}
+ style="display:none;"
+ {% endif%}
+ {% endif %}
+ {% endif %}
+ >
+ {{login_form.password_action}}
+ {% if user.is_anonymous() %}
+ {% if have_buttons %}
+ <h2 id="password-heading">
+ {% trans %}or enter your <span>user name and password</span>, then sign in{% endtrans %}
+ </h2>
+ {% else %}
+ <h1 class="section-title">
+ {% trans %}Please, sign in{% endtrans %}
+ </h1>
+ {% endif %}
+ {% if have_buttons %}
+ <p class="hint">{% trans %}(or select another login method above){% endtrans %}</p>
+ {% endif %}
+ {% if login_form.password_login_failed %}
+ <p class="error">{% trans %}Login failed, please try again{% endtrans %}</p>
+ {% endif %}
+ <table class="login">
+ <tr>
+ <td><label for="id_username">{% trans %}Login or email{% endtrans %}</label></td>
+ <td>{{login_form.username}}</td>
+ </tr>
+ <tr>
+ <td><label for="id_password">{% trans %}Password{% endtrans %}</label></td>
+ <td>{{login_form.password}}</td>
+ </tr>
+ </table>
+ <p id="local_login_buttons">
+ <input class="submit-b" name="login_with_password" type="submit" value="{% trans %}Sign in{% endtrans %}" />
+ {% if settings.USE_LDAP_FOR_PASSWORD_LOGIN == False %}
+ <a class="create-password-account" style="vertical-align:middle" href="{% url user_signup_with_password %}?login_provider=local">{% trans %}Create a password-protected account{% endtrans %}</a>
+ {% endif %}
+ </p>
+ {% elif settings.USE_LDAP_FOR_PASSWORD_LOGIN == False %}
+ <h2 id="password-heading">
+ {% trans %}To change your password - please enter the new one twice, then submit{% endtrans %}
+ </h2>
+ <table class="login">
+ <tr>
+ <td><label for="id_new_password">{% trans %}New password{% endtrans %}</label></td>
+ <td>
+ {{login_form.new_password}}
+ </td>
+ <td>
+ <span class="error">{{login_form.new_password.errors[0]}}</span>
+ </td>
+ </tr>
+ <tr>
+ <td><label for="id_new_password_retyped">{% trans %}Please, retype{% endtrans %}</label></td>
+ <td>
+ {{login_form.new_password_retyped}}
+ </td>
+ <td>
+ <span class="error">{{login_form.new_password_retyped.errors[0]}}</span>
+ </td>
+ </tr>
+ </table>
+ <p id="local_login_buttons">
+ <input class="submit-b" name="change_password" type="submit" value="{% trans %}Change password{% endtrans %}" />
+ </p>
+ {% endif %}
+ </fieldset>
+ {% endif %}
+ </form>
+ {% if user.is_authenticated() and existing_login_methods and settings.ALLOW_ADD_REMOVE_LOGIN_METHODS %}
+ <div
+ id='existing-login-methods'
+ {% if login_form.password_change_failed %}
+ style="display:none";
+ {% endif %}
+ >
+ <h2 id='ab-show-login-methods'>
+ {% trans %}Here are your current login methods{% endtrans %}
+ </h2>
+ <table id='ab-existing-login-methods'>
+ <tr>
+ <th>{% trans %}provider{% endtrans %}</th>
+ <th>{% trans %}last used{% endtrans %}</th>
+ <th>{% trans %}delete, if you like{% endtrans %}</th>
+ </tr>
+ {% for login_method in existing_login_methods %}
+ <tr class="ab-provider-row">
+ <td class="ab-provider-name">
+ {{login_method.provider_name}}
+ </td>
+ <td>
+ {% if login_method.last_used_timestamp %}
+ {{ timeago(login_method.last_used_timestamp) }}
+ {% endif %}
+ </td>
+ <td>
+ {% if login_method.is_deletable %}
+ <button>{% trans %}delete{% endtrans %}</button>
+ {% else %}
+ {% trans %}cannot be deleted{% endtrans %}
+ {% endif %}
+ </td>
+ </tr>
+ {% endfor %}
+ </table>
+ </div>
+ {% endif %}
+ {% endif %}
+ {% if view_subtype != 'email_sent' or view_subtype == 'bad_key' %}
+ {% if user.is_anonymous() and settings.ALLOW_ACCOUNT_RECOVERY_BY_EMAIL %}
+ <form id="account-recovery-form" action="{% url user_account_recover %}" method="post">{% csrf_token %}
+ {% if view_subtype != 'bad_key' %}
+ <h2 id='account-recovery-heading'>{% trans %}Still have trouble signing in?{% endtrans %}</h2>
+ {% endif %}
+ <p class="hint">
+ <span class="text">
+ {% if view_subtype == 'bad_key' %}
+ {% trans %}Please, enter your email address below and obtain a new key{% endtrans %}
+ {% else %}
+ {% trans %}Please, enter your email address below to recover your account{% endtrans %}
+ {% endif %}
+ </span>
+ <span style="display:none" class="link"> - <a href="#">{% trans %}recover your account via email{% endtrans %}</a></span>
+ </p>
+ <fieldset id='email-input-fs'>
+ {% if account_recovery_form.email.errors %}
+ <p class="error">{{account_recovery_form.email.errors[0]}}</p>
+ {% endif %}
+ {{ account_recovery_form.email }}
+ <input
+ class="submit-b"
+ type="submit"
+ {% if view_subtype == 'bad_key' %}
+ value="{% trans %}Send a new recovery key{% endtrans %}"
+ {% else %}
+ value="{% trans %}Recover your account via email{% endtrans %}"
+ {% endif %}
+ />
+ </fieldset>
+ </form>
+ {% endif %}
+ {% endif %}
+{% endblock %}
+{% block endjs %}
+{% include "authopenid/providers_javascript.html" %}
+{% endblock %}
+<!-- end signin.html -->
diff --git a/askbot/skins/common/templates/avatar/add.html b/askbot/templates/avatar/add.html
index 68a188ef..68a188ef 100644
--- a/askbot/skins/common/templates/avatar/add.html
+++ b/askbot/templates/avatar/add.html
diff --git a/askbot/skins/common/templates/avatar/change.html b/askbot/templates/avatar/change.html
index 7921a662..7921a662 100644
--- a/askbot/skins/common/templates/avatar/change.html
+++ b/askbot/templates/avatar/change.html
diff --git a/askbot/skins/common/templates/avatar/confirm_delete.html b/askbot/templates/avatar/confirm_delete.html
index ee3d10d7..ee3d10d7 100644
--- a/askbot/skins/common/templates/avatar/confirm_delete.html
+++ b/askbot/templates/avatar/confirm_delete.html
diff --git a/askbot/skins/default/templates/badge.html b/askbot/templates/badge.html
index b2c4ce8b..b2c4ce8b 100644
--- a/askbot/skins/default/templates/badge.html
+++ b/askbot/templates/badge.html
diff --git a/askbot/skins/default/templates/badges.html b/askbot/templates/badges.html
index ce76e76b..ce76e76b 100644
--- a/askbot/skins/default/templates/badges.html
+++ b/askbot/templates/badges.html
diff --git a/askbot/templates/base.html b/askbot/templates/base.html
new file mode 100644
index 00000000..63d7115f
--- /dev/null
+++ b/askbot/templates/base.html
@@ -0,0 +1,58 @@
+<!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">
+ <head>
+ <title>{% block title %}{% endblock %} - {{ settings.APP_TITLE|escape }}</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ {% block meta_description %}
+ <meta name="description" content="{{settings.APP_DESCRIPTION|escape}}" />
+ {% endblock %}
+ <meta name="keywords" content="{%block keywords%}{%endblock%},{{settings.APP_KEYWORDS|escape}}" />
+ {% if settings.GOOGLE_SITEMAP_CODE %}
+ <meta name="google-site-verification" content="{{settings.GOOGLE_SITEMAP_CODE}}" />
+ {% endif %}
+ <link rel="shortcut icon" href="{{ settings.SITE_FAVICON|media }}" />
+ {% block before_css %}{% endblock %}
+ {% include "meta/html_head_stylesheets.html" %}
+ {% block forestyle %}{% endblock %}
+ {% include "meta/html_head_javascript.html" %}
+ {% block forejs %}{% endblock %}
+ {% if settings.USE_CUSTOM_HTML_HEAD %}
+ {{ settings.CUSTOM_HTML_HEAD }}
+ {% endif %}
+ </head>
+ <body class="{% block body_class %}{% endblock %}{% if user_messages %} user-messages{% endif %}{% if page_class %} {{page_class}}{% endif %}{% if request.user.is_anonymous() %} anon{% endif %} lang-{{settings.LANGUAGE_CODE}}">
+ {% include "widgets/system_messages.html" %}
+ {% include "debug_header.html" %}
+ {% include "custom_header.html" ignore missing %}
+ {% if settings.CUSTOM_HEADER|trim != '' %}
+ <div id="custom-header">
+ {{settings.CUSTOM_HEADER}}
+ </div>
+ {% endif %}
+ {% include "widgets/header.html" %} {# Logo, user tool navigation and meta navitation #}
+ {% include "widgets/secondary_header.html" %} {# Scope selector, search input and ask button #}
+ {% if settings.ENABLE_LEADING_SIDEBAR %}
+ <div id="leading-sidebar">
+ {{ settings.LEADING_SIDEBAR }}
+ </div>
+ {% endif %}
+ <div class="content-wrapper">
+ {% block body %}
+ {% endblock %}
+ </div>
+ {% if settings.FOOTER_MODE == 'default' %}
+ {% include "widgets/footer.html" %}
+ {% elif settings.FOOTER_MODE == 'customize' %}
+ {{ settings.CUSTOM_FOOTER }}
+ {% endif %}
+ {% include "custom_footer.html" ignore missing %}
+ {% include "meta/bottom_scripts.html" %}
+ {% block endjs %}
+ {% endblock %}
+ <script type="text/javascript">
+ for (url_name in askbot['urls']){
+ askbot['urls'][url_name] = cleanUrl(askbot['urls'][url_name]);
+ }
+ </script>
+ </body>
+</html>
diff --git a/askbot/skins/default/templates/close.html b/askbot/templates/close.html
index bac2b3ee..bac2b3ee 100644
--- a/askbot/skins/default/templates/close.html
+++ b/askbot/templates/close.html
diff --git a/askbot/skins/common/templates/debug_header.html b/askbot/templates/debug_header.html
index e1230265..e1230265 100644
--- a/askbot/skins/common/templates/debug_header.html
+++ b/askbot/templates/debug_header.html
diff --git a/askbot/templates/django_error.html b/askbot/templates/django_error.html
new file mode 100644
index 00000000..c1bfcc20
--- /dev/null
+++ b/askbot/templates/django_error.html
@@ -0,0 +1,31 @@
+<html>
+ <head>
+ <title>Internal Server Error</title>
+ </head>
+ <body>
+ <h1>Internal Server Error</h1>
+ <p>
+ Most likely this is caused by an import error
+ within Django due to an incomplete setup of your
+ django project.
+ </p>
+ <p>
+ Please look into your error logs for more details.
+ </p>
+ <p>
+ Have you installed the database binding module?
+ </p>
+ <p>
+ If you made your own customizations - have you forgotten to
+ install some dependency module? Please note
+ that dependency modules may have their own dependencies, etc,
+ and they should also be satisfied.
+ </p>
+ <p>
+ If you need further assistance, please email at
+ <a href="mailto:support@askbot.com">support@askbot.com</a>,
+ post your question at <a href="http://askbot.org/en/questions/">AskBot Support Forum</a>
+ or call at +1-301-747-1533 (US).
+ <p>
+ </body>
+</html>
diff --git a/askbot/templates/email/accept_answer_reminder.html b/askbot/templates/email/accept_answer_reminder.html
new file mode 100644
index 00000000..7b922cd4
--- /dev/null
+++ b/askbot/templates/email/accept_answer_reminder.html
@@ -0,0 +1,14 @@
+{% extends "email/base_mail.html"%}
+{%block title%}{{reminder_phrase}}{% endblock %}
+{%block headline%}{{reminder_phrase}}{% endblock %}
+
+{%block content %}
+<ul>
+ {% for question in questions %}
+ <li><a href="{{site_url}}{{question.get_absolute_url()}}?sort=latest">{{question.thread.title}}</a></li>
+ {% endfor %}
+</ul>
+{% endblock %}
+{%block footer %}
+{% include "email/footer.html" %}
+{% endblock %}
diff --git a/askbot/templates/email/ask_for_signature.html b/askbot/templates/email/ask_for_signature.html
new file mode 100644
index 00000000..ee4a1311
--- /dev/null
+++ b/askbot/templates/email/ask_for_signature.html
@@ -0,0 +1,19 @@
+{% extends "email/base_mail.html"%}
+{% import "email/macros.html" as macros %}
+{%block headline%}
+{% trans user=username|escape %}{{ user }}, please reply to this message.{% endtrans %}
+{% endblock %}
+
+{%block content %}
+<p>
+ {% trans %}Your post could not be published, because we could not detect signature in your email.{% endtrans %}<br/>
+ {% trans %}This happened either because this is your first post or you have changed your email signature.{% endtrans %}<br/>
+ {% trans %}Please make a simple response, without editing this message.{% endtrans %}<br/>
+ {% trans %}We will then attempt to detect the signature in your response and you should be able to post.{% endtrans %}
+</p>
+{% endblock %}
+
+{%block footer %}
+{% include "email/footer.html" %}
+<p style="{{ macros.fine_print_style() }}">{{ footer_code }}</p>
+{% endblock %}
diff --git a/askbot/templates/email/base_mail.html b/askbot/templates/email/base_mail.html
new file mode 100644
index 00000000..eacbf87d
--- /dev/null
+++ b/askbot/templates/email/base_mail.html
@@ -0,0 +1,183 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
+ <title>{% block title%}{%endblock%}</title>
+ <style type="text/css">
+ /* Based on The MailChimp Reset INLINE: Yes. */
+ /* Client-specific Styles */
+ #outlook a {padding:0;} /* Force Outlook to provide a "view in browser" menu link. */
+ body{width:100% !important; -webkit-text-size-adjust:100%; -ms-text-size-adjust:100%; margin:0; padding:0; font-family:arial, sans-serif;font-size:13px;}
+ /* Prevent Webkit and Windows Mobile platforms from changing default font sizes.*/
+ .ExternalClass {width:100%;} /* Force Hotmail to display emails at full width */
+ .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {line-height: 100%;}
+ /* Forces Hotmail to display normal line spacing. More on that: http://www.emailonacid.com/forum/viewthread/43/ */
+ #backgroundTable {margin:0; padding:0; width:100% !important; line-height: 100% !important;}
+ /* End reset */
+
+ /* Some sensible defaults for images
+ Bring inline: Yes. */
+ img {outline:none; text-decoration:none; -ms-interpolation-mode: bicubic;}
+ a img {border:none;}
+ .image_fix {display:block;}
+
+ /* Yahoo paragraph fix
+ Bring inline: Yes. */
+ p {margin: 1em 0;}
+
+ /* Hotmail header color reset
+ Bring inline: Yes. */
+ h1, h2, h3, h4, h5, h6 {color: black !important;}
+
+ h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {color: blue !important;}
+
+ h1 a:active, h2 a:active, h3 a:active, h4 a:active, h5 a:active, h6 a:active {
+ color: red !important; /* Preferably not the same color as the normal header link color. There is limited support for psuedo classes in email clients, this was added just for good measure. */
+ }
+
+ h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited {
+ color: purple !important; /* Preferably not the same color as the normal header link color. There is limited support for psuedo classes in email clients, this was added just for good measure. */
+ }
+
+ /* Outlook 07, 10 Padding issue fix
+ Bring inline: No.*/
+ table td {border-collapse: collapse;}
+
+ /* Remove spacing around Outlook 07, 10 tables
+ Bring inline: Yes */
+ table { border-collapse:collapse; mso-table-lspace:0pt; mso-table-rspace:0pt; }
+
+ /* Styling your links has become much simpler with the new Yahoo. In fact, it falls in line with the main credo of styling in email and make sure to bring your styles inline. Your link colors will be uniform across clients when brought inline.
+ Bring inline: Yes. */
+ a {color: orange;}
+
+
+ /***************************************************
+ ****************************************************
+ MOBILE TARGETING
+ ****************************************************
+ ***************************************************/
+ @media only screen and (max-device-width: 480px) {
+ /* Part one of controlling phone number linking for mobile. */
+ a[href^="tel"], a[href^="sms"] {
+ text-decoration: none;
+ color: blue; /* or whatever your want */
+ pointer-events: none;
+ cursor: default;
+ }
+
+ .mobile_link a[href^="tel"], .mobile_link a[href^="sms"] {
+ text-decoration: default;
+ color: orange !important;
+ pointer-events: auto;
+ cursor: default;
+ }
+
+ }
+
+ /* More Specific Targeting */
+
+ @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) {
+ /* You guessed it, ipad (tablets, smaller screens, etc) */
+ /* repeating for the ipad */
+ a[href^="tel"], a[href^="sms"] {
+ text-decoration: none;
+ color: blue; /* or whatever your want */
+ pointer-events: none;
+ cursor: default;
+ }
+
+ .mobile_link a[href^="tel"], .mobile_link a[href^="sms"] {
+ text-decoration: default;
+ color: orange !important;
+ pointer-events: auto;
+ cursor: default;
+ }
+ }
+
+ @media only screen and (-webkit-min-device-pixel-ratio: 2) {
+ /* Put your iPhone 4g styles in here */
+ }
+
+ /* Android targeting */
+ @media only screen and (-webkit-device-pixel-ratio:.75){
+ /* Put CSS for low density (ldpi) Android layouts in here */
+ }
+ @media only screen and (-webkit-device-pixel-ratio:1){
+ /* Put CSS for medium density (mdpi) Android layouts in here */
+ }
+ @media only screen and (-webkit-device-pixel-ratio:1.5){
+ /* Put CSS for high density (hdpi) Android layouts in here */
+ }
+ /* end Android targeting */
+ </style>
+
+ <!-- Targeting Windows Mobile -->
+ <!--[if IEMobile 7]>
+ <style type="text/css">
+
+ </style>
+ <![endif]-->
+
+ <!-- ***********************************************
+ ****************************************************
+ END MOBILE TARGETING
+ ****************************************************
+ ************************************************ -->
+
+ <!--[if gte mso 9]>
+ <style>
+ /* Target Outlook 2007 and 2010 */
+ </style>
+ <![endif]-->
+</head>
+<body>
+<table cellpadding="0" cellspacing="0" border="0" id="backgroundTable">
+ <tr>
+ <td>
+ <table border="0" align="center" cellspacing="0" cellpadding="0" style="background-color:#E7E8E8;">
+ <tr height="20">
+ <td valign="top">
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ <table border="0" align="center" cellspacing="0" cellpadding="0" style="background-color: #fff;" width=90%>
+ <tr>
+ <td valign="top">
+ <table border="0" align="center" cellspacing="0" cellpadding="0" width=95%>
+ <tr>
+ <td valign="top">
+ <h1>{%block headline%}{%endblock%}</h1>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top">
+ {%block content%}
+ {%endblock%}
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" class="footer">
+ <hr>
+ {%block footer%}
+ {%endblock%}
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr height="20">
+ <td valign="top">
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+</body>
+</html>
diff --git a/askbot/skins/default/templates/email/feedback_email.txt b/askbot/templates/email/feedback_email.txt
index a729066a..a729066a 100644
--- a/askbot/skins/default/templates/email/feedback_email.txt
+++ b/askbot/templates/email/feedback_email.txt
diff --git a/askbot/skins/default/templates/email/footer.html b/askbot/templates/email/footer.html
index eda1269d..eda1269d 100644
--- a/askbot/skins/default/templates/email/footer.html
+++ b/askbot/templates/email/footer.html
diff --git a/askbot/templates/email/instant_notification.html b/askbot/templates/email/instant_notification.html
new file mode 100644
index 00000000..d353450d
--- /dev/null
+++ b/askbot/templates/email/instant_notification.html
@@ -0,0 +1,18 @@
+{% extends "email/base_mail.html"%}
+
+{%block content %}
+{{ reply_separator }}
+<div>{{ content_preview }}</div>
+{% trans %}
+<p style="font-size:10px; font-style:italic;">
+Please note - you can easily <a href="{{user_subscriptions_url}}">change</a>
+how often you receive these notifications or unsubscribe. Thank you for your interest in our forum!</p>
+{% endtrans %}
+{%endblock%}
+
+{%block footer %}
+{% include "email/footer.html" %}
+{% if can_reply %}
+<p style="font-size:8px;color:#aaa">{{reply_address}}</p>
+{%endif%}
+{%endblock%}
diff --git a/askbot/templates/email/insufficient_rep_to_post_by_email.html b/askbot/templates/email/insufficient_rep_to_post_by_email.html
new file mode 100644
index 00000000..a7e88b3b
--- /dev/null
+++ b/askbot/templates/email/insufficient_rep_to_post_by_email.html
@@ -0,0 +1,20 @@
+{% extends "email/base_mail.html"%}
+{% import "email/macros.html" as macros %}
+{# parameters:
+ * min_upvotes
+ * username
+ * site_name - for the footer
+ * site_link - html for the link
+#}
+{%block headline%}
+ {% trans user=username|escape %}{{ username }}, your question could not be posted by email just yet.{% endtrans %}
+{%endblock%}
+{%block content%}
+<p>
+ {% trans %}To make posts by email, you need to receive about {{min_upvotes}} upvotes.{% endtrans %}<br/>
+ {% trans link=site_link|safe %}At this time, please post your question at {{link}}{% endtrans %}
+</p>
+{%endblock%}
+{%block footer}
+{% include "email/footer.html" %}
+{%endblock%}
diff --git a/askbot/templates/email/macros.html b/askbot/templates/email/macros.html
new file mode 100644
index 00000000..125705e2
--- /dev/null
+++ b/askbot/templates/email/macros.html
@@ -0,0 +1,96 @@
+{% macro quoted_post(
+ post = None,
+ quote_level = 0,
+ format = None,
+ is_leaf_post = False
+ )
+%}
+ {% spaceless %}
+ {{ start_quote(quote_level) }}
+ {% set author = post.author.username|escape %}
+ {% if post.post_type == 'question' %}
+ <p style="font-size:10px; font-weight: bold;">
+ {% if format == 'parent_subthread' %}
+ {% if is_leaf_post %}
+ {% trans %}Question by {{ author }}:{% endtrans %}
+ {% else %}
+ {% trans -%}
+ In reply to {{ author }}'s question:
+ {%- endtrans %}
+ {% endif %}
+ {% else %}
+ {% trans %}Question :{% endtrans %}
+ {% endif %}
+ {{ post.thread.title }}
+ </p>
+ <p style="font-size:10px; font-weight: bold;">
+ {% if format != 'parent_subthread' %}
+ {% trans %}Asked by {{ author }}:{% endtrans %}
+ {% endif %}
+ </p>
+ {% set tag_names = post.get_tag_names() %}
+ {% if tag_names %}
+ <p style="font-size:10px; font-style:italic;">
+ {% trans %}Tags:{% endtrans %}
+ {{ tag_names|join(', ') }}.
+ </p>
+ {% endif %}
+ {% elif post.post_type == 'answer' %}
+ <p style="font-size:10px; font-weight: bold;">
+ {% if format == 'parent_subthread' %}
+ {% if is_leaf_post %}
+ {% trans -%}
+ {{ author }}'s answer:
+ {%- endtrans %}
+ {% else %}
+ {% trans -%}
+ In reply to {{ author }}'s answer:
+ {%- endtrans %}
+ {% endif %}
+ {% else %}
+ {% trans %}Answered by {{ author }}:{% endtrans %}
+ {% endif %}
+ </p>
+ {% else %}
+ <p style="font-size:10px; font-weight: bold;">
+ {% if format == 'parent_subthread' %}
+ {% if is_leaf_post %}
+ {% trans -%}
+ {{ author }}'s comment:
+ {%- endtrans %}
+ {% else %}
+ {% trans -%}
+ In reply to {{ author }}'s comment:
+ {%- endtrans %}
+ {% endif %}
+ {% else %}
+ {% trans author -%}
+ Commented by {{ author }}:
+ {%- endtrans %}
+ {% endif %}
+ </p>
+ {% endif %}
+ {{ post.html }}
+ {{ end_quote(quote_level) }}
+ {% endspaceless %}
+{% endmacro %}
+
+{% macro start_quote(level = 0) %}
+ {% for number in range(level) %}
+ <div style="padding-left:5px; border-left: 2px solid #aaa;">
+ {% endfor %}
+{% endmacro %}
+
+{% macro end_quote(level = 0) %}
+ {% for number in range(level) %}
+ </div>
+ {% endfor %}
+{% endmacro %}
+
+{% macro heading_style() %}
+font-size:14px;font-weight:bold;margin-bottom:0px;
+{% endmacro %}
+
+{% macro fine_print_style() %}
+font-size:8px;color:#aaa;margin-bottom:0px;
+{% endmacro %}
diff --git a/askbot/templates/email/notify_admins_about_new_tags.html b/askbot/templates/email/notify_admins_about_new_tags.html
new file mode 100644
index 00000000..9aaaffc2
--- /dev/null
+++ b/askbot/templates/email/notify_admins_about_new_tags.html
@@ -0,0 +1,8 @@
+<p>Hello,</p>
+<p>Please have a look at these new tags {{tags|join(', ')}},
+created by {{user.username}}.</p>
+<p>If you decide not to use the tags, please reply to this email
+to the user<p>
+<p>Otherwise, please <a href="{{ thread_url }}">visit the question</a>
+and apply the tags</p>
+<p>Thank you.</p>
diff --git a/askbot/templates/email/notify_author_about_approved_post.html b/askbot/templates/email/notify_author_about_approved_post.html
new file mode 100644
index 00000000..24601775
--- /dev/null
+++ b/askbot/templates/email/notify_author_about_approved_post.html
@@ -0,0 +1,30 @@
+{% extends "email/base_mail.html"%}
+
+{#
+ parameters:
+ * reply_separator_line
+ * replace_content_address
+ * mailto_link_subject
+ * post
+ * reply_code (comma-separated list of emails to respond to this message)
+#}
+
+{%block content %}
+{{ reply_separator_line }}
+<p>{% trans
+ post_text = post.text|safe_urlquote,
+ subject = mailto_link_subject|safe_urlquote,
+ author_email_signature = author_email_signature|safe_urlquote
+%}If you would like to edit by email, please
+<a href="mailto:{{ replace_content_address }}?body={{ post_text }}{{ author_email_signature}}&subject={{ subject }}">click here</a>{% endtrans %}</p>
+<p>{% trans %}Below is a copy of your post:{% endtrans %}</p>
+{% if post.post_type == 'question' %}
+ <p style="font-size:16px">{{ post.thread.title }}</p>
+{% endif %}
+{{ post.html }}
+{% endblock %}
+
+{%block footer %}
+{% include "email/footer.html" %}
+<p style="{{ macros.fine_print_style() }}">{{ email_code }}</p>{# important #}
+{% endblock %}
diff --git a/askbot/templates/email/post_as_subthread.html b/askbot/templates/email/post_as_subthread.html
new file mode 100644
index 00000000..4a4bd047
--- /dev/null
+++ b/askbot/templates/email/post_as_subthread.html
@@ -0,0 +1,18 @@
+{% from "email/macros.html" import quoted_post %}
+
+{% if post.post_type in ('question', 'answer') %}
+ {{ quoted_post(post) }}
+ {% set comments = post.get_cached_comments() %}
+ {% if comments %}
+ <p>
+ {% trans count=comments|length -%}
+ {{ comment }} comment:
+ {%- pluralize -%}
+ {{ count }} comments:
+ {%- endtrans -%}
+ </p>
+ {% for comment in comments %}
+ {{ quoted_post(comment, quote_level = 1) }}
+ {% endfor %}
+ {% endif %}
+{% endif %}
diff --git a/askbot/skins/default/templates/email/quoted_post.html b/askbot/templates/email/quoted_post.html
index ecc20ad9..ecc20ad9 100644
--- a/askbot/skins/default/templates/email/quoted_post.html
+++ b/askbot/templates/email/quoted_post.html
diff --git a/askbot/templates/email/re_welcome_lamson_on.html b/askbot/templates/email/re_welcome_lamson_on.html
new file mode 100644
index 00000000..d2c7884c
--- /dev/null
+++ b/askbot/templates/email/re_welcome_lamson_on.html
@@ -0,0 +1,13 @@
+{% extends "email/base_mail.html"%}
+{% block headline %}{% trans %}Great, you are ready to use {{ site_name }}!{% endtrans %}{%endblock%}
+{% block title %}{% trans %}Great, you are ready to use {{ site_name }}!{% endtrans %}{%endblock%}
+
+{%block content %}
+<p>{% trans %}You can post questions by emailing them at {{ ask_address }}.{% endtrans %}</p>
+<p>{% trans %}When you receive update notifications, you will be able to respond to them, also by email.{% endtrans %}</p>
+<p>{% trans %}Of course, you can always visit the {{ site_name }} at <a href="{{ site_url }}">{{ site_url }}</a>{% endtrans %}</p>
+{%endblock%}
+
+{%block footer%}
+{% include "email/footer.html" %}
+{%endblock%}
diff --git a/askbot/templates/email/rejected_post.html b/askbot/templates/email/rejected_post.html
new file mode 100644
index 00000000..7106d37f
--- /dev/null
+++ b/askbot/templates/email/rejected_post.html
@@ -0,0 +1,12 @@
+{% extends "email/base_mail.html"%}
+{%block headline%}{% trans %} Your post was rejected. {% endtrans %}{%endblock%}
+{%block title%}{% trans %} Your post was rejected. {% endtrans %}{%endblock%}
+{%block content %}
+<p>{% trans %}Your post (copied in the end), was rejected for the following reason:{% endtrans %}</p>,
+<p>{{reject_reason|safe}}</p>
+<p>{% trans %}Here is your original post{% endtrans %}</p>
+<p>{{post|safe}}</p>
+{% endblock %}
+{%block footer %}
+{% include "email/footer.html" %}
+{% endblock %}
diff --git a/askbot/skins/default/templates/email/reply_by_email_error.html b/askbot/templates/email/reply_by_email_error.html
index 53648184..53648184 100644
--- a/askbot/skins/default/templates/email/reply_by_email_error.html
+++ b/askbot/templates/email/reply_by_email_error.html
diff --git a/askbot/templates/email/unanswered_question_reminder.html b/askbot/templates/email/unanswered_question_reminder.html
new file mode 100644
index 00000000..8eaa6f40
--- /dev/null
+++ b/askbot/templates/email/unanswered_question_reminder.html
@@ -0,0 +1,14 @@
+{% extends "email/base_mail.html"%}
+{%block title%}{{subject_line}}{% endblock %}
+{%block headline%}{{subject_line}}{% endblock %}
+
+{%block content %}
+<ul>
+ {% for question in questions %}
+ <li><a href="{{site_url}}{{question.get_absolute_url()}}?sort=latest">{{question.thread.title}}</a></li>
+ {% endfor %}
+</ul>
+{% endblock %}
+{%block footer %}
+{% include "email/footer.html" %}
+{% endblock %}
diff --git a/askbot/templates/email/welcome_lamson_off.html b/askbot/templates/email/welcome_lamson_off.html
new file mode 100644
index 00000000..c5c9384c
--- /dev/null
+++ b/askbot/templates/email/welcome_lamson_off.html
@@ -0,0 +1,15 @@
+{% extends "email/base_mail.html" %}
+{% import "email/macros.html" as macros %}
+{# site_name - is short name of the site, email_code - address portion
+of the reply email used for this message, we scan to the last appearance
+of the email code to detect the response signature that will appear under #}
+{%block title%} {% trans %}Welcome to {{ site_name }}!{% endtrans %} {%endblock%}
+{%block headline%} {% trans %}Welcome to {{ site_name }}!{% endtrans %} {%endblock%}
+{%block content%}
+<p>
+ {% trans %}We look forward to your Questions!{% endtrans %}
+</p>
+{%endblock%}
+{%block footer %}
+{% include "email/footer.html" %}
+{%endblock%}
diff --git a/askbot/templates/email/welcome_lamson_on.html b/askbot/templates/email/welcome_lamson_on.html
new file mode 100644
index 00000000..3e47f44f
--- /dev/null
+++ b/askbot/templates/email/welcome_lamson_on.html
@@ -0,0 +1,20 @@
+{% extends "email/base_mail.html"%}
+{% import "email/macros.html" as macros %}
+{%block title%}{% trans %}Welcome to {{ site_name }}!{% endtrans %}{% endblock %}
+{%block headline%}{% trans %}Welcome to {{ site_name }}!{% endtrans %}{% endblock %}
+
+{%block content %}
+{# site_name - is short name of the site, email_code - address portion
+of the reply email used for this message, we scan to the last appearance
+of the email code to detect the response signature that will appear under #}
+<p>
+ {% trans %}Important: <em>Please reply</em> to this message, without editing it. We need this to determine your email signature and that the email address is valid and was typed correctly.{% endtrans %}
+</p>
+<p>
+ {% trans %}Until we receive the response from you, you will not be able ask or answer questions on {{ site_name }} by email.{% endtrans %}
+</p>
+{% endblock %}
+{%block footer %}
+{% include "email/footer.html" %}
+<p style="{{ macros.fine_print_style() }}">{{ email_code }}</p>{# important #}
+{% endblock %}
diff --git a/askbot/templates/embed/ask_by_widget.html b/askbot/templates/embed/ask_by_widget.html
new file mode 100644
index 00000000..4cec5f6d
--- /dev/null
+++ b/askbot/templates/embed/ask_by_widget.html
@@ -0,0 +1,225 @@
+{% extends "widget_base.html" %}
+{% import "macros.html" as macros %}
+{% block forestyle %}
+ {% if editor_type == 'markdown' %}
+ <link rel="stylesheet" type="text/css" href="{{"/js/wmd/wmd.css"|media}}" />
+ {%else %}
+ <link href="{{'/bootstrap/css/bootstrap.css'|media}}" rel="stylesheet" type="text/css" />
+ {%endif%}
+ {% if settings.USE_LOCAL_FONTS %}
+ {% include "meta/fonts.html" %}
+ {% else %}
+ <link href='http://fonts.googleapis.com/css?family=Open+Sans+Condensed:400,700&amp;subset=latin,cyrillic-ext,latin-ext' rel='stylesheet' type='text/css' />
+ {% endif %}
+ <style type="text/css" media="screen">
+ body{
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ }
+ #editor {
+ display: block;
+ min-height: 200px;
+ width: 98%;
+ margin: 0;
+ border:none;
+ outline:none;
+ padding: 6px;
+ }
+ .wmd-container{
+ border: #CCE6EC 3px solid;
+ width: 100%;
+ margin-top: 20px;
+ }
+
+ #id_title{
+ {% if editor_type == 'markdown' %}
+ width: 100%;
+ {%else%}
+ padding: 0px 0 0 5px;
+ width: 99.2%;
+ {%endif%}
+ font-size: 130%;
+ border: #CCE6EC 3px solid;
+ max-width: 600px;
+ }
+
+ #id_title:focus {
+ outline: none;
+ box-shadow:none;
+ }
+
+ .title{
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ font-size: 25px;
+ margin-bottom: 10px;
+ }
+
+ #question-list {
+ height: auto;
+ z-index: 10000;
+ position: absolute;
+ border: 3px solid #CCE6EC;
+ border-top:none;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ background: #fff;
+ {% if editor_type == 'markdown' %}
+ width:97.4%;
+ {%else%}
+ width:90.8%;
+ {%endif%}
+ margin-top: -4.9px;
+ }
+
+ #question-list h2{
+ text-decoration: none;
+ margin: 0px;
+ font-size: 13px;
+ padding: 3px 0 3px 5px;
+ padding-bottom: 0;
+ border-top: #F0F0EC 1px solid;
+ min-height: 30px;
+ line-height: 30px;
+ font-weight: normal
+ }
+
+ #question-list h2:first-child{
+ border-top: none;
+ }
+
+ #question-list a{
+ color: #005580;
+ }
+
+ #question-list a:hover{
+ color: #005580;
+ text-decoration: underline;
+ }
+
+ #question-list a:visited{
+ color: #005580;
+ text-decoration: none;
+ }
+
+ #question-list span{
+ width: 28px;
+ height: 26px;
+ line-height: 26px;
+ text-align: center;
+ margin-right: 10px;
+ float: left;
+ display: block;
+ color: white;
+ background: #B8D0D5;
+ border-radius: 3px;
+ -ms-border-radius: 3px;
+ -moz-border-radius: 3px;
+ -webkit-border-radius: 3px;
+ -khtml-border-radius: 3px;
+ }
+ {% if editor_type == 'markdown' %}
+ #wmd-button-bar {
+ background: url({{"/js/wmd/images/editor-toolbar-background.png"|media}}) repeat-x bottom;
+ height: 30px;
+ border: 0;
+ display: block;
+ }
+ {% endif %}
+
+ #submit{
+ font-size: 130%;
+ margin-right: -6px;
+ float: right;
+ text-align: center;
+ text-decoration: none;
+ cursor: pointer;
+ color: #4A757F;
+ font-family: 'Open Sans Condensed', Arial, sans-serif;
+ text-shadow: 0px 1px 0px #C6D9DD;
+ -moz-text-shadow: 0px 1px 0px #c6d9dd;
+ -webkit-text-shadow: 0px 1px 0px #c6d9dd;
+ border-top: #EAF2F3 1px solid;
+ background-color: #D1E2E5;
+ background-repeat: no-repeat;
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#D1E2E5), color-stop(25%, #D1E2E5), to(#A9C2C7));
+ background-image: -webkit-linear-gradient(#D1E2E5, #D1E2E5 25%, #A9C2C7);
+ background-image: -moz-linear-gradient(top, #D1E2E5, #D1E2E5 25%, #A9C2C7);
+ background-image: -ms-linear-gradient(#D1E2E5, #D1E2E5 25%, #A9C2C7);
+ background-image: -o-linear-gradient(#D1E2E5, #D1E2E5 25%, #A9C2C7);
+ background-image: linear-gradient(#D1E2E5, #D1E2E5 25%, #A9C2C7);
+ border-radius: 4px;
+ -ms-border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -khtml-border-radius: 4px;
+ -webkit-box-shadow: 1px 1px 2px #636363;
+ -moz-box-shadow: 1px 1px 2px #636363;
+ box-shadow: 1px 1px 2px #636363;
+ width: 200px;
+ }
+
+ .field-errors{
+ font-size: 10px;
+ color: #ff0000;
+ height: 10px;
+ }
+ {{widget.inner_style}}
+ </style>
+{%endblock%}
+
+{%block body%}
+<div class="title">{{widget.title}}</div>
+<form action="." method="POST" accept-charset="utf-8">
+ {% csrf_token %}
+ <label>{%trans%}Please enter a descriptive title for your question{%endtrans%}</label>
+ <div class="input-title">
+ {{form.title}}
+ </div>
+ <div id='question-list'>
+ </div>
+ <div class="field-errors">
+ {% for error in form.title.errors %} {{error}} {%endfor%}
+ </div>
+{% if widget.include_text_field %}
+ {% if editor_type == 'markdown' %}
+ <div class="wmd-container">
+ <div id="wmd-button-bar" class="wmd-panel"></div>
+ {{ form.text }}{# this element is resizable and will be wrapped by js #}
+ </div>
+ {% else %}
+ <div class="wmd-container">
+ {{ form.media }}
+ {{ form.text }}
+ </div>
+ {% endif %}
+ <div class="field-errors">
+ {% for error in form.text.errors %} {{error}} {%endfor%}
+ </div>
+ {% endif %}
+ {% if form.ask_anonymously %}
+ <p>{{form.ask_anonymously.label_tag()}}: {{form.ask_anonymously}}</p>
+ {%endif%}
+ <input type="submit" value="Ask your question" id="submit" />
+</form>
+{%endblock%}
+{% block endjs %}
+<script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
+{% if editor_type == 'markdown' %}
+ <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script>
+ <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script>
+{% else %}
+ {% include "meta/tinymce_css.html" %}{# todo - maybe move to form media? #}
+{% endif %}
+
+<script type="text/javascript" src='{{"/js/live_search_new_thread.js"|media}}'></script>
+<script type="text/javascript" charset="utf-8">
+ var minSearchWordLength = {{settings.MIN_SEARCH_WORD_LENGTH}};
+ askbot['urls']['api_get_questions'] = '{% url api_get_questions %}';
+ askbot['urls']['upload'] = '{% url upload %}';
+ $(document).ready(function(){
+ $("#id_title").focus();
+ $("#id_title").addClass('questionTitleInput');
+ liveSearchNewThreadInit(true);
+ });
+</script>
+{% endblock %}
diff --git a/askbot/templates/embed/ask_widget_complete.html b/askbot/templates/embed/ask_widget_complete.html
new file mode 100644
index 00000000..580c1f94
--- /dev/null
+++ b/askbot/templates/embed/ask_widget_complete.html
@@ -0,0 +1,8 @@
+{% extends "widget_base.html" %}
+{% block forestyle %}
+{%endblock%}
+
+{%block body%}
+<a href="{{question_url}}" target="_blank" >Question posted</a>
+{%endblock%}
+
diff --git a/askbot/templates/embed/askbot_widget.css b/askbot/templates/embed/askbot_widget.css
new file mode 100755
index 00000000..9b0b5af2
--- /dev/null
+++ b/askbot/templates/embed/askbot_widget.css
@@ -0,0 +1,38 @@
+#{{variable_name}} {
+ visibility: hidden;
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ width:100%;
+ height:100%;
+ text-align:center;
+ z-index: 99999;
+}
+
+#{{variable_name}} div{
+ width:600px;
+ {%if widget.include_text_field%}
+ {% if editor_type == 'markdown' %}
+ height:520px;
+ {%else%}
+ height:520px;
+ {%endif%}
+ {%else%}
+ height:220px;
+ {%endif%}
+ margin: 100px auto;
+ background-color: #fff;
+ border:1px solid #000;
+ padding:15px;
+ padding-left: 10px;
+ text-align: right;
+}
+
+#{{variable_name}} a{
+ padding:5px;
+}
+
+#{{variable_name}} iframe{
+ width:600px;
+ height:500px;
+}
diff --git a/askbot/templates/embed/askbot_widget.js b/askbot/templates/embed/askbot_widget.js
new file mode 100755
index 00000000..8c358855
--- /dev/null
+++ b/askbot/templates/embed/askbot_widget.js
@@ -0,0 +1,74 @@
+var {{variable_name}} = {
+ element_id: "{{variable_name}}",
+ widgetToggle: function() {
+ element = document.getElementById({{variable_name}}.element_id);
+ element.style.visibility = (element.style.visibility == "visible") ? "hidden" : "visible";
+ if (element.style.visibility == "visible"){
+ $("#" + {{variable_name}}.element_id + " iframe").focus();
+ }
+ },
+ toHtml: function() {
+ var html = {{variable_name}}.createButton();
+ var link = document.createElement('link');
+ link.setAttribute("rel", "stylesheet");
+ link.setAttribute("href", 'http://{{host}}{%url render_ask_widget_css widget.id%}');
+
+ //creating the div
+ var motherDiv = document.createElement('div');
+ motherDiv.setAttribute("id", {{variable_name}}.element_id);
+ motherDiv.style.visibility = "hidden";
+
+ var containerDiv = document.createElement('div');
+ motherDiv.appendChild(containerDiv);
+
+ {%if widget.outer_style %}
+ outerStyle = document.createElement('style');
+ outerStyle.innerText = "{{widget.outer_style}}";
+ motherDiv.appendChild(outerStyle);
+ {%endif%}
+
+ var closeButton = document.createElement('a');
+ closeButton.setAttribute('href', '#');
+ closeButton.setAttribute('id', 'AskbotModalClose');
+ closeButton.setAttribute('onClick', '{{variable_name}}.widgetToggle();');
+ closeButton.innerHTML= 'Close';
+
+ containerDiv.appendChild(closeButton);
+
+ var iframe = document.createElement('iframe');
+ iframe.setAttribute('src', 'http://{{host}}{% url ask_by_widget widget.id %}');
+
+ containerDiv.appendChild(iframe);
+
+ var body = document.getElementsByTagName('body')[0];
+ if (body){
+ body.appendChild(link);
+ body.appendChild(motherDiv);
+ }
+ },
+ createButton: function() {
+ var label="{{widget.title}}"; //TODO: add to the model
+ var buttonDiv = document.createElement('div');
+ buttonDiv.setAttribute('id', "AskbotAskButton");
+
+ var closeButton = document.createElement('input');
+ closeButton.setAttribute('onClick', '{{variable_name}}.widgetToggle();');
+ closeButton.setAttribute('type', 'button');
+ closeButton.value = label;
+
+ buttonDiv.appendChild(closeButton);
+
+ return buttonDiv;
+ }
+};
+
+previous_function = window.onload;
+var onload_functions = function(){
+ if (previous_function){
+ previous_function();
+ }
+ {{variable_name}}.toHtml();
+}
+
+window.onload = onload_functions();
+document.write({{variable_name}}.createButton().outerHTML);
diff --git a/askbot/templates/embed/delete_widget.html b/askbot/templates/embed/delete_widget.html
new file mode 100644
index 00000000..ed80c537
--- /dev/null
+++ b/askbot/templates/embed/delete_widget.html
@@ -0,0 +1,14 @@
+{% extends "one_column_body.html" %}
+<!-- create_ask_widget.html -->
+{% block title %}Delete {{widget_name|capitalize}} Widget{% endblock %}
+{% block content %}
+<h1>Are you sure that you cant to delete this {{widget_name|capitalize}}Widget?</h1>
+<br/>
+<strong>Warning: This could break the widgets on sites that currently use this widget please make sure that you don't use the widget in other sites</strong>
+<form action="." method="POST">
+ <p><input type='submit' value='Delete' /> <a href="{% url list_widgets widget_name %}">Go Back</a></p>
+</form>
+{% endblock %}
+{% block endjs %}
+{% endblock %}
+
diff --git a/askbot/templates/embed/list_widgets.html b/askbot/templates/embed/list_widgets.html
new file mode 100644
index 00000000..83de5871
--- /dev/null
+++ b/askbot/templates/embed/list_widgets.html
@@ -0,0 +1,45 @@
+{% extends "two_column_body.html" %}
+<!-- create_ask_widget.html -->
+{% block title %}{{widget_name|capitalize}} widget list{% endblock %}
+{% block content %}
+ <h1>{{widget_name|capitalize}} widget list</h1>
+
+<table border="0">
+ <tr>
+ <th>Widget Title </th>
+ <th>Code</th>
+ <th>Actions</th>
+ </tr>
+ {% if widget_name == 'ask' %}
+ {%for widget in widgets%}
+ <tr>
+ <td>{{widget.title}}</td>
+ <td> &lt;script type="text/javascript" src="http://{{request.get_host()}}{% url render_ask_widget widget.id%}" &gt;&lt;/script&gt;</td>
+ <td><a href="{% url edit_widget widget_name, widget.id %}">Edit</a> | <a href="{% url delete_widget widget_name, widget.id %}">Delete</a></td>
+ </tr>
+ {%endfor%}
+ {%else%}
+ {%for widget in widgets%}
+ <tr>
+ <td>{{widget.title}}</td>
+ <td> &lt;iframe src="http://{{request.get_host()}}{% url question_widget widget.id%}" &gt; &lt;/iframe&gt;</td>
+ <td><a href="{% url edit_widget widget_name, widget.id %}">Edit</a> | <a href="{% url delete_widget widget_name, widget.id %}">Delete</a></td>
+ </tr>
+ {%endfor%}
+
+ {%endif%}
+</table>
+
+{% endblock %}
+{% block endjs %}
+{% endblock %}
+
+{% block sidebar %}
+<div class="box">
+ <h2>{% trans %}How to use?{% endtrans %}</h2>
+ <p>{% trans %}
+ Just copy the &lt;script&gt; tag provided and paste it in the site where you wan to put it.
+ {%endtrans%}
+ </p>
+ </div>
+{% endblock %}
diff --git a/askbot/templates/embed/question_widget.html b/askbot/templates/embed/question_widget.html
new file mode 100644
index 00000000..92e29aa0
--- /dev/null
+++ b/askbot/templates/embed/question_widget.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+<head>
+ <style type="text/css">
+ {{widget.style|safe}}
+ </style>
+</head>
+<body>
+ {{widget.title|safe}}
+ <div id="container">
+ <ul>
+ {% for thread in threads %}
+ <li><a href="{{settings.APP_URL|strip_path}}{{ thread.get_absolute_url() }}" target="_blank">
+ {{ thread.title|escape }}</a></li>
+ {% endfor %}
+ </ul>
+ </div>
+</body>
+</html>
diff --git a/askbot/templates/embed/widget_form.html b/askbot/templates/embed/widget_form.html
new file mode 100644
index 00000000..65128d8e
--- /dev/null
+++ b/askbot/templates/embed/widget_form.html
@@ -0,0 +1,23 @@
+{% extends "one_column_body.html" %}
+<!-- create_ask_widget.html -->
+{% block title %}{% trans %}{{action}} an {{widget_name}} widget{% endtrans %}{% endblock %}
+{% block content %}
+<h1 class="section-title">{% trans %}{{action}} an {{widget_name}} widget{% endtrans %}</h1>
+{#% if form.non_field_errors() %}
+ {{ form.non_field_errors() }}
+{% endif %#}
+<form method="post">
+ <table>
+ {{ form.as_table() }}
+ <tr>
+ <td colspan="2" style="text-align: center">
+ <input type="submit" class="submit" value={% trans %}Save{% endtrans %} />
+ </td>
+ </tr>
+ </table>
+</form>
+
+{% endblock %}
+{% block endjs %}
+{% endblock %}
+
diff --git a/askbot/templates/embed/widgets.html b/askbot/templates/embed/widgets.html
new file mode 100644
index 00000000..767ebc2c
--- /dev/null
+++ b/askbot/templates/embed/widgets.html
@@ -0,0 +1,36 @@
+{% extends "one_column_body.html" %}
+<!-- template badges.html -->
+{% block title %}{% spaceless %}{% trans %}Widgets{% endtrans %}{% endspaceless %}{% endblock %}
+{% block content %}
+<h1 class="section-title">{% trans %}Widgets{% endtrans %}</h1>
+<p>
+</p>
+<table>
+ <thead>
+ <th colspan="3">
+ {% trans %}Create and embed widgets into your sites, here a list of available widgets.{% endtrans %}
+ </th>
+ </thead>
+ <tbody>
+ <tr>
+ <td>{% trans %}Ask a question{% endtrans %}</td>
+ <td><a href="{% url create_widget 'ask' %}">{% trans %}create{% endtrans %}</a></td>
+ <td>
+ {% if ask_widgets > 0 %}
+ <a href="{% url list_widgets 'ask' %}">{% trans %}view list{% endtrans %}</a>
+ {% endif %}
+ </td>
+ </tr>
+ <tr>
+ <td>{% trans %}List of questions{% endtrans %}</td>
+ <td><a href="{% url create_widget 'question' %}">{% trans %}create{% endtrans %}</a></td>
+ <td>
+ {% if question_widgets > 0 %}
+ <a href="{% url list_widgets 'question' %}">{% trans %}view list{% endtrans %}</a>
+ {% endif %}
+ </td>
+ </tr>
+ </tbody>
+</table>
+{% endblock %}
+<!-- end template badges.html -->
diff --git a/askbot/skins/default/templates/faq_static.html b/askbot/templates/faq_static.html
index 0bc05cc8..0bc05cc8 100644
--- a/askbot/skins/default/templates/faq_static.html
+++ b/askbot/templates/faq_static.html
diff --git a/askbot/skins/default/templates/feedback.html b/askbot/templates/feedback.html
index 04b9a5b4..04b9a5b4 100644
--- a/askbot/skins/default/templates/feedback.html
+++ b/askbot/templates/feedback.html
diff --git a/askbot/templates/group_messaging/home.html b/askbot/templates/group_messaging/home.html
new file mode 100644
index 00000000..d5d34a37
--- /dev/null
+++ b/askbot/templates/group_messaging/home.html
@@ -0,0 +1,14 @@
+<div class="group-messaging"
+ data-create-thread-url="{% url create_thread %}"
+ data-get-threads-url="{% url get_threads %}"
+ data-reply-url="{% url post_reply %}"
+>
+ <div class="first-col">
+ <button class="submit compose">{% trans %}compose{% endtrans %}</button>
+ {% include "group_messaging/senders_list.html" %}
+ </div>
+ <div class="second-col">
+ {% include "group_messaging/threads_list.html" %}
+ </div>
+ <div class="clear-fix"></div>
+</div>
diff --git a/askbot/templates/group_messaging/macros.html b/askbot/templates/group_messaging/macros.html
new file mode 100644
index 00000000..7fbe4434
--- /dev/null
+++ b/askbot/templates/group_messaging/macros.html
@@ -0,0 +1,16 @@
+{%- macro message(post, visitor) -%}
+<div class="message" data-message-id="{{ post.id }}">
+ <p class="header">
+ {% if post.sender == visitor %}
+ {% trans date=post.sent_at %}You wrote on {{ date }}:{% endtrans %}
+ {% else %}
+ {% trans user=post.sender.username,
+ date=post.sent_at
+ %}{{ user }} wrote on {{ date }}:{% endtrans %}
+ {% endif %}
+ </p>
+ <div class="content">
+ {{ post.html|safe }}
+ </div>
+</div>
+{%- endmacro -%}
diff --git a/askbot/templates/group_messaging/senders_list.html b/askbot/templates/group_messaging/senders_list.html
new file mode 100644
index 00000000..687cacd6
--- /dev/null
+++ b/askbot/templates/group_messaging/senders_list.html
@@ -0,0 +1,14 @@
+{#<ul class="mailboxes">
+ <li><a class="inbox selected">{% trans %}Inbox{% endtrans %}</a></li>
+ <li><a class="sent">{% trans %}Sent{% endtrans %}</a></li>
+ <li><a class="trash">{% trans %}Trash{% endtrans %}</a></li>
+</ul>#}
+{% if senders %}
+<ul class="senders-list">
+ <li>{% trans %}Messages by sender:{% endtrans %}</li>
+ <li><a class="selected" data-sender-id="-1">{% trans %}all users{% endtrans %}</a></li>
+ {% for sender in senders %}
+ <li><a data-sender-id="{{ sender.id }}">{{ sender.username|escape }}</a></li>
+ {% endfor %}
+</ul>
+{% endif %}
diff --git a/askbot/templates/group_messaging/stored_message.html b/askbot/templates/group_messaging/stored_message.html
new file mode 100644
index 00000000..1bf31368
--- /dev/null
+++ b/askbot/templates/group_messaging/stored_message.html
@@ -0,0 +1,2 @@
+{% from "group_messaging/macros.html" import message %}
+{{ message(post, user) }}
diff --git a/askbot/templates/group_messaging/thread_details.html b/askbot/templates/group_messaging/thread_details.html
new file mode 100644
index 00000000..969479d8
--- /dev/null
+++ b/askbot/templates/group_messaging/thread_details.html
@@ -0,0 +1,7 @@
+{% from "group_messaging/macros.html" import message %}
+<ul class="thread" data-thread-id="{{ root_message.id }}">
+ <li>{{ message(root_message, request.user) }}</li>
+ {% for response in responses %}
+ <li>{{ message(response, request.user) }}</li>
+ {% endfor %}
+</ul>
diff --git a/askbot/templates/group_messaging/threads_list.html b/askbot/templates/group_messaging/threads_list.html
new file mode 100644
index 00000000..8469198c
--- /dev/null
+++ b/askbot/templates/group_messaging/threads_list.html
@@ -0,0 +1,18 @@
+<table class="threads-list">
+{% if threads %}
+ {% for thread in threads %}
+ {% set thread_data = threads_data[thread.id] %}
+ <tr class="thread-heading {{ thread_data['status'] }}"
+ data-thread-id="{{ thread.id }}"
+ >
+ <td class="senders">{{ thread_data['senders_info']|escape }}</td>
+ <td class="subject">{{ thread.headline|escape }}</td>
+ <td class="timestamp">{{ thread.last_active_at|timesince }}</td>
+ </tr>
+ {% endfor %}
+{% else %}
+ <tr>
+ <td class="empty" colspan="3">{% trans %}there are no messages yet...{% endtrans %}<td>
+ </tr>
+{% endif %}
+</table>
diff --git a/askbot/templates/groups.html b/askbot/templates/groups.html
new file mode 100644
index 00000000..9c7dac3c
--- /dev/null
+++ b/askbot/templates/groups.html
@@ -0,0 +1,58 @@
+{% import "macros.html" as macros %}
+{% extends 'two_column_body.html' %}
+{% block title %}{% trans %}Groups{% endtrans %}{% endblock %}
+{% block content %}
+ <div id="content-header">
+ <h1 class="section-title">{% trans %}Groups{% endtrans %}</h1>
+ {% if request.user.is_authenticated() %}
+ <div class="tabBar">
+ <div class="tabsC">
+ <a id="all-groups" class="first{% if tab_name=="all-groups" %} on{% endif %}"
+ title="{% trans %}All groups{% endtrans %}"
+ href="{% url groups %}?sort=all-groups"
+ ><span>{% trans %}all groups{% endtrans %}</span></a>
+ <a id="my-groups" {% if tab_name=="my-groups" %}class="on"{% endif %}
+ title="{% trans %}My groups{% endtrans %}"
+ href="{% url groups %}?sort=my-groups"
+ ><span>{% trans %}my groups{% endtrans %}</span></a>
+ </div>
+ </div>
+ {% endif %}
+ <div class="clearfix"></div>
+ </div>
+ {% if user_can_add_groups %}
+ <p id="group-add-tip">
+ {% trans %}Tip: to create a new group - please go to some user profile and add the new group there. That user will be the first member of the group{% endtrans %}
+ </p>
+ {% endif %}
+ <table id="groups-list">
+ <thead>
+ <th>{% trans %}Group{% endtrans %}</th>
+ <th>{% trans %}Number of members{% endtrans %}</th>
+ <th>{% trans %}Description{% endtrans %}</th>
+ </thead>
+ <tbody>
+ {% for group in groups %}
+ <tr>
+ {{ macros.user_group(
+ group, groups_membership_info[group.id], show_count=True
+ )
+ }}
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+{% endblock %}
+{% block endjs %}
+ <script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
+ <script src='{{"/js/post.js"|media}}' type='text/javascript'></script>
+ {% if request.user.is_authenticated() %}
+ <script type="text/javascript">
+ askbot['urls']['join_or_leave_group'] = '{% url join_or_leave_group %}';
+ $.each($('.group-join-btn'), function(idx, elem){
+ var group_join_btn = new GroupJoinButton();
+ group_join_btn.decorate($(elem));
+ });
+ </script>
+ {% endif %}
+{% endblock %}
diff --git a/askbot/templates/help.html b/askbot/templates/help.html
new file mode 100644
index 00000000..6fdecd51
--- /dev/null
+++ b/askbot/templates/help.html
@@ -0,0 +1,57 @@
+{% extends "two_column_body.html" %}
+{% block title %}{% trans %}Help{% endtrans %}{% endblock %}
+{% block content %}
+<h1 class='section-title'>{% trans %}Help{% endtrans %}</h1>
+<p>
+ {% if request.user.is_authenticated() %}
+ {% trans username = request.user.username|escape %}Welcome {{username}},{% endtrans %}
+ {% else %}
+ {% trans %}Welcome,{% endtrans %}
+ {% endif %}
+</p>
+<p>
+ {% trans %}Thank you for using {{app_name}}, here is how it works.{% endtrans %}
+</p>
+<a name="content"></a>
+<h2>{% trans %}How questions, answers and comments work{% endtrans %}</h2>
+<p>
+ {% trans %}This site is for asking and answering questions, not for open-ended discussions.{% endtrans %}
+ {% trans %}We encourage everyone to use “question†space for asking and “answer†for answering.{% endtrans %}
+</p>
+<p>
+ {% trans %}Despite that, each question and answer can be commented –
+ the comments are good for the limited discussions.{% endtrans %}
+</p>
+<a name="search"></a>
+<h2>{% trans %}Please search before asking your questions{% endtrans %}</h2>
+<p>{% trans %}Type your question in the search bar and see whether a similar question has been asked before{% endtrans %}.
+</p>
+<p>{% trans %}Search has advanced capabilities:{% endtrans %}</p>
+<ul>
+ <li>{% trans %}to search in title - enter [title: your text]{% endtrans %}</li>
+ <li>{% trans %}to search by tags - enter [tag: sometag] or #sometag{% endtrans %}</li>
+ <li>{% trans %}to search by user - enter [user: somename] or @somename or @"some name"{% endtrans %}</li>
+</ul>
+<p>{% trans %}In addition, it is possible to click on tags to add them to the search query.{% endtrans %}
+{% if settings.TAG_SEARCH_INPUT_ENABLED %}
+ {% trans %}Finally, a separate tag search box is available in the side bar of the main page, where the search tags can be entered as well{% endtrans %}
+{% endif %}
+</p>
+<p>{% trans %}<em>Important!!!</em> All search terms are combined with a logical "AND" expression - to narrow the search by adding new terms.{% endtrans %}</p>
+<a name="voting"></a>
+<h2>{% trans %}Voting{% endtrans %}</h2>
+<p>
+ {% trans %}Voting in {{app_name}} helps to select best answers and thank most helpful users.{% endtrans %}
+</p>
+<p>
+ {% trans %}Please vote when you find helpful information,
+ it really helps the {{app_name}} community.{% endtrans %}
+</p>
+<a name="other"></a>
+<h2>{% trans %}Other topics{% endtrans %}</h2>
+<p>
+ {% trans %}You can @mention users anywhere in the text to point their attention,
+ follow users and conversations and report inappropriate content by flagging it.{% endtrans %}
+</p>
+<p>{% trans %}Enjoy.{% endtrans %}</p>
+{% endblock %}
diff --git a/askbot/skins/default/templates/import_data.html b/askbot/templates/import_data.html
index affeaa73..affeaa73 100644
--- a/askbot/skins/default/templates/import_data.html
+++ b/askbot/templates/import_data.html
diff --git a/askbot/templates/list_suggested_tags.html b/askbot/templates/list_suggested_tags.html
new file mode 100644
index 00000000..4eeb0004
--- /dev/null
+++ b/askbot/templates/list_suggested_tags.html
@@ -0,0 +1,67 @@
+{% extends "two_column_body.html" %}
+{% import "macros.html" as macros %}
+<!-- tags.html -->
+{% block title %}{{ page_title }}{% endblock %}
+{% block content %}
+ {% include "tags/header.html" %}
+ {% if tags %}
+ <table class="suggested-tags-table">
+ <thead>
+ <tr>
+ <th class="tags-col">{% trans %}Tag{% endtrans %}</th>
+ <th class="users-col">{% trans %}Suggested by{% endtrans %}</th>
+ <th class="decision-col">{% trans %}Your decision{% endtrans %}</th>
+ <th>{% trans %}Suggested tag was used for questions{% endtrans %}</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for tag in tags %}
+ <tr class="suggested-tag-row" data-tag-id="{{ tag.id }}">
+ <td class="tags-col">
+ {{ macros.tag_widget(tag.name, is_link = False) }}
+ <span class="tag-number">&#215;{{ tag.used_count }}</span>
+ </td>
+ <td class="users-col">
+ {% for user in tag.suggested_by.all() %}
+ <p>{{ user.get_profile_link() }}</p>
+ {% endfor %}
+ </td>
+ <td colspan="2">
+ <table>{# inner table for the list of questions #}
+ {% for thread in tag.threads.all() %}
+ <tr class="thread-info" data-thread-id="{{ thread.id }}">
+ <td class="per-thread-controls">
+ <button class="btn accept">{% trans %}Accept{% endtrans %}</button>
+ <button class="btn reject">{% trans %}Reject{% endtrans %}</button>
+ </td>
+ <td class="thread-links-col">
+ <a title="{{ thread._question_post().summary|escape }}"
+ href="{{ thread.get_absolute_url() }}"
+ >{{ thread.title|escape }}</a>
+ </td>
+ </tr>
+ {% endfor %}
+ </table>
+ </td>
+ </tr>
+ <tr class="per-tag-controls" data-tag-id="{{ tag.id }}">
+ <td colspan="4">
+ {% if tag.threads.count() > 1 %}
+ <button class="btn accept">{% trans name=tag.name %}Apply tag "{{ name }}" to all above questions{% endtrans %}</button>
+ <button class="btn reject">{% trans %}Reject tag{% endtrans %}</button>
+ {% endif %}
+ </td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ {% else %}
+ <span>{% trans %}Nothing found{% endtrans %}</span>
+ {% endif %}
+{% endblock %}
+{% block endjs %}
+ <script type="text/javascript">
+ askbot['urls']['moderateSuggestedTag'] = '{% url "moderate_suggested_tag" %}';
+ </script>
+ <script type="text/javascript" src="{{ '/js/tag_moderation.js'|media }}"></script>
+{% endblock %}
diff --git a/askbot/templates/macros.html b/askbot/templates/macros.html
new file mode 100644
index 00000000..8e578dec
--- /dev/null
+++ b/askbot/templates/macros.html
@@ -0,0 +1,782 @@
+{% load extra_filters_jinja %}
+
+{%- macro share(site = None, site_label = None, icon = False) -%}
+ <a class="{{ site }}-share{% if icon == True %} icon{% endif %}"
+ title="{% trans %}Share this question on {{site}}{% endtrans %}"
+ >{% if icon == False %}{% if site_label %}{{ site_label }}{% else %}{{ site }}{% endif %}{% endif %}</a>
+{%- endmacro -%}
+
+{%- macro inbox_post_snippet(response, inbox_section) -%}
+<div id="re_{{response.id}}" class="re{% if response.is_new %} new highlight{% else %} seen{% endif %}">
+ <input type="checkbox" />
+ <div class="face">
+ {{ gravatar(response.user, 48) }}
+ </div>
+ <a style="font-size:12px" href="{{ response.user.get_absolute_url() }}">{{ response.user.username|escape }}</a>
+ <a style="text-decoration:none;" href="{{ response.response_url }}">
+ {{ response.response_type }}
+ ({{ timeago(response.timestamp) }}):<br/>
+ {% if inbox_section != 'flags' %}
+ {{ response.response_snippet }}
+ {% endif %}
+ </a>
+ {% if inbox_section == 'flags' %}
+ <a class="re_expand" href="{{ response.response_url }}">
+ <!--div class="re_snippet">{{ response.response_snippet|escape }}</div-->
+ <div class="re_content">{{ response.response_content }}</div>
+ </a>
+ {% endif %}
+</div>
+{%- endmacro -%}
+
+{%- macro post_vote_buttons(post = None) -%}
+<div id="{{post.post_type}}-img-upvote-{{ post.id }}"
+ class="{{post.post_type}}-img-upvote post-vote">
+</div>
+<div
+ id="{{post.post_type}}-vote-number-{{ post.id }}"
+ class="vote-number"
+ title="{% trans %}current number of votes{% endtrans %}"
+>{{ post.score }}</div>
+<div
+ id="{{post.post_type}}-img-downvote-{{ post.id }}"
+ class="{{post.post_type}}-img-downvote post-vote">
+</div>
+<script type="text/javascript">
+ askbot['functions']['renderPostVoteButtons']('{{post.post_type}}', '{{post.id}}');
+</script>
+{%- endmacro -%}
+
+{%- macro post_contributor_avatar_and_credentials(post, user, karma_mode = None, badges_mode = None) -%}
+ {% if post.is_anonymous %}
+ <img alt="{% trans %}anonymous user{% endtrans %}" src="{{ '/images/anon.png'|media }} " class="gravatar" width="32" height="32" />
+ <p>{{ user.get_anonymous_name() }}</p>
+ {% else %}
+ {{ gravatar(user, 32) }}
+ {{ user.get_profile_link()}}{{ user_country_flag(user) }}<br/>
+ {{ user_score_and_badge_summary(user, karma_mode = karma_mode, badges_mode = badges_mode) }}<br/>
+ {{ user_website_link(user) }}
+ {% endif %}
+ {{ user_primary_group(user) }}
+{%- endmacro -%}
+
+{%- macro post_last_updater_and_creator_info(
+ post, min_rep_to_edit_wiki, karma_mode = None, badges_mode = None
+ ) -%}
+ {{ post_contributor_info(
+ post, "original_author", post.wiki, min_rep_to_edit_wiki,
+ karma_mode = karma_mode, badges_mode = badges_mode
+ )
+ }}
+ {{ post_contributor_info(
+ post, "last_updater", post.wiki, min_rep_to_edit_wiki,
+ karma_mode = karma_mode, badges_mode = badges_mode
+ )
+ }}
+{%- endmacro -%}
+
+{%- macro post_contributor_info(
+ post, contributor_type, is_wiki, wiki_min_rep,
+ karma_mode = None, badges_mode = None
+ ) -%}
+{# there is a whole bunch of trickery here, probably indicative of
+poor design of the data or methods on data objects #}
+{% if contributor_type=="original_author" %}
+ <div class='post-update-info'>
+ {% if is_wiki %}
+ <p>
+ {%- if post.post_type == 'question' -%}
+ {%- trans %}asked{% endtrans %}
+ {% elif post.post_type == 'answer' %}
+ {%- trans %}answered{% endtrans %}
+ {% else %}
+ {%- trans %}posted{% endtrans %}
+ {% endif %}
+ <strong>{{ timeago(post.added_at) }}</strong>
+ </p>
+ <img width="35" height="35"
+ src="{{'/images/wiki.png'|media}}"
+ alt="{% trans %}this post is marked as community wiki{% endtrans %}"
+ style="float:left"
+ />
+ <p class="tip">{% trans %}This post is a wiki.
+ Anyone with karma &gt;{{wiki_min_rep}} is welcome to improve it.{% endtrans %}</p>
+ {% else %}
+ <p style="line-height:12px;">
+ {# todo: access to class names needs to be removed here #}
+ {% if post.post_type == 'question' %}
+ {% trans %}asked{% endtrans %}
+ {% elif post.post_type == 'answer' %}
+ {% trans %}answered{% endtrans %}
+ {% else %}
+ {% trans %}posted{% endtrans %}
+ {% endif %}
+ {% if post.__class__.__name__ == 'PostRevision' %}
+ <strong>{{ timeago(post.revised_at) }}</strong>
+ {% else %}
+ <strong>{{ timeago(post.added_at) }}</strong>
+ {% endif %}
+ </p>
+ {{ post_contributor_avatar_and_credentials(
+ post, post.author, karma_mode = karma_mode, badges_mode = badges_mode
+ ) }}
+ {% endif %}
+ </div>
+{% elif contributor_type=="last_updater" %}
+ {% if post.post_type in ('question', 'answer') %}
+ {% set last_edited_at = post.last_edited_at %}
+ {% set original_author = post.author %}
+ {% set update_author = post.last_edited_by %}
+ {% elif post.__class__.__name__ == 'PostRevision' %}
+ {% set last_edited_at = post.revised_at %}
+ {% set original_author = None %}{# fake value to force display widget in the revision views #}
+ {% set update_author = post.author %}
+ {% endif %}
+ {% if last_edited_at %}
+ <div class='post-update-info'>
+ <p style="line-height:12px;">
+ <a
+ {% if post.post_type == 'question' %}
+ href="{% url question_revisions post.id %}"
+ {% else %}
+ href="{% url answer_revisions post.id %}"
+ {% endif %}
+ >{% trans %}updated{% endtrans %} <strong>{{ timeago(last_edited_at) }}</strong></a>
+ </p>
+ {% if original_author != update_author or is_wiki %}
+ {{
+ post_contributor_avatar_and_credentials(
+ post, update_author,
+ karma_mode = karma_mode, badges_mode = badges_mode
+ )
+ }}
+ {% endif %}
+ </div>
+ {% endif %}
+{% endif %}
+{%- endmacro -%}
+
+{%- macro if_else(condition, if_true, if_false) -%}
+ {%- if condition == True -%}
+ {{if_true}}
+ {%- else -%}
+ {{if_false}}
+ {%- endif -%}
+{%- endmacro -%}
+
+{%- macro tag_cloud(tags = None, font_sizes = None, search_state = None) -%}
+ {% for tag in tags %}
+ <span class="tag-size-{{ font_sizes[tag.name] }}">
+ <a
+ class="link-typeA"
+ title="Number of entries: {{ tag.used_count }}"
+ href="{{ search_state.add_tag(tag.name).full_url() }}"
+ >{{ tag.name }}</a>
+ </span>
+ {% endfor %}
+{%- endmacro -%}
+
+{%- macro tag_list_widget(
+ tags,
+ id = None,
+ deletable = False,
+ make_links = True,
+ search_state = None,
+ css_class = None,
+ tag_css_class = None,
+ tag_html_tag = 'li',
+ truncate_long_tags = False
+ )
+-%}
+<ul {% if id %}id="{{ id }}"{% endif %}
+ class="tags{% if css_class %} {{css_class}}{% endif %}"
+>
+ {% if tags %}
+ {% for tag in tags %}
+ {{ tag_widget(
+ tag,
+ css_class = tag_css_class,
+ deletable = deletable,
+ is_link = make_links,
+ search_state = search_state,
+ html_tag = tag_html_tag,
+ truncate_long_tag = False
+ )}}
+ {% endfor %}
+ {% endif %}
+</ul>
+{%- endmacro -%}
+
+{%- macro user_group_link(group) -%}
+ <a class="group-name"
+ href="{% url users_by_group group.id, group.name|replace('-', ' ')|slugify %}"
+ >{{ group.name|escape }}</a>
+{%- endmacro -%}
+
+{%- macro user_group(group, membership_info, show_count=False) -%}
+ <td>
+ {{ user_group_link(group) }}
+ </td>
+ {% if show_count %}
+ <td>{{ group.users_count }}</td>
+ {% endif %}
+ <td>
+ <span class="group-description">
+ {% if group.description %}
+ {{ group.description.summary }}
+ {% endif %}
+ </span>
+ {% if membership_info %}
+ <br/>
+ {{ group_join_button(
+ group_id = group.id,
+ acceptance_level = membership_info['aceptance_level'],
+ membership_level = membership_info['membership_level']
+ )
+ }}
+ {% endif %}
+ </td>
+{%- endmacro -%}
+
+{%- macro user_primary_group(user) -%}
+ {% set group=user.get_primary_group() %}
+ {% if group %}
+ <span class="primary-group-name"><a
+ class="primary-group-name"
+ href="{% url users_by_group group.id, group.name|replace('-', ' ')|slugify %}"
+ >{{ group.name|replace('-', ' ')|escape }}</a></span>
+ {% endif %}
+{%- endmacro -%}
+
+{%- macro group_join_button(
+ group_id=None, acceptance_level='closed', membership_level='none')
+-%}
+ {% if acceptance_level in ('open', 'moderated') %}
+ <button
+ class="group-join-btn follow-toggle {% if membership_level != 'none' %}on on-state{% endif %}"
+ data-group-id="{{group_id}}"
+ {% if acceptance_level == 'open' %}
+ data-off-prompt-text="{% trans %}Leave this group{% endtrans %}"
+ data-on-prompt-text="{% trans %}Join this group{% endtrans %}"
+ data-on-state-text="{% trans %}You are a member{% endtrans %}"
+ data-off-state-text="{% trans %}Join this group{% endtrans %}"
+ {% else %}
+ {% if membership_level == 'full' %}
+ data-off-prompt-text="{% trans %}Leave this group{% endtrans %}"
+ data-on-state-text="{% trans %}You are a member{% endtrans %}"
+ {% else %}
+ data-off-prompt-text="{% trans %}Cancel application{% endtrans %}"
+ data-on-state-text="{% trans %}Waiting approval{% endtrans %}"
+ {% endif %}
+ data-on-prompt-text="{% trans %}Ask to join{% endtrans %}"
+ data-off-state-text="{% trans %}Ask to join{% endtrans %}"
+ {% endif %}
+ >
+ {% if membership_level == 'full' %}
+ {% trans %}You are a member{% endtrans %}
+ {% elif membership_level == 'pending' %}
+ {% trans %}Waiting approval{% endtrans %}
+ {% else %}
+ {% if acceptance_level == 'open' %}
+ {% trans %}Join this group{% endtrans %}
+ {% else %}
+ {% trans %}Ask to join{% endtrans %}
+ {% endif %}
+ {% endif %}
+ </button>
+ {% endif %}
+{%- endmacro -%}
+
+{# todo: remove the extra content argument to make its usage more explicit #}
+{%- macro tag_widget(
+ tag,
+ deletable = False,
+ is_link = True,
+ delete_link_title = None,
+ css_class = None,
+ search_state = None,
+ html_tag = 'div',
+ extra_content = '',
+ truncate_long_tag = False
+ )
+-%}
+ {% if not search_state %} {# get empty SearchState() if there's none; CAUTION: for some reason this doesn't work inside `spaceless` tag below! #}
+ {% set search_state=search_state|get_empty_search_state %}
+ {% endif %}
+ {% spaceless %}
+ <{{ html_tag }} class="tag-left{% if deletable %} deletable-tag{% endif %}">
+ <{% if not is_link or tag[-1] == '*' %}span{% else %}a{% endif %}
+ class="tag tag-right{% if css_class %} {{ css_class }}{% endif %}"
+ {% if is_link %}
+ href="{{ search_state.add_tag(tag).full_url() }}"
+ title="{% trans tag=tag|escape %}see questions tagged '{{ tag }}'{% endtrans %}"
+ {% endif %}
+ rel="tag"
+ data-tag-name="{{ tag|replace('*', '&#10045;')|escape }}"
+ >{% if truncate_long_tag -%}
+ {{ tag|replace('*', '&#10045;')|truncate(17, True)|escape }}
+ {%- else -%}
+ {{ tag|replace('*', '&#10045;')|escape }}
+ {%- endif %}</{% if not is_link or tag[-1] == '*' %}span{% else %}a{% endif %}>
+ {% if deletable %}
+ <div class="delete-icon"
+ {% if delete_link_title %}
+ title="{{ delete_link_title }}"
+ {% endif %}
+ >x</div>
+ {% endif %}
+ </{{ html_tag }}>
+ {{ extra_content }}
+ {% endspaceless %}
+{%- endmacro -%}
+
+{%- macro radio_select(name = None, value = None, choices = None) -%}
+ {% for choice in choices %}
+ <p class="choice">
+ {% set id = "id_" ~ name ~ "_" ~ choice[0] %}
+ <input
+ id="{{ id }}"
+ name="{{ name }}"
+ value="{{ choice[0] }}"
+ type="radio"
+ {% if value == choice[0] %}
+ checked="checked"
+ {% endif %}
+ />
+ <label for="{{ id }}">{{ choice[1] }}</label>
+ </p>
+ {% endfor %}
+{%- endmacro -%}
+
+{%- macro question_summary(thread, question, extra_class=None, search_state=None, visitor = None) -%}
+{%include "widgets/question_summary.html" %}
+{%- endmacro -%}
+
+{# Warning! Any changes to the comment markup here must be duplicated in post.js
+for the purposes of the AJAX comment editor #}
+
+{%- macro add_or_show_comments_button(post = None, max_comments = None, widget_id = None) -%}
+ {% if post.comment_count > max_comments %}
+ {% set remaining_comment_count = post.comment_count - max_comments %}
+ {% else %}
+ {% set remaining_comment_count = 0 %}
+ {% endif %}
+ <a id="add-comment-to-post-{{post.id}}" class="button"></a>
+ <script type="text/javascript">
+ askbot['data']['{{widget_id}}'] = {
+ truncated: {% if post.comment_count > max_comments %}true{% else %}false{% endif %}
+ };
+ askbot['functions']['renderAddCommentButton'](
+ '{{post.id}}',
+ {{remaining_comment_count}}
+ );
+ </script>
+{%- endmacro -%}
+
+{%- macro post_comments_widget(
+ post=None,
+ show_post = None,
+ show_comment = None,
+ show_comment_position = None,
+ user=None,
+ max_comments=None
+ )
+-%}
+ {% spaceless %}
+ {% if post.comment_count > 0 %}
+ <h2 id="comment-title">Comments</h2>
+ <div class="clean"></div>
+ {% endif %}
+ {% set widget_id = 'comments-for-' + post.post_type + '-' + post.id|string %}
+ <div class="comments" id="{{widget_id}}">
+ <div class="content">
+ {% if show_post == post and show_comment and show_comment_position > max_comments %}
+ {% set comments = post.get_cached_comments()[:show_comment_position] %}
+ {% else %}
+ {% set comments = post.get_cached_comments()[:max_comments] %}
+ {% endif %}
+ {% for comment in comments %}
+ {# Warning! Any changes to the comment markup IN THIS `FOR` LOOP must be duplicated in post.js
+ for the purposes of the AJAX comment editor #}
+ <div class="comment" id="comment-{{comment.id}}">
+ <div class="comment-votes">
+ {% if comment.score > 0 %}
+ <div
+ id="comment-img-upvote-{{comment.id}}"
+ class="upvote"
+ >{{comment.score}}</div>
+ <script type="text/javascript">
+ askbot['functions']['renderPostVoteButtons']('comment', '{{comment.id}}');
+ </script>
+ {% else %}
+ <div class="upvote"></div>
+ {% endif %}
+ </div>
+ <div
+ id="post-{{comment.id}}-delete"
+ class="comment-delete"
+ >
+ <span class="delete-icon" title="{% trans %}delete this comment{% endtrans %}"></span>
+ </div>
+ <div class="comment-body">
+ {{comment.html}}
+ <a class="author" href="{{comment.author.get_profile_url()}}">{{comment.author.username|escape}}</a>
+ <span class="age">&nbsp;({{ timeago(comment.added_at) }})</span>
+ <a id="post-{{comment.id}}-edit"
+ class="edit">{% trans %}edit{% endtrans %}</a>
+ <form action="{% url comment_to_answer %}" method="POST" accept-charset="utf-8" class='convert-comment'>
+ {% csrf_token %}
+ <input type="hidden" value="{{comment.id}}" name="comment_id" id="id_comment_id">
+ <input type="submit" value="{% trans %}convert to answer{% endtrans %}">
+ </form>
+ </div>
+ </div>
+ <script type="text/javascript">
+ askbot['functions']['hideConvertLinks']();
+ askbot['functions']['renderPostControls']('{{comment.id}}');
+ </script>
+ {% endfor %}
+ </div>
+ <div class="controls">
+ {% if show_post == post and show_comment %}
+ {% if show_comment_position > max_comments %}
+ {{
+ add_or_show_comments_button(
+ post = post,
+ max_comments = show_comment_position,
+ widget_id = widget_id
+ )
+ }}
+ {% else %}
+ {{
+ add_or_show_comments_button(
+ post = post,
+ max_comments = max_comments,
+ widget_id = widget_id
+ )
+ }}
+ {% endif %}
+ {% else %}
+ {{
+ add_or_show_comments_button(
+ post = post,
+ max_comments = max_comments,
+ widget_id = widget_id
+ )
+ }}
+ {% endif %}
+ </div>
+ </div>
+ {% endspaceless %}
+{%- endmacro -%}
+
+{%- macro reversible_sort_button(button_sort_criterium=None, asc_tooltip=None,
+ desc_tooltip=None, label=None, current_sort_method=None, search_state=None) -%}
+{#
+ sort button where descending sort is default
+ and the search method is togglable between ascending and descending
+ buttons are rendered as links with id constructed as
+ "by_" + button_sort_criterium
+ class "on" is added when current_sort_method is one of
+ button_sort_criterium + "asc" or "desc"
+#}
+ {% set key_name = button_sort_criterium %}
+ {% if current_sort_method == key_name + "-asc" %}{# "worst" first #}
+ <a id="by_{{key_name}}"
+ href="{{ search_state.change_sort(key_name+"-desc").full_url() }}"
+ class="rev on"
+ title="{{desc_tooltip}}"><span>{{label}} &#9650;</span></a>
+ {% elif current_sort_method == key_name + "-desc" %}{# "best first" #}
+ <a id="by_{{key_name}}"
+ href="{{ search_state.change_sort(key_name+"-asc").full_url() }}"
+ class="rev on"
+ title="{{asc_tooltip}}"><span>{{label}} &#9660;</span></a>
+ {% else %}{# default, when other button is active #}
+ <a id="by_{{key_name}}"
+ href="{{ search_state.change_sort(key_name+"-desc").full_url() }}"
+ class="off"
+ title="{{desc_tooltip}}"><span>{{label}}</span></a>
+ {% endif %}
+ <script type="text/javascript">{# need to pass on text translations to js #}
+ var sortButtonData = sortButtonData || {};
+ sortButtonData["{{key_name}}"] = {
+ label: "{{label}}",
+ asc_tooltip: "{{asc_tooltip}}",
+ desc_tooltip: "{{desc_tooltip}}"
+ };
+ </script>
+{%- endmacro %}
+
+{%- macro checkbox_in_div(checkbox_field, class = 'checkbox') -%}
+ <div{% if class %} class="{{class}}"{% endif %}
+ title="{{checkbox_field.help_text}}">
+ {{ checkbox_field }}
+ {{ checkbox_field.label_tag() }}
+ {{ checkbox_field.errors }}
+ </div>
+{%- endmacro -%}
+
+{%- macro edit_post(
+ post_form,
+ post_type = None,
+ post_html = None,
+ mandatory_tags = None,
+ edit_title = False,
+ use_category_selector = False,
+ tag_names = None,
+ editor_type = None,
+ user = None
+ )
+-%}
+{%include "widgets/edit_post.html" %}
+{%- endmacro -%}
+
+{%- macro tag_autocomplete_js(id = '#id_tags') -%}
+ var tagAc = new AutoCompleter({
+ url: '{% url "get_tag_list" %}',
+ preloadData: true,
+ minChars: 1,
+ useCache: true,
+ matchInside: true,
+ maxCacheLength: 100,
+ delay: 10
+ });
+ tagAc.decorate($("{{ id }}"));
+{%- endmacro -%}
+
+{%- macro answer_classes(answer, question) -%}
+answer {% if answer.accepted() %}accepted-answer{% endif %} {% if answer.author_id==question.author_id %} answered-by-owner{% endif %} {% if answer.deleted %}deleted{% endif -%}
+{%- endmacro -%}
+
+{%- macro user_score_and_badge_summary(
+ user,
+ karma_mode = None,
+ badges_mode = None
+) -%}
+ {%include "widgets/user_score_and_badge_summary.html"%}
+{%- endmacro -%}
+
+{%- macro follow_toggle(follow, name, alias, id) -%}
+ {# follow - boolean; name - object type name; alias - e.g. users name; id - object id #}
+ <div
+ class="follow-toggle follow-user-toggle"
+ id="follow-{{ name|escape }}-{{ id }}"
+ >
+ {% if follow %}
+ <div class="follow">{% trans %}follow {{alias}}{% endtrans %}</div>
+ {% else %}
+ <div class="unfollow">
+ <div class="unfollow-red">{% trans %}unfollow {{alias}}{% endtrans %}</div>
+ <div class="unfollow-green">{% trans %}following {{alias}}{% endtrans %}</div>
+ </div>
+ {% endif %}
+ </div>
+{%- endmacro -%}
+
+{%- macro follow_user_toggle(visitor = None, subject = None) -%}
+ {% if visitor.is_anonymous() %}
+ {{ follow_toggle(True, 'user', subject.username|escape, subject.id) }}
+ {% else %}
+ {% if visitor != subject %}
+ {% if visitor.is_following(subject) %}
+ {{ follow_toggle(False, 'user', subject.username|escape, subject.id) }}
+ {% else %}
+ {{ follow_toggle(True, 'user', subject.username|escape, subject.id) }}
+ {% endif %}
+ {% endif %}
+ {% endif %}
+{%- endmacro -%}
+
+{%- macro user_long_score_and_badge_summary(user, badges_mode = None) -%}
+ {%- include "widgets/user_long_score_and_badge_summary.html" -%}
+{%- endmacro -%}
+
+{%- macro user_country_flag(user) -%}
+ {% if user.country and user.show_country %}
+ <img class="flag"
+ src="{{ ('/images/flags/' ~ user.country.code|lower ~ '.gif')|media }}"
+ alt="{% trans
+ country=user.country.name
+ %}flag of {{country}}{%
+ endtrans %}"
+ title="{% trans
+ country=user.country.name,
+ person=user.username|escape %}{{person}} is from {{country}}{%
+ endtrans %}"
+ />
+ {% endif %}
+{%- endmacro -%}
+
+{%- macro user_country_name_and_flag(user) -%}
+ {% if user.country and user.show_country %}
+ {{ user.country.name }}
+ {{ user_country_flag(user) }}
+ {% endif %}
+{%- endmacro -%}
+
+{%- macro user_full_location(user) -%}
+ {% if user.location %}
+ {{ user.location }},
+ {% endif %}
+ {{ user_country_name_and_flag(user) }}
+{%- endmacro -%}
+
+{%- macro user_list(
+ users, profile_section = None, karma_mode = None, badges_mode = None
+ )
+-%}
+{% include "widgets/user_list.html"%}
+{%- endmacro -%}
+
+{#todo: rename this to avatar #}
+{%- macro gravatar(user, size) -%}
+{% spaceless %}
+<a style="text-decoration:none"
+ href="{{ user.get_absolute_url() }}"
+><img class="gravatar"
+ width="{{size}}" height="{{size}}"
+ src="{{ user.get_avatar_url(size) }}"
+ title="{{user.username|escape}}"
+ alt="{% trans username=user.username|escape %}{{username}} gravatar image{% endtrans %}"
+/></a>
+{% endspaceless %}
+{%- endmacro -%}
+
+{%- macro user_website_link(user, max_display_length=25) -%}
+ {% if user.website and (not user.is_blocked()) %}
+ <a
+ href="{{user.website}}"
+ title="{% trans username=user.username|escape, url=user.website %}{{username}}'s website is {{url}}{% endtrans %}"
+ {% if user.can_have_strong_url() == False %}
+ rel="nofollow"
+ {% endif %}
+ >
+ {{user.website|truncate(length=max_display_length, killwords=True, end='...')}}
+ </a>
+ {% endif %}
+{%- endmacro -%}
+
+{%- macro paginator(p, position='left', anchor='') -%}{# p is paginator context dictionary #}
+{% spaceless %}
+ {% if p.is_paginated %}
+ <div class="paginator" style="float:{{position}}">
+ {% if p.has_previous %}
+ <span class="prev"><a href="{{p.base_url}}page={{ p.previous }}{{ anchor }}" title="{% trans %}previous{% endtrans %}">
+ &laquo; {% trans %}previous{% endtrans %}</a></span>
+ {% endif %}
+ {% if not p.in_leading_range %}
+ {% for num in p.pages_outside_trailing_range %}
+ <span class="page"><a href="{{p.base_url}}page={{ num }}{{ anchor }}" >{{ num }}</a></span>
+ {% endfor %}
+ ...
+ {% endif %}
+
+ {% for num in p.page_numbers %}
+ {% if num == p.page and p.pages != 1%}
+ <span class="curr" title="{% trans %}current page{% endtrans %}">{{ num }}</span>
+ {% else %}
+ <span class="page"><a href="{{p.base_url}}page={{ num }}{{ anchor }}" title="{% trans %}page {{num}}{% endtrans %}">{{ num }}</a></span>
+ {% endif %}
+ {% endfor %}
+
+ {% if not p.in_trailing_range %}
+ ...
+ {% for num in p.pages_outside_leading_range|reverse %}
+ <span class="page"><a href="{{p.base_url}}page={{ num }}{{ anchor }}" title="{% trans %}page {{ num }}{% endtrans %}">{{ num }}</a></span>
+ {% endfor %}
+ {% endif %}
+ {% if p.has_next %}
+ <span class="next"><a href="{{p.base_url}}page={{ p.next }}{{ anchor }}" title="{% trans %}next page{% endtrans %}">{% trans %}next page{% endtrans %} &raquo;</a></span>
+ {% endif %}
+ </div>
+ {% endif %}
+{% endspaceless %}
+{%- endmacro -%}
+
+
+
+{%- macro paginator_main_page(p, position, search_state) -%} {# p is paginator context dictionary #}
+ {% spaceless %}
+ {% if p.is_paginated %}
+ <div class="paginator" style="float:{{position}}">
+ {% if p.has_previous %}
+ <span class="prev"><a href="{{ search_state.change_page(p.previous).full_url() }}" title="{% trans %}previous{% endtrans %}">
+ &laquo; {% trans %}previous{% endtrans %}</a></span>
+ {% endif %}
+ {% if not p.in_leading_range %}
+ {% for num in p.pages_outside_trailing_range %}
+ <span class="page"><a href="{{ search_state.change_page(num).full_url() }}" >{{ num }}</a></span>
+ {% endfor %}
+ ...
+ {% endif %}
+
+ {% for num in p.page_numbers %}
+ {% if num == p.page and p.pages != 1%}
+ <span class="curr" title="{% trans %}current page{% endtrans %}">{{ num }}</span>
+ {% else %}
+ <span class="page"><a href="{{ search_state.change_page(num).full_url() }}" title="{% trans %}page {{num}}{% endtrans %}">{{ num }}</a></span>
+ {% endif %}
+ {% endfor %}
+
+ {% if not p.in_trailing_range %}
+ ...
+ {% for num in p.pages_outside_leading_range|reverse %}
+ <span class="page"><a href="{{ search_state.change_page(num).full_url() }}" title="{% trans %}page {{ num }}{% endtrans %}">{{ num }}</a></span>
+ {% endfor %}
+ {% endif %}
+ {% if p.has_next %}
+ <span class="next"><a href="{{ search_state.change_page(p.next).full_url() }}" title="{% trans %}next page{% endtrans %}">{% trans %}next page{% endtrans %} &raquo;</a></span>
+ {% endif %}
+ </div>
+ {% endif %}
+ {% endspaceless %}
+{%- endmacro -%}
+
+
+{%- macro inbox_link(user) -%}
+ {% if user.new_response_count > 0 or user.seen_response_count > 0 %}
+ <a id='ab-responses' href="{{user.get_absolute_url()}}?sort=inbox&section=forum">
+ <img
+ alt="{% trans username=user.username|escape %}responses for {{username}}{% endtrans %}"
+ {% if user.new_response_count > 0 %}
+ src="{{ "/images/mail-envelope-full.png"|media }}"
+ title="{% trans response_count=user.new_response_count %}you have {{response_count}} new response{% pluralize %}you have {{response_count}} new responses{% endtrans %}"
+ {% elif user.seen_response_count > 0 %}
+ src="{{ "/images/mail-envelope-empty.png"|media }}"
+ title="{% trans %}no new responses yet{% endtrans %}"
+ {% endif %}
+ />
+ </a>
+ {% endif %}
+{%- endmacro -%}
+
+{%- macro moderation_items_link(user, moderation_items) -%}
+ {% if moderation_items %}
+ <a id="ab-responses"
+ href="{{user.get_absolute_url()}}?sort=inbox&section=flags"
+ >
+ {% if moderation_items['new_count'] > 0 %}
+ <img src="{{'/images/dialog-warning.png'|media}}"
+ {% if moderation_items['seen_count'] > 0 %}
+ alt="{% trans new=moderation_items['new_count'], seen=moderation_items['seen_count']%}{{new}} new flagged posts and {{seen}} previous{% endtrans %}"
+ title="{% trans new=moderation_items['new_count'], seen=moderation_items['seen_count']%}{{new}} new flagged posts and {{seen}} previous{% endtrans %}"
+ {% else %}
+ alt="{% trans new=moderation_items['new_count'] %}{{new}} new flagged posts{% endtrans %}"
+ title="{% trans new=moderation_items['new_count'] %}{{new}} new flagged posts{% endtrans %}"
+ {% endif %}
+ />
+ {% elif moderation_items['seen_count'] > 0 %}
+ <img src={{'/images/dialog-warning-off.png'|media}}
+ alt="{% trans seen=moderation_items['seen_count'] %}{{seen}} flagged posts{% endtrans %}"
+ title="{% trans seen=moderation_items['seen_count'] %}{{seen}} flagged posts{% endtrans %}"
+ />
+ {% endif %}
+ </a>
+ {% endif %}
+{%- endmacro -%}
+
+{%- macro timeago(datetime_object) -%}
+ <abbr class="timeago" title="{{datetime_object.replace(microsecond=0)|add_tz_offset}}">
+ {{datetime_object.replace(microsecond=0)|add_tz_offset}}
+ </abbr>
+{%- endmacro -%}
diff --git a/askbot/skins/default/templates/main_page.html b/askbot/templates/main_page.html
index a0635a7a..a0635a7a 100644
--- a/askbot/skins/default/templates/main_page.html
+++ b/askbot/templates/main_page.html
diff --git a/askbot/skins/default/templates/main_page/content.html b/askbot/templates/main_page/content.html
index 07a50c77..07a50c77 100644
--- a/askbot/skins/default/templates/main_page/content.html
+++ b/askbot/templates/main_page/content.html
diff --git a/askbot/templates/main_page/headline.html b/askbot/templates/main_page/headline.html
new file mode 100644
index 00000000..11f638e1
--- /dev/null
+++ b/askbot/templates/main_page/headline.html
@@ -0,0 +1,41 @@
+{% import "macros.html" as macros %}
+{% if questions_count > 0 %}
+ <h1 id="questionCount" class="search-result-summary">
+ {% trans cnt=questions_count, q_num=questions_count|intcomma %}{{q_num}} question{% pluralize %}{{q_num}} questions{% endtrans %}
+ {% if author_name %}
+ {% trans %}with {{author_name}}'s contributions{% endtrans %}
+ {% endif %}
+ </h1>
+ <div class="clearfix"></div>
+ <div id="listSearchTags" {% if not search_tags %}style="display: none;"{% endif %}>
+ <span class="left">{% trans %}Tagged{% endtrans %}</span>
+ {{ macros.tag_list_widget(
+ search_tags,
+ id = 'searchTags',
+ deletable = True,
+ make_links = False,
+ search_state = search_state
+ )
+ }}
+ </div>
+ {#% if author_name or search_tags or query %}
+ <p class="search-tips"><b>{% trans %}Search tips:{% endtrans %}</b>
+ {% if reset_method_count > 1 %}
+ {% if author_name %}
+ <a href="{{ search_state.remove_author().full_url() }}">{% trans %}reset author{% endtrans %}</a>
+ {% endif %}
+ {% if search_tags %}{% if author_name and query %}, {% elif author_name %}{% trans %} or {% endtrans %}{% endif %}
+ <a href="{{ search_state.remove_tags().full_url() }}">{% trans %}reset tags{% endtrans %}</a>
+ {% endif %}
+ {% if query %}{% trans %} or {% endtrans %}
+ <a href="{% url questions %}">{% trans %}start over{% endtrans %}</a>
+ {% endif %}
+ {% else %}
+ <a href="{% url questions %}">{% trans %}start over{% endtrans %}</a>
+ {% endif %}
+ {% trans %} - to expand, or dig in by adding more tags and revising the query.{% endtrans %}
+ </p>
+ {% else %}
+ <p class="search-tips"><b>{% trans %}Search tip:{% endtrans %}</b> {% trans %}add tags and a query to focus your search{% endtrans %}</p>
+ {% endif %#}
+{% endif %}
diff --git a/askbot/templates/main_page/javascript.html b/askbot/templates/main_page/javascript.html
new file mode 100644
index 00000000..f1e0fb44
--- /dev/null
+++ b/askbot/templates/main_page/javascript.html
@@ -0,0 +1,51 @@
+<script type="text/javascript">
+ /*<![CDATA[*/
+ var sortMethod = '{{sort}}';
+ var showSortByRelevance = {% if show_sort_by_relevance %}true{% else %}false{% endif %};
+ var minSearchWordLength = {{settings.MIN_SEARCH_WORD_LENGTH}};
+ $(document).ready(function(){
+ /*var on_tab = '#nav_questions';
+ $(on_tab).attr('className','on');*/
+ liveSearch('{{ search_state.query_string()|escapejs }}');
+ Hilite.exact = false;
+ Hilite.elementid = "question-list";
+ Hilite.debug_referrer = location.href;
+ {% if update_avatar_data == True %}
+ var today = new Date();{#add timestamp to prevent browser caching #}
+ $.getJSON('{% url user_update_has_custom_avatar %}?t=' + today.getTime());
+ {% endif %}
+ });
+
+ askbot['urls']['mark_interesting_tag'] = '{% url mark_interesting_tag %}';
+ askbot['urls']['mark_ignored_tag'] = '{% url mark_ignored_tag %}';
+ askbot['urls']['mark_subscribed_tag'] = '{% url mark_subscribed_tag %}';
+ askbot['urls']['unmark_tag'] = '{% url unmark_tag %}';
+ askbot['urls']['set_tag_filter_strategy'] = '{% url "set_tag_filter_strategy" %}';
+ askbot['urls']['questions'] = '{% url "questions" %}';
+ askbot['urls']['question_url_template'] = scriptUrl + '{{'question/'|transurl}}{{ "{{QuestionID}}/" }}';
+
+ if (Modernizr.history) {
+ // history management works!
+ } else {
+ // no history support :(
+ //hash = unescape(window.location.hash).replace('#','').split("?")[0]
+ {# todo: fix this evil code!!! #}
+ var hash = History.unescapeHash(window.location.hash).replace('#','').split("?")[0];
+ var questions_url = askbot['urls']['questions'];
+ if (hash.substring(0, questions_url.length) === questions_url) {
+ var url = hash;
+ } else {
+ var url = questions_url + hash;
+ }
+ if (hash !== '' && hash !== undefined && url !== undefined){
+ {# was this causing strange redirects in IE??? #}
+ window.location = 'http://' + window.location.host + url;
+ }
+ }
+ /*]]>*/
+</script>
+<script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
+{% if request.user.is_authenticated() %}
+<script type='text/javascript' src='{{"/js/tag_selector.js"|media}}'></script>
+{% endif %}
+<script type="text/javascript" src='{{"/js/live_search.js"|media}}'></script>
diff --git a/askbot/skins/default/templates/main_page/nothing_found.html b/askbot/templates/main_page/nothing_found.html
index 1e2c5445..1e2c5445 100644
--- a/askbot/skins/default/templates/main_page/nothing_found.html
+++ b/askbot/templates/main_page/nothing_found.html
diff --git a/askbot/skins/default/templates/main_page/paginator.html b/askbot/templates/main_page/paginator.html
index e7dc246a..e7dc246a 100644
--- a/askbot/skins/default/templates/main_page/paginator.html
+++ b/askbot/templates/main_page/paginator.html
diff --git a/askbot/templates/main_page/questions_loop.html b/askbot/templates/main_page/questions_loop.html
new file mode 100644
index 00000000..ad7bf683
--- /dev/null
+++ b/askbot/templates/main_page/questions_loop.html
@@ -0,0 +1,13 @@
+{% import "macros.html" as macros %}
+{% if threads.object_list|length == 0 %}
+ {% include "main_page/nothing_found.html" %}
+{% else %}
+ {% for thread in threads.object_list %}
+ {{ thread.get_summary_html(search_state=search_state, visitor = request.user) }}
+ {% endfor %}
+ <div class="evenMore">
+ {% trans %}Did not find what you were looking for?{% endtrans %}
+ <a href="{% url ask %}">{% trans %}Please, post your question!{% endtrans %}</a>
+ </div>
+{% endif %}
+
diff --git a/askbot/skins/default/templates/main_page/sidebar.html b/askbot/templates/main_page/sidebar.html
index 7acbe091..7acbe091 100644
--- a/askbot/skins/default/templates/main_page/sidebar.html
+++ b/askbot/templates/main_page/sidebar.html
diff --git a/askbot/skins/default/templates/main_page/tab_bar.html b/askbot/templates/main_page/tab_bar.html
index 17ab810e..17ab810e 100644
--- a/askbot/skins/default/templates/main_page/tab_bar.html
+++ b/askbot/templates/main_page/tab_bar.html
diff --git a/askbot/skins/default/templates/main_page/tag_search.html b/askbot/templates/main_page/tag_search.html
index 45f12b2f..45f12b2f 100644
--- a/askbot/skins/default/templates/main_page/tag_search.html
+++ b/askbot/templates/main_page/tag_search.html
diff --git a/askbot/templates/meta/bottom_scripts.html b/askbot/templates/meta/bottom_scripts.html
new file mode 100644
index 00000000..b3fcd815
--- /dev/null
+++ b/askbot/templates/meta/bottom_scripts.html
@@ -0,0 +1,98 @@
+{# most, if not all javascripts should go here
+ this template is included at the very bottow of the
+ main template "base.html"
+#}
+<div id="no-javascript">
+ <noscript class="noscript">
+ {% trans app_name = settings.APP_SHORT_NAME %}Please note: {{app_name}} requires javascript to work properly, please enable javascript in your browser, <a href="{{noscript_url}}">here is how</a>{% endtrans %}
+ </noscript>
+ <script type="text/javascript">
+ //IE fix to hide the red margin
+ var noscript = document.getElementsByTagName('noscript')[0];
+ noscript.style.padding = '0px';
+ noscript.style.backgroundColor = 'transparent';
+ </script>
+</div>
+<script type="text/javascript">
+ var i18nLang = '{{settings.LANGUAGE_CODE}}';
+ var scriptUrl = '/{{settings.ASKBOT_URL}}'
+ var askbotSkin = '{{settings.ASKBOT_DEFAULT_SKIN}}';
+ var enableMathJax = {% if settings.ENABLE_MATHJAX %}true{% else %}false{% endif %};
+ askbot['urls']['mark_read_message'] = '{% url "read_message" %}';
+ askbot['urls']['get_tags_by_wildcard'] = '{% url "get_tags_by_wildcard" %}';
+ askbot['urls']['get_tag_list'] = '{% url "get_tag_list" %}';
+ askbot['urls']['follow_user'] = '/followit/follow/user/{{'{{'}}userId{{'}}'}}/';
+ askbot['urls']['unfollow_user'] = '/followit/unfollow/user/{{'{{'}}userId{{'}}'}}/';
+ askbot['urls']['user_signin'] = '{{ settings.LOGIN_URL }}';
+ askbot['settings']['static_url'] = '{{ settings.STATIC_URL }}';
+ askbot['urls']['getEditor'] = '{% url "get_editor" %}';
+</script>
+<script
+ type="text/javascript"
+ {% if settings.DEBUG %}
+ src="{{"/js/jquery-1.7.2.min.js"|media}}"
+ {% else %}
+ src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"
+ {% endif %}
+></script>
+<script type="text/javascript" src='{{"/bootstrap/js/bootstrap.js"|media}}'></script>
+<!-- History.js -->
+<script type='text/javascript' src="{{"/js/jquery.history.js"|media }}"></script>
+<script type='text/javascript' src="{{"/js/utils.js"|media }}"></script>
+{% if settings.ENABLE_MATHJAX %}
+ <script type='text/javascript' src="{{settings.MATHJAX_BASE_URL}}/MathJax.js">
+ MathJax.Hub.Config({
+ extensions: ["tex2jax.js"],
+ jax: ["input/TeX","output/HTML-CSS"],
+ tex2jax: {inlineMath: [["$","$"],["\\(","\\)"]]}
+ });
+ </script>
+{% endif %}
+<script type="text/javascript">
+ /*<![CDATA[*/
+ $(document).ready(function(){
+ // focus input on the search bar endcomment
+ {% if active_tab in ('users', 'questions', 'tags') %}
+ $('#keywords').focus();
+ {% elif active_tab == 'ask' %}
+ $('#id_title').focus();
+ {% else %}
+ animateHashes();
+ {% endif %}
+ if (askbot['data']['userIsAdminOrMod']) {
+ $('body').addClass('admin');
+ }
+ {%if settings.GROUPS_ENABLED %}
+ askbot['urls']['add_group'] = "{% url add_group %}";
+ var group_dropdown = new GroupDropdown({{group_list}});
+ $('.dropdown').append(group_dropdown.getElement());
+ {%if request.user.is_superuser%}
+ group_dropdown.enableAddGroups();
+ {%endif%}
+ {% endif %}
+ });
+{% if user_messages %}
+ $('#validate_email_alert').click(function(){notify.close(true)})
+ notify.show();
+{% endif %}
+ $('abbr.timeago').timeago();
+ /*]]>*/
+</script>
+{% if settings.USE_CUSTOM_JS %}
+<script
+ src="{% url "custom_js"%}?v={{ settings.MEDIA_RESOURCE_REVISION }}"
+ type="text/javascript"
+></script>
+{% endif %}
+{% if settings.GOOGLE_ANALYTICS_KEY %}
+<script type="text/javascript">
+ var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+ document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+ </script>
+ <script type="text/javascript">
+ try {
+ var pageTracker = _gat._getTracker('{{ settings.GOOGLE_ANALYTICS_KEY }}');
+ pageTracker._trackPageview();
+ } catch(err) {}
+</script>
+{% endif %}
diff --git a/askbot/templates/meta/category_tree_js.html b/askbot/templates/meta/category_tree_js.html
new file mode 100644
index 00000000..2d176d0e
--- /dev/null
+++ b/askbot/templates/meta/category_tree_js.html
@@ -0,0 +1,26 @@
+<script type='text/javascript'>
+ askbot['functions'] = askbot['functions'] || {};
+ askbot['functions']['initCategoryTree'] = function(){
+ var sel_elems = $('.category-selector');
+ if (sel_elems.length > 0) {
+ var selector = new CategorySelector();
+ selector.setData(JSON.parse("{{category_tree_data|escapejs}}"));
+ selector.decorate(sel_elems);
+ selector.setState('select');
+
+ var tag_editor = new TagEditor();
+ tag_editor.decorate($('.tag-editor'));
+ {% if page_class == 'question-page' %}
+ {% for tag_name in question.get_tag_names() %}
+ tag_editor.addTag('{{ tag_name }}');
+ {% endfor %}
+ {% endif %}
+ selector.setSelectHandler(tag_editor.getAddTagHandler());
+ return selector;
+ }
+ };
+ askbot['functions']['initCategoryTree']();
+ askbot['urls']['add_tag_category'] = '{% url add_tag_category %}';
+ askbot['urls']['rename_tag'] = '{% url rename_tag %}';
+ askbot['urls']['delete_tag'] = '{% url delete_tag %}';
+</script>
diff --git a/askbot/templates/meta/editor_data.html b/askbot/templates/meta/editor_data.html
new file mode 100644
index 00000000..f0402672
--- /dev/null
+++ b/askbot/templates/meta/editor_data.html
@@ -0,0 +1,16 @@
+<script type="text/javascript">
+ {# data necessary for the post editor, goes into endjs block #}
+ askbot['settings']['tagsAreRequired'] =
+ {% if settings.TAGS_ARE_REQUIRED %}true{% else %}false{% endif %};
+ askbot['settings']['maxTagLength'] = {{settings.MAX_TAG_LENGTH}};
+ "each tag must be shorter than %(max_chars)d characters",
+ askbot['messages']['maxTagLength'] = "{% trans max_chars = settings.MAX_TAG_LENGTH %}each tag must be shorter that {{max_chars}} character{% pluralize %}each tag must be shorter than {{max_chars}} characters{% endtrans %}";
+ askbot['settings']['maxTagsPerPost'] = {{settings.MAX_TAGS_PER_POST}};
+ askbot['messages']['maxTagsPerPost'] = "{% trans tag_count = settings.MAX_TAGS_PER_POST %}please use {{tag_count}} tag{% pluralize %}please use {{tag_count}} tags or less{% endtrans %}";
+ askbot['messages']['tagLimits'] = "{% trans tag_count=settings.MAX_TAGS_PER_POST, max_chars=settings.MAX_TAG_LENGTH %}please use up to {{tag_count}} tags, less than {{max_chars}} characters each{% endtrans %}";
+ askbot['urls']['upload'] = '{% url "upload" %}';
+ askbot['settings']['minTitleLength'] = {{settings.MIN_TITLE_LENGTH}};
+ askbot['settings']['minQuestionBodyLength'] = {{settings.MIN_QUESTION_BODY_LENGTH}};
+ askbot['settings']['minAnswerBodyLength'] = {{settings.MIN_ANSWER_BODY_LENGTH}};
+ askbot['settings']['tag_editor'] = '{{ tag_editor_settings|escapejs }}';
+</script>
diff --git a/askbot/templates/meta/fonts.html b/askbot/templates/meta/fonts.html
new file mode 100644
index 00000000..e8e54a8f
--- /dev/null
+++ b/askbot/templates/meta/fonts.html
@@ -0,0 +1,8 @@
+<style type="text/css">
+@font-face {
+ font-family: 'Open Sans Condensed';
+ font-style: normal;
+ font-weight: 700;
+ src: url('{{"/images/OpenSans-CondBold.ttf"|media}}');
+}
+</style>
diff --git a/askbot/templates/meta/html_head_javascript.html b/askbot/templates/meta/html_head_javascript.html
new file mode 100644
index 00000000..09362baa
--- /dev/null
+++ b/askbot/templates/meta/html_head_javascript.html
@@ -0,0 +1,34 @@
+<script type="text/javascript" src="{{"/js/modernizr.custom.js"|media }}"></script>
+<script type="text/javascript" src="{% url django.views.i18n.javascript_catalog %}"></script>
+<script type="text/javascript">
+ var askbot = {};
+ askbot['data'] = {};
+ {% if request.user.is_authenticated() %}
+ askbot['data']['userIsAuthenticated'] = true;
+ askbot['data']['userId'] = {{request.user.id}};
+ askbot['data']['userName'] = '{{ request.user.username }}';
+ askbot['data']['userIsAdminOrMod'] = {% if
+ request.user.is_administrator()
+ or request.user.is_moderator()
+ %}true{% else %}false{% endif %};
+ askbot['data']['userIsAdmin'] = {% if
+ request.user.is_administrator()
+ %}true{% else %}false{% endif %};
+ askbot['data']['userReputation'] = {{request.user.reputation}};
+ {% else %}
+ askbot['data']['userIsAuthenticated'] = false;
+ askbot['data']['userReputation'] = 0;
+ {% endif %}
+ askbot['urls'] = {};
+ askbot['settings'] = {};
+ askbot['settings']['editorType'] = '{{ settings.EDITOR_TYPE }}';
+ {% if settings.ALLOWED_UPLOAD_FILE_TYPES %}
+ askbot['settings']['allowedUploadFileTypes'] = [
+ "{{ settings.ALLOWED_UPLOAD_FILE_TYPES|join('", "')|replace('.','') }}"
+ ];
+ {% else %}
+ askbot['settings']['allowedUploadFileTypes'] = [];
+ {% endif %}
+ askbot['messages'] = {};
+</script>
+{# avoid adding javascript here so that pages load faster #}
diff --git a/askbot/templates/meta/html_head_stylesheets.html b/askbot/templates/meta/html_head_stylesheets.html
new file mode 100644
index 00000000..85bb489c
--- /dev/null
+++ b/askbot/templates/meta/html_head_stylesheets.html
@@ -0,0 +1,26 @@
+{%if settings.GROUPS_ENABLED%}
+<link href="{{'/bootstrap/css/bootstrap.css'|media}}" rel="stylesheet" type="text/css" />
+{% endif %}
+{% if settings.ASKBOT_CSS_DEVEL == False %}
+
+<link href="{{"/style/style.css"|media }}" rel="stylesheet" type="text/css" />
+{% else %}
+<link href="{{"/style/style.less"|media }}" rel="stylesheet/less" type="text/css" />
+<script type="text/javascript" src="{{"/js/less.min.js"|media}}"></script>
+{% endif %}
+<link href="{{'/bootstrap/css/bootstrap.css'|media}}" rel="stylesheet" type="text/css" />
+{% if settings.USE_LOCAL_FONTS %}
+ {% include "meta/fonts.html" %}
+{% else %}
+ {# note: IE8 fix - a combined font link wont work so we have two #}
+ <link href='http://fonts.googleapis.com/css?family=Open+Sans+Condensed:700&amp;subset=latin-ext' rel='stylesheet' type='text/css'>
+ <link href='http://fonts.googleapis.com/css?family=Open+Sans+Condensed:700&amp;subset=cyrillic-ext' rel='stylesheet' type='text/css'>
+{% endif %}
+{{ skin.get_extra_css_link() }}
+{% if settings.USE_CUSTOM_CSS %}
+ <link
+ href="{% url "custom_css" %}?v={{settings.MEDIA_RESOURCE_REVISION}}"
+ rel="stylesheet"
+ type="text/css"
+ />
+{% endif %}
diff --git a/askbot/skins/default/templates/meta/mandatory_tags_js.html b/askbot/templates/meta/mandatory_tags_js.html
index f04a6345..f04a6345 100644
--- a/askbot/skins/default/templates/meta/mandatory_tags_js.html
+++ b/askbot/templates/meta/mandatory_tags_js.html
diff --git a/askbot/templates/meta/tinymce_css.html b/askbot/templates/meta/tinymce_css.html
new file mode 100644
index 00000000..b6a1e798
--- /dev/null
+++ b/askbot/templates/meta/tinymce_css.html
@@ -0,0 +1,20 @@
+<style type="text/css">{# todo: clean up - this is also in style.less!!! #}
+ .defaultSkin table.mceLayout,
+ .defaultSkin table.mceLayout tr.mceFirst td {
+ border: none;
+ }
+ .defaultSkin table.mceLayout tr.mceLast td {
+ border-bottom: none;
+ }
+ .mceStatusbar {
+ height: 5px;
+ background: #fff;
+ }
+ .defaultSkin span.mce_askbot_imageuploader {
+ background-position: -380px 0px;
+ }
+ .defaultSkin span.mce_askbot_attachment {
+ background-image: url({{ '/images/attachment.png'|media }});
+ background-position: 0px 0px;
+ }
+</style>
diff --git a/askbot/skins/common/templates/one_column_body.html b/askbot/templates/one_column_body.html
index 852f8fe5..852f8fe5 100644
--- a/askbot/skins/common/templates/one_column_body.html
+++ b/askbot/templates/one_column_body.html
diff --git a/askbot/templates/question.html b/askbot/templates/question.html
new file mode 100644
index 00000000..57c71068
--- /dev/null
+++ b/askbot/templates/question.html
@@ -0,0 +1,245 @@
+{% extends "two_column_body.html" %}
+<!-- question.html -->
+{% block title %}{% spaceless %}{{ question.get_question_title()|escape }}{% endspaceless %}{% endblock %}
+{% block meta_description %}
+ <meta name="description" content="{{question.summary|striptags|escape}}" />
+{% endblock %}
+{% block keywords %}{{thread.tagname_meta_generator()}}{% endblock %}
+{% block forestyle %}
+ <link rel="canonical" href="{{settings.APP_URL|strip_path}}{{question.get_absolute_url()}}" />
+ <link rel="stylesheet" type="text/css" href="{{'/js/wmd/wmd.css'|media}}" />
+ <link href="{{'/bootstrap/css/bootstrap.css'|media}}" rel="stylesheet" type="text/css" />
+{% endblock %}
+{% block forejs %}
+ <script type="text/javascript">
+ /*<![CDATA[*/
+ //below is pure cross-browser javascript, no jQuery
+ askbot['data']['userIsThreadModerator'] = {% if user_is_thread_moderator %}true{% else %}false{% endif %};
+ (function(){
+ var data = askbot['data'];
+ if (data['userIsAuthenticated']){
+ var votes = {};
+ {% for post_id in user_votes %}
+ votes['{{post_id}}'] = {{user_votes[post_id]}};
+ {% endfor %}
+ data['user_votes'] = votes;
+ var posts = {};
+ {% for post_id in user_post_id_list %}
+ posts['{{post_id}}'] = 1;
+ {% endfor %}
+ data['user_posts'] = posts;
+ }
+
+ function render_vote_buttons(post_type, post_id){
+ var upvote_btn = document.getElementById(
+ post_type + '-img-upvote-' + post_id
+ );
+ var downvote_btn = document.getElementById(
+ post_type + '-img-downvote-' + post_id
+ );
+ if (data['userIsAuthenticated']){
+ if (post_id in data['user_votes']){
+ var vote = data['user_votes'][post_id];
+ if (vote == -1){
+ var btn = downvote_btn;
+ } else if (vote == 1){
+ var btn = upvote_btn;
+ } else {
+ return;
+ }
+ if (post_type == 'comment'){
+ btn.className = btn.className + ' upvoted';
+ } else {
+ btn.className = btn.className + ' on';
+ }
+ }
+ }
+ }
+
+ function hide_convert_answer_links(post_id){
+ var answer_convert_id = 'post-' + post_id + '-convert';
+ var convert_answer = document.getElementById(answer_convert_id);
+ if (data['userIsAdminOrMod']){
+ var answer_id = 'post-id-' + post_id;
+ var answer_container = document.getElementById(answer_id);
+ var answer_element= answer_container.getElementsByClassName('answer-body')[0].children[1];
+ if (answer_element.textContent.length > 300){
+ convert_answer.parentNode.removeChild(convert_answer);
+ }
+ } else{
+ convert_answer.parentNode.removeChild(convert_answer);
+ }
+ }
+
+ function hidePublishAnswerLink(postId) {
+ if (data['userIsThreadModerator'] === false) {
+ //hide publish/unpublish answer links
+ var answerId = 'post-' + postId + '-publish';
+ var pubBtn = document.getElementById(answerId);
+ pubBtn.parentNode.removeChild(pubBtn);
+ }
+ }
+
+ function render_post_controls(post_id){
+ if (data['userIsAdminOrMod']){
+ return;//all remaining functions stay on
+ }
+ if (data['user_posts'] === undefined) {
+ return;
+ }
+ if (post_id in data['user_posts']){
+ //todo: remove edit button from older comments
+ return;//same here
+ }
+ if (//maybe remove "delete" button
+ data['userReputation'] <
+ {{settings.MIN_REP_TO_DELETE_OTHERS_COMMENTS}}
+ ) {
+ var delete_btn = document.getElementById(
+ 'post-' + post_id + '-delete'
+ );
+ delete_btn.parentNode.removeChild(delete_btn);
+ }
+ if (//maybe remove "edit" button
+ data['userReputation'] <
+ {{settings.MIN_REP_TO_EDIT_OTHERS_POSTS}}
+ ){
+ var edit_btn = document.getElementById(
+ 'post-' + post_id + '-edit'
+ )
+ edit_btn.parentNode.removeChild(edit_btn);
+ }
+ if (//maybe remove retag button
+ data['userReputation'] <
+ {{settings.MIN_REP_TO_RETAG_OTHERS_QUESTIONS}}
+ ){
+ var retag_btn = document.getElementById('retag');
+ retag_btn.parentNode.removeChild(retag_btn);
+ }
+ }
+ function render_add_comment_button(post_id, extra_comment_count){
+ var can_add = false;
+ if (data['user_posts'] === undefined) {
+ return;
+ }
+ {% if user_can_post_comment %}
+ can_add = true;
+ {% else %}
+ if (data['user_posts'] && post_id in data['user_posts']){
+ can_add = true;
+ }
+ {% endif %}
+ var add_comment_btn = document.getElementById(
+ 'add-comment-to-post-' + post_id
+ );
+ if (can_add === false){
+ add_comment_btn.parentNode.removeChild(add_comment_btn);
+ return;
+ }
+
+ var text = '';
+ if (extra_comment_count > 0){
+ if (can_add){
+ text =
+ "{% trans %}post a comment / <strong>some</strong> more{% endtrans %}";
+ } else {
+ text =
+ "{% trans %}see <strong>some</strong> more{% endtrans%}";
+ }
+ } else {
+ if (can_add){
+ text = "{% trans %}post a comment{% endtrans %}";
+ }
+ }
+ add_comment_btn.innerHTML = text;
+ //add the count
+ for (node in add_comment_btn.childNodes){
+ if (node.nodeName === 'strong'){
+ node.innerHTML = extra_comment_count;
+ break;
+ }
+ }
+ }
+ function render_add_answer_button(){
+ var add_answer_btn = document.getElementById('add-answer-btn');
+ if (askbot['data']['userIsAuthenticated']){
+ if (askbot['data']['userId'] == {{question.author_id}}){
+ add_answer_btn.className += ' answer-own-question';
+ add_answer_btn.setAttribute(
+ 'value',
+ '{% trans %}Answer Your Own Question{% endtrans %}'
+ )
+ } else {
+ add_answer_btn.setAttribute(
+ 'value',
+ '{% trans %}Post Your Answer{% endtrans %}'
+ )
+ }
+ } else {
+ add_answer_btn.setAttribute(
+ 'value',
+ '{% trans %}Login/Signup to Post{% endtrans %}'
+ );
+ }
+ }
+
+ function hide_convert_links(){
+ if (!askbot['data']['userIsAdminOrMod']){
+ var links = document.getElementsByClassName('convert-comment');
+ for (i=0; i<links.length; i++){
+ links[i].setAttribute('style', 'display:none;');
+ }
+ }
+ }
+
+ askbot['functions'] = askbot['functions'] || {};
+ askbot['functions']['renderPostVoteButtons'] = render_vote_buttons;
+ askbot['functions']['renderPostControls'] = render_post_controls;
+ askbot['functions']['renderAddCommentButton'] = render_add_comment_button;
+ askbot['functions']['renderAddAnswerButton'] = render_add_answer_button;
+ askbot['functions']['hideConvertLinks'] = hide_convert_links;
+ askbot['functions']['hideConvertAnswerLinks'] = hide_convert_answer_links;
+ askbot['functions']['hidePublishAnswerLink'] = hidePublishAnswerLink;
+ })();
+ /*]]>*/
+ </script>
+{% endblock %}
+{% block content %}
+ <div>
+ {{ settings.QUESTION_PAGE_TOP_BANNER }}
+ </div>
+ {% if is_cacheable %}
+ {% cache long_time "thread-content-html" thread.id %}
+ {% include "question/content.html" %}
+ {% endcache %}
+ {% else %}
+ {% include "question/content.html" %}
+ {% endif %}
+{% endblock %}
+{% block sidebar %}
+ {% include "question/sidebar.html" %}
+{% endblock %}
+{% block endjs %}
+ {% include "question/javascript.html" %}
+ {% if settings.TAG_SOURCE == 'category-tree' %}
+ {% include "meta/category_tree_js.html" %}
+ {% endif %}
+ {#
+ <script type="text/javascript">
+ var messages = askbot['messages'];
+ messages['upvote_question'] = gettext(
+ 'I like this question (click again to cancel)'
+ );
+ messages['upvote_answer'] = gettext(
+ 'I like this answer (click again to cancel)'
+ );
+ messages['downvote_question'] = gettext(
+ "I don't like this question (click again to cancel)"
+ );
+ messages['downvote_answer'] = gettext(
+ "I don't like this answer (click again to cancel)"
+ );
+ </script>
+ #}
+{% endblock %}
+
diff --git a/askbot/skins/common/templates/question/answer_author_info.html b/askbot/templates/question/answer_author_info.html
index 1c729b51..1c729b51 100644
--- a/askbot/skins/common/templates/question/answer_author_info.html
+++ b/askbot/templates/question/answer_author_info.html
diff --git a/askbot/templates/question/answer_card.html b/askbot/templates/question/answer_card.html
new file mode 100644
index 00000000..ae7d30fa
--- /dev/null
+++ b/askbot/templates/question/answer_card.html
@@ -0,0 +1,32 @@
+<a name="{{ answer.id }}"></a>
+{% if answer.old_answer_id %}
+ {# Make old URL anchors/hashes work #}
+ <a class="old_answer_id_anchor" name="{{ answer.old_answer_id }}"></a>
+{% endif %}
+<div
+ id="post-id-{{ answer.id }}"
+ class="{{ macros.answer_classes(answer, question) }}">
+ <div class="vote-buttons">
+ {% include "question/answer_vote_buttons.html" %}
+ </div>
+ <div class="answer-table">
+
+ <div class="item-right">
+ <div class="answer-body">
+ <div class="post-update-info-container">
+ {% include "question/answer_author_info.html" %}
+ </div>
+ {% if answer.id in published_answer_ids %}
+ <p><strong>{% trans %}This response is published{% endtrans %}</strong></p>
+ {% endif %}
+ {{ answer.html }}
+ </div>
+ <div class="answer-controls post-controls">
+ {% include "question/answer_controls.html" %}
+ </div>
+ {% include "question/answer_comments.html" %}
+ </div>
+ </div>
+ <div class="clean"></div>
+</div>
+<div class="clean"></div>
diff --git a/askbot/skins/common/templates/question/answer_comments.html b/askbot/templates/question/answer_comments.html
index e6b5e1c5..e6b5e1c5 100644
--- a/askbot/skins/common/templates/question/answer_comments.html
+++ b/askbot/templates/question/answer_comments.html
diff --git a/askbot/templates/question/answer_controls.html b/askbot/templates/question/answer_controls.html
new file mode 100644
index 00000000..4efc7247
--- /dev/null
+++ b/askbot/templates/question/answer_controls.html
@@ -0,0 +1,69 @@
+{#<span class="action-link swap-qa">
+ <a id="swap-question-with-answer-{{answer.id}}">{% trans %}swap with question{% endtrans %}</a>
+</span>uncomment if needed#}
+<span class="action-link">
+ <a class="permant-link"
+ href="{{ answer.get_absolute_url(question_post=question) }}"
+ title="{% trans %}permanent link{% endtrans %}">
+ {% trans %}link{% endtrans %}
+ </a>
+</span>
+<span
+ id="post-{{answer.id}}-publish"
+ class="action-link"
+>
+ {% if answer.id in published_answer_ids %}
+ <a
+ class="answer-unpublish"
+ data-answer-id="{{ answer.id }}"
+ >{% trans %}unpublish{% endtrans %}</a>
+ {% else %}
+ <a
+ class="answer-publish"
+ data-answer-id="{{ answer.id}}"
+ >{% trans %}publish{% endtrans %}</a>
+ {% endif %}
+</span>
+<span id='post-{{answer.id}}-delete' class="action-link delete-post">
+ <a class="question-delete"
+ >{% if answer.deleted %}{% trans %}undelete{% endtrans %}{% else %}{% trans %}delete{% endtrans %}{% endif %}</a>
+</span>
+{% if answer.offensive_flag_count > 0 %}
+<span
+ id="answer-offensive-remove-flag-{{ answer.id }}"
+ class="action-link offensive-flag"
+ title="{% trans %}remove offensive flag{% endtrans %}"
+>
+ <a class="question-flag">{% trans %}remove flag{% endtrans %}</a>
+</span>
+<span
+ id="answer-offensive-flag-{{ answer.id }}"
+ class="action-link offensive-flag"
+ title="{% trans %}report as offensive (i.e containing spam, advertising, malicious text, etc.){% endtrans %}"
+>
+ <a class="question-flag">{% trans %}flag offensive{% endtrans %} ({{ answer.offensive_flag_count }})</a>
+</span>
+{% else %}
+<span
+ id="answer-offensive-flag-{{ answer.id }}"
+ class="action-link offensive-flag"
+ title="{% trans %}report as offensive (i.e containing spam, advertising, malicious text, etc.){% endtrans %}"
+>
+ <a class="question-flag">{% trans %}flag offensive{% endtrans %}</a>
+</span>
+{% endif %}
+<span id='post-{{answer.id}}-edit' class="action-link">
+ <a class="question-edit" href="{% url edit_answer answer.id %}">{% trans %}edit{% endtrans %}</a>
+</span>
+<span id='post-{{answer.id}}-convert' class="action-link">
+ <form class="answer-convert" action="{% url answer_to_comment %}" method="POST">
+ {% csrf_token %}
+ <input type="hidden" name="answer_id" id="id_answer_id" value="{{answer.id}}"/>
+ <input type="submit" name="" value="{% trans %}convert to comment{% endtrans %}"/>
+ </form>
+</span>
+<script type="text/javascript">
+ askbot['functions']['hideConvertAnswerLinks']('{{ answer.id }}');
+ askbot['functions']['hidePublishAnswerLink']('{{ answer.id }}');
+ askbot['functions']['renderPostControls']('{{ answer.id }}');
+</script>
diff --git a/askbot/skins/default/templates/question/answer_tab_bar.html b/askbot/templates/question/answer_tab_bar.html
index bebf68b8..bebf68b8 100644
--- a/askbot/skins/default/templates/question/answer_tab_bar.html
+++ b/askbot/templates/question/answer_tab_bar.html
diff --git a/askbot/skins/common/templates/question/answer_vote_buttons.html b/askbot/templates/question/answer_vote_buttons.html
index 242bf2be..242bf2be 100644
--- a/askbot/skins/common/templates/question/answer_vote_buttons.html
+++ b/askbot/templates/question/answer_vote_buttons.html
diff --git a/askbot/skins/common/templates/question/closed_question_info.html b/askbot/templates/question/closed_question_info.html
index f6f3f557..f6f3f557 100644
--- a/askbot/skins/common/templates/question/closed_question_info.html
+++ b/askbot/templates/question/closed_question_info.html
diff --git a/askbot/templates/question/content.html b/askbot/templates/question/content.html
new file mode 100644
index 00000000..66b3014b
--- /dev/null
+++ b/askbot/templates/question/content.html
@@ -0,0 +1,49 @@
+{% import "macros.html" as macros %}
+
+{# ==== BEGIN: question/question_card.html ==== #}
+{% include "question/question_card.html" %}
+{# ==== END: question/question_card.html ==== #}
+
+{% if answers %}
+ <div class="clean"></div>
+
+ {# ==== START: question/answer_tab_bar.html ==== #}
+ {% include "question/answer_tab_bar.html" %}
+ {# ==== END: question/answer_tab_bar.html ==== #}
+
+ <div class="clean"></div>
+ {{ macros.paginator(paginator_context, anchor='#sort-top') }}
+ <div class="clean"></div>
+
+ {% for answer in answers %}
+ {# ==== START: question/answer_card.html ==== #}
+ {% include "question/answer_card.html" %}
+ {# ==== END: question/answer_card.html ==== #}
+ {% endfor %}
+ {{ macros.paginator(paginator_context, anchor='#sort-top') }}
+ <div class="clean"></div>
+{% else %}
+ {# ==== START: question/sharing_prompt_phrase.html ==== #}
+ {% include "question/sharing_prompt_phrase.html" %}
+ {# ==== END: question/sharing_prompt_phrase.html ==== #}
+{% endif %}
+
+{# ==== START: question/new_answer_form.html ==== #}
+{# buttons below cannot be cached yet #}
+{% if user_already_gave_answer %}
+ <a
+ class="submit"
+ href="{% url "edit_answer" previous_answer.id %}"
+ >{% trans %}Edit Your Previous Answer{% endtrans %}</a>
+ <span>{% trans %}(only one answer per question is allowed){% endtrans %}</span>
+{% else %}
+ {% include "question/new_answer_form.html" %}
+{% endif %}
+{% if question.closed == False and request.user == question.author %}{# this is outside the form on purpose #}
+<input
+ type="button"
+ class="submit after-editor answer-own-question"
+ id="fmanswer_button"
+ value="{% trans %}Answer Your Own Question{% endtrans %}"
+/>
+{% endif %}
diff --git a/askbot/templates/question/javascript.html b/askbot/templates/question/javascript.html
new file mode 100644
index 00000000..5dca2522
--- /dev/null
+++ b/askbot/templates/question/javascript.html
@@ -0,0 +1,110 @@
+<script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
+<script type='text/javascript'>
+ {% if settings.ENABLE_MATHJAX or settings.MARKUP_CODE_FRIENDLY %}
+ var codeFriendlyMarkdown = true;
+ {% else %}
+ var codeFriendlyMarkdown = false;
+ {% endif %}
+ var maxCommentLength = {{settings.MAX_COMMENT_LENGTH}};
+ askbot['urls']['postComments'] = '{% url post_comments %}';
+ askbot['urls']['editComment'] = '{% url edit_comment %}';
+ askbot['urls']['deleteComment'] = '{% url delete_comment %}';
+ askbot['urls']['convertComment'] = '{% url comment_to_answer %}';
+ askbot['urls']['convertAnswer'] = '{% url answer_to_comment %}';
+ askbot['urls']['getComment'] = '{% url get_comment %}';
+ askbot['urls']['saveDraftAnswer'] = '{% url save_draft_answer %}';
+ askbot['urls']['question_url_template'] = scriptUrl + '{{ 'question/'|transurl }}{{ "{{QuestionID}}/{{questionSlug}}" }}';{# yes it needs to be that whacky #}
+ askbot['urls']['vote_url_template'] = scriptUrl + '{{ 'questions/'|transurl }}{{ "{{QuestionID}}/" }}{{ 'vote/'|transurl }}';
+ askbot['urls']['user_signin'] = '{{ settings.LOGIN_URL }}';
+ askbot['urls']['swap_question_with_answer'] = '{% url swap_question_with_answer %}';
+ askbot['urls']['upvote_comment'] = '{% url upvote_comment %}';
+ askbot['urls']['delete_post'] = '{% url delete_post %}';
+ askbot['urls']['get_html_template'] = '{% url get_html_template %}';
+ askbot['urls']['getGroupsList'] = '{% url get_groups_list %}';
+ askbot['urls']['publishAnswer'] = '{% url publish_answer %}';
+ askbot['data']['userIsThreadModerator'] = {% if user_is_thread_moderator %}true{% else %}false{% endif %};
+ askbot['messages']['addComment'] = '{% trans %}post a comment{% endtrans %}';
+ {% if settings.SAVE_COMMENT_ON_ENTER %}
+ askbot['settings']['saveCommentOnEnter'] = true;
+ {% else %}
+ askbot['settings']['saveCommentOnEnter'] = false;
+ {% endif %}
+ askbot['settings']['tagSource'] = '{{ settings.TAG_SOURCE }}';
+</script>
+<script type="text/javascript" src='{{"/bootstrap/js/bootstrap.js"|media}}'></script>
+{% if settings.EDITOR_TYPE == 'markdown' %}
+ <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script>
+ <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script>
+{% endif %}
+<script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
+<script type='text/javascript' src='{{"/js/post.js"|media}}'></script>
+<script type="text/javascript">
+ // define reputation needs for comments
+ var repNeededForComments = 50;
+ $(document).ready(function(){
+ $("#nav_questions").attr('className',"on");
+ var answer_sort_tab = "{{ tab_id }}";
+ $("#" + answer_sort_tab).attr('className',"on");
+
+ Vote.init({{ question.id }}, '{{ thread.title|slugify }}', '{{ question.author_id }}','{{ request.user.id }}');
+
+ {% if not thread.closed and request.user.is_authenticated %}initEditor();{% endif %}
+
+ lanai.highlightSyntax();
+ $('#btLogin').bind('click', function(){window.location.href='{{ settings.LOGIN_URL }}'; } )
+ if (window.location.hash === 'fmanswer'){
+ $('#fmanswer textarea').focus();
+ }
+ {% if settings.ENABLE_SHARING_GOOGLE %}$.getScript("http://apis.google.com/js/plusone.js"){% endif %}
+
+ {% if request.user.id == question.author_id %}
+ $("#fmanswer_button").click(function() {
+ $("#fmanswer").show();
+ $("#fmanswer_button").hide();
+ });
+ {%endif%}
+
+ if (askbot['data']['userIsAuthenticated']) {
+ var draftHandler = new DraftAnswer();
+ draftHandler.setThreadId({{ thread.id }});
+ draftHandler.decorate($(document));
+ }
+ });
+
+ $(window).bind('hashchange', animate_hashes);
+
+ function animate_hashes(){
+ var id_value = window.location.hash;
+ if (id_value != ""){
+ var previous_color = $(id_value).css('background-color');
+ $(id_value).css('backgroundColor', '#FFF8C6');
+ $(id_value).animate({backgroundColor: '#ff7f2a'}, 1000).animate({backgroundColor: '#FFF8C6'}, 1000, function(){
+ $(id_value).css('backgroundColor', previous_color);
+ });
+ }
+ }
+
+
+ function initEditor(){
+ $('#editor').TextAreaResizer();
+ //highlight code synctax when editor has new text
+ $("#editor").typeWatch({highlight: false, wait: 3000,
+ captureLength: 5, callback: lanai.highlightSyntax});
+
+ var display = true;
+ var txt = "[{% trans %}hide preview{% endtrans %}]";
+ $('#pre-collapse').text(txt);
+ $('#pre-collapse').bind('click', function(){
+ txt = display ? "[{% trans %}show preview{% endtrans %}]" : "[{% trans %}hide preview{% endtrans %}]";
+ display = !display;
+ $('#previewer').toggle();
+ $('#pre-collapse').text(txt);
+ });
+ setupFormValidation(
+ $("#fmanswer"),
+ CPValidator.getAnswerFormRules(),
+ CPValidator.getAnswerFormMessages()
+ );
+ }
+</script>
+{% include "meta/editor_data.html" %}
diff --git a/askbot/templates/question/new_answer_form.html b/askbot/templates/question/new_answer_form.html
new file mode 100644
index 00000000..76772abf
--- /dev/null
+++ b/askbot/templates/question/new_answer_form.html
@@ -0,0 +1,59 @@
+<form
+ id="fmanswer"
+ action="{% url answer question.id %}"
+ method="post"
+ >{% csrf_token %}
+ {# ==== START: question/subscribe_by_email_prompt.html ==== #}
+ {% include "question/subscribe_by_email_prompt.html" %}
+ {# ==== END: question/subscribe_by_email_prompt.html ==== #}
+ <div style="clear:both"></div>
+ {% if request.user.is_anonymous() and settings.ALLOW_POSTING_BEFORE_LOGGING_IN == False %}
+ {% if not thread.closed %}
+ <a
+ class="submit"
+ href="{{settings.LOGIN_URL}}?next={% url question question.id %}"
+ >{% trans %}Login/Signup to Answer{% endtrans %}</a>
+ {% endif %}
+ {% else %}
+ {% if not thread.closed %}
+ <div>
+ {% spaceless %}
+ <h2>
+ {% if answers %}
+ {% trans %}Your answer{% endtrans %}
+ {% else %}
+ {% trans %}Be the first one to answer this question!{% endtrans %}
+ {% endif %}
+ </h2>
+ {% endspaceless %}
+ </div>
+ {% if request.user.is_anonymous() %}
+ <div class="message">{% trans %}<span class='strong big'>Please start posting your answer anonymously</span> - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a <strong>substantial answer</strong>, for discussions, <strong>please use comments</strong> and <strong>please do remember to vote</strong> (after you log in)!{% endtrans %}</div>
+ {% else %}
+ <p class="message">
+ {% if request.user==question.author %}
+ {% trans %}<span class='big strong'>You are welcome to answer your own question</span>, but please make sure to give an <strong>answer</strong>. Remember that you can always <strong>revise your original question</strong>. Please <strong>use comments for discussions</strong> and <strong>please don't forget to vote :)</strong> for the answers that you liked (or perhaps did not like)!{% endtrans %}
+ {% else %}
+ {% trans %}<span class='big strong'>Please try to give a substantial answer</span>. If you wanted to comment on the question or answer, just <strong>use the commenting tool</strong>. Please remember that you can always <strong>revise your answers</strong> - no need to answer the same question twice. Also, please <strong>don't forget to vote</strong> - it really helps to select the best questions and answers!{% endtrans %}
+ {% endif %}
+ </p>
+ {% endif %}
+ {{ macros.edit_post(
+ answer,
+ user = request.user,
+ editor_type = settings.EDITOR_TYPE
+ )
+ }}
+ <input id="add-answer-btn" type="submit" class="submit after-editor" style="float:left"/>
+ <script type="text/javascript">
+ askbot['functions']['renderAddAnswerButton']();
+ </script>
+ {% if settings.WIKI_ON %}
+ {{ macros.checkbox_in_div(answer.wiki) }}
+ {% endif %}
+ {% if request.user.is_authenticated() and request.user.can_make_group_private_posts() %}
+ {{ macros.checkbox_in_div(answer.post_privately) }}
+ {% endif %}
+ {% endif %}
+ {% endif %}
+</form>
diff --git a/askbot/skins/common/templates/question/question_author_info.html b/askbot/templates/question/question_author_info.html
index c25b7d84..c25b7d84 100644
--- a/askbot/skins/common/templates/question/question_author_info.html
+++ b/askbot/templates/question/question_author_info.html
diff --git a/askbot/templates/question/question_card.html b/askbot/templates/question/question_card.html
new file mode 100644
index 00000000..c787bf34
--- /dev/null
+++ b/askbot/templates/question/question_card.html
@@ -0,0 +1,38 @@
+<div class="vote-buttons">
+ {% include "question/question_vote_buttons.html" %}
+ {% include "question/share_buttons.html" %}
+</div>
+<div id="post-id-{{question.id}}" class="question-content{% if question.deleted %} deleted{% endif %}">
+
+ <h1><a href="{{ question.get_absolute_url() }}">{{ thread.get_title(question)|escape }}</a></h1>
+ {% include "question/question_tags.html" %}
+
+ <div id="question-table">
+ <div class="question-body">
+ <div class="post-update-info-container">
+ {% include "question/question_author_info.html" %}
+ </div>
+ {{ question.html }}
+ </div>
+ <div id="question-controls" class="post-controls">
+ {% include "question/question_controls.html" %}
+ </div>
+ <script type="text/javascript">
+ (function(){
+ if (askbot['data']['userIsAuthenticated'] === false){
+ var ctrl = document.getElementById('question-controls')
+ ctrl.parentNode.removeChild(ctrl);
+ }
+ })();
+ </script>
+ {% if thread.closed %}
+ <div class="clearfix"></div>
+ {# ==== START: question/closed_question_info.html ==== #}
+ {% include "question/closed_question_info.html" %}
+ {# ==== END: question/closed_question_info.html ==== #}
+ {% endif %}
+ {% include "question/question_comments.html" %}
+ </div>
+
+</div>
+
diff --git a/askbot/skins/common/templates/question/question_comments.html b/askbot/templates/question/question_comments.html
index e9d3f724..e9d3f724 100644
--- a/askbot/skins/common/templates/question/question_comments.html
+++ b/askbot/templates/question/question_comments.html
diff --git a/askbot/skins/common/templates/question/question_controls.html b/askbot/templates/question/question_controls.html
index c782d9ad..c782d9ad 100644
--- a/askbot/skins/common/templates/question/question_controls.html
+++ b/askbot/templates/question/question_controls.html
diff --git a/askbot/skins/common/templates/question/question_tags.html b/askbot/templates/question/question_tags.html
index 4b01be81..4b01be81 100644
--- a/askbot/skins/common/templates/question/question_tags.html
+++ b/askbot/templates/question/question_tags.html
diff --git a/askbot/skins/common/templates/question/question_vote_buttons.html b/askbot/templates/question/question_vote_buttons.html
index 6b8774cc..6b8774cc 100644
--- a/askbot/skins/common/templates/question/question_vote_buttons.html
+++ b/askbot/templates/question/question_vote_buttons.html
diff --git a/askbot/skins/common/templates/question/share_buttons.html b/askbot/templates/question/share_buttons.html
index 5b4fc7ac..5b4fc7ac 100644
--- a/askbot/skins/common/templates/question/share_buttons.html
+++ b/askbot/templates/question/share_buttons.html
diff --git a/askbot/skins/default/templates/question/sharing_prompt_phrase.html b/askbot/templates/question/sharing_prompt_phrase.html
index 2e68d1f3..2e68d1f3 100644
--- a/askbot/skins/default/templates/question/sharing_prompt_phrase.html
+++ b/askbot/templates/question/sharing_prompt_phrase.html
diff --git a/askbot/templates/question/sidebar.html b/askbot/templates/question/sidebar.html
new file mode 100644
index 00000000..4d431ef2
--- /dev/null
+++ b/askbot/templates/question/sidebar.html
@@ -0,0 +1,176 @@
+{% import "macros.html" as macros %}
+{% if settings.SIDEBAR_QUESTION_HEADER %}
+<div class="box">
+ {{ settings.SIDEBAR_QUESTION_HEADER }}
+</div>
+{% endif %}
+<div class="box vote-buttons">
+ <h2 >{% trans %}Question tools{% endtrans %}</h2>
+ {% if favorited %}
+ <a class="button followed"
+ alt="{% trans %}click to unfollow this question{% endtrans %}">
+ <div>{% trans %}Following{% endtrans %}</div>
+ <div class='unfollow'>{% trans %}Unfollow{% endtrans %}</div>
+ </a>
+ {% else %}
+ <a class="button followed"
+ alt="{% trans %}click to follow this question{% endtrans %}">
+ {%trans %}Follow{%endtrans%}
+ </a>
+ {% endif %}
+ <div class="clearfix"></div>
+ <div id="favorite-number" class="favorite-number{% if favorited %} my-favorite-number{% endif %}">
+ {% set follower_count = thread.favourite_count %}
+ {% if follower_count > 0 %}
+ {% trans count=follower_count %}{{count}} follower{% pluralize %}{{count}} followers{% endtrans %}
+ {% endif %}
+ </div>
+ <div class="notify-sidebar">
+ {%if request.user.is_authenticated() %}
+ <input
+ type="checkbox"
+ id="question-subscribe-sidebar"
+ {% if thread.is_followed_by(request.user) %}
+ checked="checked"
+ {% endif %}
+ />
+ <label for="question-subscribe-sidebar">{% trans %}email the updates{% endtrans %}</label>
+ {%else%}
+ <input type="checkbox" id="question-subscribe-sidebar"/>
+ <label for="question-subscribe-sidebar">{% trans %}<strong>Here</strong> (once you log in) you will be able to sign up for the periodic email updates about this question.{% endtrans %}</label>
+ {%endif%}
+ <p class="rss">
+ <a
+ href="{{settings.APP_URL}}/feeds/question/{{ question.id }}"
+ title="{% trans %}subscribe to this question rss feed{% endtrans %}"
+ >{% trans %}subscribe to rss feed{% endtrans %}</a>
+ </p>
+ </div>
+</div>
+
+<div class="clearfix"></div>
+{% if settings.GROUPS_ENABLED %}
+<div class="box sharing-widget">
+ {% if thread.is_private() %}
+ <h2>{% trans %}Invite{% endtrans %}</h2>
+ <p style="margin: 16px 0"
+ >Invite others to help answer this question</p>
+ <form action="{% url share_question_with_user %}" method="post">{% csrf_token %}
+ <input id="share_user_name" type="text" class="groups-input" name="recipient_name" />
+ <input type="hidden" name="thread_id" value="{{ thread.id }}"/>
+ <input type="submit" class="add-groups" value="{% trans %}add{% endtrans %}"/>
+ </form>
+ <p class="share-input-col">{% trans %}- or -{% endtrans %}</p>
+ <form action="{% url share_question_with_group %}" method="post">{% csrf_token %}
+ <input id="share_group_name" type="text" class="groups-input" name="recipient_name" />
+ <input type="hidden" name="thread_id" value="{{ thread.id }}"/>
+ <input type="submit" class="add-groups" value="{% trans %}add{% endtrans %}"/>
+ </form>
+ <p class="share-input-col">{% trans %}- or -{% endtrans %}</p>
+ <form action="{% url share_question_with_group %}" method="post">{% csrf_token %}
+ <input
+ type="hidden"
+ name="recipient_name"
+ value="{{ settings.GLOBAL_GROUP_NAME }}"
+ />
+ <input type="hidden" name="thread_id" value="{{ thread.id }}"/>
+ <p class="share-input-col">
+ <input
+ type="submit"
+ class="add-groups add-everyone-group"
+ value="{% trans %}share with everyone{% endtrans %}"
+ />
+ </p>
+ </form>
+
+ {% set shared_users_count = sharing_info['users'].count() %}
+ {% set shared_groups_count = sharing_info['groups'].count() %}
+
+ {% if shared_users_count or shared_groups_count %}
+ <p
+ style="margin:16px 0 4px 0"
+ >{% trans %}This question is currently shared only with:{% endtrans %}</p>
+ {% endif %}
+ <h3>{% trans %}Individual users{% endtrans %}</h3>
+ {% set comma = joiner(',') %}
+ {{ comma() }}
+ <p>
+ <a href="{{ request.user.get_profile_url() }}">
+ {% trans %}You{% endtrans -%}
+ </a>{%- if shared_users_count -%}
+ {%- for user in sharing_info['users'] %}{{ comma() }}
+ {{ user.get_profile_link() }}
+ {%- endfor -%}
+ {% endif -%}
+ {%- if sharing_info['more_users_count'] > 0 %}
+ {% trans %}and{% endtrans %}
+ <a
+ class="see-related-users"
+ data-url="{% url get_thread_shared_users %}"
+ data-thread-id="{{ thread.id }}"
+ >{% trans
+ more_count=sharing_info['more_users_count']
+ %}{{ more_count }} more{% endtrans %}
+ </a>
+ {% endif %}
+ </p>
+
+ {% if shared_groups_count %}
+ <h3>{% trans %}Groups{% endtrans %}</h3>
+ <p>
+ {% set comma = joiner(',') %}
+ {%- for group in sharing_info['groups'] -%}{{ comma() }}
+ {{ macros.user_group_link(group) }}
+ {%- endfor -%}
+ {% if sharing_info['more_groups_count'] > 0 %}
+ {% trans %}and{% endtrans %}
+ <a
+ class="see-related-groups"
+ data-url="{% url get_thread_shared_groups %}"
+ data-thread-id="{{ thread.id }}"
+ >{% trans more_count=sharing_info['more_groups_count'] %}{{ more_count }} more{% endtrans %}
+ </a>
+ {% endif %}
+ </p>
+ {% endif %}
+ {% else %}
+ <h2>{% trans %}Public thread{% endtrans %}</h2>
+ <p>{% trans site_name=settings.APP_SHORT_NAME %}This thread is public, all members of {{ site_name }} can read this page.{% endtrans %}</p>
+ {% endif %}
+</div>
+{% endif %}
+
+{% if settings.SIDEBAR_QUESTION_SHOW_META %}
+<div class="box statsWidget">
+ <div class="clearfix"></div>
+ <h2>{% trans %}Stats{% endtrans %}</h2>
+ <p>
+ {% trans %}Asked{% endtrans %}: <strong>{{ macros.timeago(question.added_at) }}</strong>
+ </p>
+ <p>
+ {% trans %}Seen{% endtrans %}: <strong>{{ thread.view_count|intcomma }} {% trans %}times{% endtrans %}</strong>
+ </p>
+ <p>
+ {% trans %}Last updated{% endtrans %}: <strong title="{{ thread.last_activity_at }}">{{thread.last_activity_at|diff_date}}</strong>
+ </p>
+</div>
+{% endif %}
+
+{% if similar_threads.data() and settings.SIDEBAR_QUESTION_SHOW_RELATED %}
+ {#% cache 1800 "related_questions" related_questions question.id language_code %#}
+ <div class="box">
+ <h2>{% trans %}Related questions{% endtrans %}</h2>
+ <div class="questions-related">
+ {% for thread_dict in similar_threads.data() %}
+ <p>
+ <a href="{{ thread_dict.url }}">{{ thread_dict.title|escape }}</a>
+ </p>
+ {% endfor %}
+ </div>
+ </div>
+ {#% endcache %#}
+{% endif %}
+
+<div class="box">
+ {{ settings.SIDEBAR_QUESTION_FOOTER }}
+</div>
diff --git a/askbot/skins/default/templates/question/subscribe_by_email_prompt.html b/askbot/templates/question/subscribe_by_email_prompt.html
index 6a77601c..6a77601c 100644
--- a/askbot/skins/default/templates/question/subscribe_by_email_prompt.html
+++ b/askbot/templates/question/subscribe_by_email_prompt.html
diff --git a/askbot/templates/question_edit.html b/askbot/templates/question_edit.html
new file mode 100644
index 00000000..f176b11d
--- /dev/null
+++ b/askbot/templates/question_edit.html
@@ -0,0 +1,114 @@
+{% extends "two_column_body.html" %}
+{% import "macros.html" as macros %}
+<!-- question_edit.html -->
+{% block title %}{% spaceless %}{% trans %}Edit question{% endtrans %}{% endspaceless %}{% endblock %}
+{% block forestyle %}
+ <link rel="stylesheet" type="text/css" href="{{"/js/wmd/wmd.css"|media}}" />
+{% endblock %}
+{% block content %}
+<div class="section-title">{% trans %}Edit question{% endtrans %} [<a href="{{ question.get_absolute_url() }}">{% trans %}back{% endtrans %}</a>]</div>
+<form id="fmedit" action="{% url edit_question question.id %}" method="post" >{% csrf_token %}
+
+ {% if revision_form.revision.errors %}{{ revision_form.revision.errors.as_ul() }}{% endif %}
+ <div style="vertical-align:middle">
+ {{ revision_form.revision }} <input type="hidden"
+ id="select_revision"
+ name="select_revision"
+ value="false">
+ </div>
+ {% set use_category_selector = (settings.TAG_SOURCE == 'category-tree') %}
+ {{
+ macros.edit_post(
+ form,
+ post_type = 'question',
+ post_html = revision.text,
+ edit_title = True,
+ mandatory_tags = mandatory_tags,
+ use_category_selector = use_category_selector,
+ tag_names = tag_names,
+ editor_type = settings.EDITOR_TYPE,
+ user = request.user
+ )
+ }}
+ <div class="after-editor">
+ <div class="question-options">
+ {% if settings.WIKI_ON and question.wiki == False %}
+ {{ macros.checkbox_in_div(form.wiki) }}
+ {% endif %}
+ {% if form.can_stay_anonymous() %}
+ {{ macros.checkbox_in_div(form.reveal_identity) }}
+ {% endif %}
+ {% if request.user.is_authenticated() and request.user.can_make_group_private_posts() %}
+ {{ macros.checkbox_in_div(form.post_privately) }}
+ {% endif %}
+ </div>
+ <input id="edit_post_form_submit_button" type="submit" value="{% trans %}Save edit{% endtrans %}" class="submit" />&nbsp;
+ <input type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" onclick="history.back(-1);" />
+
+ </div>
+</form>
+{% endblock %}
+
+{% block sidebar %}
+{% include "widgets/question_edit_tips.html" %}
+{% endblock %}
+
+{% block endjs %}
+ {% include "meta/editor_data.html" %}
+ <script type='text/javascript' src='{{"/js/editor.js"|media }}'></script>
+ {% if mandatory_tags %}
+ {% include "meta/mandatory_tags_js.html" %}
+ {% endif %}
+ <script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
+ <script type='text/javascript' src='{{"/js/post.js"|media}}'></script>
+ {% if settings.EDITOR_TYPE == 'markdown' %}
+ <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script>
+ <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script>
+ {% endif %}
+ <script type="text/javascript">
+ {% if settings.ENABLE_MATHJAX or settings.MARKUP_CODE_FRIENDLY %}
+ var codeFriendlyMarkdown = true;
+ {% else %}
+ var codeFriendlyMarkdown = false;
+ {% endif %}
+ //todo move javascript out
+ $().ready(function(){
+ $("#nav_questions").attr('className',"on");
+
+ $('#editor').TextAreaResizer();
+ //highlight code synctax when editor has new text
+ $("#editor").typeWatch({highlight: false, wait: 3000,
+ captureLength: 5, callback: lanai.highlightSyntax});
+
+ //toggle preview of editor
+ var display = true;
+ var txt = "[{% trans %}hide preview{% endtrans %}]";
+ $('#pre-collapse').text(txt);
+ $('#pre-collapse').bind('click', function(){
+ txt = display ? "[{% trans %}show preview{% endtrans %}]" : "[{% trans %}hide preview{% endtrans %}]";
+ display = !display;
+ $('#previewer').toggle();
+ $('#pre-collapse').text(txt);
+ });
+
+ {{ macros.tag_autocomplete_js(id = '#id_tags') }}
+
+ setupFormValidation(
+ $("#fmedit"),
+ CPValidator.getQuestionFormRules(),
+ CPValidator.getQuestionFormMessages()
+ );
+
+ $('#id_revision').unbind().change(function(){
+ $("#select_revision").val('true');
+ $('#edit_post_form_submit_button').click();
+ });
+ lanai.highlightSyntax();
+
+ });
+ </script>
+ {% if settings.TAG_SOURCE == 'category-tree' %}
+ {% include "meta/category_tree_js.html" %}
+ {% endif %}
+{% endblock %}
+<!-- end question_edit.html -->
diff --git a/askbot/skins/default/templates/question_retag.html b/askbot/templates/question_retag.html
index c42b42f8..c42b42f8 100644
--- a/askbot/skins/default/templates/question_retag.html
+++ b/askbot/templates/question_retag.html
diff --git a/askbot/templates/reopen.html b/askbot/templates/reopen.html
new file mode 100644
index 00000000..4ddd6f31
--- /dev/null
+++ b/askbot/templates/reopen.html
@@ -0,0 +1,39 @@
+{% extends "two_column_body.html" %}
+{% from "macros.html" import timeago %}
+<!-- reopen.html -->
+{% block title %}{% spaceless %}{% trans %}Reopen question{% endtrans %}{% endspaceless %}{% endblock %}
+{% block content %}
+<h1>{% trans %}Reopen question{% endtrans %}</h1>
+<p>{% trans %}Title{% endtrans %}:
+ <a href="{{ question.get_absolute_url() }}">
+ <span class="big">{{ question.get_question_title()|escape }}</span>
+ </a>
+</p>
+<p>{% trans username = closed_by_username|escape %}This question has been closed by
+ <a href="{{closed_by_profile_url}}">{{username}}</a>
+{% endtrans %}
+</p>
+<p>
+ {% trans %}Close reason:{% endtrans %} "<strong>{{question.thread.get_close_reason_display()}}</strong>".
+</p>
+<p>
+ {% trans %}When:{% endtrans %} {{ timeago(question.thread.closed_at) }}
+</p>
+<p>
+ {% trans %}Reopen this question?{% endtrans %}
+</p>
+<form id="fmclose" action="{% url reopen question.id %}" method="post" >{% csrf_token %}
+ <div id="" style="padding:20px 0 20px 0">
+ <input type="submit" value="{% trans %}Reopen this question{% endtrans %}" class="submit" />&nbsp;
+ <input id="btBack" type="button" value="{% trans %}Cancel{% endtrans %}" class="submit" />
+ </div>
+</form>
+{% endblock %}
+{% block endjs %}
+ <script type="text/javascript">
+ $().ready(function(){
+ $('#btBack').bind('click', function(){ history.back(); });
+ });
+ </script>
+{% endblock %}
+<!-- end reopen.html -->
diff --git a/askbot/templates/revisions.html b/askbot/templates/revisions.html
new file mode 100644
index 00000000..a0531b80
--- /dev/null
+++ b/askbot/templates/revisions.html
@@ -0,0 +1,101 @@
+{% extends "two_column_body.html" %}
+{% import "macros.html" as macros %}
+<!-- revisions.html -->
+{% block title %}{% spaceless %}{% trans %}Revision history{% endtrans %}{% endspaceless %}{% endblock %}
+{% block content %}
+<h1 class="section-title">
+ {% trans %}Revision history{% endtrans %} [<a href="{{ post.get_absolute_url() }}">{% trans %}back{% endtrans %}</a>]
+</h1>
+<div id="revisions">
+{% for revision in revisions %}
+ <div class="revision">
+ <div
+ id="rev-header-{{ revision.revision }}"
+ class="header {% if post.author_id == revision.author_id %}author{% endif %}"
+ >
+ <div class="header-controls">
+ <table width="100%">
+ <tr>
+ <td width="20" style="vertical-align:middle">
+ <img
+ id="rev-arrow-{{ revision.revision }}"
+ src="{{"/images/expander-arrow-hide.gif"|media}}"
+ alt="{% trans %}click to hide/show revision{% endtrans %}"
+ />
+ </td>
+ <td width="30px" style="vertical-align:middle">
+ <span
+ class="revision-number"
+ title="{% trans number=revision.revision %}revision {{number}}{% endtrans %}">{{ revision.revision }}</span></td>
+ <td width="200px" style="vertical-align:middle">
+ {% if revision.summary %}
+ <div class="summary">
+ <span>{{ revision.summary|escape }}</span>
+ </div>
+ {% endif %}
+ {% if request.user|can_edit_post(post) %}
+ {% if post.post_type == 'answer' %}
+ <a href="{% url edit_answer post.id %}?revision={{ revision.revision }}">{% trans %}edit{% endtrans %}</a>
+ {% endif %}
+ {% if post.post_type == 'question' %}
+ <a href="{% url edit_question post.id %}?revision={{ revision.revision }}">{% trans %}edit{% endtrans %}</a>
+ {% endif %}
+ {% endif %}
+ </td>
+ <td align="right">
+ <div class="revision-mark" >
+ {% if revision.revision == 1 %}
+ {% set contributor_type = "original_author" %}
+ {% else %}
+ {% set contributor_type = "last_updater" %}
+ {% endif %}
+ {{ macros.post_contributor_info(
+ revision.post,
+ contributor_type,
+ False,
+ 0
+ )
+ }}
+ </div>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div id="rev-body-{{ revision.revision }}" class="answerbody">
+ {{ revision.diff }}
+ </div>
+ </div>
+{% endfor %}
+</div>
+{% endblock %}
+
+{% block endjs %}
+ <script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
+ <script type='text/javascript' src='{{"/js/post.js"|media}}'></script>
+ <script type="text/javascript">
+ //todo - take this out into .js file
+ $(document).ready(function(){
+ $("#nav_questions").attr('className',"on");
+ $('div.revision div[id^=rev-header-]').bind('click', function(){
+ var revId = this.id.substr(11);
+ toggleRev(revId);
+ });
+ lanai.highlightSyntax();
+ });
+
+ function toggleRev(id) {
+ var arrow = $("#rev-arrow-" + id);
+ var visible = arrow.attr("src").indexOf("hide") > -1;
+ if (visible) {
+ var image_path = '{{ "/images/expander-arrow-show.gif"|media }}';
+ } else {
+ var image_path = '{{ "/images/expander-arrow-hide.gif"|media }}';
+ }
+ image_path = image_path + "?v={{settings.MEDIA_RESOURCE_REVISION}}";
+ arrow.attr("src", image_path);
+ $("#rev-body-" + id).slideToggle("fast");
+ }
+</script>
+{% endblock %}
+<!-- end revisions.html -->
diff --git a/askbot/skins/default/templates/static_page.html b/askbot/templates/static_page.html
index c537e199..c537e199 100644
--- a/askbot/skins/default/templates/static_page.html
+++ b/askbot/templates/static_page.html
diff --git a/askbot/skins/default/templates/subscribe_for_tags.html b/askbot/templates/subscribe_for_tags.html
index b436fb84..b436fb84 100644
--- a/askbot/skins/default/templates/subscribe_for_tags.html
+++ b/askbot/templates/subscribe_for_tags.html
diff --git a/askbot/templates/tags.html b/askbot/templates/tags.html
new file mode 100644
index 00000000..e9049e8e
--- /dev/null
+++ b/askbot/templates/tags.html
@@ -0,0 +1,55 @@
+{% extends "two_column_body.html" %}
+{% import "macros.html" as macros %}
+<!-- tags.html -->
+{% block title %}{% spaceless %}{% trans %}Tags{% endtrans %}{% endspaceless %}{% endblock %}
+{% block content %}
+<!-- Tabs -->
+{% include "tags/header.html" %}
+{% if tag_list_type == 'list' %}
+ {% if not tags.object_list %}
+ <span>{% trans %}Nothing found{% endtrans %}</span>
+ {% endif %}
+ {% if tags.object_list %}
+ <div class='clearfix'></div>
+ <ul class='tags'>
+ {% for tag in tags.object_list %}
+ <li>
+ {{ macros.tag_widget(
+ tag = tag.name,
+ html_tag = 'div',
+ truncate_long_tag = True,
+ extra_content = '<span class="tag-number">&#215; ' ~
+ tag.used_count|intcomma ~ '</span>'
+ )
+ }}
+ </li>
+ {% endfor %}
+ </ul>
+ <div class="clean"></div>
+ <div class="pager">
+ {{macros.paginator(paginator_context)}}
+ </div>
+ {% endif %}
+{% else %}
+ <div class="clearfix"></div>
+ {% if not tags %}
+ <span>{% trans %}Nothing found{% endtrans %}</span>
+ {% endif %}
+ {{ macros.tag_cloud(tags = tags, font_sizes = font_size, search_state = search_state) }}
+{% endif %}
+
+{% endblock %}
+{% block endjs %}
+ <script type="text/javascript">
+ /*<![CDATA[*/
+ $().ready(function(){
+ $("#ipSearchTag").focus();
+ $("#type-tag").attr('checked',true);
+ Hilite.exact = false;
+ Hilite.elementid = "searchtags";
+ Hilite.debug_referrer = location.href;
+ });
+ /*]]>*/
+ </script>
+{% endblock %}
+<!-- end tags.html -->
diff --git a/askbot/templates/tags/header.html b/askbot/templates/tags/header.html
new file mode 100644
index 00000000..9f1d73e4
--- /dev/null
+++ b/askbot/templates/tags/header.html
@@ -0,0 +1,38 @@
+<div id="content-header">
+ {% if page_title %}
+ <h1 class="section-title">{{ page_title }}</h1>
+ {% else %}
+ {% if stag %}
+ <h1 class="section-title">{% trans %}Tags, matching "{{ stag }}"{% endtrans %}</h1>
+ {% else %}
+ <h1 class="section-title">{% trans %}Tags{% endtrans %}</h1>
+ {% endif %}
+ {% endif %}
+ <div class="tabBar tabBar-tags">
+ <div class="tabsA">
+ <span class="label">{% trans %}Sort by &raquo;{% endtrans %}</span>
+ <a
+ id="sort_name"
+ href="{% url tags %}?sort=name"
+ {% if tab_id == 'name' %}class="on"{% endif %}
+ title="{% trans %}sorted alphabetically{% endtrans %}"
+ ><span>{% trans %}by name{% endtrans %}</span></a>
+ <a
+ id="sort_used"
+ href="{% url tags %}?sort=used"
+ {% if tab_id == 'used' %}class="on"{% endif %}
+ title="{% trans %}sorted by frequency of tag use{% endtrans %}"
+ ><span>{% trans %}by popularity{% endtrans %}</span></a>
+ {% if settings.ENABLE_TAG_MODERATION %}
+ {% if request.user.is_authenticated() and request.user.is_administrator_or_moderator() %}
+ <a
+ href="{% url list_suggested_tags %}"
+ {% if tab_id == 'suggested' %}class="on"{% endif %}
+ title="{% trans %}suggested{% endtrans %}"
+ ><span>{% trans %}suggested{% endtrans %}</span></a>
+ {% endif %}
+ {% endif %}
+ </div>
+ </div>
+</div>
+<div class="clearfix"></div>
diff --git a/askbot/skins/common/templates/two_column_body.html b/askbot/templates/two_column_body.html
index 4c3193be..4c3193be 100644
--- a/askbot/skins/common/templates/two_column_body.html
+++ b/askbot/templates/two_column_body.html
diff --git a/askbot/templates/user_inbox/base.html b/askbot/templates/user_inbox/base.html
new file mode 100644
index 00000000..8beababc
--- /dev/null
+++ b/askbot/templates/user_inbox/base.html
@@ -0,0 +1,65 @@
+{% extends "user_profile/user.html" %}
+{% block before_css %}
+ <link href="{{'/bootstrap/css/bootstrap.css'|media}}" rel="stylesheet" type="text/css" />
+{% endblock %}
+{% block profilesection %}
+ {% trans %}inbox{% endtrans %}
+{% endblock %}
+{% block usercontent %}
+<div style="padding-top:5px;font-size:13px;">
+ {% set re_count = request.user.new_response_count +
+ request.user.seen_response_count
+ %}
+ <div id="re_sections">
+ {% trans %}Sections:{% endtrans %}
+ {% set sep = joiner('|') %}
+ {#{ sep() }}
+ <a href="{{request.user.get_absolute_url()}}?sort=inbox&section=messages"
+ {% if inbox_section == 'messages' %}class="on"{% endif %}
+ >{% trans %}messages{% endtrans %}</a>#}
+ {% if re_count > 0 %}{{ sep() }}
+ <a href="{{request.user.get_absolute_url()}}?sort=inbox&section=forum"
+ {% if inbox_section == 'forum' %}class="on"{% endif %}
+ >
+ {% trans %}forum responses ({{re_count}}){% endtrans -%}
+ </a>
+ {% endif %}
+ {% if flags_count > 0 %}{{ sep() }}
+ <a href="{{request.user.get_absolute_url()}}?sort=inbox&section=flags"
+ {% if inbox_section == 'flags' %}class="on"{% endif %}
+ >
+ {% trans %}flagged items ({{flags_count}}){% endtrans %}
+ </a>
+ {% endif %}
+ {% if group_join_requests_count %}{{ sep() }}
+ <a href="{{request.user.get_absolute_url()}}?sort=inbox&section=join_requests"
+ {% if inbox_section == 'join_requests' %}class="on"{% endif %}
+ >
+ {% trans %}group join requests{% endtrans %}
+ </a>
+ {% endif %}
+ </div>
+ {% block inbox_content %}
+ {% endblock %}
+</div>
+{% endblock %}
+{% block userjs %}
+ <script type="text/javascript">
+ var askbot = askbot || {};
+ askbot['urls'] = askbot['urls'] || {};
+ askbot['urls']['manageInbox'] = '{% url manage_inbox %}';
+ askbot['urls']['save_post_reject_reason'] = '{% url save_post_reject_reason %}';
+ askbot['urls']['delete_post_reject_reason'] = '{% url delete_post_reject_reason %}';
+ {% if request.user.is_administrator_or_moderator() %}
+ askbot['data']['postRejectReasons'] = [
+ {% for reason in post_reject_reasons %}
+ {'id': {{reason.id}}, 'title': '{{reason.title|escapejs}}'},
+ {% endfor %}
+ ];
+ {% endif %}
+ $(document).ready(function(){
+ $('body').addClass('inbox-{{ inbox_section }}');
+ setup_inbox();
+ });
+ </script>
+{% endblock %}
diff --git a/askbot/templates/user_inbox/group_join_requests.html b/askbot/templates/user_inbox/group_join_requests.html
new file mode 100644
index 00000000..2defe5e1
--- /dev/null
+++ b/askbot/templates/user_inbox/group_join_requests.html
@@ -0,0 +1,50 @@
+{% extends "user_inbox/base.html" %}
+{% import "macros.html" as macros %}
+{% block profilesection %}
+ {% trans %}inbox - group join requests{% endtrans %}
+{% endblock %}
+{% block inbox_content %}
+ <table>
+ {% for join_request in join_requests %}
+ <tr>
+ <td>{% trans
+ user=join_request.user,
+ group=groups_dict[join_request.object_id].name
+ %}{{ user }} wants to join group {{ group }}{% endtrans %}
+ </td>
+ <td>{# forms with accept and reject buttons #}
+ <form action="{% url moderate_group_join_request %}" method="post"
+ >{% csrf_token %}
+ <input
+ type="hidden"
+ name="request_id"
+ value="{{join_request.id}}"
+ />
+ <input type="hidden" name="action" value="approve"/>
+ <input
+ class="btn"
+ type="submit"
+ value="{% trans %}Approve{% endtrans %}"
+ />
+ </form>
+ </td>
+ <td>
+ <form action="{% url moderate_group_join_request %}" method="post">
+ {% csrf_token %}
+ <input
+ type="hidden"
+ name="request_id"
+ value="{{join_request.id}}"
+ />
+ <input type="hidden" name="action" value="deny"/>
+ <input
+ class="btn"
+ type="submit"
+ value="{% trans %}Deny{% endtrans %}"
+ />
+ </form>
+ </td>
+ </tr>
+ {% endfor %}
+ </table>
+{% endblock %}
diff --git a/askbot/templates/user_inbox/messages.html b/askbot/templates/user_inbox/messages.html
new file mode 100644
index 00000000..5108d15e
--- /dev/null
+++ b/askbot/templates/user_inbox/messages.html
@@ -0,0 +1,100 @@
+{% extends "user_inbox/base.html" %}
+{% import "macros.html" as macros %}
+{% block before_css %}
+ {{ super() }}
+ <style type="text/css">
+ .group-messaging {
+ padding-top: 25px;
+ }
+ ul.senders-list {
+ padding: 0px;
+ margin-left: 1em;
+ margin-top: 0.5em;
+ }
+ .senders-list li {
+ height: 1.5em;
+ vertical-align: center;
+ list-style-type: none;
+ list-style-position: outside;
+ }
+ .senders-list .selected {
+ font-weight: bold;
+ }
+ table.threads-list {
+ width: 100%;
+ }
+ .threads-list tr {
+ height: 2em;
+ }
+ .threads-list td {
+ vertical-align: center;
+ }
+ .threads-list tr.new {
+ font-weight: bold;
+ color: #777;
+ }
+ .threads-list tr:hover {
+ background-color: #eff5f6;
+ }
+ td.empty {
+ line-height: 30px;
+ vertical-align: middle;
+ background: #eee;
+ padding-left: 320px;
+ margin: 0px;
+ }
+ td.senders {
+ padding-left: 10px;
+ }
+ td.timestamp {
+ width: 180px;
+ }
+ button.compose {
+ width: 150px;
+ }
+ .first-col, .second-col {
+ float: left;
+ min-height: 45px;
+ }
+ .first-col {
+ width: 150px;
+ }
+ .second-col {
+ width: 790px;
+ margin-left: 20px;
+ }
+ .message-composer {
+ padding-bottom: 10px;
+ margin-top: -25px;
+ }
+ .reply-composer .message-composer {
+ margin-top: 0;
+ }
+ .message-composer input.recipients,
+ .message-composer textarea {
+ width: 400px;
+ display: block;
+ }
+ .message-composer input.recipients {
+ border: #CCE6EC 3px solid;
+ padding: 5px 0 5px 5px;
+ font-size: 14px;
+ }
+ .message-composer textarea {
+ height: 200px;
+ margin-bottom: 10px;
+ }
+ .message-composer label.errors {
+ padding-left: 5px;
+ }
+ </style>
+{% endblock %}
+{% block profilesection %}
+ {% trans %}inbox - messages{% endtrans %}
+{% endblock %}
+{% block inbox_content %}
+ {% include "group_messaging/home.html" %}
+{% endblock %}
+{% block userjs %}
+ <script type="text/javascript" src="{{ 'js/group_messaging.js'|media }}"></script>
+{% endblock %}
diff --git a/askbot/templates/user_inbox/responses_and_flags.html b/askbot/templates/user_inbox/responses_and_flags.html
new file mode 100644
index 00000000..c889bb0a
--- /dev/null
+++ b/askbot/templates/user_inbox/responses_and_flags.html
@@ -0,0 +1,43 @@
+{% extends "user_inbox/base.html" %}
+{% import "macros.html" as macros %}
+{% block profilesection %}
+ {% trans %}inbox - responses{% endtrans %}
+{% endblock %}
+{% block inbox_content %}
+ <div id="re_tools">
+ <strong>{% trans %}select:{% endtrans %}</strong>
+ <a id="sel_all">{% trans %}all{% endtrans %}</a> |
+ <a id="sel_seen">{% trans %}seen{% endtrans %}</a> |
+ <a id="sel_new">{% trans %}new{% endtrans %}</a> |
+ <a id="sel_none">{% trans %}none{% endtrans %}</a><br />
+ <div class="btn-group">
+ {% if inbox_section == 'forum' %}
+ <a class="btn" id="re_mark_seen">{% trans %}mark as seen{% endtrans %}</a>
+ <a class="btn" id="re_mark_new">{% trans %}mark as new{% endtrans %}</a>
+ <a class="btn" id="re_dismiss">{% trans %}dismiss{% endtrans %}</a>
+ {% else %}
+ <a class="btn" id="re_remove_flag">{% trans %}remove flags/approve{% endtrans %}</a>
+ <a
+ class="btn"
+ id="re_delete_post"
+ >{% trans %}delete post{% endtrans %}</a>
+ {% endif %}
+ </div>
+ </div>
+ {% include "user_profile/reject_post_dialog.html" %}
+ <div id="responses">
+ {% for response in responses %}
+ <div class="response-parent" data-response-id="{{response.id}}">
+ <p class="headline">
+ <strong>"{{ response.response_title.strip()|escape}}"</strong>
+ </p>
+ {{ macros.inbox_post_snippet(response, inbox_section) }}
+ {% for nested_response in response.nested_responses %}
+ {{ macros.inbox_post_snippet(nested_response, inbox_section) }}
+ {%endfor%}
+ </div>
+ <div class="clearfix"></div>
+ {% endfor %}
+ </div>
+ </div>
+{% endblock %}
diff --git a/askbot/skins/default/templates/user_profile/custom_tab.html b/askbot/templates/user_profile/custom_tab.html
index bc5647f7..bc5647f7 100644
--- a/askbot/skins/default/templates/user_profile/custom_tab.html
+++ b/askbot/templates/user_profile/custom_tab.html
diff --git a/askbot/skins/default/templates/user_profile/macros.html b/askbot/templates/user_profile/macros.html
index ac573553..ac573553 100644
--- a/askbot/skins/default/templates/user_profile/macros.html
+++ b/askbot/templates/user_profile/macros.html
diff --git a/askbot/templates/user_profile/reject_post_dialog.html b/askbot/templates/user_profile/reject_post_dialog.html
new file mode 100644
index 00000000..3483e83e
--- /dev/null
+++ b/askbot/templates/user_profile/reject_post_dialog.html
@@ -0,0 +1,109 @@
+<div class="modal" style="display:none" id="reject-edit-modal">
+ <div class="modal-header">
+ <a class="close" data-dismiss="modal">x</a>
+ <h3>{% trans %}Reject the post(s)?{% endtrans %}</h3>
+ </div>
+ <div id="reject-edit-modal-add-new">{# create new reject reason #}
+ <div class="modal-body">
+ <input
+ class="reject-reason-title tipped-input blank"
+ type="text"
+ value="{% trans %}1) Enter a brief description of why you are rejecting the post.{% endtrans %}"
+ />
+ <textarea class="reject-reason-details tipped-input blank"
+ >{% trans %}2) Please enter details here. This text will be sent to the user.{% endtrans %}</textarea>
+ </div>
+ <div class="modal-footer">
+ <div class="btn-toolbar">
+ <div class="btn-group dropup">
+ <button class="btn btn-danger save-reason-and-reject"
+ >{% trans %}Use this reason &amp; reject{% endtrans %}</button>
+ <button class="btn btn-danger dropdown-toggle" data-toggle="dropdown">
+ <span class="caret"></span>
+ </button>
+ <ul class="dropdown-menu">
+ <li>
+ <a class="select-other-reason" href="#"
+ >{% trans %}Use other reason{% endtrans %}</a>
+ </li>
+ </ul>
+ </div>
+ <div class="btn-group">
+ <a class="btn save-reason"
+ >{% trans %}Save reason, but do not reject{% endtrans %}</a>
+ </div>
+ <div class="btn-group">
+ <a class="btn cancel">{% trans %}Cancel{% endtrans %}</a>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id="reject-edit-modal-select">{# select one of existing reasons #}
+ <div class="modal-body">
+ <p>{% trans %}Please, choose a reason for the rejection.{% endtrans %}</p>
+ <ul class="select-box">
+ {% for reason in post_reject_reasons %}
+ <li
+ class="select-box-item"
+ data-original-title="{{reason.details.text|escape}}"
+ data-item-id="{{reason.id}}"
+ >{{reason.title|escape}}</li>
+ {% endfor %}
+ </ul>
+ </div>
+ <div class="modal-footer">
+ <div class="btn-toolbar">
+ <div class="btn-group dropup">
+ <a class="btn select-this-reason"
+ >{% trans %}Select this reason{% endtrans %}</a>
+ <a class="btn dropdown-toggle" data-toggle="dropdown">
+ <span class="caret"></span>
+ </a>
+ <ul class="dropdown-menu">
+ <li>
+ <a class="delete-this-reason"
+ >{% trans %}Delete this reason{% endtrans %}</a>
+ </li>
+ </ul>
+ </div>
+ <div class="btn-group">
+ <a class="btn add-new-reason"
+ >{% trans %}Add a new reason{% endtrans %}</a>
+ </div>
+ <div class="btn-group">
+ <a class="btn cancel">{% trans %}Cancel{% endtrans %}</a>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id="reject-edit-modal-preview">{# preview reject reason #}
+ <div class="modal-body">
+ <p>{% trans %}You have selected reason for the rejection <strong>"<span class="selected-reason-title"></span>"</strong>. The text below will be sent to the user and the post(s) will be deleted:{% endtrans %}</p>
+ <textarea disabled="disabled" class="selected-reason-details"></textarea>
+ </div>
+ <div class="modal-footer">
+ <div class="btn-toolbar">
+ <div class="btn-group dropup">
+ <a class="btn btn-danger reject"
+ >{% trans %}Use this reason &amp; reject{% endtrans %}</a>
+ <a class="btn btn-danger dropdown-toggle" data-toggle="dropdown">
+ <span class="caret"></span>
+ </a>
+ <ul class="dropdown-menu">
+ <li>
+ <a class="select-other-reason"
+ >{% trans %}Use other reason{% endtrans %}</a>
+ </li>
+ </ul>
+ </div>
+ <div class="btn-group">
+ <a class="btn edit-reason"
+ >{% trans %}Edit this reason{% endtrans %}</a>
+ </div>
+ <div class="btn-group">
+ <a class="btn cancel">{% trans %}Cancel{% endtrans %}</a>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/askbot/templates/user_profile/user.html b/askbot/templates/user_profile/user.html
new file mode 100644
index 00000000..3aee3cfa
--- /dev/null
+++ b/askbot/templates/user_profile/user.html
@@ -0,0 +1,46 @@
+{% extends "one_column_body.html" %}
+<!-- user.html -->
+{% block title %}{% spaceless %}{{ page_title }}{% endspaceless %}{% endblock %}
+{% block forestyle %}
+<style type="text/css">
+ .history-table td { padding: 5px; }
+</style>
+{% endblock %}
+{% block content %}
+ <h1 class="section-title">
+ {% spaceless %}
+ {% trans username=view_user.username|escape %}{{username}}'s profile{% endtrans %} - {% block profilesection %}{% endblock %}
+ {% endspaceless %}
+ </h1>
+ {% include "user_profile/user_tabs.html" %}
+ <div>
+ {% block usercontent %}
+ {% endblock %}
+ </div>
+{% endblock %}<!-- end user.html -->
+{% block endjs %}
+ <script type="text/javascript">
+ var viewUserID = {{view_user.id}};
+ askbot['data']['viewUserName'] = '{{ view_user.username|escape }}';
+ askbot['data']['viewUserId'] = {{view_user.id}};
+ askbot['urls']['edit_group_membership'] = '{% url edit_group_membership %}';
+ askbot['urls']['getGroupsList'] = '{% url get_groups_list %}';
+ </script>
+ {% if request.user|can_moderate_user(view_user) %}
+ <script type='text/javascript' src='{{"/js/jquery.form.js"|media}}'></script>
+ {% endif %}
+ <script type="text/javascript" src='{{"/js/user.js"|media}}'></script>
+ <script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
+ <script type="text/javascript" src='{{"/js/post.js"|media}}'></script>
+ {% block userjs %}
+ {% endblock %}
+{% endblock %}
+{% block sidebar %}
+<div class="box">
+ {{ settings.SIDEBAR_PROFILE_HEADER }}
+</div>
+<div class="box">
+ {{ settings.SIDEBAR_PROFILE_FOOTER }}
+</div>
+{% endblock %}
+<!-- end of user.html -->
diff --git a/askbot/skins/default/templates/user_profile/user_edit.html b/askbot/templates/user_profile/user_edit.html
index c95bf815..c95bf815 100644
--- a/askbot/skins/default/templates/user_profile/user_edit.html
+++ b/askbot/templates/user_profile/user_edit.html
diff --git a/askbot/skins/default/templates/user_profile/user_email_subscriptions.html b/askbot/templates/user_profile/user_email_subscriptions.html
index f44e8a1e..f44e8a1e 100644
--- a/askbot/skins/default/templates/user_profile/user_email_subscriptions.html
+++ b/askbot/templates/user_profile/user_email_subscriptions.html
diff --git a/askbot/skins/default/templates/user_profile/user_favorites.html b/askbot/templates/user_profile/user_favorites.html
index 08c3c688..08c3c688 100644
--- a/askbot/skins/default/templates/user_profile/user_favorites.html
+++ b/askbot/templates/user_profile/user_favorites.html
diff --git a/askbot/templates/user_profile/user_info.html b/askbot/templates/user_profile/user_info.html
new file mode 100644
index 00000000..89f06321
--- /dev/null
+++ b/askbot/templates/user_profile/user_info.html
@@ -0,0 +1,121 @@
+<!-- user_info.html -->
+{% import "macros.html" as macros %}
+<table class="user-info-table">
+ <tr>
+ <td style="vertical-align:top;text-align:center;">
+ <div class='avatar'>
+ {{ macros.gravatar(view_user, 128) }}
+ {% if request.user == view_user %}
+ <p><a
+ {% if support_custom_avatars %}
+ href="{% url avatar_change %}"
+ {% else %}
+ href="{% url faq %}#gravatar"
+ {% endif %}
+ >{% trans %}change picture{% endtrans %}</a></p>
+ {% if support_custom_avatars %}
+ <p><a
+ href="{% url avatar_delete %}"
+ >{% trans %}remove{% endtrans %}</a>
+ </p>
+ {% endif %}
+ {% endif %}
+ </div>
+ {% if can_show_karma %}
+ <div class="scoreNumber">{{view_user.reputation|intcomma}}</div>
+ <p><b style="color:#777;">{% trans %}karma{% endtrans %}</b></p>
+ {% endif %}
+ {% if user_follow_feature_on %}
+ {{ macros.follow_user_toggle(visitor = request.user, subject = view_user) }}
+ {% endif %}
+ </td>
+ <td width="360" style="padding-left:5px;vertical-align: top;">
+ <table class="user-details">
+ {% if request.user == view_user %}
+ <tr>
+ <td class="user-profile-tool-links" align="left" colspan="2">
+ <a href="{% url edit_user view_user.id %}">
+ {% trans %}update profile{% endtrans %}
+ </a>
+ {% if settings.USE_ASKBOT_LOGIN_SYSTEM and request.user == view_user and settings.ALLOW_ADD_REMOVE_LOGIN_METHODS %}
+ | <a href="{{ settings.LOGIN_URL }}?next={{ settings.LOGIN_URL }}">
+ {% trans %}manage login methods{% endtrans %}
+ </a>
+ {% endif %}
+ </td>
+ </tr>
+ {% endif %}
+ <tr>
+ <th colspan="2" align="left">
+ <h3>{{user_status_for_display}}</h3>
+ </th>
+ </tr>
+ {% if view_user.real_name %}
+ <tr>
+ <td>{% trans %}real name{% endtrans %}</td>
+ <td><b>{{view_user.real_name}}</b></td>
+ </tr>
+ {% endif %}
+ {% if settings.GROUPS_ENABLED %}
+ <tr>
+ <td>{% if user_groups %}{% trans %}groups{% endtrans %}{% endif %}</td>
+ <td>
+ <table id="groups-list">
+ {% for group in user_groups %}
+ <tr>
+ {{ macros.user_group(group, groups_membership_info[group.id]) }}
+ </tr>
+ {% endfor %}
+ </table>
+ <div class="clearfix"></div>
+ <a id="add-group">{% trans %}add group{% endtrans %}</a>
+ </td>
+ </div>
+ {% endif %}
+ <tr>
+ <td>{% trans %}member since{% endtrans %}</td>
+ <td><strong>{{ macros.timeago(view_user.date_joined) }}</strong></td>
+ </tr>
+ {% if view_user.last_seen %}
+ <tr>
+ <td>{% trans %}last seen{% endtrans %}</td>
+ <td><strong title="{{ view_user.last_seen }}">{{ macros.timeago(view_user.last_seen) }}</strong></td>
+ </tr>
+ {% endif %}
+ {% if view_user.website and (not view_user.is_blocked()) %}
+ <tr>
+ <td>{% trans %}website{% endtrans %}</td>
+ <td>{{ macros.user_website_link(view_user, max_display_length = 30) }}</td>
+ </tr>
+ {% endif %}
+ {% if view_user.location or view_user.country %}
+ <tr>
+ <td>{% trans %}location{% endtrans %}</td>
+ <td>{{ macros.user_full_location(view_user) }}</td>
+ </tr>
+ {% endif %}
+ {% if view_user.date_of_birth %}
+ <tr>
+ <!--todo - redo this with whole sentence translation -->
+ <td>{% trans %}age{% endtrans %}</td>
+ <td>{{view_user.date_of_birth|get_age}} {% trans %}age unit{% endtrans %}</td>
+ </tr>
+ {% endif %}
+ {% if votes_today_left %}
+ <tr>
+ <td>{% trans %}todays unused votes{% endtrans %}</td>
+ <td><strong class="darkred">{{ votes_today_left }}</strong> {% trans %}votes left{% endtrans %}</td>
+ </tr>
+ {% endif %}
+ </table>
+ </td>
+ <td width="380">
+ <div class="user-about">
+ {% if view_user.about and (not view_user.is_blocked()) %}
+ {{view_user.about|linebreaks}}
+ {% endif %}
+ </div>
+ </td>
+ </tr>
+</table>
+<!-- end user_info.html -->
diff --git a/askbot/skins/default/templates/user_profile/user_moderate.html b/askbot/templates/user_profile/user_moderate.html
index a7f05b1c..a7f05b1c 100644
--- a/askbot/skins/default/templates/user_profile/user_moderate.html
+++ b/askbot/templates/user_profile/user_moderate.html
diff --git a/askbot/skins/default/templates/user_profile/user_network.html b/askbot/templates/user_profile/user_network.html
index f64d95b0..f64d95b0 100644
--- a/askbot/skins/default/templates/user_profile/user_network.html
+++ b/askbot/templates/user_profile/user_network.html
diff --git a/askbot/skins/default/templates/user_profile/user_recent.html b/askbot/templates/user_profile/user_recent.html
index 8eae673d..8eae673d 100644
--- a/askbot/skins/default/templates/user_profile/user_recent.html
+++ b/askbot/templates/user_profile/user_recent.html
diff --git a/askbot/skins/default/templates/user_profile/user_reputation.html b/askbot/templates/user_profile/user_reputation.html
index 1cdf014a..1cdf014a 100644
--- a/askbot/skins/default/templates/user_profile/user_reputation.html
+++ b/askbot/templates/user_profile/user_reputation.html
diff --git a/askbot/templates/user_profile/user_stats.html b/askbot/templates/user_profile/user_stats.html
new file mode 100644
index 00000000..dc3d97e0
--- /dev/null
+++ b/askbot/templates/user_profile/user_stats.html
@@ -0,0 +1,165 @@
+{% extends "user_profile/user.html" %}
+{% import "macros.html" as macros %}
+{% import "user_profile/macros.html" as user_profile_macros %}
+<!-- user_stats.html -->
+{% block profilesection %}
+ {% trans %}overview{% endtrans %}
+{% endblock %}
+{% block usercontent %}
+ {% include "user_profile/user_info.html" %}
+ <a name="questions"></a>
+ {% spaceless %}
+ <h2>{% trans counter=question_count %}<span class="count">{{counter}}</span> Question{% pluralize %}<span class="count">{{counter}}</span> Questions{% endtrans %}</h2>
+ {% endspaceless %}
+ {% include "user_profile/users_questions.html" %}
+ <a name="answers"></a>
+ {% spaceless %}
+ <h2 style="clear:both;"><span class="count">{{ top_answer_count }}</span> {% trans counter=top_answer_count %}Answer{% pluralize %}Answers{% endtrans %}</h2>
+ {% endspaceless %}
+ <div class="user-stats-table">
+ {% for top_answer in top_answers %}
+ <div class="answer-summary">
+ <a title="{{ top_answer.summary|collapse|escape }}"
+ href="{% url question top_answer.thread._question_post().id %}{{ top_answer.thread.title|slugify }}#{{ top_answer.id }}">
+ <span class="answer-votes {% if top_answer.accepted() %}answered-accepted{% endif %}"
+ title="{% trans answer_score=top_answer.score %}the answer has been voted for {{ answer_score }} times{% endtrans %} {% if top_answer.accepted() %}{% trans %}this answer has been selected as correct{% endtrans %}{%endif%}">
+ {{ top_answer.score }}
+ </span>
+ </a>
+ <div class="answer-link">
+ {% spaceless %}
+ <a href="{% url question top_answer.thread._question_post().id %}{{ top_answer.thread.title|slugify }}#{{top_answer.id}}">{{ top_answer.thread.title|escape }}</a>
+ {% endspaceless %}
+ {% if top_answer.comment_count > 0 %}
+ <span>
+ {% trans comment_count=top_answer.comment_count %}({{ comment_count }} comment){% pluralize %}the answer has been commented {{ comment_count }} times{% endtrans %}
+ </span>
+ {% endif %}
+ </div>
+ </div>
+ {% endfor %}
+ </div>
+ <br/>
+ <a name="votes"></a>
+ {% spaceless %}
+ <h2>{% trans cnt=total_votes %}<span class="count">{{cnt}}</span> Vote{% pluralize %}<span class="count">{{cnt}}</span> Votes {% endtrans %}</h2>
+ {% endspaceless %}
+ <div class="user-stats-table">
+ <table>
+ <tr>
+ <td width="60">
+ <img style="cursor: default;" src="{{"/images/vote-arrow-up-on.png"|media}}" alt="{% trans %}thumb up{% endtrans %}" />
+ <span title="{% trans %}user has voted up this many times{% endtrans %}" class="vote-count">{{up_votes}}</span>
+ </td>
+ <td width="60">
+ <img style="cursor: default;" src="{{"/images/vote-arrow-down-on.png"|media}}" alt="{% trans %}thumb down{% endtrans %}" />
+ <span title="{% trans %}user voted down this many times{% endtrans %}" class="vote-count">{{down_votes}}</span>
+
+ </td>
+ </tr>
+ </table>
+ </div>
+ <a name="tags"></a>
+ {% spaceless %}
+ <h2>{% trans counter=user_tags|length %}<span class="count">{{counter}}</span> Tag{% pluralize %}<span class="count">{{counter}}</span> Tags{% endtrans %}</h2>
+ {% endspaceless %}
+ <div class="user-stats-table">
+ <table class="tags">
+ <tr>
+ <td valign="top">
+ <ul id="ab-user-tags" class="tags">
+ {% for tag in user_tags %}
+ <li>
+ {{ macros.tag_widget(
+ tag.name,
+ html_tag = 'div',
+ search_state = search_state,
+ truncate_long_tag = True,
+ extra_content =
+ '<span class="tag-number">&#215; ' ~
+ tag.user_tag_usage_count|intcomma ~
+ '</span>'
+ )
+ }}
+ </li>
+ {#
+ {% if loop.index is divisibleby 10 %}
+ </td>
+ <td width="180" valign="top">
+ {% endif %}
+ #}
+ {% endfor %}
+ </ul>
+ </td>
+ </tr>
+ </table>
+ </div>
+ {% if interesting_tag_names %}
+ {{ user_profile_macros.tag_selection(interesting_tag_names, 'interesting') }}
+ {% endif %}
+ {% if ignored_tag_names %}
+ {{ user_profile_macros.tag_selection(ignored_tag_names, 'ignored') }}
+ {% endif %}
+ {% if subscribed_tag_names %}
+ {{ user_profile_macros.tag_selection(subscribed_tag_names, 'subscribed') }}
+ {% endif %}
+ {% if settings.BADGES_MODE == 'public' %}
+ <a name="badges"></a>
+ {% spaceless %}
+ <h2>{% trans counter=total_badges %}<span class="count">{{counter}}</span> Badge{% pluralize %}<span class="count">{{counter}}</span> Badges{% endtrans %}</h2>
+ {% endspaceless %}
+ <div class="user-stats-table badges">
+ <table>
+ <tr>
+ <td style="line-height:35px">
+ {% for badge, badge_user_awards in badges %}
+ <a
+ href="{{badge.get_absolute_url()}}"
+ title="{% trans description=badge.description %}{{description}}{% endtrans %}"
+ class="medal"
+ ><span class="{{ badge.css_class }}">&#9679;</span>&nbsp;{% trans name=badge.name %}{{name}}{% endtrans %}
+ </a>&nbsp;
+ <span class="tag-number">&#215;
+ <span class="badge-context-toggle">{{ badge_user_awards|length|intcomma }}</span>
+ </span>
+ <ul id="badge-context-{{ badge.id }}" class="badge-context-list" style="display:none">
+ {% for award in badge_user_awards %}
+ {% if award.content_object_is_post %}
+ <li>
+ <a
+ title="{{ award.content_object.get_snippet()|collapse }}"
+ href="{{ award.content_object.get_absolute_url() }}"
+ >{% if award.content_type.post_type == 'answer' %}{% trans %}Answer to:{% endtrans %}{% endif %} {{ award.content_object.thread.title|escape }}</a>
+ </li>
+ {% endif %}
+ {% endfor %}
+ </ul>
+ {% if loop.index is divisibleby 3 %}
+ </td></tr>
+ <tr><td style="line-height:35px">
+ {% endif %}
+ {% endfor %}
+ </td>
+ </tr>
+ </table>
+ </div>
+ {% endif %}
+{% endblock %}
+{% block endjs %}
+ {{ super() }}
+ <script type="text/javascript">
+ askbot['urls']['join_or_leave_group'] = '{% url join_or_leave_group %}';
+ $(document).ready(function(){
+ setup_badge_details_toggle();
+ $.each($('.group-join-btn'), function(idx, elem){
+ var group_join_btn = new GroupJoinButton();
+ group_join_btn.decorate($(elem));
+ });
+ });
+ </script>
+ <script type='text/javascript' src='{{"/js/tag_selector.js"|media}}'></script>
+ <script type="text/javascript">
+ askbot['urls']['questions'] = '{% url "questions" %}';
+ </script>
+{% endblock %}
+<!-- end user_stats.html -->
diff --git a/askbot/skins/default/templates/user_profile/user_tabs.html b/askbot/templates/user_profile/user_tabs.html
index c7df4187..c7df4187 100644
--- a/askbot/skins/default/templates/user_profile/user_tabs.html
+++ b/askbot/templates/user_profile/user_tabs.html
diff --git a/askbot/skins/default/templates/user_profile/user_votes.html b/askbot/templates/user_profile/user_votes.html
index b5fc4560..b5fc4560 100644
--- a/askbot/skins/default/templates/user_profile/user_votes.html
+++ b/askbot/templates/user_profile/user_votes.html
diff --git a/askbot/templates/user_profile/users_questions.html b/askbot/templates/user_profile/users_questions.html
new file mode 100644
index 00000000..ca66b7e2
--- /dev/null
+++ b/askbot/templates/user_profile/users_questions.html
@@ -0,0 +1,14 @@
+<!-- users_questions.html -->
+{% import "macros.html" as macros %}
+<div class="user-stats-table">
+ {% for question in questions %}
+ {{
+ macros.question_summary(
+ question.thread, question,
+ extra_class='narrow', search_state=search_state,
+ visitor = request.user
+ )
+ }}
+ {% endfor %}
+</div>
+<!-- end users_questions.html -->
diff --git a/askbot/templates/users.html b/askbot/templates/users.html
new file mode 100644
index 00000000..a1c4ed11
--- /dev/null
+++ b/askbot/templates/users.html
@@ -0,0 +1,146 @@
+{% extends "two_column_body.html" %}
+{% import "macros.html" as macros %}
+<!-- users.html -->
+{% block title %}{% spaceless %}{% trans %}Users{% endtrans %}{% endspaceless %}{% endblock %}
+{% block forestyle %}
+ <link rel="stylesheet" type="text/css" href="{{"/js/wmd/wmd.css"|media}}" />
+{% endblock %}
+{% block content %}
+<div id="content-header">
+ <h1 class="section-title">
+ {% if group %}
+ {% trans name = group.name|replace('-', ' ')|escape %}Users in group {{name}}{% endtrans %}
+ {% else %}
+ {% trans %}Users{% endtrans %}
+ {% endif %}
+ </h1>
+ <div class="tabBar">
+ <div class="tabsA">
+ {#% if settings.GROUPS_ENABLED and user_groups %}
+ <span class="label">{% trans %}Select/Sort by &raquo;{% endtrans %}</span>
+ {% for a_group in user_groups %}
+ <a
+ href="{% url users_by_group group_id=a_group.id, group_slug=a_group.name|slugify %}"
+ {% if group.name == a_group.name %}class="on"{% endif %}
+ title="{% trans name=a_group.name|escape %}people in group {{name}}{% endtrans %}"
+ ><span>{{ a_group.name|replace('-',' ')|escape }}</span></a>
+ {% endfor %}
+ {% else %#}
+ <span class="label">{% trans %}Sort by &raquo;{% endtrans %}</span>
+ {#% endif %#}
+ {% if settings.KARMA_MODE == 'public' %}
+ <a
+ id="sort_reputation"
+ href="{{ request.path }}?sort=reputation"
+ {% if tab_id == 'reputation' %}class="on"{% endif %}
+ title="{% trans %}see people with the highest reputation{% endtrans %}"
+ ><span>{% trans %}karma{% endtrans %}</span></a>
+ {% endif %}
+ <a
+ id="sort_newest"
+ href="{{ request.path }}?sort=newest"
+ {% if tab_id == 'newest' %}class="on"{% endif %}
+ class="off" title="{% trans %}see people who joined most recently{% endtrans %}"
+ ><span>{% trans %}recent{% endtrans %}</span></a>
+ <a
+ id="sort_last"
+ href="{{ request.path }}?sort=last"
+ {% if tab_id == 'last' %}class="on"{% endif %}
+ class="off" title="{% trans %}see people who joined the site first{% endtrans %}"
+ ><span>{% trans %}oldest{% endtrans %}<span></a>
+ <a
+ id="sort_user"
+ href="{{ request.path }}?sort=user"
+ {% if tab_id == 'user' %}class="on"{% endif %}
+ title="{% trans %}see people sorted by name{% endtrans %}"
+ ><span>{% trans %}by username{% endtrans %}</span></a>
+ </div>
+ </div>
+ <div class="clearfix"></div>
+</div>
+{% if search_query %}
+ <p>{% trans %}users matching query {{search_query}}:{% endtrans %}</p>
+{% endif %}
+{% if not users.object_list %}
+ <p><span>{% trans %}Nothing found.{% endtrans %}</span></p>
+{% endif %}
+{{ macros.user_list(
+ users.object_list,
+ karma_mode = settings.KARMA_MODE, badges_mode = settings.BADGES_MODE
+ )
+}}
+<div class="pager">
+ {{ macros.paginator(paginator_context) }}
+</div>
+{% endblock %}
+{% block sidebar %}
+ {% if group %}
+ {# this widget takes variables: group, user_can_join_group, user_is_group_member #}
+ {% include "widgets/group_info.html" %}
+ {% endif %}
+{% endblock %}
+{% block endjs %}
+ <script type='text/javascript'>
+ var Attacklab = Attacklab || {};
+ Attacklab.wmd = 1;{# a trick to launch wmd manually #}
+ askbot['urls']['upload'] = '{% url upload %}';
+ askbot['urls']['load_object_description'] = '{% url load_object_description %}';
+ askbot['urls']['save_object_description'] = '{% url save_object_description %}';
+ askbot['urls']['save_group_logo_url'] = '{% url save_group_logo_url %}';
+ askbot['urls']['delete_group_logo_url'] = '{% url delete_group_logo %}';
+ askbot['urls']['join_or_leave_group'] = '{% url join_or_leave_group %}';
+ </script>
+ <script type='text/javascript' src='{{"/js/editor.js"|media}}'></script>
+ <script type='text/javascript' src='{{"/js/wmd/showdown.js"|media}}'></script>
+ <script type='text/javascript' src='{{"/js/wmd/wmd.js"|media}}'></script>
+ <script type='text/javascript' src='{{"/js/jquery.validate.min.js"|media}}'></script>
+ <script src='{{"/js/post.js"|media}}' type='text/javascript'></script>
+ <script type="text/javascript">
+ //todo move javascript out
+ {% if settings.ENABLE_MATHJAX or settings.MARKUP_CODE_FRIENDLY %}
+ var codeFriendlyMarkdown = true;
+ {% else %}
+ var codeFriendlyMarkdown = false;
+ {% endif %}
+ {% if group and request.user.is_authenticated() %}
+ $().ready(function(){
+ var group_join_btn = new GroupJoinButton();
+ group_join_btn.decorate($('.group-join-btn'));
+ //setup WMD editor
+ if (askbot['data']['userIsAdminOrMod'] === true){
+ //todo: this is kind of Attacklab.init ... should not be here
+ Attacklab.wmd = function(){
+ Attacklab.loadEnv = function(){
+ var mergeEnv = function(env){
+ if(!env){
+ return;
+ }
+
+ for(var key in env){
+ Attacklab.wmd_env[key] = env[key];
+ }
+ };
+
+ mergeEnv(Attacklab.wmd_defaults);
+ mergeEnv(Attacklab.account_options);
+ mergeEnv(top["wmd_options"]);
+ Attacklab.full = true;
+
+ var defaultButtons = "bold italic link blockquote code image ol ul heading hr";
+ Attacklab.wmd_env.buttons = Attacklab.wmd_env.buttons || defaultButtons;
+ };
+ Attacklab.loadEnv();
+ };
+ Attacklab.wmd();
+ Attacklab.wmdBase();
+ var group_editor = new UserGroupProfileEditor();
+ group_editor.decorate($('#group-wiki-{{group.id}}'));
+ }
+ Hilite.exact = false;
+ Hilite.elementid = "main-body";
+ Hilite.debug_referrer = location.href;
+ });
+ {% endif %}
+ </script>
+{% endblock %}
+<!-- end users.html -->
diff --git a/askbot/templates/widget_base.html b/askbot/templates/widget_base.html
new file mode 100644
index 00000000..44be3e5f
--- /dev/null
+++ b/askbot/templates/widget_base.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<!-- template widget_base.html -->
+<html xmlns="http://www.w3.org/1999/xhtml">
+ {% spaceless %}
+ <head>
+ {% include "meta/html_head_javascript.html" %}
+ {% block before_css %}{% endblock %}
+ {% block forestyle %}{% endblock %}
+ {% block forejs %}{% endblock %}
+ </head>
+ {% endspaceless %}
+ <body class="lang-{{settings.LANGUAGE_CODE}}">
+ {% block body%}
+ {% endblock %}
+ {% block content%}
+ {% endblock %}
+ {% include "meta/bottom_scripts.html" %}
+ {% block endjs %}
+ {% endblock %}
+ </body>
+</html>
+<!-- end template widget_base.html -->
diff --git a/askbot/templates/widgets/answer_edit_tips.html b/askbot/templates/widgets/answer_edit_tips.html
new file mode 100644
index 00000000..2bb5b256
--- /dev/null
+++ b/askbot/templates/widgets/answer_edit_tips.html
@@ -0,0 +1,27 @@
+<!-- template answer_edit_tips.html -->
+<div class="box">
+ <h2>{% trans %}Tips{% endtrans %}</h2>
+ <div id="tips">
+ <ul >
+ <li> <b>{% trans %}give an answer interesting to this community{% endtrans %}</b>
+ </li>
+ <li>
+ {% trans %}try to give an answer, rather than engage into a discussion{% endtrans %}
+ </li>
+ <li>
+ {% trans %}provide enough details{% endtrans %}
+ </li>
+ <li>
+ {% trans %}be clear and concise{% endtrans %}
+ </li>
+ </ul>
+ <p class='info-box-follow-up-links'>
+<!-- will be change to a popup windows
+ <a href="{% url faq %}" target="_blank" title="{% trans %}see frequently asked questions{% endtrans %}">{% trans %}FAQ{% endtrans %} »</a>
+-->
+ </p>
+ </div>
+</div>
+{% if settings.EDITOR_TYPE == 'markdown' %}
+ {% include "widgets/markdown_help.html" %}
+{% endif %}
diff --git a/askbot/templates/widgets/ask_button.html b/askbot/templates/widgets/ask_button.html
new file mode 100644
index 00000000..e202b110
--- /dev/null
+++ b/askbot/templates/widgets/ask_button.html
@@ -0,0 +1,9 @@
+{% if active_tab != "ask" %}
+ {% if not search_state %} {# get empty SearchState() if there's none #}
+ {% set search_state=search_state|get_empty_search_state %}
+ {% endif %}
+ <a
+ id="askButton"
+ href="{{ search_state.full_ask_url() }}{% if group %}{% if '?' in search_state.full_ask_url() %}&{% else %}?{% endif %}group_id={{ group.id }}{% endif %}"
+ >{% if group %}{% trans %}Ask the Group{% endtrans %}{% else %}{% trans %}Ask Your Question{% endtrans %}{% endif %}</a>
+{% endif %}
diff --git a/askbot/templates/widgets/ask_form.html b/askbot/templates/widgets/ask_form.html
new file mode 100644
index 00000000..d528609f
--- /dev/null
+++ b/askbot/templates/widgets/ask_form.html
@@ -0,0 +1,52 @@
+{% import "macros.html" as macros %}
+<form id="fmask" action="" method="post" >{% csrf_token %}
+ <div class="form-item">
+ <div id="askFormBar">
+ {% if not request.user.is_authenticated() %}
+<p>{% trans %}<span class=\"strong big\">You are welcome to start submitting your question anonymously</span>. When you submit the post, you will be redirected to the login/signup page. Your question will be saved in the current session and will be published after you log in. Login/signup process is very simple. Login takes about 30 seconds, initial signup takes a minute or less.{% endtrans %}</p>
+ {% else %}
+ {% if settings.EMAIL_VALIDATION %}
+ {% if not request.user.email_isvalid %}
+ {% trans email=request.user.email %}<span class='strong big'>Looks like your email address, %(email)s has not yet been validated.</span> To post messages you must verify your email, please see <a href='%(email_validation_faq_url)s'>more details here</a>.<br>You can submit your question now and validate email after that. Your question will saved as pending meanwhile.{% endtrans %}
+ {% endif %}
+ {% endif %}
+ {% endif %}
+ <input id="id_title" class="questionTitleInput" name="title" autocomplete="off"
+ value="{% if form.initial.title %}{{form.initial.title|escape}}{% endif %}"/>
+ <span class="form-error">{{ form.title.errors }}</span>
+ </div>
+ <div class="title-desc">
+ {{ form.title.help_text }}
+ </div>
+ </div>
+ <div id='question-list'></div>
+ {{
+ macros.edit_post(
+ form,
+ post_type = 'question',
+ edit_title = False,
+ mandatory_tags = mandatory_tags,
+ use_category_selector = (settings.TAG_SOURCE == 'category-tree'),
+ editor_type = settings.EDITOR_TYPE,
+ user = request.user
+ )
+ }}
+ {{ form.group_id }}
+ <div class="question-options">
+ {% if settings.WIKI_ON %}
+ {{ macros.checkbox_in_div(form.wiki) }}
+ {% endif %}
+ {% if settings.ALLOW_ASK_ANONYMOUSLY %}
+ {{ macros.checkbox_in_div(form.ask_anonymously) }}
+ {% endif %}
+ {% if request.user.is_authenticated() and request.user.can_make_group_private_posts() %}
+ {{ macros.checkbox_in_div(form.post_privately) }}
+ {% endif %}
+ </div>
+ {% if not request.user.is_authenticated() %}
+ <input type="submit" name="post_anon" value="{% trans %}Login/Signup to Post{% endtrans %}" class="submit" />
+ {% else %}
+ <input type="submit" name="post" value="{% trans %}Ask Your Question{% endtrans %}" class="submit" />
+ {% endif %}
+ <div class="clean"></div>
+</form>
diff --git a/askbot/skins/default/templates/widgets/contributors.html b/askbot/templates/widgets/contributors.html
index 9aa357dd..9aa357dd 100644
--- a/askbot/skins/default/templates/widgets/contributors.html
+++ b/askbot/templates/widgets/contributors.html
diff --git a/askbot/templates/widgets/edit_post.html b/askbot/templates/widgets/edit_post.html
new file mode 100644
index 00000000..b9bfa1e3
--- /dev/null
+++ b/askbot/templates/widgets/edit_post.html
@@ -0,0 +1,115 @@
+{% if edit_title %}
+ <div class="form-item">
+ <label for="id_title" ><strong>{{ post_form.title.label_tag() }}:</strong></label> <span class="form-error"></span><br/>
+ {{ post_form.title }} {{ post_form.title.errors }}
+ <div class="title-desc">
+ {{ post_form.title.help_text }}
+ </div>
+ </div>
+{% endif %}
+{% if editor_type == 'markdown' %}
+ <div class="wmd-container">
+ <div id="wmd-button-bar" class="wmd-panel"></div>
+ {{ post_form.text }}{# this element is resizable and will be wrapped by js #}
+ </div>
+{% else %}
+ <div class="wmd-container">
+ {{ post_form.media }}
+ {{ post_form.text }}
+ </div>
+ <script type="text/javascript">
+ {% if post_html %}
+ askbot['data']['editorContent'] = '{{ post_html|escapejs }}';
+ {% endif %}
+ </script>
+{% endif %}
+<div class="form-item">
+ <label for="editor" class="form-error">{{ post_form.text.errors }}</label>
+ <p class="editor-status action-status"><span></span></p>
+</div>
+{# need label element for resizable input, b/c form validation won't find span #}
+{% if post_type == 'question' %}
+ <div class="form-item">
+ {% if use_category_selector %}
+ {% include "widgets/three_column_category_selector.html" %}
+ <div class="tags-desc">{% trans %}Tags{% endtrans %}</div>
+ {% include "widgets/tag_editor.html" %}
+ {% else %}
+ {% if tags_are_required %}
+ <label for="id_tags">
+ {% if mandatory_tags %}
+ <strong>{% trans %}tags{% endtrans %}</strong>
+ {% trans %}, one of these is required{% endtrans %}
+ {{
+ tag_list_widget(
+ mandatory_tags,
+ make_links = False,
+ css_class = 'clearfix'
+ )
+ }}
+ {% else %}
+ <strong>{% trans %}tags:{% endtrans %}</strong>
+ {% trans %}(required){% endtrans %}
+ {% endif %}
+ </label>
+ {% else %}
+ <strong>{% trans %}tags:{% endtrans %}</strong>
+ {% endif %}
+ <span class="form-error">{{ post_form.tags.errors }}</span><br/>
+ {{ post_form.tags }}
+ <div class="title-desc">
+ {{ post_form.tags.help_text }}
+ </div>
+ {% endif %}
+ </div>
+{% endif %}
+{% if 'summary' in post_form['fields'] %}
+ <div class="form-item">
+ <strong>{{ post_form.summary.label_tag() }}</strong> <br/>
+ {{ post_form.summary }}
+ <div class="title-desc">
+ {{ post_form.summary.help_text }}
+ </div>
+ <div class="form-error" >{{ post_form.summary.errors }}</div>
+ </div>
+{% endif %}
+
+{% if editor_type == 'markdown' %}
+ <div class="preview-toggle">
+ <span
+ id="pre-collapse"
+ title="{% trans %}Toggle the real time Markdown editor preview{% endtrans %}"
+ >
+ [{% trans %}hide preview{% endtrans %}]
+ </span>
+ </div>
+ <div id="previewer" class="wmd-preview"></div>
+{% endif %}
+
+{% if user and user.is_authenticated() and user.is_administrator() %}
+ {# admin can post answers or questions on behalf of anyone. #}
+ <table class="proxy-user-info">
+ <tbody>
+ <tr><td colspan="2">
+ <label>
+ {% trans %}To post on behalf of someone else, enter user name <strong>and</strong> email below.{% endtrans %}
+ </label>
+ </td></tr>
+ <tr>
+ <td>
+ <div class="form-item">
+ {{ post_form.post_author_username }}
+ </div>
+ <div class="form-item">
+ {{ post_form.post_author_email }}
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <span class="form-error">{{ post_form.post_author_username.errors }}</span>
+ <span class="form-error">{{ post_form.post_author_email.errors }}</span>
+ </td>
+ </tbody>
+ </table>
+{% endif %}
diff --git a/askbot/skins/default/templates/widgets/footer.html b/askbot/templates/widgets/footer.html
index 6eb3afc2..6eb3afc2 100644
--- a/askbot/skins/default/templates/widgets/footer.html
+++ b/askbot/templates/widgets/footer.html
diff --git a/askbot/templates/widgets/group_info.html b/askbot/templates/widgets/group_info.html
new file mode 100644
index 00000000..cba8177a
--- /dev/null
+++ b/askbot/templates/widgets/group_info.html
@@ -0,0 +1,103 @@
+{% import "macros.html" as macros %}
+<div id="group-wiki-{{group.id}}" class="box group-wiki">
+ <h2>{% trans %}Group info{% endtrans %}</h2>
+ <img class="group-logo"
+ {% if group.logo_url %}
+ src="{{ group.logo_url }}"
+ {% else %}
+ style="display:none"
+ {% endif %}
+ />
+ <div class="content">
+ {% if group.description %}
+ {{ group.description.html }}
+ {% endif %}
+ </div>
+ <div class="clearfix"></div>
+ {{ macros.group_join_button(
+ group_id = group.id,
+ acceptance_level = user_acceptance_level,
+ membership_level = user_membership_level
+ )
+ }}
+ {% if request.user.is_authenticated() and request.user.is_administrator() %}
+ <div class="controls">
+ <a class="edit-description"
+ >{% trans %}edit description{% endtrans %}</a>
+ {% if group.logo_url %}
+ <span>|</span>
+ <a class="change-logo"
+ >{% trans %}change logo{% endtrans %}</a>
+ <span>|</span>
+ <a class="delete-logo">{% trans %}delete logo{% endtrans %}</a>
+ {% else %}
+ <span>|</span>
+ <a class="change-logo"
+ >{% trans %}add logo{% endtrans %}</a>
+ {% endif %}
+ <br/>
+ {% if group_email_moderation_enabled %}
+ <input type="checkbox"
+ id="moderate-email"
+ {% if group.moderate_email %}checked="checked"{% endif %}
+ data-toggle-url="{% url toggle_group_profile_property %}"
+ />
+ <label for="moderate-email">
+ {% trans %}moderate emailed questions{% endtrans %}
+ </label>
+ <br/>
+ {% endif %}
+
+ <input
+ type="checkbox"
+ id="moderate-answers-to-enquirers"
+ {% if group.moderate_answers_to_enquirers %}checked="checked"{% endif %}
+ data-toggle-url="{% url toggle_group_profile_property %}"
+ />
+ <label for="moderate-answers-to-enquirers">
+ {% trans %}show only selected answers to enquirers{% endtrans %}
+ </label>
+ <br/>
+
+ <label for="group-openness-selector">
+ {% trans %}How users join this group?{% endtrans %}
+ </label>
+ <br/>
+ <select
+ id="group-openness-selector"
+ data-url="{% url set_group_openness %}"
+ >
+ {% for choice in group_openness_choices %}
+ <option
+ {% if choice[0] == group.openness %}
+ selected="selected"
+ {% endif %}
+ value="{{choice[0]}}"
+ >{{ choice[1] }}</option>
+ {% endfor %}
+ </select>
+ <br/>
+ <a
+ id="preapproved-emails"
+ title="{% trans %}list of email addresses of pre-approved users{% endtrans %}"
+ data-object-id="{{group.group_ptr_id}}"
+ data-model-name="Group"
+ data-property-name="preapproved_emails"
+ data-url="{% url edit_object_property_text %}"
+ data-editor-heading="{% trans %}List of preapproved email addresses{% endtrans %}"
+ data-help-text="{% trans %}Users with these email adderesses will be added to the group automatically.{% endtrans %}"
+ >{% trans %}edit preapproved emails{% endtrans %}</a>
+ <br/>
+ <a
+ id="preapproved-email-domains"
+ title="{% trans %}list of preapproved email address domain names{% endtrans %}"
+ data-object-id="{{group.group_ptr_id}}"
+ data-model-name="Group"
+ data-property-name="preapproved_email_domains"
+ data-url="{% url edit_object_property_text %}"
+ data-editor-heading="{% trans %}List of preapproved email domain names{% endtrans %}"
+ data-help-text="{% trans %}Users whose email adderesses belong to these domains will be added to the group automatically.{% endtrans %}"
+ >{% trans %}edit preapproved email domains{% endtrans %}</a>
+ </div>
+ {% endif %}
+</div>
diff --git a/askbot/skins/default/templates/widgets/group_snippet.html b/askbot/templates/widgets/group_snippet.html
index e9364a7e..e9364a7e 100644
--- a/askbot/skins/default/templates/widgets/group_snippet.html
+++ b/askbot/templates/widgets/group_snippet.html
diff --git a/askbot/templates/widgets/groups_list.html b/askbot/templates/widgets/groups_list.html
new file mode 100644
index 00000000..0669f34f
--- /dev/null
+++ b/askbot/templates/widgets/groups_list.html
@@ -0,0 +1,4 @@
+{% import "macros.html" as macros %}
+{% for group in groups %}
+ <p>{{ macros.user_group(group) }}</p>
+{% endfor %}
diff --git a/askbot/skins/default/templates/widgets/header.html b/askbot/templates/widgets/header.html
index 52e528bc..52e528bc 100644
--- a/askbot/skins/default/templates/widgets/header.html
+++ b/askbot/templates/widgets/header.html
diff --git a/askbot/skins/default/templates/widgets/logo.html b/askbot/templates/widgets/logo.html
index 1b251432..1b251432 100644
--- a/askbot/skins/default/templates/widgets/logo.html
+++ b/askbot/templates/widgets/logo.html
diff --git a/askbot/templates/widgets/markdown_help.html b/askbot/templates/widgets/markdown_help.html
new file mode 100644
index 00000000..9816fe26
--- /dev/null
+++ b/askbot/templates/widgets/markdown_help.html
@@ -0,0 +1,42 @@
+<div class="box">
+ <h2>{% trans %}Markdown basics{% endtrans %}</h2>
+ <ul>
+ {% if settings.MARKUP_CODE_FRIENDLY or settings.ENABLE_MATHJAX %}
+ <li>
+ {% trans %}*italic*{% endtrans %}
+ </li>
+ <li>
+ {% trans %}**bold**{% endtrans %}
+ </li>
+ {% else %}
+ <li>
+ {% trans %}*italic* or _italic_{% endtrans %}
+ </li>
+ <li>
+ {% trans %}**bold** or __bold__{% endtrans %}
+ </li>
+ {% endif %}
+ <li>
+ <b>{% trans %}link{% endtrans %}</b>:[{% trans %}text{% endtrans %}](http://url.com/ "{% trans %}title{% endtrans %}")
+
+ </li>
+ <li>
+ <b>{% trans %}image{% endtrans %}</b>:![alt {% trans %}text{% endtrans %}](/path/img.jpg "{% trans %}title{% endtrans %}")
+
+ </li>
+ <li>
+ {% trans %}numbered list:{% endtrans %}
+ 1. Foo
+ 2. Bar
+ </li>
+ <li>
+ {% trans %}basic HTML tags are also supported{% endtrans %}
+ </li>
+ </ul>
+ <p class='info-box-follow-up-links'>
+<!-- will be change to a popup windows
+ <a href="http://en.wikipedia.org/wiki/Markdown" target="_blank">{% trans %}learn more about Markdown{% endtrans %} »</a>
+-->
+ </p>
+</div>
+<!-- end template answer_edit_tips.html -->
diff --git a/askbot/templates/widgets/meta_nav.html b/askbot/templates/widgets/meta_nav.html
new file mode 100644
index 00000000..20c22491
--- /dev/null
+++ b/askbot/templates/widgets/meta_nav.html
@@ -0,0 +1,28 @@
+{% import "macros.html" as macros%}
+<a
+ id="navTags"
+ href="{% url tags %}"
+ {% if active_tab == 'tags' %}class="on"{% endif %}
+>{% trans %}tags{% endtrans %}</a>
+{% if settings.GROUPS_ENABLED %}
+<span class="dropdown">
+<a
+ id="navGroups" class='{% if active_tab == 'groups' %}"on"{% endif %}'
+ href="{% url groups %}" data-target="#" >
+ {% trans %}people & groups{% endtrans %}
+</a>
+</span>
+{%else%}
+<a
+ id="navUsers"
+ href="{% url users %}"
+ {% if active_tab == 'users' %}class="on"{% endif %}
+>{% trans %}users{% endtrans %}</a>
+{% endif %}
+{% if settings.BADGES_MODE == 'public' %}
+<a
+ id="navBadges"
+ href="{% url badges %}"
+ {% if active_tab == 'badges' %}class="on"{% endif %}
+>{% trans %}badges{% endtrans %}</a>
+{% endif %}
diff --git a/askbot/templates/widgets/question_edit_tips.html b/askbot/templates/widgets/question_edit_tips.html
new file mode 100644
index 00000000..f60304c1
--- /dev/null
+++ b/askbot/templates/widgets/question_edit_tips.html
@@ -0,0 +1,22 @@
+<!-- question_edit_tips.html -->
+<div id ="tips" class="box">
+ <h2>{% trans %}Tips{% endtrans %}</h2>
+ <ul>
+ <li> <b>{% trans %}ask a question interesting to this community{% endtrans %}</b>
+ </li>
+ <li>
+ {% trans %}provide enough details{% endtrans %}
+ </li>
+ <li>
+ {% trans %}be clear and concise{% endtrans %}
+ </li>
+ </ul>
+ <p class='info-box-follow-up-links'>
+<!-- will be change to a popup windows
+ <a href="{% url faq %}" target="_blank" title="{% trans %}see frequently asked questions{% endtrans %}">{% trans %}FAQ{% endtrans %} »</a>
+-->
+ </p>
+</div>
+{% if settings.EDITOR_TYPE == 'markdown' %}
+ {% include "/widgets/markdown_help.html" %}
+{% endif %}
diff --git a/askbot/templates/widgets/question_summary.html b/askbot/templates/widgets/question_summary.html
new file mode 100644
index 00000000..78aa2f0c
--- /dev/null
+++ b/askbot/templates/widgets/question_summary.html
@@ -0,0 +1,59 @@
+{% from "macros.html" import user_country_flag, tag_list_widget, timeago, user_primary_group %}
+<div class="short-summary{% if extra_class %} {{extra_class}}{% endif %}" id="question-{{question.id}}">
+ <div class="counts">
+ <div class="views
+ {% if thread.view_count == 0 -%}
+ no-views
+ {% else -%}
+ some-views
+ {%- endif -%}">
+ <span class="item-count">{{thread.view_count|humanize_counter}}</span>
+ <div>
+ {% trans cnt=thread.view_count %}view{% pluralize %}views{% endtrans %}
+ </div>
+ </div>
+ {% set answer_count = thread.get_answer_count(visitor) %}
+ <div class="answers
+ {% if answer_count == 0 -%}
+ no-answers
+ {% else -%}
+ {%- if thread.accepted_answer_id -%} {# INFO: Use _id to not fetch the whole answer post #}
+ accepted
+ {%- else -%}
+ some-answers
+ {%- endif -%}
+ {%- endif -%}">
+ <span
+ class="item-count"
+ >{{ answer_count|humanize_counter }}{% if thread.accepted_answer_id %}{% endif %}</span>
+ <div>
+ {% trans cnt = answer_count %}answer{% pluralize %}answers{% endtrans %}
+ </div>
+ </div>
+ <div class="votes
+ {% if question.score == 0 -%}
+ no-votes
+ {% else -%}
+ some-votes
+ {%- endif -%}">
+ <span class="item-count">{{question.score|humanize_counter}}</span>
+ <div>
+ {% trans cnt=question.score %}vote{% pluralize %}votes{% endtrans %}
+ </div>
+ </div>
+ <div style="clear:both"></div>
+ <div class="userinfo">
+ {{ timeago(thread.last_activity_at) }}
+ {% if question.is_anonymous %}
+ <span class="anonymous">{{ thread.last_activity_by.get_anonymous_name() }}</span>
+ {% else %}
+ <a href="{% url user_profile thread.last_activity_by.id, thread.last_activity_by.username|slugify %}">{{thread.last_activity_by.username|escape}}</a> {{ user_country_flag(thread.last_activity_by) }}
+ {#{user_score_and_badge_summary(thread.last_activity_by)}#}
+ {% endif %}
+ {% if thread.last_activity_by.get_primary_group() %}-{% endif %}
+ {{ user_primary_group(thread.last_activity_by) }}
+ </div>
+ </div>
+ <h2><a title="{{question.summary|escape}}" href="{{ question.get_absolute_url(thread=thread) }}">{{thread.get_title(question)|escape}}</a></h2>
+ {{ tag_list_widget(thread.get_tag_names(), search_state=search_state) }}
+</div>
diff --git a/askbot/skins/common/templates/widgets/related_tags.html b/askbot/templates/widgets/related_tags.html
index 05520998..05520998 100644
--- a/askbot/skins/common/templates/widgets/related_tags.html
+++ b/askbot/templates/widgets/related_tags.html
diff --git a/askbot/skins/default/templates/widgets/scope_nav.html b/askbot/templates/widgets/scope_nav.html
index a6bda630..a6bda630 100644
--- a/askbot/skins/default/templates/widgets/scope_nav.html
+++ b/askbot/templates/widgets/scope_nav.html
diff --git a/askbot/skins/common/templates/widgets/search_bar.html b/askbot/templates/widgets/search_bar.html
index 59c4fd58..59c4fd58 100644
--- a/askbot/skins/common/templates/widgets/search_bar.html
+++ b/askbot/templates/widgets/search_bar.html
diff --git a/askbot/skins/default/templates/widgets/secondary_header.html b/askbot/templates/widgets/secondary_header.html
index caf190bc..caf190bc 100644
--- a/askbot/skins/default/templates/widgets/secondary_header.html
+++ b/askbot/templates/widgets/secondary_header.html
diff --git a/askbot/skins/default/templates/widgets/system_messages.html b/askbot/templates/widgets/system_messages.html
index 10ba4a84..10ba4a84 100644
--- a/askbot/skins/default/templates/widgets/system_messages.html
+++ b/askbot/templates/widgets/system_messages.html
diff --git a/askbot/templates/widgets/tag_category_selector.html b/askbot/templates/widgets/tag_category_selector.html
new file mode 100644
index 00000000..9eabb6eb
--- /dev/null
+++ b/askbot/templates/widgets/tag_category_selector.html
@@ -0,0 +1,3 @@
+{% include "widgets/three_column_category_selector.html" %}
+<div class="tags-desc">{% trans %}Tags{% endtrans %}</div>
+{% include "widgets/tag_editor.html" %}
diff --git a/askbot/templates/widgets/tag_editor.html b/askbot/templates/widgets/tag_editor.html
new file mode 100644
index 00000000..8f3fa8cd
--- /dev/null
+++ b/askbot/templates/widgets/tag_editor.html
@@ -0,0 +1,31 @@
+{% import "macros.html" as macros %}
+<p style="margin:-18px 0 0 42px; color: brown; font-size: 13px; font-style: italic"
+ class="tag-editor-error-alert"
+>
+ <span for="id_tags" generated="true" class="form-error" style="float: left;"></span>
+</p>
+<div class="tag-editor" style="margin-top: 18px">{# there's a hack with the margin in js as well #}
+ {{ macros.tag_list_widget(
+ tag_names,
+ deletable = True,
+ make_links = False
+ )
+ }}
+ <input
+ class="new-tags-input"
+ type="text"
+ name="new_tags_input"
+ />
+ <div class="clearfix"></div>
+ <input
+ id="id_tags"
+ name="tags"
+ type="hidden"
+ value="{% if tag_names %}{{tag_names|join(' ')}}{% endif %}"
+ />
+ {#
+ tag input is hidden because we want to edit the list visually
+ we also want to eventually allow multiword tags, which are
+ not easy to enter into a simple input box
+ #}
+</div>
diff --git a/askbot/skins/common/templates/widgets/tag_selector.html b/askbot/templates/widgets/tag_selector.html
index 7c6fe92e..7c6fe92e 100644
--- a/askbot/skins/common/templates/widgets/tag_selector.html
+++ b/askbot/templates/widgets/tag_selector.html
diff --git a/askbot/templates/widgets/three_column_category_selector.html b/askbot/templates/widgets/three_column_category_selector.html
new file mode 100644
index 00000000..ab0886c6
--- /dev/null
+++ b/askbot/templates/widgets/three_column_category_selector.html
@@ -0,0 +1,22 @@
+{# just a skeleton for the category selector - filled by js #}
+<table class="category-selector">
+ <thead>
+ <th colspan="3">{% trans %}Categorize your question using this tag selector or entering text in tag box.{% endtrans %}
+ <a style="display:none;"
+ class='category-editor-toggle'
+ data-on-state-text='{% trans %}(done editing){% endtrans %}'
+ data-off-state-text='{% trans %}(edit categories){% endtrans %}'
+ data-on-prompt-text='{% trans %}(edit categories){% endtrans %}'
+ data-off-prompt-text='{% trans %}(done editing){% endtrans %}'
+ >{% trans %}(edit categories){% endtrans %}
+ </a>
+ </th>
+ </thead>
+ <tbody>
+ <tr>
+ <td><ul class="select-box cat-col-0"></ul></td>
+ <td><ul class="select-box cat-col-1"></ul></td>
+ <td><ul class="select-box cat-col-2"></ul></td>
+ </tr>
+ </tbody>
+</table>
diff --git a/askbot/templates/widgets/user_list.html b/askbot/templates/widgets/user_list.html
new file mode 100644
index 00000000..52cf8bd4
--- /dev/null
+++ b/askbot/templates/widgets/user_list.html
@@ -0,0 +1,28 @@
+{% import "macros.html" as macros %}
+<div class="userList">
+ <table class="list-table">
+ <tr>
+ <td class="list-td">
+ {% for user in users %}
+ <div class="user">
+ <ul>
+ <li class="thumb">{{ macros.gravatar(user, 32) }}</li>
+ <li><a href="{% url user_profile user.id, user.username|slugify %}{% if profile_section %}?sort={{profile_section}}{% endif %}">{{user.username|escape}}</a>{{ macros.user_country_flag(user) }}</li>
+ <li>{{
+ macros.user_score_and_badge_summary(
+ user,
+ karma_mode = karma_mode,
+ badges_mode = badges_mode
+ )
+ }}</li>
+ </ul>
+ </div>
+ {% if loop.index is divisibleby 7 %}
+ </td>
+ <td>
+ {% endif %}
+ {% endfor %}
+ </td>
+ </tr>
+ </table>
+</div>
diff --git a/askbot/skins/default/templates/widgets/user_long_score_and_badge_summary.html b/askbot/templates/widgets/user_long_score_and_badge_summary.html
index efc59c55..efc59c55 100644
--- a/askbot/skins/default/templates/widgets/user_long_score_and_badge_summary.html
+++ b/askbot/templates/widgets/user_long_score_and_badge_summary.html
diff --git a/askbot/templates/widgets/user_navigation.html b/askbot/templates/widgets/user_navigation.html
new file mode 100644
index 00000000..06b0cdb9
--- /dev/null
+++ b/askbot/templates/widgets/user_navigation.html
@@ -0,0 +1,26 @@
+{%- if request.user.is_authenticated() -%}
+ <a href="{{ request.user.get_absolute_url() }}">{{ request.user.username|escape }}</a>
+ <span class="user-info">
+ {{ macros.inbox_link(request.user) }}
+ {{ macros.moderation_items_link(request.user, moderation_items) }}
+ {%-
+ if settings.KARMA_MODE != 'hidden' and settings.BADGES_MODE != 'hidden'
+ -%}
+ ({{ macros.user_long_score_and_badge_summary(
+ user,
+ badges_mode = settings.BADGES_MODE
+ )
+ }})
+ {%- endif -%}
+ </span>
+ {% if settings.USE_ASKBOT_LOGIN_SYSTEM %}
+ <a href="{{ settings.LOGOUT_URL }}?next={{ settings.LOGOUT_REDIRECT_URL }}">{% trans %}sign out{% endtrans %}</a>
+ {% endif %}
+{% elif settings.USE_ASKBOT_LOGIN_SYSTEM %}
+ <a href="{{ settings.LOGIN_URL }}?next={{request.path|clean_login_url}}">{% trans %}Hi there! Please sign in{% endtrans %}</a>
+{% endif %}
+{% if request.user.is_authenticated() and request.user.is_administrator() %}
+ <a href="{% url site_settings %}">{% trans %}settings{% endtrans %}</a>
+ <a href="{% url widgets %}">{% trans %}widgets{% endtrans %}</a>
+{% endif %}
+ <a href="{% url "help" %}" title="{% trans %}help{% endtrans %}">{% trans %}help{% endtrans %}</a>
diff --git a/askbot/skins/default/templates/widgets/user_score_and_badge_summary.html b/askbot/templates/widgets/user_score_and_badge_summary.html
index 80d140db..80d140db 100644
--- a/askbot/skins/default/templates/widgets/user_score_and_badge_summary.html
+++ b/askbot/templates/widgets/user_score_and_badge_summary.html
diff --git a/askbot/templatetags/extra_filters_jinja.py b/askbot/templatetags/extra_filters_jinja.py
index 3643e3c9..146de6d1 100644
--- a/askbot/templatetags/extra_filters_jinja.py
+++ b/askbot/templatetags/extra_filters_jinja.py
@@ -14,6 +14,7 @@ from askbot import exceptions as askbot_exceptions
from askbot.conf import settings as askbot_settings
from django.conf import settings as django_settings
from askbot.skins import utils as skin_utils
+from askbot.utils.html import absolutize_urls
from askbot.utils import functions
from askbot.utils import url_utils
from askbot.utils.slug import slugify
@@ -24,17 +25,7 @@ from django_countries import settings as countries_settings
register = coffin_template.Library()
-def absolutize_urls_func(text):
- url_re1 = re.compile(r'(?P<prefix><img[^<]+src=)"(?P<url>/[^"]+)"', re.I)
- url_re2 = re.compile(r"(?P<prefix><img[^<]+src=)'(?P<url>/[^']+)'", re.I)
- url_re3 = re.compile(r'(?P<prefix><a[^<]+href=)"(?P<url>/[^"]+)"', re.I)
- url_re4 = re.compile(r"(?P<prefix><a[^<]+href=)'(?P<url>/[^']+)'", re.I)
- replacement = '\g<prefix>"%s\g<url>"' % askbot_settings.APP_URL
- text = url_re1.sub(replacement, text)
- text = url_re2.sub(replacement, text)
- text = url_re3.sub(replacement, text)
- return url_re4.sub(replacement, text)
-absolutize_urls = register.filter(absolutize_urls_func)
+absolutize_urls = register.filter(absolutize_urls)
TIMEZONE_STR = pytz.timezone(
django_settings.TIME_ZONE
diff --git a/askbot/tests/__init__.py b/askbot/tests/__init__.py
index 1b8b703a..96ba2045 100644
--- a/askbot/tests/__init__.py
+++ b/askbot/tests/__init__.py
@@ -10,9 +10,14 @@ from askbot.tests.management_command_tests import *
from askbot.tests.search_state_tests import *
from askbot.tests.form_tests import *
from askbot.tests.follow_tests import *
-from askbot.tests.templatefilter_tests import *
from askbot.tests.markup_test import *
-from askbot.tests.misc_tests import *
from askbot.tests.post_model_tests import *
+from askbot.tests.thread_model_tests import *
from askbot.tests.reply_by_email_tests import *
from askbot.tests.haystack_search_tests import *
+from askbot.tests.email_parsing_tests import *
+from askbot.tests.widget_tests import *
+from askbot.tests.category_tree_tests import CategoryTreeTests
+from askbot.tests.user_model_tests import UserModelTests
+from askbot.tests.utils_tests import *
+from askbot.tests.view_context_tests import *
diff --git a/askbot/tests/badge_tests.py b/askbot/tests/badge_tests.py
index 1a4cb2b5..8e4458f6 100644
--- a/askbot/tests/badge_tests.py
+++ b/askbot/tests/badge_tests.py
@@ -68,8 +68,9 @@ class BadgeTests(AskbotTestCase):
self.assert_have_badge(badge_key, recipient = self.u2, expected_count = 1)
#post another question and check that there are no new badges
- answer2 = self.post_answer(user = self.u2, question = question)
- answer2.points = min_points - 1
+ question2 = self.post_question(user = self.u1)
+ answer2 = self.post_answer(user = self.u2, question = question2)
+ answer2.score = min_score - 1
answer2.save()
self.u1.upvote(answer2)
@@ -269,7 +270,8 @@ class BadgeTests(AskbotTestCase):
answer = self.post_answer(user = self.u2, question = question)
self.u1.accept_best_answer(answer)
self.assert_have_badge('scholar', recipient = self.u1)
- answer2 = self.post_answer(user = self.u2, question = question)
+ question2 = self.post_question(user = self.u1)
+ answer2 = self.post_answer(user = self.u2, question = question2)
self.u1.accept_best_answer(answer2)
self.assert_have_badge(
'scholar',
@@ -316,7 +318,7 @@ class BadgeTests(AskbotTestCase):
def test_guru_badge1(self):
self.assert_guru_badge_works('upvote_answer')
- def test_guru_badge1(self):
+ def test_guru_badge2(self):
self.assert_guru_badge_works('accept_best_answer')
def test_necromancer_badge(self):
diff --git a/askbot/tests/cache_tests.py b/askbot/tests/cache_tests.py
index a8416e99..5740cc2a 100644
--- a/askbot/tests/cache_tests.py
+++ b/askbot/tests/cache_tests.py
@@ -24,20 +24,3 @@ class CacheTests(AskbotTestCase):
#second hit to the same question should give fewer queries
self.assertTrue(counter > len(connection.queries))
settings.DEBUG = False
-
- def test_authentificated_no_question_cache(self):
- url = reverse('question', kwargs={'id': self.question.id})
-
- password = '123'
- self.other_user.set_password(password)
- self.client.login(username=self.other_user.username, password=password)
-
- self.visit_question()
- counter = len(connection.queries)
- self.visit_question()
-
- #expect the same number of queries both times
- self.assertEqual(counter, len(connection.queries))
- settings.DEBUG = False
-
-
diff --git a/askbot/tests/category_tree_tests.py b/askbot/tests/category_tree_tests.py
new file mode 100644
index 00000000..39362bd2
--- /dev/null
+++ b/askbot/tests/category_tree_tests.py
@@ -0,0 +1,134 @@
+import unittest
+from askbot.utils import category_tree as ct
+from django.utils import simplejson
+
+class CategoryTreeTests(unittest.TestCase):
+ def setUp(self):
+ self.tree = [
+ [
+ u'dummy', [#dummy is a sentinel node
+ [
+ u'cars', [
+ [u'volkswagen', []],
+ [u'zhiguli', []]
+ ]
+ ],
+ [
+ u'cats', [
+ [u'meow', []],
+ [u'tigers', [
+ [u'rrrr', []]
+ ]
+ ]
+ ]
+ ],
+ [
+ u'music', [
+ [u'play', [
+ [u'loud', []]]
+ ],
+ [u'listen', []],
+ [u'buy', []],
+ [u'download', []]
+ ]
+ ]
+ ]
+ ]
+ ]
+
+ def test_dummy_is_absent(self):
+ self.assertEqual(
+ ct.has_category(self.tree, 'dummy'),
+ False
+ )
+
+ def test_first_level_subcat_is_there(self):
+ self.assertEqual(
+ ct.has_category(self.tree, 'cars'),
+ True
+ )
+
+ def test_deep_level_subcat_is_there(self):
+ self.assertEqual(
+ ct.has_category(self.tree, 'download'),
+ True
+ )
+
+ def test_get_subtree_dummy(self):
+ dummy = ct.get_subtree(self.tree, [0])
+ self.assertEqual(dummy[0], 'dummy')
+
+ def test_get_subtree_cars(self):
+ cars = ct.get_subtree(self.tree, [0,0])
+ self.assertEqual(cars[0], 'cars')
+
+ def test_get_subtree_listen_music(self):
+ listen_music = ct.get_subtree(self.tree, [0,2,1])
+ self.assertEqual(listen_music[0], 'listen')
+
+ def test_path_is_valid_dummy(self):
+ self.assertEqual(
+ ct.path_is_valid(self.tree, [0]), True
+ )
+
+ def test_path_is_valid_deep(self):
+ self.assertEqual(
+ ct.path_is_valid(self.tree, [0,2,0,0]), True
+ )
+ def test_path_is_nvalid_too_deep(self):
+ self.assertEqual(
+ ct.path_is_valid(self.tree, [0,2,0,0,0]), False
+ )
+
+ def test_add_category(self):
+ ct.add_category(self.tree, 'appreciate', [0, 2])
+ appreciate = ct.get_subtree(self.tree, [0, 2, 0])
+ self.assertEqual(appreciate[0] , 'appreciate')
+
+ def test_sort_data(self):
+ unsorted_data = [
+ [
+ 'dummy',
+ [
+ [
+ 'cars',
+ []
+ ],
+ [
+ 'audio',
+ [
+ [
+ 'mp3', []
+ ],
+ [
+ 'amadeus', []
+ ]
+ ]
+ ]
+ ]
+ ]
+ ]
+ sorted_data = ct.sort_tree(unsorted_data)
+ sorted_dump = simplejson.dumps(sorted_data)
+ self.assertEqual(
+ sorted_dump,
+ '[["dummy", [["audio", [["amadeus", []], ["mp3", []]]], ["cars", []]]]]'
+ )
+
+ def test_get_leaf_names(self):
+ leaf_names = ct.get_leaf_names(self.tree)
+ self.assertEqual(
+ leaf_names,
+ set([
+ 'cars', 'volkswagen', 'zhiguli',
+ 'cats', 'meow', 'tigers', 'rrrr',
+ 'music', 'play', 'listen', 'loud',
+ 'buy', 'download'
+ ])
+ )
+
+ def test_get_leaf_names_empty(self):
+ self.assertEqual(
+ set([]),
+ ct.get_leaf_names(None)
+ )
diff --git a/askbot/tests/db_api_tests.py b/askbot/tests/db_api_tests.py
index 86c97e6d..8fadce17 100644
--- a/askbot/tests/db_api_tests.py
+++ b/askbot/tests/db_api_tests.py
@@ -7,11 +7,14 @@ from django.core import exceptions
from django.core.urlresolvers import reverse
from django.test.client import Client
from django.conf import settings
+from django.contrib.auth.models import AnonymousUser
from django import forms
from askbot.tests.utils import AskbotTestCase
+from askbot.tests.utils import with_settings
from askbot import models
from askbot import const
from askbot.conf import settings as askbot_settings
+from askbot.models.tag import get_global_group
import datetime
class DBApiTests(AskbotTestCase):
@@ -46,6 +49,13 @@ class DBApiTests(AskbotTestCase):
self.assertTrue(post.deleted_by == None)
self.assertTrue(post.deleted_at == None)
+ def test_blank_tags_impossible(self):
+ self.post_question(tags='')
+ self.assertEqual(
+ models.Tag.objects.filter(name='').count(),
+ 0
+ )
+
def test_flag_question(self):
self.user.set_status('m')
self.user.flag_post(self.question)
@@ -156,6 +166,16 @@ class DBApiTests(AskbotTestCase):
count = models.Tag.objects.filter(name='one-tag').count()
self.assertEquals(count, 0)
+ @with_settings(MAX_TAG_LENGTH=200, MAX_TAGS_PER_POST=50)
+ def test_retag_tags_too_long_raises(self):
+ tags = "aoaoesuouooeueooeuoaeuoeou aostoeuoaethoeastn oasoeoa nuhoasut oaeeots aoshootuheotuoehao asaoetoeatuoasu o aoeuethut aoaoe uou uoetu uouuou ao aouosutoeh"
+ question = self.post_question(user=self.user)
+ self.assertRaises(
+ exceptions.ValidationError,
+ self.user.retag_question,
+ question=question, tags=tags
+ )
+
def test_search_with_apostrophe_works(self):
self.post_question(
user = self.user,
@@ -392,13 +412,219 @@ class CommentTests(AskbotTestCase):
comment = models.Post.objects.get_comments().get(id = self.comment.id)
self.assertEquals(comment.points, 0)
-class TagAndGroupTests(AskbotTestCase):
+class GroupTests(AskbotTestCase):
def setUp(self):
self.u1 = self.create_user('u1')
+ askbot_settings.update('GROUPS_ENABLED', True)
+
+ def tearDown(self):
+ askbot_settings.update('GROUPS_ENABLED', False)
- def test_group_cannot_create_case_variant_tag(self):
- self.post_question(user = self.u1, tags = 'one two three')
- models.Tag.group_tags.get_or_create(user = self.u1, group_name = 'One')
- tag_one = models.Tag.objects.filter(name__iexact = 'one')
- self.assertEqual(tag_one.count(), 1)
- self.assertEqual(tag_one[0].name, 'one')
+ def assertObjectGroupsEqual(self, obj, expected_groups):
+ self.assertEqual(set(obj.groups.all()), set(expected_groups))
+
+ def post_question_answer_and_comments(self, is_private=False):
+ question = self.post_question(user=self.u1, is_private=is_private)
+ answer = self.post_answer(
+ user=self.u1, question=question, is_private=is_private
+ )
+ question_comment = self.post_comment(
+ user=self.u1, parent_post=question
+ )
+ answer_comment = self.post_comment(
+ user=self.u1, parent_post=answer
+ )
+ return {
+ 'thread': question.thread,
+ 'question': question,
+ 'answer': answer,
+ 'question_comment': question_comment,
+ 'answer_comment': answer_comment
+ }
+
+ def test_posts_added_to_global_group(self):
+ q = self.post_question(user=self.u1)
+ group_name = askbot_settings.GLOBAL_GROUP_NAME
+ self.assertEqual(q.groups.filter(name=group_name).exists(), True)
+
+ a = self.post_answer(question=q, user=self.u1)
+ self.assertEqual(a.groups.filter(name=group_name).exists(), True)
+
+ c = self.post_comment(parent_post=a, user=self.u1)
+ self.assertEqual(c.groups.filter(name=group_name).exists(), True)
+
+ def test_posts_added_to_private_group(self):
+ group = self.create_group(group_name='private')
+ self.u1.join_group(group)
+
+ q = self.post_question(user=self.u1, is_private=True)
+ self.assertEqual(q.groups.count(), 2)
+ self.assertEqual(q.groups.filter(name='private').exists(), True)
+
+ a = self.post_answer(question=q, user=self.u1, is_private=True)
+ self.assertEqual(a.groups.count(), 2)
+ self.assertEqual(a.groups.filter(name='private').exists(), True)
+
+ qc = self.post_comment(parent_post=q, user=self.u1)#w/o private arg
+ self.assertEqual(qc.groups.count(), 2)
+ self.assertEqual(qc.groups.filter(name='private').exists(), True)
+
+ qa = self.post_comment(parent_post=a, user=self.u1)#w/o private arg
+ self.assertEqual(qa.groups.count(), 2)
+ self.assertEqual(qa.groups.filter(name='private').exists(), True)
+
+ def test_global_group_name_setting_changes_group_name(self):
+ askbot_settings.update('GLOBAL_GROUP_NAME', 'all-people')
+ group = get_global_group()
+ self.assertEqual(group.name, 'all-people')
+
+ def test_ask_global_group_by_id_works(self):
+ group = get_global_group()
+ q = self.post_question(user=self.u1, group_id=group.id)
+ self.assertEqual(q.groups.count(), 2)
+ self.assertEqual(q.groups.filter(name=group.name).exists(), True)
+
+ def test_making_public_question_private_works(self):
+ question = self.post_question(user=self.u1)
+ comment = self.post_comment(parent_post=question, user=self.u1)
+ group = self.create_group(group_name='private')
+ self.u1.join_group(group)
+ self.edit_question(question=question, user=self.u1, is_private=True)
+ self.assertEqual(question.groups.count(), 2)
+ self.assertEqual(question.groups.filter(id=group.id).count(), 1)
+ #comment inherits sharing scope
+ self.assertEqual(comment.groups.count(), 2)
+ self.assertEqual(comment.groups.filter(id=group.id).count(), 1)
+
+ def test_making_public_answer_private_works(self):
+ question = self.post_question(user=self.u1)
+ answer = self.post_answer(question=question, user=self.u1)
+ comment = self.post_comment(parent_post=answer, user=self.u1)
+ group = self.create_group(group_name='private')
+ self.u1.join_group(group)
+
+ #membership in `group` should not affect things,
+ #because answer groups always inherit thread groups
+ self.edit_answer(user=self.u1, answer=answer, is_private=True)
+ self.assertEqual(answer.groups.count(), 1)
+
+ #here we have a simple case - the comment to answer was posted
+ #by the answer author!!!
+ #won't work when comment was by someone else
+ u1_group = self.u1.get_personal_group()
+ self.assertEqual(answer.groups.filter(id=u1_group.id).count(), 1)
+ #comment inherits the sharing scope
+ self.assertEqual(comment.groups.count(), 1)
+ self.assertEqual(comment.groups.filter(id=u1_group.id).count(), 1)
+
+ def test_public_question_private_answer_works(self):
+ question = self.post_question(self.u1)
+
+ u2 = self.create_user('u2')
+ group = self.create_group(group_name='private')
+ u2.join_group(group)
+
+ answer = self.post_answer(question=question, user=u2, is_private=True)
+
+ threads = models.Thread.objects
+ #u2 will see question and answer
+ self.assertEqual(answer.thread.get_answer_count(user=u2), 1)
+ self.assertEqual(threads.get_visible(u2).count(), 1)
+ #u1 will see only question
+ self.assertEqual(answer.thread.get_answer_count(user=self.u1), 0)
+ self.assertEqual(threads.get_visible(self.u1).count(), 1)
+ #anonymous will see question
+ self.assertEqual(answer.thread.get_answer_count(), 0)
+ anon = AnonymousUser()
+ self.assertEqual(threads.get_visible(anon).count(), 1)
+
+ def test_thread_answer_count_for_multiple_groups(self):
+ question = self.post_question(self.u1)
+ group = self.create_group(group_name='private')
+ self.u1.join_group(group)
+ answer = self.post_answer(question=question, user=self.u1)
+ answer.add_to_groups((group,))
+ self.assertEqual(answer.groups.count(), 3)
+ self.assertEqual(answer.thread.posts.get_answers(self.u1).count(), 1)
+
+ def test_thread_make_public_recursive(self):
+ private_group = self.create_group(group_name='private')
+ self.u1.join_group(private_group)
+ data = self.post_question_answer_and_comments(is_private=True)
+
+ groups = [private_group, self.u1.get_personal_group()]
+ self.assertObjectGroupsEqual(data['thread'], groups)
+ self.assertObjectGroupsEqual(data['question'], groups)
+ self.assertObjectGroupsEqual(data['question_comment'], groups)
+ self.assertObjectGroupsEqual(data['answer'], groups)
+ self.assertObjectGroupsEqual(data['answer_comment'], groups)
+
+ data['thread'].make_public(recursive=True)
+
+ global_group = get_global_group()
+ groups = [global_group, private_group, self.u1.get_personal_group()]
+ self.assertObjectGroupsEqual(data['thread'], groups)
+ self.assertObjectGroupsEqual(data['question'], groups)
+ self.assertObjectGroupsEqual(data['question_comment'], groups)
+ self.assertObjectGroupsEqual(data['answer'], groups)
+ self.assertObjectGroupsEqual(data['answer_comment'], groups)
+
+ def test_thread_add_to_groups_recursive(self):
+ data = self.post_question_answer_and_comments()
+
+ private_group = self.create_group(group_name='private')
+ thread = data['thread']
+ thread.add_to_groups([private_group], recursive=True)
+
+ global_group = get_global_group()
+ groups = [global_group, private_group, self.u1.get_personal_group()]
+ self.assertObjectGroupsEqual(thread, groups)
+ self.assertObjectGroupsEqual(data['question'], groups)
+ self.assertObjectGroupsEqual(data['question_comment'], groups)
+ self.assertObjectGroupsEqual(data['answer'], groups)
+ self.assertObjectGroupsEqual(data['answer_comment'], groups)
+
+ def test_private_thread_is_invisible_to_anonymous_user(self):
+ group = self.create_group(group_name='private')
+ self.u1.join_group(group)
+ self.post_question(user=self.u1, is_private=True)
+
+ visible_threads = models.Thread.objects.get_visible(AnonymousUser())
+ self.assertEqual(visible_threads.count(), 0)
+
+ def test_join_group(self):
+ #create group
+ group = models.Group(name='somegroup')
+ group.openness = models.Group.OPEN
+ group.save()
+ #join
+ self.u1 = self.create_user('user1')
+ self.u1.join_group(group)
+ #assert membership of askbot group object
+ found_count = self.u1.get_groups().filter(name='somegroup').count()
+ self.assertEqual(found_count, 1)
+
+ def test_group_moderation(self):
+ #create group
+ group = models.Group(name='somegroup')
+ #make it moderated
+ group.openness = models.Group.MODERATED
+ group.save()
+
+ #add moderator to the group
+ mod = self.create_user('mod', status='d')
+ mod.join_group(group)
+
+ #create a regular user
+ reg = self.create_user('reg')
+ reg.join_group(group)
+ #assert that moderator has a notification
+ acts = models.Activity.objects.filter(
+ user=reg,
+ activity_type=const.TYPE_ACTIVITY_ASK_TO_JOIN_GROUP,
+ object_id=group.id
+ )
+ self.assertEqual(acts.count(), 1)
+ self.assertEqual(acts[0].recipients.count(), 1)
+ recipient = acts[0].recipients.all()[0]
+ self.assertEqual(recipient, mod)
diff --git a/askbot/tests/email_alert_tests.py b/askbot/tests/email_alert_tests.py
index 9ec1a412..f4ae052b 100644
--- a/askbot/tests/email_alert_tests.py
+++ b/askbot/tests/email_alert_tests.py
@@ -1,6 +1,7 @@
+import bs4
+import copy
import datetime
import functools
-import copy
import time
from django.conf import settings as django_settings
from django.core import management
@@ -10,6 +11,7 @@ from django.core.urlresolvers import reverse
from django.test import TestCase
from django.test.client import Client
from askbot.tests import utils
+from askbot.tests.utils import with_settings
from askbot import models
from askbot import mail
from askbot.conf import settings as askbot_settings
@@ -39,7 +41,7 @@ def email_alert_test(test_func):
test_object.check_results(test_name)
else:
raise ValueError('test method names must have prefix "test_"')
- return wrapped_test
+ return wrapped_test
def setup_email_alert_tests(setup_func):
@functools.wraps(setup_func)
@@ -107,7 +109,7 @@ class SubjectLineTests(TestCase):
self.assertEquals(subj, 'hahah')
class EmailAlertTests(TestCase):
- """Base class for testing delayed Email notifications
+ """Base class for testing delayed Email notifications
that are triggered by the send_email_alerts
command
@@ -145,7 +147,7 @@ class EmailAlertTests(TestCase):
@setup_email_alert_tests
def setUp(self):
"""generic pre-test setup method:
-
+
this function is empty - because it's intendend content is
entirely defined by the decorator
@@ -157,7 +159,7 @@ class EmailAlertTests(TestCase):
def setUpUsers(self):
self.other_user = utils.create_user(
- username = 'other',
+ username = 'other',
email = 'other@domain.com',
date_joined = self.setup_timestamp,
status = 'm'
@@ -177,8 +179,8 @@ class EmailAlertTests(TestCase):
body_text = 'dummy test comment',
timestamp = None
):
- """posts and returns a comment to parent post, uses
- now timestamp if not given, dummy body_text
+ """posts and returns a comment to parent post, uses
+ now timestamp if not given, dummy body_text
author is required
"""
if timestamp is None:
@@ -211,8 +213,8 @@ class EmailAlertTests(TestCase):
)
def post_question(
- self,
- author = None,
+ self,
+ author = None,
timestamp = None,
title = 'test question title',
body_text = 'test question body',
@@ -234,7 +236,7 @@ class EmailAlertTests(TestCase):
return self.question
def maybe_visit_question(self, user = None):
- """visits question on behalf of a given user and applies
+ """visits question on behalf of a given user and applies
a timestamp set in the class attribute ``visit_timestamp``
if ``visit_timestamp`` is None, then visit is skipped
@@ -298,7 +300,7 @@ class EmailAlertTests(TestCase):
(self.target_user.email, outbox[0].recipients()[0])
#verify that target user receives the email
self.assertEqual(
- outbox[0].recipients()[0],
+ outbox[0].recipients()[0],
self.target_user.email,
error_message
)
@@ -713,6 +715,8 @@ class FeedbackTests(utils.AskbotTestCase):
def assert_feedback_works(self):
outbox = django.core.mail.outbox
self.assertEqual(len(outbox), 1)
+ #todo: change groups to django groups
+ #then replace to 4 back to 3 in the line below
self.assertEqual(len(outbox[0].recipients()), 3)
def test_feedback_post_form(self):
@@ -804,7 +808,7 @@ class EmailReminderTestCase(utils.AskbotTestCase):
#frequency_setting_name = 'UNANSWERED_REMINDER_FREQUENCY'
#days_before_setting_name = 'DAYS_BEFORE_SENDING_UNANSWERED_REMINDER'
#max_reminder_setting_name = 'MAX_UNANSWERED_REMINDERS'
-
+
def setUp(self):
self.u1 = self.create_user(username = 'user1')
self.u2 = self.create_user(username = 'user2')
@@ -869,7 +873,7 @@ class AcceptAnswerReminderTests(EmailReminderTestCase):
class UnansweredReminderTests(EmailReminderTestCase):
-
+
enable_setting_name = 'ENABLE_UNANSWERED_REMINDERS'
frequency_setting_name = 'UNANSWERED_REMINDER_FREQUENCY'
days_before_setting_name = 'DAYS_BEFORE_SENDING_UNANSWERED_REMINDER'
@@ -898,6 +902,8 @@ class UnansweredReminderTests(EmailReminderTestCase):
days_ago = self.wait_days + (self.max_emails - 1)*self.recurrence_days - 1
timestamp = datetime.datetime.now() - datetime.timedelta(days_ago, 3600)
self.do_post(timestamp)
+ #todo: change groups to django groups
+ #then replace to 2 back to 1 in the line below
self.assert_have_emails(1)
@@ -950,6 +956,29 @@ class EmailFeedSettingTests(utils.AskbotTestCase):
data_after = TO_JSON(self.get_user_feeds())
self.assertEquals(data_before, data_after)
+
+class EmailAlertTestsWithGroupsEnabled(utils.AskbotTestCase):
+
+ def setUp(self):
+ self.backup = askbot_settings.GROUPS_ENABLED
+ askbot_settings.update('GROUPS_ENABLED', True)
+
+ def tearDown(self):
+ askbot_settings.update('GROUPS_ENABLED', self.backup)
+
+ @with_settings(MIN_REP_TO_TRIGGER_EMAIL=1)
+ def test_notification_for_global_group_works(self):
+ sender = self.create_user('sender')
+ recipient = self.create_user(
+ 'recipient',
+ notification_schedule=models.EmailFeedSetting.MAX_EMAIL_SCHEDULE
+ )
+ self.post_question(user=sender)
+ outbox = django.core.mail.outbox
+ self.assertEqual(len(outbox), 1)
+ self.assertEqual(outbox[0].recipients(), [recipient.email])
+
+
class PostApprovalTests(utils.AskbotTestCase):
"""test notifications sent to authors when their posts
are approved or published"""
@@ -976,7 +1005,7 @@ class PostApprovalTests(utils.AskbotTestCase):
self.enable_content_moderation
)
askbot_settings.update(
- 'SELF_NOTIFY_EMAILED_POST_AUTHOR_WHEN',
+ 'SELF_NOTIFY_EMAILED_POST_AUTHOR_WHEN',
self.self_notify_when
)
@@ -1001,10 +1030,42 @@ class PostApprovalTests(utils.AskbotTestCase):
u2.approve_post_revision(question.get_latest_revision())
outbox = django.core.mail.outbox
- self.assertEquals(len(outbox), 2)
+ self.assertEquals(len(outbox), 1)
#moderation notification
self.assertEquals(outbox[0].recipients(), [u1.email,])
- self.assertEquals(outbox[1].recipients(), [u1.email,])#approval
+ #self.assertEquals(outbox[1].recipients(), [u1.email,])#approval
+
+
+class AbsolutizeUrlsInEmailsTests(utils.AskbotTestCase):
+ @with_settings(MIN_REP_TO_TRIGGER_EMAIL=1, APP_URL='http://example.com/')
+ def test_urls_are_absolute(self):
+ u1 = self.create_user('u1')
+ max_email = models.EmailFeedSetting.MAX_EMAIL_SCHEDULE
+ u2 = self.create_user('u2', notification_schedule=max_email)
+ text = '<a href="/index.html">home</a>' + \
+ '<img alt="an image" src=\'/img.png\'><a href="https://example.com"><img src="/img.png"/></a>'
+ question = self.post_question(user=u1, body_text=text)
+ outbox = django.core.mail.outbox
+ html_message = outbox[0].alternatives[0][0]
+ content_type = outbox[0].alternatives[0][1]
+ self.assertEqual(content_type, 'text/html')
+
+ soup = bs4.BeautifulSoup(html_message)
+ links = soup.find_all('a')
+ url_bits = {}
+ for link in links:
+ url_bits[link.attrs['href'][:4]] = 1
+
+ self.assertEqual(len(url_bits.keys()), 1)
+ self.assertEqual(url_bits.keys()[0], 'http')
+
+ images = soup.find_all('img')
+ url_bits = {}
+ for img in images:
+ url_bits[img.attrs['src'][:4]] = 1
+
+ self.assertEqual(len(url_bits.keys()), 1)
+ self.assertEqual(url_bits.keys()[0], 'http')
class MailMessagesTests(utils.AskbotTestCase):
diff --git a/askbot/tests/email_parsing_tests.py b/askbot/tests/email_parsing_tests.py
new file mode 100644
index 00000000..905bff0a
--- /dev/null
+++ b/askbot/tests/email_parsing_tests.py
@@ -0,0 +1,25 @@
+from django.conf import settings as django_settings
+from askbot.skins.loaders import get_template
+from django.template import Context
+from askbot import mail
+from askbot import models
+from askbot.tests import utils
+
+class EmailParseTests(utils.AskbotTestCase):
+
+ def setUp(self):
+ self.template_name = 'email/welcome_lamson_on.html'
+ self.context = {'site_name': 'askbot.com',
+ 'email_code': 'DwFwndQty'}
+ template = get_template(self.template_name)
+ self.rendered_template = template.render(Context(self.context))
+ self.expected_output = 'Welcome to askbot.com!\n\nImportant: Please reply to this message, without editing it. We need this to determine your email signature and that the email address is valid and was typed correctly.\n\nUntil we receive the response from you, you will not be able ask or answer questions on askbot.com by email.\n\nSincerely,askbot.com Administrator\n\nDwFwndQty'
+
+ def test_clean_email_body(self):
+ cleaned_body = mail.clean_html_email(self.rendered_template)
+ print "EXPECTED BODY"
+ print self.expected_output
+ print '=================================================='
+ print cleaned_body
+ print "CLEANED BODY"
+ self.assertEquals(cleaned_body, self.expected_output)
diff --git a/askbot/tests/form_tests.py b/askbot/tests/form_tests.py
index 5bca5eac..90f4f4f2 100644
--- a/askbot/tests/form_tests.py
+++ b/askbot/tests/form_tests.py
@@ -334,3 +334,52 @@ class AnswerEditorFieldTests(AskbotTestCase):
self.field.clean(10*'a'),
10*'a'
)
+
+
+class PostAsSomeoneFormTests(AskbotTestCase):
+
+ form = forms.PostAsSomeoneForm
+
+ def setUp(self):
+ self.good_data = {
+ 'username': 'me',
+ 'email': 'me@example.com'
+ }
+
+ def test_blank_form_validates(self):
+ form = forms.PostAsSomeoneForm({})
+ self.assertEqual(form.is_valid(), True)
+
+ def test_complete_form_validates(self):
+ form = forms.PostAsSomeoneForm(self.good_data)
+ self.assertEqual(form.is_valid(), True)
+
+ def test_missing_email_fails(self):
+ form = forms.PostAsSomeoneForm({'post_author_username': 'me'})
+ self.assertEqual(form.is_valid(), False)
+
+ def test_missing_username_fails(self):
+ form = forms.PostAsSomeoneForm({'post_author_email': 'me@example.com'})
+ self.assertEqual(form.is_valid(), False)
+
+class AskWidgetFormTests(AskbotTestCase):
+
+ form = forms.AskWidgetForm
+
+ def setUp(self):
+ self.good_data = {'title': "What's the price of a house in london?"}
+ self.good_data_anon = {'title': "What's the price of a house in london?",
+ 'ask_anonymously': True}
+
+ self.bad_data = {'title': ''}
+
+ def test_valid_input(self):
+ form_object = self.form(include_text=False, data=self.good_data)
+ print form_object.errors
+ self.assertTrue(form_object.is_valid())
+ form_object = self.form(include_text=False, data=self.good_data_anon)
+ self.assertTrue(form_object.is_valid())
+
+ def test_invalid_input(self):
+ form_object = self.form(False, data=self.bad_data)
+ self.assertFalse(form_object.is_valid())
diff --git a/askbot/tests/haystack_search_tests.py b/askbot/tests/haystack_search_tests.py
index 853f4683..d5935ff6 100644
--- a/askbot/tests/haystack_search_tests.py
+++ b/askbot/tests/haystack_search_tests.py
@@ -3,7 +3,6 @@ from django.core import exceptions
from django.conf import settings
from django.contrib.auth.models import User
from askbot.tests.utils import AskbotTestCase, skipIf
-from askbot.search.haystack import AskbotSearchQuerySet
from askbot import models
import datetime
@@ -86,6 +85,7 @@ class HaystackSearchTests(AskbotTestCase):
'''makes a query that can return multiple models and test
get_django_queryset() method from AskbotSearchQuerySet'''
#gepeto is present in profile and in question
+ from askbot.search.haystack import AskbotSearchQuerySet
qs = AskbotSearchQuerySet().filter(content='gepeto').get_django_queryset(User)
for instance in qs:
self.assertTrue(isinstance(instance, User))
diff --git a/askbot/tests/management_command_tests.py b/askbot/tests/management_command_tests.py
index d6be1a16..e9341a8b 100644
--- a/askbot/tests/management_command_tests.py
+++ b/askbot/tests/management_command_tests.py
@@ -46,6 +46,8 @@ class ManagementCommandTests(AskbotTestCase):
# Explicitly check that the values assigned to user_one are now user_two's
self.assertEqual(user_two.posts.get_questions().filter(pk=question.id).count(), 1)
self.assertEqual(user_two.posts.get_comments().filter(pk=comment.id).count(), 1)
+ #todo: change groups to django groups
+ #then replace to 3 back to 2 in the line below
user_two = models.User.objects.get(pk=2)
self.assertEqual(user_two.gold, number_of_gold)
self.assertEqual(user_two.reputation, reputation)
diff --git a/askbot/tests/misc_tests.py b/askbot/tests/misc_tests.py
index 3150c377..328c213f 100644
--- a/askbot/tests/misc_tests.py
+++ b/askbot/tests/misc_tests.py
@@ -1,6 +1,9 @@
from askbot.tests.utils import AskbotTestCase
from askbot.models.post import PostRevision
+from django.test.client import Client
+from django.core.urlresolvers import reverse
+
class MiscTests(AskbotTestCase):
def setUp(self):
@@ -13,3 +16,76 @@ class MiscTests(AskbotTestCase):
question = self.post_question(user=self.u1)
self.assertRaises(NotImplementedError, question.revisions.create)
self.assertRaises(NotImplementedError, PostRevision.objects.create)
+
+class ContentConvertionTests(AskbotTestCase):
+
+ def setUp(self):
+ self.u1 = self.create_user(username='user1')
+ self.u1.set_password('password')
+ self.u1.set_admin_status()
+ self.u1.save()
+ self.u2 = self.create_user(username='notadmin')
+ self.client = Client()
+
+ #content
+ self.question = self.post_question(user=self.u1)
+ self.answer_to_convert = self.post_answer(user=self.u2,
+ question=self.question)
+ self.comment_on_answer = self.post_comment(user=self.u1,
+ parent_post=self.answer_to_convert)
+ self.another_answer = self.post_answer(user=self.u1,
+ question=self.question)
+ self.comment_to_convert = self.post_comment(user=self.u1,
+ parent_post=self.another_answer)
+
+ def test_convert_comment_to_answer(self):
+ self.client.login(username='user1', password='password')
+ old_parent_comment_count = self.another_answer.comment_count
+ answer_count = self.question.thread.answer_count
+ self.client.post(reverse('comment_to_answer'),
+ {'comment_id': self.comment_to_convert.id})
+ converted_answer = self.reload_object(self.comment_to_convert)
+ #old_parent = self.another_answer
+ old_parent = self.reload_object(self.another_answer)
+
+ #test for convertion
+ self.assertEquals(converted_answer.post_type, 'answer')
+ #test for parent change
+ self.assertNotEquals(old_parent.id, converted_answer.parent.id)
+ #test for answer count update
+ self.assertEquals(converted_answer.thread.answer_count, answer_count + 1)
+ #test for comment count update
+ self.assertEquals(old_parent.comment_count, old_parent_comment_count - 1)
+
+ #test the delete post view for errors
+ response = self.client.post(reverse('delete_post'),
+ {'post_id': converted_answer.id,
+ 'cancel_vote': 'false'},
+ HTTP_X_REQUESTED_WITH='XMLHttpRequest')
+ self.assertEquals(response.status_code, 200)
+ self.assertTrue('is_deleted' in response.content)
+
+ def test_convert_answer_to_comment(self):
+ comment_count = self.question.comment_count
+ #because the answer itself has a comment too!
+ comment_count += self.answer_to_convert.comment_count
+
+ answer_count = self.question.thread.answer_count
+ self.client.login(username='user1', password='password')
+ self.client.post(reverse('answer_to_comment'),
+ {'answer_id': self.answer_to_convert.id})
+ converted_comment = self.reload_object(self.answer_to_convert)
+ old_parent = self.reload_object(self.question)
+
+ #test for convertion
+ self.assertEquals(converted_comment.post_type, 'comment')
+ #test for answer count update
+ self.assertEquals(converted_comment.thread.answer_count, answer_count - 1)
+ #test for comment count update
+ self.assertEquals(old_parent.comment_count, comment_count + 1)
+
+ #test the delete comment view for errors
+ response = self.client.post(reverse('delete_comment'),
+ {'comment_id': converted_comment.id},
+ HTTP_X_REQUESTED_WITH='XMLHttpRequest')
+ self.assertEquals(response.status_code, 200)
diff --git a/askbot/tests/page_load_tests.py b/askbot/tests/page_load_tests.py
index e3e699a7..3805d012 100644
--- a/askbot/tests/page_load_tests.py
+++ b/askbot/tests/page_load_tests.py
@@ -5,9 +5,11 @@ from django.core.urlresolvers import reverse
from django.core import management
from django.core.cache.backends.dummy import DummyCache
from django.core import cache
+from django.utils import simplejson
import coffin
import coffin.template
+from bs4 import BeautifulSoup
from askbot import models
from askbot.utils.slug import slugify
@@ -15,6 +17,7 @@ from askbot.deployment import package_utils
from askbot.tests.utils import AskbotTestCase
from askbot.conf import settings as askbot_settings
from askbot.tests.utils import skipIf
+from askbot.tests.utils import with_settings
@@ -69,7 +72,7 @@ class PageLoadTestCase(AskbotTestCase):
self.old_cache = cache.cache
#Disable caching (to not interfere with production cache,
#not sure if that's possible but let's not risk it)
- cache.cache = DummyCache('', {})
+ cache.cache = DummyCache('', {})
def tearDown(self):
cache.cache = self.old_cache # Restore caching
@@ -149,6 +152,33 @@ class PageLoadTestCase(AskbotTestCase):
def test_ask_page_allowed_anonymous(self):
self.proto_test_ask_page(True, 200)
+ @with_settings(GROUPS_ENABLED=False)
+ def test_api_get_questions_groups_disabled(self):
+ data = {'query': 'Question'}
+ response = self.client.get(reverse('api_get_questions'), data)
+ data = simplejson.loads(response.content)
+ self.assertTrue(len(data) > 1)
+
+ @with_settings(GROUPS_ENABLED=True)
+ def test_api_get_questions_groups_enabled(self):
+
+ group = models.Group(name='secret group', openness=models.Group.OPEN)
+ group.save()
+ user = self.create_user('user')
+ user.join_group(group)
+ self.post_question(user=user, title='alibaba', group_id=group.id)
+
+ query_data = {'query': 'alibaba'}
+ response = self.client.get(reverse('api_get_questions'), query_data)
+ response_data = simplejson.loads(response.content)
+ self.assertEqual(len(response_data), 0)
+
+ self.client.login(method='force', user_id=user.id)
+ response = self.client.get(reverse('api_get_questions'), query_data)
+ response_data = simplejson.loads(response.content)
+ self.assertEqual(len(response_data), 1)
+
+
def test_ask_page_disallowed_anonymous(self):
self.proto_test_ask_page(False, 302)
@@ -159,6 +189,10 @@ class PageLoadTestCase(AskbotTestCase):
self.try_url('sitemap')
self.try_url(
+ 'get_groups_list',
+ status_code=status_code
+ )
+ self.try_url(
'feeds',
status_code=status_code,
kwargs={'url':'rss'})
@@ -311,12 +345,12 @@ class PageLoadTestCase(AskbotTestCase):
status_code=status_code,
template='users.html'
)
- self.try_url(
- 'widget_questions',
- status_code = status_code,
- data={'tags': 'tag-1-0'},
- template='question_widget.html',
- )
+ #self.try_url(
+ # 'widget_questions',
+ # status_code = status_code,
+ # data={'tags': 'tag-1-0'},
+ # template='question_widget.html',
+ # )
#todo: really odd naming conventions for sort methods
self.try_url(
'users',
@@ -409,10 +443,9 @@ class PageLoadTestCase(AskbotTestCase):
@skipIf('askbot.middleware.forum_mode.ForumModeMiddleware' \
not in settings.MIDDLEWARE_CLASSES,
'no ForumModeMiddleware set')
+ @with_settings(ASKBOT_CLOSED_FORUM_MODE=True)
def test_non_user_urls_in_closed_forum_mode(self):
- askbot_settings.ASKBOT_CLOSED_FORUM_MODE = True
self.proto_test_non_user_urls(status_code=302)
- askbot_settings.ASKBOT_CLOSED_FORUM_MODE = False
#def test_non_user_urls_logged_in(self):
#user = User.objects.get(id=1)
@@ -481,11 +514,9 @@ class PageLoadTestCase(AskbotTestCase):
@skipIf('askbot.middleware.forum_mode.ForumModeMiddleware' \
not in settings.MIDDLEWARE_CLASSES,
'no ForumModeMiddleware set')
+ @with_settings(ASKBOT_CLOSED_FORUM_MODE=True)
def test_user_urls_in_closed_forum_mode(self):
- askbot_settings.ASKBOT_CLOSED_FORUM_MODE = True
self.proto_test_user_urls(status_code=302)
- askbot_settings.ASKBOT_CLOSED_FORUM_MODE = False
-
def test_user_urls_logged_in(self):
user = models.User.objects.get(id=2) # INFO: Hardcoded ID, might fail if DB allocates IDs in some non-continuous way
@@ -516,9 +547,16 @@ class PageLoadTestCase(AskbotTestCase):
'user_profile',
kwargs={'id': asker.id, 'slug': slugify(asker.username)},
data={'sort':'inbox'},
- template='user_profile/user_inbox.html',
+ template='user_inbox/responses_and_flags.html',
)
+ @with_settings(GROUPS_ENABLED=True)
+ def test_user_page_with_groups_enabled(self):
+ self.try_url('users', status_code=302)
+
+ @with_settings(GROUPS_ENABLED=False)
+ def test_user_page_with_groups_disabled(self):
+ self.try_url('users', status_code=200)
class AvatarTests(AskbotTestCase):
@@ -531,6 +569,17 @@ class AvatarTests(AskbotTestCase):
)
+class QuestionViewTests(AskbotTestCase):
+ def test_meta_description_has_question_summary(self):
+ user = self.create_user('user')
+ text = 'this is a question'
+ question = self.post_question(user=user, body_text=text)
+ response = self.client.get(question.get_absolute_url())
+ soup = BeautifulSoup(response.content)
+ meta_descr = soup.find_all('meta', attrs={'name': 'description'})[0]
+ self.assertTrue(text in meta_descr.attrs['content'])
+
+
class QuestionPageRedirectTests(AskbotTestCase):
def setUp(self):
@@ -614,16 +663,60 @@ class QuestionPageRedirectTests(AskbotTestCase):
self.assertRedirects(resp, expected_url = self.q.get_absolute_url())
class CommandViewTests(AskbotTestCase):
- def test_get_tag_wiki_text_succeeds(self):
- tag1 = self.create_tag('tag1')
+ def test_load_empty_object_description_works(self):
+ group = models.Group(name='somegroup')
+ group.save()
+
response = self.client.get(
- reverse('load_tag_wiki_text'),
- data = {'tag_id': tag1.id}
+ reverse('load_object_description'),
+ data = {'object_id': group.id,'model_name': 'Group'},
)
self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.content, '')
+
+ def test_load_full_object_description_works(self):
+ group = models.Group(name='somegroup')
+ user = self.create_user('someuser')
+ post_params = {'author': user, 'text':'some text'}
+ post = models.Post.objects.create_new_tag_wiki(**post_params)
+ group.description = post
+ group.save()
+
+ response = self.client.get(
+ reverse('load_object_description'),
+ data = {'object_id': group.id,'model_name': 'Group'},
+ )
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.content, 'some text')
+
+ def test_save_object_description_works(self):
+ group = models.Group(name='somegroup')
+ group.save()
+ admin = self.create_user('admin', status='d')
+ self.client.login(user_id=admin.id, method='force')
+ post_data = {
+ 'object_id': group.id,
+ 'model_name': 'Group',
+ 'text': 'some description'
+ }
+ self.client.post(#ajax post
+ reverse('save_object_description'),
+ data=post_data,
+ HTTP_X_REQUESTED_WITH='XMLHttpRequest'
+ )
+ group = self.reload_object(group)
+ self.assertEqual(group.description.text, 'some description')
+
+ #test edit
+ post_data['text'] = 'edited description'
+ self.client.post(#second post to edit
+ reverse('save_object_description'),
+ data=post_data,
+ HTTP_X_REQUESTED_WITH='XMLHttpRequest'
+ )
+ group = self.reload_object(group)
+ self.assertEqual(group.description.text, 'edited description')
- def test_get_tag_wiki_text_fails(self):
- tag1 = self.create_tag('tag1')
- response = self.client.get(reverse('load_tag_wiki_text'))
- self.assertEqual(response.status_code, 400)#bad request
-
+ def test_load_object_description_fails(self):
+ response = self.client.get(reverse('load_object_description'))
+ self.assertEqual(response.status_code, 404)#bad request
diff --git a/askbot/tests/permission_assertion_tests.py b/askbot/tests/permission_assertion_tests.py
index 2f746ef9..3849ce90 100644
--- a/askbot/tests/permission_assertion_tests.py
+++ b/askbot/tests/permission_assertion_tests.py
@@ -447,9 +447,9 @@ class ReopenQuestionPermissionAssertionTests(utils.AskbotTestCase):
)
- def test_high_rep_nonowner_cannot_reopen(self):
+ def test_high_rep_nonowner_can_reopen(self):
self.other_user.reputation = 1000000
- self.assert_cannot_reopen(user = self.other_user)
+ self.assert_can_reopen(user = self.other_user)
def test_low_rep_admin_can_reopen(self):
self.other_user.set_admin_status()
@@ -482,7 +482,7 @@ class ReopenQuestionPermissionAssertionTests(utils.AskbotTestCase):
self.assert_cannot_reopen(user = self.other_user)
class EditQuestionPermissionAssertionTests(utils.AskbotTestCase):
-
+
def setUp(self):
self.create_user()
self.create_user(username = 'other_user')
@@ -1590,7 +1590,10 @@ class ClosedForumTests(utils.AskbotTestCase):
self.test_url = self.question.get_absolute_url()
self.redirect_to = settings.LOGIN_URL
self.client = Client()
- askbot_settings.ASKBOT_CLOSED_FORUM_MODE = True
+ askbot_settings.update('ASKBOT_CLOSED_FORUM_MODE', True)
+
+ def tearDown(self):
+ askbot_settings.update('ASKBOT_CLOSED_FORUM_MODE', False)
@skipIf('askbot.middleware.forum_mode.ForumModeMiddleware' \
not in settings.MIDDLEWARE_CLASSES,
@@ -1615,6 +1618,3 @@ class ClosedForumTests(utils.AskbotTestCase):
self.client.login(username=self.other_user.username, password=self.password)
response = self.client.get(self.test_url)
self.assertEquals(response.status_code, 200)
-
- def tearDown(self):
- askbot_settings.ASKBOT_CLOSED_FORUM_MODE = False
diff --git a/askbot/tests/post_model_tests.py b/askbot/tests/post_model_tests.py
index 6fd2257b..e61fcd2d 100644
--- a/askbot/tests/post_model_tests.py
+++ b/askbot/tests/post_model_tests.py
@@ -11,9 +11,14 @@ from django.core.cache.backends.locmem import LocMemCache
from django.core.exceptions import ValidationError
from askbot.tests.utils import AskbotTestCase
-from askbot.models import Post, PostRevision, Thread, Tag
+from askbot.models import Post
+from askbot.models import PostRevision
+from askbot.models import Thread
+from askbot.models import Tag
+from askbot.models import Group
from askbot.search.state_manager import DummySearchState
from django.utils import simplejson
+from askbot.conf import settings as askbot_settings
class PostModelTests(AskbotTestCase):
@@ -24,23 +29,11 @@ class PostModelTests(AskbotTestCase):
self.u3 = self.create_user(username='user3')
def test_model_validation(self):
- self.assertRaises(
- NotImplementedError,
- PostRevision.objects.create,
- [],
- {
- 'text': 'blah',
- 'author': self.u1,
- 'revised_at': datetime.datetime.now(),
- 'revision_type': PostRevision.QUESTION_REVISION
- }
- )
-
self.assertRaisesRegexp(
AttributeError,
r"'NoneType' object has no attribute 'revisions'",
# cannot set `revision` without a parent
- PostRevision.objects.create_answer_revision,
+ PostRevision.objects.create,
*[],
**{
'text': 'blah',
@@ -54,57 +47,23 @@ class PostModelTests(AskbotTestCase):
author=self.u1,
revised_at=datetime.datetime.now(),
revision=1,
- revision_type=4
)
self.assertRaisesRegexp(
ValidationError,
- r"{'__all__': \[u'Post field has to be set.'\], 'revision_type': \[u'Value 4 is not a valid choice.'\]}",
+ r"{'__all__': \[u'Post field has to be set.'\]}",
post_revision.save
)
- # revision_type not in (1,2)
-
question = self.post_question(user=self.u1)
- rev2 = PostRevision(post=question, text='blah', author=self.u1, revised_at=datetime.datetime.now(), revision=2, revision_type=PostRevision.QUESTION_REVISION)
+ rev2 = PostRevision(
+ post=question, text='blah', author=self.u1,
+ revised_at=datetime.datetime.now(), revision=2
+ )
rev2.save()
self.assertFalse(rev2.id is None)
- post_revision = PostRevision(
- post=question,
- text='blah',
- author=self.u1,
- revised_at=datetime.datetime.now(),
- revision=2,
- revision_type=PostRevision.ANSWER_REVISION
- )
- self.assertRaisesRegexp(
- ValidationError,
- r"{'__all__': \[u'Revision_type doesn`t match values in question/answer fields.', u'Post revision with this Post and Revision already exists.'\]}",
- post_revision.save
- )
-
-
- post_revision = PostRevision(
- post=question,
- text='blah',
- author=self.u1,
- revised_at=datetime.datetime.now(),
- revision=3,
- revision_type=PostRevision.ANSWER_REVISION
- )
- self.assertRaisesRegexp(
- ValidationError,
- r"{'__all__': \[u'Revision_type doesn`t match values in question/answer fields.'\]}",
- post_revision.save
- )
-
- rev3 = PostRevision.objects.create_question_revision(post=question, text='blah', author=self.u1, revised_at=datetime.datetime.now(), revision_type=123) # revision_type
- self.assertFalse(rev3.id is None)
- self.assertEqual(3, rev3.revision) # By the way: let's test the auto-increase of revision number
- self.assertEqual(PostRevision.QUESTION_REVISION, rev3.revision_type)
-
def test_post_revision_autoincrease(self):
question = self.post_question(user=self.u1)
self.assertEqual(1, question.revisions.all()[0].revision)
@@ -179,6 +138,36 @@ class PostModelTests(AskbotTestCase):
self.assertTrue(p._thread_cache is th)
self.assertEqual('/question/3/lala-x-lala/', p.get_absolute_url(thread=th))
+ def test_get_moderators_with_groups(self):
+ groups_enabled_backup = askbot_settings.GROUPS_ENABLED
+ askbot_settings.update('GROUPS_ENABLED', True)
+ #create group
+ group = Group(name='testers', openness=Group.OPEN)
+ group.save()
+
+ #create one admin and one moderator, and one reg user
+ mod1 = self.create_user('mod1', status='m')
+ adm1 = self.create_user('adm1', status='d')
+ reg1 = self.create_user('reg1')
+ #join them to the group
+ mod1.join_group(group)
+ adm1.join_group(group)
+ reg1.join_group(group)
+ #create one admin and one moderator, and one reg user
+ mod2 = self.create_user('mod2', status='m')
+ adm2 = self.create_user('adm2', status='d')
+ reg2 = self.create_user('reg2')
+ #make a post
+ question = self.post_question(user=reg1, group_id=group.id)
+ #run get_moderators and see that only one admin and one
+ mods = question.get_moderators()
+ self.assertEqual(
+ set([mod1, adm1]),
+ set(mods)
+ )
+ #moderator are in the set of moderators
+ askbot_settings.update('GROUPS_ENABLED', groups_enabled_backup)
+
class ThreadTagModelsTests(AskbotTestCase):
@@ -331,6 +320,7 @@ class ThreadRenderLowLevelCachingTests(AskbotTestCase):
'thread': thread,
'question': thread._question_post(),
'search_state': ss,
+ 'visitor': None
}
proper_html = get_template('widgets/question_summary.html').render(context)
self.assertEqual(test_html, proper_html)
@@ -418,7 +408,7 @@ class ThreadRenderLowLevelCachingTests(AskbotTestCase):
###
cache.cache.delete(key)
- thread.update_summary_html = lambda: "Monkey-patched <<<tag2>>>"
+ thread.update_summary_html = lambda dummy: "Monkey-patched <<<tag2>>>"
self.assertFalse(thread.summary_html_cached())
self.assertIsNone(thread.get_cached_summary_html())
@@ -452,7 +442,8 @@ class ThreadRenderCacheUpdateTests(AskbotTestCase):
'thread': q.thread,
'question': q,
'search_state': DummySearchState(),
- }
+ 'visitor': None
+ }
html = get_template('widgets/question_summary.html').render(context)
return html
@@ -487,15 +478,22 @@ class ThreadRenderCacheUpdateTests(AskbotTestCase):
time.sleep(1.5) # compensate for 1-sec time resolution in some databases
- response = self.client.post(urlresolvers.reverse('edit_question', kwargs={'id': question.id}), data={
- 'title': 'edited title',
- 'text': 'edited body text',
- 'tags': 'tag1 tag2',
- 'summary': 'just some edit',
- })
+ response = self.client.post(
+ urlresolvers.reverse('edit_question', kwargs={'id': question.id}),
+ data={
+ 'title': 'edited title',
+ 'text': 'edited body text',
+ 'tags': 'tag1 tag2',
+ 'summary': 'just some edit',
+ 'select_revision': 'false'
+ }
+ )
self.assertEqual(1, Post.objects.count())
question = Post.objects.all()[0]
- self.assertRedirects(response=response, expected_url=question.get_absolute_url())
+ self.assertRedirects(
+ response=response,
+ expected_url=question.get_absolute_url()
+ )
thread = question.thread
self.assertEqual(0, thread.answer_count)
@@ -574,10 +572,17 @@ class ThreadRenderCacheUpdateTests(AskbotTestCase):
time.sleep(1.5) # compensate for 1-sec time resolution in some databases
self.client.logout()
self.client.login(username='user2', password='pswd')
- response = self.client.post(urlresolvers.reverse('edit_answer', kwargs={'id': answer.id}), data={
- 'text': 'edited body text',
- 'summary': 'just some edit',
- })
+ response = self.client.post(
+ urlresolvers.reverse(
+ 'edit_answer',
+ kwargs={'id': answer.id}
+ ),
+ data={
+ 'text': 'edited body text',
+ 'summary': 'just some edit',
+ 'select_revision': 'false'
+ }
+ )
self.assertRedirects(response=response, expected_url=answer.get_absolute_url())
answer = Post.objects.get(id=answer.id)
diff --git a/askbot/tests/reply_by_email_tests.py b/askbot/tests/reply_by_email_tests.py
index 698662fc..30cb48be 100644
--- a/askbot/tests/reply_by_email_tests.py
+++ b/askbot/tests/reply_by_email_tests.py
@@ -1,6 +1,7 @@
from django.utils.translation import ugettext as _
from askbot.models import ReplyAddress
from askbot.mail.lamson_handlers import PROCESS, VALIDATE_EMAIL, get_parts
+from askbot.mail import extract_user_signature
from askbot import const
@@ -11,9 +12,9 @@ TEST_CONTENT = 'Test content'
TEST_LONG_CONTENT = 'Test content' * 10
class MockPart(object):
- def __init__(self, body):
+ def __init__(self, body, content_type='text/plain'):
self.body = body
- self.content_encoding = {'Content-Type':('text/plain',)}
+ self.content_encoding = {'Content-Type':(content_type,)}
class MockMessage(dict):
@@ -34,13 +35,19 @@ class MockMessage(dict):
self._body = content
self._part = MockPart(content)
+ self._alternatives = []
def body(self):
return self._body
+ def attach_alternative(self, content, content_type):
+ assert content is not None
+ assert content_type is not None
+ self._alternatives.append(MockPart(content, content_type))
+
def walk(self):
"""todo: add real file attachment"""
- return [self._part]
+ return [self._part] + self._alternatives
class ReplyAddressModelTests(AskbotTestCase):
@@ -115,7 +122,7 @@ class ReplyAddressModelTests(AskbotTestCase):
self.assertEquals(post.post_type, "comment")
self.assertEquals(post.text, TEST_CONTENT)
self.assertEquals(self.answer.comments.count(), 2)
-
+
def test_create_question_comment_reply(self):
result = ReplyAddress.objects.create_new(
@@ -136,7 +143,7 @@ class ReplyAddressModelTests(AskbotTestCase):
self.assertEquals(post.text, TEST_LONG_CONTENT)
class EmailSignatureDetectionTests(AskbotTestCase):
-
+
def setUp(self):
self.u1 = self.create_user('user1', status = 'a')
self.u2 = self.create_user('user2', status = 'a')
@@ -162,7 +169,7 @@ class EmailSignatureDetectionTests(AskbotTestCase):
)
PROCESS(msg, address = reply_token.address)
- signature = self.reload_object(self.u2).email_signature
+ signature = self.reload_object(self.u2).email_signature
self.assertEqual(signature, 'Yours Truly')
def test_detect_signature_in_welcome_response(self):
@@ -184,5 +191,5 @@ class EmailSignatureDetectionTests(AskbotTestCase):
address = reply_token.address
)
- signature = self.reload_object(self.u2).email_signature
+ signature = self.reload_object(self.u2).email_signature
self.assertEqual(signature, 'Yours Truly')
diff --git a/askbot/tests/templatefilter_tests.py b/askbot/tests/templatefilter_tests.py
deleted file mode 100644
index a82737a4..00000000
--- a/askbot/tests/templatefilter_tests.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from unittest import TestCase
-from askbot.templatetags import extra_filters_jinja as filters
-from askbot.conf import settings as askbot_settings
-
-class AbsolutizeUrlsTests(TestCase):
- def setUp(self):
- askbot_settings.update('APP_URL', 'http://example.com')
- def test_absolutize_image_urls(self):
- text = """<img class="junk" src="/some.gif"> <IMG SRC='/some.png'>"""
- output = filters.absolutize_urls_func(text)
- self.assertEqual(
- output,
- '<img class="junk" src="http://example.com/some.gif"> <IMG SRC="http://example.com/some.png">'
- )
- def test_absolutize_anchor_urls(self):
- text = """<a class="junk" href="/something">link</a> <A HREF='/something'>link</A>"""
- output = filters.absolutize_urls_func(text)
- self.assertEqual(
- output,
- '<a class="junk" href="http://example.com/something">link</a> <A HREF="http://example.com/something">link</A>'
- )
diff --git a/askbot/tests/thread_model_tests.py b/askbot/tests/thread_model_tests.py
new file mode 100644
index 00000000..baf51e8e
--- /dev/null
+++ b/askbot/tests/thread_model_tests.py
@@ -0,0 +1,129 @@
+from askbot.tests.utils import AskbotTestCase
+from askbot.conf import settings as askbot_settings
+from askbot import models
+from askbot.models.tag import get_global_group
+import django.core.mail
+from django.core.urlresolvers import reverse
+
+class ThreadModelTestsWithGroupsEnabled(AskbotTestCase):
+
+ def setUp(self):
+ self.groups_enabled_backup = askbot_settings.GROUPS_ENABLED
+ askbot_settings.update('GROUPS_ENABLED', True)
+ self.admin = self.create_user('admin', status = 'd')
+ self.user = self.create_user(
+ 'user',
+ notification_schedule = {
+ 'q_ask': 'i',
+ 'q_all': 'i',
+ 'q_ans': 'i',
+ 'q_sel': 'i',
+ 'm_and_c': 'i'
+ }
+ )
+ self.group = models.Group.objects.get_or_create(name='jockeys')
+ self.admin.edit_group_membership(
+ group = self.group,
+ user = self.admin,
+ action = 'add'
+ )
+
+ def tearDown(self):
+ askbot_settings.update('GROUPS_ENABLED', self.groups_enabled_backup)
+
+ def test_private_answer(self):
+ # post question, answer, add answer to the group
+ self.question = self.post_question(self.user)
+
+ self.answer = self.post_answer(
+ user = self.admin,
+ question = self.question,
+ is_private = True
+ )
+
+ thread = self.question.thread
+
+ #test answer counts
+ self.assertEqual(thread.get_answer_count(self.user), 0)
+ self.assertEqual(thread.get_answer_count(self.admin), 1)
+
+ #test mail outbox
+ self.assertEqual(len(django.core.mail.outbox), 0)
+ user = self.reload_object(self.user)
+ self.assertEqual(user.new_response_count, 0)
+
+ self.admin.edit_answer(
+ self.answer,
+ is_private = False
+ )
+ self.assertEqual(len(django.core.mail.outbox), 1)
+ user = self.reload_object(self.user)
+ self.assertEqual(user.new_response_count, 1)
+
+ def test_answer_to_private_question_is_not_globally_visible(self):
+ question = self.post_question(user=self.admin, is_private=True)
+ answer = self.post_answer(question=question, user=self.admin, is_private=False)
+ global_group = get_global_group()
+ self.assertEqual(
+ global_group in set(answer.groups.all()),
+ False
+ )
+
+ def test_answer_to_group_question_is_not_globally_visible(self):
+ #ask into group where user is not a member
+ question = self.post_question(user=self.user, group_id=self.group.id)
+ #answer posted by a group member
+ answer = self.post_answer(question=question, user=self.admin, is_private=False)
+ global_group = get_global_group()
+ self.assertEqual(
+ global_group in set(answer.groups.all()),
+ False
+ )
+
+
+ def test_restrictive_response_publishing(self):
+ #restrictive model should work even with groups
+ #in common between the asker and the answerer
+ common_group = models.Group(
+ name='common',
+ openness=models.Group.OPEN
+ )
+ common_group.save()
+ self.admin.join_group(common_group)
+ self.user.join_group(common_group)
+
+ self.group.moderate_answers_to_enquirers = True
+ self.group.save()
+ question = self.post_question(user=self.user, group_id=self.group.id)
+ answer = self.post_answer(question=question, user=self.admin)
+
+ #answer and the user don't have groups in common
+ answer_groups = set(answer.groups.all())
+ user_groups = set(self.user.get_groups())
+ self.assertEqual(len(answer_groups & user_groups), 0)
+
+ #publish the answer
+ self.client.login(user_id=self.admin.id, method='force')
+ self.client.post(
+ reverse('publish_answer'),
+ data={'answer_id': answer.id},
+ HTTP_X_REQUESTED_WITH='XMLHttpRequest'
+ )
+ #todo: test redirect
+
+ answer = self.reload_object(answer)
+ answer_groups = set(answer.groups.all())
+ self.assertEqual(len(answer_groups & user_groups), 1)
+
+
+
+ def test_permissive_response_publishing(self):
+ self.group.moderate_answers_to_enquirers = False
+ self.group.save()
+ question = self.post_question(user=self.user, group_id=self.group.id)
+ answer = self.post_answer(question=question, user=self.admin)
+
+ #answer and user have one group in common
+ answer_groups = set(answer.groups.all())
+ user_groups = set(self.user.get_groups())
+ self.assertEqual(len(answer_groups & user_groups), 1)
diff --git a/askbot/tests/user_model_tests.py b/askbot/tests/user_model_tests.py
new file mode 100644
index 00000000..df4974dd
--- /dev/null
+++ b/askbot/tests/user_model_tests.py
@@ -0,0 +1,17 @@
+from askbot.tests.utils import AskbotTestCase
+from django.contrib.auth.models import User
+from askbot import models
+from askbot.models.tag import format_personal_group_name
+
+class UserModelTests(AskbotTestCase):
+ """test user model"""
+
+ def test_new_user_has_personal_group(self):
+ user = User.objects.create_user('somebody', 'somebody@example.com')
+ group_name = format_personal_group_name(user)
+ group = models.Group.objects.filter(name=group_name)
+ self.assertEqual(group.count(), 1)
+ memberships = models.GroupMembership.objects.filter(
+ group=group, user=user
+ )
+ self.assertEqual(memberships.count(), 1)
diff --git a/askbot/tests/utils.py b/askbot/tests/utils.py
index b672da1c..ee3cd37e 100644
--- a/askbot/tests/utils.py
+++ b/askbot/tests/utils.py
@@ -4,6 +4,38 @@ from django.test import TestCase
from functools import wraps
from askbot import models
+def with_settings(**settings_dict):
+ """a decorator that will run function with settings
+ then apply previous settings and return the result
+ of the function.
+ If the function raises an exception - decorator
+ still restores the previous settings
+ """
+
+ def decorator(func):
+
+ @wraps(func)
+ def wrapped(*args, **kwargs):
+ from askbot.conf import settings as askbot_settings
+ backup_settings_dict = dict()
+ for key, value in settings_dict.items():
+ backup_settings_dict[key] = getattr(askbot_settings, key)
+ askbot_settings.update(key, value)
+
+ try:
+ return func(*args, **kwargs)
+ except:
+ raise
+ finally:
+ for key, value in backup_settings_dict.items():
+ askbot_settings.update(key, value)
+
+ return wrapped
+
+ return decorator
+
+
+
def create_user(
username = None,
email = None,
@@ -92,7 +124,6 @@ class AskbotTestCase(TestCase):
)
setattr(self, username, user_object)
-
return user_object
def assertRaisesRegexp(self, *args, **kwargs):
@@ -108,6 +139,13 @@ class AskbotTestCase(TestCase):
args_list.pop(1)#so we can remove an item
self.assertRaises(*args_list, **kwargs)
+ def assertQuerysetEqual(self, qs1, qs2, transform=repr, ordered=True):
+ '''borrowed from django1.4 and modified a bit'''
+ items = map(transform, qs1)
+ values = map(transform, qs2)
+ if not ordered:
+ return self.assertEqual(set(items), set(values))
+ return self.assertEqual(list(items), list(values))
def post_question(
self,
@@ -118,6 +156,8 @@ class AskbotTestCase(TestCase):
by_email = False,
wiki = False,
is_anonymous = False,
+ is_private = False,
+ group_id = None,
follow = False,
timestamp = None,
):
@@ -133,13 +173,15 @@ class AskbotTestCase(TestCase):
user = self.user
question = user.post_question(
- title = title,
- body_text = body_text,
- tags = tags,
- by_email = by_email,
- wiki = wiki,
- is_anonymous = is_anonymous,
- timestamp = timestamp
+ title=title,
+ body_text=body_text,
+ tags=tags,
+ by_email=by_email,
+ wiki=wiki,
+ is_anonymous=is_anonymous,
+ is_private=is_private,
+ group_id=group_id,
+ timestamp=timestamp
)
if follow:
@@ -147,6 +189,59 @@ class AskbotTestCase(TestCase):
return question
+ def edit_question(self,
+ user=None,
+ question=None,
+ title='edited title',
+ body_text='edited body text',
+ revision_comment='edited the question',
+ tags='one two three four',
+ wiki=False,
+ edit_anonymously=False,
+ is_private=False,
+ timestamp=None,
+ force=False,#if True - bypass the assert
+ by_email=False
+ ):
+ """helper editing the question,
+ a bunch of fields are pre-filled for the ease of use
+ """
+ user.edit_question(
+ question=question,
+ title=title,
+ body_text=body_text,
+ revision_comment=revision_comment,
+ tags=tags,
+ wiki=wiki,
+ edit_anonymously=edit_anonymously,
+ is_private=is_private,
+ timestamp=timestamp,
+ force=False,#if True - bypass the assert
+ by_email=False
+ )
+
+ def edit_answer(self,
+ user=None,
+ answer=None,
+ body_text='edited answer body',
+ revision_comment='editing answer',
+ wiki=False,
+ is_private=False,
+ timestamp=None,
+ force=False,#if True - bypass the assert
+ by_email=False
+ ):
+ user.edit_answer(
+ answer=answer,
+ body_text=body_text,
+ revision_comment=revision_comment,
+ wiki=wiki,
+ is_private=is_private,
+ timestamp=timestamp,
+ force=force,
+ by_email=by_email
+ )
+
def reload_object(self, obj):
"""reloads model object from the database
"""
@@ -160,6 +255,7 @@ class AskbotTestCase(TestCase):
by_email = False,
follow = False,
wiki = False,
+ is_private = False,
timestamp = None
):
@@ -171,6 +267,7 @@ class AskbotTestCase(TestCase):
by_email = by_email,
follow = follow,
wiki = wiki,
+ is_private = is_private,
timestamp = timestamp
)
@@ -186,6 +283,11 @@ class AskbotTestCase(TestCase):
tag.save()
return tag
+ def create_group(self, group_name=None, openness=models.Group.OPEN):
+ return models.Group.objects.get_or_create(
+ name='private', openness=openness
+ )
+
def post_comment(
self,
user = None,
diff --git a/askbot/tests/utils_tests.py b/askbot/tests/utils_tests.py
new file mode 100644
index 00000000..c8526ad1
--- /dev/null
+++ b/askbot/tests/utils_tests.py
@@ -0,0 +1,57 @@
+from django.test import TestCase
+from askbot.tests.utils import with_settings
+from askbot.utils.url_utils import urls_equal
+from askbot.utils.html import absolutize_urls
+from askbot.conf import settings as askbot_settings
+
+class UrlUtilsTests(TestCase):
+
+ def tests_urls_equal(self):
+ e = urls_equal
+ self.assertTrue(e('', ''))
+ self.assertTrue(e('', '/', True))
+ self.assertTrue(e('http://cnn.com', 'http://cnn.com/', True))
+
+ self.assertFalse(e('https://cnn.com', 'http://cnn.com'))
+ self.assertFalse(e('http://cnn.com:80', 'http://cnn.com:8000'))
+
+ self.assertTrue(e('http://cnn.com/path', 'http://cnn.com/path/', True))
+ self.assertFalse(e('http://cnn.com/path', 'http://cnn.com/path/'))
+
+
+class HTMLUtilsTests(TestCase):
+ """tests for :mod:`askbot.utils.html` module"""
+
+ @with_settings(APP_URL='http://example.com')
+ def test_absolutize_urls(self):
+ text = """<img class="junk" src="/some.gif"> <img class="junk" src="/cat.gif"> <IMG SRC='/some.png'>"""
+ #jinja register.filter decorator works in a weird way
+ self.assertEqual(
+ absolutize_urls(text),
+ '<img class="junk" src="http://example.com/some.gif" style="max-width:500px;"> <img class="junk" src="http://example.com/cat.gif" style="max-width:500px;"> <IMG SRC="http://example.com/some.png" style="max-width:500px;">'
+ )
+
+ text = """<a class="junk" href="/something">link</a> <A HREF='/something'>link</A>"""
+ #jinja register.filter decorator works in a weird way
+ self.assertEqual(
+ absolutize_urls(text),
+ '<a class="junk" href="http://example.com/something">link</a> <A HREF="http://example.com/something">link</A>'
+ )
+
+ text = '<img src="/upfiles/13487900323638005.png" alt="" />'
+ self.assertEqual(
+ absolutize_urls(text),
+ '<img src="http://example.com/upfiles/13487900323638005.png" style="max-width:500px;" alt="" />'
+ )
+
+ text = 'ohaouhaosthoanstoahuaou<br /><img src="/upfiles/13487906221942257.png" alt="" /><img class="gravatar" title="Evgeny4" src="http://kp-dev.askbot.com/avatar/render_primary/5/32/" alt="Evgeny4 gravatar image" width="32" height="32" />'
+ self.assertEqual(
+ absolutize_urls(text),
+ 'ohaouhaosthoanstoahuaou<br /><img src="http://example.com/upfiles/13487906221942257.png" style="max-width:500px;" alt="" /><img class="gravatar" title="Evgeny4" src="http://kp-dev.askbot.com/avatar/render_primary/5/32/" alt="Evgeny4 gravatar image" width="32" height="32" />'
+ )
+
+ text = '<a href="/upfiles/13487909784287052.png"><img src="/upfiles/13487909942351405.png" alt="" /></a><img src="http://i2.cdn.turner.com/cnn/dam/assets/120927033530-ryder-cup-captains-wall-4-tease.jpg" alt="" width="160" height="90" border="0" />and some text<br />aouaosutoaehut'
+ self.assertEqual(
+ absolutize_urls(text),
+ '<a href="http://example.com/upfiles/13487909784287052.png"><img src="http://example.com/upfiles/13487909942351405.png" style="max-width:500px;" alt="" /></a><img src="http://i2.cdn.turner.com/cnn/dam/assets/120927033530-ryder-cup-captains-wall-4-tease.jpg" alt="" width="160" height="90" border="0" />and some text<br />aouaosutoaehut'
+ )
diff --git a/askbot/tests/view_context_tests.py b/askbot/tests/view_context_tests.py
new file mode 100644
index 00000000..4c3713d0
--- /dev/null
+++ b/askbot/tests/view_context_tests.py
@@ -0,0 +1,30 @@
+from django.contrib.auth.models import AnonymousUser
+from askbot.tests.utils import AskbotTestCase
+from askbot.models import Group
+from askbot.views import context
+
+class ViewContextTests(AskbotTestCase):
+ def test_get_for_inbox_anonymous(self):
+ anon = AnonymousUser()
+ inbox_context = context.get_for_inbox(anon)
+ self.assertEqual(inbox_context, None)
+
+ def test_get_for_inbox_group_join(self):
+ mod = self.create_user('mod', status='d')
+ group = Group(name='grp', openness=Group.MODERATED)
+ group.save()
+ mod.join_group(group)
+
+ simple = self.create_user('simple')
+ simple.join_group(group)
+
+ inbox_context = context.get_for_inbox(mod)
+
+ self.assertEqual(inbox_context['re_count'], 0)
+ self.assertEqual(inbox_context['flags_count'], 0)
+ self.assertEqual(inbox_context['group_join_requests_count'], 1)
+
+ inbox_context = context.get_for_inbox(simple)
+ values = set(inbox_context.values())
+ self.assertEqual(values, set([0, 0, 0]))
+
diff --git a/askbot/tests/widget_tests.py b/askbot/tests/widget_tests.py
new file mode 100644
index 00000000..98c5a8aa
--- /dev/null
+++ b/askbot/tests/widget_tests.py
@@ -0,0 +1,169 @@
+from datetime import datetime
+
+from askbot import models
+from askbot.tests.utils import AskbotTestCase
+
+from django.test.client import Client
+from django.core.urlresolvers import reverse
+
+
+class WidgetViewsTests(AskbotTestCase):
+
+ def setUp(self):
+ self.client = Client()
+ self.widget = models.AskWidget.objects.create(title='foo widget')
+ self.user = self.create_user('user1')
+ self.user.set_password('sample')
+ self.user.save()
+ self.good_data = {'title': 'This is a title question',
+ 'ask_anonymously': False}
+
+ def test_post_with_auth(self):
+ self.client.login(username='user1', password='sample')
+ response = self.client.post(reverse('ask_by_widget', args=(self.widget.id, )), self.good_data)
+ self.assertEquals(response.status_code, 302)
+ self.client.logout()
+
+ def test_post_without_auth(self):
+ #weird issue
+ response = self.client.post(reverse('ask_by_widget', args=(self.widget.id, )), self.good_data)
+ self.assertEquals(response.status_code, 302)
+ self.assertTrue('widget_question' in self.client.session)
+ self.assertEquals(self.client.session['widget_question']['title'],
+ self.good_data['title'])
+
+ def test_post_after_login(self):
+ widget_question_data = { 'title': 'testing post after login, does it?',
+ 'author': self.user,
+ 'added_at': datetime.now(),
+ 'wiki': False,
+ 'text': ' ',
+ 'tagnames': '',
+ 'is_anonymous': False
+ }
+
+ self.client.login(username='user1', password='sample')
+
+ session = self.client.session
+ session['widget_question'] = widget_question_data
+ session.save()
+ response = self.client.get(
+ reverse('ask_by_widget', args=(self.widget.id, )),
+ {'action': 'post-after-login'}
+ )
+ self.assertFalse('widget_question' in self.client.session)
+ self.assertEquals(response.status_code, 302)
+ #verify posting question
+
+ def test_render_widget_view(self):
+ response = self.client.get(reverse('render_ask_widget', args=(self.widget.id, )))
+ self.assertEquals(200, response.status_code)
+ mimetype = 'text/javascript'
+ self.assertTrue(mimetype in response['Content-Type'])
+
+
+class WidgetLoginViewTest(AskbotTestCase):
+
+ def test_correct_template_loading(self):
+ client = Client()
+ response = client.get(reverse('widget_signin'))
+ template_name = 'authopenid/widget_signin.html'
+ templates = [template.name for template in response.templates]
+ self.assertTrue(template_name in templates)
+
+class WidgetCreatorViewsTests(AskbotTestCase):
+
+ def setUp(self):
+ self.client = Client()
+ self.user = self.create_user('user1')
+ self.user.set_password('testpass')
+ self.user.set_admin_status()
+ self.user.save()
+ self.widget = models.AskWidget.objects.create(title='foo widget')
+
+ def test_list_ask_widget_view(self):
+ self.client.login(username='user1', password='testpass')
+ response = self.client.get(reverse('list_widgets', args=('ask',)))
+ self.assertEquals(response.status_code, 200)
+ self.assertTrue('widgets' in response.context)
+
+ def test_create_ask_widget_get(self):
+ self.client.login(username='user1', password='testpass')
+ response = self.client.get(reverse('create_widget', args=('ask',)))
+ self.assertEquals(response.status_code, 200)
+ self.assertTrue('form' in response.context)
+
+ def test_create_ask_widget_post(self):
+ self.client.login(username='user1', password='testpass')
+ post_data = {'title': 'Test widget'}
+ response = self.client.post(reverse('create_widget', args=('ask',)), post_data)
+ self.assertEquals(response.status_code, 302)
+
+ def test_edit_ask_widget_get(self):
+ self.client.login(username='user1', password='testpass')
+ response = self.client.get(reverse('edit_widget',
+ args=('ask', self.widget.id, )))
+ self.assertEquals(response.status_code, 200)
+ self.assertTrue('form' in response.context)
+
+ def test_edit_ask_widget_post(self):
+ self.client.login(username='user1', password='testpass')
+ post_data = {'title': 'Test lalalla'}
+ response = self.client.post(reverse('edit_widget',
+ args=('ask', self.widget.id, )), post_data)
+ self.assertEquals(response.status_code, 302)
+
+ def test_delete_ask_widget_get(self):
+ self.client.login(username='user1', password='testpass')
+ response = self.client.get(reverse('delete_widget',
+ args=('ask', self.widget.id, )))
+ self.assertEquals(response.status_code, 200)
+ self.assertTrue('widget' in response.context)
+
+ def test_delete_ask_widget_post(self):
+ self.client.login(username='user1', password='testpass')
+ response = self.client.post(reverse('delete_widget',
+ args=('ask', self.widget.id, )))
+ self.assertEquals(response.status_code, 302)
+
+ #this test complains about 404.html template but it's correct
+ #def test_bad_url(self):
+ # self.client.login(username='user1', password='testpass')
+ # response = self.client.get('/widgets/foo/create/')
+ # self.assertEquals(404, response.status_code)
+
+
+class QuestionWidgetViewsTests(AskbotTestCase):
+
+ def setUp(self):
+ self.user = self.create_user('testuser')
+ self.client = Client()
+ self.widget = models.QuestionWidget.objects.create(title="foo",
+ question_number=5, search_query='test',
+ tagnames='test')
+
+ #we post 6 questions!
+ titles = (
+ 'test question 1', 'this is a test',
+ 'without the magic word', 'test test test',
+ 'test just another test', 'no magic word',
+ 'test another', 'I can no believe is a test'
+ )
+
+ tagnames = 'test foo bar'
+ for title in titles:
+ self.post_question(title=title, tags=tagnames)
+
+ def test_valid_response(self):
+ filter_params = {
+ 'title__icontains': self.widget.search_query,
+ 'tags__name__in': self.widget.tagnames.split(' ')
+ }
+
+ threads = models.Thread.objects.filter(**filter_params)[:5]
+
+ response = self.client.get(reverse('question_widget', args=(self.widget.id, )))
+ self.assertEquals(200, response.status_code)
+
+ self.assertQuerysetEqual(threads, response.context['threads'])
+ self.assertEquals(self.widget, response.context['widget'])
diff --git a/askbot/urls.py b/askbot/urls.py
index 799cc346..362a16ee 100644
--- a/askbot/urls.py
+++ b/askbot/urls.py
@@ -31,9 +31,9 @@ APP_PATH = os.path.dirname(__file__)
urlpatterns = patterns('',
url(r'^$', views.readers.index, name='index'),
url(
- r'^sitemap.xml$',
- 'django.contrib.sitemaps.views.sitemap',
- {'sitemaps': sitemaps},
+ r'^sitemap.xml$',
+ 'django.contrib.sitemaps.views.sitemap',
+ {'sitemaps': sitemaps},
name='sitemap'
),
#no translation for this url!!
@@ -43,13 +43,13 @@ urlpatterns = patterns('',
url(r'^%s$' % _('privacy/'), views.meta.privacy, name='privacy'),
url(r'^%s$' % _('help/'), views.meta.help, name='help'),
url(
- r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('edit/')),
- views.writers.edit_answer,
+ r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('edit/')),
+ views.writers.edit_answer,
name='edit_answer'
),
url(
- r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('revisions/')),
- views.readers.revisions,
+ r'^%s(?P<id>\d+)/%s$' % (_('answers/'), _('revisions/')),
+ views.readers.revisions,
kwargs = {'post_type': 'answer'},
name='answer_revisions'
),
@@ -67,63 +67,102 @@ urlpatterns = patterns('',
r'(%s)?' % r'/page:(?P<page>\d+)' +
r'/$'),
- views.readers.questions,
+ views.readers.questions,
name='questions'
),
-
# END main page urls
-
+
url(
r'^api/get_questions/',
views.commands.api_get_questions,
- name = 'api_get_questions'
+ name='api_get_questions'
+ ),
+ url(
+ r'^get-thread-shared-users/',
+ views.commands.get_thread_shared_users,
+ name='get_thread_shared_users'
+ ),
+ url(
+ r'^get-thread-shared-groups/',
+ views.commands.get_thread_shared_groups,
+ name='get_thread_shared_groups'
+ ),
+ url(
+ r'^moderate-group-join-request/',
+ views.commands.moderate_group_join_request,
+ name='moderate_group_join_request'
+ ),
+ url(
+ r'^save-draft-question/',
+ views.commands.save_draft_question,
+ name = 'save_draft_question'
+ ),
+ url(
+ r'^save-draft-answer/',
+ views.commands.save_draft_answer,
+ name = 'save_draft_answer'
+ ),
+ url(
+ r'^share-question-with-group/',
+ views.commands.share_question_with_group,
+ name='share_question_with_group'
+ ),
+ url(
+ r'^share-question-with-user/',
+ views.commands.share_question_with_user,
+ name='share_question_with_user'
),
url(
- r'^%s%s$' % (_('questions/'), _('ask/')),
- views.writers.ask,
+ r'^get-users-info/',
+ views.commands.get_users_info,
+ name='get_users_info'
+ ),
+ url(
+ r'^get-editor/',
+ views.commands.get_editor,
+ name='get_editor'
+ ),
+ url(
+ r'^%s%s$' % (_('questions/'), _('ask/')),
+ views.writers.ask,
name='ask'
),
url(
- r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('edit/')),
- views.writers.edit_question,
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('edit/')),
+ views.writers.edit_question,
name='edit_question'
),
url(#this url is both regular and ajax
- r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('retag/')),
- views.writers.retag_question,
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('retag/')),
+ views.writers.retag_question,
name='retag_question'
),
url(
- r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('close/')),
- views.commands.close,
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('close/')),
+ views.commands.close,
name='close'
),
url(
- r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('reopen/')),
- views.commands.reopen,
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('reopen/')),
+ views.commands.reopen,
name='reopen'
),
url(
- r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('answer/')),
- views.writers.answer,
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('answer/')),
+ views.writers.answer,
name='answer'
),
url(#ajax only
- r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('vote/')),
- views.commands.vote,
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('vote/')),
+ views.commands.vote,
name='vote'
),
url(
- r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('revisions/')),
- views.readers.revisions,
+ r'^%s(?P<id>\d+)/%s$' % (_('questions/'), _('revisions/')),
+ views.readers.revisions,
kwargs = {'post_type': 'question'},
name='question_revisions'
),
- url(
- r'^%s%s$' % (_('widgets/'), _('questions/')),
- views.readers.widget_questions,
- name='widget_questions'
- ),
url(#ajax only
r'^comment/upvote/$',
views.commands.upvote_comment,
@@ -136,7 +175,7 @@ urlpatterns = patterns('',
),
url(#ajax only
r'^post_comments/$',
- views.writers.post_comments,
+ views.writers.post_comments,
name='post_comments'
),
url(#ajax only
@@ -146,19 +185,44 @@ urlpatterns = patterns('',
),
url(#ajax only
r'^comment/delete/$',
- views.writers.delete_comment,
+ views.writers.delete_comment,
name='delete_comment'
),
url(#ajax only
r'^comment/get_text/$',
- views.readers.get_comment,
+ views.readers.get_comment,
name='get_comment'
),
+ url(#post only
+ r'^comment/convert/$',
+ views.writers.comment_to_answer,
+ name='comment_to_answer'
+ ),
+ url(#post only
+ r'^answer/convert/$',
+ views.writers.answer_to_comment,
+ name='answer_to_comment'
+ ),
+ url(#post only
+ r'^answer/publish/$',
+ views.commands.publish_answer,
+ name='publish_answer'
+ ),
url(
- r'^%s$' % _('tags/'),
- views.readers.tags,
+ r'^%s$' % _('tags/'),
+ views.readers.tags,
name='tags'
),
+ url(
+ r'^%s$' % _('suggested-tags/'),
+ views.meta.list_suggested_tags,
+ name = 'list_suggested_tags'
+ ),
+ url(#ajax only
+ r'^%s$' % 'moderate-suggested-tag',
+ views.commands.moderate_suggested_tag,
+ name = 'moderate_suggested_tag'
+ ),
#todo: collapse these three urls and use an extra json data var
url(#ajax only
r'^%s%s$' % ('mark-tag/', 'interesting/'),
@@ -200,14 +264,29 @@ urlpatterns = patterns('',
name = 'get_tag_list'
),
url(
- r'^load-tag-wiki-text/',
- views.commands.load_tag_wiki_text,
- name = 'load_tag_wiki_text'
+ r'^load-object-description/',
+ views.commands.load_object_description,
+ name = 'load_object_description'
+ ),
+ url(#ajax only
+ r'^save-object-description/',
+ views.commands.save_object_description,
+ name = 'save_object_description'
),
url(#ajax only
- r'^save-tag-wiki-text/',
- views.commands.save_tag_wiki_text,
- name = 'save_tag_wiki_text'
+ r'^add-tag-category/',
+ views.commands.add_tag_category,
+ name = 'add_tag_category'
+ ),
+ url(#ajax only
+ r'^rename-tag/',
+ views.commands.rename_tag,
+ name = 'rename_tag'
+ ),
+ url(#
+ r'^delete-tag/',
+ views.commands.delete_tag,
+ name = 'delete_tag'
),
url(#ajax only
r'^save-group-logo-url/',
@@ -220,9 +299,19 @@ urlpatterns = patterns('',
name = 'delete_group_logo'
),
url(#ajax only
+ r'^add-group/',
+ views.commands.add_group,
+ name = 'add_group'
+ ),
+ url(#ajax only
r'^toggle-group-profile-property/',
views.commands.toggle_group_profile_property,
- name = 'toggle_group_profile_property'
+ name='toggle_group_profile_property'
+ ),
+ url(#ajax only
+ r'^set-group-openness/',
+ views.commands.set_group_openness,
+ name='set_group_openness'
),
url(#ajax only
r'^edit-object-property-text/',
@@ -246,12 +335,12 @@ urlpatterns = patterns('',
),
url(
r'^%s$' % _('users/'),
- views.users.users,
+ views.users.show_users,
name='users'
),
url(
r'^%s%s(?P<group_id>\d+)/(?P<group_slug>.*)/$' % (_('users/'), _('by-group/')),
- views.users.users,
+ views.users.show_users,
kwargs = {'by_group': True},
name = 'users_by_group'
),
@@ -295,6 +384,11 @@ urlpatterns = patterns('',
views.meta.badge,
name='badge'
),
+ url(
+ r'get-html-template/',
+ views.commands.get_html_template,
+ name='get_html_template'
+ ),
url(#ajax only
r'^%s%s$' % (_('messages/'), _('markread/')),
views.commands.read_message,
@@ -325,8 +419,62 @@ urlpatterns = patterns('',
views.commands.join_or_leave_group,
name = 'join_or_leave_group'
),
+ #widgets url!
+ url(
+ r'^%s$' % (_('widgets/')),
+ views.widgets.widgets,
+ name = 'widgets'
+ ),
+
+ url(
+ r'^%s%s(?P<widget_id>\d+)/$' % (_('widgets/'), _('ask/')),
+ views.widgets.ask_widget,
+ name = 'ask_by_widget'
+ ),
+ url(
+ r'^%s%s(?P<widget_id>\d+).js$' % (_('widgets/'), _('ask/')),
+ views.widgets.render_ask_widget_js,
+ name = 'render_ask_widget'
+ ),
+ url(
+ r'^%s%s(?P<widget_id>\d+).css$' % (_('widgets/'), _('ask/')),
+ views.widgets.render_ask_widget_css,
+ name = 'render_ask_widget_css'
+ ),
+
+ url(
+ r'^%s%s%s$' % (_('widgets/'), _('ask/'), _('complete/')),
+ views.widgets.ask_widget_complete,
+ name = 'ask_by_widget_complete'
+ ),
+ url(
+ r'^%s(?P<model>\w+)/%s$' % (_('widgets/'), _('create/')),
+ views.widgets.create_widget,
+ name = 'create_widget'
+ ),
+ url(
+ r'^%s(?P<model>\w+)/%s(?P<widget_id>\d+)/$' % (_('widgets/'), _('edit/')),
+ views.widgets.edit_widget,
+ name = 'edit_widget'
+ ),
+ url(
+ r'^%s(?P<model>\w+)/%s(?P<widget_id>\d+)/$' % (_('widgets/'), _('delete/')),
+ views.widgets.delete_widget,
+ name = 'delete_widget'
+ ),
+
+ url(
+ r'^%s(?P<model>\w+)/$' % (_('widgets/')),
+ views.widgets.list_widgets,
+ name = 'list_widgets'
+ ),
+ url(
+ r'^widgets/questions/(?P<widget_id>\d+)/$',
+ views.widgets.question_widget,
+ name = 'question_widget'
+ ),
url(
- r'^feeds/(?P<url>.*)/$',
+ r'^feeds/(?P<url>.*)/$',
'django.contrib.syndication.views.feed',
{'feed_dict': feeds},
name='feeds'
@@ -336,7 +484,7 @@ urlpatterns = patterns('',
url(r'^%s$' % _('feedback/'), views.meta.feedback, name='feedback'),
#url(r'^feeds/rss/$', RssLastestQuestionsFeed, name="latest_questions_feed"),
url(
- r'^doc/(?P<path>.*)$',
+ r'^doc/(?P<path>.*)$',
'django.views.static.serve',
{'document_root': os.path.join(APP_PATH,'doc','build','html').replace('\\','/')},
name='askbot_docs',
@@ -365,20 +513,21 @@ urlpatterns = patterns('',
{'domain': 'djangojs','packages': ('askbot',)},
name = 'askbot_jsi18n'
),
+ url('^messages/', include('group_messaging.urls')),
)
#todo - this url below won't work, because it is defined above
#therefore the stackexchange urls feature won't work
if getattr(settings, 'ASKBOT_USE_STACKEXCHANGE_URLS', False):
urlpatterns += (url(
- r'^%s(?P<id>\d+)/' % _('questions/'),
- views.readers.question,
+ r'^%s(?P<id>\d+)/' % _('questions/'),
+ views.readers.question,
name='question'
),)
else:
urlpatterns += (url(
- r'^%s(?P<id>\d+)/' % _('question/'),
- views.readers.question,
+ r'^%s(?P<id>\d+)/' % _('question/'),
+ views.readers.question,
name='question'
),)
diff --git a/askbot/utils/category_tree.py b/askbot/utils/category_tree.py
new file mode 100644
index 00000000..4406bdfd
--- /dev/null
+++ b/askbot/utils/category_tree.py
@@ -0,0 +1,149 @@
+"""This is temporary code to parse category
+tree, stored in the settings.
+The tree is plain text, with levels of branching
+reflected by indentation (2 spaces per level).
+example of desired structure, when input is parsed
+
+ cat_tree = [
+ ['dummy',
+ [
+ ['tires', [
+ ['michelin', [
+ ['trucks', []],
+ ['cars', []],
+ ['motorcycles', []]
+ ]
+ ],
+ ['good year', []],
+ ['honda', []],
+ ]
+ ],
+ ['abandonment', []],
+ ['chile', []],
+ ['vulcanization', []],
+ ]
+ ]
+ ]
+"""
+from askbot.conf import settings as askbot_settings
+from django.utils import simplejson
+
+def get_leaf_index(tree, leaf_name):
+ children = tree[1]
+ for index, child in enumerate(children):
+ if child[0] == leaf_name:
+ return index
+ return None
+
+def _get_subtree(tree, path):
+ clevel = tree
+ for pace in path:
+ clevel = clevel[1][pace]
+ return clevel
+
+def get_subtree(tree, path):
+ """path always starts with 0,
+ and is a list of integers"""
+ assert(path[0] == 0)
+ if len(path) == 1:#special case
+ return tree[0]
+ else:
+ return _get_subtree(tree[0], path[1:])
+
+def sort_tree(tree):
+ """sorts contents of the nodes alphabetically"""
+ tree = sorted(tree, lambda x,y: cmp(x[0], y[0]))
+ for item in tree:
+ item[1] = sort_tree(item[1])
+ return tree
+
+def get_data():
+ """returns category tree data structure encoded as json
+ or None, if category_tree is disabled
+ """
+ if askbot_settings.TAG_SOURCE == 'category-tree':
+ return simplejson.loads(askbot_settings.CATEGORY_TREE)
+ else:
+ return None
+
+def _get_leaf_names(subtree):
+ leaf_names = set()
+ for leaf in subtree:
+ leaf_names.add(leaf[0])
+ leaf_names |= _get_leaf_names(leaf[1])
+ return leaf_names
+
+def get_leaf_names(tree = None):
+ """returns set of leaf names"""
+ data = tree or get_data()
+ if data is None:
+ return set()
+ return _get_leaf_names(data[0][1])
+
+def path_is_valid(tree, path):
+ try:
+ get_subtree(tree, path)
+ return True
+ except IndexError:
+ return False
+ except AssertionError:
+ return False
+
+def add_category(tree, category_name, path):
+ subtree = get_subtree(tree, path)
+ children = subtree[1]
+ children.append([category_name, []])
+ children = sorted(children, lambda x,y: cmp(x[0], y[0]))
+ subtree[1] = children
+ new_path = path[:]
+ #todo: reformulate all paths in terms of names?
+ new_item_index = get_leaf_index(subtree, category_name)
+ assert new_item_index != None
+ new_path.append(new_item_index)
+ return new_path
+
+def _has_category(tree, category_name):
+ for item in tree:
+ if item[0] == category_name:
+ return True
+ if _has_category(item[1], category_name):
+ return True
+ return False
+
+def has_category(tree, category_name):
+ """true if category is in tree"""
+ #skip the dummy
+ return _has_category(tree[0][1], category_name)
+
+def rename_category(
+ tree, from_name = None, to_name = None, path = None
+):
+ if to_name == from_name:
+ return
+ subtree = get_subtree(tree, path[:-1])
+ from_index = get_leaf_index(subtree, from_name)
+ #todo possibly merge if to_name exists on the same level
+ #to_index = get_leaf_index(subtree, to_name)
+ child = subtree[1][from_index]
+ child[0] = to_name
+ return sort_tree(tree)
+
+def _delete_category(tree, name):
+ for item in tree:
+ if item[0] == name:
+ tree.remove(item)
+ return True
+ if _delete_category(item[1], name):
+ return True
+ return False
+
+def delete_category(tree, name, path):
+ subtree = get_subtree(tree, path[:-1])
+ del_index = get_leaf_index(subtree, name)
+ subtree[1].pop(del_index)
+ return sort_tree(tree)
+
+def save_data(tree):
+ assert(askbot_settings.TAG_SOURCE == 'category-tree')
+ tree_json = simplejson.dumps(tree)
+ askbot_settings.update('CATEGORY_TREE', tree_json)
diff --git a/askbot/utils/console.py b/askbot/utils/console.py
index fe6ad29e..a691d961 100644
--- a/askbot/utils/console.py
+++ b/askbot/utils/console.py
@@ -2,8 +2,16 @@
"""
import sys
import time
+import logging
from askbot.utils import path
+def start_printing_db_queries():
+ """starts logging database queries into console,
+ should be used for debugging only"""
+ logger = logging.getLogger('django.db.backends')
+ logger.setLevel(logging.DEBUG)
+ logger.addHandler(logging.StreamHandler())
+
def choice_dialog(prompt_phrase, choices = None, invalid_phrase = None):
"""prints a prompt, accepts keyboard input
and makes sure that user response is one of given
@@ -92,14 +100,8 @@ class ProgressBar(object):
def __iter__(self):
return self
- def next(self):
-
- try:
- result = self.iterable.next()
- except StopIteration:
- if self.length > 0:
- sys.stdout.write('\n')
- raise
+ def print_progress_bar(self):
+ """prints the progress bar"""
sys.stdout.write('\b'*len(self.progress))
@@ -112,5 +114,17 @@ class ProgressBar(object):
sys.stdout.write(self.progress)
sys.stdout.flush()
+
+ def next(self):
+
+ try:
+ result = self.iterable.next()
+ except StopIteration:
+ if self.length > 0:
+ self.print_progress_bar()
+ sys.stdout.write('\n')
+ raise
+
+ self.print_progress_bar()
self.counter += 1
return result
diff --git a/askbot/utils/decorators.py b/askbot/utils/decorators.py
index 0042df8f..da1cd7db 100644
--- a/askbot/utils/decorators.py
+++ b/askbot/utils/decorators.py
@@ -87,6 +87,7 @@ def ajax_only(view_func):
if data is None:
data = {}
except Exception, e:
+ #todo: also check field called "message"
if hasattr(e, 'messages'):
if len(e.messages) > 1:
message = u'<ul>' + \
diff --git a/askbot/utils/forms.py b/askbot/utils/forms.py
index b8ed253b..6f57f71f 100644
--- a/askbot/utils/forms.py
+++ b/askbot/utils/forms.py
@@ -3,11 +3,15 @@ from django import forms
from django.http import str_to_unicode
from django.contrib.auth.models import User
from django.conf import settings
+from django.http import Http404
+from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe
from askbot.conf import settings as askbot_settings
from askbot.utils.slug import slugify
+from askbot.utils.functions import split_list
from askbot import const
+from longerusername import MAX_USERNAME_LENGTH
import logging
import urllib
@@ -26,6 +30,35 @@ def clean_next(next, default = None):
def get_next_url(request, default = None):
return clean_next(request.REQUEST.get('next'), default)
+def get_db_object_or_404(params):
+ """a utility function that returns an object
+ in return to the model_name and object_id
+
+ only specific models are accessible
+ """
+ from askbot import models
+ try:
+ model_name = params['model_name']
+ assert(model_name=='Group')
+ model = models.get_model(model_name)
+ obj_id = forms.IntegerField().clean(params['object_id'])
+ return get_object_or_404(model, id=obj_id)
+ except Exception:
+ #need catch-all b/c of the nature of the function
+ raise Http404
+
+def format_errors(error_list):
+ """If there is only one error - returns a string
+ corresponding to that error, to remove the <ul> tag.
+
+ If there is > 1 error - then convert the error_list into
+ a string.
+ """
+ if len(error_list) == 1:
+ return unicode(error_list[0])
+ else:
+ return unicode(error_list)
+
class StrippedNonEmptyCharField(forms.CharField):
def clean(self, value):
value = value.strip()
@@ -58,6 +91,7 @@ class UserNameField(StrippedNonEmptyCharField):
must_exist=False,
skip_clean=False,
label=_('Choose a screen name'),
+ widget_attrs=None,
**kw
):
self.must_exist = must_exist
@@ -73,16 +107,25 @@ class UserNameField(StrippedNonEmptyCharField):
'multiple-taken': _('sorry, we have a serious error - user name is taken by several users'),
'invalid': _('user name can only consist of letters, empty space and underscore'),
'meaningless': _('please use at least some alphabetic characters in the user name'),
+ 'noemail': _('symbol "@" is not allowed')
}
if 'error_messages' in kw:
error_messages.update(kw['error_messages'])
del kw['error_messages']
- super(UserNameField,self).__init__(max_length=30,
+
+ if widget_attrs:
+ widget_attrs.update(login_form_widget_attrs)
+ else:
+ widget_attrs = login_form_widget_attrs
+
+ max_length = MAX_USERNAME_LENGTH()
+ super(UserNameField,self).__init__(
+ max_length=max_length,
widget=forms.TextInput(attrs=login_form_widget_attrs),
label=label,
error_messages=error_messages,
**kw
- )
+ )
def clean(self,username):
""" validate username """
@@ -103,12 +146,21 @@ class UserNameField(StrippedNonEmptyCharField):
except forms.ValidationError:
raise forms.ValidationError(self.error_messages['required'])
- username_regex = re.compile(const.USERNAME_REGEX_STRING, re.UNICODE)
+ username_re_string = const.USERNAME_REGEX_STRING
+ #attention: here we check @ symbol in two places: input and the regex
+ if askbot_settings.ALLOW_EMAIL_ADDRESS_IN_USERNAME is False:
+ if '@' in username:
+ raise forms.ValidationError(self.error_messages['noemail'])
+
+ username_re_string = username_re_string.replace('@', '')
+
+ username_regex = re.compile(username_re_string, re.UNICODE)
+
if self.required and not username_regex.search(username):
raise forms.ValidationError(self.error_messages['invalid'])
if username in self.RESERVED_NAMES:
raise forms.ValidationError(self.error_messages['forbidden'])
- if slugify(username, force_unidecode = True) == '':
+ if slugify(username) == '':
raise forms.ValidationError(self.error_messages['meaningless'])
try:
user = self.db_model.objects.get(
@@ -131,25 +183,63 @@ class UserNameField(StrippedNonEmptyCharField):
logging.debug('error - user with this name already exists')
raise forms.ValidationError(self.error_messages['multiple-taken'])
+
+def email_is_allowed(
+ email, allowed_emails='', allowed_email_domains=''
+):
+ """True, if email address is pre-approved or matches a allowed
+ domain"""
+ if allowed_emails:
+ email_list = split_list(allowed_emails)
+ allowed_emails = ' ' + ' '.join(email_list) + ' '
+ email_match_re = re.compile(r'\s%s\s' % email)
+ if email_match_re.search(allowed_emails):
+ return True
+
+ if allowed_email_domains:
+ email_domain = email.split('@')[1]
+ domain_list = split_list(allowed_email_domains)
+ domain_match_re = re.compile(r'\s%s\s' % email_domain)
+ allowed_email_domains = ' ' + ' '.join(domain_list) + ' '
+ return domain_match_re.search(allowed_email_domains)
+
+ return False
+
class UserEmailField(forms.EmailField):
def __init__(self,skip_clean=False,**kw):
self.skip_clean = skip_clean
- super(UserEmailField,self).__init__(widget=forms.TextInput(attrs=dict(login_form_widget_attrs,
- maxlength=200)), label=mark_safe(_('Your email <i>(never shared)</i>')),
- error_messages={'required':_('email address is required'),
- 'invalid':_('please enter a valid email address'),
- 'taken':_('this email is already used by someone else, please choose another'),
- },
+ super(UserEmailField,self).__init__(
+ widget=forms.TextInput(
+ attrs=dict(login_form_widget_attrs, maxlength=200)
+ ),
+ label=mark_safe(_('Your email <i>(never shared)</i>')),
+ error_messages={
+ 'required':_('email address is required'),
+ 'invalid':_('please enter a valid email address'),
+ 'taken':_('this email is already used by someone else, please choose another'),
+ 'unauthorized':_('this email address is not authorized')
+ },
**kw
- )
+ )
- def clean(self,email):
+ def clean(self, email):
""" validate if email exist in database
from legacy register
return: raise error if it exist """
email = super(UserEmailField,self).clean(email.strip())
if self.skip_clean:
return email
+
+ allowed_domains = askbot_settings.ALLOWED_EMAIL_DOMAINS.strip()
+ allowed_emails = askbot_settings.ALLOWED_EMAILS.strip()
+
+ if allowed_emails or allowed_domains:
+ if not email_is_allowed(
+ email,
+ allowed_emails=allowed_emails,
+ allowed_email_domains=allowed_domains
+ ):
+ raise forms.ValidationError(self.error_messages['unauthorized'])
if askbot_settings.EMAIL_UNIQUE == True:
try:
user = User.objects.get(email = email)
diff --git a/askbot/utils/html.py b/askbot/utils/html.py
index 2e3c1913..49eddee2 100644
--- a/askbot/utils/html.py
+++ b/askbot/utils/html.py
@@ -6,6 +6,7 @@ import htmlentitydefs
from urlparse import urlparse
from django.core.urlresolvers import reverse
from django.utils.html import escape
+from askbot.conf import settings as askbot_settings
class HTMLSanitizerMixin(sanitizer.HTMLSanitizerMixin):
acceptable_elements = ('a', 'abbr', 'acronym', 'address', 'b', 'big',
@@ -43,6 +44,23 @@ class HTMLSanitizer(tokenizer.HTMLTokenizer, HTMLSanitizerMixin):
if token:
yield token
+def absolutize_urls(html):
+ """turns relative urls in <img> and <a> tags to absolute,
+ starting with the ``askbot_settings.APP_URL``"""
+ #temporal fix for bad regex with wysiwyg editor
+ url_re1 = re.compile(r'(?P<prefix><img[^<]+src=)"(?P<url>/[^"]+)"', re.I)
+ url_re2 = re.compile(r"(?P<prefix><img[^<]+src=)'(?P<url>/[^']+)'", re.I)
+ url_re3 = re.compile(r'(?P<prefix><a[^<]+href=)"(?P<url>/[^"]+)"', re.I)
+ url_re4 = re.compile(r"(?P<prefix><a[^<]+href=)'(?P<url>/[^']+)'", re.I)
+ img_replacement = '\g<prefix>"%s/\g<url>" style="max-width:500px;"' % askbot_settings.APP_URL
+ replacement = '\g<prefix>"%s\g<url>"' % askbot_settings.APP_URL
+ html = url_re1.sub(img_replacement, html)
+ html= url_re2.sub(img_replacement, html)
+ html = url_re3.sub(replacement, html)
+ #temporal fix for bad regex with wysiwyg editor
+ return url_re4.sub(replacement, html).replace('%s//' % askbot_settings.APP_URL,
+ '%s/' % askbot_settings.APP_URL)
+
def sanitize_html(html):
"""Sanitizes an HTML fragment."""
p = html5lib.HTMLParser(tokenizer=HTMLSanitizer,
@@ -55,6 +73,11 @@ def sanitize_html(html):
output_generator = s.serialize(stream)
return u''.join(output_generator)
+def site_url(url):
+ from askbot.conf import settings
+ base_url = urlparse(settings.APP_URL)
+ return base_url.scheme + '://' + base_url.netloc + url
+
def site_link(url_name, title):
"""returns html for the link to the given url
todo: may be improved to process url parameters, keyword
@@ -62,8 +85,8 @@ def site_link(url_name, title):
"""
from askbot.conf import settings
base_url = urlparse(settings.APP_URL)
- url = base_url.scheme + '://' + base_url.netloc + reverse(url_name)
- return '<a href="%s">%s</a>' % (url, escape(title))
+ url = site_url(reverse(url_name))
+ return '<a href="%s">%s</a>' % (url, title)
def unescape(text):
"""source: http://effbot.org/zone/re-sub.htm#unescape-html
diff --git a/askbot/utils/slug.py b/askbot/utils/slug.py
index 58f228da..f9e30cbf 100644
--- a/askbot/utils/slug.py
+++ b/askbot/utils/slug.py
@@ -5,30 +5,63 @@ the setting was added just in case - if people actually
want to see unicode characters in the slug. If this is the choice
slug will be simply equal to the input text
"""
+import re
+import unicodedata
from unidecode import unidecode
-from django.template import defaultfilters
+
from django.conf import settings
-import re
+from django.template import defaultfilters
+from django.utils.encoding import smart_unicode
+
+
+# Extra characters outside of alphanumerics that we'll allow.
+SLUG_OK = '-_~'
+
-def slugify(input_text, max_length=50, force_unidecode = False):
+def unicode_slugify(s, ok=SLUG_OK, lower=True, spaces=False):
+ """Function copied from https://github.com/mozilla/unicode-slugify
+ because the author of the package never published it on pypi.
+
+ Copyright notice below applies just to this function
+ Copyright (c) 2011, Mozilla Foundation
+ All rights reserved.
+
+ L and N signify letter/number.
+ http://www.unicode.org/reports/tr44/tr44-4.html#GC_Values_Table
+ """
+ rv = []
+ for c in unicodedata.normalize('NFKC', smart_unicode(s)):
+ cat = unicodedata.category(c)[0]
+ if cat in 'LN' or c in ok:
+ rv.append(c)
+ if cat == 'Z': # space
+ rv.append(' ')
+ new = ''.join(rv).strip()
+ if not spaces:
+ new = re.sub('[-\s]+', '-', new)
+ return new.lower() if lower else new
+
+
+def slugify(input_text, max_length=150):
"""custom slugify function that
removes diacritic modifiers from the characters
"""
+ if input_text == '':
+ return input_text
+
allow_unicode_slugs = getattr(settings, 'ALLOW_UNICODE_SLUGS', False)
- if allow_unicode_slugs == False or force_unidecode == True:
- if input_text == '':
- return input_text
- slug = defaultfilters.slugify(unidecode(input_text))
- while len(slug) > max_length:
- # try to shorten word by word until len(slug) <= max_length
- temp = slug[:slug.rfind('-')]
- if len(temp) > 0:
- slug = temp
- else:
- #we have nothing left, do not apply the last crop,
- #apply the cut-off directly
- slug = slug[:max_length]
- break
- return slug
+ if allow_unicode_slugs:
+ slug = unicode_slugify(input_text)
else:
- return re.sub(r'\s+', '-', input_text.strip().lower())
+ slug = defaultfilters.slugify(unidecode(input_text))
+ while len(slug) > max_length:
+ # try to shorten word by word until len(slug) <= max_length
+ temp = slug[:slug.rfind('-')]
+ if len(temp) > 0:
+ slug = temp
+ else:
+ #we have nothing left, do not apply the last crop,
+ #apply the cut-off directly
+ slug = slug[:max_length]
+ break
+ return slug
diff --git a/askbot/utils/url_utils.py b/askbot/utils/url_utils.py
index 6027d096..c58239c5 100644
--- a/askbot/utils/url_utils.py
+++ b/askbot/utils/url_utils.py
@@ -1,3 +1,4 @@
+import os
import urlparse
from django.core.urlresolvers import reverse
from django.conf import settings
@@ -13,6 +14,38 @@ def strip_path(url):
)
)
+def append_trailing_slash(urlpath):
+ """if path is empty - returns slash
+ if not and path does not end with the slash
+ appends it
+ """
+ if urlpath == '':
+ return '/'
+ elif not urlpath.endswith('/'):
+ return urlpath + '/'
+ return urlpath
+
+def urls_equal(url1, url2, ignore_trailing_slash=False):
+ """True, if urls are equal"""
+ purl1 = urlparse.urlparse(url1)
+ purl2 = urlparse.urlparse(url2)
+ if purl1.scheme != purl2.scheme:
+ return False
+
+ if purl1.netloc != purl2.netloc:
+ return False
+
+ if ignore_trailing_slash is True:
+ normfunc = append_trailing_slash
+ else:
+ normfunc = lambda v: v
+
+ if normfunc(purl1.path) != normfunc(purl2.path):
+ return False
+
+ #test remaining items in the parsed url
+ return purl1[3:] == purl2[3:]
+
def get_login_url():
"""returns internal login url if
django_authopenid is used, or
diff --git a/askbot/views/__init__.py b/askbot/views/__init__.py
index b9aaf8a9..a3c5e06d 100644
--- a/askbot/views/__init__.py
+++ b/askbot/views/__init__.py
@@ -6,6 +6,7 @@ from askbot.views import writers
from askbot.views import commands
from askbot.views import users
from askbot.views import meta
+from askbot.views import widgets
from django.conf import settings
if 'avatar' in settings.INSTALLED_APPS:
from askbot.views import avatar_views
diff --git a/askbot/views/commands.py b/askbot/views/commands.py
index 6fe99dfe..1a753098 100644
--- a/askbot/views/commands.py
+++ b/askbot/views/commands.py
@@ -5,11 +5,19 @@ This module contains most (but not all) processors for Ajax requests.
Not so clear if this subdivision was necessary as separation of Ajax and non-ajax views
is not always very clean.
"""
+import datetime
+import logging
+from bs4 import BeautifulSoup
from django.conf import settings as django_settings
from django.core import exceptions
+#from django.core.management import call_command
from django.core.urlresolvers import reverse
from django.contrib.auth.decorators import login_required
-from django.http import HttpResponse, HttpResponseRedirect, Http404, HttpResponseBadRequest
+from django.http import Http404
+from django.http import HttpResponse
+from django.http import HttpResponseBadRequest
+from django.http import HttpResponseRedirect
+from django.http import HttpResponseForbidden
from django.forms import ValidationError, IntegerField, CharField
from django.shortcuts import get_object_or_404
from django.views.decorators import csrf
@@ -17,16 +25,22 @@ from django.utils import simplejson
from django.utils.html import escape
from django.utils.translation import ugettext as _
from django.utils.translation import string_concat
+from askbot.utils.slug import slugify
from askbot import models
from askbot import forms
from askbot.conf import should_show_sort_by_relevance
from askbot.conf import settings as askbot_settings
+from askbot.models.tag import get_global_group
+from askbot.utils import category_tree
from askbot.utils import decorators
from askbot.utils import url_utils
+from askbot.utils.forms import get_db_object_or_404
from askbot import mail
+from django.template import Context
from askbot.skins.loaders import render_into_skin, get_template
+from askbot.skins.loaders import render_into_skin_as_string
+from askbot.skins.loaders import render_text_into_skin
from askbot import const
-import logging
@csrf.csrf_exempt
@@ -97,17 +111,12 @@ def manage_inbox(request):
reject_reason = models.PostFlagReason.objects.get(
id = post_data['reject_reason_id']
)
- body_text = string_concat(
- _('Your post (copied in the end),'),
- '<br/>',
- _('was rejected for the following reason:'),
- '<br/><br/>',
- reject_reason.details.html,
- '<br/><br/>',
- _('Here is your original post'),
- '<br/><br/>',
- post.text
- )
+ template = get_template('email/rejected_post.html')
+ data = {
+ 'post': post.html,
+ 'reject_reason': reject_reason.details.html
+ }
+ body_text = template.render(Context(data))
mail.send_mail(
subject_line = _('your post was not accepted'),
body_text = unicode(body_text),
@@ -425,7 +434,8 @@ def mark_tag(request, **kwargs):#tagging system
action = kwargs['action']
post_data = simplejson.loads(request.raw_post_data)
raw_tagnames = post_data['tagnames']
- reason = kwargs.get('reason', None)
+ reason = post_data['reason']
+ assert reason in ('good', 'bad', 'subscribed')
#separate plain tag names and wildcard tags
tagnames, wildcards = forms.clean_marked_tagnames(raw_tagnames)
@@ -471,60 +481,181 @@ def get_tags_by_wildcard(request):
return HttpResponse(re_data, mimetype = 'application/json')
@decorators.get_only
+def get_thread_shared_users(request):
+ """returns snippet of html with users"""
+ thread_id = request.GET['thread_id']
+ thread_id = IntegerField().clean(thread_id)
+ thread = models.Thread.objects.get(id=thread_id)
+ users = thread.get_users_shared_with()
+ data = {
+ 'users': users,
+ }
+ html = render_into_skin_as_string('widgets/user_list.html', data, request)
+ re_data = simplejson.dumps({
+ 'html': html,
+ 'users_count': users.count(),
+ 'success': True
+ })
+ return HttpResponse(re_data, mimetype='application/json')
+
+@decorators.get_only
+def get_thread_shared_groups(request):
+ """returns snippet of html with groups"""
+ thread_id = request.GET['thread_id']
+ thread_id = IntegerField().clean(thread_id)
+ thread = models.Thread.objects.get(id=thread_id)
+ groups = thread.get_groups_shared_with()
+ data = {'groups': groups}
+ html = render_into_skin_as_string('widgets/groups_list.html', data, request)
+ re_data = simplejson.dumps({
+ 'html': html,
+ 'groups_count': groups.count(),
+ 'success': True
+ })
+ return HttpResponse(re_data, mimetype='application/json')
+
+@decorators.ajax_only
+def get_html_template(request):
+ """returns rendered template"""
+ template_name = request.REQUEST.get('template_name', None)
+ allowed_templates = (
+ 'widgets/tag_category_selector.html',
+ )
+ #have allow simple context for the templates
+ if template_name not in allowed_templates:
+ raise Http404
+ return {
+ 'html': get_template(template_name).render()
+ }
+
+@decorators.get_only
def get_tag_list(request):
"""returns tags to use in the autocomplete
function
"""
- tag_names = models.Tag.objects.filter(
- deleted = False
- ).values_list(
+ tags = models.Tag.objects.filter(
+ deleted = False,
+ status = models.Tag.STATUS_ACCEPTED
+ )
+
+ tag_names = tags.values_list(
'name', flat = True
)
- output = '\n'.join(tag_names)
+
+ output = '\n'.join(map(escape, tag_names))
return HttpResponse(output, mimetype = 'text/plain')
@decorators.get_only
-def load_tag_wiki_text(request):
- """returns text of the tag wiki in markdown format"""
- if 'tag_id' not in request.GET:
- return HttpResponse('', status = 400)#bad request
-
- tag = get_object_or_404(models.Tag, id = request.GET['tag_id'])
- tag_wiki_text = getattr(tag.tag_wiki, 'text', '').strip()
- return HttpResponse(tag_wiki_text, mimetype = 'text/plain')
+def load_object_description(request):
+ """returns text of the object description in text"""
+ obj = get_db_object_or_404(request.GET)#askbot forms utility
+ text = getattr(obj.description, 'text', '').strip()
+ return HttpResponse(text, mimetype = 'text/plain')
@csrf.csrf_exempt
@decorators.ajax_only
@decorators.post_only
-def save_tag_wiki_text(request):
- """if tag wiki text does not exist,
+@decorators.admins_only
+def save_object_description(request):
+ """if object description does not exist,
creates a new record, otherwise edits an existing
- tag wiki record"""
- form = forms.EditTagWikiForm(request.POST)
- if form.is_valid():
- tag_id = form.cleaned_data['tag_id']
- text = form.cleaned_data['text'] or ' '#a hack to save blank data
- tag = models.Tag.objects.get(id = tag_id)
- if tag.tag_wiki:
- request.user.edit_post(tag.tag_wiki, body_text = text)
- tag_wiki = tag.tag_wiki
- else:
- tag_wiki = request.user.post_tag_wiki(tag, body_text = text)
- return {'html': tag_wiki.html}
+ one"""
+ obj = get_db_object_or_404(request.POST)
+ text = request.POST['text']
+ if obj.description:
+ request.user.edit_post(obj.description, body_text=text)
else:
- raise ValueError('invalid post data')
+ request.user.post_object_description(obj, body_text=text)
+ return {'html': obj.description.html}
+
+@csrf.csrf_exempt
+@decorators.ajax_only
+@decorators.post_only
+def rename_tag(request):
+ if request.user.is_anonymous() \
+ or not request.user.is_administrator_or_moderator():
+ raise exceptions.PermissionDenied()
+ post_data = simplejson.loads(request.raw_post_data)
+ to_name = forms.clean_tag(post_data['to_name'])
+ from_name = forms.clean_tag(post_data['from_name'])
+ path = post_data['path']
+
+ #kwargs = {'from': old_name, 'to': new_name}
+ #call_command('rename_tags', **kwargs)
+
+ tree = category_tree.get_data()
+ category_tree.rename_category(
+ tree,
+ from_name = from_name,
+ to_name = to_name,
+ path = path
+ )
+ category_tree.save_data(tree)
+
+@csrf.csrf_exempt
+@decorators.ajax_only
+@decorators.post_only
+def delete_tag(request):
+ """todo: actually delete tags
+ now it is only deletion of category from the tree"""
+ if request.user.is_anonymous() \
+ or not request.user.is_administrator_or_moderator():
+ raise exceptions.PermissionDenied()
+ post_data = simplejson.loads(request.raw_post_data)
+ tag_name = forms.clean_tag(post_data['tag_name'])
+ path = post_data['path']
+ tree = category_tree.get_data()
+ category_tree.delete_category(tree, tag_name, path)
+ category_tree.save_data(tree)
+ return {'tree_data': tree}
+
+@csrf.csrf_exempt
+@decorators.ajax_only
+@decorators.post_only
+def add_tag_category(request):
+ """adds a category at the tip of a given path expects
+ the following keys in the ``request.POST``
+ * path - array starting with zero giving path to
+ the category page where to add the category
+ * new_category_name - string that must satisfy the
+ same requiremets as a tag
+
+ return json with the category tree data
+ todo: switch to json stored in the live settings
+ now we have indented input
+ """
+ if request.user.is_anonymous() \
+ or not request.user.is_administrator_or_moderator():
+ raise exceptions.PermissionDenied()
+
+ post_data = simplejson.loads(request.raw_post_data)
+ category_name = forms.clean_tag(post_data['new_category_name'])
+ path = post_data['path']
+
+ tree = category_tree.get_data()
+
+ if category_tree.path_is_valid(tree, path) == False:
+ raise ValueError('category insertion path is invalid')
+
+ new_path = category_tree.add_category(tree, category_name, path)
+ category_tree.save_data(tree)
+ return {
+ 'tree_data': tree,
+ 'new_path': new_path
+ }
@decorators.get_only
def get_groups_list(request):
"""returns names of group tags
for the autocomplete function"""
- group_names = models.Tag.group_tags.get_all().filter(
- deleted = False
- ).values_list(
- 'name', flat = True
- )
- group_names = map(lambda v: v.replace('-', ' '), group_names)
+ global_group = get_global_group()
+ groups = models.Group.objects.exclude_personal()
+ group_names = groups.exclude(
+ name=global_group.name
+ ).values_list(
+ 'name', flat = True
+ )
output = '\n'.join(group_names)
return HttpResponse(output, mimetype = 'text/plain')
@@ -570,15 +701,25 @@ def api_get_questions(request):
query = request.GET.get('query', '').strip()
if not query:
return HttpResponseBadRequest('Invalid query')
- threads = models.Thread.objects.get_for_query(query)
+
+ if askbot_settings.GROUPS_ENABLED:
+ threads = models.Thread.objects.get_visible(user=request.user)
+ else:
+ threads = models.Thread.objects.all()
+
+ threads = models.Thread.objects.get_for_query(
+ search_query=query,
+ qs=threads
+ )
+
if should_show_sort_by_relevance():
threads = threads.extra(order_by = ['-relevance'])
#todo: filter out deleted threads, for now there is no way
threads = threads.distinct()[:30]
thread_list = [{
- 'url': thread.get_absolute_url(),
'title': escape(thread.title),
- 'answer_count': thread.answer_count
+ 'url': thread.get_absolute_url(),
+ 'answer_count': thread.get_answer_count(request.user)
} for thread in threads]
json_data = simplejson.dumps(thread_list)
return HttpResponse(json_data, mimetype = "application/json")
@@ -675,7 +816,7 @@ def swap_question_with_answer(request):
"""
if request.user.is_authenticated():
if request.user.is_administrator() or request.user.is_moderator():
- answer = models.Post.objects.get_answers().get(id = request.POST['answer_id'])
+ answer = models.Post.objects.get_answers(request.user).get(id = request.POST['answer_id'])
new_question = answer.swap_with_question(new_title = request.POST['new_title'])
return {
'id': new_question.id,
@@ -742,12 +883,16 @@ def read_message(request):#marks message a read
@decorators.post_only
@decorators.admins_only
def edit_group_membership(request):
+ #todo: this call may need to go.
+ #it used to be the one creating groups
+ #from the user profile page
+ #we have a separate method
form = forms.EditGroupMembershipForm(request.POST)
if form.is_valid():
group_name = form.cleaned_data['group_name']
user_id = form.cleaned_data['user_id']
try:
- user = models.User.objects.get(id = user_id)
+ user = models.User.objects.get(id=user_id)
except models.User.DoesNotExist:
raise exceptions.PermissionDenied(
'user with id %d not found' % user_id
@@ -756,8 +901,8 @@ def edit_group_membership(request):
action = form.cleaned_data['action']
#warning: possible race condition
if action == 'add':
- group_params = {'group_name': group_name, 'user': user}
- group = models.Tag.group_tags.get_or_create(**group_params)
+ group_params = {'name': group_name, 'user': user}
+ group = models.Group.objects.get_or_create(**group_params)
request.user.edit_group_membership(user, group, 'add')
template = get_template('widgets/group_snippet.html')
return {
@@ -767,9 +912,9 @@ def edit_group_membership(request):
}
elif action == 'remove':
try:
- group = models.Tag.group_tags.get_by_name(group_name = group_name)
+ group = models.Group.objects.get(group_name = group_name)
request.user.edit_group_membership(user, group, 'remove')
- except models.Tag.DoesNotExist:
+ except models.Group.DoesNotExist:
raise exceptions.PermissionDenied()
else:
raise exceptions.PermissionDenied()
@@ -787,12 +932,30 @@ def save_group_logo_url(request):
if form.is_valid():
group_id = form.cleaned_data['group_id']
image_url = form.cleaned_data['image_url']
- group = models.Tag.group_tags.get(id = group_id)
- group.group_profile.logo_url = image_url
- group.group_profile.save()
+ group = models.Group.objects.get(id = group_id)
+ group.logo_url = image_url
+ group.save()
else:
raise ValueError('invalid data found when saving group logo')
+@csrf.csrf_exempt
+@decorators.ajax_only
+@decorators.post_only
+@decorators.admins_only
+def add_group(request):
+ group_name = request.POST.get('group')
+ if group_name:
+ group = models.Group.objects.get_or_create(
+ name=group_name,
+ openness=models.Group.OPEN,
+ user=request.user,
+ )
+
+ url = reverse('users_by_group', kwargs={'group_id': group.id,
+ 'group_slug': slugify(group_name)})
+ response_dict = dict(group_name = group_name,
+ url = url )
+ return response_dict
@csrf.csrf_exempt
@decorators.ajax_only
@@ -800,9 +963,9 @@ def save_group_logo_url(request):
@decorators.admins_only
def delete_group_logo(request):
group_id = IntegerField().clean(int(request.POST['group_id']))
- group = models.Tag.group_tags.get(id = group_id)
- group.group_profile.logo_url = None
- group.group_profile.save()
+ group = models.Group.objects.get(id = group_id)
+ group.logo_url = None
+ group.save()
@csrf.csrf_exempt
@@ -823,17 +986,28 @@ def toggle_group_profile_property(request):
#todo: this might be changed to more general "toggle object property"
group_id = IntegerField().clean(int(request.POST['group_id']))
property_name = CharField().clean(request.POST['property_name'])
- assert property_name in ('is_open', 'moderate_email')
-
- group = models.Tag.objects.get(id = group_id)
- new_value = not getattr(group.group_profile, property_name)
- setattr(group.group_profile, property_name, new_value)
- group.group_profile.save()
+ assert property_name in ('moderate_email', 'moderate_answers_to_enquirers')
+ group = models.Group.objects.get(id = group_id)
+ new_value = not getattr(group, property_name)
+ setattr(group, property_name, new_value)
+ group.save()
return {'is_enabled': new_value}
@csrf.csrf_exempt
@decorators.ajax_only
+@decorators.post_only
+@decorators.admins_only
+def set_group_openness(request):
+ group_id = IntegerField().clean(int(request.POST['group_id']))
+ value = IntegerField().clean(int(request.POST['value']))
+ group = models.Group.objects.get(id=group_id)
+ group.openness = value
+ group.save()
+
+
+@csrf.csrf_exempt
+@decorators.ajax_only
@decorators.admins_only
def edit_object_property_text(request):
model_name = CharField().clean(request.REQUEST['model_name'])
@@ -841,8 +1015,8 @@ def edit_object_property_text(request):
property_name = CharField().clean(request.REQUEST['property_name'])
accessible_fields = (
- ('GroupProfile', 'preapproved_emails'),
- ('GroupProfile', 'preapproved_email_domains')
+ ('Group', 'preapproved_emails'),
+ ('Group', 'preapproved_email_domains')
)
if (model_name, property_name) not in accessible_fields:
@@ -863,25 +1037,30 @@ def edit_object_property_text(request):
@decorators.ajax_only
@decorators.post_only
def join_or_leave_group(request):
- """only current user can join/leave group"""
+ """called when user wants to join/leave
+ ask to join/cancel join request, depending
+ on the groups acceptance level for the given user
+
+ returns resulting "membership_level"
+ """
if request.user.is_anonymous():
raise exceptions.PermissionDenied()
+ Group = models.Group
+ Membership = models.GroupMembership
+
group_id = IntegerField().clean(request.POST['group_id'])
- group = models.Tag.objects.get(id = group_id)
+ group = Group.objects.get(id=group_id)
- if request.user.is_group_member(group):
- action = 'remove'
- is_member = False
+ membership = request.user.get_group_membership(group)
+ if membership is None:
+ membership = request.user.join_group(group)
+ new_level = membership.get_level_display()
else:
- action = 'add'
- is_member = True
- request.user.edit_group_membership(
- user = request.user,
- group = group,
- action = action
- )
- return {'is_member': is_member}
+ membership.delete()
+ new_level = Membership.get_level_value_display(Membership.NONE)
+
+ return {'membership_level': new_level}
@csrf.csrf_exempt
@@ -914,3 +1093,307 @@ def save_post_reject_reason(request):
}
else:
raise Exception(forms.format_form_errors(form))
+
+@csrf.csrf_exempt
+@decorators.ajax_only
+@decorators.post_only
+@decorators.admins_only
+def moderate_suggested_tag(request):
+ """accepts or rejects a suggested tag
+ if thread id is given, then tag is
+ applied to or removed from only one thread,
+ otherwise the decision applies to all threads
+ """
+ form = forms.ModerateTagForm(request.POST)
+ if form.is_valid():
+ tag_id = form.cleaned_data['tag_id']
+ thread_id = form.cleaned_data.get('thread_id', None)
+
+ try:
+ tag = models.Tag.objects.get(id=tag_id)#can tag not exist?
+ except models.Tag.DoesNotExist:
+ return
+
+ if thread_id:
+ threads = models.Thread.objects.filter(id = thread_id)
+ else:
+ threads = tag.threads.all()
+
+ if form.cleaned_data['action'] == 'accept':
+ #todo: here we lose ability to come back
+ #to the tag moderation and approve tag to
+ #other threads later for the case where tag.used_count > 1
+ tag.status = models.Tag.STATUS_ACCEPTED
+ tag.save()
+ for thread in threads:
+ thread.add_tag(
+ tag_name = tag.name,
+ user = tag.created_by,
+ timestamp = datetime.datetime.now(),
+ silent = True
+ )
+ else:
+ if tag.threads.count() > len(threads):
+ for thread in threads:
+ thread.tags.remove(tag)
+ tag.used_count = tag.threads.count()
+ tag.save()
+ elif tag.status == models.Tag.STATUS_SUGGESTED:
+ tag.delete()
+ else:
+ raise Exception(forms.format_form_errors(form))
+
+
+@csrf.csrf_exempt
+@decorators.ajax_only
+@decorators.post_only
+def save_draft_question(request):
+ """saves draft questions"""
+ #todo: allow drafts for anonymous users
+ if request.user.is_anonymous():
+ return
+
+ form = forms.DraftQuestionForm(request.POST)
+ if form.is_valid():
+ title = form.cleaned_data.get('title', '')
+ text = form.cleaned_data.get('text', '')
+ tagnames = form.cleaned_data.get('tagnames', '')
+ if title or text or tagnames:
+ try:
+ draft = models.DraftQuestion.objects.get(author=request.user)
+ except models.DraftQuestion.DoesNotExist:
+ draft = models.DraftQuestion()
+
+ draft.title = title
+ draft.text = text
+ draft.tagnames = tagnames
+ draft.author = request.user
+ draft.save()
+
+
+@csrf.csrf_exempt
+@decorators.ajax_only
+@decorators.post_only
+def save_draft_answer(request):
+ """saves draft answers"""
+ #todo: allow drafts for anonymous users
+ if request.user.is_anonymous():
+ return
+
+ form = forms.DraftAnswerForm(request.POST)
+ if form.is_valid():
+ thread_id = form.cleaned_data['thread_id']
+ try:
+ thread = models.Thread.objects.get(id=thread_id)
+ except models.Thread.DoesNotExist:
+ return
+ try:
+ draft = models.DraftAnswer.objects.get(
+ thread=thread,
+ author=request.user
+ )
+ except models.DraftAnswer.DoesNotExist:
+ draft = models.DraftAnswer()
+
+ draft.author = request.user
+ draft.thread = thread
+ draft.text = form.cleaned_data.get('text', '')
+ draft.save()
+
+@decorators.get_only
+def get_users_info(request):
+ """retuns list of user names and email addresses
+ of "fake" users - so that admins can post on their
+ behalf"""
+ if request.user.is_anonymous():
+ return HttpResponseForbidden()
+
+ query = request.GET['q']
+ limit = IntegerField().clean(request.GET['limit'])
+
+ users = models.User.objects
+ user_info_list = users.filter(username__istartswith=query)
+
+ if request.user.is_administrator_or_moderator():
+ user_info_list = user_info_list.values_list('username', 'email')
+ else:
+ user_info_list = user_info_list.values_list('username')
+
+ result_list = ['|'.join(info) for info in user_info_list[:limit]]
+ return HttpResponse('\n'.join(result_list), mimetype = 'text/plain')
+
+@csrf.csrf_protect
+def share_question_with_group(request):
+ form = forms.ShareQuestionForm(request.POST)
+ try:
+ if form.is_valid():
+
+ thread_id = form.cleaned_data['thread_id']
+ group_name = form.cleaned_data['recipient_name']
+
+ thread = models.Thread.objects.get(id=thread_id)
+ question_post = thread._question_post()
+
+ #get notif set before
+ sets1 = question_post.get_notify_sets(
+ mentioned_users=list(),
+ exclude_list=[request.user,]
+ )
+
+ #share the post
+ if group_name == askbot_settings.GLOBAL_GROUP_NAME:
+ thread.make_public(recursive=True)
+ else:
+ group = models.Group.objects.get(name=group_name)
+ thread.add_to_groups((group,), recursive=True)
+
+ #get notif sets after
+ sets2 = question_post.get_notify_sets(
+ mentioned_users=list(),
+ exclude_list=[request.user,]
+ )
+
+ notify_sets = {
+ 'for_mentions': sets2['for_mentions'] - sets1['for_mentions'],
+ 'for_email': sets2['for_email'] - sets1['for_email'],
+ 'for_inbox': sets2['for_inbox'] - sets1['for_inbox']
+ }
+
+ question_post.issue_update_notifications(
+ updated_by=request.user,
+ notify_sets=notify_sets,
+ activity_type=const.TYPE_ACTIVITY_POST_SHARED,
+ timestamp=datetime.datetime.now()
+ )
+
+ return HttpResponseRedirect(thread.get_absolute_url())
+ except Exception:
+ error_message = _('Sorry, looks like sharing request was invalid')
+ request.user.message_set.create(message=error_message)
+ return HttpResponseRedirect(thread.get_absolute_url())
+
+@csrf.csrf_protect
+def share_question_with_user(request):
+ form = forms.ShareQuestionForm(request.POST)
+ try:
+ if form.is_valid():
+
+ thread_id = form.cleaned_data['thread_id']
+ username = form.cleaned_data['recipient_name']
+
+ thread = models.Thread.objects.get(id=thread_id)
+ user = models.User.objects.get(username=username)
+ group = user.get_personal_group()
+ thread.add_to_groups([group], recursive=True)
+ #notify the person
+ #todo: see if user could already see the post - b/f the sharing
+ notify_sets = {
+ 'for_inbox': set([user]),
+ 'for_mentions': set([user]),
+ 'for_email': set([user])
+ }
+ thread._question_post().issue_update_notifications(
+ updated_by=request.user,
+ notify_sets=notify_sets,
+ activity_type=const.TYPE_ACTIVITY_POST_SHARED,
+ timestamp=datetime.datetime.now()
+ )
+
+ return HttpResponseRedirect(thread.get_absolute_url())
+ except Exception:
+ error_message = _('Sorry, looks like sharing request was invalid')
+ request.user.message_set.create(message=error_message)
+ return HttpResponseRedirect(thread.get_absolute_url())
+
+@csrf.csrf_protect
+def moderate_group_join_request(request):
+ """moderator of the group can accept or reject a new user"""
+ request_id = IntegerField().clean(request.POST['request_id'])
+ action = request.POST['action']
+ assert(action in ('approve', 'deny'))
+
+ activity = get_object_or_404(models.Activity, pk=request_id)
+ group = activity.content_object
+ applicant = activity.user
+
+ if group.has_moderator(request.user):
+ group_membership = models.GroupMembership.objects.get(
+ user=applicant, group=group
+ )
+ if action == 'approve':
+ group_membership.level = models.GroupMembership.FULL
+ group_membership.save()
+ msg_data = {'user': applicant.username, 'group': group.name}
+ message = _('%(user)s, welcome to group %(group)s!') % msg_data
+ applicant.message_set.create(message=message)
+ else:
+ group_membership.delete()
+
+ activity.delete()
+ url = request.user.get_absolute_url() + '?sort=inbox&section=join_requests'
+ return HttpResponseRedirect(url)
+ else:
+ raise Http404
+
+@decorators.get_only
+def get_editor(request):
+ """returns bits of html for the tinymce editor in a dictionary with keys:
+ * html - the editor element
+ * scripts - an array of script tags
+ * success - True
+ """
+ config = simplejson.loads(request.GET['config'])
+ form = forms.EditorForm(editor_attrs=config)
+ editor_html = render_text_into_skin(
+ '{{ form.media }} {{ form.editor }}',
+ {'form': form},
+ request
+ )
+ #parse out javascript and dom, and return them separately
+ #we need that, because js needs to be added in a special way
+ html_soup = BeautifulSoup(editor_html)
+
+ parsed_scripts = list()
+ for script in html_soup.find_all('script'):
+ parsed_scripts.append({
+ 'contents': script.string,
+ 'src': script.get('src', None)
+ })
+
+ data = {
+ 'html': str(html_soup.textarea),
+ 'scripts': parsed_scripts,
+ 'success': True
+ }
+ return HttpResponse(simplejson.dumps(data), mimetype='application/json')
+
+@csrf.csrf_exempt
+@decorators.ajax_only
+@decorators.post_only
+def publish_answer(request):
+ """will publish or unpublish answer, if
+ current thread is moderated
+ """
+ denied_msg = _('Sorry, only thread moderators can use this function')
+ if request.user.is_authenticated():
+ if request.user.is_administrator_or_moderator() is False:
+ raise exceptions.PermissionDenied(denied_msg)
+ #todo: assert permission
+ answer_id = IntegerField().clean(request.POST['answer_id'])
+ answer = models.Post.objects.get(id=answer_id, post_type='answer')
+
+ if answer.thread.has_moderator(request.user) is False:
+ raise exceptions.PermissionDenied(denied_msg)
+
+ enquirer = answer.thread._question_post().author
+ enquirer_group = enquirer.get_personal_group()
+
+ if answer.has_group(enquirer_group):
+ message = _('The answer is now unpublished')
+ answer.remove_from_groups([enquirer_group])
+ else:
+ answer.add_to_groups([enquirer_group])
+ message = _('The answer is now published')
+ #todo: notify enquirer by email about the post
+ request.user.message_set.create(message=message)
+ return {'redirect_url': answer.get_absolute_url()}
diff --git a/askbot/views/context.py b/askbot/views/context.py
new file mode 100644
index 00000000..eeaf6002
--- /dev/null
+++ b/askbot/views/context.py
@@ -0,0 +1,52 @@
+"""functions, preparing parts of context for
+the templates in the various views"""
+from django.utils import simplejson
+from django.utils.translation import ugettext as _
+from askbot.conf import settings as askbot_settings
+from askbot import const
+from askbot.const import message_keys as msg
+from askbot.models import GroupMembership
+
+def get_for_tag_editor():
+ #data for the tag editor
+ data = {
+ 'tag_regex': const.TAG_REGEX,
+ 'tags_are_required': askbot_settings.TAGS_ARE_REQUIRED,
+ 'max_tags_per_post': askbot_settings.MAX_TAGS_PER_POST,
+ 'max_tag_length': askbot_settings.MAX_TAG_LENGTH,
+ 'force_lowercase_tags': askbot_settings.FORCE_LOWERCASE_TAGS,
+ 'messages': {
+ 'required': _(msg.TAGS_ARE_REQUIRED_MESSAGE),
+ 'wrong_chars': _(msg.TAG_WRONG_CHARS_MESSAGE)
+ }
+ }
+ return {'tag_editor_settings': simplejson.dumps(data)}
+
+def get_for_inbox(user):
+ """adds response counts of various types"""
+ if user.is_anonymous():
+ return None
+
+ #get flags count
+ flag_activity_types = (const.TYPE_ACTIVITY_MARK_OFFENSIVE,)
+ if askbot_settings.ENABLE_CONTENT_MODERATION:
+ flag_activity_types += (
+ const.TYPE_ACTIVITY_MODERATED_NEW_POST,
+ const.TYPE_ACTIVITY_MODERATED_POST_EDIT
+ )
+
+ #get group_join_requests_count
+ group_join_requests_count = 0
+ if user.is_administrator_or_moderator():
+ pending_memberships = GroupMembership.objects.filter(
+ group__in=user.get_groups(),
+ level=GroupMembership.PENDING
+ )
+ group_join_requests_count = pending_memberships.count()
+
+ return {
+ 're_count': user.new_response_count + user.seen_response_count,
+ 'flags_count': user.get_notifications(flag_activity_types).count(),
+ 'group_join_requests_count': group_join_requests_count
+ }
+
diff --git a/askbot/views/meta.py b/askbot/views/meta.py
index b8411b41..7b271219 100644
--- a/askbot/views/meta.py
+++ b/askbot/views/meta.py
@@ -5,6 +5,7 @@ This module contains a collection of views displaying all sorts of secondary and
"""
from django.shortcuts import render_to_response, get_object_or_404
from django.core.urlresolvers import reverse
+from django.core.paginator import Paginator, EmptyPage, InvalidPage
from django.template import RequestContext, Template
from django.http import HttpResponseRedirect, HttpResponse, Http404
from django.core.urlresolvers import reverse
@@ -12,17 +13,23 @@ from django.utils.translation import ugettext as _
from django.views import static
from django.views.decorators import csrf
from django.db.models import Max, Count
+from askbot import skins
+from askbot.conf import settings as askbot_settings
from askbot.forms import FeedbackForm
+from askbot.utils.url_utils import get_login_url
from askbot.utils.forms import get_next_url
from askbot.mail import mail_moderators
-from askbot.models import BadgeData, Award, User
+from askbot.models import BadgeData, Award, User, Tag
from askbot.models import badges as badge_data
from askbot.skins.loaders import get_template, render_into_skin, render_text_into_skin
-from askbot.conf import settings as askbot_settings
-from askbot import skins
+from askbot.utils.decorators import admins_only
+from askbot.utils.forms import get_next_url
+from askbot.utils import functions
def generic_view(request, template = None, page_class = None):
"""this may be not necessary, since it is just a rewrite of render_into_skin"""
+ if request is None: # a plug for strange import errors in django startup
+ return render_to_response('django_error.html')
return render_into_skin(template, {'page_class': page_class}, request)
def config_variable(request, variable_name = None, mimetype = None):
@@ -79,9 +86,19 @@ def faq(request):
def feedback(request):
data = {'page_class': 'meta'}
form = None
+
+ if askbot_settings.ALLOW_ANONYMOUS_FEEDBACK is False:
+ if request.user.is_anonymous():
+ message = _('Please sign in or register to send your feedback')
+ request.user.message_set.create(message=message)
+ redirect_url = get_login_url() + '?next=' + request.path
+ return HttpResponseRedirect(redirect_url)
+
if request.method == "POST":
- form = FeedbackForm(is_auth = request.user.is_authenticated(),
- data = request.POST)
+ form = FeedbackForm(
+ is_auth=request.user.is_authenticated(),
+ data=request.POST
+ )
if form.is_valid():
if not request.user.is_authenticated():
data['email'] = form.cleaned_data.get('email',None)
@@ -153,3 +170,43 @@ def badge(request, id):
'page_class': 'meta',
}
return render_into_skin('badge.html', data, request)
+
+@admins_only
+def list_suggested_tags(request):
+ """moderators and administrators can list tags that are
+ in the moderation queue, apply suggested tag to questions
+ or cancel the moderation reuest."""
+ if askbot_settings.ENABLE_TAG_MODERATION == False:
+ raise Http404
+ tags = Tag.objects.filter(status = Tag.STATUS_SUGGESTED)
+ tags = tags.order_by('-used_count', 'name')
+ #paginate moderated tags
+ paginator = Paginator(tags, 20)
+
+ page_no = request.GET.get('page', '1')
+
+ try:
+ page = paginator.page(page_no)
+ except (EmptyPage, InvalidPage):
+ page = paginator.page(paginator.num_pages)
+
+ paginator_context = functions.setup_paginator({
+ 'is_paginated' : True,
+ 'pages': paginator.num_pages,
+ 'page': page_no,
+ 'has_previous': page.has_previous(),
+ 'has_next': page.has_next(),
+ 'previous': page.previous_page_number(),
+ 'next': page.next_page_number(),
+ 'base_url' : request.path
+ })
+
+ data = {
+ 'tags': page.object_list,
+ 'active_tab': 'tags',
+ 'tab_id': 'suggested',
+ 'page_class': 'moderate-tags-page',
+ 'page_title': _('Suggested tags'),
+ 'paginator_context' : paginator_context,
+ }
+ return render_into_skin('list_suggested_tags.html', data, request)
diff --git a/askbot/views/readers.py b/askbot/views/readers.py
index 3689bd6f..c2391cab 100644
--- a/askbot/views/readers.py
+++ b/askbot/views/readers.py
@@ -30,6 +30,7 @@ import askbot
from askbot import exceptions
from askbot.utils.diff import textDiff as htmldiff
from askbot.forms import AnswerForm, ShowQuestionForm
+from askbot import conf
from askbot import models
from askbot import schedules
from askbot.models.tag import Tag
@@ -39,9 +40,9 @@ from askbot.utils.html import sanitize_html
from askbot.utils.decorators import anonymous_forbidden, ajax_only, get_only
from askbot.search.state_manager import SearchState, DummySearchState
from askbot.templatetags import extra_tags
-import askbot.conf
from askbot.conf import settings as askbot_settings
from askbot.skins.loaders import render_into_skin, get_template #jinja2 template loading enviroment
+from askbot.views import context
# used in index page
#todo: - take these out of const or settings
@@ -75,11 +76,15 @@ def questions(request, **kwargs):
if request.method != 'GET':
return HttpResponseNotAllowed(['GET'])
- search_state = SearchState(user_logged_in=request.user.is_authenticated(), **kwargs)
+ search_state = SearchState(
+ user_logged_in=request.user.is_authenticated(),
+ **kwargs
+ )
page_size = int(askbot_settings.DEFAULT_QUESTIONS_PAGE_SIZE)
- qs, meta_data = models.Thread.objects.run_advanced_search(request_user=request.user, search_state=search_state)
-
+ qs, meta_data = models.Thread.objects.run_advanced_search(
+ request_user=request.user, search_state=search_state
+ )
if meta_data['non_existing_tags']:
search_state = search_state.remove_tags(meta_data['non_existing_tags'])
@@ -87,19 +92,25 @@ def questions(request, **kwargs):
if paginator.num_pages < search_state.page:
search_state.page = 1
page = paginator.page(search_state.page)
-
- page.object_list = list(page.object_list) # evaluate queryset
+ page.object_list = list(page.object_list) # evaluate the queryset
# INFO: Because for the time being we need question posts and thread authors
# down the pipeline, we have to precache them in thread objects
models.Thread.objects.precache_view_data_hack(threads=page.object_list)
- related_tags = Tag.objects.get_related_to_search(threads=page.object_list, ignored_tag_names=meta_data.get('ignored_tag_names', []))
+ related_tags = Tag.objects.get_related_to_search(
+ threads=page.object_list,
+ ignored_tag_names=meta_data.get('ignored_tag_names',[])
+ )
tag_list_type = askbot_settings.TAG_LIST_FORMAT
if tag_list_type == 'cloud': #force cloud to sort by name
related_tags = sorted(related_tags, key = operator.attrgetter('name'))
- contributors = list(models.Thread.objects.get_thread_contributors(thread_list=page.object_list).only('id', 'username', 'gravatar'))
+ contributors = list(
+ models.Thread.objects.get_thread_contributors(
+ thread_list=page.object_list
+ ).only('id', 'username', 'gravatar')
+ )
paginator_context = {
'is_paginated' : (paginator.count > page_size),
@@ -155,6 +166,7 @@ def questions(request, **kwargs):
'threads': page,
'search_state': search_state,
'reset_method_count': reset_method_count,
+ 'request': request
}))
ajax_data = {
@@ -199,14 +211,14 @@ def questions(request, **kwargs):
'questions_count' : paginator.count,
'reset_method_count': reset_method_count,
'scope': search_state.scope,
- 'show_sort_by_relevance': askbot.conf.should_show_sort_by_relevance(),
+ 'show_sort_by_relevance': conf.should_show_sort_by_relevance(),
'search_tags' : search_state.tags,
'sort': search_state.sort,
'tab_id' : search_state.sort,
'tags' : related_tags,
'tag_list_type' : tag_list_type,
'font_size' : extra_tags.get_tag_font_size(related_tags),
- 'display_tag_filter_strategy_choices': const.TAG_DISPLAY_FILTER_STRATEGY_CHOICES,
+ 'display_tag_filter_strategy_choices': conf.get_tag_display_filter_strategy_choices(),
'email_tag_filter_strategy_choices': const.TAG_EMAIL_FILTER_STRATEGY_CHOICES,
'update_avatar_data': schedules.should_update_avatar_data(request),
'query_string': search_state.query_string(),
@@ -231,23 +243,22 @@ def tags(request):#view showing a listing of available tags - plain list
except ValueError:
page = 1
- if request.method == "GET":
- stag = request.GET.get("query", "").strip()
- if stag != '':
- objects_list = Paginator(
- models.Tag.objects.filter(
- deleted=False,
- name__icontains=stag
- ).exclude(
- used_count=0
- ),
- DEFAULT_PAGE_SIZE
- )
+ stag = request.GET.get("query", "").strip()
+ if stag != '':
+ objects_list = Paginator(
+ models.Tag.objects.filter(
+ deleted=False,
+ name__icontains=stag
+ ).exclude(
+ used_count=0
+ ),
+ DEFAULT_PAGE_SIZE
+ )
+ else:
+ if sortby == "name":
+ objects_list = Paginator(models.Tag.objects.all().filter(deleted=False).exclude(used_count=0).order_by("name"), DEFAULT_PAGE_SIZE)
else:
- if sortby == "name":
- objects_list = Paginator(models.Tag.objects.all().filter(deleted=False).exclude(used_count=0).order_by("name"), DEFAULT_PAGE_SIZE)
- else:
- objects_list = Paginator(models.Tag.objects.all().filter(deleted=False).exclude(used_count=0).order_by("-used_count"), DEFAULT_PAGE_SIZE)
+ objects_list = Paginator(models.Tag.objects.all().filter(deleted=False).exclude(used_count=0).order_by("-used_count"), DEFAULT_PAGE_SIZE)
try:
tags = objects_list.page(page)
@@ -433,10 +444,13 @@ def question(request, id):#refactor - long subroutine. display question body, an
#load answers and post id's->athor_id mapping
#posts are pre-stuffed with the correctly ordered comments
- updated_question_post, answers, post_to_author = thread.get_cached_post_data(
+ updated_question_post, answers, post_to_author, published_answer_ids = thread.get_cached_post_data(
sort_method = answer_sort_method,
+ user = request.user
)
- question_post.set_cached_comments(updated_question_post.get_cached_comments())
+ question_post.set_cached_comments(
+ updated_question_post.get_cached_comments()
+ )
#Post.objects.precache_comments(for_posts=[question_post] + answers, visitor=request.user)
@@ -521,17 +535,36 @@ def question(request, id):#refactor - long subroutine. display question body, an
elif show_comment_position > askbot_settings.MAX_COMMENTS_TO_SHOW:
is_cacheable = False
- answer_form = AnswerForm(
- initial = {
- 'wiki': question_post.wiki and askbot_settings.WIKI_ON,
- 'email_notify': thread.is_followed_by(request.user)
- }
- )
+ initial = {
+ 'wiki': question_post.wiki and askbot_settings.WIKI_ON,
+ 'email_notify': thread.is_followed_by(request.user)
+ }
+ #maybe load draft
+ if request.user.is_authenticated():
+ #todo: refactor into methor on thread
+ drafts = models.DraftAnswer.objects.filter(
+ author=request.user,
+ thread=thread
+ )
+ if drafts.count() > 0:
+ initial['text'] = drafts[0].text
+
+ answer_form = AnswerForm(initial)
user_can_post_comment = (
request.user.is_authenticated() and request.user.can_post_comment()
)
+ user_already_gave_answer = False
+ previous_answer = None
+ if request.user.is_authenticated():
+ if askbot_settings.LIMIT_ONE_ANSWER_PER_USER:
+ for answer in answers:
+ if answer.author == request.user:
+ user_already_gave_answer = True
+ previous_answer = answer
+ break
+
data = {
'is_cacheable': False,#is_cacheable, #temporary, until invalidation fix
'long_time': const.LONG_TIME,#"forever" caching
@@ -539,12 +572,18 @@ def question(request, id):#refactor - long subroutine. display question body, an
'active_tab': 'questions',
'question' : question_post,
'thread': thread,
+ 'thread_is_moderated': thread.is_moderated(),
+ 'user_is_thread_moderator': thread.has_moderator(request.user),
+ 'published_answer_ids': published_answer_ids,
'answer' : answer_form,
'answers' : page_objects.object_list,
- 'answer_count': len(answers),
+ 'answer_count': thread.get_answer_count(request.user),
+ 'category_tree_data': askbot_settings.CATEGORY_TREE,
'user_votes': user_votes,
'user_post_id_list': user_post_id_list,
'user_can_post_comment': user_can_post_comment,#in general
+ 'user_already_gave_answer': user_already_gave_answer,
+ 'previous_answer': previous_answer,
'tab_id' : answer_sort_method,
'favorited' : favorited,
'similar_threads' : thread.get_similar_threads(),
@@ -554,6 +593,11 @@ def question(request, id):#refactor - long subroutine. display question body, an
'show_comment': show_comment,
'show_comment_position': show_comment_position,
}
+ #shared with ...
+ if askbot_settings.GROUPS_ENABLED:
+ data['sharing_info'] = thread.get_sharing_info()
+
+ data.update(context.get_for_tag_editor())
return render_into_skin('question.html', data, request)
@@ -593,20 +637,3 @@ def get_comment(request):
comment = models.Post.objects.get(post_type='comment', id=id)
request.user.assert_can_edit_comment(comment)
return {'text': comment.text}
-
-def widget_questions(request):
- """Returns the first x questions based on certain tags.
- @returns template with those questions listed."""
- # make sure this is a GET request with the correct parameters.
- if request.method != 'GET':
- raise Http404
- threads = models.Thread.objects.all()
- tags_input = request.GET.get('tags','').strip()
- if len(tags_input) > 0:
- tags = [tag.strip() for tag in tags_input.split(',')]
- threads = threads.filter(tags__name__in=tags)
- data = {
- 'threads': threads[:askbot_settings.QUESTIONS_WIDGET_MAX_QUESTIONS]
- }
- return render_into_skin('question_widget.html', data, request)
-
diff --git a/askbot/views/users.py b/askbot/views/users.py
index 8588f132..ee3c7d91 100644
--- a/askbot/views/users.py
+++ b/askbot/views/users.py
@@ -33,12 +33,15 @@ from askbot.utils.http import get_request_info
from askbot.utils import functions
from askbot import forms
from askbot import const
+from askbot.views import context as view_context
from askbot.conf import settings as askbot_settings
from askbot import models
from askbot import exceptions
from askbot.models.badges import award_badges_signal
+from askbot.models.tag import get_global_group
+from askbot.models.tag import get_groups
+from askbot.models.tag import format_personal_group_name
from askbot.skins.loaders import render_into_skin
-from askbot.templatetags import extra_tags
from askbot.search.state_manager import SearchState
from askbot.utils import url_utils
from askbot.utils.loading import load_module
@@ -56,13 +59,22 @@ def owner_or_moderator_required(f):
return f(request, profile_owner, context)
return wrapped_func
-def users(request, by_group = False, group_id = None, group_slug = None):
+def show_users(request, by_group=False, group_id=None, group_slug=None):
"""Users view, including listing of users by group"""
+
+ if askbot_settings.GROUPS_ENABLED and not by_group:
+ default_group = get_global_group()
+ group_slug = slugify(default_group.name)
+ new_url = reverse('users_by_group',
+ kwargs={'group_id': default_group.id,
+ 'group_slug': group_slug})
+ return HttpResponseRedirect(new_url)
+
users = models.User.objects.exclude(status = 'b')
group = None
group_email_moderation_enabled = False
- user_can_join_group = False
- user_is_group_member = False
+ user_acceptance_level = 'closed'
+ user_membership_level = 'none'
if by_group == True:
if askbot_settings.GROUPS_ENABLED == False:
raise Http404
@@ -71,25 +83,31 @@ def users(request, by_group = False, group_id = None, group_slug = None):
return HttpResponseRedirect('groups')
else:
try:
- group = models.Tag.group_tags.get(id = group_id)
+ group = models.Group.objects.get(id = group_id)
group_email_moderation_enabled = \
(
askbot_settings.GROUP_EMAIL_ADDRESSES_ENABLED \
and askbot_settings.ENABLE_CONTENT_MODERATION
)
- user_can_join_group = group.group_profile.can_accept_user(request.user)
- except models.Tag.DoesNotExist:
+ user_acceptance_level = group.get_openness_level_for_user(
+ request.user
+ )
+ except models.Group.DoesNotExist:
raise Http404
if group_slug == slugify(group.name):
- group_users = models.User.objects.filter(
- group_memberships__group__id = group_id
- )
- if request.user.is_authenticated():
- user_is_group_member = bool(
- group_users.filter(
- id = request.user.id
- ).count()
+ #filter users by full group memberships
+ #todo: refactor as Group.get_full_members()
+ full_level = models.GroupMembership.FULL
+ memberships = models.GroupMembership.objects.filter(
+ group=group, level=full_level
)
+ user_ids = memberships.values_list('user__id', flat=True)
+ users = users.filter(id__in=user_ids)
+ if request.user.is_authenticated():
+ membership = request.user.get_group_membership(group)
+ if membership:
+ user_membership_level = membership.get_level_display()
+
else:
group_page_url = reverse(
'users_by_group',
@@ -100,7 +118,6 @@ def users(request, by_group = False, group_id = None, group_slug = None):
)
return HttpResponseRedirect(group_page_url)
-
is_paginated = True
sortby = request.GET.get('sort', 'reputation')
@@ -125,13 +142,13 @@ def users(request, by_group = False, group_id = None, group_slug = None):
order_by_parameter = '-reputation'
objects_list = Paginator(
- models.User.objects.order_by(order_by_parameter),
+ users.order_by(order_by_parameter),
const.USERS_PAGE_SIZE
)
base_url = request.path + '?sort=%s&amp;' % sortby
else:
sortby = "reputation"
- matching_users = models.get_users_by_text_query(search_query)
+ matching_users = models.get_users_by_text_query(search_query, users)
objects_list = Paginator(
matching_users.order_by('-reputation'),
const.USERS_PAGE_SIZE
@@ -154,6 +171,20 @@ def users(request, by_group = False, group_id = None, group_slug = None):
'base_url' : base_url
}
paginator_context = functions.setup_paginator(paginator_data) #
+
+ #todo: move to contexts
+ #extra context for the groups
+ if askbot_settings.GROUPS_ENABLED:
+ #todo: cleanup this branched code after groups are migrated to auth_group
+ user_groups = get_groups().exclude_personal()
+ if len(user_groups) <= 1:
+ assert(user_groups[0].name == askbot_settings.GLOBAL_GROUP_NAME)
+ user_groups = None
+ group_openness_choices = models.Group().get_openness_choices()
+ else:
+ user_groups = None
+ group_openness_choices = None
+
data = {
'active_tab': 'users',
'page_class': 'users-page',
@@ -163,9 +194,12 @@ def users(request, by_group = False, group_id = None, group_slug = None):
'tab_id' : sortby,
'paginator_context' : paginator_context,
'group_email_moderation_enabled': group_email_moderation_enabled,
- 'user_can_join_group': user_can_join_group,
- 'user_is_group_member': user_is_group_member
+ 'user_acceptance_level': user_acceptance_level,
+ 'user_membership_level': user_membership_level,
+ 'user_groups': user_groups,
+ 'group_openness_choices': group_openness_choices
}
+
return render_into_skin('users.html', data, request)
@csrf.csrf_protect
@@ -288,7 +322,12 @@ def edit_user(request, id):
set_new_email(user, new_email)
if askbot_settings.EDITABLE_SCREEN_NAME:
- user.username = sanitize_html(form.cleaned_data['username'])
+ new_username = sanitize_html(form.cleaned_data['username'])
+ if user.username != new_username:
+ group = user.get_personal_group()
+ user.username = new_username
+ group.name = format_personal_group_name(user)
+ group.save()
user.real_name = sanitize_html(form.cleaned_data['realname'])
user.website = sanitize_html(form.cleaned_data['website'])
@@ -343,14 +382,19 @@ def user_stats(request, user, context):
#
# Top answers
#
- top_answers = user.posts.get_answers().filter(
+ top_answers = user.posts.get_answers(
+ request.user
+ ).filter(
deleted=False,
thread__posts__deleted=False,
thread__posts__post_type='question',
- ).select_related('thread').order_by('-points', '-added_at')[:100]
+ ).select_related(
+ 'thread'
+ ).order_by(
+ '-score', '-added_at'
+ )[:100]
top_answer_count = len(top_answers)
-
#
# Votes
#
@@ -437,7 +481,10 @@ def user_stats(request, user, context):
badges = badges_dict.items()
badges.sort(key=operator.itemgetter(1), reverse=True)
- user_groups = models.Tag.group_tags.get_for_user(user = user)
+ user_groups = models.Group.objects.get_for_user(user = user)
+ user_groups = user_groups.exclude_personal()
+ global_group = get_global_group()
+ user_groups = user_groups.exclude(name=global_group.name)
if request.user == user:
groups_membership_info = user.get_groups_membership_info(user_groups)
@@ -631,6 +678,39 @@ def user_recent(request, user, context):
context.update(data)
return render_into_skin('user_profile/user_recent.html', context, request)
+#not a view - no direct url route here, called by `user_responses`
+@csrf.csrf_protect
+def show_group_join_requests(request, user, context):
+ """show group join requests to admins who belong to the group"""
+ if request.user.is_administrator_or_moderator() is False:
+ raise Http404
+
+ #get group to which user belongs
+ groups = request.user.get_groups()
+ #construct a dictionary group id --> group object
+ #to avoid loading group via activity content object
+ groups_dict = dict([(group.id, group) for group in groups])
+
+ #get join requests for those groups
+ group_content_type = ContentType.objects.get_for_model(models.Group)
+ join_requests = models.Activity.objects.filter(
+ activity_type=const.TYPE_ACTIVITY_ASK_TO_JOIN_GROUP,
+ content_type=group_content_type,
+ object_id__in=groups_dict.keys()
+ ).order_by('-active_at')
+ data = {
+ 'active_tab':'users',
+ 'page_class': 'user-profile-page',
+ 'tab_name' : 'join_requests',
+ 'tab_description' : _('group joining requests'),
+ 'page_title' : _('profile - moderation'),
+ 'groups_dict': groups_dict,
+ 'join_requests': join_requests
+ }
+ context.update(data)
+ return render_into_skin('user_inbox/group_join_requests.html', context, request)
+
+
@owner_or_moderator_required
def user_responses(request, user, context):
"""
@@ -644,6 +724,10 @@ def user_responses(request, user, context):
and "flags" - moderation items for mods only
"""
+ #0) temporary, till urls are fixed: update context
+ # to contain response counts for all sub-sections
+ context.update(view_context.get_for_inbox(request.user))
+
#1) select activity types according to section
section = request.GET.get('section', 'forum')
if section == 'flags' and not\
@@ -660,15 +744,35 @@ def user_responses(request, user, context):
const.TYPE_ACTIVITY_MODERATED_NEW_POST,
const.TYPE_ACTIVITY_MODERATED_POST_EDIT
)
+ elif section == 'join_requests':
+ return show_group_join_requests(request, user, context)
+ elif section == 'messages':
+ if request.user != user:
+ raise Http404
+ #here we take shortcut, because we don't care about
+ #all the extra context loaded below
+ from group_messaging.views import SendersList, ThreadsList
+ context.update(SendersList().get_context(request))
+ context.update(ThreadsList().get_context(request))
+ data = {
+ 'active_tab':'users',
+ 'page_class': 'user-profile-page',
+ 'tab_name' : 'inbox',
+ 'inbox_section': section,
+ 'tab_description' : _('private messages'),
+ 'page_title' : _('profile - messages')
+ }
+ context.update(data)
+ return render_into_skin(
+ 'user_inbox/messages.html', context, request
+ )
else:
raise Http404
#2) load the activity notifications according to activity types
#todo: insert pagination code here
- memo_set = models.ActivityAuditStatus.objects.filter(
- user = request.user,
- activity__activity_type__in = activity_types
- ).select_related(
+ memo_set = request.user.get_notifications(activity_types)
+ memo_set = memo_set.select_related(
'activity',
'activity__content_type',
'activity__question__thread',
@@ -722,14 +826,14 @@ def user_responses(request, user, context):
'active_tab':'users',
'page_class': 'user-profile-page',
'tab_name' : 'inbox',
- 'inbox_section':section,
+ 'inbox_section': section,
'tab_description' : _('comments and answers to others questions'),
'page_title' : _('profile - responses'),
'post_reject_reasons': reject_reasons,
'responses' : filtered_response_list,
}
context.update(data)
- return render_into_skin('user_profile/user_inbox.html', context, request)
+ return render_into_skin('user_inbox/responses_and_flags.html', context, request)
def user_network(request, user, context):
if 'followit' not in django_settings.INSTALLED_APPS:
@@ -983,13 +1087,14 @@ def groups(request, id = None, slug = None):
scope = 'all-groups'
if scope == 'all-groups':
- groups = models.Tag.group_tags.get_all()
+ groups = models.Group.objects.all()
else:
- groups = models.Tag.group_tags.get_for_user(
- user = request.user
+ groups = models.Group.objects.get_for_user(
+ user=request.user
)
- groups = groups.select_related('group_profile')
+ groups = groups.exclude_personal()
+ groups = groups.annotate(users_count=Count('user'))
user_can_add_groups = request.user.is_authenticated() and \
request.user.is_administrator_or_moderator()
diff --git a/askbot/views/widgets.py b/askbot/views/widgets.py
new file mode 100644
index 00000000..8699cdf1
--- /dev/null
+++ b/askbot/views/widgets.py
@@ -0,0 +1,274 @@
+from datetime import datetime
+
+from django.core import exceptions
+from django.template import Context
+from django.http import HttpResponse, Http404
+from django.views.decorators import csrf
+from django.core.urlresolvers import reverse
+from django.shortcuts import redirect, get_object_or_404
+from django.views.decorators.cache import cache_page
+
+from django.contrib.auth.decorators import login_required
+
+from askbot.skins.loaders import render_into_skin, get_template
+from askbot.conf import settings as askbot_settings
+from askbot.utils import decorators
+from askbot import models
+from askbot import forms
+
+WIDGETS_MODELS = {
+ 'ask': models.AskWidget,
+ 'question': models.QuestionWidget
+ }
+
+WIDGETS_FORMS = {
+ 'ask': forms.CreateAskWidgetForm,
+ 'question': forms.CreateQuestionWidgetForm,
+ }
+
+def _get_model(key):
+ '''like get_object_or_404 but for our models'''
+ try:
+ return WIDGETS_MODELS[key]
+ except KeyError:
+ raise Http404
+
+def _get_form(key):
+ '''like get_object_or_404 but for our forms'''
+ try:
+ return WIDGETS_FORMS[key]
+ except KeyError:
+ raise Http404
+
+@decorators.admins_only
+def widgets(request):
+ data = {
+ 'ask_widgets': models.AskWidget.objects.all().count(),
+ 'question_widgets': models.QuestionWidget.objects.all().count(),
+ 'page_class': 'widgets'
+ }
+ return render_into_skin('embed/widgets.html', data, request)
+
+@csrf.csrf_protect
+def ask_widget(request, widget_id):
+
+ def post_question(data, request):
+ thread = models.Thread.objects.create_new(**data)
+ question = thread._question_post()
+ request.session['widget_question_url'] = question.get_absolute_url()
+ return question
+
+ widget = get_object_or_404(models.AskWidget, id=widget_id)
+
+ if request.method == "POST":
+ form = forms.AskWidgetForm(include_text=widget.include_text_field,
+ data=request.POST)
+ if form.is_valid():
+ ask_anonymously = form.cleaned_data['ask_anonymously']
+ title = form.cleaned_data['title']
+ if widget.include_text_field:
+ text = form.cleaned_data['text']
+ else:
+ text = ' '
+
+
+ if widget.group:
+ group_id = widget.group.id
+ else:
+ group_id = None
+
+ if widget.tag:
+ tagnames = widget.tag.name
+ else:
+ tagnames = ''
+
+ data_dict = {
+ 'title': title,
+ 'added_at': datetime.now(),
+ 'wiki': False,
+ 'text': text,
+ 'tagnames': tagnames,
+ 'group_id': group_id,
+ 'is_anonymous': ask_anonymously
+ }
+ if request.user.is_authenticated():
+ data_dict['author'] = request.user
+ question = post_question(data_dict, request)
+ return redirect('ask_by_widget_complete')
+ else:
+ request.session['widget_question'] = data_dict
+ next_url = '%s?next=%s' % (
+ reverse('widget_signin'),
+ reverse('ask_by_widget', args=(widget.id,))
+ )
+ return redirect(next_url)
+ else:
+ if 'widget_question' in request.session and \
+ request.GET.get('action', 'post-after-login'):
+ if request.user.is_authenticated():
+ data_dict = request.session['widget_question']
+ data_dict['author'] = request.user
+ question = post_question(request.session['widget_question'], request)
+ del request.session['widget_question']
+ return redirect('ask_by_widget_complete')
+ else:
+ #FIXME: this redirect is temporal need to create the correct view
+ next_url = '%s?next=%s' % (reverse('widget_signin'), reverse('ask_by_widget'))
+ return redirect(next_url)
+
+ form = forms.AskWidgetForm(include_text=widget.include_text_field)
+
+ data = {
+ 'form': form,
+ 'widget': widget,
+ 'editor_type': askbot_settings.EDITOR_TYPE
+ }
+ return render_into_skin('embed/ask_by_widget.html', data, request)
+
+@login_required
+def ask_widget_complete(request):
+ question_url = request.session.get('widget_question_url')
+ custom_css = request.session.get('widget_css')
+ if question_url:
+ del request.session['widget_question_url']
+ else:
+ question_url = '#'
+
+ if custom_css:
+ del request.session['widget_css']
+
+ data = {'question_url': question_url, 'custom_css': custom_css}
+ return render_into_skin('embed/ask_widget_complete.html', data, request)
+
+
+@decorators.admins_only
+def list_widgets(request, model):
+ model_class = _get_model(model)
+ widgets = model_class.objects.all()
+ data = {
+ 'widgets': widgets,
+ 'widget_name': model
+ }
+ return render_into_skin('embed/list_widgets.html', data, request)
+
+@decorators.admins_only
+def create_widget(request, model):
+ form_class = _get_form(model)
+ model_class = _get_model(model)
+ if request.method == 'POST':
+ form = form_class(request.POST)
+ if form.is_valid():
+ instance = model_class(**form.cleaned_data)
+ instance.save()
+ return redirect('list_widgets', model=model)
+ else:
+ form = form_class()
+
+ data = {'form': form,
+ 'action': 'edit',
+ 'widget_name': model}
+ return render_into_skin('embed/widget_form.html', data, request)
+
+@decorators.admins_only
+def edit_widget(request, model, widget_id):
+ model_class = _get_model(model)
+ form_class = _get_form(model)
+ widget = get_object_or_404(model_class, pk=widget_id)
+ if request.method == 'POST':
+ form = form_class(request.POST)
+ if form.is_valid():
+ form_dict = dict.copy(form.cleaned_data)
+ for key in widget.__dict__:
+ if key.endswith('_id'):
+ form_key = key.split('_id')[0]
+ if form_dict[form_key]:
+ form_dict[key] = form_dict[form_key].id
+ del form_dict[form_key]
+ else:
+ continue
+
+ widget.__dict__.update(form_dict)
+ widget.save()
+ return redirect('list_widgets', model=model)
+ else:
+ initial_dict = dict.copy(widget.__dict__)
+ for key in initial_dict:
+ if key.endswith('_id'):
+ new_key = key.split('_id')[0]
+ initial_dict[new_key] = initial_dict[key]
+ del initial_dict[key]
+ else:
+ continue
+
+ del initial_dict['_state']
+ form = form_class(initial=initial_dict)
+
+ data = {'form': form,
+ 'action': 'edit',
+ 'widget_name': model}
+ return render_into_skin('embed/widget_form.html', data, request)
+
+@decorators.admins_only
+def delete_widget(request, model, widget_id):
+ model_class = _get_model(model)
+ widget = get_object_or_404(model_class, pk=widget_id)
+ if request.method == "POST":
+ widget.delete()
+ return redirect('list_widgets', model=model)
+ else:
+ return render_into_skin('embed/delete_widget.html',
+ {'widget': widget, 'widget_name': model}, request)
+
+def render_ask_widget_js(request, widget_id):
+ widget = get_object_or_404(models.AskWidget, pk=widget_id)
+ variable_name = "AskbotAskWidget%d" % widget.id
+ content_tpl = get_template('embed/askbot_widget.js', request)
+ context_dict = {'widget': widget,
+ 'host': request.get_host(),
+ 'variable_name': variable_name}
+ content = content_tpl.render(Context(context_dict))
+ return HttpResponse(content, mimetype='text/javascript')
+
+def render_ask_widget_css(request, widget_id):
+ widget = get_object_or_404(models.AskWidget, pk=widget_id)
+ variable_name = "AskbotAskWidget%d" % widget.id
+ content_tpl = get_template('embed/askbot_widget.css', request)
+ context_dict = {'widget': widget,
+ 'host': request.get_host(),
+ 'editor_type': askbot_settings.EDITOR_TYPE,
+ 'variable_name': variable_name}
+ content = content_tpl.render(Context(context_dict))
+ return HttpResponse(content, mimetype='text/css')
+
+def question_widget(request, widget_id):
+ """Returns the first x questions based on certain tags.
+ @returns template with those questions listed."""
+ # make sure this is a GET request with the correct parameters.
+ widget = get_object_or_404(models.QuestionWidget, pk=widget_id)
+
+ if request.method != 'GET':
+ raise Http404
+
+ filter_params = {}
+
+ if widget.tagnames:
+ filter_params['tags__name__in'] = widget.tagnames.split(' ')
+
+ if widget.group:
+ filter_params['groups'] = widget.group
+
+ #simple title search for now
+ if widget.search_query:
+ filter_params['title__icontains'] = widget.search_query
+
+ if filter_params:
+ threads = models.Thread.objects.filter(**filter_params).order_by(widget.order_by)[:widget.question_number]
+ else:
+ threads = models.Thread.objects.all().order_by(widget.order_by)[:widget.question_number]
+
+ data = {
+ 'threads': threads,
+ 'widget': widget
+ }
+
+ return render_into_skin('embed/question_widget.html', data, request)
diff --git a/askbot/views/writers.py b/askbot/views/writers.py
index 9e03ab78..8fcea796 100644
--- a/askbot/views/writers.py
+++ b/askbot/views/writers.py
@@ -15,6 +15,7 @@ import time
import urlparse
from django.shortcuts import get_object_or_404
from django.contrib.auth.decorators import login_required
+from django.contrib.auth.models import User
from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden, Http404
from django.utils import simplejson
from django.utils.html import strip_tags, escape
@@ -24,13 +25,17 @@ from django.core import exceptions
from django.conf import settings
from django.views.decorators import csrf
+from askbot import exceptions as askbot_exceptions
from askbot import forms
from askbot import models
+from askbot.conf import settings as askbot_settings
from askbot.skins.loaders import render_into_skin
from askbot.utils import decorators
+from askbot.utils.forms import format_errors
from askbot.utils.functions import diff_date
from askbot.utils import url_utils
from askbot.utils.file_utils import store_file
+from askbot.views import context
from askbot.templatetags import extra_filters_jinja as template_filters
from askbot.importers.stackexchange import management as stackexchange#todo: may change
@@ -67,8 +72,8 @@ def upload(request):#ajax upload file to a question or answer
if file_name_prefix not in ('', 'group_logo_'):
raise exceptions.PermissionDenied('invalid upload file name prefix')
- # check file type
- f = request.FILES['file-upload']
+ #todo: check file type
+ f = request.FILES['file-upload']#take first file
#todo: extension checking should be replaced with mimetype checking
#and this must be part of the form validation
file_extension = os.path.splitext(f.name)[1].lower()
@@ -215,16 +220,26 @@ def ask(request):#view used to ask a new question
tagnames = form.cleaned_data['tags']
text = form.cleaned_data['text']
ask_anonymously = form.cleaned_data['ask_anonymously']
+ post_privately = form.cleaned_data['post_privately']
+ group_id = form.cleaned_data.get('group_id', None)
if request.user.is_authenticated():
+ drafts = models.DraftQuestion.objects.filter(
+ author=request.user
+ )
+ drafts.delete()
+
+ user = form.get_post_user(request.user)
try:
- question = request.user.post_question(
+ question = user.post_question(
title = title,
body_text = text,
tags = tagnames,
wiki = wiki,
is_anonymous = ask_anonymously,
- timestamp = timestamp
+ is_private = post_privately,
+ timestamp = timestamp,
+ group_id = group_id
)
return HttpResponseRedirect(question.get_absolute_url())
except exceptions.PermissionDenied, e:
@@ -251,13 +266,31 @@ def ask(request):#view used to ask a new question
if request.method == 'GET':
form = forms.AskForm()
+ draft_title = ''
+ draft_text = ''
+ draft_tagnames = ''
+ if request.user.is_authenticated():
+ drafts = models.DraftQuestion.objects.filter(author=request.user)
+ if len(drafts) > 0:
+ draft = drafts[0]
+ draft_title = draft.title
+ draft_text = draft.text
+ draft_tagnames = draft.tagnames
+
form.initial = {
- 'title': request.REQUEST.get('title', ''),
- 'text': request.REQUEST.get('text', ''),
- 'tags': request.REQUEST.get('tags', ''),
+ 'title': request.REQUEST.get('title', draft_title),
+ 'text': request.REQUEST.get('text', draft_text),
+ 'tags': request.REQUEST.get('tags', draft_tagnames),
'wiki': request.REQUEST.get('wiki', False),
- 'is_anonymous': request.REQUEST.get('is_anonymous', False),
+ 'ask_anonymously': request.REQUEST.get('ask_anonymousy', False),
+ 'post_privately': request.REQUEST.get('post_privately', False)
}
+ if 'group_id' in request.REQUEST:
+ try:
+ group_id = int(request.GET.get('group_id', None))
+ form.initial['group_id'] = group_id
+ except Exception:
+ pass
data = {
'active_tab': 'ask',
@@ -265,7 +298,10 @@ def ask(request):#view used to ask a new question
'form' : form,
'mandatory_tags': models.tag.get_mandatory_tags(),
'email_validation_faq_url':reverse('faq') + '#validate',
+ 'category_tree_data': askbot_settings.CATEGORY_TREE,
+ 'tag_names': list()#need to keep context in sync with edit_question for tag editor
}
+ data.update(context.get_for_tag_editor())
return render_into_skin('ask.html', data, request)
@login_required
@@ -279,6 +315,7 @@ def retag_question(request, id):
request.user.assert_can_retag_question(question)
if request.method == 'POST':
form = forms.RetagQuestionForm(question, request.POST)
+
if form.is_valid():
if form.has_changed():
request.user.retag_question(question=question, tags=form.cleaned_data['tags'])
@@ -287,13 +324,19 @@ def retag_question(request, id):
'success': True,
'new_tags': question.thread.tagnames
}
+
+ if request.user.message_set.count() > 0:
+ #todo: here we will possibly junk messages
+ message = request.user.get_and_delete_messages()[-1]
+ response_data['message'] = message
+
data = simplejson.dumps(response_data)
return HttpResponse(data, mimetype="application/json")
else:
return HttpResponseRedirect(question.get_absolute_url())
elif request.is_ajax():
response_data = {
- 'message': unicode(form.errors['tags']),
+ 'message': format_errors(form.errors['tags']),
'success': False
}
data = simplejson.dumps(response_data)
@@ -326,46 +369,43 @@ def edit_question(request, id):
"""edit question view
"""
question = get_object_or_404(models.Post, id=id)
- latest_revision = question.get_latest_revision()
+ revision = question.get_latest_revision()
revision_form = None
try:
request.user.assert_can_edit_question(question)
if request.method == 'POST':
- if 'select_revision' in request.POST:
+ if request.POST['select_revision'] == 'true':
#revert-type edit - user selected previous revision
revision_form = forms.RevisionForm(
question,
- latest_revision,
+ revision,
request.POST
)
if revision_form.is_valid():
# Replace with those from the selected revision
rev_id = revision_form.cleaned_data['revision']
- selected_revision = models.PostRevision.objects.question_revisions().get(
- post = question,
- revision = rev_id
- )
+ revision = question.revisions.get(revision = rev_id)
form = forms.EditQuestionForm(
question = question,
user = request.user,
- revision = selected_revision
+ revision = revision
)
else:
form = forms.EditQuestionForm(
request.POST,
question = question,
user = request.user,
- revision = latest_revision
+ revision = revision
)
else:#new content edit
# Always check modifications against the latest revision
form = forms.EditQuestionForm(
request.POST,
question = question,
- revision = latest_revision,
+ revision = revision,
user = request.user,
)
- revision_form = forms.RevisionForm(question, latest_revision)
+ revision_form = forms.RevisionForm(question, revision)
if form.is_valid():
if form.has_changed():
@@ -374,8 +414,11 @@ def edit_question(request, id):
is_anon_edit = form.cleaned_data['stay_anonymous']
is_wiki = form.cleaned_data.get('wiki', question.wiki)
+ post_privately = form.cleaned_data['post_privately']
+
+ user = form.get_post_user(request.user)
- request.user.edit_question(
+ user.edit_question(
question = question,
title = form.cleaned_data['title'],
body_text = form.cleaned_data['text'],
@@ -383,25 +426,35 @@ def edit_question(request, id):
tags = form.cleaned_data['tags'],
wiki = is_wiki,
edit_anonymously = is_anon_edit,
+ is_private = post_privately
)
return HttpResponseRedirect(question.get_absolute_url())
else:
#request type was "GET"
- revision_form = forms.RevisionForm(question, latest_revision)
+ revision_form = forms.RevisionForm(question, revision)
+ initial = {
+ 'post_privately': question.is_private(),
+ 'wiki': question.wiki
+ }
form = forms.EditQuestionForm(
question = question,
- revision = latest_revision,
- user = request.user
+ revision = revision,
+ user = request.user,
+ initial = initial
)
data = {
'page_class': 'edit-question-page',
'active_tab': 'questions',
'question': question,
+ 'revision': revision,
'revision_form': revision_form,
'mandatory_tags': models.tag.get_mandatory_tags(),
'form' : form,
+ 'tag_names': question.thread.get_tag_names(),
+ 'category_tree_data': askbot_settings.CATEGORY_TREE
}
+ data.update(context.get_for_tag_editor())
return render_into_skin('question_edit.html', data, request)
except exceptions.PermissionDenied, e:
@@ -413,53 +466,54 @@ def edit_question(request, id):
@decorators.check_spam('text')
def edit_answer(request, id):
answer = get_object_or_404(models.Post, id=id)
- latest_revision = answer.get_latest_revision()
+ revision = answer.get_latest_revision()
try:
request.user.assert_can_edit_answer(answer)
- latest_revision = answer.get_latest_revision()
if request.method == "POST":
- if 'select_revision' in request.POST:
+ if request.POST['select_revision'] == 'true':
# user has changed revistion number
revision_form = forms.RevisionForm(
answer,
- latest_revision,
+ revision,
request.POST
)
if revision_form.is_valid():
# Replace with those from the selected revision
rev = revision_form.cleaned_data['revision']
- selected_revision = models.PostRevision.objects.answer_revisions().get(
- post = answer,
- revision = rev
- )
- form = forms.EditAnswerForm(answer, selected_revision)
+ revision = answer.revisions.get(revision = rev)
+ form = forms.EditAnswerForm(answer, revision)
else:
form = forms.EditAnswerForm(
answer,
- latest_revision,
+ revision,
request.POST
)
else:
- form = forms.EditAnswerForm(answer, latest_revision, request.POST)
- revision_form = forms.RevisionForm(answer, latest_revision)
+ form = forms.EditAnswerForm(answer, revision, request.POST)
+ revision_form = forms.RevisionForm(answer, revision)
if form.is_valid():
if form.has_changed():
- request.user.edit_answer(
+ user = form.get_post_user(request.user)
+ user.edit_answer(
answer = answer,
body_text = form.cleaned_data['text'],
revision_comment = form.cleaned_data['summary'],
wiki = form.cleaned_data.get('wiki', answer.wiki),
+ is_private = form.cleaned_data.get('is_private', False)
#todo: add wiki field to form
)
return HttpResponseRedirect(answer.get_absolute_url())
else:
- revision_form = forms.RevisionForm(answer, latest_revision)
- form = forms.EditAnswerForm(answer, latest_revision)
+ revision_form = forms.RevisionForm(answer, revision)
+ form = forms.EditAnswerForm(answer, revision)
+ if request.user.can_make_group_private_posts():
+ form.initial['post_privately'] = answer.is_private()
data = {
'page_class': 'edit-answer-page',
'active_tab': 'questions',
'answer': answer,
+ 'revision': revision,
'revision_form': revision_form,
'form': form,
}
@@ -489,16 +543,30 @@ def answer(request, id):#process a new answer
update_time = datetime.datetime.now()
if request.user.is_authenticated():
+ drafts = models.DraftAnswer.objects.filter(
+ author=request.user,
+ thread=question.thread
+ )
+ drafts.delete()
try:
follow = form.cleaned_data['email_notify']
- answer = request.user.post_answer(
+ is_private = form.cleaned_data['post_privately']
+
+ user = form.get_post_user(request.user)
+
+ answer = user.post_answer(
question = question,
body_text = text,
follow = follow,
wiki = wiki,
+ is_private = is_private,
timestamp = update_time,
)
return HttpResponseRedirect(answer.get_absolute_url())
+ except askbot_exceptions.AnswerAlreadyGiven, e:
+ request.user.message_set.create(message = unicode(e))
+ answer = question.thread.get_answers_by_user(request.user)[0]
+ return HttpResponseRedirect(answer.get_absolute_url())
except exceptions.PermissionDenied, e:
request.user.message_set.create(message = unicode(e))
else:
@@ -606,6 +674,8 @@ def edit_comment(request):
is_editable = template_filters.can_edit_comment(comment_post.author, comment_post)
tz = ' ' + template_filters.TIMEZONE_STR
+ tz = template_filters.TIMEZONE_STR
+
return {
'id' : comment_post.id,
'object_id': comment_post.parent.id,
@@ -655,3 +725,68 @@ def delete_comment(request):
unicode(e),
mimetype = 'application/json'
)
+
+@decorators.admins_only
+@decorators.post_only
+def comment_to_answer(request):
+ comment_id = request.POST.get('comment_id')
+ if comment_id:
+ comment_id = int(comment_id)
+ comment = get_object_or_404(models.Post,
+ post_type='comment', id=comment_id)
+ comment.post_type = 'answer'
+ old_parent = comment.parent
+
+ comment.parent = comment.thread._question_post()
+ comment.save()
+
+ comment.thread.update_answer_count()
+
+ comment.parent.comment_count += 1
+ comment.parent.save()
+
+ #to avoid db constraint error
+ if old_parent.comment_count >= 1:
+ old_parent.comment_count -= 1
+ else:
+ old_parent.comment_count = 0
+
+ old_parent.save()
+
+ comment.thread.invalidate_cached_data()
+
+ return HttpResponseRedirect(comment.get_absolute_url())
+ else:
+ raise Http404
+
+@decorators.admins_only
+@decorators.post_only
+def answer_to_comment(request):
+ answer_id = request.POST.get('answer_id')
+ if answer_id:
+ answer_id = int(answer_id)
+ answer = get_object_or_404(models.Post,
+ post_type = 'answer', id=answer_id)
+ if len(answer.text) <= 300:
+ answer.post_type = 'comment'
+ answer.parent = answer.thread._question_post()
+ #can we trust this?
+ old_comment_count = answer.comment_count
+ answer.comment_count = 0
+
+ answer_comments = models.Post.objects.get_comments().filter(parent=answer)
+ answer_comments.update(parent=answer.parent)
+
+ answer.parse_and_save(author=answer.author)
+ answer.thread.update_answer_count()
+
+ answer.parent.comment_count = 1 + old_comment_count
+ answer.parent.save()
+
+ answer.thread.invalidate_cached_data()
+ else:
+ request.user.message_set.create(message = _("the selected answer cannot be a comment"))
+
+ return HttpResponseRedirect(answer.get_absolute_url())
+ else:
+ raise Http404
diff --git a/askbot_requirements.txt b/askbot_requirements.txt
index 7b619c36..2be12b8e 100644
--- a/askbot_requirements.txt
+++ b/askbot_requirements.txt
@@ -19,3 +19,6 @@ django-recaptcha-works
python-openid
pystache==0.3.1
pytz
+django-tinymce
+longerusername
+beautifulsoup4
diff --git a/group_messaging/__init__.py b/group_messaging/__init__.py
new file mode 100644
index 00000000..642ad5c8
--- /dev/null
+++ b/group_messaging/__init__.py
@@ -0,0 +1,14 @@
+"""`group_messages` is a django application
+which allows users send messages to other users
+and groups (instances of :class:`django.contrib.auth.models.Group`)
+
+The same methods are used are used to send messages
+to users as to groups - achieved via special "personal groups".
+
+By convention - personal groups have names formatted as follows:
+_personal_<user id>, for example for the user whose `id == 1`,
+the group should be named `'_personal_1'`.
+
+Only one person must be a member of a personal group and
+each user must have such group.
+"""
diff --git a/group_messaging/migrations/0001_initial.py b/group_messaging/migrations/0001_initial.py
new file mode 100644
index 00000000..7d907dc1
--- /dev/null
+++ b/group_messaging/migrations/0001_initial.py
@@ -0,0 +1,177 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding model 'SenderList'
+ db.create_table('group_messaging_senderlist', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('recipient', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.Group'], unique=True)),
+ ))
+ db.send_create_signal('group_messaging', ['SenderList'])
+
+ # Adding M2M table for field senders on 'SenderList'
+ db.create_table('group_messaging_senderlist_senders', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('senderlist', models.ForeignKey(orm['group_messaging.senderlist'], null=False)),
+ ('user', models.ForeignKey(orm['auth.user'], null=False))
+ ))
+ db.create_unique('group_messaging_senderlist_senders', ['senderlist_id', 'user_id'])
+
+ # Adding model 'MessageMemo'
+ db.create_table('group_messaging_messagememo', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ('message', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['group_messaging.Message'])),
+ ('status', self.gf('django.db.models.fields.SmallIntegerField')(default=0)),
+ ))
+ db.send_create_signal('group_messaging', ['MessageMemo'])
+
+ # Adding unique constraint on 'MessageMemo', fields ['user', 'message']
+ db.create_unique('group_messaging_messagememo', ['user_id', 'message_id'])
+
+ # Adding model 'Message'
+ db.create_table('group_messaging_message', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('message_type', self.gf('django.db.models.fields.SmallIntegerField')(default=0)),
+ ('sender', self.gf('django.db.models.fields.related.ForeignKey')(related_name='sent_messages', to=orm['auth.User'])),
+ ('root', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='descendants', null=True, to=orm['group_messaging.Message'])),
+ ('parent', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='children', null=True, to=orm['group_messaging.Message'])),
+ ('headline', self.gf('django.db.models.fields.CharField')(max_length=80)),
+ ('text', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+ ('html', self.gf('django.db.models.fields.TextField')(null=True, blank=True)),
+ ('sent_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+ ('last_active_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+ ('active_until', self.gf('django.db.models.fields.DateTimeField')(null=True, blank=True)),
+ ))
+ db.send_create_signal('group_messaging', ['Message'])
+
+ # Adding M2M table for field recipients on 'Message'
+ db.create_table('group_messaging_message_recipients', (
+ ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)),
+ ('message', models.ForeignKey(orm['group_messaging.message'], null=False)),
+ ('group', models.ForeignKey(orm['auth.group'], null=False))
+ ))
+ db.create_unique('group_messaging_message_recipients', ['message_id', 'group_id'])
+
+ def backwards(self, orm):
+ # Removing unique constraint on 'MessageMemo', fields ['user', 'message']
+ db.delete_unique('group_messaging_messagememo', ['user_id', 'message_id'])
+
+ # Deleting model 'SenderList'
+ db.delete_table('group_messaging_senderlist')
+
+ # Removing M2M table for field senders on 'SenderList'
+ db.delete_table('group_messaging_senderlist_senders')
+
+ # Deleting model 'MessageMemo'
+ db.delete_table('group_messaging_messagememo')
+
+ # Deleting model 'Message'
+ db.delete_table('group_messaging_message')
+
+ # Removing M2M table for field recipients on 'Message'
+ db.delete_table('group_messaging_message_recipients')
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'group_messaging.message': {
+ 'Meta': {'object_name': 'Message'},
+ 'active_until': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'headline': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_active_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'message_type': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['group_messaging.Message']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False'}),
+ 'root': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'descendants'", 'null': 'True', 'to': "orm['group_messaging.Message']"}),
+ 'sender': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sent_messages'", 'to': "orm['auth.User']"}),
+ 'sent_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'group_messaging.messagememo': {
+ 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'MessageMemo'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group_messaging.Message']"}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'group_messaging.senderlist': {
+ 'Meta': {'object_name': 'SenderList'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'recipient': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']", 'unique': 'True'}),
+ 'senders': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'symmetrical': 'False'})
+ }
+ }
+
+ complete_apps = ['group_messaging'] \ No newline at end of file
diff --git a/group_messaging/migrations/0002_auto__add_lastvisittime__add_unique_lastvisittime_user_message__add_fi.py b/group_messaging/migrations/0002_auto__add_lastvisittime__add_unique_lastvisittime_user_message__add_fi.py
new file mode 100644
index 00000000..5e92ef2b
--- /dev/null
+++ b/group_messaging/migrations/0002_auto__add_lastvisittime__add_unique_lastvisittime_user_message__add_fi.py
@@ -0,0 +1,142 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding model 'LastVisitTime'
+ db.create_table('group_messaging_lastvisittime', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])),
+ ('message', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['group_messaging.Message'])),
+ ('at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
+ ))
+ db.send_create_signal('group_messaging', ['LastVisitTime'])
+
+ # Adding unique constraint on 'LastVisitTime', fields ['user', 'message']
+ db.create_unique('group_messaging_lastvisittime', ['user_id', 'message_id'])
+
+ # Adding field 'Message.senders_info'
+ db.add_column('group_messaging_message', 'senders_info',
+ self.gf('django.db.models.fields.CharField')(default='', max_length=64),
+ keep_default=False)
+
+ def backwards(self, orm):
+ # Removing unique constraint on 'LastVisitTime', fields ['user', 'message']
+ db.delete_unique('group_messaging_lastvisittime', ['user_id', 'message_id'])
+
+ # Deleting model 'LastVisitTime'
+ db.delete_table('group_messaging_lastvisittime')
+
+ # Deleting field 'Message.senders_info'
+ db.delete_column('group_messaging_message', 'senders_info')
+
+ models = {
+ 'auth.group': {
+ 'Meta': {'object_name': 'Group'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+ },
+ 'auth.permission': {
+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+ },
+ 'auth.user': {
+ 'Meta': {'object_name': 'User'},
+ 'about': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'avatar_type': ('django.db.models.fields.CharField', [], {'default': "'n'", 'max_length': '1'}),
+ 'bronze': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'consecutive_days_visit_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'country': ('django_countries.fields.CountryField', [], {'max_length': '2', 'blank': 'True'}),
+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'date_of_birth': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'display_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+ 'email_isvalid': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'email_key': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True'}),
+ 'email_signature': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'email_tag_filter_strategy': ('django.db.models.fields.SmallIntegerField', [], {'default': '1'}),
+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'gold': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'gravatar': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'ignored_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'interesting_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'is_fake': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+ 'last_seen': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+ 'location': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'new_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+ 'questions_per_page': ('django.db.models.fields.SmallIntegerField', [], {'default': '10'}),
+ 'real_name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+ 'reputation': ('django.db.models.fields.PositiveIntegerField', [], {'default': '1'}),
+ 'seen_response_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
+ 'show_country': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'show_marked_tags': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'silver': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'status': ('django.db.models.fields.CharField', [], {'default': "'w'", 'max_length': '2'}),
+ 'subscribed_tags': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
+ 'website': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'})
+ },
+ 'contenttypes.contenttype': {
+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+ },
+ 'group_messaging.lastvisittime': {
+ 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'LastVisitTime'},
+ 'at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group_messaging.Message']"}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'group_messaging.message': {
+ 'Meta': {'object_name': 'Message'},
+ 'active_until': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'headline': ('django.db.models.fields.CharField', [], {'max_length': '80'}),
+ 'html': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'last_active_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'message_type': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['group_messaging.Message']"}),
+ 'recipients': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False'}),
+ 'root': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'descendants'", 'null': 'True', 'to': "orm['group_messaging.Message']"}),
+ 'sender': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sent_messages'", 'to': "orm['auth.User']"}),
+ 'senders_info': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '64'}),
+ 'sent_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'text': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'group_messaging.messagememo': {
+ 'Meta': {'unique_together': "(('user', 'message'),)", 'object_name': 'MessageMemo'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'message': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['group_messaging.Message']"}),
+ 'status': ('django.db.models.fields.SmallIntegerField', [], {'default': '0'}),
+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"})
+ },
+ 'group_messaging.senderlist': {
+ 'Meta': {'object_name': 'SenderList'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'recipient': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']", 'unique': 'True'}),
+ 'senders': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'symmetrical': 'False'})
+ }
+ }
+
+ complete_apps = ['group_messaging'] \ No newline at end of file
diff --git a/askbot/db b/group_messaging/migrations/__init__.py
index e69de29b..e69de29b 100644
--- a/askbot/db
+++ b/group_messaging/migrations/__init__.py
diff --git a/group_messaging/models.py b/group_messaging/models.py
new file mode 100644
index 00000000..62f720cf
--- /dev/null
+++ b/group_messaging/models.py
@@ -0,0 +1,249 @@
+"""models for the ``group_messaging`` app
+"""
+import datetime
+from django.db import models
+from django.contrib.auth.models import Group
+from django.contrib.auth.models import User
+
+MAX_TITLE_LENGTH = 80
+MAX_SENDERS_INFO_LENGTH = 64
+
+#dummy parse message function
+parse_message = lambda v: v
+
+GROUP_NAME_TPL = '_personal_%s'
+
+def get_personal_group_by_user_id(user_id):
+ return Group.objects.get(name=GROUP_NAME_TPL % user_id)
+
+
+def get_personal_groups_for_users(users):
+ """for a given list of users return their personal groups"""
+ group_names = [(GROUP_NAME_TPL % user.id) for user in users]
+ return Group.objects.filter(name__in=group_names)
+
+
+def get_personal_group(user):
+ """returns personal group for the user"""
+ return get_personal_group_by_user_id(user.id)
+
+
+def create_personal_group(user):
+ """creates a personal group for the user"""
+ group = Group(name=GROUP_NAME_TPL % user.id)
+ group.save()
+ return group
+
+
+class LastVisitTime(models.Model):
+ """just remembers when a user has
+ last visited a given thread
+ """
+ user = models.ForeignKey(User)
+ message = models.ForeignKey('Message')
+ at = models.DateTimeField(auto_now_add=True)
+
+ class Meta:
+ unique_together = ('user', 'message')
+
+
+class SenderListManager(models.Manager):
+ """model manager for the :class:`SenderList`"""
+
+ def get_senders_for_user(self, user=None):
+ """returns query set of :class:`User`"""
+ user_groups = user.groups.all()
+ lists = self.filter(recipient__in=user_groups)
+ user_ids = lists.values_list(
+ 'senders__id', flat=True
+ ).distinct()
+ return User.objects.filter(id__in=user_ids)
+
+class SenderList(models.Model):
+ """a model to store denormalized data
+ about who sends messages to any given person
+ sender list is populated automatically
+ as new messages are created
+ """
+ recipient = models.ForeignKey(Group, unique=True)
+ senders = models.ManyToManyField(User)
+ objects = SenderListManager()
+
+
+class MessageMemo(models.Model):
+ """A bridge between message recipients and messages
+ these records are only created when user sees a message.
+ The idea is that using groups as recipients, we can send
+ messages to massive numbers of users, without cluttering
+ the database.
+
+ Instead we'll be creating a "seen" message after user
+ reads the message.
+ """
+ SEEN = 0
+ ARCHIVED = 1
+ STATUS_CHOICES = (
+ (SEEN, 'seen'),
+ (ARCHIVED, 'archived')
+ )
+ user = models.ForeignKey(User)
+ message = models.ForeignKey('Message')
+ status = models.SmallIntegerField(
+ choices=STATUS_CHOICES, default=SEEN
+ )
+
+ class Meta:
+ unique_together = ('user', 'message')
+
+
+class MessageManager(models.Manager):
+ """model manager for the :class:`Message`"""
+
+ def get_threads_for_user(self, user):
+ user_groups = user.groups.all()
+ return self.filter(
+ root=None,
+ message_type=Message.STORED,
+ recipients__in=user_groups
+ )
+
+ def create(self, **kwargs):
+ """creates a message"""
+ root = kwargs.get('root', None)
+ if root is None:
+ parent = kwargs.get('parent', None)
+ if parent:
+ if parent.root:
+ root = parent.root
+ else:
+ root = parent
+ kwargs['root'] = root
+
+ headline = kwargs.get('headline', kwargs['text'])
+ kwargs['headline'] = headline[:MAX_TITLE_LENGTH]
+ kwargs['html'] = parse_message(kwargs['text'])
+
+ message = super(MessageManager, self).create(**kwargs)
+ #creator of message saw it by definition
+ #crate a "seen" memo for the sender, because we
+ #don't want to inform the user about his/her own post
+ sender = kwargs['sender']
+ MessageMemo.objects.create(
+ message=message, user=sender, status=MessageMemo.SEEN
+ )
+ return message
+
+
+ def create_thread(self, sender=None, recipients=None, text=None):
+ """creates a stored message and adds recipients"""
+ message = self.create(
+ message_type=Message.STORED,
+ sender=sender,
+ senders_info=sender.username,
+ text=text,
+ )
+ message.add_recipients(recipients)
+ return message
+
+ def create_response(self, sender=None, text=None, parent=None):
+ message = self.create(
+ parent=parent,
+ message_type=Message.STORED,
+ sender=sender,
+ text=text,
+ )
+ #recipients are parent's recipients + sender
+ #creator of response gets memo in the "read" status
+ recipients = set(parent.recipients.all())
+ senders_group = get_personal_group(parent.sender)
+ recipients.add(senders_group)
+ message.add_recipients(recipients)
+ #add author of the parent as a recipient to parent
+ parent.add_recipients([senders_group])
+ #mark last active timestamp for the root message
+ #so that we know that this thread was most recently
+ #updated
+ message.update_root_info()
+ return message
+
+
+class Message(models.Model):
+ """the message model allowing users to send
+ messages to other users and groups, via
+ personal groups.
+ """
+ STORED = 0
+ TEMPORARY = 1
+ ONE_TIME = 2
+ MESSAGE_TYPE_CHOICES = (
+ (STORED, 'email-like message, stored in the inbox'),
+ (ONE_TIME, 'will be shown just once'),
+ (TEMPORARY, 'will be shown until certain time')
+ )
+
+ message_type = models.SmallIntegerField(
+ choices=MESSAGE_TYPE_CHOICES,
+ default=STORED,
+ )
+
+ sender = models.ForeignKey(User, related_name='sent_messages')
+
+ senders_info = models.CharField(
+ max_length=MAX_SENDERS_INFO_LENGTH,
+ default=''
+ )#comma-separated list of a few names
+
+ recipients = models.ManyToManyField(Group)
+
+ root = models.ForeignKey(
+ 'self', null=True,
+ blank=True, related_name='descendants'
+ )
+
+ parent = models.ForeignKey(
+ 'self', null=True,
+ blank=True, related_name='children'
+ )
+
+ headline = models.CharField(max_length=MAX_TITLE_LENGTH)
+
+ text = models.TextField(
+ null=True, blank=True,
+ help_text='source text for the message, e.g. in markdown format'
+ )
+
+ html = models.TextField(
+ null=True, blank=True,
+ help_text='rendered html of the message'
+ )
+
+ sent_at = models.DateTimeField(auto_now_add=True)
+ last_active_at = models.DateTimeField(auto_now_add=True)
+ active_until = models.DateTimeField(blank=True, null=True)
+
+ objects = MessageManager()
+
+ def add_recipients(self, recipients):
+ """adds recipients to the message
+ and updates the sender lists for all recipients
+ todo: sender lists may be updated in a lazy way - per user
+ """
+ self.recipients.add(*recipients)
+ for recipient in recipients:
+ sender_list, created = SenderList.objects.get_or_create(recipient=recipient)
+ sender_list.senders.add(self.sender)
+
+ def update_root_info(self):
+ """Update the last active at timestamp and
+ the contributors info, if relevant.
+ Root object will be saved to the database.
+ """
+ self.root.last_active_at = datetime.datetime.now()
+ senders_names = self.root.senders_info.split(',')
+
+ if self.sender.username in senders_names:
+ senders_names.remove(self.sender.username)
+ senders_names.insert(0, self.sender.username)
+
+ self.root.senders_info = (','.join(senders_names))[:64]
+ self.root.save()
diff --git a/group_messaging/tests.py b/group_messaging/tests.py
new file mode 100644
index 00000000..c8401dc1
--- /dev/null
+++ b/group_messaging/tests.py
@@ -0,0 +1,118 @@
+from django.test import TestCase
+from django.contrib.auth.models import User, Group
+from group_messaging.models import Message
+from group_messaging.models import MessageMemo
+from group_messaging.models import SenderList
+from group_messaging.models import get_personal_group
+from group_messaging.models import create_personal_group
+
+MESSAGE_TEXT = 'test message text'
+
+def create_user(name):
+ """creates a user and a personal group,
+ returns the created user"""
+ user = User.objects.create_user(name, name + '@example.com')
+ #note that askbot will take care of three lines below automatically
+ try:
+ group = get_personal_group(user)
+ except Group.DoesNotExist:
+ group = create_personal_group(user)
+ group_name = '_personal_%d' % user.id
+ group, created = Group.objects.get_or_create(name=group_name)
+ user.groups.add(group)
+ return user
+
+class ModelTests(TestCase):
+ """test cases for the `private_messaging` models"""
+
+ def setUp(self):
+ self.sender = create_user('sender')
+ self.recipient = create_user('recipient')
+
+ def create_thread(self, recipients):
+ return Message.objects.create_thread(
+ sender=self.sender, recipients=recipients,
+ text=MESSAGE_TEXT
+ )
+
+ def create_thread_for_user(self, user):
+ group = get_personal_group(user)
+ return self.create_thread([group])
+
+ def test_create_thread_for_user(self):
+ """the basic create thread with one recipient
+ tests that the recipient is there"""
+ message = self.create_thread_for_user(self.recipient)
+ #message type is stored
+ self.assertEqual(message.message_type, Message.STORED)
+ #recipient is in the list of recipients
+ recipients = set(message.recipients.all())
+ recipient_group = get_personal_group(self.recipient)
+ #sender_group = get_personal_group(self.sender) #maybe add this too
+ expected_recipients = set([recipient_group])
+ self.assertEqual(recipients, expected_recipients)
+ #self.assertRaises(
+ # MessageMemo.DoesNotExist,
+ # MessageMemo.objects.get,
+ # message=message
+ #)
+ #make sure that the original senders memo to the root
+ #message is marke ad seen
+ memos = MessageMemo.objects.filter(
+ message=message,
+ user=self.sender
+ )
+ self.assertEquals(memos.count(), 1)
+ self.assertEqual(memos[0].status, MessageMemo.SEEN)
+
+ def test_get_senders_for_user(self):
+ """this time send thread to a real group test that
+ member of the group has updated the sender list"""
+ group = Group.objects.create(name='somegroup')
+ self.recipient.groups.add(group)
+ message = self.create_thread([group])
+ senders = SenderList.objects.get_senders_for_user(self.recipient)
+ self.assertEqual(set(senders), set([self.sender]))
+
+ def test_create_thread_response(self):
+ """create a thread with one response,
+ then load thread for the user
+ test that only the root message is retrieved"""
+ root_message = self.create_thread_for_user(self.recipient)
+ response = Message.objects.create_response(
+ sender=self.recipient,
+ text='some response',
+ parent=root_message
+ )
+ self.assertEqual(response.message_type, Message.STORED)
+
+ #assert that there is only one "seen" memo for the response
+ memos = MessageMemo.objects.filter(message=response)
+ self.assertEqual(memos.count(), 1)
+ self.assertEqual(memos[0].user, self.recipient)
+ self.assertEqual(memos[0].status, MessageMemo.SEEN)
+
+ #assert that recipients are the two people who are part of
+ #this conversation
+ recipients = set(response.recipients.all())
+ sender_group = get_personal_group(self.sender)
+ recipient_group = get_personal_group(self.recipient)
+ expected_recipients = set([sender_group, recipient_group])
+ self.assertEqual(recipients, expected_recipients)
+
+ def test_get_threads_for_user(self):
+ root_message = self.create_thread_for_user(self.recipient)
+ threads = set(Message.objects.get_threads_for_user(self.sender))
+ self.assertEqual(threads, set([]))
+ threads = set(Message.objects.get_threads_for_user(self.recipient))
+ self.assertEqual(threads, set([root_message]))
+
+ response = Message.objects.create_response(
+ sender=self.recipient,
+ text='some response',
+ parent=root_message
+ )
+ threads = set(Message.objects.get_threads_for_user(self.sender))
+ self.assertEqual(threads, set([root_message]))
+ threads = set(Message.objects.get_threads_for_user(self.recipient))
+ self.assertEqual(threads, set([root_message]))
diff --git a/group_messaging/urls.py b/group_messaging/urls.py
new file mode 100644
index 00000000..30002bf3
--- /dev/null
+++ b/group_messaging/urls.py
@@ -0,0 +1,32 @@
+"""url configuration for the group_messaging application"""
+from django.conf.urls.defaults import patterns
+from django.conf.urls.defaults import url
+from group_messaging import views
+
+urlpatterns = patterns('',
+ url(
+ '^threads/$',
+ views.ThreadsList().as_view(),
+ name='get_threads'
+ ),
+ url(
+ '^threads/(?P<thread_id>\d+)/$',
+ views.ThreadDetails().as_view(),
+ name='thread_details'
+ ),
+ url(
+ '^threads/create/$',
+ views.NewThread().as_view(),
+ name='create_thread'
+ ),
+ url(
+ '^senders/$',
+ views.SendersList().as_view(),
+ name='get_senders'
+ ),
+ url(
+ '^post-reply/$',
+ views.PostReply().as_view(),
+ name='post_reply'
+ )
+)
diff --git a/group_messaging/views.py b/group_messaging/views.py
new file mode 100644
index 00000000..289961ff
--- /dev/null
+++ b/group_messaging/views.py
@@ -0,0 +1,214 @@
+"""semi-views for the `group_messaging` application
+These are not really views - rather context generator
+functions, to be used separately, when needed.
+
+For example, some other application can call these
+in order to render messages within the page.
+
+Notice that :mod:`urls` module decorates all these functions
+and turns them into complete views
+"""
+import copy
+import datetime
+from coffin.template.loader import get_template
+from django.contrib.auth.models import User
+from django.forms import IntegerField
+from django.http import HttpResponse
+from django.http import HttpResponseNotAllowed
+from django.http import HttpResponseForbidden
+from django.utils import simplejson
+from group_messaging.models import Message
+from group_messaging.models import SenderList
+from group_messaging.models import LastVisitTime
+from group_messaging.models import get_personal_group_by_user_id
+from group_messaging.models import get_personal_groups_for_users
+
+class InboxView(object):
+ """custom class-based view
+ to be used for pjax use and for generation
+ of content in the traditional way, where
+ the only the :method:`get_context` would be used.
+ """
+ template_name = None #used only for the "GET" method
+ http_method_names = ('GET', 'POST')
+
+ def render_to_response(self, context, template_name=None):
+ """like a django's shortcut, except will use
+ template_name from self, if `template_name` is not given.
+ Also, response is packaged as json with an html fragment
+ for the pjax consumption
+ """
+ if template_name is None:
+ template_name = self.template_name
+ template = get_template(template_name)
+ html = template.render(context)
+ json = simplejson.dumps({'html': html, 'success': True})
+ return HttpResponse(json, mimetype='application/json')
+
+
+ def get(self, request, *args, **kwargs):
+ """view function for the "GET" method"""
+ context = self.get_context(request, *args, **kwargs)
+ return self.render_to_response(context)
+
+ def post(self, request, *args, **kwargs):
+ """view function for the "POST" method"""
+ pass
+
+ def dispatch(self, request, *args, **kwargs):
+ """checks that the current request method is allowed
+ and calls the corresponding view function"""
+ if request.method not in self.http_method_names:
+ return HttpResponseNotAllowed()
+ view_func = getattr(self, request.method.lower())
+ return view_func(request, *args, **kwargs)
+
+ def get_context(self, request, *args, **kwargs):
+ """Returns the context dictionary for the "get"
+ method only"""
+ return {}
+
+ def as_view(self):
+ """returns the view function - for the urls.py"""
+ def view_function(request, *args, **kwargs):
+ """the actual view function"""
+ if request.user.is_authenticated() and request.is_ajax():
+ view_method = getattr(self, request.method.lower())
+ return view_method(request, *args, **kwargs)
+ else:
+ return HttpResponseForbidden()
+
+ return view_function
+
+
+class NewThread(InboxView):
+ """view for creation of new thread"""
+ http_method_list = ('POST',)
+
+ def post(self, request):
+ """creates a new thread on behalf of the user
+ response is blank, because on the client side we just
+ need to go back to the thread listing view whose
+ content should be cached in the client'
+ """
+ usernames = request.POST['to_usernames']
+ usernames = map(lambda v: v.strip(), usernames.split(','))
+ users = User.objects.filter(username__in=usernames)
+
+ missing = copy.copy(usernames)
+ for user in users:
+ if user.username in missing:
+ missing.remove(user.username)
+
+ result = dict()
+ if missing:
+ result['success'] = False
+ result['missing_users'] = missing
+ else:
+ recipients = get_personal_groups_for_users(users)
+ message = Message.objects.create_thread(
+ sender=request.user,
+ recipients=recipients,
+ text=request.POST['text']
+ )
+ result['success'] = True
+ result['message_id'] = message.id
+ return HttpResponse(simplejson.dumps(result), mimetype='application/json')
+
+
+class PostReply(InboxView):
+ """view to create a new response"""
+ http_method_list = ('POST',)
+
+ def post(self, request):
+ parent_id = IntegerField().clean(request.POST['parent_id'])
+ parent = Message.objects.get(id=parent_id)
+ message = Message.objects.create_response(
+ sender=request.user,
+ text=request.POST['text'],
+ parent=parent
+ )
+ last_visit = LastVisitTime.objects.get(
+ message=message.root,
+ user=request.user
+ )
+ last_visit.at = datetime.datetime.now()
+ last_visit.save()
+ return self.render_to_response(
+ {'post': message, 'user': request.user},
+ template_name='group_messaging/stored_message.html'
+ )
+
+class ThreadsList(InboxView):
+ """shows list of threads for a given user"""
+ template_name = 'group_messaging/threads_list.html'
+ http_method_list = ('GET',)
+
+ def get_context(self, request):
+ """returns thread list data"""
+ #get threads and the last visit time
+ threads = Message.objects.get_threads_for_user(request.user)
+
+ sender_id = IntegerField().clean(request.GET.get('sender_id', '-1'))
+ if sender_id != -1:
+ threads = threads.filter(sender__id=sender_id)
+
+ #for each thread we need to know if there is something
+ #unread for the user - to mark "new" threads as bold
+ threads_data = dict()
+ for thread in threads:
+ thread_data = dict()
+ #determine status
+ thread_data['status'] = 'new'
+ #determine the senders info
+ senders_names = thread.senders_info.split(',')
+ if request.user.username in senders_names:
+ senders_names.remove(request.user.username)
+ thread_data['senders_info'] = ', '.join(senders_names)
+ thread_data['thread'] = thread
+ threads_data[thread.id] = thread_data
+
+ last_visit_times = LastVisitTime.objects.filter(
+ user=request.user,
+ message__in=threads
+ )
+ for last_visit in last_visit_times:
+ thread_data = threads_data[last_visit.message_id]
+ if thread_data['thread'].last_active_at <= last_visit.at:
+ thread_data['status'] = 'seen'
+
+ #after we have all the data - update the last visit time
+ last_visit_times.update(at=datetime.datetime.now())
+ return {'threads': threads, 'threads_data': threads_data}
+
+
+class SendersList(InboxView):
+ """shows list of senders for a user"""
+ template_name = 'group_messaging/senders_list.html'
+ http_method_names = ('GET',)
+
+ def get_context(self, request):
+ """get data about senders for the user"""
+ senders = SenderList.objects.get_senders_for_user(request.user)
+ senders = senders.values('id', 'username')
+ return {'senders': senders}
+
+
+class ThreadDetails(InboxView):
+ """shows entire thread in the unfolded form"""
+ template_name = 'group_messaging/thread_details.html'
+ http_method_names = ('GET',)
+
+ def get_context(self, request, thread_id=None):
+ """shows individual thread"""
+ #todo: assert that current thread is the root
+ root = Message.objects.get(id=thread_id)
+ responses = Message.objects.filter(root__id=thread_id)
+ last_visit, created = LastVisitTime.objects.get_or_create(
+ message=root,
+ user=request.user
+ )
+ if created is False:
+ last_visit.at = datetime.datetime.now()
+ last_visit.save()
+ return {'root_message': root, 'responses': responses, 'request': request}