aboutsummaryrefslogtreecommitdiffstats
path: root/phpBB
diff options
context:
space:
mode:
Diffstat (limited to 'phpBB')
-rw-r--r--phpBB/adm/style/acp_attachments.html4
-rw-r--r--phpBB/adm/style/acp_avatar_options_gravatar.html11
-rw-r--r--phpBB/adm/style/acp_avatar_options_local.html25
-rw-r--r--phpBB/adm/style/acp_avatar_options_remote.html11
-rw-r--r--phpBB/adm/style/acp_avatar_options_upload.html11
-rw-r--r--phpBB/adm/style/acp_captcha.html4
-rw-r--r--phpBB/adm/style/acp_forums.html8
-rw-r--r--phpBB/adm/style/acp_groups.html86
-rw-r--r--phpBB/adm/style/acp_groups_position.html98
-rw-r--r--phpBB/adm/style/acp_icons.html8
-rw-r--r--phpBB/adm/style/acp_inactive.html2
-rw-r--r--phpBB/adm/style/acp_jabber.html4
-rw-r--r--phpBB/adm/style/acp_prune_forums.html4
-rw-r--r--phpBB/adm/style/acp_prune_users.html4
-rw-r--r--phpBB/adm/style/acp_ranks.html2
-rw-r--r--phpBB/adm/style/acp_search.html10
-rw-r--r--phpBB/adm/style/acp_users_avatar.html93
-rw-r--r--phpBB/adm/style/acp_users_overview.html2
-rw-r--r--phpBB/adm/style/acp_users_profile.html10
-rw-r--r--phpBB/adm/style/admin.css21
-rw-r--r--phpBB/adm/style/ajax.js10
-rw-r--r--phpBB/adm/style/avatars.js15
-rw-r--r--phpBB/adm/style/captcha_gd_acp.html4
-rw-r--r--phpBB/adm/style/confirm_body.html14
-rw-r--r--phpBB/adm/style/editor.js217
-rw-r--r--phpBB/adm/style/overall_footer.html6
-rw-r--r--phpBB/adm/style/permissions.js185
-rw-r--r--phpBB/adm/style/timezone.js2
-rw-r--r--phpBB/adm/style/tooltip.js102
-rw-r--r--phpBB/assets/javascript/core.js168
-rw-r--r--phpBB/assets/javascript/jquery.js20
-rw-r--r--phpBB/common.php12
-rw-r--r--phpBB/composer.json4
-rw-r--r--phpBB/composer.lock747
-rw-r--r--phpBB/config/avatars.yml55
-rw-r--r--phpBB/config/services.yml61
-rw-r--r--phpBB/config/tables.yml6
-rw-r--r--phpBB/develop/create_schema_files.php40
-rw-r--r--phpBB/docs/coding-guidelines.html4
-rw-r--r--phpBB/docs/events.md9
-rw-r--r--phpBB/docs/sphinx.sample.conf103
-rw-r--r--phpBB/download/file.php7
-rw-r--r--phpBB/includes/acp/acp_attachments.php19
-rw-r--r--phpBB/includes/acp/acp_board.php141
-rw-r--r--phpBB/includes/acp/acp_extensions.php40
-rw-r--r--phpBB/includes/acp/acp_groups.php472
-rw-r--r--phpBB/includes/acp/acp_inactive.php5
-rw-r--r--phpBB/includes/acp/acp_modules.php73
-rw-r--r--phpBB/includes/acp/acp_prune.php40
-rw-r--r--phpBB/includes/acp/acp_styles.php21
-rw-r--r--phpBB/includes/acp/acp_update.php2
-rw-r--r--phpBB/includes/acp/acp_users.php154
-rw-r--r--phpBB/includes/auth/auth_ldap.php2
-rw-r--r--phpBB/includes/avatar/driver/driver.php138
-rw-r--r--phpBB/includes/avatar/driver/gravatar.php172
-rw-r--r--phpBB/includes/avatar/driver/interface.php116
-rw-r--r--phpBB/includes/avatar/driver/local.php197
-rw-r--r--phpBB/includes/avatar/driver/remote.php164
-rw-r--r--phpBB/includes/avatar/driver/upload.php159
-rw-r--r--phpBB/includes/avatar/manager.php309
-rw-r--r--phpBB/includes/bbcode.php2
-rw-r--r--phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php2
-rw-r--r--phpBB/includes/class_loader.php8
-rw-r--r--phpBB/includes/config/db_text.php163
-rw-r--r--phpBB/includes/constants.php1
-rw-r--r--phpBB/includes/controller/helper.php38
-rw-r--r--phpBB/includes/db/driver/driver.php4
-rw-r--r--phpBB/includes/db/driver/mssql_base.php65
-rw-r--r--phpBB/includes/db/driver/mssql_odbc.php44
-rw-r--r--phpBB/includes/db/driver/mssqlnative.php44
-rw-r--r--phpBB/includes/db/driver/mysql.php124
-rw-r--r--phpBB/includes/db/driver/mysql_base.php145
-rw-r--r--phpBB/includes/db/driver/mysqli.php125
-rw-r--r--phpBB/includes/db/migration/data/310/avatars.php67
-rw-r--r--phpBB/includes/db/migration/data/310/boardindex.php23
-rw-r--r--phpBB/includes/db/migration/data/310/config_db_text.php45
-rw-r--r--phpBB/includes/db/migration/data/310/forgot_password.php28
-rw-r--r--phpBB/includes/db/migration/data/310/jquery_update.php31
-rw-r--r--phpBB/includes/db/migration/data/310/notifications_schema_fix.php92
-rw-r--r--phpBB/includes/db/migration/data/310/style_update_p1.php28
-rw-r--r--phpBB/includes/db/migration/data/310/teampage.php104
-rw-r--r--phpBB/includes/db/migration/tool/config.php4
-rw-r--r--phpBB/includes/db/migration/tool/module.php8
-rw-r--r--phpBB/includes/db/migration/tool/permission.php8
-rw-r--r--phpBB/includes/db/migrator.php217
-rw-r--r--phpBB/includes/db/sql_insert_buffer.php150
-rw-r--r--phpBB/includes/extension/base.php71
-rw-r--r--phpBB/includes/extension/finder.php102
-rw-r--r--phpBB/includes/extension/manager.php101
-rw-r--r--phpBB/includes/extension/metadata_manager.php57
-rw-r--r--phpBB/includes/filesystem.php52
-rw-r--r--phpBB/includes/functions.php127
-rw-r--r--phpBB/includes/functions_acp.php38
-rw-r--r--phpBB/includes/functions_admin.php324
-rw-r--r--phpBB/includes/functions_compatibility.php50
-rw-r--r--phpBB/includes/functions_container.php1
-rw-r--r--phpBB/includes/functions_display.php118
-rw-r--r--phpBB/includes/functions_download.php2
-rw-r--r--phpBB/includes/functions_messenger.php20
-rw-r--r--phpBB/includes/functions_profile_fields.php18
-rw-r--r--phpBB/includes/functions_url_matcher.php6
-rw-r--r--phpBB/includes/functions_user.php650
-rw-r--r--phpBB/includes/groupposition/exception.php23
-rw-r--r--phpBB/includes/groupposition/interface.php84
-rw-r--r--phpBB/includes/groupposition/legend.php (renamed from phpBB/includes/group_positions.php)134
-rw-r--r--phpBB/includes/groupposition/teampage.php604
-rw-r--r--phpBB/includes/hook/finder.php2
-rw-r--r--phpBB/includes/lock/db.php11
-rw-r--r--phpBB/includes/lock/flock.php11
-rw-r--r--phpBB/includes/log/interface.php106
-rw-r--r--phpBB/includes/log/log.php739
-rw-r--r--phpBB/includes/mcp/mcp_notes.php4
-rw-r--r--phpBB/includes/mcp/mcp_warn.php8
-rw-r--r--phpBB/includes/notification/exception.php29
-rw-r--r--phpBB/includes/notification/manager.php253
-rw-r--r--phpBB/includes/notification/method/base.php2
-rw-r--r--phpBB/includes/notification/method/email.php83
-rw-r--r--phpBB/includes/notification/method/jabber.php28
-rw-r--r--phpBB/includes/notification/method/messenger_base.php100
-rw-r--r--phpBB/includes/notification/type/base.php22
-rw-r--r--phpBB/includes/notification/type/bookmark.php9
-rw-r--r--phpBB/includes/notification/type/post.php25
-rw-r--r--phpBB/includes/notification/type/post_in_queue.php27
-rw-r--r--phpBB/includes/notification/type/quote.php23
-rw-r--r--phpBB/includes/notification/type/topic.php2
-rw-r--r--phpBB/includes/notification/type/topic_in_queue.php34
-rw-r--r--phpBB/includes/search/fulltext_native.php4
-rw-r--r--phpBB/includes/search/fulltext_postgres.php6
-rw-r--r--phpBB/includes/search/fulltext_sphinx.php10
-rw-r--r--phpBB/includes/search/sphinx/config_variable.php2
-rw-r--r--phpBB/includes/style/extension_path_provider.php20
-rw-r--r--phpBB/includes/template/compile.php39
-rw-r--r--phpBB/includes/template/filter.php92
-rw-r--r--phpBB/includes/tree/interface.php122
-rw-r--r--phpBB/includes/tree/nestedset.php850
-rw-r--r--phpBB/includes/tree/nestedset_forum.php46
-rw-r--r--phpBB/includes/ucp/info/ucp_profile.php2
-rw-r--r--phpBB/includes/ucp/ucp_activate.php2
-rw-r--r--phpBB/includes/ucp/ucp_groups.php174
-rw-r--r--phpBB/includes/ucp/ucp_notifications.php4
-rw-r--r--phpBB/includes/ucp/ucp_pm_compose.php11
-rw-r--r--phpBB/includes/ucp/ucp_pm_viewmessage.php7
-rw-r--r--phpBB/includes/ucp/ucp_profile.php161
-rw-r--r--phpBB/includes/ucp/ucp_register.php4
-rw-r--r--phpBB/includes/ucp/ucp_remind.php8
-rw-r--r--phpBB/includes/ucp/ucp_resend.php5
-rw-r--r--phpBB/includes/user.php2
-rw-r--r--phpBB/includes/user_loader.php4
-rw-r--r--phpBB/install/database_update.php60
-rw-r--r--phpBB/install/index.php20
-rw-r--r--phpBB/install/install_convert.php2
-rw-r--r--phpBB/install/install_install.php24
-rw-r--r--phpBB/install/install_update.php8
-rw-r--r--phpBB/install/schemas/firebird_schema.sql60
-rw-r--r--phpBB/install/schemas/mssql_schema.sql57
-rw-r--r--phpBB/install/schemas/mysql_40_schema.sql36
-rw-r--r--phpBB/install/schemas/mysql_41_schema.sql36
-rw-r--r--phpBB/install/schemas/oracle_schema.sql74
-rw-r--r--phpBB/install/schemas/postgres_schema.sql42
-rw-r--r--phpBB/install/schemas/schema_data.sql31
-rw-r--r--phpBB/install/schemas/sqlite_schema.sql36
-rw-r--r--phpBB/language/en/acp/board.php5
-rw-r--r--phpBB/language/en/acp/groups.php3
-rw-r--r--phpBB/language/en/acp/prune.php2
-rw-r--r--phpBB/language/en/captcha_recaptcha.php1
-rw-r--r--phpBB/language/en/common.php10
-rw-r--r--phpBB/language/en/email/post_approved.txt1
-rw-r--r--phpBB/language/en/email/post_disapproved.txt1
-rw-r--r--phpBB/language/en/email/post_in_queue.txt6
-rw-r--r--phpBB/language/en/email/report_closed.txt3
-rw-r--r--phpBB/language/en/email/report_deleted.txt3
-rw-r--r--phpBB/language/en/email/report_pm.txt6
-rw-r--r--phpBB/language/en/email/report_post.txt6
-rw-r--r--phpBB/language/en/email/short/post_approved.txt1
-rw-r--r--phpBB/language/en/email/short/post_disapproved.txt1
-rw-r--r--phpBB/language/en/email/short/post_in_queue.txt6
-rw-r--r--phpBB/language/en/email/short/report_pm.txt6
-rw-r--r--phpBB/language/en/email/short/report_post.txt6
-rw-r--r--phpBB/language/en/email/short/topic_approved.txt1
-rw-r--r--phpBB/language/en/email/short/topic_disapproved.txt1
-rw-r--r--phpBB/language/en/email/short/topic_in_queue.txt6
-rw-r--r--phpBB/language/en/email/topic_approved.txt1
-rw-r--r--phpBB/language/en/email/topic_disapproved.txt1
-rw-r--r--phpBB/language/en/email/topic_in_queue.txt6
-rw-r--r--phpBB/language/en/email/user_reactivate_account.txt1
-rw-r--r--phpBB/language/en/email/user_resend_inactive.txt1
-rw-r--r--phpBB/language/en/mcp.php2
-rw-r--r--phpBB/language/en/migrator.php7
-rw-r--r--phpBB/language/en/posting.php4
-rw-r--r--phpBB/language/en/ucp.php16
-rw-r--r--phpBB/mcp.php2
-rw-r--r--phpBB/memberlist.php58
-rw-r--r--phpBB/posting.php1
-rw-r--r--phpBB/styles/prosilver/template/ajax.js15
-rw-r--r--phpBB/styles/prosilver/template/avatars.js15
-rw-r--r--phpBB/styles/prosilver/template/confirm_body.html18
-rw-r--r--phpBB/styles/prosilver/template/custom_profile_fields.html6
-rw-r--r--phpBB/styles/prosilver/template/editor.js392
-rw-r--r--phpBB/styles/prosilver/template/forum_fn.js314
-rw-r--r--phpBB/styles/prosilver/template/forumlist_body.html30
-rw-r--r--phpBB/styles/prosilver/template/login_forum.html45
-rw-r--r--phpBB/styles/prosilver/template/mcp_approve.html28
-rw-r--r--phpBB/styles/prosilver/template/mcp_forum.html13
-rw-r--r--phpBB/styles/prosilver/template/mcp_front.html40
-rw-r--r--phpBB/styles/prosilver/template/mcp_logs.html2
-rw-r--r--phpBB/styles/prosilver/template/mcp_move.html32
-rw-r--r--phpBB/styles/prosilver/template/mcp_notes_user.html2
-rw-r--r--phpBB/styles/prosilver/template/mcp_queue.html12
-rw-r--r--phpBB/styles/prosilver/template/mcp_reports.html20
-rw-r--r--phpBB/styles/prosilver/template/mcp_topic.html8
-rw-r--r--phpBB/styles/prosilver/template/memberlist_email.html2
-rw-r--r--phpBB/styles/prosilver/template/memberlist_search.html2
-rw-r--r--phpBB/styles/prosilver/template/overall_footer.html9
-rw-r--r--phpBB/styles/prosilver/template/overall_header.html16
-rw-r--r--phpBB/styles/prosilver/template/posting_buttons.html39
-rw-r--r--phpBB/styles/prosilver/template/posting_editor.html8
-rw-r--r--phpBB/styles/prosilver/template/posting_poll_body.html6
-rw-r--r--phpBB/styles/prosilver/template/search_body.html4
-rw-r--r--phpBB/styles/prosilver/template/search_results.html46
-rw-r--r--phpBB/styles/prosilver/template/simple_footer.html1
-rw-r--r--phpBB/styles/prosilver/template/simple_header.html1
-rw-r--r--phpBB/styles/prosilver/template/timezone.js4
-rw-r--r--phpBB/styles/prosilver/template/timezone_option.html2
-rw-r--r--phpBB/styles/prosilver/template/ucp_attachments.html10
-rw-r--r--phpBB/styles/prosilver/template/ucp_avatar_options.html86
-rw-r--r--phpBB/styles/prosilver/template/ucp_avatar_options_gravatar.html25
-rw-r--r--phpBB/styles/prosilver/template/ucp_avatar_options_local.html20
-rw-r--r--phpBB/styles/prosilver/template/ucp_avatar_options_remote.html25
-rw-r--r--phpBB/styles/prosilver/template/ucp_avatar_options_upload.html11
-rw-r--r--phpBB/styles/prosilver/template/ucp_groups_manage.html37
-rw-r--r--phpBB/styles/prosilver/template/ucp_groups_membership.html62
-rw-r--r--phpBB/styles/prosilver/template/ucp_main_bookmarks.html49
-rw-r--r--phpBB/styles/prosilver/template/ucp_main_drafts.html18
-rw-r--r--phpBB/styles/prosilver/template/ucp_main_front.html34
-rwxr-xr-x[-rw-r--r--]phpBB/styles/prosilver/template/ucp_main_subscribed.html73
-rw-r--r--phpBB/styles/prosilver/template/ucp_notifications.html103
-rw-r--r--phpBB/styles/prosilver/template/ucp_pm_history.html2
-rw-r--r--phpBB/styles/prosilver/template/ucp_pm_viewfolder.html9
-rw-r--r--phpBB/styles/prosilver/template/ucp_profile_avatar.html10
-rw-r--r--phpBB/styles/prosilver/template/ucp_profile_profile_info.html12
-rw-r--r--phpBB/styles/prosilver/template/ucp_profile_reg_details.html2
-rw-r--r--phpBB/styles/prosilver/template/ucp_register.html7
-rw-r--r--phpBB/styles/prosilver/template/ucp_remind.html2
-rw-r--r--phpBB/styles/prosilver/template/ucp_resend.html2
-rw-r--r--phpBB/styles/prosilver/template/viewforum_body.html43
-rw-r--r--phpBB/styles/prosilver/template/viewtopic_body.html3
-rw-r--r--phpBB/styles/prosilver/theme/bidi.css58
-rw-r--r--phpBB/styles/prosilver/theme/buttons.css13
-rw-r--r--phpBB/styles/prosilver/theme/colours.css22
-rw-r--r--phpBB/styles/prosilver/theme/common.css22
-rw-r--r--phpBB/styles/prosilver/theme/content.css127
-rw-r--r--phpBB/styles/prosilver/theme/forms.css9
-rw-r--r--phpBB/styles/prosilver/theme/tweaks.css19
-rw-r--r--phpBB/styles/subsilver2/template/avatars.js15
-rw-r--r--phpBB/styles/subsilver2/template/confirm_body.html2
-rw-r--r--phpBB/styles/subsilver2/template/custom_profile_fields.html2
-rw-r--r--phpBB/styles/subsilver2/template/editor.js264
-rw-r--r--phpBB/styles/subsilver2/template/login_forum.html8
-rw-r--r--phpBB/styles/subsilver2/template/mcp_jumpbox.html19
-rw-r--r--phpBB/styles/subsilver2/template/mcp_topic.html4
-rw-r--r--phpBB/styles/subsilver2/template/memberlist_email.html2
-rw-r--r--phpBB/styles/subsilver2/template/memberlist_search.html8
-rw-r--r--phpBB/styles/subsilver2/template/posting_body.html2
-rw-r--r--phpBB/styles/subsilver2/template/posting_poll_body.html4
-rw-r--r--phpBB/styles/subsilver2/template/timezone.js4
-rw-r--r--phpBB/styles/subsilver2/template/timezone_option.html2
-rw-r--r--phpBB/styles/subsilver2/template/ucp_avatar_options_gravatar.html13
-rw-r--r--phpBB/styles/subsilver2/template/ucp_avatar_options_local.html39
-rw-r--r--phpBB/styles/subsilver2/template/ucp_avatar_options_remote.html10
-rw-r--r--phpBB/styles/subsilver2/template/ucp_avatar_options_upload.html12
-rw-r--r--phpBB/styles/subsilver2/template/ucp_groups_manage.html91
-rw-r--r--phpBB/styles/subsilver2/template/ucp_notifications.html238
-rw-r--r--phpBB/styles/subsilver2/template/ucp_pm_history.html2
-rw-r--r--phpBB/styles/subsilver2/template/ucp_profile_avatar.html82
-rw-r--r--phpBB/styles/subsilver2/template/ucp_profile_profile_info.html30
-rw-r--r--phpBB/styles/subsilver2/template/ucp_profile_reg_details.html2
-rw-r--r--phpBB/styles/subsilver2/template/ucp_register.html2
-rw-r--r--phpBB/styles/subsilver2/template/ucp_remind.html2
-rw-r--r--phpBB/styles/subsilver2/template/ucp_resend.html2
-rw-r--r--phpBB/styles/subsilver2/template/viewtopic_body.html1
-rw-r--r--phpBB/viewtopic.php4
281 files changed, 10417 insertions, 4835 deletions
diff --git a/phpBB/adm/style/acp_attachments.html b/phpBB/adm/style/acp_attachments.html
index 266b7e48b4..c7b451e68b 100644
--- a/phpBB/adm/style/acp_attachments.html
+++ b/phpBB/adm/style/acp_attachments.html
@@ -196,7 +196,7 @@
</dl>
<dl>
<dt><label for="extgroup_filesize">{L_MAX_EXTGROUP_FILESIZE}{L_COLON}</label></dt>
- <dd><input type="text" id="extgroup_filesize" size="3" maxlength="15" name="max_filesize" value="{EXTGROUP_FILESIZE}" /> <select name="size_select">{S_EXT_GROUP_SIZE_OPTIONS}</select></dd>
+ <dd><input type="number" id="extgroup_filesize" size="3" maxlength="15" name="max_filesize" value="{EXTGROUP_FILESIZE}" /> <select name="size_select">{S_EXT_GROUP_SIZE_OPTIONS}</select></dd>
</dl>
<dl>
<dt><label for="assigned_extensions">{L_ASSIGNED_EXTENSIONS}{L_COLON}</label></dt>
@@ -348,7 +348,7 @@
<td><a href="{orphan.U_FILE}">{orphan.REAL_FILENAME}</a></td>
<td>{orphan.FILETIME}</td>
<td>{orphan.FILESIZE}</td>
- <td><strong>{L_ATTACH_ID}{L_COLON} </strong><input type="text" name="post_id[{orphan.ATTACH_ID}]" size="7" maxlength="10" value="{orphan.POST_ID}" /></td>
+ <td><strong>{L_ATTACH_ID}{L_COLON} </strong><input type="number" name="post_id[{orphan.ATTACH_ID}]" size="7" maxlength="10" value="{orphan.POST_ID}" /></td>
<td><input type="checkbox" class="radio" name="add[{orphan.ATTACH_ID}]" /></td>
<td><input type="checkbox" class="radio" name="delete[{orphan.ATTACH_ID}]" /></td>
</tr>
diff --git a/phpBB/adm/style/acp_avatar_options_gravatar.html b/phpBB/adm/style/acp_avatar_options_gravatar.html
new file mode 100644
index 0000000000..0c2e8cc984
--- /dev/null
+++ b/phpBB/adm/style/acp_avatar_options_gravatar.html
@@ -0,0 +1,11 @@
+<dl>
+ <dt><label for="avatar_gravatar_email">{L_GRAVATAR_AVATAR_EMAIL}{L_COLON}</label><br /><span>{L_GRAVATAR_AVATAR_EMAIL_EXPLAIN}</span></dt>
+ <dd><input type="email" name="avatar_gravatar_email" id="avatar_gravatar_email" value="{AVATAR_GRAVATAR_EMAIL}" class="inputbox" /></dd>
+</dl>
+<dl>
+ <dt><label for="avatar_gravatar_width">{L_GRAVATAR_AVATAR_SIZE}{L_COLON}</label><br /><span>{L_GRAVATAR_AVATAR_SIZE_EXPLAIN}</span></dt>
+ <dd>
+ <input type="number" name="avatar_gravatar_width" id="avatar_gravatar_width" size="3" value="{AVATAR_GRAVATAR_WIDTH}" class="inputbox autowidth" /> {L_PIXEL} &times;&nbsp;
+ <input type="number" name="avatar_gravatar_height" id="avatar_gravatar_height" size="3" value="{AVATAR_GRAVATAR_HEIGHT}" class="inputbox autowidth" /> {L_PIXEL}
+ </dd>
+</dl>
diff --git a/phpBB/adm/style/acp_avatar_options_local.html b/phpBB/adm/style/acp_avatar_options_local.html
new file mode 100644
index 0000000000..148efd051b
--- /dev/null
+++ b/phpBB/adm/style/acp_avatar_options_local.html
@@ -0,0 +1,25 @@
+<dl>
+ <dt><label for="category">{L_AVATAR_CATEGORY}{L_COLON}</label></dt>
+ <dd><select name="avatar_local_cat" id="category">
+ <option value="">{L_NO_AVATAR_CATEGORY}</option>
+ <!-- BEGIN avatar_local_cats -->
+ <option value="{avatar_local_cats.NAME}"<!-- IF avatar_local_cats.SELECTED --> selected="selected"<!-- ENDIF -->>{avatar_local_cats.NAME}</option>
+ <!-- END avatar_local_cats -->
+ </select>&nbsp;<input type="submit" value="{L_GO}" name="avatar_local_go" class="button2" /></dd>
+</dl>
+ <!-- IF AVATAR_LOCAL_SHOW -->
+ <table>
+ <!-- BEGIN avatar_local_row -->
+ <tr>
+ <!-- BEGIN avatar_local_col -->
+ <td class="row1" style="text-align: center;"><img src="{avatar_local_row.avatar_local_col.AVATAR_IMAGE}" alt="{avatar_local_row.avatar_local_col.AVATAR_NAME}" title="{avatar_local_row.avatar_local_col.AVATAR_NAME}"/></td>
+ <!-- END avatar_local_col -->
+ </tr>
+ <tr>
+ <!-- BEGIN avatar_local_option -->
+ <td class="row2" style="text-align: center;"><input type="radio" name="avatar_local_file" id="av-{avatar_local_row.S_ROW_COUNT}-{avatar_local_row.avatar_local_option.S_ROW_COUNT}" value="{avatar_local_row.avatar_local_option.AVATAR_FILE}" /></td>
+ <!-- END avatar_local_option -->
+ </tr>
+ <!-- END avatar_local_row -->
+ </table>
+ <!-- ENDIF -->
diff --git a/phpBB/adm/style/acp_avatar_options_remote.html b/phpBB/adm/style/acp_avatar_options_remote.html
new file mode 100644
index 0000000000..1c0e3db599
--- /dev/null
+++ b/phpBB/adm/style/acp_avatar_options_remote.html
@@ -0,0 +1,11 @@
+<dl>
+ <dt><label for="avatar_remote_url">{L_LINK_REMOTE_AVATAR}{L_COLON}</label><br /><span>{L_LINK_REMOTE_AVATAR_EXPLAIN}</span></dt>
+ <dd><input type="url" name="avatar_remote_url" id="avatar_remote_url" value="{AVATAR_REMOTE_URL}" class="inputbox" /></dd>
+</dl>
+<dl>
+ <dt><label for="avatar_remote_width">{L_LINK_REMOTE_SIZE}{L_COLON}</label><br /><span>{L_LINK_REMOTE_SIZE_EXPLAIN}</span></dt>
+ <dd>
+ <input type="number" name="avatar_remote_width" id="avatar_remote_width" size="3" value="{AVATAR_REMOTE_WIDTH}" class="inputbox autowidth" /> {L_PIXEL} &times;&nbsp;
+ <input type="number" name="avatar_remote_height" id="avatar_remote_height" size="3" value="{AVATAR_REMOTE_HEIGHT}" class="inputbox autowidth" /> {L_PIXEL}
+ </dd>
+</dl>
diff --git a/phpBB/adm/style/acp_avatar_options_upload.html b/phpBB/adm/style/acp_avatar_options_upload.html
new file mode 100644
index 0000000000..63a734ea7d
--- /dev/null
+++ b/phpBB/adm/style/acp_avatar_options_upload.html
@@ -0,0 +1,11 @@
+<dl>
+ <dt><label for="avatar_upload_file">{L_UPLOAD_AVATAR_FILE}{L_COLON}</label></dt>
+ <dd><input type="hidden" name="MAX_FILE_SIZE" value="{AVATAR_UPLOAD_SIZE}" /><input type="file" name="avatar_upload_file" id="avatar_upload_file" class="inputbox autowidth" /></dd>
+</dl>
+
+<!-- IF S_UPLOAD_AVATAR_URL -->
+ <dl>
+ <dt><label for="avatar_upload_url">{L_UPLOAD_AVATAR_URL}{L_COLON}</label><br /><span>{L_UPLOAD_AVATAR_URL_EXPLAIN}</span></dt>
+ <dd><input type="url" name="avatar_upload_url" id="avatar_upload_url" value="" class="inputbox" /></dd>
+ </dl>
+<!-- ENDIF -->
diff --git a/phpBB/adm/style/acp_captcha.html b/phpBB/adm/style/acp_captcha.html
index ab5e207e0d..df4c675209 100644
--- a/phpBB/adm/style/acp_captcha.html
+++ b/phpBB/adm/style/acp_captcha.html
@@ -19,11 +19,11 @@
</dl>
<dl>
<dt><label for="max_reg_attempts">{L_REG_LIMIT}{L_COLON}</label><br /><span>{L_REG_LIMIT_EXPLAIN}</span></dt>
- <dd><input id="max_reg_attempts" type="text" size="4" maxlength="4" name="max_reg_attempts" value="{REG_LIMIT}" /></dd>
+ <dd><input id="max_reg_attempts" type="number" size="4" maxlength="4" min="0" max="9999" name="max_reg_attempts" value="{REG_LIMIT}" /></dd>
</dl>
<dl>
<dt><label for="max_login_attempts">{L_MAX_LOGIN_ATTEMPTS}{L_COLON}</label><br /><span>{L_MAX_LOGIN_ATTEMPTS_EXPLAIN}</span></dt>
- <dd><input id="max_login_attempts" type="text" size="4" maxlength="4" name="max_login_attempts" value="{MAX_LOGIN_ATTEMPTS}" /></dd>
+ <dd><input id="max_login_attempts" type="number" size="4" maxlength="4" min="0" max="9999" name="max_login_attempts" value="{MAX_LOGIN_ATTEMPTS}" /></dd>
</dl>
<dl>
<dt><label for="enable_post_confirm">{L_VISUAL_CONFIRM_POST}{L_COLON}</label><br /><span>{L_VISUAL_CONFIRM_POST_EXPLAIN}</span></dt>
diff --git a/phpBB/adm/style/acp_forums.html b/phpBB/adm/style/acp_forums.html
index d6c06bf6d8..c3772a22e3 100644
--- a/phpBB/adm/style/acp_forums.html
+++ b/phpBB/adm/style/acp_forums.html
@@ -239,7 +239,7 @@
</dl>
<dl>
<dt><label for="topics_per_page">{L_FORUM_TOPICS_PAGE}{L_COLON}</label><br /><span>{L_FORUM_TOPICS_PAGE_EXPLAIN}</span></dt>
- <dd><input type="text" id="topics_per_page" name="topics_per_page" value="{TOPICS_PER_PAGE}" size="4" maxlength="4" /></dd>
+ <dd><input type="number" id="topics_per_page" name="topics_per_page" value="{TOPICS_PER_PAGE}" size="4" maxlength="4" min="0" max="9999" /></dd>
</dl>
<!-- EVENT acp_forums_normal_settings_append -->
</fieldset>
@@ -253,15 +253,15 @@
</dl>
<dl>
<dt><label for="prune_freq">{L_AUTO_PRUNE_FREQ}{L_COLON}</label><br /><span>{L_AUTO_PRUNE_FREQ_EXPLAIN}</span></dt>
- <dd><input type="text" id="prune_freq" name="prune_freq" value="{PRUNE_FREQ}" maxlength="4" size="4" /> {L_DAYS}</dd>
+ <dd><input type="number" id="prune_freq" name="prune_freq" value="{PRUNE_FREQ}" maxlength="4" size="4" min="0" max="9999" /> {L_DAYS}</dd>
</dl>
<dl>
<dt><label for="prune_days">{L_AUTO_PRUNE_DAYS}{L_COLON}</label><br /><span>{L_AUTO_PRUNE_DAYS_EXPLAIN}</span></dt>
- <dd><input type="text" id="prune_days" name="prune_days" value="{PRUNE_DAYS}" maxlength="4" size="4" /> {L_DAYS}</dd>
+ <dd><input type="number" id="prune_days" name="prune_days" value="{PRUNE_DAYS}" maxlength="4" size="4" min="0" max="9999" /> {L_DAYS}</dd>
</dl>
<dl>
<dt><label for="prune_viewed">{L_AUTO_PRUNE_VIEWED}{L_COLON}</label><br /><span>{L_AUTO_PRUNE_VIEWED_EXPLAIN}</span></dt>
- <dd><input type="text" id="prune_viewed" name="prune_viewed" value="{PRUNE_VIEWED}" maxlength="4" size="4" /> {L_DAYS}</dd>
+ <dd><input type="number" id="prune_viewed" name="prune_viewed" value="{PRUNE_VIEWED}" maxlength="4" size="4" min="0" max="9999" /> {L_DAYS}</dd>
</dl>
<dl>
<dt><label for="prune_old_polls">{L_PRUNE_OLD_POLLS}{L_COLON}</label><br /><span>{L_PRUNE_OLD_POLLS_EXPLAIN}</span></dt>
diff --git a/phpBB/adm/style/acp_groups.html b/phpBB/adm/style/acp_groups.html
index 4701bf702f..2953e85bd9 100644
--- a/phpBB/adm/style/acp_groups.html
+++ b/phpBB/adm/style/acp_groups.html
@@ -17,7 +17,7 @@
</div>
<!-- ENDIF -->
- <form id="settings" method="post" action="{U_ACTION}"<!-- IF S_CAN_UPLOAD --> enctype="multipart/form-data"<!-- ENDIF -->>
+ <form id="settings" method="post" action="{U_ACTION}" enctype="multipart/form-data">
<fieldset>
<legend>{L_GROUP_DETAILS}</legend>
@@ -84,11 +84,11 @@
<legend>{L_GROUP_SETTINGS_SAVE}</legend>
<dl>
<dt><label for="group_message_limit">{L_GROUP_MESSAGE_LIMIT}{L_COLON}</label><br /><span>{L_GROUP_MESSAGE_LIMIT_EXPLAIN}</span></dt>
- <dd><input name="group_message_limit" type="text" id="group_message_limit" maxlength="4" size="4" value="{GROUP_MESSAGE_LIMIT}" /></dd>
+ <dd><input name="group_message_limit" type="number" id="group_message_limit" maxlength="4" size="4" min="0" max="9999" value="{GROUP_MESSAGE_LIMIT}" /></dd>
</dl>
<dl>
<dt><label for="group_max_recipients">{L_GROUP_MAX_RECIPIENTS}{L_COLON}</label><br /><span>{L_GROUP_MAX_RECIPIENTS_EXPLAIN}</span></dt>
- <dd><input name="group_max_recipients" type="text" id="group_max_recipients" maxlength="10" size="4" value="{GROUP_MAX_RECIPIENTS}" /></dd>
+ <dd><input name="group_max_recipients" type="number" id="group_max_recipients" maxlength="10" size="4" value="{GROUP_MAX_RECIPIENTS}" /></dd>
</dl>
<dl>
<dt><label for="group_colour">{L_GROUP_COLOR}{L_COLON}</label><br /><span>{L_GROUP_COLOR_EXPLAIN}</span></dt>
@@ -104,66 +104,26 @@
<legend>{L_GROUP_AVATAR}</legend>
<dl>
<dt><label>{L_CURRENT_IMAGE}{L_COLON}</label><br /><span>{L_AVATAR_EXPLAIN}</span></dt>
- <dd>{AVATAR_IMAGE}</dd>
- <dd><label><input type="checkbox" class="radio" name="delete" /> {L_DELETE_AVATAR}</label></dd>
+ <dd>{AVATAR}</dd>
+ <dd><label for="avatar_delete"><input type="checkbox" name="avatar_delete" id="avatar_delete" /> {L_DELETE_AVATAR}</label></dd>
</dl>
- <!-- IF not S_IN_AVATAR_GALLERY -->
- <!-- IF S_CAN_UPLOAD -->
- <dl>
- <dt><label for="uploadfile">{L_UPLOAD_AVATAR_FILE}{L_COLON}</label></dt>
- <dd><input type="file" id="uploadfile" name="uploadfile" /></dd>
- </dl>
- <dl>
- <dt><label for="uploadurl">{L_UPLOAD_AVATAR_URL}{L_COLON}</label><br /><span>{L_UPLOAD_AVATAR_URL_EXPLAIN}</span></dt>
- <dd><input name="uploadurl" type="text" id="uploadurl" value="" /></dd>
- </dl>
- <!-- ENDIF -->
- <dl>
- <dt><label for="remotelink">{L_LINK_REMOTE_AVATAR}{L_COLON}</label><br /><span>{L_LINK_REMOTE_AVATAR_EXPLAIN}</span></dt>
- <dd><input name="remotelink" type="text" id="remotelink" value="" /></dd>
- </dl>
- <dl>
- <dt><label for="width">{L_LINK_REMOTE_SIZE}{L_COLON}</label><br /><span>{L_LINK_REMOTE_SIZE_EXPLAIN}</span></dt>
- <dd><input name="width" type="text" id="width" size="3" value="{AVATAR_WIDTH}" /> <span>{L_PIXEL} &times; </span> <input type="text" name="height" size="3" value="{AVATAR_HEIGHT}" /> <span>{L_PIXEL}</span></dd>
- </dl>
- <!-- IF S_DISPLAY_GALLERY -->
- <dl>
- <dt><label>{L_AVATAR_GALLERY}{L_COLON}</label></dt>
- <dd><input class="button2" type="submit" name="display_gallery" value="{L_DISPLAY_GALLERY}" /></dd>
- </dl>
- <!-- ENDIF -->
- <!-- ELSE -->
- </fieldset>
-
- <fieldset>
- <legend>{L_AVATAR_GALLERY}</legend>
- <dl>
- <dt><label for="category">{L_AVATAR_CATEGORY}{L_COLON}</label></dt>
- <dd><select name="category" id="category">{S_CAT_OPTIONS}</select>&nbsp;<input class="button2" type="submit" value="{L_GO}" name="display_gallery" /></dd>
- </dl>
- <dl>
- <table cellspacing="1">
- <!-- BEGIN avatar_row -->
- <tr>
- <!-- BEGIN avatar_column -->
- <td class="row1" style="text-align: center;"><img src="{avatar_row.avatar_column.AVATAR_IMAGE}" alt="{avatar_row.avatar_column.AVATAR_NAME}" title="{avatar_row.avatar_column.AVATAR_NAME}" /></td>
- <!-- END avatar_column -->
- </tr>
- <tr>
- <!-- BEGIN avatar_option_column -->
- <td class="row2" style="text-align: center;"><input type="radio" class="radio" name="avatar_select" value="{avatar_row.avatar_option_column.S_OPTIONS_AVATAR}" /></td>
- <!-- END avatar_option_column -->
- </tr>
- <!-- END avatar_row -->
- </table>
- </dl>
- </fieldset>
-
- <fieldset class="quick" style="margin-top: -15px;">
- <input class="button2" type="submit" name="cancel" value="{L_CANCEL}" />
- </fieldset>
-
- <!-- ENDIF -->
+ <dl>
+ <dt><label>{L_AVATAR_TYPE}{L_COLON}</label></dt>
+ <dd><select name="avatar_driver" id="avatar_driver">
+ <option value="">{L_NO_AVATAR_CATEGORY}</option>
+ <!-- BEGIN avatar_drivers -->
+ <option value="{avatar_drivers.DRIVER}"<!-- IF avatar_drivers.SELECTED --> selected="selected"<!-- ENDIF -->>{avatar_drivers.L_TITLE}</option>
+ <!-- END avatar_drivers -->
+ </select></dd>
+ </dl>
+ <div id="avatar_options">
+ <!-- BEGIN avatar_drivers -->
+ <div id="avatar_option_{avatar_drivers.DRIVER}">
+ <p>{avatar_drivers.L_EXPLAIN}</p>
+ {avatar_drivers.OUTPUT}
+ </div>
+ <!-- END avatar_drivers -->
+ </div>
</fieldset>
<fieldset class="submit-buttons">
@@ -174,6 +134,8 @@
</fieldset>
</form>
+ <!-- INCLUDEJS avatars.js -->
+
<!-- ELSEIF S_LIST -->
<a href="{U_BACK}" style="float: {S_CONTENT_FLOW_END};">&laquo; {L_BACK}</a>
diff --git a/phpBB/adm/style/acp_groups_position.html b/phpBB/adm/style/acp_groups_position.html
index 1e309d4cbc..cf1a7be427 100644
--- a/phpBB/adm/style/acp_groups_position.html
+++ b/phpBB/adm/style/acp_groups_position.html
@@ -17,8 +17,8 @@
</dl>
<p class="submit-buttons">
- <input class="button1" type="submit" id="submit" name="update" value="{L_SUBMIT}" />&nbsp;
- <input class="button2" type="reset" id="reset" name="reset" value="{L_RESET}" />
+ <input class="button1" type="submit" name="update" value="{L_SUBMIT}" />&nbsp;
+ <input class="button2" type="reset" name="reset" value="{L_RESET}" />
<input type="hidden" name="action" value="set_config_legend" />
{S_FORM_TOKEN}
</p>
@@ -38,22 +38,22 @@
</thead>
<tbody>
<!-- BEGIN legend -->
- <tr>
- <td><strong{legend.GROUP_COLOUR}>{legend.GROUP_NAME}</strong></td>
+ <tr data-down="{legend.U_MOVE_DOWN}" data-up="{legend.U_MOVE_UP}">
+ <td><strong<!-- IF legend.GROUP_COLOUR --> style="color: {legend.GROUP_COLOUR}"<!-- ENDIF -->>{legend.GROUP_NAME}</strong></td>
<td style="text-align: center;">{legend.GROUP_TYPE}</td>
<td style="vertical-align: top; width: 100px; text-align: right; white-space: nowrap;">
<!-- IF legend.S_FIRST_ROW && not legend.S_LAST_ROW -->
- {ICON_MOVE_UP_DISABLED}
- <a href="{legend.U_MOVE_DOWN}">{ICON_MOVE_DOWN}</a>
+ <span class="up">{ICON_MOVE_UP_DISABLED}</span>
+ <span class="down"><a href="{legend.U_MOVE_DOWN}" data-ajax="row_down" data-overlay="false">{ICON_MOVE_DOWN}</a></span>
<!-- ELSEIF not legend.S_FIRST_ROW && not legend.S_LAST_ROW -->
- <a href="{legend.U_MOVE_UP}">{ICON_MOVE_UP}</a>
- <a href="{legend.U_MOVE_DOWN}">{ICON_MOVE_DOWN}</a>
+ <span class="up"><a href="{legend.U_MOVE_UP}" data-ajax="row_up" data-overlay="false">{ICON_MOVE_UP}</a></span>
+ <span class="down"><a href="{legend.U_MOVE_DOWN}" data-ajax="row_down" data-overlay="false">{ICON_MOVE_DOWN}</a></span>
<!-- ELSEIF legend.S_LAST_ROW && not legend.S_FIRST_ROW -->
- <a href="{legend.U_MOVE_UP}">{ICON_MOVE_UP}</a>
- {ICON_MOVE_DOWN_DISABLED}
+ <span class="up"><a href="{legend.U_MOVE_UP}" data-ajax="row_up" data-overlay="false">{ICON_MOVE_UP}</a></span>
+ <span class="down">{ICON_MOVE_DOWN_DISABLED}</span>
<!-- ELSE -->
- {ICON_MOVE_UP_DISABLED}
- {ICON_MOVE_DOWN_DISABLED}
+ <span class="up">{ICON_MOVE_UP_DISABLED}</span>
+ <span class="down">{ICON_MOVE_DOWN_DISABLED}</span>
<!-- ENDIF -->
<a href="{legend.U_DELETE}">{ICON_DELETE}</a>
</td>
@@ -66,9 +66,14 @@
</tbody>
</table>
- <form id="acp_groups" method="post" action="{U_ACTION_LEGEND}">
+ <form id="legend_add_group" method="post" action="{U_ACTION_LEGEND}">
<fieldset class="quick">
- <select name="g"><option value="0">{L_SELECT_GROUP}</option>{S_GROUP_SELECT_LEGEND}</select>
+ <select name="g">
+ <option value="0">{L_SELECT_GROUP}</option>
+ <!-- BEGIN add_legend -->
+ <option<!-- IF add_legend.GROUP_SPECIAL --> class="sep"<!-- ENDIF --> value="{add_legend.GROUP_ID}">{add_legend.GROUP_NAME}</option>
+ <!-- END add_legend -->
+ </select>
<input class="button2" type="submit" name="submit" value="{L_ADD}" />
<input type="hidden" name="action" value="add" />
{S_FORM_TOKEN}
@@ -82,7 +87,7 @@
<fieldset>
<legend>{L_TEAMPAGE_SETTINGS}</legend>
<dl>
- <dt><label for="teampage_multiple">{L_TEAMPAGE_MEMBERSHIPS}{L_COLON}</label></dt>
+ <dt><label for="teampage_memberships">{L_TEAMPAGE_MEMBERSHIPS}{L_COLON}</label></dt>
<dd>
<label><input type="radio" name="teampage_memberships" class="radio" value="0"<!-- IF DISPLAY_MEMBERSHIPS == 0 --> checked="checked"<!-- ENDIF --> /> {L_TEAMPAGE_DISP_FIRST}</label><br />
<label><input type="radio" name="teampage_memberships" class="radio" value="1"<!-- IF DISPLAY_MEMBERSHIPS == 1 --> checked="checked"<!-- ENDIF --> /> {L_TEAMPAGE_DISP_DEFAULT}</label><br />
@@ -98,8 +103,8 @@
</dl>
<p class="submit-buttons">
- <input class="button1" type="submit" id="submit" name="update" value="{L_SUBMIT}" />&nbsp;
- <input class="button2" type="reset" id="reset" name="reset" value="{L_RESET}" />
+ <input class="button1" type="submit" name="update" value="{L_SUBMIT}" />&nbsp;
+ <input class="button2" type="reset" name="reset" value="{L_RESET}" />
<input type="hidden" name="action" value="set_config_teampage" />
{S_FORM_TOKEN}
</p>
@@ -108,6 +113,8 @@
<p>{L_TEAMPAGE_EXPLAIN}</p>
+ <!-- IF S_TEAMPAGE_CATEGORY and CURRENT_CATEGORY_NAME --><p><strong><a href="{U_ACTION}">{L_TEAMPAGE}</a> &raquo; {CURRENT_CATEGORY_NAME}</strong></p><!-- ENDIF -->
+
<table cellspacing="1">
<col class="col1" /><col class="col2" /><col class="col2" />
<thead>
@@ -119,22 +126,29 @@
</thead>
<tbody>
<!-- BEGIN teampage -->
- <tr>
- <td><strong{teampage.GROUP_COLOUR}>{teampage.GROUP_NAME}</strong></td>
- <td style="text-align: center;">{teampage.GROUP_TYPE}</td>
+ <tr data-down="{teampage.U_MOVE_DOWN}" data-up="{teampage.U_MOVE_UP}">
+ <td>
+ <!-- IF teampage.U_CATEGORY -->
+ <a href="{teampage.U_CATEGORY}">{teampage.GROUP_NAME}</a>
+ <!-- ELSE -->
+ <strong<!-- IF teampage.GROUP_COLOUR --> style="color: {teampage.GROUP_COLOUR}"<!-- ENDIF -->>{teampage.GROUP_NAME}</strong>
+ <!-- ENDIF -->
+ </td>
+ <td style="text-align: center;"><!-- IF teampage.GROUP_TYPE -->{teampage.GROUP_TYPE}<!-- ELSE -->-<!-- ENDIF -->
+ </td></td>
<td style="vertical-align: top; width: 100px; text-align: right; white-space: nowrap;">
<!-- IF teampage.S_FIRST_ROW && not teampage.S_LAST_ROW -->
- {ICON_MOVE_UP_DISABLED}
- <a href="{teampage.U_MOVE_DOWN}">{ICON_MOVE_DOWN}</a>
+ <span class="up">{ICON_MOVE_UP_DISABLED}</span>
+ <span class="down"><a href="{teampage.U_MOVE_DOWN}" data-ajax="row_down" data-overlay="false">{ICON_MOVE_DOWN}</a></span>
<!-- ELSEIF not teampage.S_FIRST_ROW && not teampage.S_LAST_ROW -->
- <a href="{teampage.U_MOVE_UP}">{ICON_MOVE_UP}</a>
- <a href="{teampage.U_MOVE_DOWN}">{ICON_MOVE_DOWN}</a>
+ <span class="up"><a href="{teampage.U_MOVE_UP}" data-ajax="row_up" data-overlay="false">{ICON_MOVE_UP}</a></span>
+ <span class="down"><a href="{teampage.U_MOVE_DOWN}" data-ajax="row_down" data-overlay="false">{ICON_MOVE_DOWN}</a></span>
<!-- ELSEIF teampage.S_LAST_ROW && not teampage.S_FIRST_ROW -->
- <a href="{teampage.U_MOVE_UP}">{ICON_MOVE_UP}</a>
- {ICON_MOVE_DOWN_DISABLED}
+ <span class="up"><a href="{teampage.U_MOVE_UP}" data-ajax="row_up" data-overlay="false">{ICON_MOVE_UP}</a></span>
+ <span class="down">{ICON_MOVE_DOWN_DISABLED}</span>
<!-- ELSE -->
- {ICON_MOVE_UP_DISABLED}
- {ICON_MOVE_DOWN_DISABLED}
+ <span class="up">{ICON_MOVE_UP_DISABLED}</span>
+ <span class="down">{ICON_MOVE_DOWN_DISABLED}</span>
<!-- ENDIF -->
<a href="{teampage.U_DELETE}">{ICON_DELETE}</a>
</td>
@@ -147,13 +161,37 @@
</tbody>
</table>
- <form id="acp_groups" method="post" action="{U_ACTION_TEAMPAGE}">
+ <!-- IF not S_TEAMPAGE_CATEGORY -->
+ <form id="teampage_add_category" method="post" action="{U_ACTION_TEAMPAGE}">
<fieldset class="quick">
- <select name="g"><option value="0">{L_SELECT_GROUP}</option>{S_GROUP_SELECT_TEAMPAGE}</select>
+ <input class="inputbox autowidth" type="text" maxlength="255" name="category_name" placeholder="{L_GROUP_CATEGORY_NAME}" />
+ <input class="button2" type="submit" name="submit" value="{L_ADD_GROUP_CATEGORY}" />
+ <input type="hidden" name="action" value="add_category" />
+ {S_FORM_TOKEN}
+ </fieldset>
+ </form>
+ <!-- ENDIF -->
+
+ <form id="teampage_add_group" method="post" action="{U_ACTION_TEAMPAGE}">
+ <fieldset class="quick">
+ <select name="g">
+ <option value="0">{L_SELECT_GROUP}</option>
+ <!-- BEGIN add_teampage -->
+ <option<!-- IF add_teampage.GROUP_SPECIAL --> class="sep"<!-- ENDIF --> value="{add_teampage.GROUP_ID}">{add_teampage.GROUP_NAME}</option>
+ <!-- END add_teampage -->
+ </select>
<input class="button2" type="submit" name="submit" value="{L_ADD}" />
<input type="hidden" name="action" value="add" />
{S_FORM_TOKEN}
</fieldset>
</form>
+ <div class="hidden">
+ <a class="template-up-img" href="#">{ICON_MOVE_UP}</a>
+ <span class="template-up-img-disabled">{ICON_MOVE_UP_DISABLED}</span>
+
+ <a class="template-down-img" href="#">{ICON_MOVE_DOWN}</a>
+ <span class="template-down-img-disabled">{ICON_MOVE_DOWN_DISABLED}</span>
+ </div>
+
<!-- INCLUDE overall_footer.html -->
diff --git a/phpBB/adm/style/acp_icons.html b/phpBB/adm/style/acp_icons.html
index b9af20d5a2..373a7b890c 100644
--- a/phpBB/adm/style/acp_icons.html
+++ b/phpBB/adm/style/acp_icons.html
@@ -108,8 +108,8 @@
<td><input class="text post" type="text" name="code[{items.IMG}]" value="{items.CODE}" size="10" maxlength="50" /></td>
<td><input class="text post" type="text" name="emotion[{items.IMG}]" value="{items.EMOTION}" size="10" maxlength="50" /></td>
<!-- ENDIF -->
- <td><input class="text post" type="text" size="3" name="width[{items.IMG}]" value="{items.WIDTH}" /></td>
- <td><input class="text post" type="text" size="3" name="height[{items.IMG}]" value="{items.HEIGHT}" /></td>
+ <td><input class="text post" type="number" size="3" name="width[{items.IMG}]" value="{items.WIDTH}" /></td>
+ <td><input class="text post" type="number" size="3" name="height[{items.IMG}]" value="{items.HEIGHT}" /></td>
<td>
<input type="checkbox" class="radio" name="display_on_posting[{items.IMG}]"{items.POSTING_CHECKED} onclick="toggle_select('{items.A_IMG}', this.checked, '{items.S_ROW_COUNT}');"/>
<!-- IF items.S_ID -->
@@ -136,8 +136,8 @@
<td style="vertical-align: top;"><img src="{IMG_SRC}" id="add_image_src" alt="" title="" /></td>
<td><input class="text post" type="text" name="add_code" id="add_code" value="{CODE}" size="10" maxlength="50" /></td>
<td><input class="text post" type="text" name="add_emotion" id="add_emotion" value="{EMOTION}" size="10" maxlength="50" /></td>
- <td><input class="text post" type="text" size="3" name="add_width" id="add_width" value="{WIDTH}" /></td>
- <td><input class="text post" type="text" size="3" name="add_height" id="add_height" value="{HEIGHT}" /></td>
+ <td><input class="text post" type="number" size="3" name="add_width" id="add_width" value="{WIDTH}" /></td>
+ <td><input class="text post" type="number" size="3" name="add_height" id="add_height" value="{HEIGHT}" /></td>
<td><input type="checkbox" class="radio" name="add_display_on_posting" checked="checked" onclick="toggle_select('add', this.checked, 'add_order');"/></td>
<td><select id="order_add_order" name="add_order">
<optgroup id="order_disp_add_order" label="{L_DISPLAY_POSTING}">{S_ADD_ORDER_LIST_DISPLAY}</optgroup>
diff --git a/phpBB/adm/style/acp_inactive.html b/phpBB/adm/style/acp_inactive.html
index 726c8c8b32..68a168a5d6 100644
--- a/phpBB/adm/style/acp_inactive.html
+++ b/phpBB/adm/style/acp_inactive.html
@@ -53,7 +53,7 @@
</table>
<fieldset class="display-options">
- {L_DISPLAY_LOG}{L_COLON} &nbsp;{S_LIMIT_DAYS}&nbsp;{L_SORT_BY}{L_COLON} {S_SORT_KEY} {S_SORT_DIR}<!-- IF .pagination -->&nbsp;Users per page{L_COLON} <input class="inputbox autowidth" type="text" name="users_per_page" id="users_per_page" size="3" value="{USERS_PER_PAGE}" /><!-- ENDIF -->
+ {L_DISPLAY_LOG}{L_COLON} &nbsp;{S_LIMIT_DAYS}&nbsp;{L_SORT_BY}{L_COLON} {S_SORT_KEY} {S_SORT_DIR}<!-- IF .pagination -->&nbsp;Users per page{L_COLON} <input class="inputbox autowidth" type="number" name="users_per_page" id="users_per_page" size="3" value="{USERS_PER_PAGE}" /><!-- ENDIF -->
<input class="button2" type="submit" value="{L_GO}" name="sort" />
</fieldset>
diff --git a/phpBB/adm/style/acp_jabber.html b/phpBB/adm/style/acp_jabber.html
index 639bcd221f..4d0b1b0d97 100644
--- a/phpBB/adm/style/acp_jabber.html
+++ b/phpBB/adm/style/acp_jabber.html
@@ -31,7 +31,7 @@
</dl>
<dl>
<dt><label for="jab_port">{L_JAB_PORT}{L_COLON}</label><br /><span>{L_JAB_PORT_EXPLAIN}</span></dt>
- <dd><input type="text" id="jab_port" name="jab_port" value="{JAB_PORT}" maxlength="5" size="5" /></dd>
+ <dd><input type="number" id="jab_port" name="jab_port" value="{JAB_PORT}" maxlength="5" size="5" /></dd>
</dl>
<dl>
<dt><label for="jab_username">{L_JAB_USERNAME}{L_COLON}</label><br /><span>{L_JAB_USERNAME_EXPLAIN}</span></dt>
@@ -50,7 +50,7 @@
<!-- ENDIF -->
<dl>
<dt><label for="jab_package_size">{L_JAB_PACKAGE_SIZE}{L_COLON}</label><br /><span>{L_JAB_PACKAGE_SIZE_EXPLAIN}</span></dt>
- <dd><input type="text" id="jab_package_size" name="jab_package_size" value="{JAB_PACKAGE_SIZE}" maxlength="5" size="5" /></dd>
+ <dd><input type="number" id="jab_package_size" name="jab_package_size" value="{JAB_PACKAGE_SIZE}" maxlength="5" size="5" min="0" max="99999" /></dd>
</dl>
</fieldset>
diff --git a/phpBB/adm/style/acp_prune_forums.html b/phpBB/adm/style/acp_prune_forums.html
index aede662bcb..67cdaa784a 100644
--- a/phpBB/adm/style/acp_prune_forums.html
+++ b/phpBB/adm/style/acp_prune_forums.html
@@ -73,11 +73,11 @@
<legend>{L_FORUM_PRUNE}</legend>
<dl>
<dt><label for="prune_days">{L_PRUNE_NOT_POSTED}{L_COLON}</label></dt>
- <dd><input type="text" id="prune_days" name="prune_days" /></dd>
+ <dd><input type="number" id="prune_days" name="prune_days" /></dd>
</dl>
<dl>
<dt><label for="prune_vieweddays">{L_PRUNE_NOT_VIEWED}{L_COLON}</label></dt>
- <dd><input type="text" id="prune_vieweddays" name="prune_vieweddays" /></dd>
+ <dd><input type="number" id="prune_vieweddays" name="prune_vieweddays" /></dd>
</dl>
<dl>
<dt><label for="polls">{L_PRUNE_OLD_POLLS}{L_COLON}</label><br /><span>{L_PRUNE_OLD_POLLS_EXPLAIN}</span></dt>
diff --git a/phpBB/adm/style/acp_prune_users.html b/phpBB/adm/style/acp_prune_users.html
index 75fa04a157..1257f3fb3d 100644
--- a/phpBB/adm/style/acp_prune_users.html
+++ b/phpBB/adm/style/acp_prune_users.html
@@ -35,11 +35,11 @@
</dl>
<dl>
<dt><label for="count">{L_POSTS}{L_COLON}</label></dt>
- <dd><select name="count_select">{S_COUNT_OPTIONS}</select> <input type="text" id="count" name="count" /></dd>
+ <dd><select name="count_select">{S_COUNT_OPTIONS}</select> <input type="number" id="count" name="count" /></dd>
</dl>
<dl>
<dt><label for="posts_on_queue">{L_POSTS_ON_QUEUE}{L_COLON}</label></dt>
- <dd><select name="queue_select">{S_COUNT_OPTIONS}</select> <input type="text" id="posts_on_queue" name="posts_on_queue" /></select>
+ <dd><select name="queue_select">{S_COUNT_OPTIONS}</select> <input type="number" id="posts_on_queue" name="posts_on_queue" /></select>
</dl>
<!-- IF S_GROUP_LIST -->
<dl>
diff --git a/phpBB/adm/style/acp_ranks.html b/phpBB/adm/style/acp_ranks.html
index a475370f73..4b2e52536f 100644
--- a/phpBB/adm/style/acp_ranks.html
+++ b/phpBB/adm/style/acp_ranks.html
@@ -41,7 +41,7 @@
<!-- IF S_SPECIAL_RANK --><div id="posts" style="display: none;"><!-- ELSE --><div id="posts"><!-- ENDIF -->
<dl>
<dt><label for="min_posts">{L_RANK_MINIMUM}{L_COLON}</label></dt>
- <dd><input name="min_posts" type="text" id="min_posts" maxlength="10" value="{MIN_POSTS}" /></dd>
+ <dd><input name="min_posts" type="number" id="min_posts" maxlength="10" value="{MIN_POSTS}" /></dd>
</dl>
</div>
diff --git a/phpBB/adm/style/acp_search.html b/phpBB/adm/style/acp_search.html
index 3da70bc0c8..bf353d62f2 100644
--- a/phpBB/adm/style/acp_search.html
+++ b/phpBB/adm/style/acp_search.html
@@ -18,11 +18,11 @@
</dl>
<dl>
<dt><label for="search_interval">{L_SEARCH_INTERVAL}{L_COLON}</label><br /><span>{L_SEARCH_INTERVAL_EXPLAIN}</span></dt>
- <dd><input id="search_interval" type="text" size="4" maxlength="4" name="config[search_interval]" value="{SEARCH_INTERVAL}" /> {L_SECONDS}</dd>
+ <dd><input id="search_interval" type="number" size="4" maxlength="4" min="0" max="9999" name="config[search_interval]" value="{SEARCH_INTERVAL}" /> {L_SECONDS}</dd>
</dl>
<dl>
<dt><label for="search_anonymous_interval">{L_SEARCH_GUEST_INTERVAL}{L_COLON}</label><br /><span>{L_SEARCH_GUEST_INTERVAL_EXPLAIN}</span></dt>
- <dd><input id="search_anonymous_interval" type="text" size="4" maxlength="4" name="config[search_anonymous_interval]" value="{SEARCH_GUEST_INTERVAL}" /> {L_SECONDS}</dd>
+ <dd><input id="search_anonymous_interval" type="number" size="4" maxlength="4" min="0" max="9999" name="config[search_anonymous_interval]" value="{SEARCH_GUEST_INTERVAL}" /> {L_SECONDS}</dd>
</dl>
<dl>
<dt><label for="limit_search_load">{L_LIMIT_SEARCH_LOAD}{L_COLON}</label><br /><span>{L_LIMIT_SEARCH_LOAD_EXPLAIN}</span></dt>
@@ -30,15 +30,15 @@
</dl>
<dl>
<dt><label for="min_search_author_chars">{L_MIN_SEARCH_AUTHOR_CHARS}{L_COLON}</label><br /><span>{L_MIN_SEARCH_AUTHOR_CHARS_EXPLAIN}</span></dt>
- <dd><input id="min_search_author_chars" type="text" size="4" maxlength="4" name="config[min_search_author_chars]" value="{MIN_SEARCH_AUTHOR_CHARS}" /></dd>
+ <dd><input id="min_search_author_chars" type="number" size="4" maxlength="4" min="0" max="9999" name="config[min_search_author_chars]" value="{MIN_SEARCH_AUTHOR_CHARS}" /></dd>
</dl>
<dl>
<dt><label for="max_num_search_keywords">{L_MAX_NUM_SEARCH_KEYWORDS}{L_COLON}</label><br /><span>{L_MAX_NUM_SEARCH_KEYWORDS_EXPLAIN}</span></dt>
- <dd><input id="max_num_search_keywords" type="text" size="4" maxlength="4" name="config[max_num_search_keywords]" value="{MAX_NUM_SEARCH_KEYWORDS}" /></dd>
+ <dd><input id="max_num_search_keywords" type="number" size="4" maxlength="4" min="0" max="9999" name="config[max_num_search_keywords]" value="{MAX_NUM_SEARCH_KEYWORDS}" /></dd>
</dl>
<dl>
<dt><label for="search_store_results">{L_SEARCH_STORE_RESULTS}{L_COLON}</label><br /><span>{L_SEARCH_STORE_RESULTS_EXPLAIN}</span></dt>
- <dd><input id="search_store_results" type="text" size="4" maxlength="6" name="config[search_store_results]" value="{SEARCH_STORE_RESULTS}" /> {L_SECONDS}</dd>
+ <dd><input id="search_store_results" type="number" size="4" maxlength="6" min="0" max="999999" name="config[search_store_results]" value="{SEARCH_STORE_RESULTS}" /> {L_SECONDS}</dd>
</dl>
</fieldset>
diff --git a/phpBB/adm/style/acp_users_avatar.html b/phpBB/adm/style/acp_users_avatar.html
index 2135b52fb9..0a72bb0b62 100644
--- a/phpBB/adm/style/acp_users_avatar.html
+++ b/phpBB/adm/style/acp_users_avatar.html
@@ -1,78 +1,39 @@
- <form id="avatar_settings" method="post" action="{U_ACTION}"<!-- IF S_CAN_UPLOAD --> enctype="multipart/form-data"<!-- ENDIF -->>
+ <form id="avatar_settings" method="post" action="{U_ACTION}" enctype="multipart/form-data">
<fieldset>
<legend>{L_ACP_USER_AVATAR}</legend>
- <dl>
- <dt><label>{L_CURRENT_IMAGE}{L_COLON}</label><br /><span>{L_AVATAR_EXPLAIN}</span></dt>
- <dd>{AVATAR_IMAGE}</dd>
- <dd><label><input type="checkbox" class="radio" name="delete" /> {L_DELETE_AVATAR}</label></dd>
- </dl>
- <!-- IF not S_IN_AVATAR_GALLERY -->
- <!-- IF S_UPLOAD_FILE -->
- <dl>
- <dt><label for="uploadfile">{L_UPLOAD_AVATAR_FILE}{L_COLON}</label></dt>
- <dd><input type="hidden" name="MAX_FILE_SIZE" value="{AVATAR_MAX_FILESIZE}" /><input type="file" id="uploadfile" name="uploadfile" /></dd>
- </dl>
- <!-- ENDIF -->
- <!-- IF S_REMOTE_UPLOAD -->
- <dl>
- <dt><label for="uploadurl">{L_UPLOAD_AVATAR_URL}{L_COLON}</label><br /><span>{L_UPLOAD_AVATAR_URL_EXPLAIN}</span></dt>
- <dd><input name="uploadurl" type="text" id="uploadurl" value="" /></dd>
- </dl>
- <!-- ENDIF -->
- <!-- IF S_ALLOW_REMOTE -->
- <dl>
- <dt><label for="remotelink">{L_LINK_REMOTE_AVATAR}{L_COLON}</label><br /><span>{L_LINK_REMOTE_AVATAR_EXPLAIN}</span></dt>
- <dd><input name="remotelink" type="text" id="remotelink" value="" /></dd>
- </dl>
- <dl>
- <dt><label for="width">{L_LINK_REMOTE_SIZE}{L_COLON}</label><br /><span>{L_LINK_REMOTE_SIZE_EXPLAIN}</span></dt>
- <dd><input name="width" type="text" id="width" size="3" value="{USER_AVATAR_WIDTH}" /> <span>{L_PIXEL} &times; </span> <input type="text" name="height" size="3" value="{USER_AVATAR_HEIGHT}" /> <span>{L_PIXEL}</span></dd>
- </dl>
- <!-- ENDIF -->
- <!-- IF S_DISPLAY_GALLERY -->
- <dl>
- <dt><label>{L_AVATAR_GALLERY}{L_COLON}</label></dt>
- <dd><input class="button2" type="submit" name="display_gallery" value="{L_DISPLAY_GALLERY}" /></dd>
- </dl>
- <!-- ENDIF -->
- <!-- ELSE -->
- </fieldset>
-
- <fieldset>
- <legend>{L_AVATAR_GALLERY}</legend>
+ <!-- IF ERROR --><p class="error">{ERROR}</p><!-- ENDIF -->
<dl>
- <dt><label for="category">{L_AVATAR_CATEGORY}{L_COLON}</label></dt>
- <dd><select name="category" id="category">{S_CAT_OPTIONS}</select>&nbsp;<input class="button2" type="submit" value="{L_GO}" name="display_gallery" /></dd>
+ <dt><label>{L_CURRENT_IMAGE}{L_COLON}</label><br /><span>{L_AVATAR_EXPLAIN}</span></dt>
+ <dd>{AVATAR}</dd>
+ <dd><label for="avatar_delete"><input type="checkbox" name="avatar_delete" id="avatar_delete" /> {L_DELETE_AVATAR}</label></dd>
</dl>
+ </fieldset>
+ <fieldset>
+ <legend>{L_AVATAR_SELECT}</legend>
<dl>
- <table cellspacing="1">
- <!-- BEGIN avatar_row -->
- <tr>
- <!-- BEGIN avatar_column -->
- <td class="row1" style="text-align: center;"><img src="{avatar_row.avatar_column.AVATAR_IMAGE}" alt="{avatar_row.avatar_column.AVATAR_NAME}" title="{avatar_row.avatar_column.AVATAR_NAME}" /></td>
- <!-- END avatar_column -->
- </tr>
- <tr>
- <!-- BEGIN avatar_option_column -->
- <td class="row2" style="text-align: center;"><input type="radio" class="radio" name="avatar_select" value="{avatar_row.avatar_option_column.S_OPTIONS_AVATAR}" /></td>
- <!-- END avatar_option_column -->
- </tr>
- <!-- END avatar_row -->
- </table>
+ <dt><label>{L_AVATAR_TYPE}</label></dt>
+ <dd><select name="avatar_driver" id="avatar_driver">
+ <option value="">{L_NO_AVATAR_CATEGORY}</option>
+ <!-- BEGIN avatar_drivers -->
+ <option value="{avatar_drivers.DRIVER}"<!-- IF avatar_drivers.SELECTED --> selected="selected"<!-- ENDIF -->>{avatar_drivers.L_TITLE}</option>
+ <!-- END avatar_drivers -->
+ </select></dd>
</dl>
- </fieldset>
-
- <fieldset class="quick" style="margin-top: -15px;">
- <input class="button2" type="submit" name="cancel" value="{L_CANCEL}" />
- </fieldset>
-
- <!-- ENDIF -->
+ <div id="avatar_options">
+ <!-- BEGIN avatar_drivers -->
+ <div id="avatar_option_{avatar_drivers.DRIVER}">
+ <p>{avatar_drivers.L_EXPLAIN}</p>
+ {avatar_drivers.OUTPUT}
+ </div>
+ <!-- END avatar_drivers -->
+ </div>
</fieldset>
<fieldset class="quick">
- <input class="button1" type="submit" name="update" value="{L_SUBMIT}" />
- {S_FORM_TOKEN}
+ <input type="submit" name="update" value="{L_SUBMIT}" class="button1" />
+ {S_FORM_TOKEN}
</fieldset>
-
</form>
+
+ <!-- INCLUDEJS avatars.js -->
diff --git a/phpBB/adm/style/acp_users_overview.html b/phpBB/adm/style/acp_users_overview.html
index a8e862c141..1caa6e5e13 100644
--- a/phpBB/adm/style/acp_users_overview.html
+++ b/phpBB/adm/style/acp_users_overview.html
@@ -43,7 +43,7 @@
</dl>
<dl>
<dt><label for="user_email">{L_EMAIL}{L_COLON}</label></dt>
- <dd><input class="text medium" type="text" id="user_email" name="user_email" value="{USER_EMAIL}" autocomplete="off" /></dd>
+ <dd><input class="text medium" type="email" id="user_email" name="user_email" value="{USER_EMAIL}" autocomplete="off" /></dd>
</dl>
<dl>
<dt><label for="new_password">{L_NEW_PASSWORD}{L_COLON}</label><br /><span>{L_CHANGE_PASSWORD_EXPLAIN}</span></dt>
diff --git a/phpBB/adm/style/acp_users_profile.html b/phpBB/adm/style/acp_users_profile.html
index 3232e8d1f5..cad1dca9d8 100644
--- a/phpBB/adm/style/acp_users_profile.html
+++ b/phpBB/adm/style/acp_users_profile.html
@@ -12,7 +12,7 @@
</dl>
<dl>
<dt><label for="msn">{L_UCP_MSNM}{L_COLON}</label></dt>
- <dd><input type="text" id="msn" name="msn" value="{MSN}" /></dd>
+ <dd><input type="email" id="msn" name="msn" value="{MSN}" /></dd>
</dl>
<dl>
<dt><label for="yim">{L_UCP_YIM}{L_COLON}</label></dt>
@@ -20,11 +20,11 @@
</dl>
<dl>
<dt><label for="jabber">{L_UCP_JABBER}{L_COLON}</label></dt>
- <dd><input type="text" id="jabber" name="jabber" value="{JABBER}" /></dd>
+ <dd><input type="email" id="jabber" name="jabber" value="{JABBER}" /></dd>
</dl>
<dl>
<dt><label for="website">{L_WEBSITE}{L_COLON}</label></dt>
- <dd><input type="text" id="website" name="website" value="{WEBSITE}" /></dd>
+ <dd><input type="url" id="website" name="website" value="{WEBSITE}" /></dd>
</dl>
<dl>
<dt><label for="location">{L_LOCATION}{L_COLON}</label></dt>
@@ -38,7 +38,7 @@
<dt><label for="interests">{L_INTERESTS}{L_COLON}</label></dt>
<dd><textarea id="interests" name="interests" rows="3" cols="30">{INTERESTS}</textarea></dd>
</dl>
- <dl>
+ <dl>
<dt><label for="birthday">{L_BIRTHDAY}{L_COLON}</label><br /><span>{L_BIRTHDAY_EXPLAIN}</span></dt>
<dd>{L_DAY}{L_COLON} <select id="birthday" name="bday_day">{S_BIRTHDAY_DAY_OPTIONS}</select> {L_MONTH}{L_COLON} <select name="bday_month">{S_BIRTHDAY_MONTH_OPTIONS}</select> {L_YEAR}{L_COLON} <select name="bday_year">{S_BIRTHDAY_YEAR_OPTIONS}</select></dd>
</dl>
@@ -48,7 +48,7 @@
<fieldset>
<legend>{L_USER_CUSTOM_PROFILE_FIELDS}</legend>
<!-- BEGIN profile_fields -->
- <dl>
+ <dl>
<dt><label<!-- IF profile_fields.FIELD_ID --> for="{profile_fields.FIELD_ID}"<!-- ENDIF -->>{profile_fields.LANG_NAME}{L_COLON}</label><!-- IF profile_fields.LANG_EXPLAIN --><br /><span>{profile_fields.LANG_EXPLAIN}</span><!-- ENDIF --></dt>
<dd>{profile_fields.FIELD}</dd>
<!-- IF profile_fields.ERROR -->
diff --git a/phpBB/adm/style/admin.css b/phpBB/adm/style/admin.css
index 8551c952c7..f7a7f9f9bf 100644
--- a/phpBB/adm/style/admin.css
+++ b/phpBB/adm/style/admin.css
@@ -1098,12 +1098,13 @@ input.disabled {
border: 1px solid #999999;
position: fixed;
display: none;
- top: 100px;
- left: 35%;
- width: 30%;
+ top: 150px;
+ left: 25%;
+ width: 50%;
z-index: 50;
padding: 25px;
padding: 0 25px 20px 25px;
+ text-align: left;
}
.phpbb_alert .alert_close {
@@ -1127,6 +1128,20 @@ input.disabled {
padding-bottom: 8px;
}
+.phpbb_alert label {
+ display: block;
+ margin: 8px 0;
+ padding-bottom: 8px;
+}
+
+.phpbb_alert div.alert_text > p,
+.phpbb_alert div.alert_text > label,
+.phpbb_alert div.alert_text > select,
+.phpbb_alert div.alert_text > textarea,
+.phpbb_alert div.alert_text > input {
+ font-size: 0.9em;
+}
+
#darkenwrapper {
display: none;
}
diff --git a/phpBB/adm/style/ajax.js b/phpBB/adm/style/ajax.js
index 294a35b615..6f21dfa6ac 100644
--- a/phpBB/adm/style/ajax.js
+++ b/phpBB/adm/style/ajax.js
@@ -115,9 +115,9 @@ phpbb.addAjaxCallback('activate_deactivate', function(res) {
el.text(res.text);
if (newHref.indexOf('deactivate') !== -1) {
- newHref = newHref.replace('deactivate', 'activate')
+ newHref = newHref.replace('deactivate', 'activate');
} else {
- newHref = newHref.replace('activate', 'deactivate')
+ newHref = newHref.replace('activate', 'deactivate');
}
el.attr('href', newHref);
@@ -148,6 +148,12 @@ $('[data-ajax]').each(function() {
}
});
+/**
+* Automatically resize textarea
+*/
+$(document).ready(function() {
+ phpbb.resizeTextArea($('textarea:not(.no-auto-resize)'), {minHeight: 75});
+});
})(jQuery); // Avoid conflicts with other libraries
diff --git a/phpBB/adm/style/avatars.js b/phpBB/adm/style/avatars.js
new file mode 100644
index 0000000000..26ea24c0db
--- /dev/null
+++ b/phpBB/adm/style/avatars.js
@@ -0,0 +1,15 @@
+(function($) { // Avoid conflicts with other libraries
+
+"use strict";
+
+function avatarHide() {
+ $('#avatar_options > div').hide();
+
+ var selected = $('#avatar_driver').val();
+ $('#avatar_option_' + selected).show();
+}
+
+avatarHide();
+$('#avatar_driver').bind('change', avatarHide);
+
+})(jQuery); // Avoid conflicts with other libraries
diff --git a/phpBB/adm/style/captcha_gd_acp.html b/phpBB/adm/style/captcha_gd_acp.html
index b333d9205c..43d54adc0b 100644
--- a/phpBB/adm/style/captcha_gd_acp.html
+++ b/phpBB/adm/style/captcha_gd_acp.html
@@ -20,11 +20,11 @@
</dl>
<dl>
<dt><label for="captcha_gd_x_grid">{L_CAPTCHA_GD_X_GRID}{L_COLON}</label><br /><span>{L_CAPTCHA_GD_X_GRID_EXPLAIN}</span></dt>
- <dd><input id="captcha_gd_x_grid" name="captcha_gd_x_grid" value="{CAPTCHA_GD_X_GRID}" type="text" /></dd>
+ <dd><input id="captcha_gd_x_grid" name="captcha_gd_x_grid" value="{CAPTCHA_GD_X_GRID}" type="number" /></dd>
</dl>
<dl>
<dt><label for="captcha_gd_y_grid">{L_CAPTCHA_GD_Y_GRID}{L_COLON}</label><br /><span>{L_CAPTCHA_GD_Y_GRID_EXPLAIN}</span></dt>
- <dd><input id="captcha_gd_y_grid" name="captcha_gd_y_grid" value="{CAPTCHA_GD_Y_GRID}" type="text" /></dd>
+ <dd><input id="captcha_gd_y_grid" name="captcha_gd_y_grid" value="{CAPTCHA_GD_Y_GRID}" type="number" /></dd>
</dl>
<dl>
<dt><label for="captcha_gd_wave">{L_CAPTCHA_GD_WAVE}{L_COLON}</label><br /><span>{L_CAPTCHA_GD_WAVE_EXPLAIN}</span></dt>
diff --git a/phpBB/adm/style/confirm_body.html b/phpBB/adm/style/confirm_body.html
index 2fbb1a60d7..d0360d1b3a 100644
--- a/phpBB/adm/style/confirm_body.html
+++ b/phpBB/adm/style/confirm_body.html
@@ -1,3 +1,15 @@
+<!-- IF S_AJAX_REQUEST -->
+
+ <h3>{MESSAGE_TITLE}</h3>
+ <p>{MESSAGE_TEXT}</p>
+
+ <fieldset class="submit-buttons">
+ <input type="button" name="confirm" value="{L_YES}" class="button2" />&nbsp;
+ <input type="button" name="cancel" value="{L_NO}" class="button2" />
+ </fieldset>
+
+<!-- ELSE -->
+
<!-- INCLUDE overall_header.html -->
<form id="confirm" method="post" action="{S_CONFIRM_ACTION}">
@@ -14,7 +26,7 @@
</div>
</fieldset>
-
</form>
<!-- INCLUDE overall_footer.html -->
+<!-- ENDIF -->
diff --git a/phpBB/adm/style/editor.js b/phpBB/adm/style/editor.js
index c9e8afe08e..9938ff5d0b 100644
--- a/phpBB/adm/style/editor.js
+++ b/phpBB/adm/style/editor.js
@@ -10,18 +10,16 @@ var theSelection = false;
// Check for Browser & Platform for PC & IE specific bits
// More details from: http://www.mozilla.org/docs/web-developer/sniffer/browser_type.html
var clientPC = navigator.userAgent.toLowerCase(); // Get client info
-var clientVer = parseInt(navigator.appVersion); // Get browser version
-
-var is_ie = ((clientPC.indexOf('msie') != -1) && (clientPC.indexOf('opera') == -1));
-var is_win = ((clientPC.indexOf('win') != -1) || (clientPC.indexOf('16bit') != -1));
+var clientVer = parseInt(navigator.appVersion, 10); // Get browser version
+var is_ie = ((clientPC.indexOf('msie') !== -1) && (clientPC.indexOf('opera') === -1));
+var is_win = ((clientPC.indexOf('win') !== -1) || (clientPC.indexOf('16bit') !== -1));
var baseHeight;
/**
* Shows the help messages in the helpline window
*/
-function helpline(help)
-{
+function helpline(help) {
document.forms[form_name].helpbox.value = help_line[help];
}
@@ -29,26 +27,22 @@ function helpline(help)
* Fix a bug involving the TextRange object. From
* http://www.frostjedi.com/terra/scripts/demo/caretBug.html
*/
-function initInsertions()
-{
+function initInsertions() {
var doc;
- if(document.forms[form_name])
- {
+
+ if (document.forms[form_name]) {
doc = document;
- }
- else
- {
+ } else {
doc = opener.document;
}
var textarea = doc.forms[form_name].elements[text_name];
- if (is_ie && typeof(baseHeight) != 'number')
- {
+
+ if (is_ie && typeof(baseHeight) !== 'number') {
textarea.focus();
baseHeight = doc.selection.createRange().duplicate().boundingHeight;
- if (!document.forms[form_name])
- {
+ if (!document.forms[form_name]) {
document.body.focus();
}
}
@@ -57,69 +51,59 @@ function initInsertions()
/**
* bbstyle
*/
-function bbstyle(bbnumber)
-{
- if (bbnumber != -1)
- {
+function bbstyle(bbnumber) {
+ if (bbnumber !== -1) {
bbfontstyle(bbtags[bbnumber], bbtags[bbnumber+1]);
- }
- else
- {
+ } else {
insert_text('[*]');
- document.forms[form_name].elements[text_name].focus();
+ document.forms[form_name].elements[text_name].focus();
}
}
/**
* Apply bbcodes
*/
-function bbfontstyle(bbopen, bbclose)
-{
+function bbfontstyle(bbopen, bbclose) {
theSelection = false;
-
+
var textarea = document.forms[form_name].elements[text_name];
textarea.focus();
- if ((clientVer >= 4) && is_ie && is_win)
- {
+ if ((clientVer >= 4) && is_ie && is_win) {
// Get text selection
theSelection = document.selection.createRange().text;
- if (theSelection)
- {
+ if (theSelection) {
// Add tags around selection
document.selection.createRange().text = bbopen + theSelection + bbclose;
document.forms[form_name].elements[text_name].focus();
theSelection = '';
return;
}
- }
- else if (document.forms[form_name].elements[text_name].selectionEnd && (document.forms[form_name].elements[text_name].selectionEnd - document.forms[form_name].elements[text_name].selectionStart > 0))
- {
+ } else if (document.forms[form_name].elements[text_name].selectionEnd
+ && (document.forms[form_name].elements[text_name].selectionEnd - document.forms[form_name].elements[text_name].selectionStart > 0)) {
mozWrap(document.forms[form_name].elements[text_name], bbopen, bbclose);
document.forms[form_name].elements[text_name].focus();
theSelection = '';
return;
}
-
+
//The new position for the cursor after adding the bbcode
var caret_pos = getCaretPosition(textarea).start;
- var new_pos = caret_pos + bbopen.length;
+ var new_pos = caret_pos + bbopen.length;
// Open tag
insert_text(bbopen + bbclose);
// Center the cursor when we don't have a selection
// Gecko and proper browsers
- if (!isNaN(textarea.selectionStart))
- {
+ if (!isNaN(textarea.selectionStart)) {
textarea.selectionStart = new_pos;
textarea.selectionEnd = new_pos;
- }
+ }
// IE
- else if (document.selection)
- {
+ else if (document.selection) {
var range = textarea.createTextRange();
range.move("character", new_pos);
range.select();
@@ -133,62 +117,47 @@ function bbfontstyle(bbopen, bbclose)
/**
* Insert text at position
*/
-function insert_text(text, spaces, popup)
-{
+function insert_text(text, spaces, popup) {
var textarea;
-
- if (!popup)
- {
+
+ if (!popup) {
textarea = document.forms[form_name].elements[text_name];
- }
- else
- {
+ } else {
textarea = opener.document.forms[form_name].elements[text_name];
}
- if (spaces)
- {
+ if (spaces) {
text = ' ' + text + ' ';
}
- if (!isNaN(textarea.selectionStart))
- {
+ if (!isNaN(textarea.selectionStart)) {
var sel_start = textarea.selectionStart;
var sel_end = textarea.selectionEnd;
mozWrap(textarea, text, '');
textarea.selectionStart = sel_start + text.length;
textarea.selectionEnd = sel_end + text.length;
- }
-
- else if (textarea.createTextRange && textarea.caretPos)
- {
- if (baseHeight != textarea.caretPos.boundingHeight)
- {
+ } else if (textarea.createTextRange && textarea.caretPos) {
+ if (baseHeight !== textarea.caretPos.boundingHeight) {
textarea.focus();
storeCaret(textarea);
}
+
var caret_pos = textarea.caretPos;
- caret_pos.text = caret_pos.text.charAt(caret_pos.text.length - 1) == ' ' ? caret_pos.text + text + ' ' : caret_pos.text + text;
-
- }
- else
- {
+ caret_pos.text = caret_pos.text.charAt(caret_pos.text.length - 1) === ' ' ? caret_pos.text + text + ' ' : caret_pos.text + text;
+ } else {
textarea.value = textarea.value + text;
}
- if (!popup)
- {
+ if (!popup) {
textarea.focus();
}
-
}
/**
* Add inline attachment at position
*/
-function attach_inline(index, filename)
-{
+function attach_inline(index, filename) {
insert_text('[attachment=' + index + ']' + filename + '[/attachment]');
document.forms[form_name].elements[text_name].focus();
}
@@ -202,56 +171,39 @@ function addquote(post_id, username)
var theSelection = '';
var divarea = false;
- if (document.all)
- {
+ if (document.all) {
divarea = document.all[message_name];
- }
- else
- {
+ } else {
divarea = document.getElementById(message_name);
}
// Get text selection - not only the post content :(
- if (window.getSelection)
- {
+ if (window.getSelection) {
theSelection = window.getSelection().toString();
- }
- else if (document.getSelection)
- {
+ } else if (document.getSelection) {
theSelection = document.getSelection();
- }
- else if (document.selection)
- {
+ } else if (document.selection) {
theSelection = document.selection.createRange().text;
}
- if (theSelection == '' || typeof theSelection == 'undefined' || theSelection == null)
- {
- if (divarea.innerHTML)
- {
+ if (theSelection === '' || typeof theSelection === 'undefined' || theSelection === null) {
+ if (divarea.innerHTML) {
theSelection = divarea.innerHTML.replace(/<br>/ig, '\n');
theSelection = theSelection.replace(/<br\/>/ig, '\n');
theSelection = theSelection.replace(/&lt\;/ig, '<');
theSelection = theSelection.replace(/&gt\;/ig, '>');
- theSelection = theSelection.replace(/&amp\;/ig, '&');
+ theSelection = theSelection.replace(/&amp\;/ig, '&');
theSelection = theSelection.replace(/&nbsp\;/ig, ' ');
- }
- else if (document.all)
- {
+ } else if (document.all) {
theSelection = divarea.innerText;
- }
- else if (divarea.textContent)
- {
+ } else if (divarea.textContent) {
theSelection = divarea.textContent;
- }
- else if (divarea.firstChild.nodeValue)
- {
+ } else if (divarea.firstChild.nodeValue) {
theSelection = divarea.firstChild.nodeValue;
}
}
- if (theSelection)
- {
+ if (theSelection) {
insert_text('[quote="' + username + '"]' + theSelection + '[/quote]');
}
@@ -261,15 +213,13 @@ function addquote(post_id, username)
/**
* From http://www.massless.org/mozedit/
*/
-function mozWrap(txtarea, open, close)
-{
- var selLength = (typeof(txtarea.textLength) == 'undefined') ? txtarea.value.length : txtarea.textLength;
+function mozWrap(txtarea, open, close) {
+ var selLength = (typeof(txtarea.textLength) === 'undefined') ? txtarea.value.length : txtarea.textLength;
var selStart = txtarea.selectionStart;
var selEnd = txtarea.selectionEnd;
var scrollTop = txtarea.scrollTop;
- if (selEnd == 1 || selEnd == 2)
- {
+ if (selEnd === 1 || selEnd === 2) {
selEnd = selLength;
}
@@ -290,10 +240,8 @@ function mozWrap(txtarea, open, close)
* Insert at Caret position. Code from
* http://www.faqts.com/knowledge_base/view.phtml/aid/1052/fid/130
*/
-function storeCaret(textEl)
-{
- if (textEl.createTextRange)
- {
+function storeCaret(textEl) {
+ if (textEl.createTextRange) {
textEl.caretPos = document.selection.createRange().duplicate();
}
}
@@ -301,8 +249,7 @@ function storeCaret(textEl)
/**
* Color pallette
*/
-function colorPalette(dir, width, height)
-{
+function colorPalette(dir, width, height) {
var r = 0, g = 0, b = 0;
var numberList = new Array(6);
var color = '';
@@ -315,88 +262,74 @@ function colorPalette(dir, width, height)
document.writeln('<table class="type2">');
- for (r = 0; r < 5; r++)
- {
- if (dir == 'h')
- {
+ for (r = 0; r < 5; r++) {
+ if (dir === 'h') {
document.writeln('<tr>');
}
- for (g = 0; g < 5; g++)
- {
- if (dir == 'v')
- {
+ for (g = 0; g < 5; g++) {
+ if (dir === 'v') {
document.writeln('<tr>');
}
-
- for (b = 0; b < 5; b++)
- {
+
+ for (b = 0; b < 5; b++) {
color = String(numberList[r]) + String(numberList[g]) + String(numberList[b]);
document.write('<td bgcolor="#' + color + '" style="width: ' + width + 'px; height: ' + height + 'px;">');
document.write('<a href="#" onclick="bbfontstyle(\'[color=#' + color + ']\', \'[/color]\'); return false;"><img src="images/spacer.gif" width="' + width + '" height="' + height + '" alt="#' + color + '" title="#' + color + '" /></a>');
document.writeln('</td>');
}
- if (dir == 'v')
- {
+ if (dir === 'v') {
document.writeln('</tr>');
}
}
- if (dir == 'h')
- {
+ if (dir === 'h') {
document.writeln('</tr>');
}
}
document.writeln('</table>');
}
-
/**
* Caret Position object
*/
-function caretPosition()
-{
+function caretPosition() {
var start = null;
var end = null;
}
-
/**
* Get the caret position in an textarea
*/
-function getCaretPosition(txtarea)
-{
+function getCaretPosition(txtarea) {
var caretPos = new caretPosition();
-
+
// simple Gecko/Opera way
- if (txtarea.selectionStart || txtarea.selectionStart == 0)
- {
+ if (txtarea.selectionStart || txtarea.selectionStart === 0) {
caretPos.start = txtarea.selectionStart;
caretPos.end = txtarea.selectionEnd;
}
// dirty and slow IE way
- else if (document.selection)
- {
+ else if (document.selection) {
// get current selection
var range = document.selection.createRange();
// a new selection of the whole textarea
var range_all = document.body.createTextRange();
range_all.moveToElementText(txtarea);
-
+
// calculate selection start point by moving beginning of range_all to beginning of range
var sel_start;
- for (sel_start = 0; range_all.compareEndPoints('StartToStart', range) < 0; sel_start++)
- {
+ for (sel_start = 0; range_all.compareEndPoints('StartToStart', range) < 0; sel_start++) {
range_all.moveStart('character', 1);
}
-
+
txtarea.sel_start = sel_start;
-
+
// we ignore the end value for IE, this is already dirty enough and we don't need it
caretPos.start = txtarea.sel_start;
- caretPos.end = txtarea.sel_start;
+ caretPos.end = txtarea.sel_start;
}
return caretPos;
diff --git a/phpBB/adm/style/overall_footer.html b/phpBB/adm/style/overall_footer.html
index 2a8b46d458..54ed4dcc9e 100644
--- a/phpBB/adm/style/overall_footer.html
+++ b/phpBB/adm/style/overall_footer.html
@@ -18,7 +18,7 @@
{DEBUG_OUTPUT}
<!-- ENDIF -->
- <div id="darkenwrapper" data-ajax-error-title="{L_AJAX_ERROR_TITLE}" data-ajax-error-text="{L_AJAX_ERROR_TEXT}">
+ <div id="darkenwrapper" data-ajax-error-title="{L_AJAX_ERROR_TITLE}" data-ajax-error-text="{L_AJAX_ERROR_TEXT}" data-ajax-error-text-abort="{L_AJAX_ERROR_TEXT_ABORT}" data-ajax-error-text-timeout="{L_AJAX_ERROR_TEXT_TIMEOUT}" data-ajax-error-text-parsererror="{L_AJAX_ERROR_TEXT_PARSERERROR}">
<div id="darken">&nbsp;</div>
<div class="jalert" id="loadingalert"><h3>{L_LOADING}</h3><p>{L_PLEASE_WAIT}</p></div>
</div>
@@ -29,9 +29,7 @@
</div>
<div id="phpbb_confirm" class="phpbb_alert">
<a href="#" class="alert_close"></a>
- <p class="alert_text"></p>
- <input type="button" class="button1" value="{L_YES}" />&nbsp;
- <input type="button" class="button2" value="{L_NO}" />
+ <div class="alert_text"></div>
</div>
</div>
</div>
diff --git a/phpBB/adm/style/permissions.js b/phpBB/adm/style/permissions.js
index adc8995c23..1c85fbd9ef 100644
--- a/phpBB/adm/style/permissions.js
+++ b/phpBB/adm/style/permissions.js
@@ -2,35 +2,27 @@
* Hide and show all checkboxes
* status = true (show boxes), false (hide boxes)
*/
-function display_checkboxes(status)
-{
+function display_checkboxes(status) {
var form = document.getElementById('set-permissions');
var cb = document.getElementsByTagName('input');
var display;
//show
- if (status)
- {
+ if (status) {
display = 'inline';
}
//hide
- else
- {
+ else {
display = 'none';
}
-
- for (var i = 0; i < cb.length; i++ )
- {
- if (cb[i].className == 'permissions-checkbox')
- {
+
+ for (var i = 0; i < cb.length; i++ ) {
+ if (cb[i].className === 'permissions-checkbox') {
cb[i].style.display = display;
}
-
- }
-
+ }
}
-
/**
* Change opacity of element
* e = element
@@ -38,7 +30,7 @@ function display_checkboxes(status)
*/
function set_opacity(e, value) {
e.style.opacity = value/10;
-
+
//IE opacity currently turned off, because of its astronomical stupidity
//e.style.filter = 'alpha(opacity=' + value*10 + ')';
}
@@ -50,13 +42,10 @@ function set_opacity(e, value) {
function toggle_opacity(block_id) {
var cb = document.getElementById('checkbox' + block_id);
var fs = document.getElementById('perm' + block_id);
-
- if (cb.checked)
- {
+
+ if (cb.checked) {
set_opacity(fs, 5);
- }
- else
- {
+ } else {
set_opacity(fs, 10);
}
}
@@ -71,21 +60,17 @@ function reset_opacity(status, except_id) {
var fs = perm.getElementsByTagName('fieldset');
var opacity = 5;
- if (status)
- {
- opacity = 10;
+ if (status) {
+ opacity = 10;
}
-
- for (var i = 0; i < fs.length; i++ )
- {
- if (fs[i].className != 'quick')
- {
+
+ for (var i = 0; i < fs.length; i++ ) {
+ if (fs[i].className !== 'quick') {
set_opacity(fs[i], opacity);
}
}
- if (typeof(except_id) != 'undefined')
- {
+ if (typeof(except_id) !== 'undefined') {
set_opacity(document.getElementById('perm' + except_id), 10);
}
@@ -93,20 +78,15 @@ function reset_opacity(status, except_id) {
marklist('set-permissions', 'inherit', !status);
}
-
/**
* Check whether we have a full radiobutton row of true
* index = offset for the row of inputs (0 == first row, 1 == second, 2 == third),
* rb = array of radiobuttons
*/
-function get_radio_status(index, rb)
-{
- for (var i = index; i < rb.length; i = i + 3 )
- {
- if (rb[i].checked != true)
- {
- if (i > index)
- {
+function get_radio_status(index, rb) {
+ for (var i = index; i < rb.length; i = i + 3 ) {
+ if (rb[i].checked !== true) {
+ if (i > index) {
//at least one is true, but not all (custom)
return 2;
}
@@ -121,17 +101,15 @@ function get_radio_status(index, rb)
/**
* Set tab colours
-* id = panel the tab needs to be set for,
-* init = initialising on open,
+* id = panel the tab needs to be set for,
+* init = initialising on open,
* quick = If no calculation needed, this contains the colour
*/
-function set_colours(id, init, quick)
-{
+function set_colours(id, init, quick) {
var table = document.getElementById('table' + id);
var tab = document.getElementById('tab' + id);
- if (typeof(quick) != 'undefined')
- {
+ if (typeof(quick) !== 'undefined') {
tab.className = 'permissions-preset-' + quick + ' activetab';
return;
}
@@ -141,37 +119,27 @@ function set_colours(id, init, quick)
var status = get_radio_status(0, rb);
- if (status == 1)
- {
+ if (status === 1) {
colour = 'yes';
- }
- else if (status == 0)
- {
+ } else if (status === 0) {
// We move on to No
status = get_radio_status(1, rb);
- if (status == 1)
- {
+ if (status === 1) {
colour = 'no';
- }
- else if (status == 0)
- {
+ } else if (status === 0) {
// We move on to Never
status = get_radio_status(2, rb);
- if (status == 1)
- {
+ if (status === 1) {
colour = 'never';
}
}
}
- if (init)
- {
+ if (init) {
tab.className = 'permissions-preset-' + colour;
- }
- else
- {
+ } else {
tab.className = 'permissions-preset-' + colour + ' activetab';
}
}
@@ -180,16 +148,13 @@ function set_colours(id, init, quick)
* Initialise advanced tab colours on first load
* block_id = block that is opened
*/
-function init_colours(block_id)
-{
+function init_colours(block_id) {
var block = document.getElementById('advanced' + block_id);
var panels = block.getElementsByTagName('div');
var tab = document.getElementById('tab' + id);
- for (var i = 0; i < panels.length; i++)
- {
- if(panels[i].className == 'permissions-panel')
- {
+ for (var i = 0; i < panels.length; i++) {
+ if (panels[i].className === 'permissions-panel') {
set_colours(panels[i].id.replace(/options/, ''), true);
}
}
@@ -203,17 +168,15 @@ function init_colours(block_id)
* adv = we are opening advanced permissions
* view = called from view permissions
*/
-function swap_options(pmask, fmask, cat, adv, view)
-{
+function swap_options(pmask, fmask, cat, adv, view) {
id = pmask + fmask + cat;
active_option = active_pmask + active_fmask + active_cat;
- var old_tab = document.getElementById('tab' + active_option);
+ var old_tab = document.getElementById('tab' + active_option);
var new_tab = document.getElementById('tab' + id);
var adv_block = document.getElementById('advanced' + pmask + fmask);
- if (adv_block.style.display == 'block' && adv == true)
- {
+ if (adv_block.style.display === 'block' && adv === true) {
dE('advanced' + pmask + fmask, -1);
reset_opacity(1);
display_checkboxes(false);
@@ -221,20 +184,16 @@ function swap_options(pmask, fmask, cat, adv, view)
}
// no need to set anything if we are clicking on the same tab again
- if (new_tab == old_tab && !adv)
- {
+ if (new_tab === old_tab && !adv) {
return;
}
// init colours
- if (adv && (pmask + fmask) != (active_pmask + active_fmask))
- {
+ if (adv && (pmask + fmask) !== (active_pmask + active_fmask)) {
init_colours(pmask + fmask);
display_checkboxes(true);
reset_opacity(1);
- }
- else if (adv)
- {
+ } else if (adv) {
//Checkbox might have been clicked, but we need full visibility
display_checkboxes(true);
reset_opacity(1);
@@ -244,31 +203,26 @@ function swap_options(pmask, fmask, cat, adv, view)
old_tab.className = old_tab.className.replace(/\ activetab/g, '');
new_tab.className = new_tab.className + ' activetab';
- if (id == active_option && adv != true)
- {
+ if (id === active_option && adv !== true) {
return;
}
dE('options' + active_option, -1);
-
+
//hiding and showing the checkbox
- if (document.getElementById('checkbox' + active_pmask + active_fmask))
- {
- dE('checkbox' + pmask + fmask, -1);
-
- if ((pmask + fmask) != (active_pmask + active_fmask))
- {
+ if (document.getElementById('checkbox' + active_pmask + active_fmask)) {
+ dE('checkbox' + pmask + fmask, -1);
+
+ if ((pmask + fmask) !== (active_pmask + active_fmask)) {
document.getElementById('checkbox' + active_pmask + active_fmask).style.display = 'inline';
}
}
- if (!view)
- {
+ if (!view) {
dE('advanced' + active_pmask + active_fmask, -1);
}
- if (!view)
- {
+ if (!view) {
dE('advanced' + pmask + fmask, 1);
}
dE('options' + id, 1);
@@ -282,41 +236,33 @@ function swap_options(pmask, fmask, cat, adv, view)
* Mark all radio buttons in one panel
* id = table ID container, s = status ['y'/'u'/'n']
*/
-function mark_options(id, s)
-{
+function mark_options(id, s) {
var t = document.getElementById(id);
- if (!t)
- {
+ if (!t) {
return;
}
var rb = t.getElementsByTagName('input');
- for (var r = 0; r < rb.length; r++)
- {
- if (rb[r].id.substr(rb[r].id.length-1) == s)
- {
+ for (var r = 0; r < rb.length; r++) {
+ if (rb[r].id.substr(rb[r].id.length-1) === s) {
rb[r].checked = true;
}
}
}
-function mark_one_option(id, field_name, s)
-{
+function mark_one_option(id, field_name, s) {
var t = document.getElementById(id);
- if (!t)
- {
+ if (!t) {
return;
}
var rb = t.getElementsByTagName('input');
- for (var r = 0; r < rb.length; r++)
- {
- if (rb[r].id.substr(rb[r].id.length-field_name.length-3, field_name.length) == field_name && rb[r].id.substr(rb[r].id.length-1) == s)
- {
+ for (var r = 0; r < rb.length; r++) {
+ if (rb[r].id.substr(rb[r].id.length-field_name.length-3, field_name.length) === field_name && rb[r].id.substr(rb[r].id.length-1) === s) {
rb[r].checked = true;
}
}
@@ -325,12 +271,10 @@ function mark_one_option(id, field_name, s)
/**
* Reset role dropdown field to Select role... if an option gets changed
*/
-function reset_role(id)
-{
+function reset_role(id) {
var t = document.getElementById(id);
- if (!t)
- {
+ if (!t) {
return;
}
@@ -340,20 +284,17 @@ function reset_role(id)
/**
* Load role and set options accordingly
*/
-function set_role_settings(role_id, target_id)
-{
+function set_role_settings(role_id, target_id) {
settings = role_options[role_id];
- if (!settings)
- {
+ if (!settings) {
return;
}
// Mark all options to no (unset) first...
mark_options(target_id, 'u');
- for (var r in settings)
- {
- mark_one_option(target_id, r, (settings[r] == 1) ? 'y' : 'n');
+ for (var r in settings) {
+ mark_one_option(target_id, r, (settings[r] === 1) ? 'y' : 'n');
}
}
diff --git a/phpBB/adm/style/timezone.js b/phpBB/adm/style/timezone.js
index 419d37c34f..b5e27c907c 100644
--- a/phpBB/adm/style/timezone.js
+++ b/phpBB/adm/style/timezone.js
@@ -1,5 +1,7 @@
(function($) { // Avoid conflicts with other libraries
+"use strict";
+
$('#tz_date').change(function() {
phpbb.timezoneSwitchDate(false);
});
diff --git a/phpBB/adm/style/tooltip.js b/phpBB/adm/style/tooltip.js
index 20610b52fe..3a89008706 100644
--- a/phpBB/adm/style/tooltip.js
+++ b/phpBB/adm/style/tooltip.js
@@ -1,6 +1,6 @@
/*
javascript for Bubble Tooltips by Alessandro Fulciniti
-- http://pro.html.it - http://web-graphics.com
+- http://pro.html.it - http://web-graphics.com
obtained from: http://web-graphics.com/mtarchive/001717.php
phpBB Development Team:
@@ -15,14 +15,12 @@ var head_text, tooltip_mode;
/**
* Enable tooltip replacements for links
*/
-function enable_tooltips_link(id, headline, sub_id)
-{
+function enable_tooltips_link(id, headline, sub_id) {
var links, i, hold;
-
+
head_text = headline;
- if (!document.getElementById || !document.getElementsByTagName)
- {
+ if (!document.getElementById || !document.getElementsByTagName) {
return;
}
@@ -33,26 +31,18 @@ function enable_tooltips_link(id, headline, sub_id)
document.getElementsByTagName('body')[0].appendChild(hold);
- if (id == null)
- {
+ if (id === null) {
links = document.getElementsByTagName('a');
- }
- else
- {
+ } else {
links = document.getElementById(id).getElementsByTagName('a');
}
- for (i = 0; i < links.length; i++)
- {
- if (sub_id)
- {
- if (links[i].id.substr(0, sub_id.length) == sub_id)
- {
+ for (i = 0; i < links.length; i++) {
+ if (sub_id) {
+ if (links[i].id.substr(0, sub_id.length) === sub_id) {
prepare(links[i]);
}
- }
- else
- {
+ } else {
prepare(links[i]);
}
}
@@ -63,14 +53,12 @@ function enable_tooltips_link(id, headline, sub_id)
/**
* Enable tooltip replacements for selects
*/
-function enable_tooltips_select(id, headline, sub_id)
-{
+function enable_tooltips_select(id, headline, sub_id) {
var links, i, hold;
-
+
head_text = headline;
- if (!document.getElementById || !document.getElementsByTagName)
- {
+ if (!document.getElementById || !document.getElementsByTagName) {
return;
}
@@ -81,26 +69,18 @@ function enable_tooltips_select(id, headline, sub_id)
document.getElementsByTagName('body')[0].appendChild(hold);
- if (id == null)
- {
+ if (id === null) {
links = document.getElementsByTagName('option');
- }
- else
- {
+ } else {
links = document.getElementById(id).getElementsByTagName('option');
}
- for (i = 0; i < links.length; i++)
- {
- if (sub_id)
- {
- if (links[i].parentNode.id.substr(0, sub_id.length) == sub_id)
- {
+ for (i = 0; i < links.length; i++) {
+ if (sub_id) {
+ if (links[i].parentNode.id.substr(0, sub_id.length) === sub_id) {
prepare(links[i]);
}
- }
- else
- {
+ } else {
prepare(links[i]);
}
}
@@ -111,14 +91,12 @@ function enable_tooltips_select(id, headline, sub_id)
/**
* Prepare elements to replace
*/
-function prepare(element)
-{
+function prepare(element) {
var tooltip, text, desc, title;
text = element.getAttribute('title');
- if (text == null || text.length == 0)
- {
+ if (text === null || text.length === 0) {
return;
}
@@ -139,8 +117,7 @@ function prepare(element)
element.onmouseover = show_tooltip;
element.onmouseout = hide_tooltip;
- if (tooltip_mode == 'link')
- {
+ if (tooltip_mode === 'link') {
element.onmousemove = locate;
}
}
@@ -148,8 +125,7 @@ function prepare(element)
/**
* Show tooltip
*/
-function show_tooltip(e)
-{
+function show_tooltip(e) {
document.getElementById('_tooltip_container').appendChild(this.tooltip);
locate(this);
}
@@ -157,11 +133,9 @@ function show_tooltip(e)
/**
* Hide tooltip
*/
-function hide_tooltip(e)
-{
+function hide_tooltip(e) {
var d = document.getElementById('_tooltip_container');
- if (d.childNodes.length > 0)
- {
+ if (d.childNodes.length > 0) {
d.removeChild(d.firstChild);
}
}
@@ -169,8 +143,7 @@ function hide_tooltip(e)
/**
* Set opacity on tooltip element
*/
-function set_opacity(element)
-{
+function set_opacity(element) {
element.style.filter = 'alpha(opacity:95)';
element.style.KHTMLOpacity = '0.95';
element.style.MozOpacity = '0.95';
@@ -180,8 +153,7 @@ function set_opacity(element)
/**
* Create new element
*/
-function create_element(tag, c)
-{
+function create_element(tag, c) {
var x = document.createElement(tag);
x.className = c;
x.style.display = 'block';
@@ -191,34 +163,26 @@ function create_element(tag, c)
/**
* Correct positioning of tooltip container
*/
-function locate(e)
-{
+function locate(e) {
var posx = 0;
var posy = 0;
e = e.parentNode;
- if (e.offsetParent)
- {
- for (var posx = 0, posy = 0; e.offsetParent; e = e.offsetParent)
- {
+ if (e.offsetParent) {
+ for (posx = 0, posy = 0; e.offsetParent; e = e.offsetParent) {
posx += e.offsetLeft;
posy += e.offsetTop;
}
- }
- else
- {
+ } else {
posx = e.offsetLeft;
posy = e.offsetTop;
}
- if (tooltip_mode == 'link')
- {
+ if (tooltip_mode === 'link') {
document.getElementById('_tooltip_container').style.top=(posy+20) + 'px';
document.getElementById('_tooltip_container').style.left=(posx-20) + 'px';
- }
- else
- {
+ } else {
document.getElementById('_tooltip_container').style.top=(posy+30) + 'px';
document.getElementById('_tooltip_container').style.left=(posx-205) + 'px';
}
diff --git a/phpBB/assets/javascript/core.js b/phpBB/assets/javascript/core.js
index 9909359c2c..e0f1dc1eef 100644
--- a/phpBB/assets/javascript/core.js
+++ b/phpBB/assets/javascript/core.js
@@ -57,7 +57,7 @@ phpbb.clearLoadingTimeout = function() {
* @param string title Title of the message, eg "Information" (HTML).
* @param string msg Message to display (HTML).
* @param bool fadedark Remove the dark background when done? Defaults
- * to yes.
+ * to yes.
*
* @returns object Returns the div created.
*/
@@ -121,9 +121,9 @@ phpbb.alert = function(title, msg, fadedark) {
*
* @param string msg Message to display (HTML).
* @param function callback Callback. Bool param, whether the user pressed
- * yes or no (or whatever their language is).
+ * yes or no (or whatever their language is).
* @param bool fadedark Remove the dark background when done? Defaults
- * to yes.
+ * to yes.
*
* @returns object Returns the div created.
*/
@@ -136,7 +136,7 @@ phpbb.confirm = function(msg, callback, fadedark) {
});
var clickHandler = function(e) {
- var res = this.className === 'button1';
+ var res = this.name === 'confirm';
var fade = (typeof fadedark !== 'undefined' && !fadedark && res) ? div : dark;
fade.fadeOut(phpbb.alertTime, function() {
div.hide();
@@ -164,11 +164,11 @@ phpbb.confirm = function(msg, callback, fadedark) {
$(document).bind('keydown', function(e) {
if (e.keyCode === keymap.ENTER) {
- $('input[type="button"].button1').trigger('click');
+ $('input[name="confirm"]').trigger('click');
e.preventDefault();
e.stopPropagation();
} else if (e.keyCode === keymap.ESC) {
- $('input[type="button"].button2').trigger('click');
+ $('input[name="cancel"]').trigger('click');
e.preventDefault();
e.stopPropagation();
}
@@ -232,10 +232,10 @@ phpbb.parseQuerystring = function(string) {
*
* @param object options Options.
* @param bool/function refresh If we are sent back a refresh, should it be
- * acted upon? This can either be true / false / a function.
+ * acted upon? This can either be true / false / a function.
* @param function callback Callback to call on completion of event. Has
- * three parameters: the element that the event was evoked from, the JSON
- * that was returned and (if it is a form) the form action.
+ * three parameters: the element that the event was evoked from, the JSON
+ * that was returned and (if it is a form) the form action.
*/
phpbb.ajaxify = function(options) {
var elements = $(options.selector),
@@ -253,6 +253,26 @@ phpbb.ajaxify = function(options) {
}
/**
+ * Handler for AJAX errors
+ */
+ function errorHandler(jqXHR, textStatus, errorThrown) {
+ if (console && console.log) {
+ console.log('AJAX error. status: ' + textStatus + ', message: ' + errorThrown);
+ }
+ phpbb.clearLoadingTimeout();
+ var errorText = false;
+ if (typeof errorThrown === 'string' && errorThrown.length > 0) {
+ errorText = errorThrown;
+ }
+ else {
+ errorText = dark.attr('data-ajax-error-text-' + textStatus);
+ if (typeof errorText !== 'string' || !errorText.length)
+ errorText = dark.attr('data-ajax-error-text');
+ }
+ phpbb.alert(dark.attr('data-ajax-error-title'), errorText);
+ }
+
+ /**
* This is a private function used to handle the callbacks, refreshes
* and alert. It calls the callback, refreshes the page if necessary, and
* displays an alert to the user and removes it after an amount of time.
@@ -303,8 +323,8 @@ phpbb.ajaxify = function(options) {
}, res.REFRESH_DATA.time * 1000); // Server specifies time in seconds
}
} else {
- // If confirmation is required, display a diologue to the user.
- phpbb.confirm(res.MESSAGE_TEXT, function(del) {
+ // If confirmation is required, display a dialog to the user.
+ phpbb.confirm(res.MESSAGE_BODY, function(del) {
if (del) {
phpbb.loadingAlert();
data = $('<form>' + res.S_HIDDEN_FIELDS + '</form>').serialize();
@@ -320,13 +340,6 @@ phpbb.ajaxify = function(options) {
}
}
- function errorHandler() {
- var alert;
-
- phpbb.clearLoadingTimeout();
- alert = phpbb.alert(dark.attr('data-ajax-error-title'), dark.attr('data-ajax-error-text'));
- }
-
// If the element is a form, POST must be used and some extra data must
// be taken from the form.
var runFilter = (typeof options.filter === 'function');
@@ -355,8 +368,7 @@ phpbb.ajaxify = function(options) {
return;
}
- if (overlay && (typeof $this.attr('data-overlay') === 'undefined' || $this.attr('data-overlay') == 'true'))
- {
+ if (overlay && (typeof $this.attr('data-overlay') === 'undefined' || $this.attr('data-overlay') === 'true')) {
phpbb.loadingAlert();
}
@@ -389,7 +401,7 @@ phpbb.ajaxify = function(options) {
* @param bool keepSelection Shall we keep the value selected, or shall the user be forced to repick one.
*/
phpbb.timezoneSwitchDate = function(keepSelection) {
- if ($('#timezone_copy').length == 0) {
+ if ($('#timezone_copy').length === 0) {
// We make a backup of the original dropdown, so we can remove optgroups
// instead of setting display to none, because IE and chrome will not
// hide options inside of optgroups and selects via css
@@ -399,17 +411,17 @@ phpbb.timezoneSwitchDate = function(keepSelection) {
$('#timezone').replaceWith($('#timezone_copy').clone().attr('id', 'timezone').css('display', 'block').attr('name', 'tz'));
}
- if ($('#tz_date').val() != '') {
+ if ($('#tz_date').val() !== '') {
$('#timezone > optgroup').remove(":not([label='" + $('#tz_date').val() + "'])");
}
- if ($('#tz_date').val() == $('#tz_select_date_suggest').attr('data-suggested-tz')) {
+ if ($('#tz_date').val() === $('#tz_select_date_suggest').attr('data-suggested-tz')) {
$('#tz_select_date_suggest').css('display', 'none');
} else {
$('#tz_select_date_suggest').css('display', 'inline');
}
- if ($("#timezone > optgroup[label='" + $('#tz_date').val() + "'] > option").size() == 1) {
+ if ($("#timezone > optgroup[label='" + $('#tz_date').val() + "'] > option").size() === 1) {
// If there is only one timezone for the selected date, we just select that automatically.
$("#timezone > optgroup[label='" + $('#tz_date').val() + "'] > option:first").attr('selected', true);
keepSelection = true;
@@ -440,12 +452,11 @@ phpbb.timezonePreselectSelect = function(forceSelector) {
// The offset returned here is in minutes and negated.
// http://www.w3schools.com/jsref/jsref_getTimezoneOffset.asp
var offset = (new Date()).getTimezoneOffset();
+ var sign = '-';
if (offset < 0) {
- var sign = '+';
+ sign = '+';
offset = -offset;
- } else {
- var sign = '-';
}
var minutes = offset % 60;
@@ -466,12 +477,13 @@ phpbb.timezonePreselectSelect = function(forceSelector) {
var prefix = 'GMT' + sign + hours + ':' + minutes;
var prefixLength = prefix.length;
var selectorOptions = $('#tz_date > option');
+ var i;
- for (var i = 0; i < selectorOptions.length; ++i) {
+ for (i = 0; i < selectorOptions.length; ++i) {
var option = selectorOptions[i];
- if (option.value.substring(0, prefixLength) == prefix) {
- if ($('#tz_date').val() != option.value && !forceSelector) {
+ if (option.value.substring(0, prefixLength) === prefix) {
+ if ($('#tz_date').val() !== option.value && !forceSelector) {
// We do not select the option for the user, but notify him,
// that we would suggest a different setting.
phpbb.timezoneSwitchDate(true);
@@ -571,4 +583,100 @@ phpbb.addAjaxCallback('toggle_link', function() {
el.parent().attr('class', toggleClass);
});
+/**
+* Automatically resize textarea
+*
+* This function automatically resizes textarea elements when user
+* types text.
+*
+* @param {jQuery} items jQuery object(s) to resize
+* @param {object} options Optional parameter that adjusts default
+* configuration. See configuration variable
+*
+* Optional parameters:
+* minWindowHeight {number} Minimum browser window height when textareas are resized. Default = 500
+* minHeight {number} Minimum height of textarea. Default = 200
+* maxHeight {number} Maximum height of textarea. Default = 500
+* heightDiff {number} Minimum difference between window and textarea height. Default = 200
+* resizeCallback {function} Function to call after resizing textarea
+* resetCallback {function} Function to call when resize has been canceled
+
+* Callback function format: function(item) {}
+* this points to DOM object
+* item is a jQuery object, same as this
+*/
+phpbb.resizeTextArea = function(items, options) {
+ // Configuration
+ var configuration = {
+ minWindowHeight: 500,
+ minHeight: 200,
+ maxHeight: 500,
+ heightDiff: 200,
+ resizeCallback: function(item) { },
+ resetCallback: function(item) { }
+ };
+
+ if (arguments.length > 1)
+ {
+ configuration = $.extend(configuration, options);
+ }
+
+ function resetAutoResize(item)
+ {
+ var $item = $(item);
+ if ($item.hasClass('auto-resized'))
+ {
+ $(item).css({height: '', resize: ''}).removeClass('auto-resized');
+ configuration.resetCallback.call(item, $item);
+ }
+ }
+
+ function autoResize(item)
+ {
+ function setHeight(height)
+ {
+ $item.css({height: height + 'px', resize: 'none'}).addClass('auto-resized');
+ configuration.resizeCallback.call(item, $item);
+ }
+
+ var windowHeight = $(window).height();
+
+ if (windowHeight < configuration.minWindowHeight)
+ {
+ resetAutoResize(item);
+ return;
+ }
+
+ var maxHeight = Math.min(Math.max(windowHeight - configuration.heightDiff, configuration.minHeight), configuration.maxHeight),
+ $item = $(item),
+ height = parseInt($item.height()),
+ scrollHeight = (item.scrollHeight) ? item.scrollHeight : 0;
+
+ if (height > maxHeight)
+ {
+ setHeight(maxHeight);
+ }
+ else if (scrollHeight > (height + 5))
+ {
+ setHeight(Math.min(maxHeight, scrollHeight));
+ }
+ }
+
+ items.bind('focus change keyup', function() {
+ $(this).each(function() {
+ autoResize(this);
+ });
+ }).change();
+
+ $(window).resize(function() {
+ items.each(function() {
+ if ($(this).hasClass('auto-resized'))
+ {
+ autoResize(this);
+ }
+ });
+ });
+};
+
+
})(jQuery); // Avoid conflicts with other libraries
diff --git a/phpBB/assets/javascript/jquery.js b/phpBB/assets/javascript/jquery.js
index 48590ecb96..83589daa70 100644
--- a/phpBB/assets/javascript/jquery.js
+++ b/phpBB/assets/javascript/jquery.js
@@ -1,18 +1,2 @@
-/*!
- * jQuery JavaScript Library v1.6.2
- * http://jquery.com/
- *
- * Copyright 2011, John Resig
- * Dual licensed under the MIT or GPL Version 2 licenses.
- * http://jquery.org/license
- *
- * Includes Sizzle.js
- * http://sizzlejs.com/
- * Copyright 2011, The Dojo Foundation
- * Released under the MIT, BSD, and GPL Licenses.
- *
- * Date: Thu Jun 30 14:16:56 2011 -0400
- */
-(function(a,b){function cv(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cs(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cr(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cq(){cn=b}function cp(){setTimeout(cq,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function bZ(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function bY(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bC.test(a)?d(a,e):bY(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)bY(a+"["+e+"]",b[e],c,d);else d(a,b)}function bX(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bR,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bX(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bX(a,c,d,e,"*",g));return l}function bW(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bN),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bA(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bv:bw;if(d>0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bx(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bm(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(be,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bl(a){f.nodeName(a,"input")?bk(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bk)}function bk(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bj(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bi(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bh(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i<j;i++)f.event.add(b,h+(g[h][i].namespace?".":"")+g[h][i].namespace,g[h][i],g[h][i].data)}}}}function bg(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function W(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(R.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function V(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function N(a,b){return(a&&a!=="*"?a+".":"")+b.replace(z,"`").replace(A,"&")}function M(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;i<s.length;i++)g=s[i],g.origType.replace(x,"")===a.type?q.push(g.selector):s.splice(i--,1);e=f(a.target).closest(q,a.currentTarget);for(j=0,k=e.length;j<k;j++){m=e[j];for(i=0;i<s.length;i++){g=s[i];if(m.selector===g.selector&&(!n||n.test(g.namespace))&&!m.elem.disabled){h=m.elem,d=null;if(g.preType==="mouseenter"||g.preType==="mouseleave")a.type=g.preType,d=f(a.relatedTarget).closest(g.selector)[0],d&&f.contains(h,d)&&(d=h);(!d||d!==h)&&p.push({elem:h,handleObj:g,level:m.level})}}}for(j=0,k=p.length;j<k;j++){e=p[j];if(c&&e.level>c)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function K(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function E(){return!0}function D(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z])/ig,x=function(a,b){return b.toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!A){A=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||D.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b){if(H)return H.call(b,a);for(var c=0,d=b.length;c<d;c++)if(b[c]===a)return c;return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=s.exec(a)||t.exec(a)||u.exec(a)||a.indexOf("compatible")<0&&v.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g="done fail isResolved isRejected promise then always pipe".split(" "),h=[].slice;f.extend({_Deferred:function(){var a=[],b,c,d,e={done:function(){if(!d){var c=arguments,g,h,i,j,k;b&&(k=b,b=0);for(g=0,h=c.length;g<h;g++)i=c[g],j=f.type(i),j==="array"?e.done.apply(e,i):j==="function"&&a.push(i);k&&e.resolveWith(k[0],k[1])}return this},resolveWith:function(e,f){if(!d&&!b&&!c){f=f||[],c=1;try{while(a[0])a.shift().apply(e,f)}finally{b=[e,f],c=0}}return this},resolve:function(){e.resolveWith(this,arguments);return this},isResolved:function(){return!!c||!!b},cancel:function(){d=1,a=[];return this}};return e},Deferred:function(a){var b=f._Deferred(),c=f._Deferred(),d;f.extend(b,{then:function(a,c){b.done(a).fail(c);return this},always:function(){return b.done.apply(b,arguments).fail.apply(this,arguments)},fail:c.done,rejectWith:c.resolveWith,reject:c.resolve,isRejected:c.isResolved,pipe:function(a,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[c,"reject"]},function(a,c){var e=c[0],g=c[1],h;f.isFunction(e)?b[a](function(){h=e.apply(this,arguments),h&&f.isFunction(h.promise)?h.promise().then(d.resolve,d.reject):d[g](h)}):b[a](d[g])})}).promise()},promise:function(a){if(a==null){if(d)return d;d=a={}}var c=g.length;while(c--)a[g[c]]=b[g[c]];return a}}),b.done(c.cancel).fail(b.cancel),delete b.cancel,a&&a.call(b,b);return b},when:function(a){function i(a){return function(c){b[a]=arguments.length>1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c<d;c++)b[c]&&f.isFunction(b[c].promise)?b[c].promise().then(i(c),g.reject):--e;e||g.resolveWith(g,b)}else g!==a&&g.resolveWith(g,d?[a]:[]);return g.promise()}}),f.support=function(){var a=c.createElement("div"),b=c.documentElement,d,e,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u;a.setAttribute("className","t"),a.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0},m&&f.extend(p,{position:"absolute",left:-1e3,top:-1e3});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="<div style='width:4px;'></div>",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([a-z])([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g=f.expando,h=typeof c=="string",i,j=a.nodeType,k=j?f.cache:a,l=j?a[f.expando]:a[f.expando]&&f.expando;if((!l||e&&l&&!k[l][g])&&h&&d===b)return;l||(j?a[f.expando]=l=++f.uuid:l=f.expando),k[l]||(k[l]={},j||(k[l].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?k[l][g]=f.extend(k[l][g],c):k[l]=f.extend(k[l],c);i=k[l],e&&(i[g]||(i[g]={}),i=i[g]),d!==b&&(i[f.camelCase(c)]=d);if(c==="events"&&!i[c])return i[g]&&i[g].events;return h?i[f.camelCase(c)]||i[c]:i}},removeData:function(b,c,d){if(!!f.acceptData(b)){var e=f.expando,g=b.nodeType,h=g?f.cache:b,i=g?b[f.expando]:f.expando;if(!h[i])return;if(c){var j=d?h[i][e]:h[i];if(j){delete j[c];if(!l(j))return}}if(d){delete h[i][e];if(!l(h[i]))return}var k=h[i][e];f.support.deleteExpando||h!=a?delete h[i]:h[i]=null,k?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=k):g&&(f.support.deleteExpando?delete b[f.expando]:b.removeAttribute?b.removeAttribute(f.expando):b[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h<i;h++)g=e[h].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),k(this[0],g,d[g]))}}return d}if(typeof a=="object")return this.each(function(){f.data(this,a)});var j=a.split(".");j[1]=j[1]?"."+j[1]:"";if(c===b){d=this.triggerHandler("getData"+j[1]+"!",[j[0]]),d===b&&this.length&&(d=f.data(this[0],a),d=k(this[0],a,d));return d===b&&j[1]?this.data(j[0]):d}return this.each(function(){var b=f(this),d=[j[0],c];b.triggerHandler("setData"+j[1]+"!",d),f.data(this,a,c),b.triggerHandler("changeData"+j[1]+"!",d)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,c){a&&(c=(c||"fx")+"mark",f.data(a,c,(f.data(a,c,b,!0)||0)+1,!0))},_unmark:function(a,c,d){a!==!0&&(d=c,c=a,a=!1);if(c){d=d||"fx";var e=d+"mark",g=a?0:(f.data(c,e,b,!0)||1)-1;g?f.data(c,e,g,!0):(f.removeData(c,e,!0),m(c,d,"mark"))}},queue:function(a,c,d){if(a){c=(c||"fx")+"queue";var e=f.data(a,c,b,!0);d&&(!e||f.isArray(d)?e=f.data(a,c,f.makeArray(d),!0):e.push(d));return e||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e;d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),d.call(a,function(){f.dequeue(a,b)})),c.length||(f.removeData(a,b+"queue",!0),m(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(){var c=this;setTimeout(function(){f.dequeue(c,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f._Deferred(),!0))h++,l.done(m);m();return d.promise()}});var n=/[\n\t\r]/g,o=/\s+/,p=/\r/g,q=/^(?:button|input)$/i,r=/^(?:button|input|object|select|textarea)$/i,s=/^a(?:rea)?$/i,t=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,u=/\:|^on/,v,w;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(o);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(o);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(n," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(o);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ";for(var c=0,d=this.length;c<d;c++)if((" "+this[c].className+" ").replace(n," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h<i;h++){var j=e[h];if(j.selected&&(f.support.optDisabled?!j.disabled:j.getAttribute("disabled")===null)&&(!j.parentNode.disabled||!f.nodeName(j.parentNode,"optgroup"))){b=f(j).val();if(g)return b;d.push(b)}}if(g&&!d.length&&e.length)return f(e[c]).val();return d},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=w:v&&c!=="className"&&(f.nodeName(a,"form")||u.test(c))&&(i=v)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.support.getSetAttribute?a.removeAttribute(b):(f.attr(a,b,""),a.removeAttributeNode(a.getAttributeNode(b))),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},tabIndex:{get:function(a){var c=a.getAttributeNode("tabIndex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}},value:{get:function(a,b){if(v&&f.nodeName(a,"button"))return v.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(v&&f.nodeName(a,"button"))return v.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==b?g:a[c]},propHooks:{}}),w={get:function(a,c){return f.prop(a,c)?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(f.attrFix=f.propFix,v=f.attrHooks.name=f.attrHooks.title=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,c){var d=a.getAttributeNode(c);if(d){d.nodeValue=b;return b}}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var x=/\.(.*)$/,y=/^(?:textarea|input|select)$/i,z=/\./g,A=/ /g,B=/[^\w\s.|`]/g,C=function(a){return a.replace(B,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=D;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=D);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),C).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j<p.length;j++){q=p[j];if(l||n.test(q.namespace))f.event.remove(a,r,q.handler,j),p.splice(j--,1)}continue}o=f.event.special[h]||{};for(j=e||0;j<p.length;j++){q=p[j];if(d.guid===q.guid){if(l||n.test(q.namespace))e==null&&p.splice(j--,1),o.remove&&o.remove.call(a,q);if(e!=null)break}}if(p.length===0||e!=null&&p.length===1)(!o.teardown||o.teardown.call(a,m)===!1)&&f.removeEvent(a,h,s.handle),g=null,delete t[h]}if(f.isEmptyObject(t)){var u=s.handle;u&&(u.elem=null),delete s.events,delete s.handle,f.isEmptyObject(s)&&f.removeData(a,b,!0)}}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){var h=c.type||c,i=[],j;h.indexOf("!")>=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.
-shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h<i;h++){var j=d[h];if(e||c.namespace_re.test(j.namespace)){c.handler=j.handler,c.data=j.data,c.handleObj=j;var k=j.handler.apply(this,g);k!==b&&(c.result=k,k===!1&&(c.preventDefault(),c.stopPropagation()));if(c.isImmediatePropagationStopped())break}}return c.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[f.expando])return a;var d=a;a=f.Event(d);for(var e=this.props.length,g;e;)g=this.props[--e],a[g]=d[g];a.target||(a.target=a.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),!a.relatedTarget&&a.fromElement&&(a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement);if(a.pageX==null&&a.clientX!=null){var h=a.target.ownerDocument||c,i=h.documentElement,j=h.body;a.pageX=a.clientX+(i&&i.scrollLeft||j&&j.scrollLeft||0)-(i&&i.clientLeft||j&&j.clientLeft||0),a.pageY=a.clientY+(i&&i.scrollTop||j&&j.scrollTop||0)-(i&&i.clientTop||j&&j.clientTop||0)}a.which==null&&(a.charCode!=null||a.keyCode!=null)&&(a.which=a.charCode!=null?a.charCode:a.keyCode),!a.metaKey&&a.ctrlKey&&(a.metaKey=a.ctrlKey),!a.which&&a.button!==b&&(a.which=a.button&1?1:a.button&2?3:a.button&4?2:0);return a},guid:1e8,proxy:f.proxy,special:{ready:{setup:f.bindReady,teardown:f.noop},live:{add:function(a){f.event.add(this,N(a.origType,a.selector),f.extend({},a,{handler:M,guid:a.handler.guid}))},remove:function(a){f.event.remove(this,N(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}}},f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!this.preventDefault)return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?E:D):this.type=a,b&&f.extend(this,b),this.timeStamp=f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=E;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=E;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=E,this.stopPropagation()},isDefaultPrevented:D,isPropagationStopped:D,isImmediatePropagationStopped:D};var F=function(a){var b=a.relatedTarget,c=!1,d=a.type;a.type=a.data,b!==this&&(b&&(c=f.contains(this,b)),c||(f.event.handle.apply(this,arguments),a.type=d))},G=function(a){a.type=a.data,f.event.handle.apply(this,arguments)};f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={setup:function(c){f.event.add(this,b,c&&c.selector?G:F,a)},teardown:function(a){f.event.remove(this,b,a&&a.selector?G:F)}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(a,b){if(!f.nodeName(this,"form"))f.event.add(this,"click.specialSubmit",function(a){var b=a.target,c=b.type;(c==="submit"||c==="image")&&f(b).closest("form").length&&K("submit",this,arguments)}),f.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,c=b.type;(c==="text"||c==="password")&&f(b).closest("form").length&&a.keyCode===13&&K("submit",this,arguments)});else return!1},teardown:function(a){f.event.remove(this,".specialSubmit")}});if(!f.support.changeBubbles){var H,I=function(a){var b=a.type,c=a.value;b==="radio"||b==="checkbox"?c=a.checked:b==="select-multiple"?c=a.selectedIndex>-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},J=function(c){var d=c.target,e,g;if(!!y.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=I(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:J,beforedeactivate:J,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&J.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&J.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",I(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in H)f.event.add(this,c+".specialChange",H[c]);return y.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return y.test(this.nodeName)}},H=f.event.special.change.filters,H.focus=H.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i<j;i++)f.event.add(this[i],a,g,d);return this}}),f.fn.extend({unbind:function(a,b){if(typeof a=="object"&&!a.preventDefault)for(var c in a)this.unbind(c,a[c]);else for(var d=0,e=this.length;d<e;d++)f.event.remove(this[d],a,b);return this},delegate:function(a,b,c,d){return this.live(b,c,d,a)},undelegate:function(a,b,c){return arguments.length===0?this.unbind("live"):this.die(b,null,c,a)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f.data(this,"lastToggle"+a.guid)||0)%d;f.data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var L={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};f.each(["live","die"],function(a,c){f.fn[c]=function(a,d,e,g){var h,i=0,j,k,l,m=g||this.selector,n=g?this:f(this.context);if(typeof a=="object"&&!a.preventDefault){for(var o in a)n[c](o,d,a[o],m);return this}if(c==="die"&&!a&&g&&g.charAt(0)==="."){n.unbind(g);return this}if(d===!1||f.isFunction(d))e=d||D,d=b;a=(a||"").split(" ");while((h=a[i++])!=null){j=x.exec(h),k="",j&&(k=j[0],h=h.replace(x,""));if(h==="hover"){a.push("mouseenter"+k,"mouseleave"+k);continue}l=h,L[h]?(a.push(L[h]+k),h=h+k):h=(L[h]||h)+k;if(c==="live")for(var p=0,q=n.length;p<q;p++)f.event.add(n[p],"live."+N(h,m),{data:d,selector:m,handler:e,origType:h,origHandler:e,preType:l});else n.unbind("live."+N(h,m),e)}return this}}),f.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){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}if(i.nodeType===1){f||(i.sizcache=c,i.sizset=g);if(typeof b!="string"){if(i===b){j=!0;break}}else if(k.filter(b,[i]).length>0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g<h;g++){var i=d[g];if(i){var j=!1;i=i[a];while(i){if(i.sizcache===c){j=d[i.sizset];break}i.nodeType===1&&!f&&(i.sizcache=c,i.sizset=g);if(i.nodeName.toLowerCase()===b){j=i;break}i=i[a]}d[g]=j}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},k.matches=function(a,b){return k(a,null,null,b)},k.matchesSelector=function(a,b){return k(b,null,null,[a]).length>0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e<f;e++){var g,h=l.order[e];if(g=l.leftMatch[h].exec(a)){var j=g[1];g.splice(1,1);if(j.substr(j.length-1)!=="\\"){g[1]=(g[1]||"").replace(i,""),d=l.find[h](g,b,c);if(d!=null){a=a.replace(l.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},k.filter=function(a,c,d,e){var f,g,h=a,i=[],j=c,m=c&&c[0]&&k.isXML(c[0]);while(a&&c.length){for(var n in l.filter)if((f=l.leftMatch[n].exec(a))!=null&&f[2]){var o,p,q=l.filter[n],r=f[1];g=!1,f.splice(1,1);if(r.substr(r.length-1)==="\\")continue;j===i&&(i=[]);if(l.preFilter[n]){f=l.preFilter[n](f,j,d,i,e,m);if(!f)g=o=!0;else if(f===!0)continue}if(f)for(var s=0;(p=j[s])!=null;s++)if(p){o=q(p,f,s,j);var t=e^!!o;d&&o!=null?t?g=!0:j[s]=!1:t&&(i.push(p),g=!0)}if(o!==b){d||(j=i),a=a.replace(l.match[n],"");if(!g)return[];break}}if(a===h)if(g==null)k.error(a);else break;h=a}return j},k.error=function(a){throw"Syntax error, unrecognized expression: "+a};var l=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\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(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!j.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&k.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&k.filter(b,a,!0)}},"":function(a,b,c){var e,f=d++,g=u;typeof b=="string"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g("parentNode",b,f,a,e,c)},"~":function(a,b,c){var e,f=d++,g=u;typeof b=="string"&&!j.test(b)&&(b=b.toLowerCase(),e=b,g=t),g("previousSibling",b,f,a,e,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(i,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!k(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}k.error(e)},CHILD:function(a,b){var c=b[1],d=a;switch(c){case"only":case"first":while(d=d.previousSibling)if(d.nodeType===1)return!1;if(c==="first")return!0;d=a;case"last":while(d=d.nextSibling)if(d.nodeType===1)return!1;return!0;case"nth":var e=b[2],f=b[3];if(e===1&&f===0)return!0;var g=b[0],h=a.parentNode;if(h&&(h.sizcache!==g||!a.nodeIndex)){var i=0;for(d=h.firstChild;d;d=d.nextSibling)d.nodeType===1&&(d.nodeIndex=++i);h.sizcache=g}var j=a.nodeIndex-f;return e===0?j===0:j%e===0&&j/e>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c<f;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var r,s;c.documentElement.compareDocumentPosition?r=function(a,b){if(a===b){g=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(r=function(a,b){if(a===b){g=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],h=a.parentNode,i=b.parentNode,j=h;if(h===i)return s(a,b);if(!h)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return s(e[k],f[k]);return k===c?s(a,f[k],-1):s(e[k],b,1)},s=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),k.getText=function(a){var b="",c;for(var d=0;a[d];d++)c=a[d],c.nodeType===3||c.nodeType===4?b+=c.nodeValue:c.nodeType!==8&&(b+=k.getText(c.childNodes));return b},function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},l.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(l.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return k(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g<h;g++)k(a,f[g],d);return k.filter(e,d)};f.find=k,f.expr=k.selectors,f.expr[":"]=f.expr.filters,f.unique=k.uniqueSort,f.text=k.getText,f.isXMLDoc=k.isXML,f.contains=k.contains}();var O=/Until$/,P=/^(?:parents|prevUntil|prevAll)/,Q=/,/,R=/^.[^:#\[\.,]*$/,S=Array.prototype.slice,T=f.expr.match.POS,U={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(W(this,a,!1),"not",a)},filter:function(a){return this.pushStack(W(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d<e;d++)i=a[d],j[i]||(j[i]=T.test(i)?f(i,b||this.context):i);while(g&&g.ownerDocument&&g!==b){for(i in j)h=j[i],(h.jquery?h.index(g)>-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=T.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(l?l.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a||typeof a=="string")return f.inArray(this[0],a?f(a):this.parent().children());return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(V(c[0])||V(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=S.call(arguments);O.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!U[a]?f.unique(e):e,(this.length>1||Q.test(d))&&P.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var X=/ jQuery\d+="(?:\d+|null)"/g,Y=/^\s+/,Z=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,$=/<([\w:]+)/,_=/<tbody/i,ba=/<|&#?\w+;/,bb=/<(?:script|object|embed|option|style)/i,bc=/checked\s*(?:[^=]|=\s*.checked.)/i,bd=/\/(java|ecma)script/i,be=/^\s*<!(?:\[CDATA\[|\-\-)/,bf={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,"",""]};bf.optgroup=bf.option,bf.tbody=bf.tfoot=bf.colgroup=bf.caption=bf.thead,bf.th=bf.td,f.support.htmlSerialize||(bf._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(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,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(X,""):null;if(typeof a=="string"&&!bb.test(a)&&(f.support.leadingWhitespace||!Y.test(a))&&!bf[($.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Z,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bc.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bg(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bm)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i;b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof a[0]=="string"&&a[0].length<512&&i===c&&a[0].charAt(0)==="<"&&!bb.test(a[0])&&(f.support.checkClone||!bc.test(a[0]))&&(g=!0,h=f.fragments[a[0]],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[a[0]]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j
-)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bi(a,d),e=bj(a),g=bj(d);for(h=0;e[h];++h)bi(e[h],g[h])}if(b){bh(a,d);if(c){e=bj(a),g=bj(d);for(h=0;e[h];++h)bh(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!ba.test(k))k=b.createTextNode(k);else{k=k.replace(Z,"<$1></$2>");var l=($.exec(k)||["",""])[1].toLowerCase(),m=bf[l]||bf._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=_.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&Y.test(k)&&o.insertBefore(b.createTextNode(Y.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bl(k[i]);else bl(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||bd.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.expando,g=f.event.special,h=f.support.deleteExpando;for(var i=0,j;(j=a[i])!=null;i++){if(j.nodeName&&f.noData[j.nodeName.toLowerCase()])continue;c=j[f.expando];if(c){b=d[c]&&d[c][e];if(b&&b.events){for(var k in b.events)g[k]?f.event.remove(j,k):f.removeEvent(j,k,b.handle);b.handle&&(b.handle.elem=null)}h?delete j[f.expando]:j.removeAttribute&&j.removeAttribute(f.expando),delete d[c]}}}});var bn=/alpha\([^)]*\)/i,bo=/opacity=([^)]*)/,bp=/([A-Z]|^ms)/g,bq=/^-?\d+(?:px)?$/i,br=/^-?\d/,bs=/^[+\-]=/,bt=/[^+\-\.\de]+/g,bu={position:"absolute",visibility:"hidden",display:"block"},bv=["Left","Right"],bw=["Top","Bottom"],bx,by,bz;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bx(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d;if(h==="number"&&isNaN(d)||d==null)return;h==="string"&&bs.test(d)&&(d=+d.replace(bt,"")+parseFloat(f.css(a,c)),h="number"),h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bx)return bx(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return bA(a,b,d);f.swap(a,bu,function(){e=bA(a,b,d)});return e}},set:function(a,b){if(!bq.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bo.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle;c.zoom=1;var e=f.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.filter=bn.test(g)?g.replace(bn,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bx(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(by=function(a,c){var d,e,g;c=c.replace(bp,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bz=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bq.test(d)&&br.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bx=by||bz,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bB=/%20/g,bC=/\[\]$/,bD=/\r?\n/g,bE=/#.*$/,bF=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bG=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bH=/^(?:about|app|app\-storage|.+\-extension|file|widget):$/,bI=/^(?:GET|HEAD)$/,bJ=/^\/\//,bK=/\?/,bL=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bM=/^(?:select|textarea)/i,bN=/\s+/,bO=/([?&])_=[^&]*/,bP=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bQ=f.fn.load,bR={},bS={},bT,bU;try{bT=e.href}catch(bV){bT=c.createElement("a"),bT.href="",bT=bT.href}bU=bP.exec(bT.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bQ)return bQ.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bL,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bM.test(this.nodeName)||bG.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bD,"\r\n")}}):{name:b.name,value:c.replace(bD,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?f.extend(!0,a,f.ajaxSettings,b):(b=a,a=f.extend(!0,f.ajaxSettings,b));for(var c in{context:1,url:1})c in b?a[c]=b[c]:c in f.ajaxSettings&&(a[c]=f.ajaxSettings[c]);return a},ajaxSettings:{url:bT,isLocal:bH.test(bU[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":"*/*"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML}},ajaxPrefilter:bW(bR),ajaxTransport:bW(bS),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a?4:0;var o,r,u,w=l?bZ(d,v,l):b,x,y;if(a>=200&&a<300||a===304){if(d.ifModified){if(x=v.getResponseHeader("Last-Modified"))f.lastModified[k]=x;if(y=v.getResponseHeader("Etag"))f.etag[k]=y}if(a===304)c="notmodified",o=!0;else try{r=b$(d,w),c="success",o=!0}catch(z){c="parsererror",u=z}}else{u=c;if(!c||a)c="error",a<0&&(a=0)}v.status=a,v.statusText=c,o?h.resolveWith(e,[r,c,v]):h.rejectWith(e,[v,c,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.resolveWith(e,[v,c]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f._Deferred(),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bF.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.done,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bE,"").replace(bJ,bU[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bN),d.crossDomain==null&&(r=bP.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bU[1]&&r[2]==bU[2]&&(r[3]||(r[1]==="http:"?80:443))==(bU[3]||(bU[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bX(bR,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bI.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bK.test(d.url)?"&":"?")+d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bO,"$1_="+x);d.url=y+(y===d.url?(bK.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", */*; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bX(bS,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){status<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)bY(g,a[g],c,e);return d.join("&").replace(bB,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ca,l),b.url===j&&(e&&(k=k.replace(ca,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cb&&delete cd[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn,co=a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cr("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cs(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cr("hide",3),a,b,c);for(var d=0,e=this.length;d<e;d++)if(this[d].style){var g=f.css(this[d],"display");g!=="none"&&!f._data(this[d],"olddisplay")&&f._data(this[d],"olddisplay",g)}for(d=0;d<e;d++)this[d].style&&(this[d].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cr("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return this[e.queue===!1?"each":"queue"](function(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(f.support.inlineBlockNeedsLayout?(j=cs(this.nodeName),j==="inline"?this.style.display="inline-block":(this.style.display="inline",this.style.zoom=1)):this.style.display="inline-block"))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)k=new f.fx(this,b,i),h=a[i],cj.test(h)?k[h==="toggle"?d?"show":"hide":h]():(l=ck.exec(h),m=k.cur(),l?(n=parseFloat(l[2]),o=l[3]||(f.cssNumber[i]?"":"px"),o!=="px"&&(f.style(this,i,(n||1)+o),m=(n||1)/k.cur()*m,f.style(this,i,m+o)),l[1]&&(n=(l[1]==="-="?-1:1)*n+m),k.custom(m,n,o)):k.custom(m,h,""));return!0})},stop:function(a,b){a&&this.queue([]),this.each(function(){var a=f.timers,c=a.length;b||f._unmark(!0,this);while(c--)a[c].elem===this&&(b&&a[c](!0),a.splice(c,1))}),b||this.dequeue();return this}}),f.each({slideDown:cr("show",1),slideUp:cr("hide",1),slideToggle:cr("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default,d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue!==!1?f.dequeue(this):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.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,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,b,c){function h(a){return d.step(a)}var d=this,e=f.fx,g;this.startTime=cn||cp(),this.start=a,this.end=b,this.unit=c||this.unit||(f.cssNumber[this.prop]?"":"px"),this.now=this.start,this.pos=this.state=0,h.elem=this.elem,h()&&f.timers.push(h)&&!cl&&(co?(cl=!0,g=function(){cl&&(co(g),e.tick())},co(g)):cl=setInterval(e.tick,e.interval))},show:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.show=!0,this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b=cn||cp(),c=!0,d=this.elem,e=this.options,g,h;if(a||b>=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b<a.length;++b)a[b]()||a.splice(b--,1);a.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cl),cl=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){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:a.elem[a.prop]=a.now}}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var ct=/^t(?:able|d|h)$/i,cu=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cv(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);f.offset.initialize();var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.offset.supportsFixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.offset.doesNotAddBorder&&(!f.offset.doesAddBorderForTableAndCells||!ct.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.offset.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.offset.supportsFixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={initialize:function(){var a=c.body,b=c.createElement("div"),d,e,g,h,i=parseFloat(f.css(a,"marginTop"))||0,j="<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>";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.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!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cu.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cu.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cv(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cv(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c];return e.document.compatMode==="CSS1Compat"&&g||e.document.body["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var h=f.css(e,d),i=parseFloat(h);return f.isNaN(i)?h:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file
+/*! jQuery v1.8.3 jquery.com | jquery.org/license */
+(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r<i;r++)v.event.add(t,n,u[n][r])}o.data&&(o.data=v.extend({},o.data))}function Ot(e,t){var n;if(t.nodeType!==1)return;t.clearAttributes&&t.clearAttributes(),t.mergeAttributes&&t.mergeAttributes(e),n=t.nodeName.toLowerCase(),n==="object"?(t.parentNode&&(t.outerHTML=e.outerHTML),v.support.html5Clone&&e.innerHTML&&!v.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):n==="input"&&Et.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):n==="option"?t.selected=e.defaultSelected:n==="input"||n==="textarea"?t.defaultValue=e.defaultValue:n==="script"&&t.text!==e.text&&(t.text=e.text),t.removeAttribute(v.expando)}function Mt(e){return typeof e.getElementsByTagName!="undefined"?e.getElementsByTagName("*"):typeof e.querySelectorAll!="undefined"?e.querySelectorAll("*"):[]}function _t(e){Et.test(e.type)&&(e.defaultChecked=e.checked)}function Qt(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Jt.length;while(i--){t=Jt[i]+n;if(t in e)return t}return r}function Gt(e,t){return e=t||e,v.css(e,"display")==="none"||!v.contains(e.ownerDocument,e)}function Yt(e,t){var n,r,i=[],s=0,o=e.length;for(;s<o;s++){n=e[s];if(!n.style)continue;i[s]=v._data(n,"olddisplay"),t?(!i[s]&&n.style.display==="none"&&(n.style.display=""),n.style.display===""&&Gt(n)&&(i[s]=v._data(n,"olddisplay",nn(n.nodeName)))):(r=Dt(n,"display"),!i[s]&&r!=="none"&&v._data(n,"olddisplay",r))}for(s=0;s<o;s++){n=e[s];if(!n.style)continue;if(!t||n.style.display==="none"||n.style.display==="")n.style.display=t?i[s]||"":"none"}return e}function Zt(e,t,n){var r=Rt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function en(e,t,n,r){var i=n===(r?"border":"content")?4:t==="width"?1:0,s=0;for(;i<4;i+=2)n==="margin"&&(s+=v.css(e,n+$t[i],!0)),r?(n==="content"&&(s-=parseFloat(Dt(e,"padding"+$t[i]))||0),n!=="margin"&&(s-=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0)):(s+=parseFloat(Dt(e,"padding"+$t[i]))||0,n!=="padding"&&(s+=parseFloat(Dt(e,"border"+$t[i]+"Width"))||0));return s}function tn(e,t,n){var r=t==="width"?e.offsetWidth:e.offsetHeight,i=!0,s=v.support.boxSizing&&v.css(e,"boxSizing")==="border-box";if(r<=0||r==null){r=Dt(e,t);if(r<0||r==null)r=e.style[t];if(Ut.test(r))return r;i=s&&(v.support.boxSizingReliable||r===e.style[t]),r=parseFloat(r)||0}return r+en(e,t,n||(s?"border":"content"),i)+"px"}function nn(e){if(Wt[e])return Wt[e];var t=v("<"+e+">").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write("<!doctype html><html><body>"),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u<a;u++)r=o[u],s=/^\+/.test(r),s&&(r=r.substr(1)||"*"),i=e[r]=e[r]||[],i[s?"unshift":"push"](n)}}function kn(e,n,r,i,s,o){s=s||n.dataTypes[0],o=o||{},o[s]=!0;var u,a=e[s],f=0,l=a?a.length:0,c=e===Sn;for(;f<l&&(c||!u);f++)u=a[f](n,r,i),typeof u=="string"&&(!c||o[u]?u=t:(n.dataTypes.unshift(u),u=kn(e,n,r,i,u,o)));return(c||!u)&&!o["*"]&&(u=kn(e,n,r,i,"*",o)),u}function Ln(e,n){var r,i,s=v.ajaxSettings.flatOptions||{};for(r in n)n[r]!==t&&((s[r]?e:i||(i={}))[r]=n[r]);i&&v.extend(!0,e,i)}function An(e,n,r){var i,s,o,u,a=e.contents,f=e.dataTypes,l=e.responseFields;for(s in l)s in r&&(n[l[s]]=r[s]);while(f[0]==="*")f.shift(),i===t&&(i=e.mimeType||n.getResponseHeader("content-type"));if(i)for(s in a)if(a[s]&&a[s].test(i)){f.unshift(s);break}if(f[0]in r)o=f[0];else{for(s in r){if(!f[0]||e.converters[s+" "+f[0]]){o=s;break}u||(u=s)}o=o||u}if(o)return o!==f[0]&&f.unshift(o),r[o]}function On(e,t){var n,r,i,s,o=e.dataTypes.slice(),u=o[0],a={},f=0;e.dataFilter&&(t=e.dataFilter(t,e.dataType));if(o[1])for(n in e.converters)a[n.toLowerCase()]=e.converters[n];for(;i=o[++f];)if(i!=="*"){if(u!=="*"&&u!==i){n=a[u+" "+i]||a["* "+i];if(!n)for(r in a){s=r.split(" ");if(s[1]===i){n=a[u+" "+s[0]]||a["* "+s[0]];if(n){n===!0?n=a[r]:a[r]!==!0&&(i=s[0],o.splice(f--,0,i));break}}}if(n!==!0)if(n&&e["throws"])t=n(t);else try{t=n(t)}catch(l){return{state:"parsererror",error:n?l:"No conversion from "+u+" to "+i}}}u=i}return{state:"success",data:t}}function Fn(){try{return new e.XMLHttpRequest}catch(t){}}function In(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}function $n(){return setTimeout(function(){qn=t},0),qn=v.now()}function Jn(e,t){v.each(t,function(t,n){var r=(Vn[t]||[]).concat(Vn["*"]),i=0,s=r.length;for(;i<s;i++)if(r[i].call(e,t,n))return})}function Kn(e,t,n){var r,i=0,s=0,o=Xn.length,u=v.Deferred().always(function(){delete a.elem}),a=function(){var t=qn||$n(),n=Math.max(0,f.startTime+f.duration-t),r=n/f.duration||0,i=1-r,s=0,o=f.tweens.length;for(;s<o;s++)f.tweens[s].run(i);return u.notifyWith(e,[f,i,n]),i<1&&o?n:(u.resolveWith(e,[f]),!1)},f=u.promise({elem:e,props:v.extend({},t),opts:v.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:qn||$n(),duration:n.duration,tweens:[],createTween:function(t,n,r){var i=v.Tween(e,f.opts,t,n,f.opts.specialEasing[t]||f.opts.easing);return f.tweens.push(i),i},stop:function(t){var n=0,r=t?f.tweens.length:0;for(;n<r;n++)f.tweens[n].run(1);return t?u.resolveWith(e,[f,t]):u.rejectWith(e,[f,t]),this}}),l=f.props;Qn(l,f.opts.specialEasing);for(;i<o;i++){r=Xn[i].call(f,e,l,f.opts);if(r)return r}return Jn(f,l),v.isFunction(f.opts.start)&&f.opts.start.call(e,f),v.fx.timer(v.extend(a,{anim:f,queue:f.opts.queue,elem:e})),f.progress(f.opts.progress).done(f.opts.done,f.opts.complete).fail(f.opts.fail).always(f.opts.always)}function Qn(e,t){var n,r,i,s,o;for(n in e){r=v.camelCase(n),i=t[r],s=e[n],v.isArray(s)&&(i=s[1],s=e[n]=s[0]),n!==r&&(e[r]=s,delete e[n]),o=v.cssHooks[r];if(o&&"expand"in o){s=o.expand(s),delete e[r];for(n in s)n in e||(e[n]=s[n],t[n]=i)}else t[r]=i}}function Gn(e,t,n){var r,i,s,o,u,a,f,l,c,h=this,p=e.style,d={},m=[],g=e.nodeType&&Gt(e);n.queue||(l=v._queueHooks(e,"fx"),l.unqueued==null&&(l.unqueued=0,c=l.empty.fire,l.empty.fire=function(){l.unqueued||c()}),l.unqueued++,h.always(function(){h.always(function(){l.unqueued--,v.queue(e,"fx").length||l.empty.fire()})})),e.nodeType===1&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],v.css(e,"display")==="inline"&&v.css(e,"float")==="none"&&(!v.support.inlineBlockNeedsLayout||nn(e.nodeName)==="inline"?p.display="inline-block":p.zoom=1)),n.overflow&&(p.overflow="hidden",v.support.shrinkWrapBlocks||h.done(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t){s=t[r];if(Un.exec(s)){delete t[r],a=a||s==="toggle";if(s===(g?"hide":"show"))continue;m.push(r)}}o=m.length;if(o){u=v._data(e,"fxshow")||v._data(e,"fxshow",{}),"hidden"in u&&(g=u.hidden),a&&(u.hidden=!g),g?v(e).show():h.done(function(){v(e).hide()}),h.done(function(){var t;v.removeData(e,"fxshow",!0);for(t in d)v.style(e,t,d[t])});for(r=0;r<o;r++)i=m[r],f=h.createTween(i,g?u[i]:0),d[i]=u[i]||v.style(e,i),i in u||(u[i]=f.start,g&&(f.end=f.start,f.start=i==="width"||i==="height"?1:0))}}function Yn(e,t,n,r,i){return new Yn.prototype.init(e,t,n,r,i)}function Zn(e,t){var n,r={height:e},i=0;t=t?1:0;for(;i<4;i+=2-t)n=$t[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}function tr(e){return v.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:!1}var n,r,i=e.document,s=e.location,o=e.navigator,u=e.jQuery,a=e.$,f=Array.prototype.push,l=Array.prototype.slice,c=Array.prototype.indexOf,h=Object.prototype.toString,p=Object.prototype.hasOwnProperty,d=String.prototype.trim,v=function(e,t){return new v.fn.init(e,t,n)},m=/[\-+]?(?:\d*\.|)\d+(?:[eE][\-+]?\d+|)/.source,g=/\S/,y=/\s+/,b=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,w=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a<f;a++)if((e=arguments[a])!=null)for(n in e){r=u[n],i=e[n];if(u===i)continue;l&&i&&(v.isPlainObject(i)||(s=v.isArray(i)))?(s?(s=!1,o=r&&v.isArray(r)?r:[]):o=r&&v.isPlainObject(r)?r:{},u[n]=v.extend(l,o,i)):i!==t&&(u[n]=i)}return u},v.extend({noConflict:function(t){return e.$===v&&(e.$=a),t&&e.jQuery===v&&(e.jQuery=u),v},isReady:!1,readyWait:1,holdReady:function(e){e?v.readyWait++:v.ready(!0)},ready:function(e){if(e===!0?--v.readyWait:v.isReady)return;if(!i.body)return setTimeout(v.ready,1);v.isReady=!0;if(e!==!0&&--v.readyWait>0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s<o;)if(n.apply(e[s++],r)===!1)break}else if(u){for(i in e)if(n.call(e[i],i,e[i])===!1)break}else for(;s<o;)if(n.call(e[s],s,e[s++])===!1)break;return e},trim:d&&!d.call("\ufeff\u00a0")?function(e){return e==null?"":d.call(e)}:function(e){return e==null?"":(e+"").replace(b,"")},makeArray:function(e,t){var n,r=t||[];return e!=null&&(n=v.type(e),e.length==null||n==="string"||n==="function"||n==="regexp"||v.isWindow(e)?f.call(r,e):v.merge(r,e)),r},inArray:function(e,t,n){var r;if(t){if(c)return c.call(t,e,n);r=t.length,n=n?n<0?Math.max(0,r+n):n:0;for(;n<r;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,s=0;if(typeof r=="number")for(;s<r;s++)e[i++]=n[s];else while(n[s]!==t)e[i++]=n[s++];return e.length=i,e},grep:function(e,t,n){var r,i=[],s=0,o=e.length;n=!!n;for(;s<o;s++)r=!!t(e[s],s),n!==r&&i.push(e[s]);return i},map:function(e,n,r){var i,s,o=[],u=0,a=e.length,f=e instanceof v||a!==t&&typeof a=="number"&&(a>0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u<a;u++)i=n(e[u],u,r),i!=null&&(o[o.length]=i);else for(s in e)i=n(e[s],s,r),i!=null&&(o[o.length]=i);return o.concat.apply([],o)},guid:1,proxy:function(e,n){var r,i,s;return typeof n=="string"&&(r=e[n],n=e,e=r),v.isFunction(e)?(i=l.call(arguments,2),s=function(){return e.apply(n,i.concat(l.call(arguments)))},s.guid=e.guid=e.guid||v.guid++,s):t},access:function(e,n,r,i,s,o,u){var a,f=r==null,l=0,c=e.length;if(r&&typeof r=="object"){for(l in r)v.access(e,n,l,r[l],1,o,i);s=1}else if(i!==t){a=u===t&&v.isFunction(i),f&&(a?(a=n,n=function(e,t,n){return a.call(v(e),n)}):(n.call(e,i),n=null));if(n)for(;l<c;l++)n(e[l],r,a?i.call(e[l],l,n(e[l],r)):i,u);s=1}return s?e:f?n.call(e):c?n(e[0],r):o},now:function(){return(new Date).getTime()}}),v.ready.promise=function(t){if(!r){r=v.Deferred();if(i.readyState==="complete")setTimeout(v.ready,1);else if(i.addEventListener)i.addEventListener("DOMContentLoaded",A,!1),e.addEventListener("load",v.ready,!1);else{i.attachEvent("onreadystatechange",A),e.attachEvent("onload",v.ready);var n=!1;try{n=e.frameElement==null&&i.documentElement}catch(s){}n&&n.doScroll&&function o(){if(!v.isReady){try{n.doScroll("left")}catch(e){return setTimeout(o,50)}v.ready()}}()}}return r.promise(t)},v.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(e,t){O["[object "+t+"]"]=t.toLowerCase()}),n=v(i);var M={};v.Callbacks=function(e){e=typeof e=="string"?M[e]||_(e):v.extend({},e);var n,r,i,s,o,u,a=[],f=!e.once&&[],l=function(t){n=e.memory&&t,r=!0,u=s||0,s=0,o=a.length,i=!0;for(;a&&u<o;u++)if(a[u].apply(t[0],t[1])===!1&&e.stopOnFalse){n=!1;break}i=!1,a&&(f?f.length&&l(f.shift()):n?a=[]:c.disable())},c={add:function(){if(a){var t=a.length;(function r(t){v.each(t,function(t,n){var i=v.type(n);i==="function"?(!e.unique||!c.has(n))&&a.push(n):n&&n.length&&i!=="string"&&r(n)})})(arguments),i?o=a.length:n&&(s=t,l(n))}return this},remove:function(){return a&&v.each(arguments,function(e,t){var n;while((n=v.inArray(t,a,n))>-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t<r;t++)n[t]&&v.isFunction(n[t].promise)?n[t].promise().done(o(t,f,n)).fail(s.reject).progress(o(t,a,u)):--i}return i||s.resolveWith(f,n),s.promise()}}),v.support=function(){var t,n,r,s,o,u,a,f,l,c,h,p=i.createElement("div");p.setAttribute("className","t"),p.innerHTML=" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="<table><tr><td></td><td>t</td></tr></table>",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="<div></div>",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i<s;i++)delete r[t[i]];if(!(n?B:v.isEmptyObject)(r))return}}if(!n){delete u[a].data;if(!B(u[a]))return}o?v.cleanData([e],!0):v.support.deleteExpando||u!=u.window?delete u[a]:u[a]=null},_data:function(e,t,n){return v.data(e,t,n,!0)},acceptData:function(e){var t=e.nodeName&&v.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),v.fn.extend({data:function(e,n){var r,i,s,o,u,a=this[0],f=0,l=null;if(e===t){if(this.length){l=v.data(a);if(a.nodeType===1&&!v._data(a,"parsedAttrs")){s=a.attributes;for(u=s.length;f<u;f++)o=s[f].name,o.indexOf("data-")||(o=v.camelCase(o.substring(5)),H(a,o,l[o]));v._data(a,"parsedAttrs",!0)}}return l}return typeof e=="object"?this.each(function(){v.data(this,e)}):(r=e.split(".",2),r[1]=r[1]?"."+r[1]:"",i=r[1]+"!",v.access(this,function(n){if(n===t)return l=this.triggerHandler("getData"+i,[r[0]]),l===t&&a&&(l=v.data(a,e),l=H(a,e,l)),l===t&&r[1]?this.data(r[0]):l;r[1]=n,this.each(function(){var t=v(this);t.triggerHandler("setData"+i,r),v.data(this,e,n),t.triggerHandler("changeData"+i,r)})},null,n,arguments.length>1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length<r?v.queue(this[0],e):n===t?this:this.each(function(){var t=v.queue(this,e,n);v._queueHooks(this,e),e==="fx"&&t[0]!=="inprogress"&&v.dequeue(this,e)})},dequeue:function(e){return this.each(function(){v.dequeue(this,e)})},delay:function(e,t){return e=v.fx?v.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,s=v.Deferred(),o=this,u=this.length,a=function(){--i||s.resolveWith(o,[o])};typeof e!="string"&&(n=e,e=t),e=e||"fx";while(u--)r=v._data(o[u],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(a));return a(),s.promise(n)}});var j,F,I,q=/[\t\r\n]/g,R=/\r/g,U=/^(?:button|input)$/i,z=/^(?:button|input|object|select|textarea)$/i,W=/^a(?:rea|)$/i,X=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,V=v.support.getSetAttribute;v.fn.extend({attr:function(e,t){return v.access(this,v.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n<r;n++){i=this[n];if(i.nodeType===1)if(!i.className&&t.length===1)i.className=e;else{s=" "+i.className+" ";for(o=0,u=t.length;o<u;o++)s.indexOf(" "+t[o]+" ")<0&&(s+=t[o]+" ");i.className=v.trim(s)}}}return this},removeClass:function(e){var n,r,i,s,o,u,a;if(v.isFunction(e))return this.each(function(t){v(this).removeClass(e.call(this,t,this.className))});if(e&&typeof e=="string"||e===t){n=(e||"").split(y);for(u=0,a=this.length;u<a;u++){i=this[u];if(i.nodeType===1&&i.className){r=(" "+i.className+" ").replace(q," ");for(s=0,o=n.length;s<o;s++)while(r.indexOf(" "+n[s]+" ")>=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n<r;n++)if(this[n].nodeType===1&&(" "+this[n].className+" ").replace(q," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a<u;a++){n=r[a];if((n.selected||a===i)&&(v.support.optDisabled?!n.disabled:n.getAttribute("disabled")===null)&&(!n.parentNode.disabled||!v.nodeName(n.parentNode,"optgroup"))){t=v(n).val();if(s)return t;o.push(t)}}return o},set:function(e,t){var n=v.makeArray(t);return v(e).find("option").each(function(){this.selected=v.inArray(v(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o<r.length;o++)i=r[o],i&&(n=v.propFix[i]||i,s=X.test(i),s||v.attr(e,i,""),e.removeAttribute(V?i:n),s&&n in e&&(e[n]=!1))}},attrHooks:{type:{set:function(e,t){if(U.test(e.nodeName)&&e.parentNode)v.error("type property can't be changed");else if(!v.support.radioValue&&t==="radio"&&v.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}},value:{get:function(e,t){return j&&v.nodeName(e,"button")?j.get(e,t):t in e?e.value:null},set:function(e,t,n){if(j&&v.nodeName(e,"button"))return j.set(e,t,n);e.value=t}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,s,o,u=e.nodeType;if(!e||u===3||u===8||u===2)return;return o=u!==1||!v.isXMLDoc(e),o&&(n=v.propFix[n]||n,s=v.propHooks[n]),r!==t?s&&"set"in s&&(i=s.set(e,r,n))!==t?i:e[n]=r:s&&"get"in s&&(i=s.get(e,n))!==null?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):z.test(e.nodeName)||W.test(e.nodeName)&&e.href?0:t}}}}),F={get:function(e,n){var r,i=v.prop(e,n);return i===!0||typeof i!="boolean"&&(r=e.getAttributeNode(n))&&r.nodeValue!==!1?n.toLowerCase():t},set:function(e,t,n){var r;return t===!1?v.removeAttr(e,n):(r=v.propFix[n]||n,r in e&&(e[r]=!0),e.setAttribute(n,n.toLowerCase())),n}},V||(I={name:!0,id:!0,coords:!0},j=v.valHooks.button={get:function(e,n){var r;return r=e.getAttributeNode(n),r&&(I[n]?r.value!=="":r.specified)?r.value:t},set:function(e,t,n){var r=e.getAttributeNode(n);return r||(r=i.createAttribute(n),e.setAttributeNode(r)),r.value=t+""}},v.each(["width","height"],function(e,t){v.attrHooks[t]=v.extend(v.attrHooks[t],{set:function(e,n){if(n==="")return e.setAttribute(t,"auto"),n}})}),v.attrHooks.contenteditable={get:j.get,set:function(e,t,n){t===""&&(t="false"),j.set(e,t,n)}}),v.support.hrefNormalized||v.each(["href","src","width","height"],function(e,n){v.attrHooks[n]=v.extend(v.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return r===null?t:r}})}),v.support.style||(v.attrHooks.style={get:function(e){return e.style.cssText.toLowerCase()||t},set:function(e,t){return e.style.cssText=t+""}}),v.support.optSelected||(v.propHooks.selected=v.extend(v.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),v.support.enctype||(v.propFix.enctype="encoding"),v.support.checkOn||v.each(["radio","checkbox"],function(){v.valHooks[this]={get:function(e){return e.getAttribute("value")===null?"on":e.value}}}),v.each(["radio","checkbox"],function(){v.valHooks[this]=v.extend(v.valHooks[this],{set:function(e,t){if(v.isArray(t))return e.checked=v.inArray(v(e).val(),t)>=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f<n.length;f++){l=J.exec(n[f])||[],c=l[1],h=(l[2]||"").split(".").sort(),g=v.event.special[c]||{},c=(s?g.delegateType:g.bindType)||c,g=v.event.special[c]||{},p=v.extend({type:c,origType:l[1],data:i,handler:r,guid:r.guid,selector:s,needsContext:s&&v.expr.match.needsContext.test(s),namespace:h.join(".")},d),m=a[c];if(!m){m=a[c]=[],m.delegateCount=0;if(!g.setup||g.setup.call(e,i,h,u)===!1)e.addEventListener?e.addEventListener(c,u,!1):e.attachEvent&&e.attachEvent("on"+c,u)}g.add&&(g.add.call(e,p),p.handler.guid||(p.handler.guid=r.guid)),s?m.splice(m.delegateCount++,0,p):m.push(p),v.event.global[c]=!0}e=null},global:{},remove:function(e,t,n,r,i){var s,o,u,a,f,l,c,h,p,d,m,g=v.hasData(e)&&v._data(e);if(!g||!(h=g.events))return;t=v.trim(Z(t||"")).split(" ");for(s=0;s<t.length;s++){o=J.exec(t[s])||[],u=a=o[1],f=o[2];if(!u){for(u in h)v.event.remove(e,u+t[s],n,r,!0);continue}p=v.event.special[u]||{},u=(r?p.delegateType:p.bindType)||u,d=h[u]||[],l=d.length,f=f?new RegExp("(^|\\.)"+f.split(".").sort().join("\\.(?:.*\\.|)")+"(\\.|$)"):null;for(c=0;c<d.length;c++)m=d[c],(i||a===m.origType)&&(!n||n.guid===m.guid)&&(!f||f.test(m.namespace))&&(!r||r===m.selector||r==="**"&&m.selector)&&(d.splice(c--,1),m.selector&&d.delegateCount--,p.remove&&p.remove.call(e,m));d.length===0&&l!==d.length&&((!p.teardown||p.teardown.call(e,f,g.handle)===!1)&&v.removeEvent(e,u,g.handle),delete h[u])}v.isEmptyObject(h)&&(delete g.handle,v.removeData(e,"events",!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(n,r,s,o){if(!s||s.nodeType!==3&&s.nodeType!==8){var u,a,f,l,c,h,p,d,m,g,y=n.type||n,b=[];if(Y.test(y+v.event.triggered))return;y.indexOf("!")>=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f<m.length&&!n.isPropagationStopped();f++)l=m[f][0],n.type=m[f][1],d=(v._data(l,"events")||{})[n.type]&&v._data(l,"handle"),d&&d.apply(l,r),d=h&&l[h],d&&v.acceptData(l)&&d.apply&&d.apply(l,r)===!1&&n.preventDefault();return n.type=y,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(s.ownerDocument,r)===!1)&&(y!=="click"||!v.nodeName(s,"a"))&&v.acceptData(s)&&h&&s[y]&&(y!=="focus"&&y!=="blur"||n.target.offsetWidth!==0)&&!v.isWindow(s)&&(c=s[h],c&&(s[h]=null),v.event.triggered=y,s[y](),v.event.triggered=t,c&&(s[h]=c)),n.result}return},dispatch:function(n){n=v.event.fix(n||e.event);var r,i,s,o,u,a,f,c,h,p,d=(v._data(this,"events")||{})[n.type]||[],m=d.delegateCount,g=l.call(arguments),y=!n.exclusive&&!n.namespace,b=v.event.special[n.type]||{},w=[];g[0]=n,n.delegateTarget=this;if(b.preDispatch&&b.preDispatch.call(this,n)===!1)return;if(m&&(!n.button||n.type!=="click"))for(s=n.target;s!=this;s=s.parentNode||this)if(s.disabled!==!0||n.type!=="click"){u={},f=[];for(r=0;r<m;r++)c=d[r],h=c.selector,u[h]===t&&(u[h]=c.needsContext?v(h,this).index(s)>=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r<w.length&&!n.isPropagationStopped();r++){a=w[r],n.currentTarget=a.elem;for(i=0;i<a.matches.length&&!n.isImmediatePropagationStopped();i++){c=a.matches[i];if(y||!n.namespace&&!c.namespace||n.namespace_re&&n.namespace_re.test(c.namespace))n.data=c.data,n.handleObj=c,o=((v.event.special[c.origType]||{}).handle||c.handler).apply(a.elem,g),o!==t&&(n.result=o,o===!1&&(n.preventDefault(),n.stopPropagation()))}}return b.postDispatch&&b.postDispatch.call(this,n),n.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return e.which==null&&(e.which=t.charCode!=null?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,s,o,u=n.button,a=n.fromElement;return e.pageX==null&&n.clientX!=null&&(r=e.target.ownerDocument||i,s=r.documentElement,o=r.body,e.pageX=n.clientX+(s&&s.scrollLeft||o&&o.scrollLeft||0)-(s&&s.clientLeft||o&&o.clientLeft||0),e.pageY=n.clientY+(s&&s.scrollTop||o&&o.scrollTop||0)-(s&&s.clientTop||o&&o.clientTop||0)),!e.relatedTarget&&a&&(e.relatedTarget=a===e.target?n.toElement:a),!e.which&&u!==t&&(e.which=u&1?1:u&2?3:u&4?2:0),e}},fix:function(e){if(e[v.expando])return e;var t,n,r=e,s=v.event.fixHooks[e.type]||{},o=s.props?this.props.concat(s.props):this.props;e=v.Event(r);for(t=o.length;t;)n=o[--t],e[n]=r[n];return e.target||(e.target=r.srcElement||i),e.target.nodeType===3&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,r):e},special:{load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(e,t,n){v.isWindow(this)&&(this.onbeforeunload=n)},teardown:function(e,t){this.onbeforeunload===t&&(this.onbeforeunload=null)}}},simulate:function(e,t,n,r){var i=v.extend(new v.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?v.event.trigger(i,null,t):v.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},v.event.handle=v.event.dispatch,v.removeEvent=i.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]=="undefined"&&(e[r]=null),e.detachEvent(r,n))},v.Event=function(e,t){if(!(this instanceof v.Event))return new v.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?tt:et):this.type=e,t&&v.extend(this,t),this.timeStamp=e&&e.timeStamp||v.now(),this[v.expando]=!0},v.Event.prototype={preventDefault:function(){this.isDefaultPrevented=tt;var e=this.originalEvent;if(!e)return;e.preventDefault?e.preventDefault():e.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=tt;var e=this.originalEvent;if(!e)return;e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=tt,this.stopPropagation()},isDefaultPrevented:et,isPropagationStopped:et,isImmediatePropagationStopped:et},v.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){v.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,s=e.handleObj,o=s.selector;if(!i||i!==r&&!v.contains(r,i))e.type=s.origType,n=s.handler.apply(this,arguments),e.type=t;return n}}}),v.support.submitBubbles||(v.event.special.submit={setup:function(){if(v.nodeName(this,"form"))return!1;v.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=v.nodeName(n,"input")||v.nodeName(n,"button")?n.form:t;r&&!v._data(r,"_submit_attached")&&(v.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),v._data(r,"_submit_attached",!0))})},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&v.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){if(v.nodeName(this,"form"))return!1;v.event.remove(this,"._submit")}}),v.support.changeBubbles||(v.event.special.change={setup:function(){if($.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")v.event.add(this,"propertychange._change",function(e){e.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),v.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),v.event.simulate("change",this,e,!0)});return!1}v.event.add(this,"beforeactivate._change",function(e){var t=e.target;$.test(t.nodeName)&&!v._data(t,"_change_attached")&&(v.event.add(t,"change._change",function(e){this.parentNode&&!e.isSimulated&&!e.isTrigger&&v.event.simulate("change",this.parentNode,e,!0)}),v._data(t,"_change_attached",!0))})},handle:function(e){var t=e.target;if(this!==t||e.isSimulated||e.isTrigger||t.type!=="radio"&&t.type!=="checkbox")return e.handleObj.handler.apply(this,arguments)},teardown:function(){return v.event.remove(this,"._change"),!$.test(this.nodeName)}}),v.support.focusinBubbles||v.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){v.event.simulate(t,e.target,v.event.fix(e),!0)};v.event.special[t]={setup:function(){n++===0&&i.addEventListener(e,r,!0)},teardown:function(){--n===0&&i.removeEventListener(e,r,!0)}}}),v.fn.extend({on:function(e,n,r,i,s){var o,u;if(typeof e=="object"){typeof n!="string"&&(r=r||n,n=t);for(u in e)this.on(u,n,r,e[u],s);return this}r==null&&i==null?(i=n,r=n=t):i==null&&(typeof n=="string"?(i=r,r=t):(i=r,r=n,n=t));if(i===!1)i=et;else if(!i)return this;return s===1&&(o=i,i=function(e){return v().off(e),o.apply(this,arguments)},i.guid=o.guid||(o.guid=v.guid++)),this.each(function(){v.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,s;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,v(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if(typeof e=="object"){for(s in e)this.off(s,n,e[s]);return this}if(n===!1||typeof n=="function")r=n,n=t;return r===!1&&(r=et),this.each(function(){v.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},live:function(e,t,n){return v(this.context).on(e,this.selector,t,n),this},die:function(e,t){return v(this.context).off(e,this.selector||"**",t),this},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return arguments.length===1?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){v.event.trigger(e,t,this)})},triggerHandler:function(e,t){if(this[0])return v.event.trigger(e,t,this[0],!0)},toggle:function(e){var t=arguments,n=e.guid||v.guid++,r=0,i=function(n){var i=(v._data(this,"lastToggle"+e.guid)||0)%r;return v._data(this,"lastToggle"+e.guid,i+1),n.preventDefault(),t[i].apply(this,arguments)||!1};i.guid=n;while(r<t.length)t[r++].guid=n;return this.click(i)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),v.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 contextmenu".split(" "),function(e,t){v.fn[t]=function(e,n){return n==null&&(n=e,e=null),arguments.length>0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u<a;u++)if(s=e[u])if(!n||n(s,r,i))o.push(s),f&&t.push(u);return o}function ct(e,t,n,r,i,s){return r&&!r[d]&&(r=ct(r)),i&&!i[d]&&(i=ct(i,s)),N(function(s,o,u,a){var f,l,c,h=[],p=[],d=o.length,v=s||dt(t||"*",u.nodeType?[u]:u,[]),m=e&&(s||!t)?lt(v,h,e,u,a):v,g=n?i||(s?e:d||r)?[]:o:m;n&&n(m,g,u,a);if(r){f=lt(g,p),r(f,[],u,a),l=f.length;while(l--)if(c=f[l])g[p[l]]=!(m[p[l]]=c)}if(s){if(i||e){if(i){f=[],l=g.length;while(l--)(c=g[l])&&f.push(m[l]=c);i(null,g=[],f,a)}l=g.length;while(l--)(c=g[l])&&(f=i?T.call(s,c):h[l])>-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a<s;a++)if(n=i.relative[e[a].type])h=[at(ft(h),n)];else{n=i.filter[e[a].type].apply(null,e[a].matches);if(n[d]){r=++a;for(;r<s;r++)if(i.relative[e[r].type])break;return ct(a>1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a<r&&ht(e.slice(a,r)),r<s&&ht(e=e.slice(r)),r<s&&e.join(""))}h.push(n)}return ft(h)}function pt(e,t){var r=t.length>0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r<i;r++)nt(e,t[r],n);return n}function vt(e,t,n,r,s){var o,u,f,l,c,h=ut(e),p=h.length;if(!r&&h.length===1){u=h[0]=h[0].slice(0);if(u.length>2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;t<n;t++)if(this[t]===e)return t;return-1},N=function(e,t){return e[d]=t==null||t,e},C=function(){var e={},t=[];return N(function(n,r){return t.push(n)>i.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="<select></select>";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="<a name='"+d+"'></a><div name='"+d+"'></div>",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:st(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:st(function(e,t,n){for(var r=n<0?n+t:n;--r>=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}},f=y.compareDocumentPosition?function(e,t){return e===t?(l=!0,0):(!e.compareDocumentPosition||!t.compareDocumentPosition?e.compareDocumentPosition:e.compareDocumentPosition(t)&4)?-1:1}:function(e,t){if(e===t)return l=!0,0;if(e.sourceIndex&&t.sourceIndex)return e.sourceIndex-t.sourceIndex;var n,r,i=[],s=[],o=e.parentNode,u=t.parentNode,a=o;if(o===u)return ot(e,t);if(!o)return-1;if(!u)return 1;while(a)i.unshift(a),a=a.parentNode;a=u;while(a)s.unshift(a),a=a.parentNode;n=i.length,r=s.length;for(var f=0;f<n&&f<r;f++)if(i[f]!==s[f])return ot(i[f],s[f]);return f===n?ot(e,s[f],-1):ot(i[f],t,1)},[0,0].sort(f),h=!l,nt.uniqueSort=function(e){var t,n=[],r=1,i=0;l=h,e.sort(f);if(l){for(;t=e[r];r++)t===e[r-1]&&(i=n.push(r));while(i--)e.splice(n[i],1)}return e},nt.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},a=nt.compile=function(e,t){var n,r=[],i=[],s=A[d][e+" "];if(!s){t||(t=ut(e)),n=t.length;while(n--)s=ht(t[n]),s[d]?r.push(s):i.push(s);s=A(e,pt(i,r))}return s},g.querySelectorAll&&function(){var e,t=vt,n=/'|\\/g,r=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,i=[":focus"],s=[":active"],u=y.matchesSelector||y.mozMatchesSelector||y.webkitMatchesSelector||y.oMatchesSelector||y.msMatchesSelector;K(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="<p test=''></p>",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="<input type='hidden'/>",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t<n;t++)if(v.contains(u[t],this))return!0});o=this.pushStack("","find",e);for(t=0,n=this.length;t<n;t++){r=o.length,v.find(e,this[t],o);if(t>0)for(i=r;i<o.length;i++)for(s=0;s<r;s++)if(o[s]===o[i]){o.splice(i--,1);break}}return o},has:function(e){var t,n=v(e,this),r=n.length;return this.filter(function(){for(t=0;t<r;t++)if(v.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e,!1),"not",e)},filter:function(e){return this.pushStack(ft(this,e,!0),"filter",e)},is:function(e){return!!e&&(typeof e=="string"?st.test(e)?v(e,this.context).index(this[0])>=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r<i;r++){n=this[r];while(n&&n.ownerDocument&&n!==t&&n.nodeType!==11){if(o?o.index(n)>-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/<tbody/i,gt=/<|&#?\w+;/,yt=/<(?:script|style|link)/i,bt=/<(?:script|object|embed|option|style)/i,wt=new RegExp("<(?:"+ct+")[\\s/>]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*<!(?:\[CDATA\[|\-\-)|[\]\-]{2}>\s*$/g,Nt={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,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X<div>","</div>"]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1></$2>");try{for(;r<i;r++)n=this[r]||{},n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),n.innerHTML=e);n=0}catch(s){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){return ut(this[0])?this.length?this.pushStack(v(v.isFunction(e)?e():e),"replaceWith",e):this:v.isFunction(e)?this.each(function(t){var n=v(this),r=n.html();n.replaceWith(e.call(this,t,r))}):(typeof e!="string"&&(e=v(e).detach()),this.each(function(){var t=this.nextSibling,n=this.parentNode;v(this).remove(),t?v(t).before(e):v(n).append(e)}))},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){e=[].concat.apply([],e);var i,s,o,u,a=0,f=e[0],l=[],c=this.length;if(!v.support.checkClone&&c>1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a<c;a++)r.call(n&&v.nodeName(this[a],"table")?Lt(this[a],"tbody"):this[a],a===u?o:v.clone(o,!0,!0))}o=s=null,l.length&&v.each(l,function(e,t){t.src?v.ajax?v.ajax({url:t.src,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0}):v.error("no ajax"):v.globalEval((t.text||t.textContent||t.innerHTML||"").replace(Tt,"")),t.parentNode&&t.parentNode.removeChild(t)})}return this}}),v.buildFragment=function(e,n,r){var s,o,u,a=e[0];return n=n||i,n=!n.nodeType&&n[0]||n,n=n.ownerDocument||n,e.length===1&&typeof a=="string"&&a.length<512&&n===i&&a.charAt(0)==="<"&&!bt.test(a)&&(v.support.checkClone||!St.test(a))&&(v.support.html5Clone||!wt.test(a))&&(o=!0,s=v.fragments[a],u=s!==t),s||(s=n.createDocumentFragment(),v.clean(e,n,s,r),o&&(v.fragments[a]=u&&s)),{fragment:s,cacheable:o}},v.fragments={},v.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){v.fn[e]=function(n){var r,i=0,s=[],o=v(n),u=o.length,a=this.length===1&&this[0].parentNode;if((a==null||a&&a.nodeType===11&&a.childNodes.length===1)&&u===1)return o[t](this[0]),this;for(;i<u;i++)r=(i>0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1></$2>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]==="<table>"&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("<div>").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r<i;r++)n=e[r],Vn[n]=Vn[n]||[],Vn[n].unshift(t)},prefilter:function(e,t){t?Xn.unshift(e):Xn.push(e)}}),v.Tween=Yn,Yn.prototype={constructor:Yn,init:function(e,t,n,r,i,s){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=s||(v.cssNumber[n]?"":"px")},cur:function(){var e=Yn.propHooks[this.prop];return e&&e.get?e.get(this):Yn.propHooks._default.get(this)},run:function(e){var t,n=Yn.propHooks[this.prop];return this.options.duration?this.pos=t=v.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Yn.propHooks._default.set(this),this}},Yn.prototype.init.prototype=Yn.prototype,Yn.propHooks={_default:{get:function(e){var t;return e.elem[e.prop]==null||!!e.elem.style&&e.elem.style[e.prop]!=null?(t=v.css(e.elem,e.prop,!1,""),!t||t==="auto"?0:t):e.elem[e.prop]},set:function(e){v.fx.step[e.prop]?v.fx.step[e.prop](e):e.elem.style&&(e.elem.style[v.cssProps[e.prop]]!=null||v.cssHooks[e.prop])?v.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Yn.propHooks.scrollTop=Yn.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},v.each(["toggle","show","hide"],function(e,t){var n=v.fn[t];v.fn[t]=function(r,i,s){return r==null||typeof r=="boolean"||!e&&v.isFunction(r)&&v.isFunction(i)?n.apply(this,arguments):this.animate(Zn(t,!0),r,i,s)}}),v.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Gt).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=v.isEmptyObject(e),s=v.speed(t,n,r),o=function(){var t=Kn(this,v.extend({},e),s);i&&t.stop(!0)};return i||s.queue===!1?this.each(o):this.queue(s.queue,o)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return typeof e!="string"&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=e!=null&&e+"queueHooks",s=v.timers,o=v._data(this);if(n)o[n]&&o[n].stop&&i(o[n]);else for(n in o)o[n]&&o[n].stop&&Wn.test(n)&&i(o[n]);for(n=s.length;n--;)s[n].elem===this&&(e==null||s[n].queue===e)&&(s[n].anim.stop(r),t=!1,s.splice(n,1));(t||!r)&&v.dequeue(this,e)})}}),v.each({slideDown:Zn("show"),slideUp:Zn("hide"),slideToggle:Zn("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){v.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),v.speed=function(e,t,n){var r=e&&typeof e=="object"?v.extend({},e):{complete:n||!n&&t||v.isFunction(e)&&e,duration:e,easing:n&&t||t&&!v.isFunction(t)&&t};r.duration=v.fx.off?0:typeof r.duration=="number"?r.duration:r.duration in v.fx.speeds?v.fx.speeds[r.duration]:v.fx.speeds._default;if(r.queue==null||r.queue===!0)r.queue="fx";return r.old=r.complete,r.complete=function(){v.isFunction(r.old)&&r.old.call(this),r.queue&&v.dequeue(this,r.queue)},r},v.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},v.timers=[],v.fx=Yn.prototype.init,v.fx.tick=function(){var e,n=v.timers,r=0;qn=v.now();for(;r<n.length;r++)e=n[r],!e()&&n[r]===e&&n.splice(r--,1);n.length||v.fx.stop(),qn=t},v.fx.timer=function(e){e()&&v.timers.push(e)&&!Rn&&(Rn=setInterval(v.fx.tick,v.fx.interval))},v.fx.interval=13,v.fx.stop=function(){clearInterval(Rn),Rn=null},v.fx.speeds={slow:600,fast:200,_default:400},v.fx.step={},v.expr&&v.expr.filters&&(v.expr.filters.animated=function(e){return v.grep(v.timers,function(t){return e===t.elem}).length});var er=/^(?:body|html)$/i;v.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){v.offset.setOffset(this,e,t)});var n,r,i,s,o,u,a,f={top:0,left:0},l=this[0],c=l&&l.ownerDocument;if(!c)return;return(r=c.body)===l?v.offset.bodyOffset(l):(n=c.documentElement,v.contains(n,l)?(typeof l.getBoundingClientRect!="undefined"&&(f=l.getBoundingClientRect()),i=tr(c),s=n.clientTop||r.clientTop||0,o=n.clientLeft||r.clientLeft||0,u=i.pageYOffset||n.scrollTop,a=i.pageXOffset||n.scrollLeft,{top:f.top+u-s,left:f.left+a-o}):f)},v.offset={bodyOffset:function(e){var t=e.offsetTop,n=e.offsetLeft;return v.support.doesNotIncludeMarginInBodyOffset&&(t+=parseFloat(v.css(e,"marginTop"))||0,n+=parseFloat(v.css(e,"marginLeft"))||0),{top:t,left:n}},setOffset:function(e,t,n){var r=v.css(e,"position");r==="static"&&(e.style.position="relative");var i=v(e),s=i.offset(),o=v.css(e,"top"),u=v.css(e,"left"),a=(r==="absolute"||r==="fixed")&&v.inArray("auto",[o,u])>-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); \ No newline at end of file
diff --git a/phpBB/common.php b/phpBB/common.php
index f502d37c8f..f6f109c3de 100644
--- a/phpBB/common.php
+++ b/phpBB/common.php
@@ -44,8 +44,11 @@ if (!defined('PHPBB_INSTALLED'))
// Replace any number of consecutive backslashes and/or slashes with a single slash
// (could happen on some proxy setups and/or Windows servers)
$script_path = preg_replace('#[\\\\/]{2,}#', '/', $script_path);
+
// Eliminate . and .. from the path
- $script_path = phpbb_clean_path($script_path);
+ require($phpbb_root_path . 'includes/filesystem.' . $phpEx);
+ $phpbb_filesystem = new phpbb_filesystem();
+ $script_path = $phpbb_filesystem->clean_path($script_path);
$url = (($secure) ? 'https://' : 'http://') . $server_name;
@@ -73,6 +76,7 @@ require($phpbb_root_path . 'includes/class_loader.' . $phpEx);
require($phpbb_root_path . 'includes/functions.' . $phpEx);
require($phpbb_root_path . 'includes/functions_content.' . $phpEx);
require($phpbb_root_path . 'includes/functions_container.' . $phpEx);
+include($phpbb_root_path . 'includes/functions_compatibility.' . $phpEx);
require($phpbb_root_path . 'includes/constants.' . $phpEx);
require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);
@@ -81,9 +85,9 @@ require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);
set_error_handler(defined('PHPBB_MSG_HANDLER') ? PHPBB_MSG_HANDLER : 'msg_handler');
// Setup class loader first
-$phpbb_class_loader = new phpbb_class_loader('phpbb_', "{$phpbb_root_path}includes/", ".$phpEx");
+$phpbb_class_loader = new phpbb_class_loader('phpbb_', "{$phpbb_root_path}includes/", $phpEx);
$phpbb_class_loader->register();
-$phpbb_class_loader_ext = new phpbb_class_loader('phpbb_ext_', "{$phpbb_root_path}ext/", ".$phpEx");
+$phpbb_class_loader_ext = new phpbb_class_loader('phpbb_ext_', "{$phpbb_root_path}ext/", $phpEx);
$phpbb_class_loader_ext->register();
// Set up container
@@ -110,6 +114,8 @@ $config = $phpbb_container->get('config');
set_config(null, null, null, $config);
set_config_count(null, null, null, $config);
+$phpbb_log = $phpbb_container->get('log');
+
// load extensions
$phpbb_extension_manager = $phpbb_container->get('ext.manager');
$phpbb_subscriber_loader = $phpbb_container->get('event.subscriber_loader');
diff --git a/phpBB/composer.json b/phpBB/composer.json
index d2536a73cf..abc1df57b7 100644
--- a/phpBB/composer.json
+++ b/phpBB/composer.json
@@ -9,6 +9,8 @@
"symfony/yaml": "2.1.*"
},
"require-dev": {
- "fabpot/goutte": "v0.1.0"
+ "fabpot/goutte": "v0.1.0",
+ "phpunit/dbunit": "1.2.*",
+ "phpunit/phpunit": "3.7.*"
}
}
diff --git a/phpBB/composer.lock b/phpBB/composer.lock
index e96c15fe8b..e3b564fb1a 100644
--- a/phpBB/composer.lock
+++ b/phpBB/composer.lock
@@ -1,37 +1,35 @@
{
- "hash": "c1a76530df6b9daa16b8033d61b76503",
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
+ ],
+ "hash": "3792dc25490f24210ece3b40789c5b98",
"packages": [
{
"name": "symfony/config",
- "version": "v2.1.3",
+ "version": "v2.1.10",
"target-dir": "Symfony/Component/Config",
"source": {
"type": "git",
- "url": "https://github.com/symfony/Config",
- "reference": "v2.1.3"
+ "url": "https://github.com/symfony/Config.git",
+ "reference": "v2.1.10"
},
"dist": {
"type": "zip",
- "url": "https://github.com/symfony/Config/zipball/v2.1.3",
- "reference": "v2.1.3",
+ "url": "https://api.github.com/repos/symfony/Config/zipball/v2.1.10",
+ "reference": "v2.1.10",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
- "time": "2012-10-20 00:10:30",
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.1-dev"
- }
- },
- "installation-source": "dist",
"autoload": {
"psr-0": {
"Symfony\\Component\\Config": ""
}
},
+ "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -46,47 +44,42 @@
}
],
"description": "Symfony Config Component",
- "homepage": "http://symfony.com"
+ "homepage": "http://symfony.com",
+ "time": "2013-04-22 04:28:40"
},
{
"name": "symfony/dependency-injection",
- "version": "v2.1.3",
+ "version": "v2.1.10",
"target-dir": "Symfony/Component/DependencyInjection",
"source": {
"type": "git",
- "url": "https://github.com/symfony/DependencyInjection",
- "reference": "v2.1.3"
+ "url": "https://github.com/symfony/DependencyInjection.git",
+ "reference": "v2.1.10"
},
"dist": {
"type": "zip",
- "url": "https://github.com/symfony/DependencyInjection/zipball/v2.1.3",
- "reference": "v2.1.3",
+ "url": "https://api.github.com/repos/symfony/DependencyInjection/zipball/v2.1.10",
+ "reference": "v2.1.10",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
- "symfony/yaml": "2.1.*",
- "symfony/config": "2.1.*"
+ "symfony/config": "2.1.*",
+ "symfony/yaml": "2.1.*"
},
"suggest": {
- "symfony/yaml": "2.1.*",
- "symfony/config": "2.1.*"
+ "symfony/config": "2.1.*",
+ "symfony/yaml": "2.1.*"
},
- "time": "2012-10-22 07:37:12",
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.1-dev"
- }
- },
- "installation-source": "dist",
"autoload": {
"psr-0": {
"Symfony\\Component\\DependencyInjection": ""
}
},
+ "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -101,21 +94,22 @@
}
],
"description": "Symfony DependencyInjection Component",
- "homepage": "http://symfony.com"
+ "homepage": "http://symfony.com",
+ "time": "2013-05-03 05:08:13"
},
{
"name": "symfony/event-dispatcher",
- "version": "v2.1.3",
+ "version": "v2.1.10",
"target-dir": "Symfony/Component/EventDispatcher",
"source": {
"type": "git",
- "url": "https://github.com/symfony/EventDispatcher",
- "reference": "v2.1.3"
+ "url": "https://github.com/symfony/EventDispatcher.git",
+ "reference": "v2.1.10"
},
"dist": {
"type": "zip",
- "url": "https://github.com/symfony/EventDispatcher/zipball/v2.1.3",
- "reference": "v2.1.3",
+ "url": "https://api.github.com/repos/symfony/EventDispatcher/zipball/v2.1.10",
+ "reference": "v2.1.10",
"shasum": ""
},
"require": {
@@ -128,19 +122,13 @@
"symfony/dependency-injection": "2.1.*",
"symfony/http-kernel": "2.1.*"
},
- "time": "2012-10-04 08:17:57",
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.1-dev"
- }
- },
- "installation-source": "dist",
"autoload": {
"psr-0": {
"Symfony\\Component\\EventDispatcher": ""
}
},
+ "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -155,40 +143,35 @@
}
],
"description": "Symfony EventDispatcher Component",
- "homepage": "http://symfony.com"
+ "homepage": "http://symfony.com",
+ "time": "2013-02-11 11:26:14"
},
{
"name": "symfony/http-foundation",
- "version": "v2.1.3",
+ "version": "v2.1.10",
"target-dir": "Symfony/Component/HttpFoundation",
"source": {
"type": "git",
- "url": "https://github.com/symfony/HttpFoundation",
- "reference": "v2.1.3"
+ "url": "https://github.com/symfony/HttpFoundation.git",
+ "reference": "v2.1.10"
},
"dist": {
"type": "zip",
- "url": "https://github.com/symfony/HttpFoundation/zipball/v2.1.3",
- "reference": "v2.1.3",
+ "url": "https://api.github.com/repos/symfony/HttpFoundation/zipball/v2.1.10",
+ "reference": "v2.1.10",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
- "time": "2012-10-20 00:10:30",
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.1-dev"
- }
- },
- "installation-source": "dist",
"autoload": {
"psr-0": {
"Symfony\\Component\\HttpFoundation": "",
"SessionHandlerInterface": "Symfony/Component/HttpFoundation/Resources/stubs"
}
},
+ "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -203,21 +186,22 @@
}
],
"description": "Symfony HttpFoundation Component",
- "homepage": "http://symfony.com"
+ "homepage": "http://symfony.com",
+ "time": "2013-04-30 17:01:33"
},
{
"name": "symfony/http-kernel",
- "version": "v2.1.3",
+ "version": "v2.1.10",
"target-dir": "Symfony/Component/HttpKernel",
"source": {
"type": "git",
- "url": "https://github.com/symfony/HttpKernel",
- "reference": "v2.1.3"
+ "url": "https://github.com/symfony/HttpKernel.git",
+ "reference": "v2.1.10"
},
"dist": {
"type": "zip",
- "url": "https://github.com/symfony/HttpKernel/zipball/v2.1.3",
- "reference": "v2.1.3",
+ "url": "https://api.github.com/repos/symfony/HttpKernel/zipball/v2.1.10",
+ "reference": "v2.1.10",
"shasum": ""
},
"require": {
@@ -243,19 +227,13 @@
"symfony/dependency-injection": "2.1.*",
"symfony/finder": "2.1.*"
},
- "time": "2012-10-30 01:14:14",
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.1-dev"
- }
- },
- "installation-source": "dist",
"autoload": {
"psr-0": {
"Symfony\\Component\\HttpKernel": ""
}
},
+ "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -270,50 +248,45 @@
}
],
"description": "Symfony HttpKernel Component",
- "homepage": "http://symfony.com"
+ "homepage": "http://symfony.com",
+ "time": "2013-05-06 11:01:51"
},
{
"name": "symfony/routing",
- "version": "v2.1.3",
+ "version": "v2.1.9",
"target-dir": "Symfony/Component/Routing",
"source": {
"type": "git",
- "url": "https://github.com/symfony/Routing",
- "reference": "v2.1.3"
+ "url": "https://github.com/symfony/Routing.git",
+ "reference": "v2.1.9"
},
"dist": {
"type": "zip",
- "url": "https://github.com/symfony/Routing/zipball/v2.1.3",
- "reference": "v2.1.3",
+ "url": "https://api.github.com/repos/symfony/Routing/zipball/v2.1.9",
+ "reference": "v2.1.9",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
+ "doctrine/common": ">=2.2,<3.0",
"symfony/config": "2.1.*",
- "symfony/yaml": "2.1.*",
"symfony/http-kernel": "2.1.*",
- "doctrine/common": ">=2.2,<2.4-dev"
+ "symfony/yaml": "2.1.*"
},
"suggest": {
+ "doctrine/common": "~2.2",
"symfony/config": "2.1.*",
- "symfony/yaml": "2.1.*",
- "doctrine/common": ">=2.2,<2.4-dev"
+ "symfony/yaml": "2.1.*"
},
- "time": "2012-10-26 02:26:42",
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.1-dev"
- }
- },
- "installation-source": "dist",
"autoload": {
"psr-0": {
"Symfony\\Component\\Routing": ""
}
},
+ "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -328,39 +301,34 @@
}
],
"description": "Symfony Routing Component",
- "homepage": "http://symfony.com"
+ "homepage": "http://symfony.com",
+ "time": "2013-03-23 07:47:35"
},
{
"name": "symfony/yaml",
- "version": "v2.1.3",
+ "version": "v2.1.9",
"target-dir": "Symfony/Component/Yaml",
"source": {
"type": "git",
- "url": "https://github.com/symfony/Yaml",
- "reference": "v2.1.3"
+ "url": "https://github.com/symfony/Yaml.git",
+ "reference": "v2.1.9"
},
"dist": {
"type": "zip",
- "url": "https://github.com/symfony/Yaml/zipball/v2.1.3",
- "reference": "v2.1.3",
+ "url": "https://api.github.com/repos/symfony/Yaml/zipball/v2.1.9",
+ "reference": "v2.1.9",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
- "time": "2012-10-29 04:15:41",
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.1-dev"
- }
- },
- "installation-source": "dist",
"autoload": {
"psr-0": {
"Symfony\\Component\\Yaml": ""
}
},
+ "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -375,7 +343,8 @@
}
],
"description": "Symfony Yaml Component",
- "homepage": "http://symfony.com"
+ "homepage": "http://symfony.com",
+ "time": "2013-03-23 01:54:33"
}
],
"packages-dev": [
@@ -394,28 +363,27 @@
"shasum": ""
},
"require": {
- "php": ">=5.3.0",
"ext-curl": "*",
+ "guzzle/guzzle": "3.0.*",
+ "php": ">=5.3.0",
"symfony/browser-kit": "2.1.*",
"symfony/css-selector": "2.1.*",
"symfony/dom-crawler": "2.1.*",
"symfony/finder": "2.1.*",
- "symfony/process": "2.1.*",
- "guzzle/guzzle": "3.0.*"
+ "symfony/process": "2.1.*"
},
- "time": "2012-12-02 13:44:35",
"type": "application",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
- "installation-source": "source",
"autoload": {
"psr-0": {
"Goutte": "."
}
},
+ "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -429,26 +397,27 @@
"homepage": "https://github.com/fabpot/Goutte",
"keywords": [
"scraper"
- ]
+ ],
+ "time": "2012-12-02 13:44:35"
},
{
"name": "guzzle/guzzle",
- "version": "v3.0.5",
+ "version": "v3.0.7",
"source": {
"type": "git",
"url": "https://github.com/guzzle/guzzle",
- "reference": "v3.0.5"
+ "reference": "v3.0.7"
},
"dist": {
"type": "zip",
- "url": "https://github.com/guzzle/guzzle/archive/v3.0.5.zip",
- "reference": "v3.0.5",
+ "url": "https://github.com/guzzle/guzzle/archive/v3.0.7.zip",
+ "reference": "v3.0.7",
"shasum": ""
},
"require": {
- "php": ">=5.3.2",
"ext-curl": "*",
- "symfony/event-dispatcher": "2.1.*"
+ "php": ">=5.3.2",
+ "symfony/event-dispatcher": ">=2.1"
},
"replace": {
"guzzle/batch": "self.version",
@@ -475,23 +444,27 @@
},
"require-dev": {
"doctrine/common": "*",
- "symfony/class-loader": "*",
"monolog/monolog": "1.*",
- "zendframework/zend-cache": "2.0.*",
- "zendframework/zend-log": "2.0.*",
- "zend/zend-log1": "1.12",
+ "phpunit/phpunit": "3.7.*",
+ "symfony/class-loader": "*",
"zend/zend-cache1": "1.12",
- "phpunit/phpunit": "3.7.*"
+ "zend/zend-log1": "1.12",
+ "zendframework/zend-cache": "2.0.*",
+ "zendframework/zend-log": "2.0.*"
},
- "time": "2012-11-19 00:15:33",
"type": "library",
- "installation-source": "dist",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
"autoload": {
"psr-0": {
"Guzzle\\Tests": "tests/",
"Guzzle": "src/"
}
},
+ "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -509,54 +482,461 @@
"description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients",
"homepage": "http://guzzlephp.org/",
"keywords": [
- "framework",
+ "client",
"curl",
+ "framework",
"http",
- "rest",
"http client",
- "client",
+ "rest",
"web service"
- ]
+ ],
+ "time": "2012-12-19 23:06:35"
},
{
- "name": "symfony/browser-kit",
- "version": "v2.1.3",
- "target-dir": "Symfony/Component/BrowserKit",
+ "name": "phpunit/dbunit",
+ "version": "1.2.3",
"source": {
"type": "git",
- "url": "https://github.com/symfony/BrowserKit",
- "reference": "v2.1.3"
+ "url": "https://github.com/sebastianbergmann/dbunit.git",
+ "reference": "1.2.3"
},
"dist": {
"type": "zip",
- "url": "https://github.com/symfony/BrowserKit/zipball/v2.1.3",
- "reference": "v2.1.3",
+ "url": "https://api.github.com/repos/sebastianbergmann/dbunit/zipball/1.2.3",
+ "reference": "1.2.3",
"shasum": ""
},
"require": {
+ "ext-pdo": "*",
+ "ext-simplexml": "*",
"php": ">=5.3.3",
- "symfony/dom-crawler": "2.1.*"
+ "phpunit/phpunit": ">=3.7.0@stable"
+ },
+ "bin": [
+ "dbunit.php"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.2.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "PHPUnit/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ "",
+ "../../symfony/yaml/"
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "DbUnit port for PHP/PHPUnit to support database interaction testing.",
+ "homepage": "https://github.com/sebastianbergmann/dbunit/",
+ "keywords": [
+ "database",
+ "testing",
+ "xunit"
+ ],
+ "time": "2013-03-01 11:50:46"
+ },
+ {
+ "name": "phpunit/php-code-coverage",
+ "version": "1.2.9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
+ "reference": "1.2.9"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1.2.9",
+ "reference": "1.2.9",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "phpunit/php-file-iterator": ">=1.3.0@stable",
+ "phpunit/php-text-template": ">=1.1.1@stable",
+ "phpunit/php-token-stream": ">=1.1.3@stable"
+ },
+ "suggest": {
+ "ext-dom": "*",
+ "ext-xdebug": ">=2.0.5"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "PHP/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.",
+ "homepage": "https://github.com/sebastianbergmann/php-code-coverage",
+ "keywords": [
+ "coverage",
+ "testing",
+ "xunit"
+ ],
+ "time": "2013-02-26 18:55:56"
+ },
+ {
+ "name": "phpunit/php-file-iterator",
+ "version": "1.3.3",
+ "source": {
+ "type": "git",
+ "url": "git://github.com/sebastianbergmann/php-file-iterator.git",
+ "reference": "1.3.3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://github.com/sebastianbergmann/php-file-iterator/zipball/1.3.3",
+ "reference": "1.3.3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "File/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "FilterIterator implementation that filters files based on a list of suffixes.",
+ "homepage": "http://www.phpunit.de/",
+ "keywords": [
+ "filesystem",
+ "iterator"
+ ],
+ "time": "2012-10-11 04:44:38"
+ },
+ {
+ "name": "phpunit/php-text-template",
+ "version": "1.1.4",
+ "source": {
+ "type": "git",
+ "url": "git://github.com/sebastianbergmann/php-text-template.git",
+ "reference": "1.1.4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://github.com/sebastianbergmann/php-text-template/zipball/1.1.4",
+ "reference": "1.1.4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "Text/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Simple template engine.",
+ "homepage": "https://github.com/sebastianbergmann/php-text-template/",
+ "keywords": [
+ "template"
+ ],
+ "time": "2012-10-31 11:15:28"
+ },
+ {
+ "name": "phpunit/php-timer",
+ "version": "1.0.4",
+ "source": {
+ "type": "git",
+ "url": "git://github.com/sebastianbergmann/php-timer.git",
+ "reference": "1.0.4"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://github.com/sebastianbergmann/php-timer/zipball/1.0.4",
+ "reference": "1.0.4",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "PHP/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Utility class for timing",
+ "homepage": "http://www.phpunit.de/",
+ "keywords": [
+ "timer"
+ ],
+ "time": "2012-10-11 04:45:58"
+ },
+ {
+ "name": "phpunit/php-token-stream",
+ "version": "1.1.5",
+ "source": {
+ "type": "git",
+ "url": "git://github.com/sebastianbergmann/php-token-stream.git",
+ "reference": "1.1.5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://github.com/sebastianbergmann/php-token-stream/zipball/1.1.5",
+ "reference": "1.1.5",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": ">=5.3.3"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "PHP/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Wrapper around PHP's tokenizer extension.",
+ "homepage": "http://www.phpunit.de/",
+ "keywords": [
+ "tokenizer"
+ ],
+ "time": "2012-10-11 04:47:14"
+ },
+ {
+ "name": "phpunit/phpunit",
+ "version": "3.7.19",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/sebastianbergmann/phpunit.git",
+ "reference": "3.7.19"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3.7.19",
+ "reference": "3.7.19",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-pcre": "*",
+ "ext-reflection": "*",
+ "ext-spl": "*",
+ "php": ">=5.3.3",
+ "phpunit/php-code-coverage": ">=1.2.1,<1.3.0",
+ "phpunit/php-file-iterator": ">=1.3.1",
+ "phpunit/php-text-template": ">=1.1.1",
+ "phpunit/php-timer": ">=1.0.2,<1.1.0",
+ "phpunit/phpunit-mock-objects": ">=1.2.0,<1.3.0",
+ "symfony/yaml": ">=2.0.0,<2.3.0"
},
"require-dev": {
- "symfony/process": "2.1.*",
- "symfony/css-selector": "2.1.*"
+ "pear-pear/pear": "1.9.4"
},
"suggest": {
- "symfony/process": "2.1.*"
+ "ext-json": "*",
+ "ext-simplexml": "*",
+ "ext-tokenizer": "*",
+ "phpunit/php-invoker": ">=1.1.0,<1.2.0"
},
- "time": "2012-10-25 06:11:50",
+ "bin": [
+ "composer/bin/phpunit"
+ ],
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.1-dev"
+ "dev-master": "3.7.x-dev"
}
},
- "installation-source": "dist",
+ "autoload": {
+ "classmap": [
+ "PHPUnit/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ "",
+ "../../symfony/yaml/"
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sebastian@phpunit.de",
+ "role": "lead"
+ }
+ ],
+ "description": "The PHP Unit Testing framework.",
+ "homepage": "http://www.phpunit.de/",
+ "keywords": [
+ "phpunit",
+ "testing",
+ "xunit"
+ ],
+ "time": "2013-03-25 11:45:06"
+ },
+ {
+ "name": "phpunit/phpunit-mock-objects",
+ "version": "1.2.3",
+ "source": {
+ "type": "git",
+ "url": "git://github.com/sebastianbergmann/phpunit-mock-objects.git",
+ "reference": "1.2.3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://github.com/sebastianbergmann/phpunit-mock-objects/archive/1.2.3.zip",
+ "reference": "1.2.3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "phpunit/php-text-template": ">=1.1.1@stable"
+ },
+ "suggest": {
+ "ext-soap": "*"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "PHPUnit/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Sebastian Bergmann",
+ "email": "sb@sebastian-bergmann.de",
+ "role": "lead"
+ }
+ ],
+ "description": "Mock Object library for PHPUnit",
+ "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
+ "keywords": [
+ "mock",
+ "xunit"
+ ],
+ "time": "2013-01-13 10:24:48"
+ },
+ {
+ "name": "symfony/browser-kit",
+ "version": "v2.1.10",
+ "target-dir": "Symfony/Component/BrowserKit",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/BrowserKit.git",
+ "reference": "v2.1.10"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/BrowserKit/zipball/v2.1.10",
+ "reference": "v2.1.10",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.3",
+ "symfony/dom-crawler": "2.1.*"
+ },
+ "require-dev": {
+ "symfony/css-selector": "2.1.*",
+ "symfony/process": "2.1.*"
+ },
+ "suggest": {
+ "symfony/process": "2.1.*"
+ },
+ "type": "library",
"autoload": {
"psr-0": {
"Symfony\\Component\\BrowserKit": ""
}
},
+ "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -571,39 +951,34 @@
}
],
"description": "Symfony BrowserKit Component",
- "homepage": "http://symfony.com"
+ "homepage": "http://symfony.com",
+ "time": "2013-04-29 20:22:06"
},
{
"name": "symfony/css-selector",
- "version": "v2.1.3",
+ "version": "v2.1.10",
"target-dir": "Symfony/Component/CssSelector",
"source": {
"type": "git",
- "url": "https://github.com/symfony/CssSelector",
- "reference": "v2.1.3"
+ "url": "https://github.com/symfony/CssSelector.git",
+ "reference": "v2.1.10"
},
"dist": {
"type": "zip",
- "url": "https://github.com/symfony/CssSelector/zipball/v2.1.3",
- "reference": "v2.1.3",
+ "url": "https://api.github.com/repos/symfony/CssSelector/zipball/v2.1.10",
+ "reference": "v2.1.10",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
- "time": "2012-10-04 08:17:57",
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.1-dev"
- }
- },
- "installation-source": "dist",
"autoload": {
"psr-0": {
"Symfony\\Component\\CssSelector": ""
}
},
+ "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -618,21 +993,22 @@
}
],
"description": "Symfony CssSelector Component",
- "homepage": "http://symfony.com"
+ "homepage": "http://symfony.com",
+ "time": "2013-01-09 08:51:07"
},
{
"name": "symfony/dom-crawler",
- "version": "v2.1.3",
+ "version": "v2.1.10",
"target-dir": "Symfony/Component/DomCrawler",
"source": {
"type": "git",
- "url": "https://github.com/symfony/DomCrawler",
- "reference": "v2.1.3"
+ "url": "https://github.com/symfony/DomCrawler.git",
+ "reference": "v2.1.10"
},
"dist": {
"type": "zip",
- "url": "https://github.com/symfony/DomCrawler/zipball/v2.1.3",
- "reference": "v2.1.3",
+ "url": "https://api.github.com/repos/symfony/DomCrawler/zipball/v2.1.10",
+ "reference": "v2.1.10",
"shasum": ""
},
"require": {
@@ -644,19 +1020,13 @@
"suggest": {
"symfony/css-selector": "2.1.*"
},
- "time": "2012-10-18 14:16:01",
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.1-dev"
- }
- },
- "installation-source": "dist",
"autoload": {
"psr-0": {
"Symfony\\Component\\DomCrawler": ""
}
},
+ "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -671,39 +1041,34 @@
}
],
"description": "Symfony DomCrawler Component",
- "homepage": "http://symfony.com"
+ "homepage": "http://symfony.com",
+ "time": "2013-03-27 17:13:16"
},
{
"name": "symfony/finder",
- "version": "v2.1.3",
+ "version": "v2.1.10",
"target-dir": "Symfony/Component/Finder",
"source": {
"type": "git",
- "url": "https://github.com/symfony/Finder",
- "reference": "v2.1.3"
+ "url": "https://github.com/symfony/Finder.git",
+ "reference": "v2.1.10"
},
"dist": {
"type": "zip",
- "url": "https://github.com/symfony/Finder/zipball/v2.1.3",
- "reference": "v2.1.3",
+ "url": "https://api.github.com/repos/symfony/Finder/zipball/v2.1.10",
+ "reference": "v2.1.10",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
- "time": "2012-10-20 00:10:30",
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.1-dev"
- }
- },
- "installation-source": "dist",
"autoload": {
"psr-0": {
"Symfony\\Component\\Finder": ""
}
},
+ "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -718,39 +1083,34 @@
}
],
"description": "Symfony Finder Component",
- "homepage": "http://symfony.com"
+ "homepage": "http://symfony.com",
+ "time": "2013-03-06 19:26:55"
},
{
"name": "symfony/process",
- "version": "v2.1.3",
+ "version": "v2.1.9",
"target-dir": "Symfony/Component/Process",
"source": {
"type": "git",
- "url": "https://github.com/symfony/Process",
- "reference": "v2.1.3"
+ "url": "https://github.com/symfony/Process.git",
+ "reference": "v2.1.9"
},
"dist": {
"type": "zip",
- "url": "https://github.com/symfony/Process/zipball/v2.1.3",
- "reference": "v2.1.3",
+ "url": "https://api.github.com/repos/symfony/Process/zipball/v2.1.9",
+ "reference": "v2.1.9",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
- "time": "2012-10-20 00:10:30",
"type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.1-dev"
- }
- },
- "installation-source": "dist",
"autoload": {
"psr-0": {
"Symfony\\Component\\Process": ""
}
},
+ "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -765,7 +1125,8 @@
}
],
"description": "Symfony Process Component",
- "homepage": "http://symfony.com"
+ "homepage": "http://symfony.com",
+ "time": "2013-03-23 07:44:01"
}
],
"aliases": [
@@ -774,5 +1135,11 @@
"minimum-stability": "beta",
"stability-flags": [
+ ],
+ "platform": [
+
+ ],
+ "platform-dev": [
+
]
}
diff --git a/phpBB/config/avatars.yml b/phpBB/config/avatars.yml
new file mode 100644
index 0000000000..0aad08bac9
--- /dev/null
+++ b/phpBB/config/avatars.yml
@@ -0,0 +1,55 @@
+services:
+ avatar.driver.gravatar:
+ class: phpbb_avatar_driver_gravatar
+ arguments:
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - @cache.driver
+ calls:
+ - [set_name, [avatar.driver.gravatar]]
+ tags:
+ - { name: avatar.driver }
+
+ avatar.driver.local:
+ class: phpbb_avatar_driver_local
+ arguments:
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - @cache.driver
+ calls:
+ - [set_name, [avatar.driver.local]]
+ tags:
+ - { name: avatar.driver }
+
+ avatar.driver.remote:
+ class: phpbb_avatar_driver_remote
+ arguments:
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - @cache.driver
+ calls:
+ - [set_name, [avatar.driver.remote]]
+ tags:
+ - { name: avatar.driver }
+
+ avatar.driver.upload:
+ class: phpbb_avatar_driver_upload
+ arguments:
+ - @config
+ - %core.root_path%
+ - %core.php_ext%
+ - @cache.driver
+ calls:
+ - [set_name, [avatar.driver.upload]]
+ tags:
+ - { name: avatar.driver }
+
+ avatar.driver_collection:
+ class: phpbb_di_service_collection
+ arguments:
+ - @service_container
+ tags:
+ - { name: service_collection, tag: avatar.driver }
diff --git a/phpBB/config/services.yml b/phpBB/config/services.yml
index 3e4ae8d129..7a0fddf0c1 100644
--- a/phpBB/config/services.yml
+++ b/phpBB/config/services.yml
@@ -3,11 +3,19 @@ imports:
- { resource: cron_tasks.yml }
- { resource: notifications.yml }
- { resource: migrator.yml }
+ - { resource: avatars.yml }
services:
auth:
class: phpbb_auth
+ avatar.manager:
+ class: phpbb_avatar_manager
+ arguments:
+ - @config
+ - @avatar.driver_collection
+ - @service_container
+
cache:
class: phpbb_cache_service
arguments:
@@ -28,7 +36,7 @@ services:
arguments:
- phpbb_
- %core.root_path%includes/
- - .%core.php_ext%
+ - %core.php_ext%
calls:
- [register, []]
- [set_cache, [@cache.driver]]
@@ -38,7 +46,7 @@ services:
arguments:
- phpbb_ext_
- %core.root_path%ext/
- - .%core.php_ext%
+ - %core.php_ext%
calls:
- [register, []]
- [set_cache, [@cache.driver]]
@@ -50,13 +58,19 @@ services:
- @cache.driver
- %tables.config%
+ config_text:
+ class: phpbb_config_db_text
+ arguments:
+ - @dbal.conn
+ - %tables.config_text%
+
controller.helper:
class: phpbb_controller_helper
arguments:
- @template
- @user
- %core.root_path%
- - .%core.php_ext%
+ - %core.php_ext%
controller.resolver:
class: phpbb_controller_resolver
@@ -116,21 +130,38 @@ services:
- @service_container
- @dbal.conn
- @config
- - @migrator
+ - @filesystem
- %tables.ext%
- %core.root_path%
- - .%core.php_ext%
+ - %core.php_ext%
- @cache.driver
ext.finder:
class: phpbb_extension_finder
arguments:
- @ext.manager
+ - @filesystem
- %core.root_path%
- @cache.driver
- - .%core.php_ext%
+ - %core.php_ext%
- _ext_finder
+ filesystem:
+ class: phpbb_filesystem
+
+ groupposition.legend:
+ class: phpbb_groupposition_legend
+ arguments:
+ - @dbal.conn
+ - @user
+
+ groupposition.teampage:
+ class: phpbb_groupposition_teampage
+ arguments:
+ - @dbal.conn
+ - @user
+ - @cache.driver
+
http_kernel:
class: Symfony\Component\HttpKernel\HttpKernel
arguments:
@@ -141,7 +172,7 @@ services:
class: phpbb_hook_finder
arguments:
- %core.root_path%
- - .%core.php_ext%
+ - %core.php_ext%
- @cache.driver
kernel_request_subscriber:
@@ -149,7 +180,7 @@ services:
arguments:
- @ext.finder
- %core.root_path%
- - .%core.php_ext%
+ - %core.php_ext%
tags:
- { name: kernel.event_subscriber }
@@ -166,6 +197,18 @@ services:
tags:
- { name: kernel.event_subscriber }
+ log:
+ class: phpbb_log
+ arguments:
+ - @dbal.conn
+ - @user
+ - @auth
+ - @dispatcher
+ - %core.root_path%
+ - %core.adm_relative_path%
+ - %core.php_ext%
+ - %tables.log%
+
notification_manager:
class: phpbb_notification_manager
arguments:
@@ -174,6 +217,7 @@ services:
- @service_container
- @user_loader
- @dbal.conn
+ - @cache
- @user
- %core.root_path%
- %core.php_ext%
@@ -203,6 +247,7 @@ services:
arguments:
- @ext.manager
- @style.path_provider
+ - %core.root_path%
style.path_provider:
class: phpbb_style_path_provider
diff --git a/phpBB/config/tables.yml b/phpBB/config/tables.yml
index 10db8fbab6..ec5fec23ad 100644
--- a/phpBB/config/tables.yml
+++ b/phpBB/config/tables.yml
@@ -1,9 +1,11 @@
parameters:
tables.config: %core.table_prefix%config
+ tables.config_text: %core.table_prefix%config_text
tables.ext: %core.table_prefix%ext
+ tables.log: %core.table_prefix%log
+ tables.migrations: %core.table_prefix%migrations
+ tables.modules: %core.table_prefix%modules
tables.notification_types: %core.table_prefix%notification_types
tables.notifications: %core.table_prefix%notifications
tables.user_notifications: %core.table_prefix%user_notifications
tables.users: %core.table_prefix%users
- tables.migrations: %core.table_prefix%migrations
- tables.modules: %core.table_prefix%modules
diff --git a/phpBB/develop/create_schema_files.php b/phpBB/develop/create_schema_files.php
index 0a48ef58ff..0fd1a722ca 100644
--- a/phpBB/develop/create_schema_files.php
+++ b/phpBB/develop/create_schema_files.php
@@ -998,6 +998,14 @@ function get_schema_struct()
),
);
+ $schema_data['phpbb_config_text'] = array(
+ 'COLUMNS' => array(
+ 'config_name' => array('VCHAR', ''),
+ 'config_value' => array('MTEXT', ''),
+ ),
+ 'PRIMARY_KEY' => 'config_name',
+ );
+
$schema_data['phpbb_confirm'] = array(
'COLUMNS' => array(
'confirm_id' => array('CHAR:32', ''),
@@ -1168,7 +1176,7 @@ function get_schema_struct()
'group_desc_uid' => array('VCHAR:8', ''),
'group_display' => array('BOOL', 0),
'group_avatar' => array('VCHAR', ''),
- 'group_avatar_type' => array('TINT:2', 0),
+ 'group_avatar_type' => array('VCHAR:255', ''),
'group_avatar_width' => array('USINT', 0),
'group_avatar_height' => array('USINT', 0),
'group_rank' => array('UINT', 0),
@@ -1178,7 +1186,6 @@ function get_schema_struct()
'group_message_limit' => array('UINT', 0),
'group_max_recipients' => array('UINT', 0),
'group_legend' => array('UINT', 0),
- 'group_teampage' => array('UINT', 0),
),
'PRIMARY_KEY' => 'group_id',
'KEYS' => array(
@@ -1310,16 +1317,20 @@ function get_schema_struct()
$schema_data['phpbb_notification_types'] = array(
'COLUMNS' => array(
- 'notification_type' => array('VCHAR:255', ''),
+ 'notification_type_id' => array('USINT', NULL, 'auto_increment'),
+ 'notification_type_name' => array('VCHAR:255', ''),
'notification_type_enabled' => array('BOOL', 1),
),
- 'PRIMARY_KEY' => array('notification_type', 'notification_type_enabled'),
+ 'PRIMARY_KEY' => array('notification_type_id'),
+ 'KEYS' => array(
+ 'type' => array('UNIQUE', array('notification_type_name')),
+ ),
);
$schema_data['phpbb_notifications'] = array(
'COLUMNS' => array(
- 'notification_id' => array('UINT', NULL, 'auto_increment'),
- 'item_type' => array('VCHAR:255', ''),
+ 'notification_id' => array('UINT:10', NULL, 'auto_increment'),
+ 'notification_type_id' => array('USINT', 0),
'item_id' => array('UINT', 0),
'item_parent_id' => array('UINT', 0),
'user_id' => array('UINT', 0),
@@ -1329,7 +1340,7 @@ function get_schema_struct()
),
'PRIMARY_KEY' => 'notification_id',
'KEYS' => array(
- 'item_ident' => array('INDEX', array('item_type', 'item_id')),
+ 'item_ident' => array('INDEX', array('notification_type_id', 'item_id')),
'user' => array('INDEX', array('user_id', 'notification_read')),
),
);
@@ -1711,6 +1722,17 @@ function get_schema_struct()
),
);
+ $schema_data['phpbb_teampage'] = array(
+ 'COLUMNS' => array(
+ 'teampage_id' => array('UINT', NULL, 'auto_increment'),
+ 'group_id' => array('UINT', 0),
+ 'teampage_name' => array('VCHAR_UNI:255', ''),
+ 'teampage_position' => array('UINT', 0),
+ 'teampage_parent' => array('UINT', 0),
+ ),
+ 'PRIMARY_KEY' => 'teampage_id',
+ );
+
$schema_data['phpbb_topics'] = array(
'COLUMNS' => array(
'topic_id' => array('UINT', NULL, 'auto_increment'),
@@ -1796,7 +1818,7 @@ function get_schema_struct()
);
$schema_data['phpbb_user_notifications'] = array(
- 'COLUMNS' => array(
+ 'COLUMNS' => array(
'item_type' => array('VCHAR:255', ''),
'item_id' => array('UINT', 0),
'user_id' => array('UINT', 0),
@@ -1875,7 +1897,7 @@ function get_schema_struct()
'user_allow_massemail' => array('BOOL', 1),
'user_options' => array('UINT:11', 230271),
'user_avatar' => array('VCHAR', ''),
- 'user_avatar_type' => array('TINT:2', 0),
+ 'user_avatar_type' => array('VCHAR:255', ''),
'user_avatar_width' => array('USINT', 0),
'user_avatar_height' => array('USINT', 0),
'user_sig' => array('MTEXT_UNI', ''),
diff --git a/phpBB/docs/coding-guidelines.html b/phpBB/docs/coding-guidelines.html
index 14c2281323..e73c563d5b 100644
--- a/phpBB/docs/coding-guidelines.html
+++ b/phpBB/docs/coding-guidelines.html
@@ -1060,6 +1060,8 @@ $action_ary = request_var('action', array('' =&gt; 0));
<h4>Login checks/redirection: </h4>
<p>To show a forum login box use <code>login_forum_box($forum_data)</code>, else use the <code>login_box()</code> function.</p>
+ <p><code>$forum_data</code> should contain at least the <code>forum_id</code> and <code>forum_password</code> fields. If the field <code>forum_name</code> is available, then it is displayed on the forum login page.</p>
+
<p>The <code>login_box()</code> function can have a redirect as the first parameter. As a thumb of rule, specify an empty string if you want to redirect to the users current location, else do not add the <code>$SID</code> to the redirect string (for example within the ucp/login we redirect to the board index because else the user would be redirected to the login screen).</p>
<h4>Sensitive Operations: </h4>
@@ -2490,7 +2492,7 @@ if (utf8_case_fold_nfc($string1) == utf8_case_fold_nfc($string2))
<hr />
-<a name="disclaimer"></a><h2>8. Copyright and disclaimer</h2>
+<a name="disclaimer"></a><h2>7. Copyright and disclaimer</h2>
<div class="paragraph">
<div class="inner"><span class="corners-top"><span></span></span>
diff --git a/phpBB/docs/events.md b/phpBB/docs/events.md
index f0b3b81822..3723bf7b3f 100644
--- a/phpBB/docs/events.md
+++ b/phpBB/docs/events.md
@@ -124,6 +124,15 @@ viewtopic_print_head_append
* Location: styles/prosilver/template/viewtopic_print.html
* Purpose: Add asset calls directly before the `</head>` tag of the Print Topic screen
+viewtopic_body_footer_before
+===
+* Locations:
+ + styles/prosilver/template/viewtopic_body.html
+ + styles/subsilver2/template/viewtopic_body.html
+* Purpose: Add content to the bottom of the View topic screen below the posts
+and quick reply, directly before the jumpbox in Prosilver, breadcrumbs in
+Subsilver2.
+
viewtopic_topic_title_prepend
===
* Locations:
diff --git a/phpBB/docs/sphinx.sample.conf b/phpBB/docs/sphinx.sample.conf
index fcaba6dcf3..d1b98d6cbc 100644
--- a/phpBB/docs/sphinx.sample.conf
+++ b/phpBB/docs/sphinx.sample.conf
@@ -1,46 +1,31 @@
source source_phpbb_{SPHINX_ID}_main
{
- type = mysql #mysql or pgsql
- sql_host = localhost #SQL server host sphinx connects to
+ type = mysql # mysql or pgsql
+ sql_host = localhost # SQL server host sphinx connects to
sql_user = username
sql_pass = password
sql_db = db_name
- sql_port = 3306 #optional, default is 3306 for mysql and 5432 for pgsql
+ sql_port = 3306 # optional, default is 3306 for mysql and 5432 for pgsql
sql_query_pre = SET NAMES 'utf8'
- sql_query_pre = UPDATE phpbb_sphinx SET max_doc_id = MAX(post_id) WHERE counter_id = 1
+ sql_query_pre = UPDATE phpbb_sphinx SET max_doc_id = (SELECT MAX(post_id) FROM phpbb_posts) WHERE counter_id = 1
sql_query_range = SELECT MIN(post_id), MAX(post_id) FROM phpbb_posts
sql_range_step = 5000
- sql_query = SELECT
-\
- p.post_id AS id,
-\
- p.forum_id,
-\
- p.topic_id,
-\
- p.poster_id,
-\
- CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post,
-\
- p.post_time,
-\
- p.post_subject,
-\
- p.post_subject as title,
-\
- p.post_text as data,
-\
- t.topic_last_post_time,
-\
- 0 as deleted
-\
- FROM phpbb_posts p, phpbb_topics t
-\
- WHERE
-\
- p.topic_id = t.topic_id
-\
- AND p.post_id >= $start AND p.post_id <= $end
+ sql_query = SELECT \
+ p.post_id AS id, \
+ p.forum_id, \
+ p.topic_id, \
+ p.poster_id, \
+ CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post, \
+ p.post_time, \
+ p.post_subject, \
+ p.post_subject as title, \
+ p.post_text as data, \
+ t.topic_last_post_time, \
+ 0 as deleted\
+ FROM phpbb_posts p, phpbb_topics t \
+ WHERE \
+ p.topic_id = t.topic_id \
+ AND p.post_id >= $start AND p.post_id <= $end
sql_query_post =
sql_query_post_index = UPDATE phpbb_sphinx SET max_doc_id = $maxid WHERE counter_id = 1
sql_query_info = SELECT * FROM phpbb_posts WHERE post_id = $id
@@ -55,39 +40,25 @@ source source_phpbb_{SPHINX_ID}_main
}
source source_phpbb_{SPHINX_ID}_delta : source_phpbb_{SPHINX_ID}_main
{
+ sql_query_pre =
sql_query_range =
sql_range_step =
- sql_query = SELECT
-\
- p.post_id AS id,
-\
- p.forum_id,
-\
- p.topic_id,
-\
- p.poster_id,
-\
- CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post,
-\
- p.post_time,
-\
- p.post_subject,
-\
- p.post_subject as title,
-\
- p.post_text as data,
-\
- t.topic_last_post_time,
-\
- 0 as deleted
-\
- FROM phpbb_posts p, phpbb_topics t
-\
- WHERE
-\
- p.topic_id = t.topic_id
-\
- AND p.post_id >= ( SELECT max_doc_id FROM phpbb_sphinx WHERE counter_id=1 )
+ sql_query = SELECT \
+ p.post_id AS id, \
+ p.forum_id, \
+ p.topic_id, \
+ p.poster_id, \
+ CASE WHEN p.post_id = t.topic_first_post_id THEN 1 ELSE 0 END as topic_first_post, \
+ p.post_time, \
+ p.post_subject, \
+ p.post_subject as title, \
+ p.post_text as data, \
+ t.topic_last_post_time, \
+ 0 as deleted \
+ FROM phpbb_posts p, phpbb_topics t \
+ WHERE \
+ p.topic_id = t.topic_id \
+ AND p.post_id >= ( SELECT max_doc_id FROM phpbb_sphinx WHERE counter_id=1 )
sql_query_pre =
}
index index_phpbb_{SPHINX_ID}_main
diff --git a/phpBB/download/file.php b/phpBB/download/file.php
index 4a392b002d..eee2090da0 100644
--- a/phpBB/download/file.php
+++ b/phpBB/download/file.php
@@ -50,9 +50,9 @@ if (isset($_GET['avatar']))
require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);
// Setup class loader first
- $phpbb_class_loader = new phpbb_class_loader('phpbb_', "{$phpbb_root_path}includes/", ".$phpEx");
+ $phpbb_class_loader = new phpbb_class_loader('phpbb_', "{$phpbb_root_path}includes/", $phpEx);
$phpbb_class_loader->register();
- $phpbb_class_loader_ext = new phpbb_class_loader('phpbb_ext_', "{$phpbb_root_path}ext/", ".$phpEx");
+ $phpbb_class_loader_ext = new phpbb_class_loader('phpbb_ext_', "{$phpbb_root_path}ext/", $phpEx);
$phpbb_class_loader_ext->register();
// Set up container
@@ -67,6 +67,7 @@ if (isset($_GET['avatar']))
$phpbb_dispatcher = $phpbb_container->get('dispatcher');
$request = $phpbb_container->get('request');
$db = $phpbb_container->get('dbal.conn');
+ $phpbb_log = $phpbb_container->get('log');
// Connect to DB
if (!@$db->sql_connect($dbhost, $dbuser, $dbpasswd, $dbname, $dbport, false, false))
@@ -88,6 +89,8 @@ if (isset($_GET['avatar']))
// worst-case default
$browser = strtolower($request->header('User-Agent', 'msie 6.0'));
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+
$filename = request_var('avatar', '');
$avatar_group = false;
$exit = false;
diff --git a/phpBB/includes/acp/acp_attachments.php b/phpBB/includes/acp/acp_attachments.php
index 9d6c2d5de1..d0e8ff3882 100644
--- a/phpBB/includes/acp/acp_attachments.php
+++ b/phpBB/includes/acp/acp_attachments.php
@@ -117,8 +117,8 @@ class acp_attachments
'attachment_quota' => array('lang' => 'ATTACH_QUOTA', 'validate' => 'string', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true),
'max_filesize' => array('lang' => 'ATTACH_MAX_FILESIZE', 'validate' => 'string', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true),
'max_filesize_pm' => array('lang' => 'ATTACH_MAX_PM_FILESIZE','validate' => 'string', 'type' => 'custom', 'method' => 'max_filesize', 'explain' => true),
- 'max_attachments' => array('lang' => 'MAX_ATTACHMENTS', 'validate' => 'int', 'type' => 'text:3:3', 'explain' => false),
- 'max_attachments_pm' => array('lang' => 'MAX_ATTACHMENTS_PM', 'validate' => 'int', 'type' => 'text:3:3', 'explain' => false),
+ 'max_attachments' => array('lang' => 'MAX_ATTACHMENTS', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => false),
+ 'max_attachments_pm' => array('lang' => 'MAX_ATTACHMENTS_PM', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => false),
'secure_downloads' => array('lang' => 'SECURE_DOWNLOADS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'secure_allow_deny' => array('lang' => 'SECURE_ALLOW_DENY', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_allow_deny', 'explain' => true),
'secure_allow_empty_referer' => array('lang' => 'SECURE_EMPTY_REFERRER', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
@@ -128,11 +128,11 @@ class acp_attachments
'legend2' => $l_legend_cat_images,
'img_display_inlined' => array('lang' => 'DISPLAY_INLINED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'img_create_thumbnail' => array('lang' => 'CREATE_THUMBNAIL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'img_max_thumb_width' => array('lang' => 'MAX_THUMB_WIDTH', 'validate' => 'int', 'type' => 'text:7:15', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
- 'img_min_thumb_filesize' => array('lang' => 'MIN_THUMB_FILESIZE', 'validate' => 'int', 'type' => 'text:7:15', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']),
+ 'img_max_thumb_width' => array('lang' => 'MAX_THUMB_WIDTH', 'validate' => 'int:0:999999999999999', 'type' => 'number:0:999999999999999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
+ 'img_min_thumb_filesize' => array('lang' => 'MIN_THUMB_FILESIZE', 'validate' => 'int:0:999999999999999', 'type' => 'number:0:999999999999999', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']),
'img_imagick' => array('lang' => 'IMAGICK_PATH', 'validate' => 'string', 'type' => 'text:20:200', 'explain' => true, 'append' => '&nbsp;&nbsp;<span>[ <a href="' . $this->u_action . '&amp;action=imgmagick">' . $user->lang['SEARCH_IMAGICK'] . '</a> ]</span>'),
- 'img_max' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
- 'img_link' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
+ 'img_max' => array('lang' => 'MAX_IMAGE_SIZE', 'validate' => 'int:0:9999', 'type' => 'dimension:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
+ 'img_link' => array('lang' => 'IMAGE_LINK_SIZE', 'validate' => 'int:0:9999', 'type' => 'dimension:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
)
);
@@ -1203,8 +1203,8 @@ class acp_attachments
// Just get the files
$sql = 'SELECT a.*, u.username, u.user_colour, t.topic_title
- FROM ' . ATTACHMENTS_TABLE . ' a
- LEFT JOIN ' . USERS_TABLE . ' u ON (u.user_id = a.poster_id)
+ FROM ' . ATTACHMENTS_TABLE . ' a
+ LEFT JOIN ' . USERS_TABLE . ' u ON (u.user_id = a.poster_id)
LEFT JOIN ' . TOPICS_TABLE . " t ON (a.topic_id = t.topic_id)
WHERE a.is_orphan = 0
$limit_filetime
@@ -1670,7 +1670,8 @@ class acp_attachments
$size_var = $filesize['si_identifier'];
$value = $filesize['value'];
- return '<input type="text" id="' . $key . '" size="8" maxlength="15" name="config[' . $key . ']" value="' . $value . '" /> <select name="' . $key . '">' . size_select_options($size_var) . '</select>';
+ // size="8" and maxlength="15" attributes as a fallback for browsers that do not support type="number" yet.
+ return '<input type="number" id="' . $key . '" size="8" maxlength="15" min="0" name="config[' . $key . ']" value="' . $value . '" /> <select name="' . $key . '">' . size_select_options($size_var) . '</select>';
}
/**
diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php
index a213102cc6..6881e03fdb 100644
--- a/phpBB/includes/acp/acp_board.php
+++ b/phpBB/includes/acp/acp_board.php
@@ -28,7 +28,7 @@ class acp_board
{
global $db, $user, $auth, $template;
global $config, $phpbb_root_path, $phpbb_admin_path, $phpEx;
- global $cache;
+ global $cache, $phpbb_container;
$user->add_lang('acp/board');
@@ -53,8 +53,9 @@ class acp_board
'legend1' => 'ACP_BOARD_SETTINGS',
'sitename' => array('lang' => 'SITE_NAME', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => false),
'site_desc' => array('lang' => 'SITE_DESC', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => false),
- 'site_home_url' => array('lang' => 'SITE_HOME_URL', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true),
+ 'site_home_url' => array('lang' => 'SITE_HOME_URL', 'validate' => 'string', 'type' => 'url:40:255', 'explain' => true),
'site_home_text' => array('lang' => 'SITE_HOME_TEXT', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true),
+ 'board_index_text' => array('lang' => 'BOARD_INDEX_TEXT', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true),
'board_disable' => array('lang' => 'DISABLE_BOARD', 'validate' => 'bool', 'type' => 'custom', 'method' => 'board_disable', 'explain' => true),
'board_disable_msg' => false,
'default_lang' => array('lang' => 'DEFAULT_LANGUAGE', 'validate' => 'lang', 'type' => 'select', 'function' => 'language_select', 'params' => array('{CONFIG_VALUE}'), 'explain' => false),
@@ -64,7 +65,7 @@ class acp_board
'override_user_style' => array('lang' => 'OVERRIDE_STYLE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'legend2' => 'WARNINGS',
- 'warnings_expire_days' => array('lang' => 'WARNINGS_EXPIRE', 'validate' => 'int', 'type' => 'text:3:4', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
+ 'warnings_expire_days' => array('lang' => 'WARNINGS_EXPIRE', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
'legend3' => 'ACP_SUBMIT_CHANGES',
)
@@ -107,6 +108,23 @@ class acp_board
break;
case 'avatar':
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $avatar_drivers = $phpbb_avatar_manager->get_all_drivers();
+
+ $avatar_vars = array();
+ foreach ($avatar_drivers as $current_driver)
+ {
+ $driver = $phpbb_avatar_manager->get_driver($current_driver, false);
+
+ /*
+ * First grab the settings for enabling/disabling the avatar
+ * driver and afterwards grab additional settings the driver
+ * might have.
+ */
+ $avatar_vars += $phpbb_avatar_manager->get_avatar_settings($driver);
+ $avatar_vars += $driver->prepare_form_acp($user);
+ }
+
$display_vars = array(
'title' => 'ACP_AVATAR_SETTINGS',
'vars' => array(
@@ -118,17 +136,15 @@ class acp_board
'avatar_max_height' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => false, 'method' => false, 'explain' => false),
'allow_avatar' => array('lang' => 'ALLOW_AVATARS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'allow_avatar_local' => array('lang' => 'ALLOW_LOCAL', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
- 'allow_avatar_remote' => array('lang' => 'ALLOW_REMOTE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'allow_avatar_upload' => array('lang' => 'ALLOW_UPLOAD', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
- 'allow_avatar_remote_upload'=> array('lang' => 'ALLOW_REMOTE_UPLOAD', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'avatar_filesize' => array('lang' => 'MAX_FILESIZE', 'validate' => 'int:0', 'type' => 'text:4:10', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']),
- 'avatar_min' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
- 'avatar_max' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:3:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
- 'avatar_path' => array('lang' => 'AVATAR_STORAGE_PATH', 'validate' => 'rwpath', 'type' => 'text:20:255', 'explain' => true),
- 'avatar_gallery_path' => array('lang' => 'AVATAR_GALLERY_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true),
+ 'avatar_min' => array('lang' => 'MIN_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:0', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
+ 'avatar_max' => array('lang' => 'MAX_AVATAR_SIZE', 'validate' => 'int:0', 'type' => 'dimension:0', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
)
);
+
+ if (!empty($avatar_vars))
+ {
+ $display_vars['vars'] += $avatar_vars;
+ }
break;
case 'message':
@@ -138,11 +154,11 @@ class acp_board
'vars' => array(
'legend1' => 'GENERAL_SETTINGS',
'allow_privmsg' => array('lang' => 'BOARD_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'pm_max_boxes' => array('lang' => 'BOXES_MAX', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true),
- 'pm_max_msgs' => array('lang' => 'BOXES_LIMIT', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true),
+ 'pm_max_boxes' => array('lang' => 'BOXES_MAX', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'pm_max_msgs' => array('lang' => 'BOXES_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
'full_folder_action' => array('lang' => 'FULL_FOLDER_ACTION', 'validate' => 'int', 'type' => 'select', 'method' => 'full_folder_select', 'explain' => true),
- 'pm_edit_time' => array('lang' => 'PM_EDIT_TIME', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']),
- 'pm_max_recipients' => array('lang' => 'PM_MAX_RECIPIENTS', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true),
+ 'pm_edit_time' => array('lang' => 'PM_EDIT_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']),
+ 'pm_max_recipients' => array('lang' => 'PM_MAX_RECIPIENTS', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true),
'legend2' => 'GENERAL_OPTIONS',
'allow_mass_pm' => array('lang' => 'ALLOW_MASS_PM', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
@@ -179,24 +195,24 @@ class acp_board
'legend2' => 'POSTING',
'bump_type' => false,
- 'edit_time' => array('lang' => 'EDIT_TIME', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']),
- 'delete_time' => array('lang' => 'DELETE_TIME', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']),
+ 'edit_time' => array('lang' => 'EDIT_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']),
+ 'delete_time' => array('lang' => 'DELETE_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']),
'display_last_edited' => array('lang' => 'DISPLAY_LAST_EDITED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'flood_interval' => array('lang' => 'FLOOD_INTERVAL', 'validate' => 'int:0', 'type' => 'text:3:10', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
+ 'flood_interval' => array('lang' => 'FLOOD_INTERVAL', 'validate' => 'int:0:9999999999', 'type' => 'number:0:9999999999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
'bump_interval' => array('lang' => 'BUMP_INTERVAL', 'validate' => 'int:0', 'type' => 'custom', 'method' => 'bump_interval', 'explain' => true),
- 'topics_per_page' => array('lang' => 'TOPICS_PER_PAGE', 'validate' => 'int:1', 'type' => 'text:3:4', 'explain' => false),
- 'posts_per_page' => array('lang' => 'POSTS_PER_PAGE', 'validate' => 'int:1', 'type' => 'text:3:4', 'explain' => false),
- 'smilies_per_page' => array('lang' => 'SMILIES_PER_PAGE', 'validate' => 'int:1', 'type' => 'text:3:4', 'explain' => false),
- 'hot_threshold' => array('lang' => 'HOT_THRESHOLD', 'validate' => 'int:0', 'type' => 'text:3:4', 'explain' => true),
- 'max_poll_options' => array('lang' => 'MAX_POLL_OPTIONS', 'validate' => 'int:2:127', 'type' => 'text:4:4', 'explain' => false),
- 'max_post_chars' => array('lang' => 'CHAR_LIMIT', 'validate' => 'int:0', 'type' => 'text:4:6', 'explain' => true),
- 'min_post_chars' => array('lang' => 'MIN_CHAR_LIMIT', 'validate' => 'int:1', 'type' => 'text:4:6', 'explain' => true),
- 'max_post_smilies' => array('lang' => 'SMILIES_LIMIT', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true),
- 'max_post_urls' => array('lang' => 'MAX_POST_URLS', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true),
- 'max_post_font_size' => array('lang' => 'MAX_POST_FONT_SIZE', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' %'),
- 'max_quote_depth' => array('lang' => 'QUOTE_DEPTH_LIMIT', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true),
- 'max_post_img_width' => array('lang' => 'MAX_POST_IMG_WIDTH', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
- 'max_post_img_height' => array('lang' => 'MAX_POST_IMG_HEIGHT', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
+ 'topics_per_page' => array('lang' => 'TOPICS_PER_PAGE', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => false),
+ 'posts_per_page' => array('lang' => 'POSTS_PER_PAGE', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => false),
+ 'smilies_per_page' => array('lang' => 'SMILIES_PER_PAGE', 'validate' => 'int:1:9999', 'type' => 'number:1:9999', 'explain' => false),
+ 'hot_threshold' => array('lang' => 'HOT_THRESHOLD', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'max_poll_options' => array('lang' => 'MAX_POLL_OPTIONS', 'validate' => 'int:2:127', 'type' => 'number:2:127', 'explain' => false),
+ 'max_post_chars' => array('lang' => 'CHAR_LIMIT', 'validate' => 'int:0:999999', 'type' => 'number:0:999999', 'explain' => true),
+ 'min_post_chars' => array('lang' => 'MIN_CHAR_LIMIT', 'validate' => 'int:1:999999', 'type' => 'number:1:999999', 'explain' => true),
+ 'max_post_smilies' => array('lang' => 'SMILIES_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'max_post_urls' => array('lang' => 'MAX_POST_URLS', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'max_post_font_size' => array('lang' => 'MAX_POST_FONT_SIZE', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' %'),
+ 'max_quote_depth' => array('lang' => 'QUOTE_DEPTH_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'max_post_img_width' => array('lang' => 'MAX_POST_IMG_WIDTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
+ 'max_post_img_height' => array('lang' => 'MAX_POST_IMG_HEIGHT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
'legend3' => 'ACP_SUBMIT_CHANGES',
)
@@ -216,12 +232,12 @@ class acp_board
'allow_sig_links' => array('lang' => 'ALLOW_SIG_LINKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'legend2' => 'GENERAL_SETTINGS',
- 'max_sig_chars' => array('lang' => 'MAX_SIG_LENGTH', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true),
- 'max_sig_urls' => array('lang' => 'MAX_SIG_URLS', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true),
- 'max_sig_font_size' => array('lang' => 'MAX_SIG_FONT_SIZE', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' %'),
- 'max_sig_smilies' => array('lang' => 'MAX_SIG_SMILIES', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true),
- 'max_sig_img_width' => array('lang' => 'MAX_SIG_IMG_WIDTH', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
- 'max_sig_img_height' => array('lang' => 'MAX_SIG_IMG_HEIGHT', 'validate' => 'int:0', 'type' => 'text:5:4', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
+ 'max_sig_chars' => array('lang' => 'MAX_SIG_LENGTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'max_sig_urls' => array('lang' => 'MAX_SIG_URLS', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'max_sig_font_size' => array('lang' => 'MAX_SIG_FONT_SIZE', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' %'),
+ 'max_sig_smilies' => array('lang' => 'MAX_SIG_SMILIES', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'max_sig_img_width' => array('lang' => 'MAX_SIG_IMG_WIDTH', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
+ 'max_sig_img_height' => array('lang' => 'MAX_SIG_IMG_HEIGHT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true, 'append' => ' ' . $user->lang['PIXEL']),
'legend3' => 'ACP_SUBMIT_CHANGES',
)
@@ -237,20 +253,20 @@ class acp_board
'max_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:8:255', 'type' => false, 'method' => false, 'explain' => false,),
'require_activation' => array('lang' => 'ACC_ACTIVATION', 'validate' => 'int', 'type' => 'select', 'method' => 'select_acc_activation', 'explain' => true),
- 'new_member_post_limit' => array('lang' => 'NEW_MEMBER_POST_LIMIT', 'validate' => 'int:0:255', 'type' => 'text:4:4', 'explain' => true, 'append' => ' ' . $user->lang['POSTS']),
+ 'new_member_post_limit' => array('lang' => 'NEW_MEMBER_POST_LIMIT', 'validate' => 'int:0:255', 'type' => 'number:0:255', 'explain' => true, 'append' => ' ' . $user->lang['POSTS']),
'new_member_group_default'=> array('lang' => 'NEW_MEMBER_GROUP_DEFAULT', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'min_name_chars' => array('lang' => 'USERNAME_LENGTH', 'validate' => 'int:1', 'type' => 'custom:5:180', 'method' => 'username_length', 'explain' => true),
'min_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:1', 'type' => 'custom', 'method' => 'password_length', 'explain' => true),
'allow_name_chars' => array('lang' => 'USERNAME_CHARS', 'validate' => 'string', 'type' => 'select', 'method' => 'select_username_chars', 'explain' => true),
'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true),
- 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
+ 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
'legend2' => 'GENERAL_OPTIONS',
'allow_namechange' => array('lang' => 'ALLOW_NAME_CHANGE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
'allow_emailreuse' => array('lang' => 'ALLOW_EMAIL_REUSE', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'enable_confirm' => array('lang' => 'VISUAL_CONFIRM_REG', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true),
- 'max_reg_attempts' => array('lang' => 'REG_LIMIT', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true),
+ 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true),
+ 'max_reg_attempts' => array('lang' => 'REG_LIMIT', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
'legend3' => 'COPPA',
'coppa_enable' => array('lang' => 'ENABLE_COPPA', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
@@ -272,13 +288,13 @@ class acp_board
'feed_http_auth' => array('lang' => 'ACP_FEED_HTTP_AUTH', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true),
'legend2' => 'ACP_FEED_POST_BASED',
- 'feed_limit_post' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5', 'type' => 'text:3:4', 'explain' => true),
+ 'feed_limit_post' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5:9999', 'type' => 'number:5:9999', 'explain' => true),
'feed_overall' => array('lang' => 'ACP_FEED_OVERALL', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ),
'feed_forum' => array('lang' => 'ACP_FEED_FORUM', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ),
'feed_topic' => array('lang' => 'ACP_FEED_TOPIC', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ),
'legend3' => 'ACP_FEED_TOPIC_BASED',
- 'feed_limit_topic' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5', 'type' => 'text:3:4', 'explain' => true),
+ 'feed_limit_topic' => array('lang' => 'ACP_FEED_LIMIT', 'validate' => 'int:5:9999', 'type' => 'number:5:9999', 'explain' => true),
'feed_topics_new' => array('lang' => 'ACP_FEED_TOPICS_NEW', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ),
'feed_topics_active' => array('lang' => 'ACP_FEED_TOPICS_ACTIVE', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true ),
'feed_news_id' => array('lang' => 'ACP_FEED_NEWS', 'validate' => 'string', 'type' => 'custom', 'method' => 'select_news_forums', 'explain' => true),
@@ -308,10 +324,10 @@ class acp_board
'title' => 'ACP_LOAD_SETTINGS',
'vars' => array(
'legend1' => 'GENERAL_SETTINGS',
- 'limit_load' => array('lang' => 'LIMIT_LOAD', 'validate' => 'string', 'type' => 'text:4:4', 'explain' => true),
- 'session_length' => array('lang' => 'SESSION_LENGTH', 'validate' => 'int:60', 'type' => 'text:5:10', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
- 'active_sessions' => array('lang' => 'LIMIT_SESSIONS', 'validate' => 'int:0', 'type' => 'text:4:4', 'explain' => true),
- 'load_online_time' => array('lang' => 'ONLINE_LENGTH', 'validate' => 'int:0', 'type' => 'text:4:3', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']),
+ 'limit_load' => array('lang' => 'LIMIT_LOAD', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'session_length' => array('lang' => 'SESSION_LENGTH', 'validate' => 'int:60:9999999999', 'type' => 'number:60:9999999999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
+ 'active_sessions' => array('lang' => 'LIMIT_SESSIONS', 'validate' => 'int:0:9999', 'type' => 'number:0:9999', 'explain' => true),
+ 'load_online_time' => array('lang' => 'ONLINE_LENGTH', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true, 'append' => ' ' . $user->lang['MINUTES']),
'legend2' => 'GENERAL_OPTIONS',
'load_notifications' => array('lang' => 'LOAD_NOTIFICATIONS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
@@ -368,7 +384,7 @@ class acp_board
'force_server_vars' => array('lang' => 'FORCE_SERVER_VARS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'server_protocol' => array('lang' => 'SERVER_PROTOCOL', 'validate' => 'string', 'type' => 'text:10:10', 'explain' => true),
'server_name' => array('lang' => 'SERVER_NAME', 'validate' => 'string', 'type' => 'text:40:255', 'explain' => true),
- 'server_port' => array('lang' => 'SERVER_PORT', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true),
+ 'server_port' => array('lang' => 'SERVER_PORT', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true),
'script_path' => array('lang' => 'SCRIPT_PATH', 'validate' => 'script_path', 'type' => 'text::255', 'explain' => true),
'legend4' => 'ACP_SUBMIT_CHANGES',
@@ -382,7 +398,8 @@ class acp_board
'vars' => array(
'legend1' => 'ACP_SECURITY_SETTINGS',
'allow_autologin' => array('lang' => 'ALLOW_AUTOLOGIN', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'max_autologin_time' => array('lang' => 'AUTOLOGIN_LENGTH', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
+ 'allow_password_reset' => array('lang' => 'ALLOW_PASSWORD_RESET', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
+ 'max_autologin_time' => array('lang' => 'AUTOLOGIN_LENGTH', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
'ip_check' => array('lang' => 'IP_VALID', 'validate' => 'int', 'type' => 'custom', 'method' => 'select_ip_check', 'explain' => true),
'browser_check' => array('lang' => 'BROWSER_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'forwarded_for_check' => array('lang' => 'FORWARDED_FOR_VALID', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
@@ -392,13 +409,13 @@ class acp_board
'max_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:8:255', 'type' => false, 'method' => false, 'explain' => false,),
'min_pass_chars' => array('lang' => 'PASSWORD_LENGTH', 'validate' => 'int:1', 'type' => 'custom', 'method' => 'password_length', 'explain' => true),
'pass_complex' => array('lang' => 'PASSWORD_TYPE', 'validate' => 'string', 'type' => 'select', 'method' => 'select_password_chars', 'explain' => true),
- 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
- 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true),
- 'ip_login_limit_max' => array('lang' => 'IP_LOGIN_LIMIT_MAX', 'validate' => 'int:0', 'type' => 'text:3:3', 'explain' => true),
- 'ip_login_limit_time' => array('lang' => 'IP_LOGIN_LIMIT_TIME', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
+ 'chg_passforce' => array('lang' => 'FORCE_PASS_CHANGE', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true, 'append' => ' ' . $user->lang['DAYS']),
+ 'max_login_attempts' => array('lang' => 'MAX_LOGIN_ATTEMPTS', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true),
+ 'ip_login_limit_max' => array('lang' => 'IP_LOGIN_LIMIT_MAX', 'validate' => 'int:0:999', 'type' => 'number:0:999', 'explain' => true),
+ 'ip_login_limit_time' => array('lang' => 'IP_LOGIN_LIMIT_TIME', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
'ip_login_limit_use_forwarded' => array('lang' => 'IP_LOGIN_LIMIT_USE_FORWARDED', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'tpl_allow_php' => array('lang' => 'TPL_ALLOW_PHP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
- 'form_token_lifetime' => array('lang' => 'FORM_TIME_MAX', 'validate' => 'int:-1', 'type' => 'text:5:5', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
+ 'form_token_lifetime' => array('lang' => 'FORM_TIME_MAX', 'validate' => 'int:-1:99999', 'type' => 'number:-1:99999', 'explain' => true, 'append' => ' ' . $user->lang['SECONDS']),
'form_token_sid_guests' => array('lang' => 'FORM_SID_GUESTS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
)
@@ -413,16 +430,16 @@ class acp_board
'email_enable' => array('lang' => 'ENABLE_EMAIL', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true),
'board_email_form' => array('lang' => 'BOARD_EMAIL_FORM', 'validate' => 'bool', 'type' => 'radio:enabled_disabled', 'explain' => true),
'email_function_name' => array('lang' => 'EMAIL_FUNCTION_NAME', 'validate' => 'string', 'type' => 'text:20:50', 'explain' => true),
- 'email_package_size' => array('lang' => 'EMAIL_PACKAGE_SIZE', 'validate' => 'int:0', 'type' => 'text:5:5', 'explain' => true),
- 'board_contact' => array('lang' => 'CONTACT_EMAIL', 'validate' => 'email', 'type' => 'text:25:100', 'explain' => true),
- 'board_email' => array('lang' => 'ADMIN_EMAIL', 'validate' => 'email', 'type' => 'text:25:100', 'explain' => true),
+ 'email_package_size' => array('lang' => 'EMAIL_PACKAGE_SIZE', 'validate' => 'int:0', 'type' => 'number:0:99999', 'explain' => true),
+ 'board_contact' => array('lang' => 'CONTACT_EMAIL', 'validate' => 'email', 'type' => 'email:25:100', 'explain' => true),
+ 'board_email' => array('lang' => 'ADMIN_EMAIL', 'validate' => 'email', 'type' => 'email:25:100', 'explain' => true),
'board_email_sig' => array('lang' => 'EMAIL_SIG', 'validate' => 'string', 'type' => 'textarea:5:30', 'explain' => true),
'board_hide_emails' => array('lang' => 'BOARD_HIDE_EMAILS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'legend2' => 'SMTP_SETTINGS',
'smtp_delivery' => array('lang' => 'USE_SMTP', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'smtp_host' => array('lang' => 'SMTP_SERVER', 'validate' => 'string', 'type' => 'text:25:50', 'explain' => false),
- 'smtp_port' => array('lang' => 'SMTP_PORT', 'validate' => 'int:0', 'type' => 'text:4:5', 'explain' => true),
+ 'smtp_port' => array('lang' => 'SMTP_PORT', 'validate' => 'int:0:99999', 'type' => 'number:0:99999', 'explain' => true),
'smtp_auth_method' => array('lang' => 'SMTP_AUTH_METHOD', 'validate' => 'string', 'type' => 'select', 'method' => 'mail_auth_select', 'explain' => true),
'smtp_username' => array('lang' => 'SMTP_USERNAME', 'validate' => 'string', 'type' => 'text:25:255', 'explain' => true),
'smtp_password' => array('lang' => 'SMTP_PASSWORD', 'validate' => 'string', 'type' => 'password:25:255', 'explain' => true),
@@ -788,7 +805,7 @@ class acp_board
{
$act_ary['ACC_USER'] = USER_ACTIVATION_SELF;
$act_ary['ACC_ADMIN'] = USER_ACTIVATION_ADMIN;
- }
+ }
$act_options = '';
foreach ($act_ary as $key => $value)
@@ -807,7 +824,7 @@ class acp_board
{
global $user;
- return '<input id="' . $key . '" type="text" size="3" maxlength="3" name="config[min_name_chars]" value="' . $value . '" /> ' . $user->lang['MIN_CHARS'] . '&nbsp;&nbsp;<input type="text" size="3" maxlength="3" name="config[max_name_chars]" value="' . $this->new_config['max_name_chars'] . '" /> ' . $user->lang['MAX_CHARS'];
+ return '<input id="' . $key . '" type="number" size="3" maxlength="3" min="1" max="999" name="config[min_name_chars]" value="' . $value . '" /> ' . $user->lang['MIN_CHARS'] . '&nbsp;&nbsp;<input type="number" size="3" maxlength="3" min="8" max="180" name="config[max_name_chars]" value="' . $this->new_config['max_name_chars'] . '" /> ' . $user->lang['MAX_CHARS'];
}
/**
@@ -835,7 +852,7 @@ class acp_board
{
global $user;
- return '<input id="' . $key . '" type="text" size="3" maxlength="3" name="config[min_pass_chars]" value="' . $value . '" /> ' . $user->lang['MIN_CHARS'] . '&nbsp;&nbsp;<input type="text" size="3" maxlength="3" name="config[max_pass_chars]" value="' . $this->new_config['max_pass_chars'] . '" /> ' . $user->lang['MAX_CHARS'];
+ return '<input id="' . $key . '" type="number" size="3" maxlength="3" min="1" max="999" name="config[min_pass_chars]" value="' . $value . '" /> ' . $user->lang['MIN_CHARS'] . '&nbsp;&nbsp;<input type="number" size="3" maxlength="3" min="8" max="255" name="config[max_pass_chars]" value="' . $this->new_config['max_pass_chars'] . '" /> ' . $user->lang['MAX_CHARS'];
}
/**
diff --git a/phpBB/includes/acp/acp_extensions.php b/phpBB/includes/acp/acp_extensions.php
index 24211196bd..379e779c2c 100644
--- a/phpBB/includes/acp/acp_extensions.php
+++ b/phpBB/includes/acp/acp_extensions.php
@@ -44,6 +44,10 @@ class acp_extensions
$action = $request->variable('action', 'list');
$ext_name = $request->variable('ext_name', '');
+ // What is a safe limit of execution time? Half the max execution time should be safe.
+ $safe_time_limit = (ini_get('max_execution_time') / 2);
+ $start_time = time();
+
// Cancel action
if ($request->is_set_post('cancel'))
{
@@ -54,7 +58,7 @@ class acp_extensions
// If they've specified an extension, let's load the metadata manager and validate it.
if ($ext_name)
{
- $md_manager = new phpbb_extension_metadata_manager($ext_name, $db, $phpbb_extension_manager, $phpbb_root_path, ".$phpEx", $template, $config);
+ $md_manager = new phpbb_extension_metadata_manager($ext_name, $config, $phpbb_extension_manager, $template, $phpbb_root_path);
try
{
@@ -81,7 +85,7 @@ class acp_extensions
case 'enable_pre':
if (!$md_manager->validate_enable())
{
- trigger_error($user->lang['EXTENSION_NOT_AVAILABLE'] . adm_back_link($this->u_action));
+ trigger_error($user->lang['EXTENSION_NOT_AVAILABLE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
if ($phpbb_extension_manager->enabled($ext_name))
@@ -100,16 +104,20 @@ class acp_extensions
case 'enable':
if (!$md_manager->validate_enable())
{
- trigger_error($user->lang['EXTENSION_NOT_AVAILABLE'] . adm_back_link($this->u_action));
+ trigger_error($user->lang['EXTENSION_NOT_AVAILABLE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
try
{
- if ($phpbb_extension_manager->enable_step($ext_name))
+ while ($phpbb_extension_manager->enable_step($ext_name))
{
- $template->assign_var('S_NEXT_STEP', true);
+ // Are we approaching the time limit? If so we want to pause the update and continue after refreshing
+ if ((time() - $start_time) >= $safe_time_limit)
+ {
+ $template->assign_var('S_NEXT_STEP', true);
- meta_refresh(0, $this->u_action . '&amp;action=enable&amp;ext_name=' . urlencode($ext_name));
+ meta_refresh(0, $this->u_action . '&amp;action=enable&amp;ext_name=' . urlencode($ext_name));
+ }
}
}
catch (phpbb_db_migration_exception $e)
@@ -139,11 +147,15 @@ class acp_extensions
break;
case 'disable':
- if ($phpbb_extension_manager->disable_step($ext_name))
+ while ($phpbb_extension_manager->disable_step($ext_name))
{
- $template->assign_var('S_NEXT_STEP', true);
+ // Are we approaching the time limit? If so we want to pause the update and continue after refreshing
+ if ((time() - $start_time) >= $safe_time_limit)
+ {
+ $template->assign_var('S_NEXT_STEP', true);
- meta_refresh(0, $this->u_action . '&amp;action=disable&amp;ext_name=' . urlencode($ext_name));
+ meta_refresh(0, $this->u_action . '&amp;action=disable&amp;ext_name=' . urlencode($ext_name));
+ }
}
$this->tpl_name = 'acp_ext_disable';
@@ -165,11 +177,15 @@ class acp_extensions
case 'purge':
try
{
- if ($phpbb_extension_manager->purge_step($ext_name))
+ while ($phpbb_extension_manager->purge_step($ext_name))
{
- $template->assign_var('S_NEXT_STEP', true);
+ // Are we approaching the time limit? If so we want to pause the update and continue after refreshing
+ if ((time() - $start_time) >= $safe_time_limit)
+ {
+ $template->assign_var('S_NEXT_STEP', true);
- meta_refresh(0, $this->u_action . '&amp;action=purge&amp;ext_name=' . urlencode($ext_name));
+ meta_refresh(0, $this->u_action . '&amp;action=purge&amp;ext_name=' . urlencode($ext_name));
+ }
}
}
catch (phpbb_db_migration_exception $e)
diff --git a/phpBB/includes/acp/acp_groups.php b/phpBB/includes/acp/acp_groups.php
index 21b1d4b837..c740ff7ddc 100644
--- a/phpBB/includes/acp/acp_groups.php
+++ b/phpBB/includes/acp/acp_groups.php
@@ -26,7 +26,7 @@ class acp_groups
{
global $config, $db, $user, $auth, $template, $cache;
global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix, $file_uploads;
- global $request;
+ global $request, $phpbb_container;
$user->add_lang('acp/groups');
$this->tpl_name = 'acp_groups';
@@ -55,15 +55,16 @@ class acp_groups
// Clear some vars
- $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false;
$group_row = array();
// Grab basic data for group, if group_id is set and exists
if ($group_id)
{
- $sql = 'SELECT *
- FROM ' . GROUPS_TABLE . "
- WHERE group_id = $group_id";
+ $sql = 'SELECT g.*, t.teampage_position AS group_teampage
+ FROM ' . GROUPS_TABLE . ' g
+ LEFT JOIN ' . TEAMPAGE_TABLE . ' t
+ ON (t.group_id = g.group_id)
+ WHERE g.group_id = ' . $group_id;
$result = $db->sql_query($sql);
$group_row = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
@@ -147,57 +148,58 @@ class acp_groups
'action' => $action))
);
}
+ break;
- break;
case 'set_default_on_all':
- if (confirm_box(true))
- {
- $group_name = ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name'];
-
- $start = 0;
+ if (confirm_box(true))
+ {
+ $group_name = ($group_row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $group_row['group_name']] : $group_row['group_name'];
+
+ $start = 0;
- do
+ do
+ {
+ $sql = 'SELECT user_id
+ FROM ' . USER_GROUP_TABLE . "
+ WHERE group_id = $group_id
+ ORDER BY user_id";
+ $result = $db->sql_query_limit($sql, 200, $start);
+
+ $mark_ary = array();
+ if ($row = $db->sql_fetchrow($result))
{
- $sql = 'SELECT user_id
- FROM ' . USER_GROUP_TABLE . "
- WHERE group_id = $group_id
- ORDER BY user_id";
- $result = $db->sql_query_limit($sql, 200, $start);
-
- $mark_ary = array();
- if ($row = $db->sql_fetchrow($result))
+ do
{
- do
- {
- $mark_ary[] = $row['user_id'];
- }
- while ($row = $db->sql_fetchrow($result));
+ $mark_ary[] = $row['user_id'];
+ }
+ while ($row = $db->sql_fetchrow($result));
- group_user_attributes('default', $group_id, $mark_ary, false, $group_name, $group_row);
+ group_user_attributes('default', $group_id, $mark_ary, false, $group_name, $group_row);
- $start = (sizeof($mark_ary) < 200) ? 0 : $start + 200;
- }
- else
- {
- $start = 0;
- }
- $db->sql_freeresult($result);
+ $start = (sizeof($mark_ary) < 200) ? 0 : $start + 200;
}
- while ($start);
-
- trigger_error($user->lang['GROUP_DEFS_UPDATED'] . adm_back_link($this->u_action . '&amp;action=list&amp;g=' . $group_id));
- }
- else
- {
- confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array(
- 'mark' => $mark_ary,
- 'g' => $group_id,
- 'i' => $id,
- 'mode' => $mode,
- 'action' => $action))
- );
+ else
+ {
+ $start = 0;
+ }
+ $db->sql_freeresult($result);
}
+ while ($start);
+
+ trigger_error($user->lang['GROUP_DEFS_UPDATED'] . adm_back_link($this->u_action . '&amp;action=list&amp;g=' . $group_id));
+ }
+ else
+ {
+ confirm_box(false, $user->lang['CONFIRM_OPERATION'], build_hidden_fields(array(
+ 'mark' => $mark_ary,
+ 'g' => $group_id,
+ 'i' => $id,
+ 'mode' => $mode,
+ 'action' => $action))
+ );
+ }
break;
+
case 'deleteusers':
if (empty($mark_ary))
{
@@ -300,8 +302,21 @@ class acp_groups
$error = array();
$user->add_lang('ucp');
- $avatar_select = basename(request_var('avatar_select', ''));
- $category = basename(request_var('category', ''));
+ // Setup avatar data for later
+ $avatars_enabled = false;
+ $avatar_drivers = null;
+ $avatar_data = null;
+ $avatar_error = array();
+
+ if ($config['allow_avatar'])
+ {
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers();
+
+ // This is normalised data, without the group_ prefix
+ $avatar_data = phpbb_avatar_manager::clean_row($group_row);
+ }
+
// Did we submit?
if ($update)
@@ -319,12 +334,6 @@ class acp_groups
$allow_desc_urls = request_var('desc_parse_urls', false);
$allow_desc_smilies = request_var('desc_parse_smilies', false);
- $data['uploadurl'] = request_var('uploadurl', '');
- $data['remotelink'] = request_var('remotelink', '');
- $data['width'] = request_var('width', '');
- $data['height'] = request_var('height', '');
- $delete = request_var('delete', '');
-
$submit_ary = array(
'colour' => request_var('group_colour', ''),
'rank' => request_var('group_rank', 0),
@@ -342,91 +351,56 @@ class acp_groups
$submit_ary['founder_manage'] = isset($_REQUEST['group_founder_manage']) ? 1 : 0;
}
- $uploadfile = $request->file('uploadfile');
- if (!empty($uploadfile['tmp_name']) || $data['uploadurl'] || $data['remotelink'])
+ if ($config['allow_avatar'])
{
- // Avatar stuff
- $var_ary = array(
- 'uploadurl' => array('string', true, 5, 255),
- 'remotelink' => array('string', true, 5, 255),
- 'width' => array('string', true, 1, 3),
- 'height' => array('string', true, 1, 3),
- );
+ // Handle avatar
+ $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', ''));
- if (!($error = validate_data($data, $var_ary)))
+ if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete'))
{
- $data['user_id'] = "g$group_id";
+ $driver = $phpbb_avatar_manager->get_driver($driver_name);
+ $result = $driver->process_form($request, $template, $user, $avatar_data, $avatar_error);
- if ((!empty($uploadfile['tmp_name']) || $data['uploadurl']) && $can_upload)
+ if ($result && empty($avatar_error))
{
- list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_upload($data, $error);
+ $result['avatar_type'] = $driver_name;
+ $submit_ary = array_merge($submit_ary, $result);
}
- else if ($data['remotelink'])
- {
- list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_remote($data, $error);
- }
- }
- }
- else if ($avatar_select && $config['allow_avatar_local'])
- {
- // check avatar gallery
- if (is_dir($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category))
- {
- $submit_ary['avatar_type'] = AVATAR_GALLERY;
-
- list($submit_ary['avatar_width'], $submit_ary['avatar_height']) = getimagesize($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category . '/' . $avatar_select);
- $submit_ary['avatar'] = $category . '/' . $avatar_select;
}
- }
- else if ($delete)
- {
- $submit_ary['avatar'] = '';
- $submit_ary['avatar_type'] = $submit_ary['avatar_width'] = $submit_ary['avatar_height'] = 0;
- }
- else if ($data['width'] && $data['height'])
- {
- // Only update the dimensions?
- if ($config['avatar_max_width'] || $config['avatar_max_height'])
+ else
{
- if ($data['width'] > $config['avatar_max_width'] || $data['height'] > $config['avatar_max_height'])
+ $driver = $phpbb_avatar_manager->get_driver($user->data['user_avatar_type']);
+ if ($driver)
{
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
+ $driver->delete($avatar_data);
}
- }
- if (!sizeof($error))
- {
- if ($config['avatar_min_width'] || $config['avatar_min_height'])
- {
- if ($data['width'] < $config['avatar_min_width'] || $data['height'] < $config['avatar_min_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
- }
- }
+ // Removing the avatar
+ $submit_ary['avatar_type'] = '';
+ $submit_ary['avatar'] = '';
+ $submit_ary['avatar_width'] = 0;
+ $submit_ary['avatar_height'] = 0;
}
- if (!sizeof($error))
- {
- $submit_ary['avatar_width'] = $data['width'];
- $submit_ary['avatar_height'] = $data['height'];
- }
+ // Merge any avatar errors into the primary error array
+ $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error));
}
- if ((isset($submit_ary['avatar']) && $submit_ary['avatar'] && (!isset($group_row['group_avatar']))) || $delete)
- {
- if (isset($group_row['group_avatar']) && $group_row['group_avatar'])
- {
- avatar_delete('group', $group_row, true);
- }
- }
+ /*
+ * Validate the length of "Maximum number of allowed recipients per
+ * private message" setting. We use 16777215 as a maximum because it matches
+ * MySQL unsigned mediumint maximum value which is the lowest amongst DBMSes
+ * supported by phpBB3. Also validate the submitted colour value.
+ */
+ $validation_checks = array(
+ 'max_recipients' => array('num', false, 0, 16777215),
+ 'colour' => array('hex_colour', true),
+ );
- // Validate the length of "Maximum number of allowed recipients per private message" setting.
- // We use 16777215 as a maximum because it matches MySQL unsigned mediumint maximum value
- // which is the lowest amongst DBMSes supported by phpBB3
- if ($max_recipients_error = validate_data($submit_ary, array('max_recipients' => array('num', false, 0, 16777215))))
+ if ($validation_error = validate_data($submit_ary, $validation_checks))
{
// Replace "error" string with its real, localised form
- $error = array_merge($error, array_map(array(&$user, 'lang'), $max_recipients_error));
+ $error = array_merge($error, array_map(array(&$user, 'lang'), $validation_error));
}
if (!sizeof($error))
@@ -443,7 +417,7 @@ class acp_groups
'rank' => 'int',
'colour' => 'string',
'avatar' => 'string',
- 'avatar_type' => 'int',
+ 'avatar_type' => 'string',
'avatar_width' => 'int',
'avatar_height' => 'int',
'receive_pm' => 'int',
@@ -514,7 +488,7 @@ class acp_groups
}
}
- $cache->destroy('sql', GROUPS_TABLE);
+ $cache->destroy('sql', array(GROUPS_TABLE, TEAMPAGE_TABLE));
$message = ($action == 'edit') ? 'GROUP_UPDATED' : 'GROUP_CREATED';
trigger_error($user->lang[$message] . adm_back_link($this->u_action));
@@ -573,13 +547,44 @@ class acp_groups
$type_closed = ($group_type == GROUP_CLOSED) ? ' checked="checked"' : '';
$type_hidden = ($group_type == GROUP_HIDDEN) ? ' checked="checked"' : '';
- $avatar_img = (!empty($group_row['group_avatar'])) ? get_user_avatar($group_row['group_avatar'], $group_row['group_avatar_type'], $group_row['group_avatar_width'], $group_row['group_avatar_height'], 'GROUP_AVATAR') : '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />';
+ // Load up stuff for avatars
+ if ($config['allow_avatar'])
+ {
+ $avatars_enabled = false;
+ $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $avatar_data['avatar_type']));
+
+ foreach ($avatar_drivers as $current_driver)
+ {
+ $driver = $phpbb_avatar_manager->get_driver($current_driver);
- $display_gallery = (isset($_POST['display_gallery'])) ? true : false;
+ $avatars_enabled = true;
+ $config_name = $phpbb_avatar_manager->get_driver_config_name($driver);
+ $template->set_filenames(array(
+ 'avatar' => "acp_avatar_options_{$config_name}.html",
+ ));
- if ($config['allow_avatar_local'] && $display_gallery)
+ if ($driver->prepare_form($request, $template, $user, $avatar_data, $avatar_error))
+ {
+ $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver);
+ $driver_upper = strtoupper($driver_name);
+ $template->assign_block_vars('avatar_drivers', array(
+ 'L_TITLE' => $user->lang($driver_upper . '_TITLE'),
+ 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'),
+
+ 'DRIVER' => $driver_name,
+ 'SELECTED' => $current_driver == $selected_driver,
+ 'OUTPUT' => $template->assign_display('avatar'),
+ ));
+ }
+ }
+ }
+
+ $avatar = phpbb_get_group_avatar($group_row, 'GROUP_AVATAR', true);
+
+ if (!$update)
{
- avatar_gallery($category, $avatar_select, 4);
+ // Merge any avatar errors into the primary error array
+ $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error));
}
$back_link = request_var('back_link', '');
@@ -600,12 +605,10 @@ class acp_groups
'S_ADD_GROUP' => ($action == 'add') ? true : false,
'S_GROUP_PERM' => ($action == 'add' && $auth->acl_get('a_authgroups') && $auth->acl_gets('a_aauth', 'a_fauth', 'a_mauth', 'a_uauth')) ? true : false,
'S_INCLUDE_SWATCH' => true,
- 'S_CAN_UPLOAD' => $can_upload,
'S_ERROR' => (sizeof($error)) ? true : false,
'S_SPECIAL_GROUP' => ($group_type == GROUP_SPECIAL) ? true : false,
- 'S_DISPLAY_GALLERY' => ($config['allow_avatar_local'] && !$display_gallery) ? true : false,
- 'S_IN_GALLERY' => ($config['allow_avatar_local'] && $display_gallery) ? true : false,
'S_USER_FOUNDER' => ($user->data['user_type'] == USER_FOUNDER) ? true : false,
+ 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled),
'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '',
'GROUP_NAME' => ($group_type == GROUP_SPECIAL) ? $user->lang['G_' . $group_name] : $group_name,
@@ -626,8 +629,7 @@ class acp_groups
'S_RANK_OPTIONS' => $rank_options,
'S_GROUP_OPTIONS' => group_select_options(false, false, (($user->data['user_type'] == USER_FOUNDER) ? false : 0)),
- 'AVATAR' => $avatar_img,
- 'AVATAR_IMAGE' => $avatar_img,
+ 'AVATAR' => empty($avatar) ? '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />' : $avatar,
'AVATAR_MAX_FILESIZE' => $config['avatar_filesize'],
'AVATAR_WIDTH' => (isset($group_row['group_avatar_width'])) ? $group_row['group_avatar_width'] : '',
'AVATAR_HEIGHT' => (isset($group_row['group_avatar_height'])) ? $group_row['group_avatar_height'] : '',
@@ -829,56 +831,112 @@ class acp_groups
public function manage_position()
{
- global $config, $db, $template, $user;
+ global $config, $db, $template, $user, $request, $phpbb_container;
$this->tpl_name = 'acp_groups_position';
$this->page_title = 'ACP_GROUPS_POSITION';
- $field = request_var('field', '');
- $action = request_var('action', '');
- $group_id = request_var('g', 0);
+ $field = $request->variable('field', '');
+ $action = $request->variable('action', '');
+ $group_id = $request->variable('g', 0);
+ $teampage_id = $request->variable('t', 0);
+ $category_id = $request->variable('c', 0);
if ($field && !in_array($field, array('legend', 'teampage')))
{
// Invalid mode
trigger_error($user->lang['NO_MODE'] . adm_back_link($this->u_action), E_USER_WARNING);
}
- else if ($field)
+ else if ($field && in_array($field, array('legend', 'teampage')))
{
- $group_position = new phpbb_group_positions($db, $field, $this->u_action);
+
+ $group_position = $phpbb_container->get('groupposition.' . $field);
}
- switch ($action)
+ if ($field == 'teampage')
{
- case 'set_config_legend':
- set_config('legend_sort_groupname', request_var('legend_sort_groupname', 0));
- break;
+ try
+ {
+ switch ($action)
+ {
+ case 'add':
+ $group_position->add_group_teampage($group_id, $category_id);
+ break;
- case 'set_config_teampage':
- set_config('teampage_forums', request_var('teampage_forums', 0));
- set_config('teampage_memberships', request_var('teampage_memberships', 0));
- break;
+ case 'add_category':
+ $group_position->add_category_teampage($request->variable('category_name', '', true));
+ break;
- case 'add':
- $group_position->add_group($group_id);
- break;
+ case 'delete':
+ $group_position->delete_teampage($teampage_id);
+ break;
- case 'delete':
- $group_position->delete_group($group_id);
- break;
+ case 'move_up':
+ $group_position->move_up_teampage($teampage_id);
+ break;
- case 'move_up':
- $group_position->move_up($group_id);
- break;
+ case 'move_down':
+ $group_position->move_down_teampage($teampage_id);
+ break;
+ }
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ trigger_error($user->lang($exception->getMessage()) . adm_back_link($this->u_action), E_USER_WARNING);
+ }
+ }
+ else if ($field == 'legend')
+ {
+ try
+ {
+ switch ($action)
+ {
+ case 'add':
+ $group_position->add_group($group_id);
+ break;
- case 'move_down':
- $group_position->move_down($group_id);
- break;
+ case 'delete':
+ $group_position->delete_group($group_id);
+ break;
+
+ case 'move_up':
+ $group_position->move_up($group_id);
+ break;
+
+ case 'move_down':
+ $group_position->move_down($group_id);
+ break;
+ }
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ trigger_error($user->lang($exception->getMessage()) . adm_back_link($this->u_action), E_USER_WARNING);
+ }
+ }
+ else
+ {
+ switch ($action)
+ {
+ case 'set_config_teampage':
+ $config->set('teampage_forums', $request->variable('teampage_forums', 0));
+ $config->set('teampage_memberships', $request->variable('teampage_memberships', 0));
+ break;
+
+ case 'set_config_legend':
+ $config->set('legend_sort_groupname', $request->variable('legend_sort_groupname', 0));
+ break;
+ }
+ }
+
+ if (($action == 'move_up' || $action == 'move_down') && $request->is_ajax())
+ {
+ $json_response = new phpbb_json_response;
+ $json_response->send(array('success' => true));
}
$sql = 'SELECT group_id, group_name, group_colour, group_type, group_legend
FROM ' . GROUPS_TABLE . '
- ORDER BY group_legend, group_name ASC';
+ ORDER BY group_legend ASC, group_type DESC, group_name ASC';
$result = $db->sql_query($sql);
$s_group_select_legend = '';
@@ -888,57 +946,99 @@ class acp_groups
if ($row['group_legend'])
{
$template->assign_block_vars('legend', array(
- 'GROUP_NAME' => $group_name,
- 'GROUP_COLOUR' => ($row['group_colour']) ? ' style="color: #' . $row['group_colour'] . '"' : '',
- 'GROUP_TYPE' => $user->lang[phpbb_group_positions::group_type_language($row['group_type'])],
+ 'GROUP_NAME' => $group_name,
+ 'GROUP_COLOUR' => ($row['group_colour']) ? '#' . $row['group_colour'] : '',
+ 'GROUP_TYPE' => $user->lang[phpbb_groupposition_legend::group_type_language($row['group_type'])],
- 'U_MOVE_DOWN' => "{$this->u_action}&amp;field=legend&amp;action=move_down&amp;g=" . $row['group_id'],
- 'U_MOVE_UP' => "{$this->u_action}&amp;field=legend&amp;action=move_up&amp;g=" . $row['group_id'],
- 'U_DELETE' => "{$this->u_action}&amp;field=legend&amp;action=delete&amp;g=" . $row['group_id'],
+ 'U_MOVE_DOWN' => "{$this->u_action}&amp;field=legend&amp;action=move_down&amp;g=" . $row['group_id'],
+ 'U_MOVE_UP' => "{$this->u_action}&amp;field=legend&amp;action=move_up&amp;g=" . $row['group_id'],
+ 'U_DELETE' => "{$this->u_action}&amp;field=legend&amp;action=delete&amp;g=" . $row['group_id'],
));
}
else
{
- $s_group_select_legend .= '<option value="' . (int) $row['group_id'] . '">' . $group_name . '</option>';
+ $template->assign_block_vars('add_legend', array(
+ 'GROUP_ID' => (int) $row['group_id'],
+ 'GROUP_NAME' => $group_name,
+ 'GROUP_SPECIAL' => ($row['group_type'] == GROUP_SPECIAL),
+ ));
}
}
$db->sql_freeresult($result);
- $sql = 'SELECT group_id, group_name, group_colour, group_type, group_teampage
- FROM ' . GROUPS_TABLE . '
- ORDER BY group_teampage, group_name ASC';
+ $category_url_param = (($category_id) ? '&amp;c=' . $category_id : '');
+
+ $sql = 'SELECT t.*, g.group_name, g.group_colour, g.group_type
+ FROM ' . TEAMPAGE_TABLE . ' t
+ LEFT JOIN ' . GROUPS_TABLE . ' g
+ ON (t.group_id = g.group_id)
+ WHERE t.teampage_parent = ' . $category_id . '
+ OR t.teampage_id = ' . $category_id . '
+ ORDER BY t.teampage_position ASC';
$result = $db->sql_query($sql);
- $s_group_select_teampage = '';
+ $category_data = array();
while ($row = $db->sql_fetchrow($result))
{
- $group_name = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
- if ($row['group_teampage'])
+ if ($row['teampage_id'] == $category_id)
{
- $template->assign_block_vars('teampage', array(
- 'GROUP_NAME' => $group_name,
- 'GROUP_COLOUR' => ($row['group_colour']) ? ' style="color: #' . $row['group_colour'] . '"' : '',
- 'GROUP_TYPE' => $user->lang[phpbb_group_positions::group_type_language($row['group_type'])],
-
- 'U_MOVE_DOWN' => "{$this->u_action}&amp;field=teampage&amp;action=move_down&amp;g=" . $row['group_id'],
- 'U_MOVE_UP' => "{$this->u_action}&amp;field=teampage&amp;action=move_up&amp;g=" . $row['group_id'],
- 'U_DELETE' => "{$this->u_action}&amp;field=teampage&amp;action=delete&amp;g=" . $row['group_id'],
+ $template->assign_vars(array(
+ 'CURRENT_CATEGORY_NAME' => $row['teampage_name'],
));
+ continue;
+ }
+
+ if ($row['group_id'])
+ {
+ $group_name = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
+ $group_type = $user->lang[phpbb_groupposition_teampage::group_type_language($row['group_type'])];
}
else
{
- $s_group_select_teampage .= '<option value="' . (int) $row['group_id'] . '">' . $group_name . '</option>';
+ $group_name = $row['teampage_name'];
+ $group_type = '';
}
+
+ $template->assign_block_vars('teampage', array(
+ 'GROUP_NAME' => $group_name,
+ 'GROUP_COLOUR' => ($row['group_colour']) ? '#' . $row['group_colour'] : '',
+ 'GROUP_TYPE' => $group_type,
+
+ 'U_CATEGORY' => (!$row['group_id']) ? "{$this->u_action}&amp;c=" . $row['teampage_id'] : '',
+ 'U_MOVE_DOWN' => "{$this->u_action}&amp;field=teampage&amp;action=move_down{$category_url_param}&amp;t=" . $row['teampage_id'],
+ 'U_MOVE_UP' => "{$this->u_action}&amp;field=teampage&amp;action=move_up{$category_url_param}&amp;t=" . $row['teampage_id'],
+ 'U_DELETE' => "{$this->u_action}&amp;field=teampage&amp;action=delete{$category_url_param}&amp;t=" . $row['teampage_id'],
+ ));
+ }
+ $db->sql_freeresult($result);
+
+ $sql = 'SELECT g.group_id, g.group_name, g.group_colour, g.group_type
+ FROM ' . GROUPS_TABLE . ' g
+ LEFT JOIN ' . TEAMPAGE_TABLE . ' t
+ ON (t.group_id = g.group_id)
+ WHERE t.teampage_id IS NULL
+ ORDER BY g.group_type DESC, g.group_name ASC';
+ $result = $db->sql_query($sql);
+
+ $s_group_select_teampage = '';
+ while ($row = $db->sql_fetchrow($result))
+ {
+ $group_name = ($row['group_type'] == GROUP_SPECIAL) ? $user->lang['G_' . $row['group_name']] : $row['group_name'];
+ $template->assign_block_vars('add_teampage', array(
+ 'GROUP_ID' => (int) $row['group_id'],
+ 'GROUP_NAME' => $group_name,
+ 'GROUP_SPECIAL' => ($row['group_type'] == GROUP_SPECIAL),
+ ));
}
$db->sql_freeresult($result);
$template->assign_vars(array(
- 'U_ACTION' => $this->u_action,
- 'U_ACTION_LEGEND' => $this->u_action . '&amp;field=legend',
- 'U_ACTION_TEAMPAGE' => $this->u_action . '&amp;field=teampage',
+ 'U_ACTION' => $this->u_action,
+ 'U_ACTION_LEGEND' => $this->u_action . '&amp;field=legend',
+ 'U_ACTION_TEAMPAGE' => $this->u_action . '&amp;field=teampage' . $category_url_param,
+ 'U_ACTION_TEAMPAGE_CAT' => $this->u_action . '&amp;field=teampage_cat',
- 'S_GROUP_SELECT_LEGEND' => $s_group_select_legend,
- 'S_GROUP_SELECT_TEAMPAGE' => $s_group_select_teampage,
+ 'S_TEAMPAGE_CATEGORY' => $category_id,
'DISPLAY_FORUMS' => ($config['teampage_forums']) ? true : false,
'DISPLAY_MEMBERSHIPS' => $config['teampage_memberships'],
'LEGEND_SORT_GROUPNAME' => ($config['legend_sort_groupname']) ? true : false,
diff --git a/phpBB/includes/acp/acp_inactive.php b/phpBB/includes/acp/acp_inactive.php
index e61115f681..de4679b58d 100644
--- a/phpBB/includes/acp/acp_inactive.php
+++ b/phpBB/includes/acp/acp_inactive.php
@@ -115,7 +115,7 @@ class acp_inactive
{
$messenger->template('admin_welcome_activated', $row['user_lang']);
- $messenger->to($row['user_email'], $row['username']);
+ $messenger->set_addresses($row);
$messenger->anti_abuse_headers($config, $user);
@@ -203,8 +203,7 @@ class acp_inactive
{
$messenger->template('user_remind_inactive', $row['user_lang']);
- $messenger->to($row['user_email'], $row['username']);
- $messenger->im($row['user_jabber'], $row['username']);
+ $messenger->set_addresses($row);
$messenger->anti_abuse_headers($config, $user);
diff --git a/phpBB/includes/acp/acp_modules.php b/phpBB/includes/acp/acp_modules.php
index fce26bf45f..ab416fb406 100644
--- a/phpBB/includes/acp/acp_modules.php
+++ b/phpBB/includes/acp/acp_modules.php
@@ -544,81 +544,60 @@ class acp_modules
*/
function get_module_infos($module = '', $module_class = false, $use_all_available = false)
{
- global $phpbb_root_path, $phpEx;
+ global $phpbb_extension_manager, $phpbb_root_path, $phpEx;
$module_class = ($module_class === false) ? $this->module_class : $module_class;
$directory = $phpbb_root_path . 'includes/' . $module_class . '/info/';
$fileinfo = array();
- if (!$module)
- {
- global $phpbb_extension_manager;
-
- $finder = $phpbb_extension_manager->get_finder();
+ $finder = $phpbb_extension_manager->get_finder();
- $modules = $finder
- ->extension_suffix('_module')
- ->extension_directory("/$module_class")
- ->core_path("includes/$module_class/info/")
- ->core_prefix($module_class . '_')
- ->get_classes(true, $use_all_available);
+ $modules = $finder
+ ->extension_suffix('_module')
+ ->extension_directory("/$module_class")
+ ->core_path("includes/$module_class/info/")
+ ->core_prefix($module_class . '_')
+ ->get_classes(true, $use_all_available);
- foreach ($modules as $module)
+ foreach ($modules as $cur_module)
+ {
+ // Skip entries we do not need if we know the module we are
+ // looking for
+ if ($module && strpos($cur_module, $module) === false)
{
- $info_class = preg_replace('/_module$/', '_info', $module);
-
- // If the class does not exist it might be following the old
- // format. phpbb_acp_info_acp_foo needs to be turned into
- // acp_foo_info and the respective file has to be included
- // manually because it does not support auto loading
- if (!class_exists($info_class))
- {
- $info_class = str_replace("phpbb_{$module_class}_info_", '', $module) . '_info';
- if (file_exists($directory . $info_class . '.' . $phpEx))
- {
- include($directory . $info_class . '.' . $phpEx);
- }
- }
-
- if (class_exists($info_class))
- {
- $info = new $info_class();
- $module_info = $info->module();
-
- $main_class = (isset($module_info['filename'])) ? $module_info['filename'] : $module;
-
- $fileinfo[$main_class] = $module_info;
- }
+ continue;
}
- ksort($fileinfo);
- }
- else
- {
- $info_class = preg_replace('/_module$/', '_info', $module);
+ $info_class = preg_replace('/_module$/', '_info', $cur_module);
+ // If the class does not exist it might be following the old
+ // format. phpbb_acp_info_acp_foo needs to be turned into
+ // acp_foo_info and the respective file has to be included
+ // manually because it does not support auto loading
if (!class_exists($info_class))
{
- if (file_exists($directory . $module . '.' . $phpEx))
+ $info_class_file = str_replace("phpbb_{$module_class}_info_", '', $cur_module);
+ $info_class = $info_class_file . '_info';
+ if (!class_exists($info_class) && file_exists($directory . $info_class_file . '.' . $phpEx))
{
- include($directory . $module . '.' . $phpEx);
+ include($directory . $info_class_file . '.' . $phpEx);
}
- $info_class = $module . '_info';
}
- // Get module title tag
if (class_exists($info_class))
{
$info = new $info_class();
$module_info = $info->module();
- $main_class = (isset($module_info['filename'])) ? $module_info['filename'] : $module;
+ $main_class = (isset($module_info['filename'])) ? $module_info['filename'] : $cur_module;
$fileinfo[$main_class] = $module_info;
}
}
+ ksort($fileinfo);
+
return $fileinfo;
}
diff --git a/phpBB/includes/acp/acp_prune.php b/phpBB/includes/acp/acp_prune.php
index a5dc02849a..4234ec1505 100644
--- a/phpBB/includes/acp/acp_prune.php
+++ b/phpBB/includes/acp/acp_prune.php
@@ -331,7 +331,7 @@ class acp_prune
$s_find_active_time .= '<option value="' . $key . '">' . $value . '</option>';
}
- $s_group_list = '';
+ $s_group_list = '<option value="0"></option>';
$sql = 'SELECT group_id, group_name
FROM ' . GROUPS_TABLE . '
WHERE group_type <> ' . GROUP_SPECIAL . '
@@ -340,7 +340,7 @@ class acp_prune
while ($row = $db->sql_fetchrow($result))
{
- $s_group_list .= '<option value="' . $row['group_id'] . '">' . $row['group_name'] . '</select>';
+ $s_group_list .= '<option value="' . $row['group_id'] . '">' . $row['group_name'] . '</option>';
}
$db->sql_freeresult($result);
@@ -491,11 +491,12 @@ class acp_prune
if ($group_id)
{
- $sql = 'SELECT user_id
- FROM ' . USER_GROUP_TABLE . '
- WHERE group_id = ' . (int) $group_id . '
- AND user_pending = 0
- AND ' . $db->sql_in_set('user_id', $user_ids, false, true);
+ $sql = 'SELECT u.user_id, u.username
+ FROM ' . USER_GROUP_TABLE . ' ug, ' . USERS_TABLE . ' u
+ WHERE ug.group_id = ' . (int) $group_id . '
+ AND ug.user_pending = 0
+ AND ' . $db->sql_in_set('ug.user_id', $user_ids, false, true) . '
+ AND u.user_id = ug.user_id';
$result = $db->sql_query($sql);
// we're performing an intersection operation, so all the relevant users
@@ -504,24 +505,19 @@ class acp_prune
$user_ids = $usernames = array();
while ($row = $db->sql_fetchrow($result))
{
- $user_ids[] = $row['poster_id'];
+ $user_ids[] = $row['user_id'];
+ $usernames[$row['user_id']] = $row['username'];
}
$db->sql_freeresult($result);
-
- // only get usernames if they are needed (not part of some later query)
- if (!$posts_on_queue)
- {
- // this is an additional query aginst the users table
- user_get_id_name($user_ids, $usernames);
- }
}
if ($posts_on_queue)
{
- $sql = 'SELECT poster_id, COUNT(post_id) AS queue_posts
- FROM ' . POSTS_TABLE . '
- WHERE ' . $db->sql_in_set('poster_id', $user_ids, false, true) . '
- GROUP BY poster_id
+ $sql = 'SELECT u.user_id, u.username, COUNT(p.post_id) AS queue_posts
+ FROM ' . POSTS_TABLE . ' p, ' . USERS_TABLE . ' u
+ WHERE ' . $db->sql_in_set('p.poster_id', $user_ids, false, true) . '
+ AND u.user_id = p.poster_id
+ GROUP BY p.poster_id
HAVING queue_posts ' . $key_match[$queue_select] . ' ' . $posts_on_queue;
$result = $db->sql_query($result);
@@ -529,12 +525,10 @@ class acp_prune
$user_ids = $usernames = array();
while ($row = $db->sql_fetchrow($result))
{
- $user_ids[] = $row['poster_id'];
+ $user_ids[] = $row['user_id'];
+ $usernames[$row['user_id']] = $row['username'];
}
$db->sql_freeresult($result);
-
- // do an additional query to get the correct set of usernames
- user_get_id_name($user_ids, $usernames);
}
}
}
diff --git a/phpBB/includes/acp/acp_styles.php b/phpBB/includes/acp/acp_styles.php
index 266495972b..094d84de40 100644
--- a/phpBB/includes/acp/acp_styles.php
+++ b/phpBB/includes/acp/acp_styles.php
@@ -68,13 +68,20 @@ class acp_styles
$action = $this->request->variable('action', '');
$post_actions = array('install', 'activate', 'deactivate', 'uninstall');
+
+ if ($action && in_array($action, $post_actions) && !check_link_hash($request->variable('hash', ''), $action))
+ {
+ trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
+ }
+
foreach ($post_actions as $key)
{
- if (isset($_POST[$key]))
+ if ($this->request->is_set_post($key))
{
$action = $key;
}
}
+
if ($action != '')
{
$this->s_hidden_fields['action'] = $action;
@@ -921,21 +928,23 @@ class acp_styles
'L_ACTION' => $this->user->lang['DETAILS']
);
- // Activate
+ // Activate/Deactive
+ $action_name = ($style['style_active'] ? 'de' : '') . 'activate';
+
$actions[] = array(
- 'U_ACTION' => $this->u_action . '&amp;action=' . ($style['style_active'] ? 'de' : '') . 'activate&amp;id=' . $style['style_id'],
+ 'U_ACTION' => $this->u_action . '&amp;action=' . $action_name . '&amp;hash=' . generate_link_hash($action_name) . '&amp;id=' . $style['style_id'],
'L_ACTION' => $this->user->lang['STYLE_' . ($style['style_active'] ? 'DE' : '') . 'ACTIVATE']
);
/* // Export
$actions[] = array(
- 'U_ACTION' => $this->u_action . '&amp;action=export&amp;id=' . $style['style_id'],
+ 'U_ACTION' => $this->u_action . '&amp;action=export&amp;hash=' . generate_link_hash('export') . '&amp;id=' . $style['style_id'],
'L_ACTION' => $this->user->lang['EXPORT']
); */
// Uninstall
$actions[] = array(
- 'U_ACTION' => $this->u_action . '&amp;action=uninstall&amp;id=' . $style['style_id'],
+ 'U_ACTION' => $this->u_action . '&amp;action=uninstall&amp;hash=' . generate_link_hash('uninstall') . '&amp;id=' . $style['style_id'],
'L_ACTION' => $this->user->lang['STYLE_UNINSTALL']
);
@@ -957,7 +966,7 @@ class acp_styles
else
{
$actions[] = array(
- 'U_ACTION' => $this->u_action . '&amp;action=install&amp;dir=' . urlencode($style['style_path']),
+ 'U_ACTION' => $this->u_action . '&amp;action=install&amp;hash=' . generate_link_hash('install') . '&amp;dir=' . urlencode($style['style_path']),
'L_ACTION' => $this->user->lang['INSTALL_STYLE']
);
}
diff --git a/phpBB/includes/acp/acp_update.php b/phpBB/includes/acp/acp_update.php
index f7f003781d..6b5407067d 100644
--- a/phpBB/includes/acp/acp_update.php
+++ b/phpBB/includes/acp/acp_update.php
@@ -38,7 +38,7 @@ class acp_update
$info = obtain_latest_version_info(request_var('versioncheck_force', false));
- if ($info === false)
+ if (empty($info))
{
trigger_error('VERSIONCHECK_FAIL', E_USER_WARNING);
}
diff --git a/phpBB/includes/acp/acp_users.php b/phpBB/includes/acp/acp_users.php
index 82d8ef5cbb..c8542ddbe7 100644
--- a/phpBB/includes/acp/acp_users.php
+++ b/phpBB/includes/acp/acp_users.php
@@ -33,6 +33,7 @@ class acp_users
global $config, $db, $user, $auth, $template, $cache;
global $phpbb_root_path, $phpbb_admin_path, $phpEx, $table_prefix, $file_uploads;
global $phpbb_dispatcher, $request;
+ global $phpbb_container;
$user->add_lang(array('posting', 'ucp', 'acp/users'));
$this->tpl_name = 'acp_users';
@@ -346,7 +347,7 @@ class acp_users
$messenger->template($email_template, $user_row['user_lang']);
- $messenger->to($user_row['user_email'], $user_row['username']);
+ $messenger->set_addresses($user_row);
$messenger->anti_abuse_headers($config, $user);
@@ -401,7 +402,7 @@ class acp_users
$messenger->template('admin_welcome_activated', $user_row['user_lang']);
- $messenger->to($user_row['user_email'], $user_row['username']);
+ $messenger->set_addresses($user_row);
$messenger->anti_abuse_headers($config, $user);
@@ -456,7 +457,7 @@ class acp_users
$sql_ary = array(
'user_avatar' => '',
- 'user_avatar_type' => 0,
+ 'user_avatar_type' => '',
'user_avatar_width' => 0,
'user_avatar_height' => 0,
);
@@ -467,9 +468,11 @@ class acp_users
$db->sql_query($sql);
// Delete old avatar if present
- if ($user_row['user_avatar'] && $user_row['user_avatar_type'] != AVATAR_GALLERY)
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $driver = $phpbb_avatar_manager->get_driver($user_row['user_avatar_type']);
+ if ($driver)
{
- avatar_delete('user', $user_row);
+ $driver->delete($user_row);
}
add_log('admin', 'LOG_USER_DEL_AVATAR', $user_row['username']);
@@ -1728,65 +1731,120 @@ class acp_users
case 'avatar':
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
- include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
- $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false;
+ $avatars_enabled = false;
- if ($submit)
+ if ($config['allow_avatar'])
{
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers();
- if (!check_form_key($form_name))
+ // This is normalised data, without the user_ prefix
+ $avatar_data = phpbb_avatar_manager::clean_row($user_row);
+
+ if ($submit)
{
+ if (check_form_key($form_name))
+ {
+ $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', ''));
+
+ if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete'))
+ {
+ $driver = $phpbb_avatar_manager->get_driver($driver_name);
+ $result = $driver->process_form($request, $template, $user, $avatar_data, $error);
+
+ if ($result && empty($error))
+ {
+ // Success! Lets save the result in the database
+ $result = array(
+ 'user_avatar_type' => $driver_name,
+ 'user_avatar' => $result['avatar'],
+ 'user_avatar_width' => $result['avatar_width'],
+ 'user_avatar_height' => $result['avatar_height'],
+ );
+
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET ' . $db->sql_build_array('UPDATE', $result) . '
+ WHERE user_id = ' . (int) $user_id;
+
+ $db->sql_query($sql);
+ trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&amp;u=' . $user_id));
+ }
+ }
+ else
+ {
+ $driver = $phpbb_avatar_manager->get_driver($user->data['user_avatar_type']);
+ if ($driver)
+ {
+ $driver->delete($avatar_data);
+ }
+
+ // Removing the avatar
+ $result = array(
+ 'user_avatar' => '',
+ 'user_avatar_type' => '',
+ 'user_avatar_width' => 0,
+ 'user_avatar_height' => 0,
+ );
+
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET ' . $db->sql_build_array('UPDATE', $result) . '
+ WHERE user_id = ' . (int) $user_id;
+
+ $db->sql_query($sql);
+ trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&amp;u=' . $user_id));
+ }
+ }
+ else
+ {
trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action . '&amp;u=' . $user_id), E_USER_WARNING);
+ }
}
- if (avatar_process_user($error, $user_row, $can_upload))
- {
- trigger_error($user->lang['USER_AVATAR_UPDATED'] . adm_back_link($this->u_action . '&amp;u=' . $user_row['user_id']));
- }
+ $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $user_row['user_avatar_type']));
- // Replace "error" strings with their real, localised form
- $error = array_map(array($user, 'lang'), $error);
- }
+ foreach ($avatar_drivers as $current_driver)
+ {
+ $driver = $phpbb_avatar_manager->get_driver($current_driver);
- if (!$config['allow_avatar'] && $user_row['user_avatar_type'])
- {
- $error[] = $user->lang['USER_AVATAR_NOT_ALLOWED'];
- }
- else if ((($user_row['user_avatar_type'] == AVATAR_UPLOAD) && !$config['allow_avatar_upload']) ||
- (($user_row['user_avatar_type'] == AVATAR_REMOTE) && !$config['allow_avatar_remote']) ||
- (($user_row['user_avatar_type'] == AVATAR_GALLERY) && !$config['allow_avatar_local']))
- {
- $error[] = $user->lang['USER_AVATAR_TYPE_NOT_ALLOWED'];
- }
+ $avatars_enabled = true;
+ $config_name = $phpbb_avatar_manager->get_driver_config_name($driver);
+ $template->set_filenames(array(
+ 'avatar' => "acp_avatar_options_{$config_name}.html",
+ ));
- // Generate users avatar
- $avatar_img = ($user_row['user_avatar']) ? get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height'], 'USER_AVATAR', true) : '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />';
+ if ($driver->prepare_form($request, $template, $user, $avatar_data, $error))
+ {
+ $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver);
+ $driver_upper = strtoupper($driver_name);
- $display_gallery = (isset($_POST['display_gallery'])) ? true : false;
- $avatar_select = basename(request_var('avatar_select', ''));
- $category = basename(request_var('category', ''));
+ $template->assign_block_vars('avatar_drivers', array(
+ 'L_TITLE' => $user->lang($driver_upper . '_TITLE'),
+ 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'),
- if ($config['allow_avatar_local'] && $display_gallery)
- {
- avatar_gallery($category, $avatar_select, 4);
+ 'DRIVER' => $driver_name,
+ 'SELECTED' => $current_driver == $selected_driver,
+ 'OUTPUT' => $template->assign_display('avatar'),
+ ));
+ }
+ }
}
+ // Replace "error" strings with their real, localised form
+ $error = $phpbb_avatar_manager->localize_errors($user, $error);
+
+ $avatar = phpbb_get_user_avatar($user_row, 'USER_AVATAR', true);
+
$template->assign_vars(array(
- 'S_AVATAR' => true,
- 'S_CAN_UPLOAD' => $can_upload,
- 'S_UPLOAD_FILE' => ($config['allow_avatar'] && $can_upload && $config['allow_avatar_upload']) ? true : false,
- 'S_REMOTE_UPLOAD' => ($config['allow_avatar'] && $can_upload && $config['allow_avatar_remote_upload']) ? true : false,
- 'S_ALLOW_REMOTE' => ($config['allow_avatar'] && $config['allow_avatar_remote']) ? true : false,
- 'S_DISPLAY_GALLERY' => ($config['allow_avatar'] && $config['allow_avatar_local'] && !$display_gallery) ? true : false,
- 'S_IN_GALLERY' => ($config['allow_avatar'] && $config['allow_avatar_local'] && $display_gallery) ? true : false,
-
- 'AVATAR_IMAGE' => $avatar_img,
- 'AVATAR_MAX_FILESIZE' => $config['avatar_filesize'],
- 'USER_AVATAR_WIDTH' => $user_row['user_avatar_width'],
- 'USER_AVATAR_HEIGHT' => $user_row['user_avatar_height'],
-
- 'L_AVATAR_EXPLAIN' => phpbb_avatar_explanation_string(),
+ 'S_AVATAR' => true,
+ 'ERROR' => (!empty($error)) ? implode('<br />', $error) : '',
+ 'AVATAR' => (empty($avatar) ? '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />' : $avatar),
+
+ 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"',
+
+ 'L_AVATAR_EXPLAIN' => sprintf($user->lang['AVATAR_EXPLAIN'], $config['avatar_max_width'], $config['avatar_max_height'], $config['avatar_filesize'] / 1024),
+
+ 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled),
));
break;
diff --git a/phpBB/includes/auth/auth_ldap.php b/phpBB/includes/auth/auth_ldap.php
index 24823f9ce7..98355dd044 100644
--- a/phpBB/includes/auth/auth_ldap.php
+++ b/phpBB/includes/auth/auth_ldap.php
@@ -330,7 +330,7 @@ function acp_ldap(&$new)
</dl>
<dl>
<dt><label for="ldap_email">' . $user->lang['LDAP_EMAIL'] . $user->lang['COLON'] . '</label><br /><span>' . $user->lang['LDAP_EMAIL_EXPLAIN'] . '</span></dt>
- <dd><input type="text" id="ldap_email" size="40" name="config[ldap_email]" value="' . $new['ldap_email'] . '" /></dd>
+ <dd><input type="email" id="ldap_email" size="40" name="config[ldap_email]" value="' . $new['ldap_email'] . '" /></dd>
</dl>
<dl>
<dt><label for="ldap_user">' . $user->lang['LDAP_USER'] . $user->lang['COLON'] . '</label><br /><span>' . $user->lang['LDAP_USER_EXPLAIN'] . '</span></dt>
diff --git a/phpBB/includes/avatar/driver/driver.php b/phpBB/includes/avatar/driver/driver.php
new file mode 100644
index 0000000000..29c58d4e62
--- /dev/null
+++ b/phpBB/includes/avatar/driver/driver.php
@@ -0,0 +1,138 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2011 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Base class for avatar drivers
+* @package phpBB3
+*/
+abstract class phpbb_avatar_driver implements phpbb_avatar_driver_interface
+{
+ /**
+ * Avatar driver name
+ * @var string
+ */
+ protected $name;
+
+ /**
+ * Current board configuration
+ * @var phpbb_config
+ */
+ protected $config;
+
+ /**
+ * Current $phpbb_root_path
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Current $php_ext
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Cache driver
+ * @var phpbb_cache_driver_interface
+ */
+ protected $cache;
+
+ /**
+ * Array of allowed avatar image extensions
+ * Array is used for setting the allowed extensions in the fileupload class
+ * and as a base for a regex of allowed extensions, which will be formed by
+ * imploding the array with a "|".
+ *
+ * @var array
+ */
+ protected $allowed_extensions = array(
+ 'gif',
+ 'jpg',
+ 'jpeg',
+ 'png',
+ );
+
+ /**
+ * Construct a driver object
+ *
+ * @param phpbb_config $config phpBB configuration
+ * @param phpbb_request $request Request object
+ * @param string $phpbb_root_path Path to the phpBB root
+ * @param string $php_ext PHP file extension
+ * @param phpbb_cache_driver_interface $cache Cache driver
+ */
+ public function __construct(phpbb_config $config, $phpbb_root_path, $php_ext, phpbb_cache_driver_interface $cache = null)
+ {
+ $this->config = $config;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->php_ext = $php_ext;
+ $this->cache = $cache;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function get_custom_html($user, $row, $alt = '')
+ {
+ return '';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function prepare_form_acp($user)
+ {
+ return array();
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function delete($row)
+ {
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function get_template_name()
+ {
+ $driver = preg_replace('#^phpbb_avatar_driver_#', '', get_class($this));
+ $template = "ucp_avatar_options_$driver.html";
+
+ return $template;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function get_name()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Sets the name of the driver.
+ *
+ * @param string $name Driver name
+ */
+ public function set_name($name)
+ {
+ $this->name = $name;
+ }
+}
diff --git a/phpBB/includes/avatar/driver/gravatar.php b/phpBB/includes/avatar/driver/gravatar.php
new file mode 100644
index 0000000000..d559da1c0d
--- /dev/null
+++ b/phpBB/includes/avatar/driver/gravatar.php
@@ -0,0 +1,172 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2012 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Handles avatars hosted at gravatar.com
+* @package phpBB3
+*/
+class phpbb_avatar_driver_gravatar extends phpbb_avatar_driver
+{
+ /**
+ * The URL for the gravatar service
+ */
+ const GRAVATAR_URL = '//secure.gravatar.com/avatar/';
+
+ /**
+ * @inheritdoc
+ */
+ public function get_data($row)
+ {
+ return array(
+ 'src' => $row['avatar'],
+ 'width' => $row['avatar_width'],
+ 'height' => $row['avatar_height'],
+ );
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function get_custom_html($user, $row, $alt = '')
+ {
+ return '<img src="' . $this->get_gravatar_url($row) . '" ' .
+ ($row['avatar_width'] ? ('width="' . $row['avatar_width'] . '" ') : '') .
+ ($row['avatar_height'] ? ('height="' . $row['avatar_height'] . '" ') : '') .
+ 'alt="' . ((!empty($user->lang[$alt])) ? $user->lang[$alt] : $alt) . '" />';
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function prepare_form($request, $template, $user, $row, &$error)
+ {
+ $template->assign_vars(array(
+ 'AVATAR_GRAVATAR_WIDTH' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar_width']) ? $row['avatar_width'] : $request->variable('avatar_gravatar_width', 0),
+ 'AVATAR_GRAVATAR_HEIGHT' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar_height']) ? $row['avatar_height'] : $request->variable('avatar_gravatar_width', 0),
+ 'AVATAR_GRAVATAR_EMAIL' => (($row['avatar_type'] == $this->get_name() || $row['avatar_type'] == 'gravatar') && $row['avatar']) ? $row['avatar'] : '',
+ ));
+
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function process_form($request, $template, $user, $row, &$error)
+ {
+ $row['avatar'] = $request->variable('avatar_gravatar_email', '');
+ $row['avatar_width'] = $request->variable('avatar_gravatar_width', 0);
+ $row['avatar_height'] = $request->variable('avatar_gravatar_height', 0);
+
+ if (!function_exists('validate_data'))
+ {
+ require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
+ }
+
+ $validate_array = validate_data(
+ array(
+ 'email' => $row['avatar'],
+ ),
+ array(
+ 'email' => array(
+ array('string', false, 6, 60),
+ array('email'))
+ )
+ );
+
+ $error = array_merge($error, $validate_array);
+
+ if (!empty($error))
+ {
+ return false;
+ }
+
+ // Make sure getimagesize works...
+ if (function_exists('getimagesize') && ($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0))
+ {
+ /**
+ * default to the minimum of the maximum allowed avatar size if the size
+ * is not or only partially entered
+ */
+ $row['avatar_width'] = $row['avatar_height'] = min($this->config['avatar_max_width'], $this->config['avatar_max_height']);
+ $url = $this->get_gravatar_url($row);
+
+ if (($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0) && (($image_data = getimagesize($url)) === false))
+ {
+ $error[] = 'UNABLE_GET_IMAGE_SIZE';
+ return false;
+ }
+
+ if (!empty($image_data) && ($image_data[0] <= 0 || $image_data[1] <= 0))
+ {
+ $error[] = 'AVATAR_NO_SIZE';
+ return false;
+ }
+
+ $row['avatar_width'] = ($row['avatar_width'] && $row['avatar_height']) ? $row['avatar_width'] : $image_data[0];
+ $row['avatar_height'] = ($row['avatar_width'] && $row['avatar_height']) ? $row['avatar_height'] : $image_data[1];
+ }
+
+ if ($row['avatar_width'] <= 0 || $row['avatar_height'] <= 0)
+ {
+ $error[] = 'AVATAR_NO_SIZE';
+ return false;
+ }
+
+ if ($this->config['avatar_max_width'] || $this->config['avatar_max_height'])
+ {
+ if ($row['avatar_width'] > $this->config['avatar_max_width'] || $row['avatar_height'] > $this->config['avatar_max_height'])
+ {
+ $error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $row['avatar_width'], $row['avatar_height']);
+ return false;
+ }
+ }
+
+ if ($this->config['avatar_min_width'] || $this->config['avatar_min_height'])
+ {
+ if ($row['avatar_width'] < $this->config['avatar_min_width'] || $row['avatar_height'] < $this->config['avatar_min_height'])
+ {
+ $error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $row['avatar_width'], $row['avatar_height']);
+ return false;
+ }
+ }
+
+ return array(
+ 'avatar' => $row['avatar'],
+ 'avatar_width' => $row['avatar_width'],
+ 'avatar_height' => $row['avatar_height'],
+ );
+ }
+
+ /**
+ * Build gravatar URL for output on page
+ *
+ * @return string Gravatar URL
+ */
+ protected function get_gravatar_url($row)
+ {
+ $url = self::GRAVATAR_URL;
+ $url .= md5(strtolower(trim($row['avatar'])));
+
+ if ($row['avatar_width'] || $row['avatar_height'])
+ {
+ $url .= '?s=' . max($row['avatar_width'], $row['avatar_height']);
+ }
+
+ return $url;
+ }
+}
diff --git a/phpBB/includes/avatar/driver/interface.php b/phpBB/includes/avatar/driver/interface.php
new file mode 100644
index 0000000000..3d62969aef
--- /dev/null
+++ b/phpBB/includes/avatar/driver/interface.php
@@ -0,0 +1,116 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2011 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Interface for avatar drivers
+* @package phpBB3
+*/
+interface phpbb_avatar_driver_interface
+{
+ /**
+ * Returns the name of the driver.
+ *
+ * @return string Name of driver.
+ */
+ public function get_name();
+
+ /**
+ * Get the avatar url and dimensions
+ *
+ * @param array $row User data or group data that has been cleaned with
+ * phpbb_avatar_manager::clean_row
+ * @return array Avatar data, must have keys src, width and height, e.g.
+ * ['src' => '', 'width' => 0, 'height' => 0]
+ */
+ public function get_data($row);
+
+ /**
+ * Returns custom html if it is needed for displaying this avatar
+ *
+ * @param phpbb_user $user phpBB user object
+ * @param array $row User data or group data that has been cleaned with
+ * phpbb_avatar_manager::clean_row
+ * @param string $alt Alternate text for avatar image
+ *
+ * @return string HTML
+ */
+ public function get_custom_html($user, $row, $alt = '');
+
+ /**
+ * Prepare form for changing the settings of this avatar
+ *
+ * @param phpbb_request $request Request object
+ * @param phpbb_template $template Template object
+ * @param phpbb_user $user User object
+ * @param array $row User data or group data that has been cleaned with
+ * phpbb_avatar_manager::clean_row
+ * @param array &$error Reference to an error array that is filled by this
+ * function. Key values can either be a string with a language key or
+ * an array that will be passed to vsprintf() with the language key in
+ * the first array key.
+ *
+ * @return bool True if form has been successfully prepared
+ */
+ public function prepare_form($request, $template, $user, $row, &$error);
+
+ /**
+ * Prepare form for changing the acp settings of this avatar
+ *
+ * @param phpbb_user $user phpBB user object
+ *
+ * @return array Array of configuration options as consumed by acp_board.
+ * The setting for enabling/disabling the avatar will be handled by
+ * the avatar manager.
+ */
+ public function prepare_form_acp($user);
+
+ /**
+ * Process form data
+ *
+ * @param phpbb_request $request Request object
+ * @param phpbb_template $template Template object
+ * @param phpbb_user $user User object
+ * @param array $row User data or group data that has been cleaned with
+ * phpbb_avatar_manager::clean_row
+ * @param array &$error Reference to an error array that is filled by this
+ * function. Key values can either be a string with a language key or
+ * an array that will be passed to vsprintf() with the language key in
+ * the first array key.
+ *
+ * @return array Array containing the avatar data as follows:
+ * ['avatar'], ['avatar_width'], ['avatar_height']
+ */
+ public function process_form($request, $template, $user, $row, &$error);
+
+ /**
+ * Delete avatar
+ *
+ * @param array $row User data or group data that has been cleaned with
+ * phpbb_avatar_manager::clean_row
+ *
+ * @return bool True if avatar has been deleted or there is no need to delete,
+ * i.e. when the avatar is not hosted locally.
+ */
+ public function delete($row);
+
+ /**
+ * Get the avatar driver's template name
+ *
+ * @return string Avatar driver's template name
+ */
+ public function get_template_name();
+}
diff --git a/phpBB/includes/avatar/driver/local.php b/phpBB/includes/avatar/driver/local.php
new file mode 100644
index 0000000000..f4bcd4ce74
--- /dev/null
+++ b/phpBB/includes/avatar/driver/local.php
@@ -0,0 +1,197 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2011 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Handles avatars selected from the board gallery
+* @package phpBB3
+*/
+class phpbb_avatar_driver_local extends phpbb_avatar_driver
+{
+ /**
+ * @inheritdoc
+ */
+ public function get_data($row)
+ {
+ return array(
+ 'src' => $this->phpbb_root_path . $this->config['avatar_gallery_path'] . '/' . $row['avatar'],
+ 'width' => $row['avatar_width'],
+ 'height' => $row['avatar_height'],
+ );
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function prepare_form($request, $template, $user, $row, &$error)
+ {
+ $avatar_list = $this->get_avatar_list($user);
+ $category = $request->variable('avatar_local_cat', '');
+
+ foreach ($avatar_list as $cat => $null)
+ {
+ if (!empty($avatar_list[$cat]))
+ {
+ $template->assign_block_vars('avatar_local_cats', array(
+ 'NAME' => $cat,
+ 'SELECTED' => ($cat == $category),
+ ));
+ }
+
+ if ($cat != $category)
+ {
+ unset($avatar_list[$cat]);
+ }
+ }
+
+ if (!empty($avatar_list[$category]))
+ {
+ $template->assign_vars(array(
+ 'AVATAR_LOCAL_SHOW' => true,
+ ));
+
+ $table_cols = isset($row['avatar_gallery_cols']) ? $row['avatar_gallery_cols'] : 4;
+ $row_count = $col_count = $avatar_pos = 0;
+ $avatar_count = sizeof($avatar_list[$category]);
+
+ reset($avatar_list[$category]);
+
+ while ($avatar_pos < $avatar_count)
+ {
+ $img = current($avatar_list[$category]);
+ next($avatar_list[$category]);
+
+ if ($col_count == 0)
+ {
+ ++$row_count;
+ $template->assign_block_vars('avatar_local_row', array(
+ ));
+ }
+
+ $template->assign_block_vars('avatar_local_row.avatar_local_col', array(
+ 'AVATAR_IMAGE' => $this->phpbb_root_path . $this->config['avatar_gallery_path'] . '/' . $img['file'],
+ 'AVATAR_NAME' => $img['name'],
+ 'AVATAR_FILE' => $img['filename'],
+ ));
+
+ $template->assign_block_vars('avatar_local_row.avatar_local_option', array(
+ 'AVATAR_FILE' => $img['filename'],
+ 'S_OPTIONS_AVATAR' => $img['filename']
+ ));
+
+ $col_count = ($col_count + 1) % $table_cols;
+
+ ++$avatar_pos;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function prepare_form_acp($user)
+ {
+ return array(
+ 'avatar_gallery_path' => array('lang' => 'AVATAR_GALLERY_PATH', 'validate' => 'rpath', 'type' => 'text:20:255', 'explain' => true),
+ );
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function process_form($request, $template, $user, $row, &$error)
+ {
+ $avatar_list = $this->get_avatar_list($user);
+ $category = $request->variable('avatar_local_cat', '');
+
+ $file = $request->variable('avatar_local_file', '');
+
+ if (empty($category) || empty($file))
+ {
+ $error[] = 'NO_AVATAR_SELECTED';
+ return false;
+ }
+
+ if (!isset($avatar_list[$category][urldecode($file)]))
+ {
+ $error[] = 'AVATAR_URL_NOT_FOUND';
+ return false;
+ }
+
+ return array(
+ 'avatar' => ($category != $user->lang['MAIN']) ? $category . '/' . $file : $file,
+ 'avatar_width' => $avatar_list[$category][urldecode($file)]['width'],
+ 'avatar_height' => $avatar_list[$category][urldecode($file)]['height'],
+ );
+ }
+
+ /**
+ * Get a list of avatars that are locally available
+ * Results get cached for 24 hours (86400 seconds)
+ *
+ * @param phpbb_user $user User object
+ *
+ * @return array Array containing the locally available avatars
+ */
+ protected function get_avatar_list($user)
+ {
+ $avatar_list = ($this->cache == null) ? false : $this->cache->get('avatar_local_list');
+
+ if ($avatar_list === false)
+ {
+ $avatar_list = array();
+ $path = $this->phpbb_root_path . $this->config['avatar_gallery_path'];
+
+ $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS | FilesystemIterator::UNIX_PATHS), RecursiveIteratorIterator::SELF_FIRST);
+ foreach ($iterator as $file_info)
+ {
+ $file_path = $file_info->getPath();
+ $image = $file_info->getFilename();
+
+ // Match all images in the gallery folder
+ if (preg_match('#^[^&\'"<>]+\.(?:' . implode('|', $this->allowed_extensions) . ')$#i', $image) && is_file($file_path . '/' . $image))
+ {
+ if (function_exists('getimagesize'))
+ {
+ $dims = getimagesize($file_path . '/' . $image);
+ }
+ else
+ {
+ $dims = array(0, 0);
+ }
+ $cat = ($path == $file_path) ? $user->lang['MAIN'] : str_replace("$path/", '', $file_path);
+ $avatar_list[$cat][$image] = array(
+ 'file' => ($cat != $user->lang['MAIN']) ? rawurlencode($cat) . '/' . rawurlencode($image) : rawurlencode($image),
+ 'filename' => rawurlencode($image),
+ 'name' => ucfirst(str_replace('_', ' ', preg_replace('#^(.*)\..*$#', '\1', $image))),
+ 'width' => $dims[0],
+ 'height' => $dims[1],
+ );
+ }
+ }
+ ksort($avatar_list);
+
+ if ($this->cache != null)
+ {
+ $this->cache->put('avatar_local_list', $avatar_list, 86400);
+ }
+ }
+
+ return $avatar_list;
+ }
+}
diff --git a/phpBB/includes/avatar/driver/remote.php b/phpBB/includes/avatar/driver/remote.php
new file mode 100644
index 0000000000..7da58107a1
--- /dev/null
+++ b/phpBB/includes/avatar/driver/remote.php
@@ -0,0 +1,164 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2011 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Handles avatars hosted remotely
+* @package phpBB3
+*/
+class phpbb_avatar_driver_remote extends phpbb_avatar_driver
+{
+ /**
+ * @inheritdoc
+ */
+ public function get_data($row)
+ {
+ return array(
+ 'src' => $row['avatar'],
+ 'width' => $row['avatar_width'],
+ 'height' => $row['avatar_height'],
+ );
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function prepare_form($request, $template, $user, $row, &$error)
+ {
+ $template->assign_vars(array(
+ 'AVATAR_REMOTE_WIDTH' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar_width']) ? $row['avatar_width'] : $request->variable('avatar_remote_width', 0),
+ 'AVATAR_REMOTE_HEIGHT' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar_height']) ? $row['avatar_height'] : $request->variable('avatar_remote_width', 0),
+ 'AVATAR_REMOTE_URL' => ((in_array($row['avatar_type'], array(AVATAR_REMOTE, $this->get_name(), 'remote'))) && $row['avatar']) ? $row['avatar'] : '',
+ ));
+
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function process_form($request, $template, $user, $row, &$error)
+ {
+ $url = $request->variable('avatar_remote_url', '');
+ $width = $request->variable('avatar_remote_width', 0);
+ $height = $request->variable('avatar_remote_height', 0);
+
+ if (!preg_match('#^(http|https|ftp)://#i', $url))
+ {
+ $url = 'http://' . $url;
+ }
+
+ if (!function_exists('validate_data'))
+ {
+ require($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
+ }
+
+ $validate_array = validate_data(
+ array(
+ 'url' => $url,
+ ),
+ array(
+ 'url' => array('string', true, 5, 255),
+ )
+ );
+
+ $error = array_merge($error, $validate_array);
+
+ if (!empty($error))
+ {
+ return false;
+ }
+
+ // Check if this url looks alright
+ // This isn't perfect, but it's what phpBB 3.0 did, and might as well make sure everything is compatible
+ if (!preg_match('#^(http|https|ftp)://(?:(.*?\.)*?[a-z0-9\-]+?\.[a-z]{2,4}|(?:\d{1,3}\.){3,5}\d{1,3}):?([0-9]*?).*?\.('. implode('|', $this->allowed_extensions) . ')$#i', $url))
+ {
+ $error[] = 'AVATAR_URL_INVALID';
+ return false;
+ }
+
+ // Make sure getimagesize works...
+ if (function_exists('getimagesize'))
+ {
+ if (($width <= 0 || $height <= 0) && (($image_data = getimagesize($url)) === false))
+ {
+ $error[] = 'UNABLE_GET_IMAGE_SIZE';
+ return false;
+ }
+
+ if (!empty($image_data) && ($image_data[0] <= 0 || $image_data[1] <= 0))
+ {
+ $error[] = 'AVATAR_NO_SIZE';
+ return false;
+ }
+
+ $width = ($width && $height) ? $width : $image_data[0];
+ $height = ($width && $height) ? $height : $image_data[1];
+ }
+
+ if ($width <= 0 || $height <= 0)
+ {
+ $error[] = 'AVATAR_NO_SIZE';
+ return false;
+ }
+
+ if (!class_exists('fileupload'))
+ {
+ include($this->phpbb_root_path . 'includes/functions_upload.' . $this->php_ext);
+ }
+
+ $types = fileupload::image_types();
+ $extension = strtolower(filespec::get_extension($url));
+
+ if (!empty($image_data) && (!isset($types[$image_data[2]]) || !in_array($extension, $types[$image_data[2]])))
+ {
+ if (!isset($types[$image_data[2]]))
+ {
+ $error[] = 'UNABLE_GET_IMAGE_SIZE';
+ }
+ else
+ {
+ $error[] = array('IMAGE_FILETYPE_MISMATCH', $types[$image_data[2]][0], $extension);
+ }
+
+ return false;
+ }
+
+ if ($this->config['avatar_max_width'] || $this->config['avatar_max_height'])
+ {
+ if ($width > $this->config['avatar_max_width'] || $height > $this->config['avatar_max_height'])
+ {
+ $error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $width, $height);
+ return false;
+ }
+ }
+
+ if ($this->config['avatar_min_width'] || $this->config['avatar_min_height'])
+ {
+ if ($width < $this->config['avatar_min_width'] || $height < $this->config['avatar_min_height'])
+ {
+ $error[] = array('AVATAR_WRONG_SIZE', $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], $width, $height);
+ return false;
+ }
+ }
+
+ return array(
+ 'avatar' => $url,
+ 'avatar_width' => $width,
+ 'avatar_height' => $height,
+ );
+ }
+}
diff --git a/phpBB/includes/avatar/driver/upload.php b/phpBB/includes/avatar/driver/upload.php
new file mode 100644
index 0000000000..baf51f61c1
--- /dev/null
+++ b/phpBB/includes/avatar/driver/upload.php
@@ -0,0 +1,159 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2011 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Handles avatars uploaded to the board
+* @package phpBB3
+*/
+class phpbb_avatar_driver_upload extends phpbb_avatar_driver
+{
+ /**
+ * @inheritdoc
+ */
+ public function get_data($row, $ignore_config = false)
+ {
+ return array(
+ 'src' => $this->phpbb_root_path . 'download/file.' . $this->php_ext . '?avatar=' . $row['avatar'],
+ 'width' => $row['avatar_width'],
+ 'height' => $row['avatar_height'],
+ );
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function prepare_form($request, $template, $user, $row, &$error)
+ {
+ if (!$this->can_upload())
+ {
+ return false;
+ }
+
+ $template->assign_vars(array(
+ 'S_UPLOAD_AVATAR_URL' => ($this->config['allow_avatar_remote_upload']) ? true : false,
+ 'AVATAR_UPLOAD_SIZE' => $this->config['avatar_filesize'],
+ ));
+
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function process_form($request, $template, $user, $row, &$error)
+ {
+ if (!$this->can_upload())
+ {
+ return false;
+ }
+
+ if (!class_exists('fileupload'))
+ {
+ include($this->phpbb_root_path . 'includes/functions_upload.' . $this->php_ext);
+ }
+
+ $upload = new fileupload('AVATAR_', $this->allowed_extensions, $this->config['avatar_filesize'], $this->config['avatar_min_width'], $this->config['avatar_min_height'], $this->config['avatar_max_width'], $this->config['avatar_max_height'], (isset($this->config['mime_triggers']) ? explode('|', $this->config['mime_triggers']) : false));
+
+ $url = $request->variable('avatar_upload_url', '');
+ $upload_file = $request->file('avatar_upload_file');
+
+ if (!empty($upload_file['name']))
+ {
+ $file = $upload->form_upload('avatar_upload_file');
+ }
+ elseif (!empty($this->config['allow_avatar_remote_upload']) && !empty($url))
+ {
+ $file = $upload->remote_upload($url);
+ }
+ else
+ {
+ $error[] = 'NO_AVATAR_SELECTED';
+ return false;
+ }
+
+ $prefix = $this->config['avatar_salt'] . '_';
+ $file->clean_filename('avatar', $prefix, $row['id']);
+
+ $destination = $this->config['avatar_path'];
+
+ // Adjust destination path (no trailing slash)
+ if (substr($destination, -1, 1) == '/' || substr($destination, -1, 1) == '\\')
+ {
+ $destination = substr($destination, 0, -1);
+ }
+
+ $destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination);
+ if ($destination && ($destination[0] == '/' || $destination[0] == "\\"))
+ {
+ $destination = '';
+ }
+
+ // Move file and overwrite any existing image
+ $file->move_file($destination, true);
+
+ if (sizeof($file->error))
+ {
+ $file->remove();
+ $error = array_merge($error, $file->error);
+ return false;
+ }
+
+ return array(
+ 'avatar' => $row['id'] . '_' . time() . '.' . $file->get('extension'),
+ 'avatar_width' => $file->get('width'),
+ 'avatar_height' => $file->get('height'),
+ );
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function prepare_form_acp($user)
+ {
+ return array(
+ 'allow_avatar_remote_upload'=> array('lang' => 'ALLOW_REMOTE_UPLOAD', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
+ 'avatar_filesize' => array('lang' => 'MAX_FILESIZE', 'validate' => 'int:0', 'type' => 'number:0', 'explain' => true, 'append' => ' ' . $user->lang['BYTES']),
+ 'avatar_path' => array('lang' => 'AVATAR_STORAGE_PATH', 'validate' => 'rwpath', 'type' => 'text:20:255', 'explain' => true),
+ );
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function delete($row)
+ {
+ $ext = substr(strrchr($row['avatar'], '.'), 1);
+ $filename = $this->phpbb_root_path . $this->config['avatar_path'] . '/' . $this->config['avatar_salt'] . '_' . $row['id'] . '.' . $ext;
+
+ if (file_exists($filename))
+ {
+ @unlink($filename);
+ }
+
+ return true;
+ }
+
+ /**
+ * Check if user is able to upload an avatar
+ *
+ * @return bool True if user can upload, false if not
+ */
+ protected function can_upload()
+ {
+ return (file_exists($this->phpbb_root_path . $this->config['avatar_path']) && phpbb_is_writable($this->phpbb_root_path . $this->config['avatar_path']) && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on'));
+ }
+}
diff --git a/phpBB/includes/avatar/manager.php b/phpBB/includes/avatar/manager.php
new file mode 100644
index 0000000000..58d994c3c0
--- /dev/null
+++ b/phpBB/includes/avatar/manager.php
@@ -0,0 +1,309 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2011 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* @package avatar
+*/
+class phpbb_avatar_manager
+{
+ /**
+ * phpBB configuration
+ * @var phpbb_config
+ */
+ protected $config;
+
+ /**
+ * Array that contains a list of enabled drivers
+ * @var array
+ */
+ static protected $enabled_drivers = false;
+
+ /**
+ * Array that contains all available avatar drivers which are passed via the
+ * service container
+ * @var array
+ */
+ protected $avatar_drivers;
+
+ /**
+ * Service container object
+ * @var object
+ */
+ protected $container;
+
+ /**
+ * Default avatar data row
+ * @var array
+ */
+ static protected $default_row = array(
+ 'avatar' => '',
+ 'avatar_type' => '',
+ 'avatar_width' => '',
+ 'avatar_height' => '',
+ );
+
+ /**
+ * Construct an avatar manager object
+ *
+ * @param phpbb_config $config phpBB configuration
+ * @param array $avatar_drivers Avatar drivers passed via the service container
+ * @param object $container Container object
+ */
+ public function __construct(phpbb_config $config, $avatar_drivers, $container)
+ {
+ $this->config = $config;
+ $this->avatar_drivers = $avatar_drivers;
+ $this->container = $container;
+ }
+
+ /**
+ * Get the driver object specified by the avatar type
+ *
+ * @param string $avatar_type Avatar type; by default an avatar's service container name
+ * @param bool $load_enabled Load only enabled avatars
+ *
+ * @return object Avatar driver object
+ */
+ public function get_driver($avatar_type, $load_enabled = true)
+ {
+ if (self::$enabled_drivers === false)
+ {
+ $this->load_enabled_drivers();
+ }
+
+ $avatar_drivers = ($load_enabled) ? self::$enabled_drivers : $this->get_all_drivers();
+
+ // Legacy stuff...
+ switch ($avatar_type)
+ {
+ case AVATAR_GALLERY:
+ $avatar_type = 'avatar.driver.local';
+ break;
+ case AVATAR_UPLOAD:
+ $avatar_type = 'avatar.driver.upload';
+ break;
+ case AVATAR_REMOTE:
+ $avatar_type = 'avatar.driver.remote';
+ break;
+ }
+
+ if (!isset($avatar_drivers[$avatar_type]))
+ {
+ return null;
+ }
+
+ /*
+ * There is no need to handle invalid avatar types as the following code
+ * will cause a ServiceNotFoundException if the type does not exist
+ */
+ $driver = $this->container->get($avatar_type);
+
+ return $driver;
+ }
+
+ /**
+ * Load the list of enabled drivers
+ * This is executed once and fills self::$enabled_drivers
+ */
+ protected function load_enabled_drivers()
+ {
+ if (!empty($this->avatar_drivers))
+ {
+ self::$enabled_drivers = array();
+ foreach ($this->avatar_drivers as $driver)
+ {
+ if ($this->is_enabled($driver))
+ {
+ self::$enabled_drivers[$driver->get_name()] = $driver->get_name();
+ }
+ }
+ asort(self::$enabled_drivers);
+ }
+ }
+
+ /**
+ * Get a list of all avatar drivers
+ *
+ * As this function will only be called in the ACP avatar settings page, it
+ * doesn't make much sense to cache the list of all avatar drivers like the
+ * list of the enabled drivers.
+ *
+ * @return array Array containing a list of all avatar drivers
+ */
+ public function get_all_drivers()
+ {
+ $drivers = array();
+
+ if (!empty($this->avatar_drivers))
+ {
+ foreach ($this->avatar_drivers as $driver)
+ {
+ $drivers[$driver->get_name()] = $driver->get_name();
+ }
+ asort($drivers);
+ }
+
+ return $drivers;
+ }
+
+ /**
+ * Get a list of enabled avatar drivers
+ *
+ * @return array Array containing a list of the enabled avatar drivers
+ */
+ public function get_enabled_drivers()
+ {
+ if (self::$enabled_drivers === false)
+ {
+ $this->load_enabled_drivers();
+ }
+
+ return self::$enabled_drivers;
+ }
+
+ /**
+ * Strip out user_ and group_ prefixes from keys
+ *
+ * @param array $row User data or group data
+ *
+ * @return array User data or group data with keys that have been
+ * stripped from the preceding "user_" or "group_"
+ */
+ static public function clean_row($row)
+ {
+ // Upon creation of a user/group $row might be empty
+ if (empty($row))
+ {
+ return self::$default_row;
+ }
+
+ $keys = array_keys($row);
+ $values = array_values($row);
+
+ $keys = array_map(array('phpbb_avatar_manager', 'strip_prefix'), $keys);
+
+ return array_combine($keys, $values);
+ }
+
+ /**
+ * Strip prepending user_ or group_ prefix from key
+ *
+ * @param string Array key
+ * @return string Key that has been stripped from its prefix
+ */
+ static protected function strip_prefix($key)
+ {
+ return preg_replace('#^(?:user_|group_)#', '', $key);
+ }
+
+ /**
+ * Clean driver names that are returned from template files
+ * Underscores are replaced with dots
+ *
+ * @param string $name Driver name
+ *
+ * @return string Cleaned driver name
+ */
+ static public function clean_driver_name($name)
+ {
+ return str_replace('_', '.', $name);
+ }
+
+ /**
+ * Prepare driver names for use in template files
+ * Dots are replaced with underscores
+ *
+ * @param string $name Clean driver name
+ *
+ * @return string Prepared driver name
+ */
+ static public function prepare_driver_name($name)
+ {
+ return str_replace('.', '_', $name);
+ }
+
+ /**
+ * Check if avatar is enabled
+ *
+ * @param object $driver Avatar driver object
+ *
+ * @return bool True if avatar is enabled, false if it's disabled
+ */
+ public function is_enabled($driver)
+ {
+ $config_name = $this->get_driver_config_name($driver);
+
+ return $this->config["allow_avatar_{$config_name}"];
+ }
+
+ /**
+ * Get the settings array for enabling/disabling an avatar driver
+ *
+ * @param object $driver Avatar driver object
+ *
+ * @return array Array of configuration options as consumed by acp_board
+ */
+ public function get_avatar_settings($driver)
+ {
+ $config_name = $this->get_driver_config_name($driver);
+
+ return array(
+ 'allow_avatar_' . $config_name => array('lang' => 'ALLOW_' . strtoupper($config_name), 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
+ );
+ }
+
+ /**
+ * Get the config name of an avatar driver
+ *
+ * @param object $driver Avatar driver object
+ *
+ * @return string Avatar driver config name
+ */
+ public function get_driver_config_name($driver)
+ {
+ return preg_replace('#^phpbb_avatar_driver_#', '', get_class($driver));
+ }
+
+ /**
+ * Replace "error" strings with their real, localized form
+ *
+ * @param phpbb_user phpBB User object
+ * @param array $error Array containing error strings
+ * Key values can either be a string with a language key or an array
+ * that will be passed to vsprintf() with the language key in the
+ * first array key.
+ *
+ * @return array Array containing the localized error strings
+ */
+ public function localize_errors(phpbb_user $user, $error)
+ {
+ foreach ($error as $key => $lang)
+ {
+ if (is_array($lang))
+ {
+ $lang_key = array_shift($lang);
+ $error[$key] = vsprintf($user->lang($lang_key), $lang);
+ }
+ else
+ {
+ $error[$key] = $user->lang("$lang");
+ }
+ }
+
+ return $error;
+ }
+}
diff --git a/phpBB/includes/bbcode.php b/phpBB/includes/bbcode.php
index e8681420d4..c198abeb54 100644
--- a/phpBB/includes/bbcode.php
+++ b/phpBB/includes/bbcode.php
@@ -133,7 +133,7 @@ class bbcode
$this->template_bitfield = new bitfield($user->style['bbcode_bitfield']);
$style_resource_locator = new phpbb_style_resource_locator();
- $style_path_provider = new phpbb_style_extension_path_provider($phpbb_extension_manager, new phpbb_style_path_provider());
+ $style_path_provider = new phpbb_style_extension_path_provider($phpbb_extension_manager, new phpbb_style_path_provider(), $phpbb_root_path);
$template = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, new phpbb_template_context(), $phpbb_extension_manager);
$style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, $style_path_provider, $template);
$style->set_style();
diff --git a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php
index 83d40bbba7..cb21b04ec5 100644
--- a/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php
+++ b/phpBB/includes/captcha/plugins/phpbb_recaptcha_plugin.php
@@ -270,7 +270,7 @@ class phpbb_recaptcha extends phpbb_default_captcha
$response = '';
if (false == ($fs = @fsockopen($host, $port, $errno, $errstr, 10)))
{
- trigger_error('Could not open socket', E_USER_ERROR);
+ trigger_error('RECAPTCHA_SOCKET_ERROR', E_USER_ERROR);
}
fwrite($fs, $http_request);
diff --git a/phpBB/includes/class_loader.php b/phpBB/includes/class_loader.php
index 6082800908..02a2d584dc 100644
--- a/phpBB/includes/class_loader.php
+++ b/phpBB/includes/class_loader.php
@@ -52,7 +52,7 @@ class phpbb_class_loader
* @param string $php_ext The file extension for PHP files
* @param phpbb_cache_driver_interface $cache An implementation of the phpBB cache interface.
*/
- public function __construct($prefix, $path, $php_ext = '.php', phpbb_cache_driver_interface $cache = null)
+ public function __construct($prefix, $path, $php_ext = 'php', phpbb_cache_driver_interface $cache = null)
{
$this->prefix = $prefix;
$this->path = $path;
@@ -111,7 +111,7 @@ class phpbb_class_loader
{
if (isset($this->cached_paths[$class]))
{
- return $this->path . $this->cached_paths[$class] . $this->php_ext;
+ return $this->path . $this->cached_paths[$class] . '.' . $this->php_ext;
}
if (!preg_match('/^' . $this->prefix . '[a-zA-Z0-9_]+$/', $class))
@@ -136,7 +136,7 @@ class phpbb_class_loader
$relative_path = $dirs . implode(array_slice($parts, $i, sizeof($parts) - $i), '_');
- if (!file_exists($this->path . $relative_path . $this->php_ext))
+ if (!file_exists($this->path . $relative_path . '.' . $this->php_ext))
{
return false;
}
@@ -147,7 +147,7 @@ class phpbb_class_loader
$this->cache->put('class_loader_' . $this->prefix, $this->cached_paths);
}
- return $this->path . $relative_path . $this->php_ext;
+ return $this->path . $relative_path . '.' . $this->php_ext;
}
/**
diff --git a/phpBB/includes/config/db_text.php b/phpBB/includes/config/db_text.php
new file mode 100644
index 0000000000..b365cb5c77
--- /dev/null
+++ b/phpBB/includes/config/db_text.php
@@ -0,0 +1,163 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Manages configuration options with an arbitrary length value stored in a TEXT
+* column. In constrast to class phpbb_config_db, values are never cached and
+* prefetched, but every get operation sends a query to the database.
+*
+* @package phpBB3
+*/
+class phpbb_config_db_text
+{
+ /**
+ * Database connection
+ * @var phpbb_db_driver
+ */
+ protected $db;
+
+ /**
+ * Name of the database table used.
+ * @var string
+ */
+ protected $table;
+
+ /**
+ * @param phpbb_db_driver $db Database connection
+ * @param string $table Table name
+ */
+ public function __construct(phpbb_db_driver $db, $table)
+ {
+ $this->db = $db;
+ $this->table = $this->db->sql_escape($table);
+ }
+
+ /**
+ * Sets the configuration option with the name $key to $value.
+ *
+ * @param string $key The configuration option's name
+ * @param string $value New configuration value
+ *
+ * @return null
+ */
+ public function set($key, $value)
+ {
+ $this->set_array(array($key => $value));
+ }
+
+ /**
+ * Gets the configuration value for the name $key.
+ *
+ * @param string $key The configuration option's name
+ *
+ * @return string|null String result on success
+ * null if there is no such option
+ */
+ public function get($key)
+ {
+ $map = $this->get_array(array($key));
+
+ return isset($map[$key]) ? $map[$key] : null;
+ }
+
+ /**
+ * Removes the configuration option with the name $key.
+ *
+ * @param string $key The configuration option's name
+ *
+ * @return null
+ */
+ public function delete($key)
+ {
+ $this->delete_array(array($key));
+ }
+
+ /**
+ * Mass set configuration options: Receives an associative array,
+ * treats array keys as configuration option names and associated
+ * array values as their configuration option values.
+ *
+ * @param array $map Map from configuration names to values
+ *
+ * @return null
+ */
+ public function set_array(array $map)
+ {
+ $this->db->sql_transaction('begin');
+
+ foreach ($map as $key => $value)
+ {
+ $sql = 'UPDATE ' . $this->table . "
+ SET config_value = '" . $this->db->sql_escape($value) . "'
+ WHERE config_name = '" . $this->db->sql_escape($key) . "'";
+ $result = $this->db->sql_query($sql);
+
+ if (!$this->db->sql_affectedrows($result))
+ {
+ $sql = 'INSERT INTO ' . $this->table . ' ' . $this->db->sql_build_array('INSERT', array(
+ 'config_name' => $key,
+ 'config_value' => $value,
+ ));
+ $this->db->sql_query($sql);
+ }
+ }
+
+ $this->db->sql_transaction('commit');
+ }
+
+ /**
+ * Mass get configuration options: Receives a set of configuration
+ * option names and returns the result as a key => value map where
+ * array keys are configuration option names and array values are
+ * associated config option values.
+ *
+ * @param array $keys Set of configuration option names
+ *
+ * @return array Map from configuration names to values
+ */
+ public function get_array(array $keys)
+ {
+ $sql = 'SELECT *
+ FROM ' . $this->table . '
+ WHERE ' . $this->db->sql_in_set('config_name', $keys, false, true);
+ $result = $this->db->sql_query($sql);
+
+ $map = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $map[$row['config_name']] = $row['config_value'];
+ }
+ $this->db->sql_freeresult($result);
+
+ return $map;
+ }
+
+ /**
+ * Mass delete configuration options.
+ *
+ * @param array $keys Set of configuration option names
+ *
+ * @return null
+ */
+ public function delete_array(array $keys)
+ {
+ $sql = 'DELETE
+ FROM ' . $this->table . '
+ WHERE ' . $this->db->sql_in_set('config_name', $keys, false, true);
+ $result = $this->db->sql_query($sql);
+ }
+}
diff --git a/phpBB/includes/constants.php b/phpBB/includes/constants.php
index 36576e5344..8c27d3fd0c 100644
--- a/phpBB/includes/constants.php
+++ b/phpBB/includes/constants.php
@@ -270,6 +270,7 @@ define('STYLES_TEMPLATE_DATA_TABLE',$table_prefix . 'styles_template_data');
define('STYLES_THEME_TABLE', $table_prefix . 'styles_theme');
define('STYLES_IMAGESET_TABLE', $table_prefix . 'styles_imageset');
define('STYLES_IMAGESET_DATA_TABLE',$table_prefix . 'styles_imageset_data');
+define('TEAMPAGE_TABLE', $table_prefix . 'teampage');
define('TOPICS_TABLE', $table_prefix . 'topics');
define('TOPICS_POSTED_TABLE', $table_prefix . 'topics_posted');
define('TOPICS_TRACK_TABLE', $table_prefix . 'topics_track');
diff --git a/phpBB/includes/controller/helper.php b/phpBB/includes/controller/helper.php
index 6cacc8fefa..74410ddfd1 100644
--- a/phpBB/includes/controller/helper.php
+++ b/phpBB/includes/controller/helper.php
@@ -85,17 +85,39 @@ class phpbb_controller_helper
}
/**
- * Easily generate a URL
+ * Generate a URL
*
- * @param array $url_parts Each array element is a 'folder'
- * i.e. array('my', 'ext') maps to ./app.php/my/ext
- * @param mixed $query The Query string, passed directly into the second
- * argument of append_sid()
- * @return string A URL that has already been run through append_sid()
+ * @param string $route The route to travel
+ * @param mixed $params String or array of additional url parameters
+ * @param bool $is_amp Is url using &amp; (true) or & (false)
+ * @param string $session_id Possibility to use a custom session id instead of the global one
+ * @return string The URL already passed through append_sid()
*/
- public function url(array $url_parts, $query = '')
+ public function url($route, $params = false, $is_amp = true, $session_id = false)
{
- return append_sid($this->phpbb_root_path . implode('/', $url_parts), $query);
+ $route_params = '';
+ if (($route_delim = strpos($route, '?')) !== false)
+ {
+ $route_params = substr($route, $route_delim);
+ $route = substr($route, 0, $route_delim);
+ }
+
+ if (is_array($params) && !empty($params))
+ {
+ $params = array_merge(array(
+ 'controller' => $route,
+ ), $params);
+ }
+ else if (is_string($params) && $params)
+ {
+ $params = 'controller=' . $route . (($is_amp) ? '&amp;' : '&') . $params;
+ }
+ else
+ {
+ $params = array('controller' => $route);
+ }
+
+ return append_sid($this->phpbb_root_path . 'app.' . $this->php_ext . $route_params, $params, $is_amp, $session_id);
}
/**
diff --git a/phpBB/includes/db/driver/driver.php b/phpBB/includes/db/driver/driver.php
index 8dda94bc2c..b915ee081b 100644
--- a/phpBB/includes/db/driver/driver.php
+++ b/phpBB/includes/db/driver/driver.php
@@ -568,12 +568,12 @@ class phpbb_db_driver
* Run more than one insert statement.
*
* @param string $table table name to run the statements on
- * @param array &$sql_ary multi-dimensional array holding the statement data.
+ * @param array $sql_ary multi-dimensional array holding the statement data.
*
* @return bool false if no statements were executed.
* @access public
*/
- function sql_multi_insert($table, &$sql_ary)
+ function sql_multi_insert($table, $sql_ary)
{
if (!sizeof($sql_ary))
{
diff --git a/phpBB/includes/db/driver/mssql_base.php b/phpBB/includes/db/driver/mssql_base.php
new file mode 100644
index 0000000000..56c111c871
--- /dev/null
+++ b/phpBB/includes/db/driver/mssql_base.php
@@ -0,0 +1,65 @@
+<?php
+/**
+*
+* @package dbal
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* MSSQL Database Base Abstraction Layer
+* @package dbal
+ */
+abstract class phpbb_db_driver_mssql_base extends phpbb_db_driver
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function sql_concatenate($expr1, $expr2)
+ {
+ return $expr1 . ' + ' . $expr2;
+ }
+
+ /**
+ * Escape string used in sql query
+ */
+ function sql_escape($msg)
+ {
+ return str_replace(array("'", "\0"), array("''", ''), $msg);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ function sql_lower_text($column_name)
+ {
+ return "LOWER(SUBSTRING($column_name, 1, DATALENGTH($column_name)))";
+ }
+
+ /**
+ * Build LIKE expression
+ * @access private
+ */
+ function _sql_like_expression($expression)
+ {
+ return $expression . " ESCAPE '\\'";
+ }
+
+ /**
+ * Build db-specific query data
+ * @access private
+ */
+ function _sql_custom_build($stage, $data)
+ {
+ return $data;
+ }
+}
diff --git a/phpBB/includes/db/driver/mssql_odbc.php b/phpBB/includes/db/driver/mssql_odbc.php
index f7834443eb..cde9d332ba 100644
--- a/phpBB/includes/db/driver/mssql_odbc.php
+++ b/phpBB/includes/db/driver/mssql_odbc.php
@@ -26,7 +26,7 @@ if (!defined('IN_PHPBB'))
*
* @package dbal
*/
-class phpbb_db_driver_mssql_odbc extends phpbb_db_driver
+class phpbb_db_driver_mssql_odbc extends phpbb_db_driver_mssql_base
{
var $last_query_text = '';
var $connect_error = '';
@@ -126,14 +126,6 @@ class phpbb_db_driver_mssql_odbc extends phpbb_db_driver
}
/**
- * {@inheritDoc}
- */
- public function sql_concatenate($expr1, $expr2)
- {
- return $expr1 . ' + ' . $expr2;
- }
-
- /**
* SQL Transaction
* @access private
*/
@@ -326,40 +318,6 @@ class phpbb_db_driver_mssql_odbc extends phpbb_db_driver
}
/**
- * Escape string used in sql query
- */
- function sql_escape($msg)
- {
- return str_replace(array("'", "\0"), array("''", ''), $msg);
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_lower_text($column_name)
- {
- return "LOWER(SUBSTRING($column_name, 1, DATALENGTH($column_name)))";
- }
-
- /**
- * Build LIKE expression
- * @access private
- */
- function _sql_like_expression($expression)
- {
- return $expression . " ESCAPE '\\'";
- }
-
- /**
- * Build db-specific query data
- * @access private
- */
- function _sql_custom_build($stage, $data)
- {
- return $data;
- }
-
- /**
* return sql error array
* @access private
*/
diff --git a/phpBB/includes/db/driver/mssqlnative.php b/phpBB/includes/db/driver/mssqlnative.php
index 656cbd2437..6f433e10cf 100644
--- a/phpBB/includes/db/driver/mssqlnative.php
+++ b/phpBB/includes/db/driver/mssqlnative.php
@@ -191,7 +191,7 @@ class result_mssqlnative
/**
* @package dbal
*/
-class phpbb_db_driver_mssqlnative extends phpbb_db_driver
+class phpbb_db_driver_mssqlnative extends phpbb_db_driver_mssql_base
{
var $m_insert_id = NULL;
var $last_query_text = '';
@@ -259,14 +259,6 @@ class phpbb_db_driver_mssqlnative extends phpbb_db_driver
/**
* {@inheritDoc}
*/
- public function sql_concatenate($expr1, $expr2)
- {
- return $expr1 . ' + ' . $expr2;
- }
-
- /**
- * {@inheritDoc}
- */
function sql_buffer_nested_transactions()
{
return true;
@@ -491,31 +483,6 @@ class phpbb_db_driver_mssqlnative extends phpbb_db_driver
}
/**
- * Escape string used in sql query
- */
- function sql_escape($msg)
- {
- return str_replace(array("'", "\0"), array("''", ''), $msg);
- }
-
- /**
- * {@inheritDoc}
- */
- function sql_lower_text($column_name)
- {
- return "LOWER(SUBSTRING($column_name, 1, DATALENGTH($column_name)))";
- }
-
- /**
- * Build LIKE expression
- * @access private
- */
- function _sql_like_expression($expression)
- {
- return $expression . " ESCAPE '\\'";
- }
-
- /**
* return sql error array
* @access private
*/
@@ -561,15 +528,6 @@ class phpbb_db_driver_mssqlnative extends phpbb_db_driver
}
/**
- * Build db-specific query data
- * @access private
- */
- function _sql_custom_build($stage, $data)
- {
- return $data;
- }
-
- /**
* Close sql connection
* @access private
*/
diff --git a/phpBB/includes/db/driver/mysql.php b/phpBB/includes/db/driver/mysql.php
index 9de7283a42..f3744ac09d 100644
--- a/phpBB/includes/db/driver/mysql.php
+++ b/phpBB/includes/db/driver/mysql.php
@@ -24,7 +24,7 @@ if (!defined('IN_PHPBB'))
* MySQL 5.0+
* @package dbal
*/
-class phpbb_db_driver_mysql extends phpbb_db_driver
+class phpbb_db_driver_mysql extends phpbb_db_driver_mysql_base
{
var $multi_insert = true;
var $connect_error = '';
@@ -136,14 +136,6 @@ class phpbb_db_driver_mysql extends phpbb_db_driver
}
/**
- * {@inheritDoc}
- */
- public function sql_concatenate($expr1, $expr2)
- {
- return 'CONCAT(' . $expr1 . ', ' . $expr2 . ')';
- }
-
- /**
* SQL Transaction
* @access private
*/
@@ -227,25 +219,6 @@ class phpbb_db_driver_mysql extends phpbb_db_driver
}
/**
- * Build LIMIT query
- */
- function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
- {
- $this->query_result = false;
-
- // if $total is set to 0 we do not want to limit the number of rows
- if ($total == 0)
- {
- // Having a value of -1 was always a bug
- $total = '18446744073709551615';
- }
-
- $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total);
-
- return $this->sql_query($query, $cache_ttl);
- }
-
- /**
* Return number of affected rows
*/
function sql_affectedrows()
@@ -342,101 +315,6 @@ class phpbb_db_driver_mysql extends phpbb_db_driver
}
/**
- * Gets the estimated number of rows in a specified table.
- *
- * @param string $table_name Table name
- *
- * @return string Number of rows in $table_name.
- * Prefixed with ~ if estimated (otherwise exact).
- *
- * @access public
- */
- function get_estimated_row_count($table_name)
- {
- $table_status = $this->get_table_status($table_name);
-
- if (isset($table_status['Engine']))
- {
- if ($table_status['Engine'] === 'MyISAM')
- {
- return $table_status['Rows'];
- }
- else if ($table_status['Engine'] === 'InnoDB' && $table_status['Rows'] > 100000)
- {
- return '~' . $table_status['Rows'];
- }
- }
-
- return parent::get_row_count($table_name);
- }
-
- /**
- * Gets the exact number of rows in a specified table.
- *
- * @param string $table_name Table name
- *
- * @return string Exact number of rows in $table_name.
- *
- * @access public
- */
- function get_row_count($table_name)
- {
- $table_status = $this->get_table_status($table_name);
-
- if (isset($table_status['Engine']) && $table_status['Engine'] === 'MyISAM')
- {
- return $table_status['Rows'];
- }
-
- return parent::get_row_count($table_name);
- }
-
- /**
- * Gets some information about the specified table.
- *
- * @param string $table_name Table name
- *
- * @return array
- *
- * @access protected
- */
- function get_table_status($table_name)
- {
- $sql = "SHOW TABLE STATUS
- LIKE '" . $this->sql_escape($table_name) . "'";
- $result = $this->sql_query($sql);
- $table_status = $this->sql_fetchrow($result);
- $this->sql_freeresult($result);
-
- return $table_status;
- }
-
- /**
- * Build LIKE expression
- * @access private
- */
- function _sql_like_expression($expression)
- {
- return $expression;
- }
-
- /**
- * Build db-specific query data
- * @access private
- */
- function _sql_custom_build($stage, $data)
- {
- switch ($stage)
- {
- case 'FROM':
- $data = '(' . $data . ')';
- break;
- }
-
- return $data;
- }
-
- /**
* return sql error array
* @access private
*/
diff --git a/phpBB/includes/db/driver/mysql_base.php b/phpBB/includes/db/driver/mysql_base.php
new file mode 100644
index 0000000000..ba44ea61aa
--- /dev/null
+++ b/phpBB/includes/db/driver/mysql_base.php
@@ -0,0 +1,145 @@
+<?php
+/**
+*
+* @package dbal
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Abstract MySQL Database Base Abstraction Layer
+* @package dbal
+*/
+abstract class phpbb_db_driver_mysql_base extends phpbb_db_driver
+{
+ /**
+ * {@inheritDoc}
+ */
+ public function sql_concatenate($expr1, $expr2)
+ {
+ return 'CONCAT(' . $expr1 . ', ' . $expr2 . ')';
+ }
+
+ /**
+ * Build LIMIT query
+ */
+ function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
+ {
+ $this->query_result = false;
+
+ // if $total is set to 0 we do not want to limit the number of rows
+ if ($total == 0)
+ {
+ // MySQL 4.1+ no longer supports -1 in limit queries
+ $total = '18446744073709551615';
+ }
+
+ $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total);
+
+ return $this->sql_query($query, $cache_ttl);
+ }
+
+ /**
+ * Gets the estimated number of rows in a specified table.
+ *
+ * @param string $table_name Table name
+ *
+ * @return string Number of rows in $table_name.
+ * Prefixed with ~ if estimated (otherwise exact).
+ *
+ * @access public
+ */
+ function get_estimated_row_count($table_name)
+ {
+ $table_status = $this->get_table_status($table_name);
+
+ if (isset($table_status['Engine']))
+ {
+ if ($table_status['Engine'] === 'MyISAM')
+ {
+ return $table_status['Rows'];
+ }
+ else if ($table_status['Engine'] === 'InnoDB' && $table_status['Rows'] > 100000)
+ {
+ return '~' . $table_status['Rows'];
+ }
+ }
+
+ return parent::get_row_count($table_name);
+ }
+
+ /**
+ * Gets the exact number of rows in a specified table.
+ *
+ * @param string $table_name Table name
+ *
+ * @return string Exact number of rows in $table_name.
+ *
+ * @access public
+ */
+ function get_row_count($table_name)
+ {
+ $table_status = $this->get_table_status($table_name);
+
+ if (isset($table_status['Engine']) && $table_status['Engine'] === 'MyISAM')
+ {
+ return $table_status['Rows'];
+ }
+
+ return parent::get_row_count($table_name);
+ }
+
+ /**
+ * Gets some information about the specified table.
+ *
+ * @param string $table_name Table name
+ *
+ * @return array
+ *
+ * @access protected
+ */
+ function get_table_status($table_name)
+ {
+ $sql = "SHOW TABLE STATUS
+ LIKE '" . $this->sql_escape($table_name) . "'";
+ $result = $this->sql_query($sql);
+ $table_status = $this->sql_fetchrow($result);
+ $this->sql_freeresult($result);
+
+ return $table_status;
+ }
+
+ /**
+ * Build LIKE expression
+ * @access private
+ */
+ function _sql_like_expression($expression)
+ {
+ return $expression;
+ }
+
+ /**
+ * Build db-specific query data
+ * @access private
+ */
+ function _sql_custom_build($stage, $data)
+ {
+ switch ($stage)
+ {
+ case 'FROM':
+ $data = '(' . $data . ')';
+ break;
+ }
+
+ return $data;
+ }
+}
diff --git a/phpBB/includes/db/driver/mysqli.php b/phpBB/includes/db/driver/mysqli.php
index 7448bf1670..0f7a73ee6e 100644
--- a/phpBB/includes/db/driver/mysqli.php
+++ b/phpBB/includes/db/driver/mysqli.php
@@ -21,7 +21,7 @@ if (!defined('IN_PHPBB'))
* MySQL 4.1+ or MySQL 5.0+
* @package dbal
*/
-class phpbb_db_driver_mysqli extends phpbb_db_driver
+class phpbb_db_driver_mysqli extends phpbb_db_driver_mysql_base
{
var $multi_insert = true;
var $connect_error = '';
@@ -103,6 +103,7 @@ class phpbb_db_driver_mysqli extends phpbb_db_driver
/**
* Version information about used database
+ * @param bool $raw if true, only return the fetched sql_server_version
* @param bool $use_cache If true, it is safe to retrieve the value from the cache
* @return string sql server version
*/
@@ -128,14 +129,6 @@ class phpbb_db_driver_mysqli extends phpbb_db_driver
}
/**
- * {@inheritDoc}
- */
- public function sql_concatenate($expr1, $expr2)
- {
- return 'CONCAT(' . $expr1 . ', ' . $expr2 . ')';
- }
-
- /**
* SQL Transaction
* @access private
*/
@@ -218,25 +211,6 @@ class phpbb_db_driver_mysqli extends phpbb_db_driver
}
/**
- * Build LIMIT query
- */
- function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
- {
- $this->query_result = false;
-
- // if $total is set to 0 we do not want to limit the number of rows
- if ($total == 0)
- {
- // MySQL 4.1+ no longer supports -1 in limit queries
- $total = '18446744073709551615';
- }
-
- $query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total);
-
- return $this->sql_query($query, $cache_ttl);
- }
-
- /**
* Return number of affected rows
*/
function sql_affectedrows()
@@ -328,101 +302,6 @@ class phpbb_db_driver_mysqli extends phpbb_db_driver
}
/**
- * Gets the estimated number of rows in a specified table.
- *
- * @param string $table_name Table name
- *
- * @return string Number of rows in $table_name.
- * Prefixed with ~ if estimated (otherwise exact).
- *
- * @access public
- */
- function get_estimated_row_count($table_name)
- {
- $table_status = $this->get_table_status($table_name);
-
- if (isset($table_status['Engine']))
- {
- if ($table_status['Engine'] === 'MyISAM')
- {
- return $table_status['Rows'];
- }
- else if ($table_status['Engine'] === 'InnoDB' && $table_status['Rows'] > 100000)
- {
- return '~' . $table_status['Rows'];
- }
- }
-
- return parent::get_row_count($table_name);
- }
-
- /**
- * Gets the exact number of rows in a specified table.
- *
- * @param string $table_name Table name
- *
- * @return string Exact number of rows in $table_name.
- *
- * @access public
- */
- function get_row_count($table_name)
- {
- $table_status = $this->get_table_status($table_name);
-
- if (isset($table_status['Engine']) && $table_status['Engine'] === 'MyISAM')
- {
- return $table_status['Rows'];
- }
-
- return parent::get_row_count($table_name);
- }
-
- /**
- * Gets some information about the specified table.
- *
- * @param string $table_name Table name
- *
- * @return array
- *
- * @access protected
- */
- function get_table_status($table_name)
- {
- $sql = "SHOW TABLE STATUS
- LIKE '" . $this->sql_escape($table_name) . "'";
- $result = $this->sql_query($sql);
- $table_status = $this->sql_fetchrow($result);
- $this->sql_freeresult($result);
-
- return $table_status;
- }
-
- /**
- * Build LIKE expression
- * @access private
- */
- function _sql_like_expression($expression)
- {
- return $expression;
- }
-
- /**
- * Build db-specific query data
- * @access private
- */
- function _sql_custom_build($stage, $data)
- {
- switch ($stage)
- {
- case 'FROM':
- $data = '(' . $data . ')';
- break;
- }
-
- return $data;
- }
-
- /**
* return sql error array
* @access private
*/
diff --git a/phpBB/includes/db/migration/data/310/avatars.php b/phpBB/includes/db/migration/data/310/avatars.php
new file mode 100644
index 0000000000..79547337f7
--- /dev/null
+++ b/phpBB/includes/db/migration/data/310/avatars.php
@@ -0,0 +1,67 @@
+<?php
+/**
+*
+* @package migration
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License v2
+*
+*/
+
+class phpbb_db_migration_data_310_avatars extends phpbb_db_migration
+{
+ public function effectively_installed()
+ {
+ return isset($this->config['allow_avatar_gravatar']);
+ }
+
+ static public function depends_on()
+ {
+ return array('phpbb_db_migration_data_30x_3_0_11');
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'change_columns' => array(
+ $this->table_prefix . 'users' => array(
+ 'user_avatar_type' => array('VCHAR:255', ''),
+ ),
+ $this->table_prefix . 'groups' => array(
+ 'group_avatar_type' => array('VCHAR:255', ''),
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'change_columns' => array(
+ $this->table_prefix . 'users' => array(
+ 'user_avatar_type' => array('TINT:2', ''),
+ ),
+ $this->table_prefix . 'groups' => array(
+ 'group_avatar_type' => array('TINT:2', ''),
+ ),
+ ),
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.add', array('allow_avatar_gravatar', 0)),
+ array('custom', array(array($this, 'update_module_auth'))),
+ );
+ }
+
+ public function update_module_auth()
+ {
+ $sql = 'UPDATE ' . $this->table_prefix . "modules
+ SET module_auth = 'cfg_allow_avatar'
+ WHERE module_class = 'ucp'
+ AND module_basename = 'ucp_profile'
+ AND module_mode = 'avatar'";
+ $this->db->sql_query($sql);
+ }
+}
diff --git a/phpBB/includes/db/migration/data/310/boardindex.php b/phpBB/includes/db/migration/data/310/boardindex.php
new file mode 100644
index 0000000000..965e32c15c
--- /dev/null
+++ b/phpBB/includes/db/migration/data/310/boardindex.php
@@ -0,0 +1,23 @@
+<?php
+/**
+*
+* @package migration
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License v2
+*
+*/
+
+class phpbb_db_migration_data_310_boardindex extends phpbb_db_migration
+{
+ public function effectively_installed()
+ {
+ return isset($this->config['board_index_text']);
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.add', array('board_index_text', '')),
+ );
+ }
+}
diff --git a/phpBB/includes/db/migration/data/310/config_db_text.php b/phpBB/includes/db/migration/data/310/config_db_text.php
new file mode 100644
index 0000000000..89f211adda
--- /dev/null
+++ b/phpBB/includes/db/migration/data/310/config_db_text.php
@@ -0,0 +1,45 @@
+<?php
+/**
+*
+* @package migration
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License v2
+*
+*/
+
+class phpbb_db_migration_data_310_config_db_text extends phpbb_db_migration
+{
+ public function effectively_installed()
+ {
+ return $this->db_tools->sql_table_exists($this->table_prefix . 'config_text');
+ }
+
+ static public function depends_on()
+ {
+ return array('phpbb_db_migration_data_30x_3_0_11');
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'add_tables' => array(
+ $this->table_prefix . 'config_text' => array(
+ 'COLUMNS' => array(
+ 'config_name' => array('VCHAR', ''),
+ 'config_value' => array('MTEXT', ''),
+ ),
+ 'PRIMARY_KEY' => 'config_name',
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'drop_tables' => array(
+ $this->table_prefix . 'config_text',
+ ),
+ );
+ }
+}
diff --git a/phpBB/includes/db/migration/data/310/forgot_password.php b/phpBB/includes/db/migration/data/310/forgot_password.php
new file mode 100644
index 0000000000..a553e51f35
--- /dev/null
+++ b/phpBB/includes/db/migration/data/310/forgot_password.php
@@ -0,0 +1,28 @@
+<?php
+/**
+*
+* @package migration
+* @copyright (c) 2012 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License v2
+*
+*/
+
+class phpbb_db_migration_data_310_forgot_password extends phpbb_db_migration
+{
+ public function effectively_installed()
+ {
+ return isset($this->config['allow_password_reset']);
+ }
+
+ static public function depends_on()
+ {
+ return array('phpbb_db_migration_data_30x_3_0_11');
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.add', array('allow_password_reset', 1)),
+ );
+ }
+}
diff --git a/phpBB/includes/db/migration/data/310/jquery_update.php b/phpBB/includes/db/migration/data/310/jquery_update.php
new file mode 100644
index 0000000000..dc49f74fcb
--- /dev/null
+++ b/phpBB/includes/db/migration/data/310/jquery_update.php
@@ -0,0 +1,31 @@
+<?php
+/**
+*
+* @package migration
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License v2
+*
+*/
+
+class phpbb_db_migration_data_310_jquery_update extends phpbb_db_migration
+{
+ public function effectively_installed()
+ {
+ return $this->config['load_jquery_url'] !== '//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js';
+ }
+
+ static public function depends_on()
+ {
+ return array(
+ 'phpbb_db_migration_data_310_dev',
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('config.update', array('load_jquery_url', '//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js')),
+ );
+ }
+
+}
diff --git a/phpBB/includes/db/migration/data/310/notifications_schema_fix.php b/phpBB/includes/db/migration/data/310/notifications_schema_fix.php
new file mode 100644
index 0000000000..27e63e10d0
--- /dev/null
+++ b/phpBB/includes/db/migration/data/310/notifications_schema_fix.php
@@ -0,0 +1,92 @@
+<?php
+/**
+*
+* @package migration
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License v2
+*
+*/
+
+class phpbb_db_migration_data_310_notifications_schema_fix extends phpbb_db_migration
+{
+ static public function depends_on()
+ {
+ return array('phpbb_db_migration_data_310_notifications');
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'drop_tables' => array(
+ $this->table_prefix . 'notification_types',
+ $this->table_prefix . 'notifications',
+ ),
+ 'add_tables' => array(
+ $this->table_prefix . 'notification_types' => array(
+ 'COLUMNS' => array(
+ 'notification_type_id' => array('USINT', NULL, 'auto_increment'),
+ 'notification_type_name' => array('VCHAR:255', ''),
+ 'notification_type_enabled' => array('BOOL', 1),
+ ),
+ 'PRIMARY_KEY' => array('notification_type_id'),
+ 'KEYS' => array(
+ 'type' => array('UNIQUE', array('notification_type_name')),
+ ),
+ ),
+ $this->table_prefix . 'notifications' => array(
+ 'COLUMNS' => array(
+ 'notification_id' => array('UINT:10', NULL, 'auto_increment'),
+ 'notification_type_id' => array('USINT', 0),
+ 'item_id' => array('UINT', 0),
+ 'item_parent_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ 'notification_read' => array('BOOL', 0),
+ 'notification_time' => array('TIMESTAMP', 1),
+ 'notification_data' => array('TEXT_UNI', ''),
+ ),
+ 'PRIMARY_KEY' => 'notification_id',
+ 'KEYS' => array(
+ 'item_ident' => array('INDEX', array('notification_type_id', 'item_id')),
+ 'user' => array('INDEX', array('user_id', 'notification_read')),
+ ),
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'drop_tables' => array(
+ $this->table_prefix . 'notification_types',
+ $this->table_prefix . 'notifications',
+ ),
+ 'add_tables' => array(
+ $this->table_prefix . 'notification_types' => array(
+ 'COLUMNS' => array(
+ 'notification_type' => array('VCHAR:255', ''),
+ 'notification_type_enabled' => array('BOOL', 1),
+ ),
+ 'PRIMARY_KEY' => array('notification_type', 'notification_type_enabled'),
+ ),
+ $this->table_prefix . 'notifications' => array(
+ 'COLUMNS' => array(
+ 'notification_id' => array('UINT', NULL, 'auto_increment'),
+ 'item_type' => array('VCHAR:255', ''),
+ 'item_id' => array('UINT', 0),
+ 'item_parent_id' => array('UINT', 0),
+ 'user_id' => array('UINT', 0),
+ 'notification_read' => array('BOOL', 0),
+ 'notification_time' => array('TIMESTAMP', 1),
+ 'notification_data' => array('TEXT_UNI', ''),
+ ),
+ 'PRIMARY_KEY' => 'notification_id',
+ 'KEYS' => array(
+ 'item_ident' => array('INDEX', array('item_type', 'item_id')),
+ 'user' => array('INDEX', array('user_id', 'notification_read')),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/phpBB/includes/db/migration/data/310/style_update_p1.php b/phpBB/includes/db/migration/data/310/style_update_p1.php
index e324ce7f24..d43537559d 100644
--- a/phpBB/includes/db/migration/data/310/style_update_p1.php
+++ b/phpBB/includes/db/migration/data/310/style_update_p1.php
@@ -19,6 +19,34 @@ class phpbb_db_migration_data_310_style_update_p1 extends phpbb_db_migration
return array('phpbb_db_migration_data_30x_3_0_11');
}
+ public function update_schema()
+ {
+ return array(
+ 'add_columns' => array(
+ $this->table_prefix . 'styles' => array(
+ 'style_path' => array('VCHAR:100', ''),
+ 'bbcode_bitfield' => array('VCHAR:255', 'kNg='),
+ 'style_parent_id' => array('UINT', 0),
+ 'style_parent_tree' => array('TEXT', ''),
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'drop_columns' => array(
+ $this->table_prefix . 'styles' => array(
+ 'style_path',
+ 'bbcode_bitfield',
+ 'style_parent_id',
+ 'style_parent_tree',
+ ),
+ ),
+ );
+ }
+
public function update_data()
{
return array(
diff --git a/phpBB/includes/db/migration/data/310/teampage.php b/phpBB/includes/db/migration/data/310/teampage.php
new file mode 100644
index 0000000000..4e77da17b7
--- /dev/null
+++ b/phpBB/includes/db/migration/data/310/teampage.php
@@ -0,0 +1,104 @@
+<?php
+/**
+*
+* @package migration
+* @copyright (c) 2012 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License v2
+*
+*/
+
+class phpbb_db_migration_data_310_teampage extends phpbb_db_migration
+{
+ public function effectively_installed()
+ {
+ return $this->db_tools->sql_table_exists($this->table_prefix . 'teampage');
+ }
+
+ static public function depends_on()
+ {
+ return array('phpbb_db_migration_data_310_dev');
+ }
+
+ public function update_schema()
+ {
+ return array(
+ 'add_tables' => array(
+ $this->table_prefix . 'teampage' => array(
+ 'COLUMNS' => array(
+ 'teampage_id' => array('UINT', NULL, 'auto_increment'),
+ 'group_id' => array('UINT', 0),
+ 'teampage_name' => array('VCHAR_UNI:255', ''),
+ 'teampage_position' => array('UINT', 0),
+ 'teampage_parent' => array('UINT', 0),
+ ),
+ 'PRIMARY_KEY' => 'teampage_id',
+ ),
+ ),
+ 'drop_columns' => array(
+ $this->table_prefix . 'groups' => array(
+ 'group_teampage',
+ ),
+ ),
+ );
+ }
+
+ public function revert_schema()
+ {
+ return array(
+ 'drop_tables' => array(
+ $this->table_prefix . 'teampage',
+ ),
+ 'add_columns' => array(
+ $this->table_prefix . 'groups' => array(
+ 'group_teampage' => array('UINT', 0, 'after' => 'group_legend'),
+ ),
+ ),
+ );
+ }
+
+ public function update_data()
+ {
+ return array(
+ array('custom', array(array($this, 'add_groups_teampage'))),
+ );
+ }
+
+ public function add_groups_teampage()
+ {
+ $sql = 'SELECT teampage_id
+ FROM ' . TEAMPAGE_TABLE;
+ $result = $this->db->sql_query_limit($sql, 1);
+ $added_groups_teampage = (bool) $this->db->sql_fetchfield('teampage_id');
+ $this->db->sql_freeresult($result);
+
+ if (!$added_groups_teampage)
+ {
+ $sql = 'SELECT *
+ FROM ' . GROUPS_TABLE . '
+ WHERE group_type = ' . GROUP_SPECIAL . "
+ AND (group_name = 'ADMINISTRATORS'
+ OR group_name = 'GLOBAL_MODERATORS')
+ ORDER BY group_name ASC";
+ $result = $this->db->sql_query($sql);
+
+ $teampage_entries = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $teampage_entries[] = array(
+ 'group_id' => (int) $row['group_id'],
+ 'teampage_name' => '',
+ 'teampage_position' => sizeof($teampage_entries) + 1,
+ 'teampage_parent' => 0,
+ );
+ }
+ $this->db->sql_freeresult($result);
+
+ if (sizeof($teampage_entries))
+ {
+ $this->db->sql_multi_insert(TEAMPAGE_TABLE, $teampage_entries);
+ }
+ unset($teampage_entries);
+ }
+
+ }
+}
diff --git a/phpBB/includes/db/migration/tool/config.php b/phpBB/includes/db/migration/tool/config.php
index 458a25fb66..0b626bf455 100644
--- a/phpBB/includes/db/migration/tool/config.php
+++ b/phpBB/includes/db/migration/tool/config.php
@@ -49,7 +49,7 @@ class phpbb_db_migration_tool_config implements phpbb_db_migration_tool_interfac
{
if (isset($this->config[$config_name]))
{
- throw new phpbb_db_migration_exception('CONFIG_ALREADY_EXIST', $config_name);
+ return;
}
$this->config->set($config_name, $config_value, !$is_dynamic);
@@ -105,7 +105,7 @@ class phpbb_db_migration_tool_config implements phpbb_db_migration_tool_interfac
{
if (!isset($this->config[$config_name]))
{
- throw new phpbb_db_migration_exception('CONFIG_NOT_EXIST', $config_name);
+ return;
}
$this->config->delete($config_name);
diff --git a/phpBB/includes/db/migration/tool/module.php b/phpBB/includes/db/migration/tool/module.php
index 3ba82d8a0f..ac4d2c9bd7 100644
--- a/phpBB/includes/db/migration/tool/module.php
+++ b/phpBB/includes/db/migration/tool/module.php
@@ -233,7 +233,7 @@ class phpbb_db_migration_tool_module implements phpbb_db_migration_tool_interfac
if ($this->exists($class, $parent, $data['module_langname']))
{
- throw new phpbb_db_migration_exception('MODULE_ALREADY_EXIST', $data['module_langname']);
+ return;
}
if (!class_exists('acp_modules'))
@@ -368,7 +368,7 @@ class phpbb_db_migration_tool_module implements phpbb_db_migration_tool_interfac
{
if (!$this->exists($class, $parent, $module))
{
- throw new phpbb_db_migration_exception('MODULE_NOT_EXIST', ((isset($this->user->lang[$module])) ? $this->user->lang[$module] : $module));
+ return;
}
$parent_sql = '';
@@ -441,7 +441,7 @@ class phpbb_db_migration_tool_module implements phpbb_db_migration_tool_interfac
$result = $acp_modules->delete_module($module_id);
if (!empty($result))
{
- throw new phpbb_db_migration_exception('MODULE_NOT_REMOVABLE', $module_id, $result);
+ return;
}
}
@@ -491,7 +491,7 @@ class phpbb_db_migration_tool_module implements phpbb_db_migration_tool_interfac
$acp_modules = new acp_modules();
$module = $acp_modules->get_module_infos($basename, $class, true);
- if (empty($module));
+ if (empty($module))
{
throw new phpbb_db_migration_exception('MODULE_INFO_FILE_NOT_EXIST', $class, $basename);
}
diff --git a/phpBB/includes/db/migration/tool/permission.php b/phpBB/includes/db/migration/tool/permission.php
index 4231fbe1dd..2f09c0ac72 100644
--- a/phpBB/includes/db/migration/tool/permission.php
+++ b/phpBB/includes/db/migration/tool/permission.php
@@ -107,7 +107,7 @@ class phpbb_db_migration_tool_permission implements phpbb_db_migration_tool_inte
{
if ($this->exists($auth_option, $global))
{
- throw new phpbb_db_migration_exception('PERMISSION_ALREADY_EXIST', $auth_option);
+ return;
}
// We've added permissions, so set to true to notify the user.
@@ -190,7 +190,7 @@ class phpbb_db_migration_tool_permission implements phpbb_db_migration_tool_inte
{
if (!$this->exists($auth_option, $global))
{
- throw new phpbb_db_migration_exception('PERMISSION_NOT_EXIST', $auth_option);
+ return;
}
if ($global)
@@ -315,7 +315,7 @@ class phpbb_db_migration_tool_permission implements phpbb_db_migration_tool_inte
if (!$role_id)
{
- throw new phpbb_db_migration_exception('ROLE_NOT_EXIST', $role_name);
+ return;
}
$sql = 'DELETE FROM ' . ACL_ROLES_DATA_TABLE . '
@@ -422,7 +422,7 @@ class phpbb_db_migration_tool_permission implements phpbb_db_migration_tool_inte
$this->db->sql_query($sql);
$role_name = $this->db->sql_fetchfield('role_name');
- return $this->set($role_name, $auth_option, 'role', $has_permission);
+ return $this->permission_set($role_name, $auth_option, 'role', $has_permission);
}
$sql = 'SELECT auth_option_id, auth_setting
diff --git a/phpBB/includes/db/migrator.php b/phpBB/includes/db/migrator.php
index ec0b6a87da..ca3ffc8043 100644
--- a/phpBB/includes/db/migrator.php
+++ b/phpBB/includes/db/migrator.php
@@ -60,7 +60,9 @@ class phpbb_db_migrator
protected $migrations = array();
/**
- * 'name' and 'class' of the last migration run
+ * 'name,' 'class,' and 'state' of the last migration run
+ *
+ * 'effectively_installed' set and set to true if the migration was effectively_installed
*
* @var array
*/
@@ -133,121 +135,6 @@ class phpbb_db_migrator
}
/**
- * This function adds all migrations in a specified directory to the migrations table
- *
- * THIS SHOULD NOT GENERALLY BE USED! THIS IS FOR THE PHPBB INSTALLER.
- * THIS WILL THROW ERRORS IF MIGRATIONS ALREADY EXIST IN THE TABLE, DO NOT CALL MORE THAN ONCE!
- *
- * @param string $path Path to migration data files
- * @param bool $recursive Set to true to also load data files from subdirectories
- * @return null
- */
- public function populate_migrations_from_directory($path, $recursive = true)
- {
- $existing_migrations = $this->migrations;
-
- $this->migrations = array();
- $this->load_migrations($path, true, $recursive);
-
- foreach ($this->migrations as $name)
- {
- if ($this->migration_state($name) === false)
- {
- $state = array(
- 'migration_depends_on' => $name::depends_on(),
- 'migration_schema_done' => true,
- 'migration_data_done' => true,
- 'migration_data_state' => '',
- 'migration_start_time' => time(),
- 'migration_end_time' => time(),
- );
- $this->insert_migration($name, $state);
- }
- }
-
- $this->migrations = $existing_migrations;
- }
-
- /**
- * Load migration data files from a directory
- *
- * Migration data files loaded with this function MUST contain
- * ONLY ONE class in them (or an exception will be thrown).
- *
- * @param string $path Path to migration data files
- * @param bool $check_fulfillable If TRUE (default), we will check
- * if all of the migrations are fulfillable after loading them.
- * If FALSE, we will not check. You SHOULD check at least once
- * to prevent errors (if including multiple directories, check
- * with the last call to prevent throwing errors unnecessarily).
- * @param bool $recursive Set to true to also load data files from subdirectories
- * @return array Array of migration names
- */
- public function load_migrations($path, $check_fulfillable = true, $recursive = true)
- {
- if (!is_dir($path))
- {
- throw new phpbb_db_migration_exception('DIRECTORY INVALID', $path);
- }
-
- $handle = opendir($path);
- while (($file = readdir($handle)) !== false)
- {
- if ($file == '.' || $file == '..')
- {
- continue;
- }
-
- // Recursion through subdirectories
- if (is_dir($path . $file) && $recursive)
- {
- $this->load_migrations($path . $file . '/', $check_fulfillable, $recursive);
- }
-
- if (strpos($file, '_') !== 0 && strrpos($file, '.' . $this->php_ext) === (strlen($file) - strlen($this->php_ext) - 1))
- {
- // We try to find what class existed by comparing the classes declared before and after including the file.
- $declared_classes = get_declared_classes();
-
- include ($path . $file);
-
- $added_classes = array_diff(get_declared_classes(), $declared_classes);
-
- if (
- // If two classes have been added and phpbb_db_migration is one of them, we've only added one real migration
- !(sizeof($added_classes) == 2 && in_array('phpbb_db_migration', $added_classes)) &&
- // Otherwise there should only be one class added
- sizeof($added_classes) != 1
- )
- {
- throw new phpbb_db_migration_exception('MIGRATION DATA FILE INVALID', $path . $file);
- }
-
- $name = array_pop($added_classes);
-
- if (!in_array($name, $this->migrations))
- {
- $this->migrations[] = $name;
- }
- }
- }
-
- if ($check_fulfillable)
- {
- foreach ($this->migrations as $name)
- {
- $unfulfillable = $this->unfulfillable($name);
- if ($unfulfillable !== false)
- {
- throw new phpbb_db_migration_exception('MIGRATION_NOT_FULFILLABLE', $name, $unfulfillable);
- }
- }
- }
-
- return $this->migrations;
- }
-
- /**
* Runs a single update step from the next migration to be applied.
*
* The update step can either be a schema or a (partial) data update. To
@@ -314,6 +201,7 @@ class phpbb_db_migrator
$this->last_run_migration = array(
'name' => $name,
'class' => $migration,
+ 'state' => $state,
);
if (!isset($this->migration_state[$name]))
@@ -328,6 +216,8 @@ class phpbb_db_migrator
'migration_start_time' => 0,
'migration_end_time' => 0,
);
+
+ $this->last_run_migration['effectively_installed'] = true;
}
else
{
@@ -360,7 +250,7 @@ class phpbb_db_migrator
}
}
- $this->insert_migration($name, $state);
+ $this->set_migration_state($name, $state);
return true;
}
@@ -432,7 +322,7 @@ class phpbb_db_migrator
$state['migration_data_done'] = ($result === true) ? false : true;
}
- $this->insert_migration($name, $state);
+ $this->set_migration_state($name, $state);
}
else
{
@@ -472,6 +362,12 @@ class phpbb_db_migrator
{
$state = ($state) ? unserialize($state) : false;
+ // reverse order of steps if reverting
+ if ($revert === true)
+ {
+ $steps = array_reverse($steps);
+ }
+
foreach ($steps as $step_identifier => $step)
{
$last_result = false;
@@ -651,7 +547,7 @@ class phpbb_db_migrator
* @param array $state
* @return null
*/
- protected function insert_migration($name, $state)
+ protected function set_migration_state($name, $state)
{
$migration_row = $state;
$migration_row['migration_depends_on'] = serialize($state['migration_depends_on']);
@@ -672,6 +568,8 @@ class phpbb_db_migrator
}
$this->migration_state[$name] = $state;
+
+ $this->last_run_migration['state'] = $state;
}
/**
@@ -764,4 +662,85 @@ class phpbb_db_migrator
{
return new $name($this->config, $this->db, $this->db_tools, $this->phpbb_root_path, $this->php_ext, $this->table_prefix);
}
+
+ /**
+ * This function adds all migrations sent to it to the migrations table
+ *
+ * THIS SHOULD NOT GENERALLY BE USED! THIS IS FOR THE PHPBB INSTALLER.
+ * THIS WILL THROW ERRORS IF MIGRATIONS ALREADY EXIST IN THE TABLE, DO NOT CALL MORE THAN ONCE!
+ *
+ * @param array $migrations Array of migrations (names) to add to the migrations table
+ * @return null
+ */
+ public function populate_migrations($migrations)
+ {
+ foreach ($migrations as $name)
+ {
+ if ($this->migration_state($name) === false)
+ {
+ $state = array(
+ 'migration_depends_on' => $name::depends_on(),
+ 'migration_schema_done' => true,
+ 'migration_data_done' => true,
+ 'migration_data_state' => '',
+ 'migration_start_time' => time(),
+ 'migration_end_time' => time(),
+ );
+ $this->set_migration_state($name, $state);
+ }
+ }
+ }
+
+ /**
+ * Load migration data files from a directory
+ *
+ * @param phpbb_extension_finder $finder
+ * @param string $path Path to migration data files
+ * @param bool $check_fulfillable If TRUE (default), we will check
+ * if all of the migrations are fulfillable after loading them.
+ * If FALSE, we will not check. You SHOULD check at least once
+ * to prevent errors (if including multiple directories, check
+ * with the last call to prevent throwing errors unnecessarily).
+ * @return array Array of migration names
+ */
+ public function load_migrations(phpbb_extension_finder $finder, $path, $check_fulfillable = true)
+ {
+ if (!is_dir($path))
+ {
+ throw new phpbb_db_migration_exception('DIRECTORY INVALID', $path);
+ }
+
+ $migrations = array();
+
+ $files = $finder
+ ->extension_directory("/")
+ ->find_from_paths(array('/' => $path));
+ foreach ($files as $file)
+ {
+ $migrations[$file['path'] . $file['filename']] = '';
+ }
+ $migrations = $finder->get_classes_from_files($migrations);
+
+ foreach ($migrations as $migration)
+ {
+ if (!in_array($migration, $this->migrations))
+ {
+ $this->migrations[] = $migration;
+ }
+ }
+
+ if ($check_fulfillable)
+ {
+ foreach ($this->migrations as $name)
+ {
+ $unfulfillable = $this->unfulfillable($name);
+ if ($unfulfillable !== false)
+ {
+ throw new phpbb_db_migration_exception('MIGRATION_NOT_FULFILLABLE', $name, $unfulfillable);
+ }
+ }
+ }
+
+ return $this->migrations;
+ }
}
diff --git a/phpBB/includes/db/sql_insert_buffer.php b/phpBB/includes/db/sql_insert_buffer.php
new file mode 100644
index 0000000000..c18f908429
--- /dev/null
+++ b/phpBB/includes/db/sql_insert_buffer.php
@@ -0,0 +1,150 @@
+<?php
+/**
+*
+* @package dbal
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Collects rows for insert into a database until the buffer size is reached.
+* Then flushes the buffer to the database and starts over again.
+*
+* Benefits over collecting a (possibly huge) insert array and then using
+* $db->sql_multi_insert() include:
+*
+* - Going over max packet size of the database connection is usually prevented
+* because the data is submitted in batches.
+*
+* - Reaching database connection timeout is usually prevented because
+* submission of batches talks to the database every now and then.
+*
+* - Usage of less PHP memory because data no longer needed is discarded on
+* buffer flush.
+*
+* Attention:
+* Please note that users of this class have to call flush() to flush the
+* remaining rows to the database after their batch insert operation is
+* finished.
+*
+* Usage:
+* <code>
+* $buffer = new phpbb_db_sql_insert_buffer($db, 'test_table', 1234);
+*
+* while (do_stuff())
+* {
+* $buffer->insert(array(
+* 'column1' => 'value1',
+* 'column2' => 'value2',
+* ));
+* }
+*
+* $buffer->flush();
+* </code>
+*
+* @package dbal
+*/
+class phpbb_db_sql_insert_buffer
+{
+ /** @var phpbb_db_driver */
+ protected $db;
+
+ /** @var string */
+ protected $table_name;
+
+ /** @var int */
+ protected $max_buffered_rows;
+
+ /** @var array */
+ protected $buffer = array();
+
+ /**
+ * @param phpbb_db_driver $db
+ * @param string $table_name
+ * @param int $max_buffered_rows
+ */
+ public function __construct(phpbb_db_driver $db, $table_name, $max_buffered_rows = 500)
+ {
+ $this->db = $db;
+ $this->table_name = $table_name;
+ $this->max_buffered_rows = $max_buffered_rows;
+ }
+
+ /**
+ * Inserts a single row into the buffer if multi insert is supported by the
+ * database (otherwise an insert query is sent immediately). Then flushes
+ * the buffer if the number of rows in the buffer is now greater than or
+ * equal to $max_buffered_rows.
+ *
+ * @param array $row
+ *
+ * @return bool True when some data was flushed to the database.
+ * False otherwise.
+ */
+ public function insert(array $row)
+ {
+ $this->buffer[] = $row;
+
+ // Flush buffer if it is full or when DB does not support multi inserts.
+ // In the later case, the buffer will always only contain one row.
+ if (!$this->db->multi_insert || sizeof($this->buffer) >= $this->max_buffered_rows)
+ {
+ return $this->flush();
+ }
+
+ return false;
+ }
+
+ /**
+ * Inserts a row set, i.e. an array of rows, by calling insert().
+ *
+ * Please note that it is in most cases better to use insert() instead of
+ * first building a huge rowset. Or at least sizeof($rows) should be kept
+ * small.
+ *
+ * @param array $rows
+ *
+ * @return bool True when some data was flushed to the database.
+ * False otherwise.
+ */
+ public function insert_all(array $rows)
+ {
+ // Using bitwise |= because PHP does not have logical ||=
+ $result = 0;
+
+ foreach ($rows as $row)
+ {
+ $result |= (int) $this->insert($row);
+ }
+
+ return (bool) $result;
+ }
+
+ /**
+ * Flushes the buffer content to the DB and clears the buffer.
+ *
+ * @return bool True when some data was flushed to the database.
+ * False otherwise.
+ */
+ public function flush()
+ {
+ if (!empty($this->buffer))
+ {
+ $this->db->sql_multi_insert($this->table_name, $this->buffer);
+ $this->buffer = array();
+
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/phpBB/includes/extension/base.php b/phpBB/includes/extension/base.php
index d51589d719..c4462b64d8 100644
--- a/phpBB/includes/extension/base.php
+++ b/phpBB/includes/extension/base.php
@@ -27,25 +27,51 @@ class phpbb_extension_base implements phpbb_extension_interface
/** @var ContainerInterface */
protected $container;
+ /** @var phpbb_extension_finder */
+ protected $finder;
+
+ /** @var phpbb_db_migrator */
+ protected $migrator;
+
+ /** @var string */
+ protected $extension_name;
+
+ /** @var string */
+ protected $extension_path;
+
/**
* Constructor
*
* @param ContainerInterface $container Container object
+ * @param phpbb_extension_finder $extension_finder
+ * @param string $extension_name Name of this extension (from ext.manager)
+ * @param string $extension_path Relative path to this extension
*/
- public function __construct(ContainerInterface $container)
+ public function __construct(ContainerInterface $container, phpbb_extension_finder $extension_finder, phpbb_db_migrator $migrator, $extension_name, $extension_path)
{
$this->container = $container;
+ $this->extension_finder = $extension_finder;
+ $this->migrator = $migrator;
+
+ $this->extension_name = $extension_name;
+ $this->extension_path = $extension_path;
}
/**
- * Single enable step that does nothing
+ * Single enable step that installs any included migrations
*
* @param mixed $old_state State returned by previous call of this method
* @return false Indicates no further steps are required
*/
public function enable_step($old_state)
{
- return false;
+ $migrations = $this->get_migration_file_list();
+
+ $this->migrator->set_migrations($migrations);
+
+ $this->migrator->update();
+
+ return !$this->migrator->finished();
}
/**
@@ -60,13 +86,50 @@ class phpbb_extension_base implements phpbb_extension_interface
}
/**
- * Single purge step that does nothing
+ * Single purge step that reverts any included and installed migrations
*
* @param mixed $old_state State returned by previous call of this method
* @return false Indicates no further steps are required
*/
public function purge_step($old_state)
{
+ $migrations = $this->get_migration_file_list();
+
+ $this->migrator->set_migrations($migrations);
+
+ foreach ($migrations as $migration)
+ {
+ while ($this->migrator->migration_state($migration) !== false)
+ {
+ $this->migrator->revert($migration);
+
+ return true;
+ }
+ }
+
return false;
}
+
+ /**
+ * Get the list of migration files from this extension
+ *
+ * @return array
+ */
+ protected function get_migration_file_list()
+ {
+ static $migrations = false;
+
+ if ($migrations !== false)
+ {
+ return $migrations;
+ }
+
+ // Only have the finder search in this extension path directory
+ $migrations = $this->extension_finder
+ ->extension_directory('/migrations')
+ ->find_from_extension($this->extension_name, $this->extension_path);
+ $migrations = $this->extension_finder->get_classes_from_files($migrations);
+
+ return $migrations;
+ }
}
diff --git a/phpBB/includes/extension/finder.php b/phpBB/includes/extension/finder.php
index af31478337..49bb2a514f 100644
--- a/phpBB/includes/extension/finder.php
+++ b/phpBB/includes/extension/finder.php
@@ -23,6 +23,7 @@ if (!defined('IN_PHPBB'))
class phpbb_extension_finder
{
protected $extension_manager;
+ protected $filesystem;
protected $phpbb_root_path;
protected $cache;
protected $php_ext;
@@ -54,15 +55,17 @@ class phpbb_extension_finder
* @param phpbb_extension_manager $extension_manager An extension manager
* instance that provides the finder with a list of active
* extensions and their locations
+ * @param phpbb_filesystem $filesystem Filesystem instance
* @param string $phpbb_root_path Path to the phpbb root directory
* @param phpbb_cache_driver_interface $cache A cache instance or null
* @param string $php_ext php file extension
* @param string $cache_name The name of the cache variable, defaults to
* _ext_finder
*/
- public function __construct(phpbb_extension_manager $extension_manager, $phpbb_root_path = '', phpbb_cache_driver_interface $cache = null, $php_ext = '.php', $cache_name = '_ext_finder')
+ public function __construct(phpbb_extension_manager $extension_manager, phpbb_filesystem $filesystem, $phpbb_root_path = '', phpbb_cache_driver_interface $cache = null, $php_ext = 'php', $cache_name = '_ext_finder')
{
$this->extension_manager = $extension_manager;
+ $this->filesystem = $filesystem;
$this->phpbb_root_path = $phpbb_root_path;
$this->cache = $cache;
$this->php_ext = $php_ext;
@@ -227,7 +230,7 @@ class phpbb_extension_finder
*/
protected function sanitise_directory($directory)
{
- $directory = preg_replace('#(?:^|/)\./#', '/', $directory);
+ $directory = $this->filesystem->clean_path($directory);
$dir_len = strlen($directory);
if ($dir_len > 1 && $directory[$dir_len - 1] === '/')
@@ -253,17 +256,28 @@ class phpbb_extension_finder
*/
public function get_classes($cache = true, $use_all_available = false)
{
- $this->query['extension_suffix'] .= $this->php_ext;
- $this->query['core_suffix'] .= $this->php_ext;
+ $this->query['extension_suffix'] .= '.' . $this->php_ext;
+ $this->query['core_suffix'] .= '.' . $this->php_ext;
$files = $this->find($cache, false, $use_all_available);
+ return $this->get_classes_from_files($files);
+ }
+
+ /**
+ * Get class names from a list of files
+ *
+ * @param array $files Array of files (from find())
+ * @return array Array of class names
+ */
+ public function get_classes_from_files($files)
+ {
$classes = array();
foreach ($files as $file => $ext_name)
{
$file = preg_replace('#^includes/#', '', $file);
- $classes[] = 'phpbb_' . str_replace('/', '_', substr($file, 0, -strlen($this->php_ext)));
+ $classes[] = 'phpbb_' . str_replace('/', '_', substr($file, 0, -strlen('.' . $this->php_ext)));
}
return $classes;
}
@@ -339,16 +353,6 @@ class phpbb_extension_finder
*/
public function find($cache = true, $is_dir = false, $use_all_available = false)
{
- $this->query['is_dir'] = $is_dir;
- $query = md5(serialize($this->query));
-
- if (!defined('DEBUG') && $cache && isset($this->cached_queries[$query]))
- {
- return $this->cached_queries[$query];
- }
-
- $files = array();
-
if ($use_all_available)
{
$extensions = $this->extension_manager->all_available();
@@ -363,6 +367,67 @@ class phpbb_extension_finder
$extensions['/'] = $this->phpbb_root_path . $this->query['core_path'];
}
+ $files = array();
+ $file_list = $this->find_from_paths($extensions, $cache, $is_dir);
+
+ foreach ($file_list as $file)
+ {
+ $files[$file['named_path']] = $file['ext_name'];
+ }
+
+ return $files;
+ }
+
+ /**
+ * Finds all file system entries matching the configured options for one
+ * specific extension
+ *
+ * @param string $extension_name Name of the extension
+ * @param string $extension_path Relative path to the extension root directory
+ * @param bool $cache Whether the result should be cached
+ * @param bool $is_dir Directories will be returned when true, only files
+ * otherwise
+ * @return array An array of paths to found items
+ */
+ public function find_from_extension($extension_name, $extension_path, $cache = true, $is_dir = false)
+ {
+ $extensions = array(
+ $extension_name => $extension_path,
+ );
+
+ $files = array();
+ $file_list = $this->find_from_paths($extensions, $cache, $is_dir);
+
+ foreach ($file_list as $file)
+ {
+ $files[$file['named_path']] = $file['ext_name'];
+ }
+
+ return $files;
+ }
+
+ /**
+ * Finds all file system entries matching the configured options from
+ * an array of paths
+ *
+ * @param array $extensions Array of extensions (name => full relative path)
+ * @param bool $cache Whether the result should be cached
+ * @param bool $is_dir Directories will be returned when true, only files
+ * otherwise
+ * @return array An array of paths to found items
+ */
+ public function find_from_paths($extensions, $cache = true, $is_dir = false)
+ {
+ $this->query['is_dir'] = $is_dir;
+ $query = md5(serialize($this->query) . serialize($extensions));
+
+ if (!defined('DEBUG') && $cache && isset($this->cached_queries[$query]))
+ {
+ return $this->cached_queries[$query];
+ }
+
+ $files = array();
+
foreach ($extensions as $name => $path)
{
$ext_name = $name;
@@ -436,7 +501,12 @@ class phpbb_extension_finder
(!$prefix || substr($filename, 0, strlen($prefix)) === $prefix) &&
(!$directory || preg_match($directory_pattern, $relative_path)))
{
- $files[str_replace(DIRECTORY_SEPARATOR, '/', $location . $name . substr($relative_path, 1))] = $ext_name;
+ $files[] = array(
+ 'named_path' => str_replace(DIRECTORY_SEPARATOR, '/', $location . $name . substr($relative_path, 1)),
+ 'ext_name' => $ext_name,
+ 'path' => str_replace(array(DIRECTORY_SEPARATOR, $this->phpbb_root_path), array('/', ''), $file_info->getPath()) . '/',
+ 'filename' => $filename,
+ );
}
}
}
diff --git a/phpBB/includes/extension/manager.php b/phpBB/includes/extension/manager.php
index 21a9ec1370..4451049d04 100644
--- a/phpBB/includes/extension/manager.php
+++ b/phpBB/includes/extension/manager.php
@@ -29,7 +29,6 @@ class phpbb_extension_manager
protected $db;
protected $config;
- protected $migrator;
protected $cache;
protected $php_ext;
protected $extensions;
@@ -43,20 +42,21 @@ class phpbb_extension_manager
* @param ContainerInterface $container A container
* @param phpbb_db_driver $db A database connection
* @param phpbb_config $config phpbb_config
+ * @param phpbb_filesystem $filesystem
* @param string $extension_table The name of the table holding extensions
* @param string $phpbb_root_path Path to the phpbb includes directory.
* @param string $php_ext php file extension
* @param phpbb_cache_driver_interface $cache A cache instance or null
* @param string $cache_name The name of the cache variable, defaults to _ext
*/
- public function __construct(ContainerInterface $container, phpbb_db_driver $db, phpbb_config $config, phpbb_db_migrator $migrator, $extension_table, $phpbb_root_path, $php_ext = '.php', phpbb_cache_driver_interface $cache = null, $cache_name = '_ext')
+ public function __construct(ContainerInterface $container, phpbb_db_driver $db, phpbb_config $config, phpbb_filesystem $filesystem, $extension_table, $phpbb_root_path, $php_ext = 'php', phpbb_cache_driver_interface $cache = null, $cache_name = '_ext')
{
$this->container = $container;
$this->phpbb_root_path = $phpbb_root_path;
$this->db = $db;
$this->config = $config;
- $this->migrator = $migrator;
$this->cache = $cache;
+ $this->filesystem = $filesystem;
$this->php_ext = $php_ext;
$this->extension_table = $extension_table;
$this->cache_name = $cache_name;
@@ -133,13 +133,15 @@ class phpbb_extension_manager
{
$extension_class_name = 'phpbb_ext_' . str_replace('/', '_', $name) . '_ext';
+ $migrator = $this->container->get('migrator');
+
if (class_exists($extension_class_name))
{
- return new $extension_class_name($this->container);
+ return new $extension_class_name($this->container, $this->get_finder(), $migrator, $name, $this->get_extension_path($name, true));
}
else
{
- return new phpbb_extension_base($this->container);
+ return new phpbb_extension_base($this->container, $this->get_finder(), $migrator, $name, $this->get_extension_path($name, true));
}
}
@@ -152,7 +154,7 @@ class phpbb_extension_manager
*/
public function create_extension_metadata_manager($name, phpbb_template $template)
{
- return new phpbb_extension_metadata_manager($name, $this->db, $this, $this->phpbb_root_path, $this->php_ext, $template, $this->config);
+ return new phpbb_extension_metadata_manager($name, $this->config, $this, $template, $this->phpbb_root_path);
}
/**
@@ -175,12 +177,6 @@ class phpbb_extension_manager
$old_state = (isset($this->extensions[$name]['ext_state'])) ? unserialize($this->extensions[$name]['ext_state']) : false;
- // Returns false if not completed
- if (!$this->handle_migrations($name, 'enable'))
- {
- return true;
- }
-
$extension = $this->get_extension($name);
$state = $extension->enable_step($old_state);
@@ -196,12 +192,21 @@ class phpbb_extension_manager
$this->extensions[$name]['ext_path'] = $this->get_extension_path($extension_data['ext_name']);
ksort($this->extensions);
- $sql = 'UPDATE ' . $this->extension_table . '
- SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . "
+ $sql = 'SELECT COUNT(ext_name) as row_count
+ FROM ' . $this->extension_table . "
WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
- $this->db->sql_query($sql);
+ $result = $this->db->sql_query($sql);
+ $count = $this->db->sql_fetchfield('row_count');
+ $this->db->sql_freeresult($result);
- if (!$this->db->sql_affectedrows())
+ if ($count)
+ {
+ $sql = 'UPDATE ' . $this->extension_table . '
+ SET ' . $this->db->sql_build_array('UPDATE', $extension_data) . "
+ WHERE ext_name = '" . $this->db->sql_escape($name) . "'";
+ $this->db->sql_query($sql);
+ }
+ else
{
$sql = 'INSERT INTO ' . $this->extension_table . '
' . $this->db->sql_build_array('INSERT', $extension_data);
@@ -332,12 +337,6 @@ class phpbb_extension_manager
$old_state = unserialize($this->extensions[$name]['ext_state']);
- // Returns false if not completed
- if (!$this->handle_migrations($name, 'purge'))
- {
- return true;
- }
-
$extension = $this->get_extension($name);
$state = $extension->purge_step($old_state);
@@ -409,7 +408,7 @@ class phpbb_extension_manager
RecursiveIteratorIterator::SELF_FIRST);
foreach ($iterator as $file_info)
{
- if ($file_info->isFile() && $file_info->getFilename() == 'ext' . $this->php_ext)
+ if ($file_info->isFile() && $file_info->getFilename() == 'ext.' . $this->php_ext)
{
$ext_name = $iterator->getInnerIterator()->getSubPath();
@@ -509,60 +508,6 @@ class phpbb_extension_manager
*/
public function get_finder()
{
- return new phpbb_extension_finder($this, $this->phpbb_root_path, $this->cache, $this->php_ext, $this->cache_name . '_finder');
- }
-
- /**
- * Handle installing/reverting migrations
- *
- * @param string $extension_name Name of the extension
- * @param string $mode enable or purge
- * @return bool True if completed, False if not completed
- */
- protected function handle_migrations($extension_name, $mode)
- {
- $migrations_path = $this->phpbb_root_path . $this->get_extension_path($extension_name) . 'migrations/';
- if (!file_exists($migrations_path) || !is_dir($migrations_path))
- {
- return true;
- }
-
- $migrations = $this->migrator->load_migrations($migrations_path);
-
- // What is a safe limit of execution time? Half the max execution time should be safe.
- $safe_time_limit = (ini_get('max_execution_time') / 2);
- $start_time = time();
-
- if ($mode == 'enable')
- {
- while (!$this->migrator->finished())
- {
- $this->migrator->update();
-
- // Are we approaching the time limit? If so we want to pause the update and continue after refreshing
- if ((time() - $start_time) >= $safe_time_limit)
- {
- return false;
- }
- }
- }
- else if ($mode == 'purge')
- {
- foreach ($migrations as $migration)
- {
- while ($this->migrator->migration_state($migration) !== false)
- {
- $this->migrator->revert($migration);
-
- // Are we approaching the time limit? If so we want to pause the update and continue after refreshing
- if ((time() - $start_time) >= $safe_time_limit)
- {
- return false;
- }
- }
- }
- }
-
- return true;
+ return new phpbb_extension_finder($this, $this->filesystem, $this->phpbb_root_path, $this->cache, $this->php_ext, $this->cache_name . '_finder');
}
}
diff --git a/phpBB/includes/extension/metadata_manager.php b/phpBB/includes/extension/metadata_manager.php
index 36b0f8b184..14b77c085b 100644
--- a/phpBB/includes/extension/metadata_manager.php
+++ b/phpBB/includes/extension/metadata_manager.php
@@ -22,31 +22,64 @@ if (!defined('IN_PHPBB'))
*/
class phpbb_extension_metadata_manager
{
- protected $phpEx;
+ /**
+ * phpBB Config instance
+ * @var phpbb_config
+ */
+ protected $config;
+
+ /**
+ * phpBB Extension Manager
+ * @var phpbb_extension_manager
+ */
protected $extension_manager;
- protected $db;
- protected $phpbb_root_path;
+
+ /**
+ * phpBB Template instance
+ * @var phpbb_template
+ */
protected $template;
+
+ /**
+ * phpBB root path
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Name (including vendor) of the extension
+ * @var string
+ */
protected $ext_name;
+
+ /**
+ * Metadata from the composer.json file
+ * @var array
+ */
protected $metadata;
+
+ /**
+ * Link (including root path) to the metadata file
+ * @var string
+ */
protected $metadata_file;
/**
* Creates the metadata manager
*
- * @param phpbb_db_driver $db A database connection
- * @param string $extension_manager An instance of the phpbb extension manager
- * @param string $phpbb_root_path Path to the phpbb includes directory.
- * @param string $phpEx php file extension
+ * @param string $ext_name Name (including vendor) of the extension
+ * @param phpbb_config $config phpBB Config instance
+ * @param phpbb_extension_manager $extension_manager An instance of the phpBBb extension manager
+ * @param phpbb_template $template phpBB Template instance
+ * @param string $phpbb_root_path Path to the phpbb includes directory.
*/
- public function __construct($ext_name, phpbb_db_driver $db, phpbb_extension_manager $extension_manager, $phpbb_root_path, $phpEx = '.php', phpbb_template $template, phpbb_config $config)
+ public function __construct($ext_name, phpbb_config $config, phpbb_extension_manager $extension_manager, phpbb_template $template, $phpbb_root_path)
{
- $this->phpbb_root_path = $phpbb_root_path;
- $this->db = $db;
$this->config = $config;
- $this->phpEx = $phpEx;
- $this->template = $template;
$this->extension_manager = $extension_manager;
+ $this->template = $template;
+ $this->phpbb_root_path = $phpbb_root_path;
+
$this->ext_name = $ext_name;
$this->metadata = array();
$this->metadata_file = '';
diff --git a/phpBB/includes/filesystem.php b/phpBB/includes/filesystem.php
new file mode 100644
index 0000000000..27cab48fb0
--- /dev/null
+++ b/phpBB/includes/filesystem.php
@@ -0,0 +1,52 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* A class with various functions that are related to paths, files and the filesystem
+* @package phpBB3
+*/
+class phpbb_filesystem
+{
+ /**
+ * Eliminates useless . and .. components from specified path.
+ *
+ * @param string $path Path to clean
+ * @return string Cleaned path
+ */
+ public function clean_path($path)
+ {
+ $exploded = explode('/', $path);
+ $filtered = array();
+ foreach ($exploded as $part)
+ {
+ if ($part === '.' && !empty($filtered))
+ {
+ continue;
+ }
+
+ if ($part === '..' && !empty($filtered) && $filtered[sizeof($filtered) - 1] !== '..')
+ {
+ array_pop($filtered);
+ }
+ else
+ {
+ $filtered[] = $part;
+ }
+ }
+ $path = implode('/', $filtered);
+ return $path;
+ }
+}
diff --git a/phpBB/includes/functions.php b/phpBB/includes/functions.php
index 6a1f144967..b087e1298b 100644
--- a/phpBB/includes/functions.php
+++ b/phpBB/includes/functions.php
@@ -846,7 +846,7 @@ function phpbb_is_writable($file)
*/
function phpbb_is_absolute($path)
{
- return ($path[0] == '/' || (DIRECTORY_SEPARATOR == '\\' && preg_match('#^[a-z]:[/\\\]#i', $path))) ? true : false;
+ return (isset($path[0]) && $path[0] == '/' || preg_match('#^[a-z]:[/\\\]#i', $path)) ? true : false;
}
/**
@@ -1049,31 +1049,33 @@ else
/**
* Eliminates useless . and .. components from specified path.
*
+* Deprecated, use filesystem class instead
+*
* @param string $path Path to clean
* @return string Cleaned path
+*
+* @deprecated
*/
function phpbb_clean_path($path)
{
- $exploded = explode('/', $path);
- $filtered = array();
- foreach ($exploded as $part)
- {
- if ($part === '.' && !empty($filtered))
- {
- continue;
- }
+ global $phpbb_container;
- if ($part === '..' && !empty($filtered) && $filtered[sizeof($filtered) - 1] !== '..')
- {
- array_pop($filtered);
- }
- else
+ if ($phpbb_container)
+ {
+ $phpbb_filesystem = $phpbb_container->get('filesystem');
+ }
+ else
+ {
+ // The container is not yet loaded, use a new instance
+ if (!class_exists('phpbb_filesystem'))
{
- $filtered[] = $part;
+ global $phpbb_root_path, $phpEx;
+ require($phpbb_root_path . 'includes/filesystem.' . $phpEx);
}
+ $phpbb_filesystem = new phpbb_filesystem();
}
- $path = implode('/', $filtered);
- return $path;
+
+ return $phpbb_filesystem->clean_path($path);
}
// functions used for building option fields
@@ -2731,7 +2733,7 @@ function redirect($url, $return = false, $disable_cd_check = false)
// Make sure no linebreaks are there... to prevent http response splitting for PHP < 4.4.2
if (strpos(urldecode($url), "\n") !== false || strpos(urldecode($url), "\r") !== false || strpos($url, ';') !== false)
{
- trigger_error('Tried to redirect to potentially insecure url.', E_USER_ERROR);
+ trigger_error('INSECURE_REDIRECT', E_USER_ERROR);
}
// Now, also check the protocol and for a valid url the last time...
@@ -2740,7 +2742,7 @@ function redirect($url, $return = false, $disable_cd_check = false)
if ($url_parts === false || empty($url_parts['scheme']) || !in_array($url_parts['scheme'], $allowed_protocols))
{
- trigger_error('Tried to redirect to potentially insecure url.', E_USER_ERROR);
+ trigger_error('INSECURE_REDIRECT', E_USER_ERROR);
}
if ($return)
@@ -2905,7 +2907,7 @@ function meta_refresh($time, $url, $disable_cd_check = false)
// For XHTML compatibility we change back & to &amp;
$template->assign_vars(array(
- 'META' => '<meta http-equiv="refresh" content="' . $time . ';url=' . $url . '" />')
+ 'META' => '<meta http-equiv="refresh" content="' . $time . '; url=' . $url . '" />')
);
}
@@ -3158,8 +3160,9 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo
'YES_VALUE' => $user->lang['YES'],
'S_CONFIRM_ACTION' => $u_action,
- 'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields)
- );
+ 'S_HIDDEN_FIELDS' => $hidden . $s_hidden_fields,
+ 'S_AJAX_REQUEST' => $request->is_ajax(),
+ ));
$sql = 'UPDATE ' . USERS_TABLE . " SET user_last_confirm_key = '" . $db->sql_escape($confirm_key) . "'
WHERE user_id = " . $user->data['user_id'];
@@ -3171,8 +3174,9 @@ function confirm_box($check, $title = '', $hidden = '', $html_body = 'confirm_bo
$u_action .= '&confirm_uid=' . $user->data['user_id'] . '&sess=' . $user->session_id . '&sid=' . $user->session_id;
$json_response = new phpbb_json_response;
$json_response->send(array(
+ 'MESSAGE_BODY' => $template->assign_display('body'),
'MESSAGE_TITLE' => (!isset($user->lang[$title])) ? $user->lang['CONFIRM'] : $user->lang[$title],
- 'MESSAGE_TEXT' => (!isset($user->lang[$title . '_CONFIRM'])) ? $title : $user->lang[$title . '_CONFIRM'],
+ 'MESSAGE_TEXT' => (!isset($user->lang[$title . '_CONFIRM'])) ? $title : $user->lang[$title . '_CONFIRM'],
'YES_VALUE' => $user->lang['YES'],
'S_CONFIRM_ACTION' => str_replace('&amp;', '&', $u_action), //inefficient, rewrite whole function
@@ -3463,6 +3467,7 @@ function login_forum_box($forum_data)
page_header($user->lang['LOGIN'], false);
$template->assign_vars(array(
+ 'FORUM_NAME' => isset($forum_data['forum_name']) ? $forum_data['forum_name'] : '',
'S_LOGIN_ACTION' => build_url(array('f')),
'S_HIDDEN_FIELDS' => build_hidden_fields(array('f' => $forum_data['forum_id'])))
);
@@ -3582,69 +3587,49 @@ function parse_cfg_file($filename, $lines = false)
}
/**
-* Add log event
+* Add log entry
+*
+* @param string $mode The mode defines which log_type is used and from which log the entry is retrieved
+* @param int $forum_id Mode 'mod' ONLY: forum id of the related item, NOT INCLUDED otherwise
+* @param int $topic_id Mode 'mod' ONLY: topic id of the related item, NOT INCLUDED otherwise
+* @param int $reportee_id Mode 'user' ONLY: user id of the reportee, NOT INCLUDED otherwise
+* @param string $log_operation Name of the operation
+* @param array $additional_data More arguments can be added, depending on the log_type
+*
+* @return int|bool Returns the log_id, if the entry was added to the database, false otherwise.
+*
+* @deprecated Use $phpbb_log->add() instead
*/
function add_log()
{
- global $db, $user;
-
- // In phpBB 3.1.x i want to have logging in a class to be able to control it
- // For now, we need a quite hakish approach to circumvent logging for some actions
- // @todo implement cleanly
- if (!empty($GLOBALS['skip_add_log']))
- {
- return false;
- }
+ global $phpbb_log, $user;
$args = func_get_args();
+ $mode = array_shift($args);
- $mode = array_shift($args);
- $reportee_id = ($mode == 'user') ? intval(array_shift($args)) : '';
- $forum_id = ($mode == 'mod') ? intval(array_shift($args)) : '';
- $topic_id = ($mode == 'mod') ? intval(array_shift($args)) : '';
- $action = array_shift($args);
- $data = (!sizeof($args)) ? '' : serialize($args);
-
- $sql_ary = array(
- 'user_id' => (empty($user->data)) ? ANONYMOUS : $user->data['user_id'],
- 'log_ip' => $user->ip,
- 'log_time' => time(),
- 'log_operation' => $action,
- 'log_data' => $data,
- );
-
+ // This looks kind of dirty, but add_log has some additional data before the log_operation
+ $additional_data = array();
switch ($mode)
{
case 'admin':
- $sql_ary['log_type'] = LOG_ADMIN;
+ case 'critical':
break;
-
case 'mod':
- $sql_ary += array(
- 'log_type' => LOG_MOD,
- 'forum_id' => $forum_id,
- 'topic_id' => $topic_id
- );
+ $additional_data['forum_id'] = array_shift($args);
+ $additional_data['topic_id'] = array_shift($args);
break;
-
case 'user':
- $sql_ary += array(
- 'log_type' => LOG_USERS,
- 'reportee_id' => $reportee_id
- );
- break;
-
- case 'critical':
- $sql_ary['log_type'] = LOG_CRITICAL;
+ $additional_data['reportee_id'] = array_shift($args);
break;
-
- default:
- return false;
}
- $db->sql_query('INSERT INTO ' . LOG_TABLE . ' ' . $db->sql_build_array('INSERT', $sql_ary));
+ $log_operation = array_shift($args);
+ $additional_data = array_merge($additional_data, $args);
+
+ $user_id = (empty($user->data)) ? ANONYMOUS : $user->data['user_id'];
+ $user_ip = (empty($user->ip)) ? '' : $user->ip;
- return $db->sql_nextid();
+ return $phpbb_log->add($mode, $user_id, $user_ip, $log_operation, time(), $additional_data);
}
/**
@@ -4200,7 +4185,7 @@ function phpbb_checkdnsrr($host, $type = 'MX')
// Handler, header and footer
/**
-* Error and message handler, call with trigger_error if reqd
+* Error and message handler, call with trigger_error if read
*/
function msg_handler($errno, $msg_text, $errfile, $errline)
{
@@ -5310,7 +5295,7 @@ function page_header($page_title = '', $display_online_list = true, $item_id = 0
'BOARD_URL' => $board_url,
'L_LOGIN_LOGOUT' => $l_login_logout,
- 'L_INDEX' => $user->lang['FORUM_INDEX'],
+ 'L_INDEX' => ($config['board_index_text'] !== '') ? $config['board_index_text'] : $user->lang['FORUM_INDEX'],
'L_SITE_HOME' => ($config['site_home_text'] !== '') ? $config['site_home_text'] : $user->lang['HOME'],
'L_ONLINE_EXPLAIN' => $l_online_time,
diff --git a/phpBB/includes/functions_acp.php b/phpBB/includes/functions_acp.php
index d6bd9e35dd..ff0e2a1ac1 100644
--- a/phpBB/includes/functions_acp.php
+++ b/phpBB/includes/functions_acp.php
@@ -249,17 +249,49 @@ function build_cfg_template($tpl_type, $key, &$new, $config_key, $vars)
{
case 'text':
case 'password':
+ case 'url':
+ case 'email':
+ case 'color':
+ case 'date':
+ case 'time':
+ case 'datetime':
+ case 'datetime-local':
+ case 'month':
+ case 'range':
+ case 'search':
+ case 'tel':
+ case 'url':
+ case 'week':
$size = (int) $tpl_type[1];
$maxlength = (int) $tpl_type[2];
$tpl = '<input id="' . $key . '" type="' . $tpl_type[0] . '"' . (($size) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength) ? $maxlength : 255) . '" name="' . $name . '" value="' . $new[$config_key] . '"' . (($tpl_type[0] === 'password') ? ' autocomplete="off"' : '') . ' />';
break;
+ case 'number':
+ $min = $max = $maxlength = '';
+ $min = ( isset($tpl_type[1]) ) ? (int) $tpl_type[1] : false;
+ if ( isset($tpl_type[2]) )
+ {
+ $max = (int) $tpl_type[2];
+ $maxlength = strlen( (string) $max );
+ }
+
+ $tpl = '<input id="' . $key . '" type="number" maxlength="' . (( $maxlength != '' ) ? $maxlength : 255) . '"' . (( $min != '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="' . $name . '" value="' . $new[$config_key] . '" />';
+ break;
+
case 'dimension':
- $size = (int) $tpl_type[1];
- $maxlength = (int) $tpl_type[2];
+ $min = $max = $maxlength = $size = '';
+
+ $min = (int) $tpl_type[1];
+
+ if ( isset($tpl_type[2]) )
+ {
+ $max = (int) $tpl_type[2];
+ $size = $maxlength = strlen( (string) $max );
+ }
- $tpl = '<input id="' . $key . '" type="text"' . (($size) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength) ? $maxlength : 255) . '" name="config[' . $config_key . '_width]" value="' . $new[$config_key . '_width'] . '" /> x <input type="text"' . (($size) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength) ? $maxlength : 255) . '" name="config[' . $config_key . '_height]" value="' . $new[$config_key . '_height'] . '" />';
+ $tpl = '<input id="' . $key . '" type="number"' . (( $size != '' ) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength != '') ? $maxlength : 255) . '"' . (( $min !== '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="config[' . $config_key . '_width]" value="' . $new[$config_key . '_width'] . '" /> x <input type="number"' . (( $size != '' ) ? ' size="' . $size . '"' : '') . ' maxlength="' . (($maxlength != '') ? $maxlength : 255) . '"' . (( $min !== '' ) ? ' min="' . $min . '"' : '') . (( $max != '' ) ? ' max="' . $max . '"' : '') . ' name="config[' . $config_key . '_height]" value="' . $new[$config_key . '_height'] . '" />';
break;
case 'textarea':
diff --git a/phpBB/includes/functions_admin.php b/phpBB/includes/functions_admin.php
index baf107bcda..72855af5f8 100644
--- a/phpBB/includes/functions_admin.php
+++ b/phpBB/includes/functions_admin.php
@@ -2506,273 +2506,32 @@ function cache_moderators()
/**
* View log
-* If $log_count is set to false, we will skip counting all entries in the database.
+*
+* @param string $mode The mode defines which log_type is used and from which log the entry is retrieved
+* @param array &$log The result array with the logs
+* @param mixed &$log_count If $log_count is set to false, we will skip counting all entries in the database.
+* Otherwise an integer with the number of total matching entries is returned.
+* @param int $limit Limit the number of entries that are returned
+* @param int $offset Offset when fetching the log entries, f.e. when paginating
+* @param mixed $forum_id Restrict the log entries to the given forum_id (can also be an array of forum_ids)
+* @param int $topic_id Restrict the log entries to the given topic_id
+* @param int $user_id Restrict the log entries to the given user_id
+* @param int $log_time Only get log entries newer than the given timestamp
+* @param string $sort_by SQL order option, e.g. 'l.log_time DESC'
+* @param string $keywords Will only return log entries that have the keywords in log_operation or log_data
+*
+* @return int Returns the offset of the last valid page, if the specified offset was invalid (too high)
*/
function view_log($mode, &$log, &$log_count, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $limit_days = 0, $sort_by = 'l.log_time DESC', $keywords = '')
{
- global $db, $user, $auth, $phpEx, $phpbb_root_path, $phpbb_admin_path;
-
- $topic_id_list = $reportee_id_list = $is_auth = $is_mod = array();
+ global $phpbb_log;
- $profile_url = (defined('IN_ADMIN')) ? append_sid("{$phpbb_admin_path}index.$phpEx", 'i=users&amp;mode=overview') : append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=viewprofile');
-
- switch ($mode)
- {
- case 'admin':
- $log_type = LOG_ADMIN;
- $sql_forum = '';
- break;
+ $count_logs = ($log_count !== false);
- case 'mod':
- $log_type = LOG_MOD;
- $sql_forum = '';
+ $log = $phpbb_log->get_logs($mode, $count_logs, $limit, $offset, $forum_id, $topic_id, $user_id, $limit_days, $sort_by, $keywords);
+ $log_count = $phpbb_log->get_log_count();
- if ($topic_id)
- {
- $sql_forum = 'AND l.topic_id = ' . (int) $topic_id;
- }
- else if (is_array($forum_id))
- {
- $sql_forum = 'AND ' . $db->sql_in_set('l.forum_id', array_map('intval', $forum_id));
- }
- else if ($forum_id)
- {
- $sql_forum = 'AND l.forum_id = ' . (int) $forum_id;
- }
- break;
-
- case 'user':
- $log_type = LOG_USERS;
- $sql_forum = 'AND l.reportee_id = ' . (int) $user_id;
- break;
-
- case 'users':
- $log_type = LOG_USERS;
- $sql_forum = '';
- break;
-
- case 'critical':
- $log_type = LOG_CRITICAL;
- $sql_forum = '';
- break;
-
- default:
- return;
- }
-
- // Use no preg_quote for $keywords because this would lead to sole backslashes being added
- // We also use an OR connection here for spaces and the | string. Currently, regex is not supported for searching (but may come later).
- $keywords = preg_split('#[\s|]+#u', utf8_strtolower($keywords), 0, PREG_SPLIT_NO_EMPTY);
- $sql_keywords = '';
-
- if (!empty($keywords))
- {
- $keywords_pattern = array();
-
- // Build pattern and keywords...
- for ($i = 0, $num_keywords = sizeof($keywords); $i < $num_keywords; $i++)
- {
- $keywords_pattern[] = preg_quote($keywords[$i], '#');
- $keywords[$i] = $db->sql_like_expression($db->any_char . $keywords[$i] . $db->any_char);
- }
-
- $keywords_pattern = '#' . implode('|', $keywords_pattern) . '#ui';
-
- $operations = array();
- foreach ($user->lang as $key => $value)
- {
- if (substr($key, 0, 4) == 'LOG_' && preg_match($keywords_pattern, $value))
- {
- $operations[] = $key;
- }
- }
-
- $sql_keywords = 'AND (';
- if (!empty($operations))
- {
- $sql_keywords .= $db->sql_in_set('l.log_operation', $operations) . ' OR ';
- }
- $sql_lower = $db->sql_lower_text('l.log_data');
- $sql_keywords .= "$sql_lower " . implode(" OR $sql_lower ", $keywords) . ')';
- }
-
- if ($log_count !== false)
- {
- $sql = 'SELECT COUNT(l.log_id) AS total_entries
- FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . " u
- WHERE l.log_type = $log_type
- AND l.user_id = u.user_id
- AND l.log_time >= $limit_days
- $sql_keywords
- $sql_forum";
- $result = $db->sql_query($sql);
- $log_count = (int) $db->sql_fetchfield('total_entries');
- $db->sql_freeresult($result);
- }
-
- // $log_count may be false here if false was passed in for it,
- // because in this case we did not run the COUNT() query above.
- // If we ran the COUNT() query and it returned zero rows, return;
- // otherwise query for logs below.
- if ($log_count === 0)
- {
- // Save the queries, because there are no logs to display
- return 0;
- }
-
- if ($offset >= $log_count)
- {
- $offset = ($offset - $limit < 0) ? 0 : $offset - $limit;
- }
-
- $sql = "SELECT l.*, u.username, u.username_clean, u.user_colour
- FROM " . LOG_TABLE . " l, " . USERS_TABLE . " u
- WHERE l.log_type = $log_type
- AND u.user_id = l.user_id
- " . (($limit_days) ? "AND l.log_time >= $limit_days" : '') . "
- $sql_keywords
- $sql_forum
- ORDER BY $sort_by";
- $result = $db->sql_query_limit($sql, $limit, $offset);
-
- $i = 0;
- $log = array();
- while ($row = $db->sql_fetchrow($result))
- {
- if ($row['topic_id'])
- {
- $topic_id_list[] = $row['topic_id'];
- }
-
- if ($row['reportee_id'])
- {
- $reportee_id_list[] = $row['reportee_id'];
- }
-
- $log[$i] = array(
- 'id' => $row['log_id'],
-
- 'reportee_id' => $row['reportee_id'],
- 'reportee_username' => '',
- 'reportee_username_full'=> '',
-
- 'user_id' => $row['user_id'],
- 'username' => $row['username'],
- 'username_full' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, $profile_url),
-
- 'ip' => $row['log_ip'],
- 'time' => $row['log_time'],
- 'forum_id' => $row['forum_id'],
- 'topic_id' => $row['topic_id'],
-
- 'viewforum' => ($row['forum_id'] && $auth->acl_get('f_read', $row['forum_id'])) ? append_sid("{$phpbb_root_path}viewforum.$phpEx", 'f=' . $row['forum_id']) : false,
- 'action' => (isset($user->lang[$row['log_operation']])) ? $user->lang[$row['log_operation']] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}',
- );
-
- if (!empty($row['log_data']))
- {
- $log_data_ary = @unserialize($row['log_data']);
- $log_data_ary = ($log_data_ary === false) ? array() : $log_data_ary;
-
- if (isset($user->lang[$row['log_operation']]))
- {
- // Check if there are more occurrences of % than arguments, if there are we fill out the arguments array
- // It doesn't matter if we add more arguments than placeholders
- if ((substr_count($log[$i]['action'], '%') - sizeof($log_data_ary)) > 0)
- {
- $log_data_ary = array_merge($log_data_ary, array_fill(0, substr_count($log[$i]['action'], '%') - sizeof($log_data_ary), ''));
- }
-
- $log[$i]['action'] = vsprintf($log[$i]['action'], $log_data_ary);
-
- // If within the admin panel we do not censor text out
- if (defined('IN_ADMIN'))
- {
- $log[$i]['action'] = bbcode_nl2br($log[$i]['action']);
- }
- else
- {
- $log[$i]['action'] = bbcode_nl2br(censor_text($log[$i]['action']));
- }
- }
- else if (!empty($log_data_ary))
- {
- $log[$i]['action'] .= '<br />' . implode('', $log_data_ary);
- }
-
- /* Apply make_clickable... has to be seen if it is for good. :/
- // Seems to be not for the moment, reconsider later...
- $log[$i]['action'] = make_clickable($log[$i]['action']);
- */
- }
-
- $i++;
- }
- $db->sql_freeresult($result);
-
- if (sizeof($topic_id_list))
- {
- $topic_id_list = array_unique($topic_id_list);
-
- // This query is not really needed if move_topics() updates the forum_id field,
- // although it's also used to determine if the topic still exists in the database
- $sql = 'SELECT topic_id, forum_id
- FROM ' . TOPICS_TABLE . '
- WHERE ' . $db->sql_in_set('topic_id', array_map('intval', $topic_id_list));
- $result = $db->sql_query($sql);
-
- $default_forum_id = 0;
-
- while ($row = $db->sql_fetchrow($result))
- {
- if ($auth->acl_get('f_read', $row['forum_id']))
- {
- $is_auth[$row['topic_id']] = $row['forum_id'];
- }
-
- if ($auth->acl_gets('a_', 'm_', $row['forum_id']))
- {
- $is_mod[$row['topic_id']] = $row['forum_id'];
- }
- }
- $db->sql_freeresult($result);
-
- foreach ($log as $key => $row)
- {
- $log[$key]['viewtopic'] = (isset($is_auth[$row['topic_id']])) ? append_sid("{$phpbb_root_path}viewtopic.$phpEx", 'f=' . $is_auth[$row['topic_id']] . '&amp;t=' . $row['topic_id']) : false;
- $log[$key]['viewlogs'] = (isset($is_mod[$row['topic_id']])) ? append_sid("{$phpbb_root_path}mcp.$phpEx", 'i=logs&amp;mode=topic_logs&amp;t=' . $row['topic_id'], true, $user->session_id) : false;
- }
- }
-
- if (sizeof($reportee_id_list))
- {
- $reportee_id_list = array_unique($reportee_id_list);
- $reportee_names_list = array();
-
- $sql = 'SELECT user_id, username, user_colour
- FROM ' . USERS_TABLE . '
- WHERE ' . $db->sql_in_set('user_id', $reportee_id_list);
- $result = $db->sql_query($sql);
-
- while ($row = $db->sql_fetchrow($result))
- {
- $reportee_names_list[$row['user_id']] = $row;
- }
- $db->sql_freeresult($result);
-
- foreach ($log as $key => $row)
- {
- if (!isset($reportee_names_list[$row['reportee_id']]))
- {
- continue;
- }
-
- $log[$key]['reportee_username'] = $reportee_names_list[$row['reportee_id']]['username'];
- $log[$key]['reportee_username_full'] = get_username_string('full', $row['reportee_id'], $reportee_names_list[$row['reportee_id']]['username'], $reportee_names_list[$row['reportee_id']]['user_colour'], false, $profile_url);
- }
- }
-
- return $offset;
+ return $phpbb_log->get_valid_offset();
}
/**
@@ -3281,38 +3040,29 @@ function tidy_database()
*/
function add_permission_language()
{
- global $user, $phpEx;
+ global $user, $phpEx, $phpbb_extension_manager;
- // First of all, our own file. We need to include it as the first file because it presets all relevant variables.
- $user->add_lang('acp/permissions_phpbb');
+ // add permission language files from extensions
+ $finder = $phpbb_extension_manager->get_finder();
- $files_to_add = array();
+ $lang_files = $finder
+ ->prefix('permissions_')
+ ->suffix(".$phpEx")
+ ->core_path('language/' . $user->lang_name . '/')
+ ->extension_directory('/language/' . $user->lang_name)
+ ->find();
- // Now search in acp and mods folder for permissions_ files.
- foreach (array('acp/', 'mods/') as $path)
+ foreach ($lang_files as $lang_file => $ext_name)
{
- $dh = @opendir($user->lang_path . $user->lang_name . '/' . $path);
-
- if ($dh)
+ if ($ext_name === '/')
{
- while (($file = readdir($dh)) !== false)
- {
- if ($file !== 'permissions_phpbb.' . $phpEx && strpos($file, 'permissions_') === 0 && substr($file, -(strlen($phpEx) + 1)) === '.' . $phpEx)
- {
- $files_to_add[] = $path . substr($file, 0, -(strlen($phpEx) + 1));
- }
- }
- closedir($dh);
+ $user->add_lang($lang_file);
+ }
+ else
+ {
+ $user->add_lang_ext($ext_name, $lang_file);
}
}
-
- if (!sizeof($files_to_add))
- {
- return false;
- }
-
- $user->add_lang($files_to_add);
- return true;
}
/**
@@ -3338,7 +3088,7 @@ function obtain_latest_version_info($force_update = false, $warn_fail = false, $
$info = get_remote_file('version.phpbb.com', '/phpbb',
((defined('PHPBB_QA')) ? '30x_qa.txt' : '30x.txt'), $errstr, $errno);
- if ($info === false)
+ if (empty($info))
{
$cache->destroy('versioncheck');
if ($warn_fail)
diff --git a/phpBB/includes/functions_compatibility.php b/phpBB/includes/functions_compatibility.php
new file mode 100644
index 0000000000..2197815087
--- /dev/null
+++ b/phpBB/includes/functions_compatibility.php
@@ -0,0 +1,50 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Get user avatar
+*
+* @deprecated 3.1.0-a1 (To be removed: 3.3.0)
+*
+* @param string $avatar Users assigned avatar name
+* @param int $avatar_type Type of avatar
+* @param string $avatar_width Width of users avatar
+* @param string $avatar_height Height of users avatar
+* @param string $alt Optional language string for alt tag within image, can be a language key or text
+* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP
+*
+* @return string Avatar image
+*/
+function get_user_avatar($avatar, $avatar_type, $avatar_width, $avatar_height, $alt = 'USER_AVATAR', $ignore_config = false)
+{
+ // map arguments to new function phpbb_get_avatar()
+ $row = array(
+ 'avatar' => $avatar,
+ 'avatar_type' => $avatar_type,
+ 'avatar_width' => $avatar_width,
+ 'avatar_height' => $avatar_height,
+ );
+
+ if (!function_exists('phpbb_get_avatar'))
+ {
+ global $phpbb_root_path, $phpEx;
+
+ include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ }
+
+ return phpbb_get_avatar($row, $alt, $ignore_config);
+}
diff --git a/phpBB/includes/functions_container.php b/phpBB/includes/functions_container.php
index a3ed21c35b..106b7d75cc 100644
--- a/phpBB/includes/functions_container.php
+++ b/phpBB/includes/functions_container.php
@@ -57,6 +57,7 @@ function phpbb_create_install_container($phpbb_root_path, $php_ext)
$container = phpbb_create_container(array($core), $phpbb_root_path, $php_ext);
$container->setParameter('core.root_path', $phpbb_root_path);
+ $container->setParameter('core.adm_relative_path', $phpbb_adm_relative_path);
$container->setParameter('core.php_ext', $php_ext);
$container->setParameter('core.table_prefix', '');
diff --git a/phpBB/includes/functions_display.php b/phpBB/includes/functions_display.php
index cd4c901b58..9854cd6d70 100644
--- a/phpBB/includes/functions_display.php
+++ b/phpBB/includes/functions_display.php
@@ -1341,79 +1341,87 @@ function get_user_rank($user_rank, $user_posts, &$rank_title, &$rank_img, &$rank
/**
* Get user avatar
*
-* @param string $avatar Users assigned avatar name
-* @param int $avatar_type Type of avatar
-* @param string $avatar_width Width of users avatar
-* @param string $avatar_height Height of users avatar
+* @param array $user_row Row from the users table
* @param string $alt Optional language string for alt tag within image, can be a language key or text
* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP
*
-* @return string Avatar image
+* @return string Avatar html
*/
-function get_user_avatar($avatar, $avatar_type, $avatar_width, $avatar_height, $alt = 'USER_AVATAR', $ignore_config = false)
+function phpbb_get_user_avatar($user_row, $alt = 'USER_AVATAR', $ignore_config = false)
{
- global $user, $config, $phpbb_root_path, $phpEx;
- global $phpbb_dispatcher;
-
- $overwrite_avatar = '';
+ $row = phpbb_avatar_manager::clean_row($user_row);
+ return phpbb_get_avatar($row, $alt, $ignore_config);
+}
- /**
- * Overwrite users avatar
- *
- * @event core.display_custom_bbcodes_modify_row
- * @var string avatar Users assigned avatar name
- * @var int avatar_type Type of avatar
- * @var string avatar_width Width of users avatar
- * @var string avatar_height Height of users avatar
- * @var string alt Language string for alt tag within image
- * Can be a language key or text
- * @var bool ignore_config Ignores config and force displaying avatar
- * @var string overwrite_avatar If set, this string will be the avatar
- * @since 3.1-A1
- */
- $vars = array('avatar', 'avatar_type', 'avatar_width', 'avatar_height', 'alt', 'ignore_config', 'overwrite_avatar');
- extract($phpbb_dispatcher->trigger_event('core.user_get_avatar', compact($vars)));
+/**
+* Get group avatar
+*
+* @param array $group_row Row from the groups table
+* @param string $alt Optional language string for alt tag within image, can be a language key or text
+* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP
+*
+* @return string Avatar html
+*/
+function phpbb_get_group_avatar($user_row, $alt = 'GROUP_AVATAR', $ignore_config = false)
+{
+ $row = phpbb_avatar_manager::clean_row($user_row);
+ return phpbb_get_avatar($row, $alt, $ignore_config);
+}
- if ($overwrite_avatar)
- {
- return $overwrite_avatar;
- }
+/**
+* Get avatar
+*
+* @param array $row Row cleaned by phpbb_avatar_driver::clean_row
+* @param string $alt Optional language string for alt tag within image, can be a language key or text
+* @param bool $ignore_config Ignores the config-setting, to be still able to view the avatar in the UCP
+*
+* @return string Avatar html
+*/
+function phpbb_get_avatar($row, $alt, $ignore_config = false)
+{
+ global $user, $config, $cache, $phpbb_root_path, $phpEx;
+ global $request;
+ global $phpbb_container;
- if (empty($avatar) || !$avatar_type || (!$config['allow_avatar'] && !$ignore_config))
+ if (!$config['allow_avatar'] && !$ignore_config)
{
return '';
}
- $avatar_img = '';
+ $avatar_data = array(
+ 'src' => $row['avatar'],
+ 'width' => $row['avatar_width'],
+ 'height' => $row['avatar_height'],
+ );
+
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $driver = $phpbb_avatar_manager->get_driver($row['avatar_type'], $ignore_config);
+ $html = '';
- switch ($avatar_type)
+ if ($driver)
{
- case AVATAR_UPLOAD:
- if (!$config['allow_avatar_upload'] && !$ignore_config)
- {
- return '';
- }
- $avatar_img = $phpbb_root_path . "download/file.$phpEx?avatar=";
- break;
+ $html = $driver->get_custom_html($user, $row, $alt);
+ if (!empty($html))
+ {
+ return $html;
+ }
- case AVATAR_GALLERY:
- if (!$config['allow_avatar_local'] && !$ignore_config)
- {
- return '';
- }
- $avatar_img = $phpbb_root_path . $config['avatar_gallery_path'] . '/';
- break;
+ $avatar_data = $driver->get_data($row, $ignore_config);
+ }
+ else
+ {
+ $avatar_data['src'] = '';
+ }
- case AVATAR_REMOTE:
- if (!$config['allow_avatar_remote'] && !$ignore_config)
- {
- return '';
- }
- break;
+ if (!empty($avatar_data['src']))
+ {
+ $html = '<img src="' . $avatar_data['src'] . '" ' .
+ ($avatar_data['width'] ? ('width="' . $avatar_data['width'] . '" ') : '') .
+ ($avatar_data['height'] ? ('height="' . $avatar_data['height'] . '" ') : '') .
+ 'alt="' . ((!empty($user->lang[$alt])) ? $user->lang[$alt] : $alt) . '" />';
}
- $avatar_img .= $avatar;
- return '<img src="' . (str_replace(' ', '%20', $avatar_img)) . '" width="' . $avatar_width . '" height="' . $avatar_height . '" alt="' . ((!empty($user->lang[$alt])) ? $user->lang[$alt] : $alt) . '" />';
+ return $html;
}
/**
diff --git a/phpBB/includes/functions_download.php b/phpBB/includes/functions_download.php
index 9ae647d806..ee4e2f5135 100644
--- a/phpBB/includes/functions_download.php
+++ b/phpBB/includes/functions_download.php
@@ -625,7 +625,7 @@ function phpbb_increment_downloads($db, $ids)
*/
function phpbb_download_handle_forum_auth($db, $auth, $topic_id)
{
- $sql = 'SELECT t.forum_id, f.forum_password, f.parent_id
+ $sql = 'SELECT t.forum_id, f.forum_name, f.forum_password, f.parent_id
FROM ' . TOPICS_TABLE . ' t, ' . FORUMS_TABLE . " f
WHERE t.topic_id = " . (int) $topic_id . "
AND t.forum_id = f.forum_id";
diff --git a/phpBB/includes/functions_messenger.php b/phpBB/includes/functions_messenger.php
index 821f0d970d..a646f35fdd 100644
--- a/phpBB/includes/functions_messenger.php
+++ b/phpBB/includes/functions_messenger.php
@@ -55,6 +55,24 @@ class messenger
$this->vars = $this->msg = $this->replyto = $this->from = '';
$this->mail_priority = MAIL_NORMAL_PRIORITY;
}
+
+ /**
+ * Set addresses for to/im as available
+ *
+ * @param array $user User row
+ */
+ function set_addresses($user)
+ {
+ if (isset($user['user_email']) && $user['user_email'])
+ {
+ $this->to($user['user_email'], (isset($user['username']) ? $user['username'] : ''));
+ }
+
+ if (isset($user['user_jabber']) && $user['user_jabber'])
+ {
+ $this->im($user['user_jabber'], (isset($user['username']) ? $user['username'] : ''));
+ }
+ }
/**
* Sets an email address to send to
@@ -209,7 +227,7 @@ class messenger
if (!isset($this->tpl_msg[$template_lang . $template_file]))
{
$style_resource_locator = new phpbb_style_resource_locator();
- $style_path_provider = new phpbb_style_extension_path_provider($phpbb_extension_manager, new phpbb_style_path_provider());
+ $style_path_provider = new phpbb_style_extension_path_provider($phpbb_extension_manager, new phpbb_style_path_provider(), $phpbb_root_path);
$tpl = new phpbb_template($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, new phpbb_template_context(), $phpbb_extension_manager);
$style = new phpbb_style($phpbb_root_path, $phpEx, $config, $user, $style_resource_locator, $style_path_provider, $tpl);
diff --git a/phpBB/includes/functions_profile_fields.php b/phpBB/includes/functions_profile_fields.php
index 10af997bff..7dd0b0e87d 100644
--- a/phpBB/includes/functions_profile_fields.php
+++ b/phpBB/includes/functions_profile_fields.php
@@ -1040,9 +1040,9 @@ class custom_profile_admin extends custom_profile
global $user;
$options = array(
- 0 => array('TITLE' => $user->lang['FIELD_LENGTH'], 'FIELD' => '<input type="text" name="field_length" size="5" value="' . $this->vars['field_length'] . '" />'),
- 1 => array('TITLE' => $user->lang['MIN_FIELD_CHARS'], 'FIELD' => '<input type="text" name="field_minlen" size="5" value="' . $this->vars['field_minlen'] . '" />'),
- 2 => array('TITLE' => $user->lang['MAX_FIELD_CHARS'], 'FIELD' => '<input type="text" name="field_maxlen" size="5" value="' . $this->vars['field_maxlen'] . '" />'),
+ 0 => array('TITLE' => $user->lang['FIELD_LENGTH'], 'FIELD' => '<input type="number" min="0" name="field_length" size="5" value="' . $this->vars['field_length'] . '" />'),
+ 1 => array('TITLE' => $user->lang['MIN_FIELD_CHARS'], 'FIELD' => '<input type="number" min="0" name="field_minlen" size="5" value="' . $this->vars['field_minlen'] . '" />'),
+ 2 => array('TITLE' => $user->lang['MAX_FIELD_CHARS'], 'FIELD' => '<input type="number" min="0" size="5" value="' . $this->vars['field_maxlen'] . '" />'),
3 => array('TITLE' => $user->lang['FIELD_VALIDATION'], 'FIELD' => '<select name="field_validation">' . $this->validate_options() . '</select>')
);
@@ -1057,9 +1057,9 @@ class custom_profile_admin extends custom_profile
global $user;
$options = array(
- 0 => array('TITLE' => $user->lang['FIELD_LENGTH'], 'FIELD' => '<input name="rows" size="5" value="' . $this->vars['rows'] . '" /> ' . $user->lang['ROWS'] . '</dd><dd><input name="columns" size="5" value="' . $this->vars['columns'] . '" /> ' . $user->lang['COLUMNS'] . ' <input type="hidden" name="field_length" value="' . $this->vars['field_length'] . '" />'),
- 1 => array('TITLE' => $user->lang['MIN_FIELD_CHARS'], 'FIELD' => '<input type="text" name="field_minlen" size="10" value="' . $this->vars['field_minlen'] . '" />'),
- 2 => array('TITLE' => $user->lang['MAX_FIELD_CHARS'], 'FIELD' => '<input type="text" name="field_maxlen" size="10" value="' . $this->vars['field_maxlen'] . '" />'),
+ 0 => array('TITLE' => $user->lang['FIELD_LENGTH'], 'FIELD' => '<input type="number" min="0" max="99999" name="rows" size="5" value="' . $this->vars['rows'] . '" /> ' . $user->lang['ROWS'] . '</dd><dd><input type="number" min="0" max="99999" name="columns" size="5" value="' . $this->vars['columns'] . '" /> ' . $user->lang['COLUMNS'] . ' <input type="hidden" name="field_length" value="' . $this->vars['field_length'] . '" />'),
+ 1 => array('TITLE' => $user->lang['MIN_FIELD_CHARS'], 'FIELD' => '<input type="number" min="0" max="9999999999" name="field_minlen" size="10" value="' . $this->vars['field_minlen'] . '" />'),
+ 2 => array('TITLE' => $user->lang['MAX_FIELD_CHARS'], 'FIELD' => '<input type="number" min="0" max="9999999999" name="field_maxlen" size="10" value="' . $this->vars['field_maxlen'] . '" />'),
3 => array('TITLE' => $user->lang['FIELD_VALIDATION'], 'FIELD' => '<select name="field_validation">' . $this->validate_options() . '</select>')
);
@@ -1074,9 +1074,9 @@ class custom_profile_admin extends custom_profile
global $user;
$options = array(
- 0 => array('TITLE' => $user->lang['FIELD_LENGTH'], 'FIELD' => '<input type="text" name="field_length" size="5" value="' . $this->vars['field_length'] . '" />'),
- 1 => array('TITLE' => $user->lang['MIN_FIELD_NUMBER'], 'FIELD' => '<input type="text" name="field_minlen" size="5" value="' . $this->vars['field_minlen'] . '" />'),
- 2 => array('TITLE' => $user->lang['MAX_FIELD_NUMBER'], 'FIELD' => '<input type="text" name="field_maxlen" size="5" value="' . $this->vars['field_maxlen'] . '" />'),
+ 0 => array('TITLE' => $user->lang['FIELD_LENGTH'], 'FIELD' => '<input type="number" min="0" max="99999" name="field_length" size="5" value="' . $this->vars['field_length'] . '" />'),
+ 1 => array('TITLE' => $user->lang['MIN_FIELD_NUMBER'], 'FIELD' => '<input type="number" min="0" max="99999" name="field_minlen" size="5" value="' . $this->vars['field_minlen'] . '" />'),
+ 2 => array('TITLE' => $user->lang['MAX_FIELD_NUMBER'], 'FIELD' => '<input type="number" min="0" max="99999" name="field_maxlen" size="5" value="' . $this->vars['field_maxlen'] . '" />'),
3 => array('TITLE' => $user->lang['DEFAULT_VALUE'], 'FIELD' => '<input type="post" name="field_default_value" value="' . $this->vars['field_default_value'] . '" />')
);
diff --git a/phpBB/includes/functions_url_matcher.php b/phpBB/includes/functions_url_matcher.php
index 7280cb74eb..a89ab7b126 100644
--- a/phpBB/includes/functions_url_matcher.php
+++ b/phpBB/includes/functions_url_matcher.php
@@ -60,7 +60,7 @@ function phpbb_create_dumped_url_matcher(phpbb_extension_finder $finder, $root_p
'class' => 'phpbb_url_matcher',
));
- file_put_contents($root_path . 'cache/url_matcher' . $php_ext, $cached_url_matcher_dump);
+ file_put_contents($root_path . 'cache/url_matcher.' . $php_ext, $cached_url_matcher_dump);
}
/**
@@ -87,7 +87,7 @@ function phpbb_create_url_matcher(phpbb_extension_finder $finder, RequestContext
*/
function phpbb_load_url_matcher(RequestContext $context, $root_path, $php_ext)
{
- require($root_path . 'cache/url_matcher' . $php_ext);
+ require($root_path . 'cache/url_matcher.' . $php_ext);
return new phpbb_url_matcher($context);
}
@@ -102,5 +102,5 @@ function phpbb_load_url_matcher(RequestContext $context, $root_path, $php_ext)
*/
function phpbb_url_matcher_dumped($root_path, $php_ext)
{
- return file_exists($root_path . 'cache/url_matcher' . $php_ext);
+ return file_exists($root_path . 'cache/url_matcher.' . $php_ext);
}
diff --git a/phpBB/includes/functions_user.php b/phpBB/includes/functions_user.php
index b7878ddfc7..7b11e4f01b 100644
--- a/phpBB/includes/functions_user.php
+++ b/phpBB/includes/functions_user.php
@@ -310,8 +310,10 @@ function user_add($user_row, $cp_data = false)
if ($add_group_id)
{
- // Because these actions only fill the log unneccessarily we skip the add_log() entry with a little hack. :/
- $GLOBALS['skip_add_log'] = true;
+ global $phpbb_log;
+
+ // Because these actions only fill the log unneccessarily we skip the add_log() entry.
+ $phpbb_log->disable('admin');
// Add user to "newly registered users" group and set to default group if admin specified so.
if ($config['new_member_group_default'])
@@ -324,7 +326,7 @@ function user_add($user_row, $cp_data = false)
group_user_add($add_group_id, $user_id);
}
- unset($GLOBALS['skip_add_log']);
+ $phpbb_log->enable('admin');
}
}
@@ -1328,22 +1330,12 @@ function validate_data($data, $val_ary)
{
$function = array_shift($validate);
array_unshift($validate, $data[$var]);
+ $function_prefix = (function_exists('phpbb_validate_' . $function)) ? 'phpbb_validate_' : 'validate_';
- if (function_exists('phpbb_validate_' . $function))
- {
- if ($result = call_user_func_array('phpbb_validate_' . $function, $validate))
- {
- // Since errors are checked later for their language file existence, we need to make sure custom errors are not adjusted.
- $error[] = (empty($user->lang[$result . '_' . strtoupper($var)])) ? $result : $result . '_' . strtoupper($var);
- }
- }
- else
+ if ($result = call_user_func_array($function_prefix . $function, $validate))
{
- if ($result = call_user_func_array('validate_' . $function, $validate))
- {
- // Since errors are checked later for their language file existence, we need to make sure custom errors are not adjusted.
- $error[] = (empty($user->lang[$result . '_' . strtoupper($var)])) ? $result : $result . '_' . strtoupper($var);
- }
+ // Since errors are checked later for their language file existence, we need to make sure custom errors are not adjusted.
+ $error[] = (empty($user->lang[$result . '_' . strtoupper($var)])) ? $result : $result . '_' . strtoupper($var);
}
}
}
@@ -2007,6 +1999,30 @@ function validate_jabber($jid)
}
/**
+* Validate hex colour value
+*
+* @param string $colour The hex colour value
+* @param bool $optional Whether the colour value is optional. True if an empty
+* string will be accepted as correct input, false if not.
+* @return bool|string Error message if colour value is incorrect, false if it
+* fits the hex colour code
+*/
+function phpbb_validate_hex_colour($colour, $optional = false)
+{
+ if ($colour === '')
+ {
+ return (($optional) ? false : 'WRONG_DATA');
+ }
+
+ if (!preg_match('/^([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$/', $colour))
+ {
+ return 'WRONG_DATA';
+ }
+
+ return false;
+}
+
+/**
* Verifies whether a style ID corresponds to an active style.
*
* @param int $style_id The style_id of a style which should be checked if activated or not.
@@ -2048,6 +2064,7 @@ function avatar_delete($mode, $row, $clean_db = false)
avatar_remove_db($row[$mode . '_avatar']);
}
$filename = get_avatar_filename($row[$mode . '_avatar']);
+
if (file_exists($phpbb_root_path . $config['avatar_path'] . '/' . $filename))
{
@unlink($phpbb_root_path . $config['avatar_path'] . '/' . $filename);
@@ -2058,134 +2075,6 @@ function avatar_delete($mode, $row, $clean_db = false)
}
/**
-* Remote avatar linkage
-*/
-function avatar_remote($data, &$error)
-{
- global $config, $db, $user, $phpbb_root_path, $phpEx;
-
- if (!preg_match('#^(http|https|ftp)://#i', $data['remotelink']))
- {
- $data['remotelink'] = 'http://' . $data['remotelink'];
- }
- if (!preg_match('#^(http|https|ftp)://(?:(.*?\.)*?[a-z0-9\-]+?\.[a-z]{2,4}|(?:\d{1,3}\.){3,5}\d{1,3}):?([0-9]*?).*?\.(gif|jpg|jpeg|png)$#i', $data['remotelink']))
- {
- $error[] = $user->lang['AVATAR_URL_INVALID'];
- return false;
- }
-
- // Make sure getimagesize works...
- if (($image_data = @getimagesize($data['remotelink'])) === false && (empty($data['width']) || empty($data['height'])))
- {
- $error[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
- return false;
- }
-
- if (!empty($image_data) && ($image_data[0] < 2 || $image_data[1] < 2))
- {
- $error[] = $user->lang['AVATAR_NO_SIZE'];
- return false;
- }
-
- $width = ($data['width'] && $data['height']) ? $data['width'] : $image_data[0];
- $height = ($data['width'] && $data['height']) ? $data['height'] : $image_data[1];
-
- if ($width < 2 || $height < 2)
- {
- $error[] = $user->lang['AVATAR_NO_SIZE'];
- return false;
- }
-
- // Check image type
- include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx);
- $types = fileupload::image_types();
- $extension = strtolower(filespec::get_extension($data['remotelink']));
-
- if (!empty($image_data) && (!isset($types[$image_data[2]]) || !in_array($extension, $types[$image_data[2]])))
- {
- if (!isset($types[$image_data[2]]))
- {
- $error[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
- }
- else
- {
- $error[] = sprintf($user->lang['IMAGE_FILETYPE_MISMATCH'], $types[$image_data[2]][0], $extension);
- }
- return false;
- }
-
- if ($config['avatar_max_width'] || $config['avatar_max_height'])
- {
- if ($width > $config['avatar_max_width'] || $height > $config['avatar_max_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($width, $height);
- return false;
- }
- }
-
- if ($config['avatar_min_width'] || $config['avatar_min_height'])
- {
- if ($width < $config['avatar_min_width'] || $height < $config['avatar_min_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($width, $height);
- return false;
- }
- }
-
- return array(AVATAR_REMOTE, $data['remotelink'], $width, $height);
-}
-
-/**
-* Avatar upload using the upload class
-*/
-function avatar_upload($data, &$error)
-{
- global $phpbb_root_path, $config, $db, $user, $phpEx, $request;
-
- // Init upload class
- include_once($phpbb_root_path . 'includes/functions_upload.' . $phpEx);
- $upload = new fileupload('AVATAR_', array('jpg', 'jpeg', 'gif', 'png'), $config['avatar_filesize'], $config['avatar_min_width'], $config['avatar_min_height'], $config['avatar_max_width'], $config['avatar_max_height'], (isset($config['mime_triggers']) ? explode('|', $config['mime_triggers']) : false));
-
- $uploadfile = $request->file('uploadfile');
- if (!empty($uploadfile['name']))
- {
- $file = $upload->form_upload('uploadfile');
- }
- else
- {
- $file = $upload->remote_upload($data['uploadurl']);
- }
-
- $prefix = $config['avatar_salt'] . '_';
- $file->clean_filename('avatar', $prefix, $data['user_id']);
-
- $destination = $config['avatar_path'];
-
- // Adjust destination path (no trailing slash)
- if (substr($destination, -1, 1) == '/' || substr($destination, -1, 1) == '\\')
- {
- $destination = substr($destination, 0, -1);
- }
-
- $destination = str_replace(array('../', '..\\', './', '.\\'), '', $destination);
- if ($destination && ($destination[0] == '/' || $destination[0] == "\\"))
- {
- $destination = '';
- }
-
- // Move file and overwrite any existing image
- $file->move_file($destination, true);
-
- if (sizeof($file->error))
- {
- $file->remove();
- $error = array_merge($error, $file->error);
- }
-
- return array(AVATAR_UPLOAD, $data['user_id'] . '_' . time() . '.' . $file->get('extension'), $file->get('width'), $file->get('height'));
-}
-
-/**
* Generates avatar filename from the database entry
*/
function get_avatar_filename($avatar_entry)
@@ -2208,344 +2097,6 @@ function get_avatar_filename($avatar_entry)
}
/**
-* Avatar Gallery
-*/
-function avatar_gallery($category, $avatar_select, $items_per_column, $block_var = 'avatar_row')
-{
- global $user, $cache, $template;
- global $config, $phpbb_root_path;
-
- $avatar_list = array();
-
- $path = $phpbb_root_path . $config['avatar_gallery_path'];
-
- if (!file_exists($path) || !is_dir($path))
- {
- $avatar_list = array($user->lang['NO_AVATAR_CATEGORY'] => array());
- }
- else
- {
- // Collect images
- $dp = @opendir($path);
-
- if (!$dp)
- {
- return array($user->lang['NO_AVATAR_CATEGORY'] => array());
- }
-
- while (($file = readdir($dp)) !== false)
- {
- if ($file[0] != '.' && preg_match('#^[^&"\'<>]+$#i', $file) && is_dir("$path/$file"))
- {
- $avatar_row_count = $avatar_col_count = 0;
-
- if ($dp2 = @opendir("$path/$file"))
- {
- while (($sub_file = readdir($dp2)) !== false)
- {
- if (preg_match('#^[^&\'"<>]+\.(?:gif|png|jpe?g)$#i', $sub_file))
- {
- $avatar_list[$file][$avatar_row_count][$avatar_col_count] = array(
- 'file' => rawurlencode($file) . '/' . rawurlencode($sub_file),
- 'filename' => rawurlencode($sub_file),
- 'name' => ucfirst(str_replace('_', ' ', preg_replace('#^(.*)\..*$#', '\1', $sub_file))),
- );
- $avatar_col_count++;
- if ($avatar_col_count == $items_per_column)
- {
- $avatar_row_count++;
- $avatar_col_count = 0;
- }
- }
- }
- closedir($dp2);
- }
- }
- }
- closedir($dp);
- }
-
- if (!sizeof($avatar_list))
- {
- $avatar_list = array($user->lang['NO_AVATAR_CATEGORY'] => array());
- }
-
- @ksort($avatar_list);
-
- $category = (!$category) ? key($avatar_list) : $category;
- $avatar_categories = array_keys($avatar_list);
-
- $s_category_options = '';
- foreach ($avatar_categories as $cat)
- {
- $s_category_options .= '<option value="' . $cat . '"' . (($cat == $category) ? ' selected="selected"' : '') . '>' . $cat . '</option>';
- }
-
- $template->assign_vars(array(
- 'S_AVATARS_ENABLED' => true,
- 'S_IN_AVATAR_GALLERY' => true,
- 'S_CAT_OPTIONS' => $s_category_options)
- );
-
- $avatar_list = (isset($avatar_list[$category])) ? $avatar_list[$category] : array();
-
- foreach ($avatar_list as $avatar_row_ary)
- {
- $template->assign_block_vars($block_var, array());
-
- foreach ($avatar_row_ary as $avatar_col_ary)
- {
- $template->assign_block_vars($block_var . '.avatar_column', array(
- 'AVATAR_IMAGE' => $phpbb_root_path . $config['avatar_gallery_path'] . '/' . $avatar_col_ary['file'],
- 'AVATAR_NAME' => $avatar_col_ary['name'],
- 'AVATAR_FILE' => $avatar_col_ary['filename'])
- );
-
- $template->assign_block_vars($block_var . '.avatar_option_column', array(
- 'AVATAR_IMAGE' => $phpbb_root_path . $config['avatar_gallery_path'] . '/' . $avatar_col_ary['file'],
- 'S_OPTIONS_AVATAR' => $avatar_col_ary['filename'])
- );
- }
- }
-
- return $avatar_list;
-}
-
-
-/**
-* Tries to (re-)establish avatar dimensions
-*/
-function avatar_get_dimensions($avatar, $avatar_type, &$error, $current_x = 0, $current_y = 0)
-{
- global $config, $phpbb_root_path, $user;
-
- switch ($avatar_type)
- {
- case AVATAR_REMOTE :
- break;
-
- case AVATAR_UPLOAD :
- $avatar = $phpbb_root_path . $config['avatar_path'] . '/' . get_avatar_filename($avatar);
- break;
-
- case AVATAR_GALLERY :
- $avatar = $phpbb_root_path . $config['avatar_gallery_path'] . '/' . $avatar ;
- break;
- }
-
- // Make sure getimagesize works...
- if (($image_data = @getimagesize($avatar)) === false)
- {
- $error[] = $user->lang['UNABLE_GET_IMAGE_SIZE'];
- return false;
- }
-
- if ($image_data[0] < 2 || $image_data[1] < 2)
- {
- $error[] = $user->lang['AVATAR_NO_SIZE'];
- return false;
- }
-
- // try to maintain ratio
- if (!(empty($current_x) && empty($current_y)))
- {
- if ($current_x != 0)
- {
- $image_data[1] = (int) floor(($current_x / $image_data[0]) * $image_data[1]);
- $image_data[1] = min($config['avatar_max_height'], $image_data[1]);
- $image_data[1] = max($config['avatar_min_height'], $image_data[1]);
- }
- if ($current_y != 0)
- {
- $image_data[0] = (int) floor(($current_y / $image_data[1]) * $image_data[0]);
- $image_data[0] = min($config['avatar_max_width'], $image_data[1]);
- $image_data[0] = max($config['avatar_min_width'], $image_data[1]);
- }
- }
- return array($image_data[0], $image_data[1]);
-}
-
-/**
-* Uploading/Changing user avatar
-*/
-function avatar_process_user(&$error, $custom_userdata = false, $can_upload = null)
-{
- global $config, $phpbb_root_path, $auth, $user, $db, $request;
-
- $data = array(
- 'uploadurl' => request_var('uploadurl', ''),
- 'remotelink' => request_var('remotelink', ''),
- 'width' => request_var('width', 0),
- 'height' => request_var('height', 0),
- );
-
- $error = validate_data($data, array(
- 'uploadurl' => array('string', true, 5, 255),
- 'remotelink' => array('string', true, 5, 255),
- 'width' => array('string', true, 1, 3),
- 'height' => array('string', true, 1, 3),
- ));
-
- if (sizeof($error))
- {
- return false;
- }
-
- $sql_ary = array();
-
- if ($custom_userdata === false)
- {
- $userdata = &$user->data;
- }
- else
- {
- $userdata = &$custom_userdata;
- }
-
- $data['user_id'] = $userdata['user_id'];
- $change_avatar = ($custom_userdata === false) ? $auth->acl_get('u_chgavatar') : true;
- $avatar_select = basename(request_var('avatar_select', ''));
-
- // Can we upload?
- if (is_null($can_upload))
- {
- $can_upload = ($config['allow_avatar_upload'] && file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $change_avatar && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on')) ? true : false;
- }
-
- $uploadfile = $request->file('uploadfile');
- if ((!empty($uploadfile['name']) || $data['uploadurl']) && $can_upload)
- {
- list($sql_ary['user_avatar_type'], $sql_ary['user_avatar'], $sql_ary['user_avatar_width'], $sql_ary['user_avatar_height']) = avatar_upload($data, $error);
- }
- else if ($data['remotelink'] && $change_avatar && $config['allow_avatar_remote'])
- {
- list($sql_ary['user_avatar_type'], $sql_ary['user_avatar'], $sql_ary['user_avatar_width'], $sql_ary['user_avatar_height']) = avatar_remote($data, $error);
- }
- else if ($avatar_select && $change_avatar && $config['allow_avatar_local'])
- {
- $category = basename(request_var('category', ''));
-
- $sql_ary['user_avatar_type'] = AVATAR_GALLERY;
- $sql_ary['user_avatar'] = $avatar_select;
-
- // check avatar gallery
- if (!is_dir($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category))
- {
- $sql_ary['user_avatar'] = '';
- $sql_ary['user_avatar_type'] = $sql_ary['user_avatar_width'] = $sql_ary['user_avatar_height'] = 0;
- }
- else
- {
- list($sql_ary['user_avatar_width'], $sql_ary['user_avatar_height']) = getimagesize($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category . '/' . urldecode($sql_ary['user_avatar']));
- $sql_ary['user_avatar'] = $category . '/' . $sql_ary['user_avatar'];
- }
- }
- else if (isset($_POST['delete']) && $change_avatar)
- {
- $sql_ary['user_avatar'] = '';
- $sql_ary['user_avatar_type'] = $sql_ary['user_avatar_width'] = $sql_ary['user_avatar_height'] = 0;
- }
- else if (!empty($userdata['user_avatar']))
- {
- // Only update the dimensions
-
- if (empty($data['width']) || empty($data['height']))
- {
- if ($dims = avatar_get_dimensions($userdata['user_avatar'], $userdata['user_avatar_type'], $error, $data['width'], $data['height']))
- {
- list($guessed_x, $guessed_y) = $dims;
- if (empty($data['width']))
- {
- $data['width'] = $guessed_x;
- }
- if (empty($data['height']))
- {
- $data['height'] = $guessed_y;
- }
- }
- }
- if (($config['avatar_max_width'] || $config['avatar_max_height']) &&
- (($data['width'] != $userdata['user_avatar_width']) || $data['height'] != $userdata['user_avatar_height']))
- {
- if ($data['width'] > $config['avatar_max_width'] || $data['height'] > $config['avatar_max_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
- }
- }
-
- if (!sizeof($error))
- {
- if ($config['avatar_min_width'] || $config['avatar_min_height'])
- {
- if ($data['width'] < $config['avatar_min_width'] || $data['height'] < $config['avatar_min_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
- }
- }
- }
-
- if (!sizeof($error))
- {
- $sql_ary['user_avatar_width'] = $data['width'];
- $sql_ary['user_avatar_height'] = $data['height'];
- }
- }
-
- if (!sizeof($error))
- {
- // Do we actually have any data to update?
- if (sizeof($sql_ary))
- {
- $ext_new = $ext_old = '';
- if (isset($sql_ary['user_avatar']))
- {
- $userdata = ($custom_userdata === false) ? $user->data : $custom_userdata;
- $ext_new = (empty($sql_ary['user_avatar'])) ? '' : substr(strrchr($sql_ary['user_avatar'], '.'), 1);
- $ext_old = (empty($userdata['user_avatar'])) ? '' : substr(strrchr($userdata['user_avatar'], '.'), 1);
-
- if ($userdata['user_avatar_type'] == AVATAR_UPLOAD)
- {
- // Delete old avatar if present
- if ((!empty($userdata['user_avatar']) && empty($sql_ary['user_avatar']))
- || ( !empty($userdata['user_avatar']) && !empty($sql_ary['user_avatar']) && $ext_new !== $ext_old))
- {
- avatar_delete('user', $userdata);
- }
- }
- }
-
- $sql = 'UPDATE ' . USERS_TABLE . '
- SET ' . $db->sql_build_array('UPDATE', $sql_ary) . '
- WHERE user_id = ' . (($custom_userdata === false) ? $user->data['user_id'] : $custom_userdata['user_id']);
- $db->sql_query($sql);
-
- }
- }
-
- return (sizeof($error)) ? false : true;
-}
-
-/**
-* Returns a language string with the avatar size of the new avatar and the allowed maximum and minimum
-*
-* @param $width int The width of the new uploaded/selected avatar
-* @param $height int The height of the new uploaded/selected avatar
-* @return string
-*/
-function phpbb_avatar_error_wrong_size($width, $height)
-{
- global $config, $user;
-
- return $user->lang('AVATAR_WRONG_SIZE',
- $user->lang('PIXELS', (int) $config['avatar_min_width']),
- $user->lang('PIXELS', (int) $config['avatar_min_height']),
- $user->lang('PIXELS', (int) $config['avatar_max_width']),
- $user->lang('PIXELS', (int) $config['avatar_max_height']),
- $user->lang('PIXELS', (int) $width),
- $user->lang('PIXELS', (int) $height));
-}
-
-/**
* Returns an explanation string with maximum avatar settings
*
* @return string
@@ -2570,7 +2121,7 @@ function phpbb_avatar_explanation_string()
*/
function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow_desc_bbcode = false, $allow_desc_urls = false, $allow_desc_smilies = false)
{
- global $phpbb_root_path, $config, $db, $user, $file_upload;
+ global $phpbb_root_path, $config, $db, $user, $file_upload, $phpbb_container;
$error = array();
@@ -2594,22 +2145,32 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
$error[] = $user->lang['GROUP_ERR_TYPE'];
}
+ $group_teampage = !empty($group_attributes['group_teampage']);
+ unset($group_attributes['group_teampage']);
+
if (!sizeof($error))
{
- $current_legend = phpbb_group_positions::GROUP_DISABLED;
- $current_teampage = phpbb_group_positions::GROUP_DISABLED;
+ $current_legend = phpbb_groupposition_legend::GROUP_DISABLED;
+ $current_teampage = phpbb_groupposition_teampage::GROUP_DISABLED;
- $legend = new phpbb_group_positions($db, 'legend');
- $teampage = new phpbb_group_positions($db, 'teampage');
+ $legend = $phpbb_container->get('groupposition.legend');
+ $teampage = $phpbb_container->get('groupposition.teampage');
if ($group_id)
{
- $current_legend = $legend->get_group_value($group_id);
- $current_teampage = $teampage->get_group_value($group_id);
+ try
+ {
+ $current_legend = $legend->get_group_value($group_id);
+ $current_teampage = $teampage->get_group_value($group_id);
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ trigger_error($user->lang($exception->getMessage()));
+ }
}
if (!empty($group_attributes['group_legend']))
{
- if (($group_id && ($current_legend == phpbb_group_positions::GROUP_DISABLED)) || !$group_id)
+ if (($group_id && ($current_legend == phpbb_groupposition_legend::GROUP_DISABLED)) || !$group_id)
{
// Old group currently not in the legend or new group, add at the end.
$group_attributes['group_legend'] = 1 + $legend->get_group_count();
@@ -2620,44 +2181,26 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
$group_attributes['group_legend'] = $current_legend;
}
}
- else if ($group_id && ($current_legend > phpbb_group_positions::GROUP_DISABLED))
+ else if ($group_id && ($current_legend != phpbb_groupposition_legend::GROUP_DISABLED))
{
// Group is removed from the legend
- $legend->delete_group($group_id, true);
- $group_attributes['group_legend'] = phpbb_group_positions::GROUP_DISABLED;
- }
- else
- {
- $group_attributes['group_legend'] = phpbb_group_positions::GROUP_DISABLED;
- }
-
- if (!empty($group_attributes['group_teampage']))
- {
- if (($group_id && ($current_teampage == phpbb_group_positions::GROUP_DISABLED)) || !$group_id)
+ try
{
- // Old group currently not on the teampage or new group, add at the end.
- $group_attributes['group_teampage'] = 1 + $teampage->get_group_count();
+ $legend->delete_group($group_id, true);
}
- else
+ catch (phpbb_groupposition_exception $exception)
{
- // Group stayes on the teampage
- $group_attributes['group_teampage'] = $current_teampage;
+ trigger_error($user->lang($exception->getMessage()));
}
- }
- else if ($group_id && ($current_teampage > phpbb_group_positions::GROUP_DISABLED))
- {
- // Group is removed from the teampage
- $teampage->delete_group($group_id, true);
- $group_attributes['group_teampage'] = phpbb_group_positions::GROUP_DISABLED;
+ $group_attributes['group_legend'] = phpbb_groupposition_legend::GROUP_DISABLED;
}
else
{
- $group_attributes['group_teampage'] = phpbb_group_positions::GROUP_DISABLED;
+ $group_attributes['group_legend'] = phpbb_groupposition_legend::GROUP_DISABLED;
}
// Unset the objects, we don't need them anymore.
unset($legend);
- unset($teampage);
$user_ary = array();
$sql_ary = array(
@@ -2751,6 +2294,20 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
$db->sql_query($sql);
}
+ // Remove the group from the teampage, only if unselected and we are editing a group,
+ // which is currently displayed.
+ if (!$group_teampage && $group_id && $current_teampage != phpbb_groupposition_teampage::GROUP_DISABLED)
+ {
+ try
+ {
+ $teampage->delete_group($group_id);
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ trigger_error($user->lang($exception->getMessage()));
+ }
+ }
+
if (!$group_id)
{
$group_id = $db->sql_nextid();
@@ -2761,6 +2318,31 @@ function group_create(&$group_id, $type, $name, $desc, $group_attributes, $allow
}
}
+ try
+ {
+ if ($group_teampage && $current_teampage == phpbb_groupposition_teampage::GROUP_DISABLED)
+ {
+ $teampage->add_group($group_id);
+ }
+
+ if ($group_teampage)
+ {
+ if ($current_teampage == phpbb_groupposition_teampage::GROUP_DISABLED)
+ {
+ $teampage->add_group($group_id);
+ }
+ }
+ else if ($group_id && ($current_teampage != phpbb_groupposition_teampage::GROUP_DISABLED))
+ {
+ $teampage->delete_group($group_id);
+ }
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ trigger_error($user->lang($exception->getMessage()));
+ }
+ unset($teampage);
+
// Set user attributes
$sql_ary = array();
if (sizeof($group_attributes))
@@ -2842,7 +2424,7 @@ function avatar_remove_db($avatar_name)
*/
function group_delete($group_id, $group_name = false)
{
- global $db, $cache, $auth, $phpbb_root_path, $phpEx, $phpbb_dispatcher;
+ global $db, $cache, $auth, $user, $phpbb_root_path, $phpEx, $phpbb_dispatcher, $phpbb_container;
if (!$group_name)
{
@@ -2884,12 +2466,31 @@ function group_delete($group_id, $group_name = false)
while ($start);
// Delete group from legend and teampage
- $legend = new phpbb_group_positions($db, 'legend');
- $legend->delete_group($group_id);
- unset($legend);
- $teampage = new phpbb_group_positions($db, 'teampage');
- $teampage->delete_group($group_id);
- unset($teampage);
+ try
+ {
+ $legend = $phpbb_container->get('groupposition.legend');
+ $legend->delete_group($group_id);
+ unset($legend);
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ // The group we want to delete does not exist.
+ // No reason to worry, we just continue the deleting process.
+ //trigger_error($user->lang($exception->getMessage()));
+ }
+
+ try
+ {
+ $teampage = $phpbb_container->get('groupposition.teampage');
+ $teampage->delete_group($group_id);
+ unset($teampage);
+ }
+ catch (phpbb_groupposition_exception $exception)
+ {
+ // The group we want to delete does not exist.
+ // No reason to worry, we just continue the deleting process.
+ //trigger_error($user->lang($exception->getMessage()));
+ }
// Delete group
$sql = 'DELETE FROM ' . GROUPS_TABLE . "
@@ -3337,8 +2938,7 @@ function group_user_attributes($action, $group_id, $user_id_ary = false, $userna
{
$messenger->template('group_approved', $row['user_lang']);
- $messenger->to($row['user_email'], $row['username']);
- $messenger->im($row['user_jabber'], $row['username']);
+ $messenger->set_addresses($row);
$messenger->assign_vars(array(
'USERNAME' => htmlspecialchars_decode($row['username']),
diff --git a/phpBB/includes/groupposition/exception.php b/phpBB/includes/groupposition/exception.php
new file mode 100644
index 0000000000..e4ff09c703
--- /dev/null
+++ b/phpBB/includes/groupposition/exception.php
@@ -0,0 +1,23 @@
+<?php
+/**
+*
+* @package groupposition
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* @package groupposition
+*/
+class phpbb_groupposition_exception extends \Exception
+{
+}
diff --git a/phpBB/includes/groupposition/interface.php b/phpBB/includes/groupposition/interface.php
new file mode 100644
index 0000000000..eacc04e1a4
--- /dev/null
+++ b/phpBB/includes/groupposition/interface.php
@@ -0,0 +1,84 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2012 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Interface to manage group positions in various places of phpbb
+*
+* The interface provides simple methods to add, delete and move a group
+*
+* @package phpBB3
+*/
+interface phpbb_groupposition_interface
+{
+ /**
+ * Returns the value for a given group, if the group exists.
+ * @param int $group_id group_id of the group to be selected
+ * @return int position of the group
+ */
+ public function get_group_value($group_id);
+
+ /**
+ * Get number of groups displayed
+ *
+ * @return int value of the last item displayed
+ */
+ public function get_group_count();
+
+ /**
+ * Addes a group by group_id
+ *
+ * @param int $group_id group_id of the group to be added
+ * @return bool True if the group was added successfully
+ */
+ public function add_group($group_id);
+
+ /**
+ * Deletes a group by group_id
+ *
+ * @param int $group_id group_id of the group to be deleted
+ * @param bool $skip_group Skip setting the value for this group, to save the query, when you need to update it anyway.
+ * @return bool True if the group was deleted successfully
+ */
+ public function delete_group($group_id, $skip_group = false);
+
+ /**
+ * Moves a group up by group_id
+ *
+ * @param int $group_id group_id of the group to be moved
+ * @return bool True if the group was moved successfully
+ */
+ public function move_up($group_id);
+
+ /**
+ * Moves a group down by group_id
+ *
+ * @param int $group_id group_id of the group to be moved
+ * @return bool True if the group was moved successfully
+ */
+ public function move_down($group_id);
+
+ /**
+ * Moves a group up/down
+ *
+ * @param int $group_id group_id of the group to be moved
+ * @param int $delta number of steps:
+ * - positive = move up
+ * - negative = move down
+ * @return bool True if the group was moved successfully
+ */
+ public function move($group_id, $delta);
+}
diff --git a/phpBB/includes/group_positions.php b/phpBB/includes/groupposition/legend.php
index 60352ed97d..7fddadde99 100644
--- a/phpBB/includes/group_positions.php
+++ b/phpBB/includes/groupposition/legend.php
@@ -2,7 +2,7 @@
/**
*
* @package phpBB3
-* @copyright (c) 2011 phpBB Group
+* @copyright (c) 2012 phpBB Group
* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
*
*/
@@ -16,13 +16,14 @@ if (!defined('IN_PHPBB'))
}
/**
-* Group Position class, containing all functions to manage the groups in the teampage and legend.
+* Legend group position class
*
-* group_teampage/group_legend is an ascending list 1, 2, ..., n for groups which are displayed. 1 is the first group, n the last.
+* group_legend is an ascending list 1, 2, ..., n for groups which are displayed. 1 is the first group, n the last.
* If the value is 0 (self::GROUP_DISABLED) the group is not displayed.
+*
* @package phpBB3
*/
-class phpbb_group_positions
+class phpbb_groupposition_legend implements phpbb_groupposition_interface
{
/**
* Group is not displayed
@@ -30,81 +31,73 @@ class phpbb_group_positions
const GROUP_DISABLED = 0;
/**
- * phpbb-database object
- */
- public $db = null;
-
- /**
- * Name of the field we want to handle: either 'teampage' or 'legend'
+ * Database object
+ * @var phpbb_db_driver
*/
- private $field = '';
+ protected $db;
/**
- * URI for the adm_back_link when there was an error.
+ * User object
+ * @var phpbb_user
*/
- private $adm_back_link = '';
+ protected $user;
/**
* Constructor
+ *
+ * @param phpbb_db_driver $db Database object
+ * @param phpbb_user $user User object
*/
- public function __construct ($db, $field, $adm_back_link = '')
+ public function __construct(phpbb_db_driver $db, phpbb_user $user)
{
- $this->adm_back_link = $adm_back_link;
-
- if (!in_array($field, array('teampage', 'legend')))
- {
- $this->error('NO_MODE');
- }
-
$this->db = $db;
- $this->field = $field;
+ $this->user = $user;
}
/**
- * Returns the group_{$this->field} for a given group, if the group exists.
- * @param int $group_id group_id of the group to be selected
- * @return int position of the group
+ * Returns the group_legend for a given group, if the group exists.
+ *
+ * {@inheritDoc}
*/
public function get_group_value($group_id)
{
- $sql = 'SELECT group_' . $this->field . '
+ $sql = 'SELECT group_legend
FROM ' . GROUPS_TABLE . '
WHERE group_id = ' . (int) $group_id;
$result = $this->db->sql_query($sql);
- $current_value = $this->db->sql_fetchfield('group_' . $this->field);
+ $current_value = $this->db->sql_fetchfield('group_legend');
$this->db->sql_freeresult($result);
if ($current_value === false)
{
// Group not found.
- $this->error('NO_GROUP');
+ throw new phpbb_groupposition_exception('NO_GROUP');
}
return (int) $current_value;
}
/**
- * Get number of groups, displayed on the teampage/legend
+ * Get number of groups, displayed on the legend
*
- * @return int value of the last group displayed
+ * {@inheritDoc}
*/
public function get_group_count()
{
- $sql = 'SELECT group_' . $this->field . '
+ $sql = 'SELECT group_legend
FROM ' . GROUPS_TABLE . '
- ORDER BY group_' . $this->field . ' DESC';
+ ORDER BY group_legend DESC';
$result = $this->db->sql_query_limit($sql, 1);
- $group_count = (int) $this->db->sql_fetchfield('group_' . $this->field);
+ $group_count = (int) $this->db->sql_fetchfield('group_legend');
$this->db->sql_freeresult($result);
return $group_count;
}
/**
- * Addes a group by group_id
+ * Adds a group by group_id
*
- * @param int $group_id group_id of the group to be added
- * @return null
+ * {@inheritDoc}
*/
public function add_group($group_id)
{
@@ -116,19 +109,20 @@ class phpbb_group_positions
$next_value = 1 + $this->get_group_count();
$sql = 'UPDATE ' . GROUPS_TABLE . '
- SET group_' . $this->field . ' = ' . $next_value . '
- WHERE group_' . $this->field . ' = ' . self::GROUP_DISABLED . '
+ SET group_legend = ' . $next_value . '
+ WHERE group_legend = ' . self::GROUP_DISABLED . '
AND group_id = ' . (int) $group_id;
$this->db->sql_query($sql);
+ return true;
}
+
+ return false;
}
/**
* Deletes a group by setting the field to self::GROUP_DISABLED and closing the gap in the list.
*
- * @param int $group_id group_id of the group to be deleted
- * @param bool $skip_group Skip setting the group to GROUP_DISABLED, to save the query, when you need to update it anyway.
- * @return null
+ * {@inheritDoc}
*/
public function delete_group($group_id, $skip_group = false)
{
@@ -139,58 +133,57 @@ class phpbb_group_positions
$this->db->sql_transaction('begin');
$sql = 'UPDATE ' . GROUPS_TABLE . '
- SET group_' . $this->field . ' = group_' . $this->field . ' - 1
- WHERE group_' . $this->field . ' > ' . $current_value;
+ SET group_legend = group_legend - 1
+ WHERE group_legend > ' . $current_value;
$this->db->sql_query($sql);
if (!$skip_group)
{
$sql = 'UPDATE ' . GROUPS_TABLE . '
- SET group_' . $this->field . ' = ' . self::GROUP_DISABLED . '
+ SET group_legend = ' . self::GROUP_DISABLED . '
WHERE group_id = ' . (int) $group_id;
$this->db->sql_query($sql);
}
$this->db->sql_transaction('commit');
+
+ return true;
}
+
+ return false;
}
/**
* Moves a group up by group_id
*
- * @param int $group_id group_id of the group to be moved
- * @return null
+ * {@inheritDoc}
*/
public function move_up($group_id)
{
- $this->move($group_id, 1);
+ return $this->move($group_id, 1);
}
/**
* Moves a group down by group_id
*
- * @param int $group_id group_id of the group to be moved
- * @return null
+ * {@inheritDoc}
*/
public function move_down($group_id)
{
- $this->move($group_id, -1);
+ return $this->move($group_id, -1);
}
/**
* Moves a group up/down
*
- * @param int $group_id group_id of the group to be moved
- * @param int $delta number of steps:
- * - positive = move up
- * - negative = move down
- * @return null
+ * {@inheritDoc}
*/
public function move($group_id, $delta)
{
- if (!is_int($delta) || !$delta)
+ $delta = (int) $delta;
+ if (!$delta)
{
- return;
+ return false;
}
$move_up = ($delta > 0) ? true : false;
@@ -203,10 +196,10 @@ class phpbb_group_positions
// First we move all groups between our current value and the target value up/down 1,
// so we have a gap for our group to move.
$sql = 'UPDATE ' . GROUPS_TABLE . '
- SET group_' . $this->field . ' = group_' . $this->field . (($move_up) ? ' + 1' : ' - 1') . '
- WHERE group_' . $this->field . ' > ' . self::GROUP_DISABLED . '
- AND group_' . $this->field . (($move_up) ? ' >= ' : ' <= ') . ($current_value - $delta) . '
- AND group_' . $this->field . (($move_up) ? ' < ' : ' > ') . $current_value;
+ SET group_legend = group_legend' . (($move_up) ? ' + 1' : ' - 1') . '
+ WHERE group_legend > ' . self::GROUP_DISABLED . '
+ AND group_legend' . (($move_up) ? ' >= ' : ' <= ') . ($current_value - $delta) . '
+ AND group_legend' . (($move_up) ? ' < ' : ' > ') . $current_value;
$this->db->sql_query($sql);
// Because there might be fewer groups above/below the group than we wanted to move,
@@ -218,20 +211,26 @@ class phpbb_group_positions
// And now finally, when we moved some other groups and built a gap,
// we can move the desired group to it.
$sql = 'UPDATE ' . GROUPS_TABLE . '
- SET group_' . $this->field . ' = group_' . $this->field . (($move_up) ? ' - ' : ' + ') . $delta . '
+ SET group_legend = group_legend ' . (($move_up) ? ' - ' : ' + ') . $delta . '
WHERE group_id = ' . (int) $group_id;
$this->db->sql_query($sql);
+
+ $this->db->sql_transaction('commit');
+
+ return true;
}
$this->db->sql_transaction('commit');
}
+
+ return false;
}
/**
* Get group type language var
*
* @param int $group_type group_type from the groups-table
- * @return string name of the language variable for the given group-type.
+ * @return string name of the language variable for the given group-type.
*/
static public function group_type_language($group_type)
{
@@ -249,13 +248,4 @@ class phpbb_group_positions
return 'GROUP_OPEN';
}
}
-
- /**
- * Error
- */
- public function error($message)
- {
- global $user;
- trigger_error($user->lang[$message] . (($this->adm_back_link) ? adm_back_link($this->adm_back_link) : ''), E_USER_WARNING);
- }
}
diff --git a/phpBB/includes/groupposition/teampage.php b/phpBB/includes/groupposition/teampage.php
new file mode 100644
index 0000000000..7c758199e7
--- /dev/null
+++ b/phpBB/includes/groupposition/teampage.php
@@ -0,0 +1,604 @@
+<?php
+/**
+*
+* @package phpBB3
+* @copyright (c) 2012 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Teampage group position class
+*
+* Teampage position is an ascending list 1, 2, ..., n for items which are displayed. 1 is the first item, n the last.
+*
+* @package phpBB3
+*/
+class phpbb_groupposition_teampage implements phpbb_groupposition_interface
+{
+ /**
+ * Group is not displayed
+ */
+ const GROUP_DISABLED = 0;
+
+ /**
+ * No parent item
+ */
+ const NO_PARENT = 0;
+
+ /**
+ * Database object
+ * @var phpbb_db_driver
+ */
+ protected $db;
+
+ /**
+ * User object
+ * @var phpbb_user
+ */
+ protected $user;
+
+ /**
+ * Cache object
+ * @var phpbb_cache_driver_interface
+ */
+ protected $cache;
+
+ /**
+ * Constructor
+ *
+ * @param phpbb_db_driver $db Database object
+ * @param phpbb_user $user User object
+ * @param phpbb_cache_driver_interface $cache Cache object
+ */
+ public function __construct(phpbb_db_driver $db, phpbb_user $user, phpbb_cache_driver_interface $cache)
+ {
+ $this->db = $db;
+ $this->user = $user;
+ $this->cache = $cache;
+ }
+
+ /**
+ * Returns the teampage position for a given group, if the group exists.
+ *
+ * {@inheritDoc}
+ */
+ public function get_group_value($group_id)
+ {
+ // The join is required to ensure that the group itself exists
+ $sql = 'SELECT g.group_id, t.teampage_position
+ FROM ' . GROUPS_TABLE . ' g
+ LEFT JOIN ' . TEAMPAGE_TABLE . ' t
+ ON (t.group_id = g.group_id)
+ WHERE g.group_id = ' . (int) $group_id;
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if ($row === false)
+ {
+ // Group not found.
+ throw new phpbb_groupposition_exception('NO_GROUP');
+ }
+
+ return (int) $row['teampage_position'];
+ }
+
+ /**
+ * Returns the row for a given group, if the group exists.
+ *
+ * @param int $group_id group_id of the group to be selected
+ * @return array Data row of the group
+ */
+ public function get_group_values($group_id)
+ {
+ // The join is required to ensure that the group itself exists
+ $sql = 'SELECT *
+ FROM ' . GROUPS_TABLE . ' g
+ LEFT JOIN ' . TEAMPAGE_TABLE . ' t
+ ON (t.group_id = g.group_id)
+ WHERE g.group_id = ' . (int) $group_id;
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if ($row === false)
+ {
+ // Group not found.
+ throw new phpbb_groupposition_exception('NO_GROUP');
+ }
+
+ return $row;
+ }
+
+ /**
+ * Returns the teampage position for a given teampage item, if the item exists.
+ *
+ * @param int $teampage_id Teampage_id of the selected item
+ * @return int Teampage position of the item
+ */
+ public function get_teampage_value($teampage_id)
+ {
+ $sql = 'SELECT teampage_position
+ FROM ' . TEAMPAGE_TABLE . '
+ WHERE teampage_id = ' . (int) $teampage_id;
+ $result = $this->db->sql_query($sql);
+ $current_value = $this->db->sql_fetchfield('teampage_position');
+ $this->db->sql_freeresult($result);
+
+ if ($current_value === false)
+ {
+ // Group not found.
+ throw new phpbb_groupposition_exception('NO_GROUP');
+ }
+
+ return (int) $current_value;
+ }
+
+ /**
+ * Returns the teampage row for a given teampage item, if the item exists.
+ *
+ * @param int $teampage_id Teampage_id of the selected item
+ * @return array Teampage row of the item
+ */
+ public function get_teampage_values($teampage_id)
+ {
+ $sql = 'SELECT teampage_position, teampage_parent
+ FROM ' . TEAMPAGE_TABLE . '
+ WHERE teampage_id = ' . (int) $teampage_id;
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if ($row === false)
+ {
+ // Group not found.
+ throw new phpbb_groupposition_exception('NO_GROUP');
+ }
+
+ return $row;
+ }
+
+
+ /**
+ * Get number of items displayed
+ *
+ * {@inheritDoc}
+ */
+ public function get_group_count()
+ {
+ $sql = 'SELECT teampage_position
+ FROM ' . TEAMPAGE_TABLE . '
+ ORDER BY teampage_position DESC';
+ $result = $this->db->sql_query_limit($sql, 1);
+ $group_count = (int) $this->db->sql_fetchfield('teampage_position');
+ $this->db->sql_freeresult($result);
+
+ return $group_count;
+ }
+
+ /**
+ * Adds a group by group_id
+ *
+ * {@inheritDoc}
+ */
+ public function add_group($group_id)
+ {
+ return $this->add_group_teampage($group_id, self::NO_PARENT);
+ }
+
+ /**
+ * Adds a group by group_id
+ *
+ * @param int $group_id group_id of the group to be added
+ * @param int $parent_id Teampage ID of the parent item
+ * @return bool True if the group was added successfully
+ */
+ public function add_group_teampage($group_id, $parent_id)
+ {
+ $current_value = $this->get_group_value($group_id);
+
+ if ($current_value == self::GROUP_DISABLED)
+ {
+ if ($parent_id != self::NO_PARENT)
+ {
+ // Check, whether the given parent is a category
+ $sql = 'SELECT teampage_id
+ FROM ' . TEAMPAGE_TABLE . '
+ WHERE group_id = 0
+ AND teampage_id = ' . (int) $parent_id;
+ $result = $this->db->sql_query_limit($sql, 1);
+ $parent_is_category = (bool) $this->db->sql_fetchfield('teampage_id');
+ $this->db->sql_freeresult($result);
+
+ if ($parent_is_category)
+ {
+ // Get value of last child from this parent and add group there
+ $sql = 'SELECT teampage_position
+ FROM ' . TEAMPAGE_TABLE . '
+ WHERE teampage_parent = ' . (int) $parent_id . '
+ OR teampage_id = ' . (int) $parent_id . '
+ ORDER BY teampage_position DESC';
+ $result = $this->db->sql_query_limit($sql, 1);
+ $new_position = (int) $this->db->sql_fetchfield('teampage_position');
+ $this->db->sql_freeresult($result);
+
+ $sql = 'UPDATE ' . TEAMPAGE_TABLE . '
+ SET teampage_position = teampage_position + 1
+ WHERE teampage_position > ' . $new_position;
+ $this->db->sql_query($sql);
+ }
+ }
+ else
+ {
+ // Add group at the end
+ $new_position = $this->get_group_count();
+ }
+
+ $sql_ary = array(
+ 'group_id' => $group_id,
+ 'teampage_position' => $new_position + 1,
+ 'teampage_parent' => $parent_id,
+ );
+
+ $sql = 'INSERT INTO ' . TEAMPAGE_TABLE . ' ' . $this->db->sql_build_array('INSERT', $sql_ary);
+ $this->db->sql_query($sql);
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return true;
+ }
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return false;
+ }
+
+ /**
+ * Adds a new category
+ *
+ * @param string $category_name Name of the category to be added
+ * @return bool True if the category was added successfully
+ */
+ public function add_category_teampage($category_name)
+ {
+ if ($category_name === '')
+ {
+ return false;
+ }
+
+ $num_entries = $this->get_group_count();
+
+ $sql_ary = array(
+ 'group_id' => 0,
+ 'teampage_position' => $num_entries + 1,
+ 'teampage_parent' => 0,
+ 'teampage_name' => truncate_string($category_name, 255, 255),
+ );
+
+ $sql = 'INSERT INTO ' . TEAMPAGE_TABLE . ' ' . $this->db->sql_build_array('INSERT', $sql_ary);
+ $this->db->sql_query($sql);
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return true;
+ }
+
+ /**
+ * Deletes a group from the list and closes the gap in the position list.
+ *
+ * {@inheritDoc}
+ */
+ public function delete_group($group_id, $skip_group = false)
+ {
+ $current_value = $this->get_group_value($group_id);
+
+ if ($current_value != self::GROUP_DISABLED)
+ {
+ $sql = 'UPDATE ' . TEAMPAGE_TABLE . '
+ SET teampage_position = teampage_position - 1
+ WHERE teampage_position > ' . $current_value;
+ $this->db->sql_query($sql);
+
+ $sql = 'DELETE FROM ' . TEAMPAGE_TABLE . '
+ WHERE group_id = ' . $group_id;
+ $this->db->sql_query($sql);
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return true;
+ }
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return false;
+ }
+
+ /**
+ * Deletes an item from the list and closes the gap in the position list.
+ *
+ * @param int $teampage_id teampage_id of the item to be deleted
+ * @param bool $skip_group Skip setting the group to GROUP_DISABLED, to save the query, when you need to update it anyway.
+ * @return bool True if the item was deleted successfully
+ */
+ public function delete_teampage($teampage_id, $skip_group = false)
+ {
+ $current_value = $this->get_teampage_value($teampage_id);
+
+ if ($current_value != self::GROUP_DISABLED)
+ {
+ $sql = 'DELETE FROM ' . TEAMPAGE_TABLE . '
+ WHERE teampage_id = ' . $teampage_id . '
+ OR teampage_parent = ' . $teampage_id;
+ $this->db->sql_query($sql);
+
+ $delta = (int) $this->db->sql_affectedrows();
+
+ $sql = 'UPDATE ' . TEAMPAGE_TABLE . '
+ SET teampage_position = teampage_position - ' . $delta . '
+ WHERE teampage_position > ' . $current_value;
+ $this->db->sql_query($sql);
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return true;
+ }
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return false;
+ }
+
+ /**
+ * Moves a group up by group_id
+ *
+ * {@inheritDoc}
+ */
+ public function move_up($group_id)
+ {
+ return $this->move($group_id, 1);
+ }
+
+ /**
+ * Moves an item up by teampage_id
+ *
+ * @param int $group_id group_id of the group to be moved
+ * @return bool True if the group was moved successfully
+ */
+ public function move_up_teampage($teampage_id)
+ {
+ return $this->move_teampage($teampage_id, 1);
+ }
+
+ /**
+ * Moves a group down by group_id
+ *
+ * {@inheritDoc}
+ */
+ public function move_down($group_id)
+ {
+ return $this->move($group_id, -1);
+ }
+
+ /**
+ * Movesan item down by teampage_id
+ *
+ * @param int $group_id group_id of the group to be moved
+ * @return bool True if the group was moved successfully
+ */
+ public function move_down_teampage($teampage_id)
+ {
+ return $this->move_teampage($teampage_id, -1);
+ }
+
+ /**
+ * Moves a group up/down
+ *
+ * {@inheritDoc}
+ */
+ public function move($group_id, $delta)
+ {
+ $delta = (int) $delta;
+ if (!$delta)
+ {
+ return false;
+ }
+
+ $move_up = ($delta > 0) ? true : false;
+ $data = $this->get_group_values($group_id);
+
+ $current_value = (int) $data['teampage_position'];
+ if ($current_value != self::GROUP_DISABLED)
+ {
+ $this->db->sql_transaction('begin');
+
+ if (!$move_up && $data['teampage_parent'] == self::NO_PARENT)
+ {
+ // If we move items down, we need to grab the one sibling more,
+ // so we do not ignore the children of the previous sibling.
+ // We will remove the additional sibling later on.
+ $delta = abs($delta) + 1;
+ }
+
+ $sql = 'SELECT teampage_position
+ FROM ' . TEAMPAGE_TABLE . '
+ WHERE teampage_parent = ' . (int) $data['teampage_parent'] . '
+ AND teampage_position' . (($move_up) ? ' < ' : ' > ') . $current_value . '
+ ORDER BY teampage_position' . (($move_up) ? ' DESC' : ' ASC');
+ $result = $this->db->sql_query_limit($sql, $delta);
+
+ $sibling_count = 0;
+ $sibling_limit = $delta;
+
+ // Reset the delta, as we recalculate the new real delta
+ $delta = 0;
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $sibling_count++;
+ $delta = $current_value - $row['teampage_position'];
+
+ if (!$move_up && $data['teampage_parent'] == self::NO_PARENT && $sibling_count == $sibling_limit)
+ {
+ // Remove the additional sibling we added previously
+ $delta++;
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ if ($delta)
+ {
+ // First we move all items between our current value and the target value up/down 1,
+ // so we have a gap for our item to move.
+ $sql = 'UPDATE ' . TEAMPAGE_TABLE . '
+ SET teampage_position = teampage_position' . (($move_up) ? ' + 1' : ' - 1') . '
+ WHERE teampage_position' . (($move_up) ? ' >= ' : ' <= ') . ($current_value - $delta) . '
+ AND teampage_position' . (($move_up) ? ' < ' : ' > ') . $current_value;
+ $this->db->sql_query($sql);
+
+ // And now finally, when we moved some other items and built a gap,
+ // we can move the desired item to it.
+ $sql = 'UPDATE ' . TEAMPAGE_TABLE . '
+ SET teampage_position = teampage_position ' . (($move_up) ? ' - ' : ' + ') . abs($delta) . '
+ WHERE group_id = ' . (int) $group_id;
+ $this->db->sql_query($sql);
+
+ $this->db->sql_transaction('commit');
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+
+ return true;
+ }
+
+ $this->db->sql_transaction('commit');
+ }
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return false;
+ }
+
+ /**
+ * Moves an item up/down
+ *
+ * @param int $teampage_id teampage_id of the item to be moved
+ * @param int $delta number of steps:
+ * - positive = move up
+ * - negative = move down
+ * @return bool True if the group was moved successfully
+ */
+ public function move_teampage($teampage_id, $delta)
+ {
+ $delta = (int) $delta;
+ if (!$delta)
+ {
+ return false;
+ }
+
+ $move_up = ($delta > 0) ? true : false;
+ $data = $this->get_teampage_values($teampage_id);
+
+ $current_value = (int) $data['teampage_position'];
+ if ($current_value != self::GROUP_DISABLED)
+ {
+ $this->db->sql_transaction('begin');
+
+ if (!$move_up && $data['teampage_parent'] == self::NO_PARENT)
+ {
+ // If we move items down, we need to grab the one sibling more,
+ // so we do not ignore the children of the previous sibling.
+ // We will remove the additional sibling later on.
+ $delta = abs($delta) + 1;
+ }
+
+ $sql = 'SELECT teampage_id, teampage_position
+ FROM ' . TEAMPAGE_TABLE . '
+ WHERE teampage_parent = ' . (int) $data['teampage_parent'] . '
+ AND teampage_position' . (($move_up) ? ' < ' : ' > ') . $current_value . '
+ ORDER BY teampage_position' . (($move_up) ? ' DESC' : ' ASC');
+ $result = $this->db->sql_query_limit($sql, $delta);
+
+ $sibling_count = 0;
+ $sibling_limit = $delta;
+
+ // Reset the delta, as we recalculate the new real delta
+ $delta = 0;
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $sibling_count++;
+ $delta = $current_value - $row['teampage_position'];
+
+ // Remove the additional sibling we added previously
+ // But only, if we included it, this is not be the case
+ // when we reached the end of our list
+ if (!$move_up && $data['teampage_parent'] == self::NO_PARENT && $sibling_count == $sibling_limit)
+ {
+ $delta++;
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ if ($delta)
+ {
+ $sql = 'SELECT COUNT(teampage_id) as num_items
+ FROM ' . TEAMPAGE_TABLE . '
+ WHERE teampage_id = ' . (int) $teampage_id . '
+ OR teampage_parent = ' . (int) $teampage_id;
+ $result = $this->db->sql_query($sql);
+ $num_items = (int) $this->db->sql_fetchfield('num_items');
+ $this->db->sql_freeresult($result);
+
+ // First we move all items between our current value and the target value up/down 1,
+ // so we have a gap for our item to move.
+ $sql = 'UPDATE ' . TEAMPAGE_TABLE . '
+ SET teampage_position = teampage_position' . (($move_up) ? ' + ' : ' - ') . $num_items . '
+ WHERE teampage_position' . (($move_up) ? ' >= ' : ' <= ') . ($current_value - $delta) . '
+ AND teampage_position' . (($move_up) ? ' < ' : ' > ') . $current_value . '
+ AND NOT (teampage_id = ' . (int) $teampage_id . '
+ OR teampage_parent = ' . (int) $teampage_id . ')';
+ $this->db->sql_query($sql);
+
+ $delta = (!$move_up && $data['teampage_parent'] == self::NO_PARENT) ? (abs($delta) - ($num_items - 1)) : abs($delta);
+
+ // And now finally, when we moved some other items and built a gap,
+ // we can move the desired item to it.
+ $sql = 'UPDATE ' . TEAMPAGE_TABLE . '
+ SET teampage_position = teampage_position ' . (($move_up) ? ' - ' : ' + ') . $delta . '
+ WHERE teampage_id = ' . (int) $teampage_id . '
+ OR teampage_parent = ' . (int) $teampage_id;
+ $this->db->sql_query($sql);
+
+ $this->db->sql_transaction('commit');
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+
+ return true;
+ }
+
+ $this->db->sql_transaction('commit');
+ }
+
+ $this->cache->destroy('sql', TEAMPAGE_TABLE);
+ return false;
+ }
+
+ /**
+ * Get group type language var
+ *
+ * @param int $group_type group_type from the groups-table
+ * @return string name of the language variable for the given group-type.
+ */
+ static public function group_type_language($group_type)
+ {
+ switch ($group_type)
+ {
+ case GROUP_OPEN:
+ return 'GROUP_REQUEST';
+ case GROUP_CLOSED:
+ return 'GROUP_CLOSED';
+ case GROUP_HIDDEN:
+ return 'GROUP_HIDDEN';
+ case GROUP_SPECIAL:
+ return 'GROUP_SPECIAL';
+ case GROUP_FREE:
+ return 'GROUP_OPEN';
+ }
+ }
+}
diff --git a/phpBB/includes/hook/finder.php b/phpBB/includes/hook/finder.php
index 065e685514..7b0412f733 100644
--- a/phpBB/includes/hook/finder.php
+++ b/phpBB/includes/hook/finder.php
@@ -66,7 +66,7 @@ class phpbb_hook_finder
{
while (($file = readdir($dh)) !== false)
{
- if (strpos($file, 'hook_') === 0 && substr($file, -(strlen($this->php_ext) + 1)) === '.' . $this->php_ext)
+ if (strpos($file, 'hook_') === 0 && substr($file, -strlen('.' . $this->php_ext)) === '.' . $this->php_ext)
{
$hook_files[] = substr($file, 0, -(strlen($this->php_ext) + 1));
}
diff --git a/phpBB/includes/lock/db.php b/phpBB/includes/lock/db.php
index ccdaed0b28..5cc0821aa0 100644
--- a/phpBB/includes/lock/db.php
+++ b/phpBB/includes/lock/db.php
@@ -117,6 +117,17 @@ class phpbb_lock_db
}
/**
+ * Does this process own the lock?
+ *
+ * @return bool true if lock is owned
+ * false otherwise
+ */
+ public function owns_lock()
+ {
+ return (bool) $this->locked;
+ }
+
+ /**
* Releases the lock.
*
* The lock must have been previously obtained, that is, acquire() call
diff --git a/phpBB/includes/lock/flock.php b/phpBB/includes/lock/flock.php
index 97bc7dd2b9..17de0847c0 100644
--- a/phpBB/includes/lock/flock.php
+++ b/phpBB/includes/lock/flock.php
@@ -111,6 +111,17 @@ class phpbb_lock_flock
}
/**
+ * Does this process own the lock?
+ *
+ * @return bool true if lock is owned
+ * false otherwise
+ */
+ public function owns_lock()
+ {
+ return (bool) $this->lock_fp;
+ }
+
+ /**
* Releases the lock.
*
* The lock must have been previously obtained, that is, acquire() call
diff --git a/phpBB/includes/log/interface.php b/phpBB/includes/log/interface.php
new file mode 100644
index 0000000000..3b459c9bdf
--- /dev/null
+++ b/phpBB/includes/log/interface.php
@@ -0,0 +1,106 @@
+<?php
+/**
+*
+* @package phpbb_log
+* @copyright (c) 2012 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* The interface for the log-system.
+*
+* @package phpbb_log
+*/
+interface phpbb_log_interface
+{
+ /**
+ * This function returns the state of the log system.
+ *
+ * @param string $type The log type we want to check. Empty to get
+ * global log status.
+ *
+ * @return bool True if log for the type is enabled
+ */
+ public function is_enabled($type = '');
+
+ /**
+ * Disable log
+ *
+ * This function allows disabling the log system or parts of it, for this
+ * page call. When add_log is called and the type is disabled,
+ * the log will not be added to the database.
+ *
+ * @param mixed $type The log type we want to disable. Empty to
+ * disable all logs. Can also be an array of types.
+ *
+ * @return null
+ */
+ public function disable($type = '');
+
+ /**
+ * Enable log
+ *
+ * This function allows re-enabling the log system.
+ *
+ * @param mixed $type The log type we want to enable. Empty to
+ * enable all logs. Can also be an array of types.
+ *
+ * @return null
+ */
+ public function enable($type = '');
+
+ /**
+ * Adds a log entry to the database
+ *
+ * @param string $mode The mode defines which log_type is used and from which log the entry is retrieved
+ * @param int $user_id User ID of the user
+ * @param string $log_ip IP address of the user
+ * @param string $log_operation Name of the operation
+ * @param int $log_time Timestamp when the log entry was added, if empty time() will be used
+ * @param array $additional_data More arguments can be added, depending on the log_type
+ *
+ * @return int|bool Returns the log_id, if the entry was added to the database, false otherwise.
+ */
+ public function add($mode, $user_id, $log_ip, $log_operation, $log_time = false, $additional_data = array());
+
+ /**
+ * Grab the logs from the database
+ *
+ * @param string $mode The mode defines which log_type is used and ifrom which log the entry is retrieved
+ * @param bool $count_logs Shall we count all matching log entries?
+ * @param int $limit Limit the number of entries that are returned
+ * @param int $offset Offset when fetching the log entries, f.e. when paginating
+ * @param mixed $forum_id Restrict the log entries to the given forum_id (can also be an array of forum_ids)
+ * @param int $topic_id Restrict the log entries to the given topic_id
+ * @param int $user_id Restrict the log entries to the given user_id
+ * @param int $log_time Only get log entries newer than the given timestamp
+ * @param string $sort_by SQL order option, e.g. 'l.log_time DESC'
+ * @param string $keywords Will only return log entries that have the keywords in log_operation or log_data
+ *
+ * @return array The result array with the logs
+ */
+ public function get_logs($mode, $count_logs = true, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $log_time = 0, $sort_by = 'l.log_time DESC', $keywords = '');
+
+ /**
+ * Get total log count
+ *
+ * @return int Returns the number of matching logs from the last call to get_logs()
+ */
+ public function get_log_count();
+
+ /**
+ * Get offset of the last valid page
+ *
+ * @return int Returns the offset of the last valid page from the last call to get_logs()
+ */
+ public function get_valid_offset();
+}
diff --git a/phpBB/includes/log/log.php b/phpBB/includes/log/log.php
new file mode 100644
index 0000000000..7a26858348
--- /dev/null
+++ b/phpBB/includes/log/log.php
@@ -0,0 +1,739 @@
+<?php
+/**
+*
+* @package phpbb_log
+* @copyright (c) 2012 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* This class is used to add entries into the log table.
+*
+* @package phpbb_log
+*/
+class phpbb_log implements phpbb_log_interface
+{
+ /**
+ * If set, administrative user profile links will be returned and messages
+ * will not be censored.
+ * @var bool
+ */
+ protected $is_in_admin;
+
+ /**
+ * An array with the disabled log types. Logs of such types will not be
+ * added when add_log() is called.
+ * @var array
+ */
+ protected $disabled_types;
+
+ /**
+ * Keeps the total log count of the last call to get_logs()
+ * @var int
+ */
+ protected $entry_count;
+
+ /**
+ * Keeps the offset of the last valid page of the last call to get_logs()
+ * @var int
+ */
+ protected $last_page_offset;
+
+ /**
+ * The table we use to store our logs.
+ * @var string
+ */
+ protected $log_table;
+
+ /**
+ * Database object
+ * @var phpbb_db_driver
+ */
+ protected $db;
+
+ /**
+ * User object
+ * @var phpbb_user
+ */
+ protected $user;
+
+ /**
+ * Auth object
+ * @var phpbb_auth
+ */
+ protected $auth;
+
+ /**
+ * Event dispatcher object
+ * @var phpbb_dispatcher
+ */
+ protected $dispatcher;
+
+ /**
+ * phpBB root path
+ * @var string
+ */
+ protected $phpbb_root_path;
+
+ /**
+ * Admin root path
+ * @var string
+ */
+ protected $phpbb_admin_path;
+
+ /**
+ * PHP Extension
+ * @var string
+ */
+ protected $php_ext;
+
+ /**
+ * Constructor
+ *
+ * @param phpbb_db_driver $db Database object
+ * @param phpbb_user $user User object
+ * @param phpbb_auth $auth Auth object
+ * @param phpbb_dispatcher $phpbb_dispatcher Event dispatcher
+ * @param string $phpbb_root_path Root path
+ * @param string $relative_admin_path Relative admin root path
+ * @param string $php_ext PHP Extension
+ * @param string $log_table Name of the table we use to store our logs
+ * @return null
+ */
+ public function __construct($db, $user, $auth, $phpbb_dispatcher, $phpbb_root_path, $relative_admin_path, $php_ext, $log_table)
+ {
+ $this->db = $db;
+ $this->user = $user;
+ $this->auth = $auth;
+ $this->dispatcher = $phpbb_dispatcher;
+ $this->phpbb_root_path = $phpbb_root_path;
+ $this->phpbb_admin_path = $this->phpbb_root_path . $relative_admin_path;
+ $this->php_ext = $php_ext;
+ $this->log_table = $log_table;
+
+ /*
+ * IN_ADMIN is set after the session is created,
+ * so we need to take ADMIN_START into account as well, otherwise
+ * it will not work for the phpbb_log object we create in common.php
+ */
+ $this->set_is_admin((defined('ADMIN_START') && ADMIN_START) || (defined('IN_ADMIN') && IN_ADMIN));
+ $this->enable();
+ }
+
+ /**
+ * Set is_in_admin in order to return administrative user profile links
+ * in get_logs()
+ *
+ * @param bool $is_in_admin Are we called from within the acp?
+ * @return null
+ */
+ public function set_is_admin($is_in_admin)
+ {
+ $this->is_in_admin = (bool) $is_in_admin;
+ }
+
+ /**
+ * Returns the is_in_admin option
+ *
+ * @return bool
+ */
+ public function get_is_admin()
+ {
+ return $this->is_in_admin;
+ }
+
+ /**
+ * Set table name
+ *
+ * @param string $log_table Can overwrite the table to use for the logs
+ * @return null
+ */
+ public function set_log_table($log_table)
+ {
+ $this->log_table = $log_table;
+ }
+
+ /**
+ * This function returns the state of the log system.
+ *
+ * {@inheritDoc}
+ */
+ public function is_enabled($type = '')
+ {
+ if ($type == '' || $type == 'all')
+ {
+ return !isset($this->disabled_types['all']);
+ }
+ return !isset($this->disabled_types[$type]) && !isset($this->disabled_types['all']);
+ }
+
+ /**
+ * Disable log
+ *
+ * This function allows disabling the log system or parts of it, for this
+ * page call. When add_log is called and the type is disabled,
+ * the log will not be added to the database.
+ *
+ * {@inheritDoc}
+ */
+ public function disable($type = '')
+ {
+ if (is_array($type))
+ {
+ foreach ($type as $disable_type)
+ {
+ $this->disable($disable_type);
+ }
+ return;
+ }
+
+ // Empty string is an equivalent for all types.
+ if ($type == '')
+ {
+ $type = 'all';
+ }
+ $this->disabled_types[$type] = true;
+ }
+
+ /**
+ * Enable log
+ *
+ * This function allows re-enabling the log system.
+ *
+ * {@inheritDoc}
+ */
+ public function enable($type = '')
+ {
+ if (is_array($type))
+ {
+ foreach ($type as $enable_type)
+ {
+ $this->enable($enable_type);
+ }
+ return;
+ }
+
+ if ($type == '' || $type == 'all')
+ {
+ $this->disabled_types = array();
+ return;
+ }
+ unset($this->disabled_types[$type]);
+ }
+
+ /**
+ * Adds a log to the database
+ *
+ * {@inheritDoc}
+ */
+ public function add($mode, $user_id, $log_ip, $log_operation, $log_time = false, $additional_data = array())
+ {
+ if (!$this->is_enabled($mode))
+ {
+ return false;
+ }
+
+ if ($log_time == false)
+ {
+ $log_time = time();
+ }
+
+ $sql_ary = array(
+ 'user_id' => $user_id,
+ 'log_ip' => $log_ip,
+ 'log_time' => $log_time,
+ 'log_operation' => $log_operation,
+ );
+
+ switch ($mode)
+ {
+ case 'admin':
+ $sql_ary += array(
+ 'log_type' => LOG_ADMIN,
+ 'log_data' => (!empty($additional_data)) ? serialize($additional_data) : '',
+ );
+ break;
+
+ case 'mod':
+ $forum_id = (int) $additional_data['forum_id'];
+ unset($additional_data['forum_id']);
+ $topic_id = (int) $additional_data['topic_id'];
+ unset($additional_data['topic_id']);
+ $sql_ary += array(
+ 'log_type' => LOG_MOD,
+ 'forum_id' => $forum_id,
+ 'topic_id' => $topic_id,
+ 'log_data' => (!empty($additional_data)) ? serialize($additional_data) : '',
+ );
+ break;
+
+ case 'user':
+ $reportee_id = (int) $additional_data['reportee_id'];
+ unset($additional_data['reportee_id']);
+
+ $sql_ary += array(
+ 'log_type' => LOG_USERS,
+ 'reportee_id' => $reportee_id,
+ 'log_data' => (!empty($additional_data)) ? serialize($additional_data) : '',
+ );
+ break;
+
+ case 'critical':
+ $sql_ary += array(
+ 'log_type' => LOG_CRITICAL,
+ 'log_data' => (!empty($additional_data)) ? serialize($additional_data) : '',
+ );
+ break;
+ }
+
+ /**
+ * Allows to modify log data before we add it to the database
+ *
+ * NOTE: if sql_ary does not contain a log_type value, the entry will
+ * not be stored in the database. So ensure to set it, if needed.
+ *
+ * @event core.add_log
+ * @var string mode Mode of the entry we log
+ * @var int user_id ID of the user who triggered the log
+ * @var string log_ip IP of the user who triggered the log
+ * @var string log_operation Language key of the log operation
+ * @var int log_time Timestamp, when the log was added
+ * @var array additional_data Array with additional log data
+ * @var array sql_ary Array with log data we insert into the
+ * database. If sql_ary[log_type] is not set,
+ * we won't add the entry to the database.
+ * @since 3.1-A1
+ */
+ $vars = array('mode', 'user_id', 'log_ip', 'log_operation', 'log_time', 'additional_data', 'sql_ary');
+ extract($this->dispatcher->trigger_event('core.add_log', $vars));
+
+ // We didn't find a log_type, so we don't save it in the database.
+ if (!isset($sql_ary['log_type']))
+ {
+ return false;
+ }
+
+ $this->db->sql_query('INSERT INTO ' . $this->log_table . ' ' . $this->db->sql_build_array('INSERT', $sql_ary));
+
+ return $this->db->sql_nextid();
+ }
+
+ /**
+ * Grab the logs from the database
+ *
+ * {@inheritDoc}
+ */
+ public function get_logs($mode, $count_logs = true, $limit = 0, $offset = 0, $forum_id = 0, $topic_id = 0, $user_id = 0, $log_time = 0, $sort_by = 'l.log_time DESC', $keywords = '')
+ {
+ $this->entry_count = 0;
+ $this->last_page_offset = $offset;
+
+ $topic_id_list = $reportee_id_list = array();
+
+ $profile_url = ($this->get_is_admin() && $this->phpbb_admin_path) ? append_sid("{$this->phpbb_admin_path}index.{$this->php_ext}", 'i=users&amp;mode=overview') : append_sid("{$this->phpbb_root_path}memberlist.{$this->php_ext}", 'mode=viewprofile');
+
+ switch ($mode)
+ {
+ case 'admin':
+ $log_type = LOG_ADMIN;
+ $sql_additional = '';
+ break;
+
+ case 'mod':
+ $log_type = LOG_MOD;
+ $sql_additional = '';
+
+ if ($topic_id)
+ {
+ $sql_additional = 'AND l.topic_id = ' . (int) $topic_id;
+ }
+ else if (is_array($forum_id))
+ {
+ $sql_additional = 'AND ' . $this->db->sql_in_set('l.forum_id', array_map('intval', $forum_id));
+ }
+ else if ($forum_id)
+ {
+ $sql_additional = 'AND l.forum_id = ' . (int) $forum_id;
+ }
+ break;
+
+ case 'user':
+ $log_type = LOG_USERS;
+ $sql_additional = 'AND l.reportee_id = ' . (int) $user_id;
+ break;
+
+ case 'users':
+ $log_type = LOG_USERS;
+ $sql_additional = '';
+ break;
+
+ case 'critical':
+ $log_type = LOG_CRITICAL;
+ $sql_additional = '';
+ break;
+
+ default:
+ $log_type = false;
+ $sql_additional = '';
+ }
+
+ /**
+ * Overwrite log type and limitations before we count and get the logs
+ *
+ * NOTE: if log_type is false, no entries will be returned.
+ *
+ * @event core.get_logs_modify_type
+ * @var string mode Mode of the entries we display
+ * @var bool count_logs Do we count all matching entries?
+ * @var int limit Limit the number of entries
+ * @var int offset Offset when fetching the entries
+ * @var mixed forum_id Limit entries to the forum_id,
+ * can also be an array of forum_ids
+ * @var int topic_id Limit entries to the topic_id
+ * @var int user_id Limit entries to the user_id
+ * @var int log_time Limit maximum age of log entries
+ * @var string sort_by SQL order option
+ * @var string keywords Will only return entries that have the
+ * keywords in log_operation or log_data
+ * @var string profile_url URL to the users profile
+ * @var int log_type Limit logs to a certain type. If log_type
+ * is false, no entries will be returned.
+ * @var string sql_additional Additional conditions for the entries,
+ * e.g.: 'AND l.forum_id = 1'
+ * @since 3.1-A1
+ */
+ $vars = array('mode', 'count_logs', 'limit', 'offset', 'forum_id', 'topic_id', 'user_id', 'log_time', 'sort_by', 'keywords', 'profile_url', 'log_type', 'sql_additional');
+ extract($this->dispatcher->trigger_event('core.get_logs_modify_type', $vars));
+
+ if ($log_type === false)
+ {
+ $this->last_page_offset = 0;
+ return array();
+ }
+
+ $sql_keywords = '';
+ if (!empty($keywords))
+ {
+ // Get the SQL condition for our keywords
+ $sql_keywords = $this->generate_sql_keyword($keywords);
+ }
+
+ if ($count_logs)
+ {
+ $sql = 'SELECT COUNT(l.log_id) AS total_entries
+ FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . ' u
+ WHERE l.log_type = ' . (int) $log_type . '
+ AND l.user_id = u.user_id
+ AND l.log_time >= ' . (int) $log_time . "
+ $sql_keywords
+ $sql_additional";
+ $result = $this->db->sql_query($sql);
+ $this->entry_count = (int) $this->db->sql_fetchfield('total_entries');
+ $this->db->sql_freeresult($result);
+
+ if ($this->entry_count == 0)
+ {
+ // Save the queries, because there are no logs to display
+ $this->last_page_offset = 0;
+ return array();
+ }
+
+ // Return the user to the last page that is valid
+ while ($this->last_page_offset >= $this->entry_count)
+ {
+ $this->last_page_offset = max(0, $this->last_page_offset - $limit);
+ }
+ }
+
+ $sql = 'SELECT l.*, u.username, u.username_clean, u.user_colour
+ FROM ' . LOG_TABLE . ' l, ' . USERS_TABLE . ' u
+ WHERE l.log_type = ' . (int) $log_type . '
+ AND u.user_id = l.user_id
+ ' . (($log_time) ? 'AND l.log_time >= ' . (int) $log_time : '') . "
+ $sql_keywords
+ $sql_additional
+ ORDER BY $sort_by";
+ $result = $this->db->sql_query_limit($sql, $limit, $this->last_page_offset);
+
+ $i = 0;
+ $log = array();
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $row['forum_id'] = (int) $row['forum_id'];
+ if ($row['topic_id'])
+ {
+ $topic_id_list[] = (int) $row['topic_id'];
+ }
+
+ if ($row['reportee_id'])
+ {
+ $reportee_id_list[] = (int) $row['reportee_id'];
+ }
+
+ $log_entry_data = array(
+ 'id' => (int) $row['log_id'],
+
+ 'reportee_id' => (int) $row['reportee_id'],
+ 'reportee_username' => '',
+ 'reportee_username_full'=> '',
+
+ 'user_id' => (int) $row['user_id'],
+ 'username' => $row['username'],
+ 'username_full' => get_username_string('full', $row['user_id'], $row['username'], $row['user_colour'], false, $profile_url),
+
+ 'ip' => $row['log_ip'],
+ 'time' => (int) $row['log_time'],
+ 'forum_id' => (int) $row['forum_id'],
+ 'topic_id' => (int) $row['topic_id'],
+
+ 'viewforum' => ($row['forum_id'] && $this->auth->acl_get('f_read', $row['forum_id'])) ? append_sid("{$this->phpbb_root_path}viewforum.{$this->php_ext}", 'f=' . $row['forum_id']) : false,
+ 'action' => (isset($this->user->lang[$row['log_operation']])) ? $this->user->lang[$row['log_operation']] : '{' . ucfirst(str_replace('_', ' ', $row['log_operation'])) . '}',
+ );
+
+ /**
+ * Modify the entry's data before it is returned
+ *
+ * @event core.get_logs_modify_entry_data
+ * @var array row Entry data from the database
+ * @var array log_entry_data Entry's data which is returned
+ * @since 3.1-A1
+ */
+ $vars = array('row', 'log_entry_data');
+ extract($this->dispatcher->trigger_event('core.get_logs_modify_entry_data', $vars));
+
+ $log[$i] = $log_entry_data;
+
+ if (!empty($row['log_data']))
+ {
+ $log_data_ary = unserialize($row['log_data']);
+ $log_data_ary = ($log_data_ary !== false) ? $log_data_ary : array();
+
+ if (isset($this->user->lang[$row['log_operation']]))
+ {
+ // Check if there are more occurrences of % than
+ // arguments, if there are we fill out the arguments
+ // array. It doesn't matter if we add more arguments than
+ // placeholders.
+ if ((substr_count($log[$i]['action'], '%') - sizeof($log_data_ary)) > 0)
+ {
+ $log_data_ary = array_merge($log_data_ary, array_fill(0, substr_count($log[$i]['action'], '%') - sizeof($log_data_ary), ''));
+ }
+
+ $log[$i]['action'] = vsprintf($log[$i]['action'], $log_data_ary);
+
+ // If within the admin panel we do not censor text out
+ if ($this->get_is_admin())
+ {
+ $log[$i]['action'] = bbcode_nl2br($log[$i]['action']);
+ }
+ else
+ {
+ $log[$i]['action'] = bbcode_nl2br(censor_text($log[$i]['action']));
+ }
+ }
+ else if (!empty($log_data_ary))
+ {
+ $log[$i]['action'] .= '<br />' . implode('', $log_data_ary);
+ }
+
+ /* Apply make_clickable... has to be seen if it is for good. :/
+ // Seems to be not for the moment, reconsider later...
+ $log[$i]['action'] = make_clickable($log[$i]['action']);
+ */
+ }
+
+ $i++;
+ }
+ $this->db->sql_freeresult($result);
+
+ /**
+ * Get some additional data after we got all log entries
+ *
+ * @event core.get_logs_get_additional_data
+ * @var array log Array with all our log entries
+ * @var array topic_id_list Array of topic ids, for which we
+ * get the permission data
+ * @var array reportee_id_list Array of additional user IDs we
+ * get the username strings for
+ * @since 3.1-A1
+ */
+ $vars = array('log', 'topic_id_list', 'reportee_id_list');
+ extract($this->dispatcher->trigger_event('core.get_logs_get_additional_data', $vars));
+
+ if (sizeof($topic_id_list))
+ {
+ $topic_auth = $this->get_topic_auth($topic_id_list);
+
+ foreach ($log as $key => $row)
+ {
+ $log[$key]['viewtopic'] = (isset($topic_auth['f_read'][$row['topic_id']])) ? append_sid("{$this->phpbb_root_path}viewtopic.{$this->php_ext}", 'f=' . $topic_auth['f_read'][$row['topic_id']] . '&amp;t=' . $row['topic_id']) : false;
+ $log[$key]['viewlogs'] = (isset($topic_auth['m_'][$row['topic_id']])) ? append_sid("{$this->phpbb_root_path}mcp.{$this->php_ext}", 'i=logs&amp;mode=topic_logs&amp;t=' . $row['topic_id'], true, $this->user->session_id) : false;
+ }
+ }
+
+ if (sizeof($reportee_id_list))
+ {
+ $reportee_data_list = $this->get_reportee_data($reportee_id_list);
+
+ foreach ($log as $key => $row)
+ {
+ if (!isset($reportee_data_list[$row['reportee_id']]))
+ {
+ continue;
+ }
+
+ $log[$key]['reportee_username'] = $reportee_data_list[$row['reportee_id']]['username'];
+ $log[$key]['reportee_username_full'] = get_username_string('full', $row['reportee_id'], $reportee_data_list[$row['reportee_id']]['username'], $reportee_data_list[$row['reportee_id']]['user_colour'], false, $profile_url);
+ }
+ }
+
+ return $log;
+ }
+
+ /**
+ * Generates a sql condition for the specified keywords
+ *
+ * @param string $keywords The keywords the user specified to search for
+ *
+ * @return string Returns the SQL condition searching for the keywords
+ */
+ protected function generate_sql_keyword($keywords)
+ {
+ // Use no preg_quote for $keywords because this would lead to sole
+ // backslashes being added. We also use an OR connection here for
+ // spaces and the | string. Currently, regex is not supported for
+ // searching (but may come later).
+ $keywords = preg_split('#[\s|]+#u', utf8_strtolower($keywords), 0, PREG_SPLIT_NO_EMPTY);
+ $sql_keywords = '';
+
+ if (!empty($keywords))
+ {
+ $keywords_pattern = array();
+
+ // Build pattern and keywords...
+ for ($i = 0, $num_keywords = sizeof($keywords); $i < $num_keywords; $i++)
+ {
+ $keywords_pattern[] = preg_quote($keywords[$i], '#');
+ $keywords[$i] = $this->db->sql_like_expression($this->db->any_char . $keywords[$i] . $this->db->any_char);
+ }
+
+ $keywords_pattern = '#' . implode('|', $keywords_pattern) . '#ui';
+
+ $operations = array();
+ foreach ($this->user->lang as $key => $value)
+ {
+ if (substr($key, 0, 4) == 'LOG_' && preg_match($keywords_pattern, $value))
+ {
+ $operations[] = $key;
+ }
+ }
+
+ $sql_keywords = 'AND (';
+ if (!empty($operations))
+ {
+ $sql_keywords .= $this->db->sql_in_set('l.log_operation', $operations) . ' OR ';
+ }
+ $sql_lower = $this->db->sql_lower_text('l.log_data');
+ $sql_keywords .= " $sql_lower " . implode(" OR $sql_lower ", $keywords) . ')';
+ }
+
+ return $sql_keywords;
+ }
+
+ /**
+ * Determine whether the user is allowed to read and/or moderate the forum of the topic
+ *
+ * @param array $topic_ids Array with the topic ids
+ *
+ * @return array Returns an array with two keys 'm_' and 'read_f' which are also an array of topic_id => forum_id sets when the permissions are given. Sample:
+ * array(
+ * 'permission' => array(
+ * topic_id => forum_id
+ * ),
+ * ),
+ */
+ protected function get_topic_auth(array $topic_ids)
+ {
+ $forum_auth = array('f_read' => array(), 'm_' => array());
+ $topic_ids = array_unique($topic_ids);
+
+ $sql = 'SELECT topic_id, forum_id
+ FROM ' . TOPICS_TABLE . '
+ WHERE ' . $this->db->sql_in_set('topic_id', array_map('intval', $topic_ids));
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $row['topic_id'] = (int) $row['topic_id'];
+ $row['forum_id'] = (int) $row['forum_id'];
+
+ if ($this->auth->acl_get('f_read', $row['forum_id']))
+ {
+ $forum_auth['f_read'][$row['topic_id']] = $row['forum_id'];
+ }
+
+ if ($this->auth->acl_gets('a_', 'm_', $row['forum_id']))
+ {
+ $forum_auth['m_'][$row['topic_id']] = $row['forum_id'];
+ }
+ }
+ $this->db->sql_freeresult($result);
+
+ return $forum_auth;
+ }
+
+ /**
+ * Get the data for all reportee from the database
+ *
+ * @param array $reportee_ids Array with the user ids of the reportees
+ *
+ * @return array Returns an array with the reportee data
+ */
+ protected function get_reportee_data(array $reportee_ids)
+ {
+ $reportee_ids = array_unique($reportee_ids);
+ $reportee_data_list = array();
+
+ $sql = 'SELECT user_id, username, user_colour
+ FROM ' . USERS_TABLE . '
+ WHERE ' . $this->db->sql_in_set('user_id', $reportee_ids);
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $reportee_data_list[$row['user_id']] = $row;
+ }
+ $this->db->sql_freeresult($result);
+
+ return $reportee_data_list;
+ }
+
+ /**
+ * Get total log count
+ *
+ * {@inheritDoc}
+ */
+ public function get_log_count()
+ {
+ return ($this->entry_count) ? $this->entry_count : 0;
+ }
+
+ /**
+ * Get offset of the last valid log page
+ *
+ * {@inheritDoc}
+ */
+ public function get_valid_offset()
+ {
+ return ($this->last_page_offset) ? $this->last_page_offset : 0;
+ }
+}
diff --git a/phpBB/includes/mcp/mcp_notes.php b/phpBB/includes/mcp/mcp_notes.php
index 59cdf3c27e..12fcbfe91e 100644
--- a/phpBB/includes/mcp/mcp_notes.php
+++ b/phpBB/includes/mcp/mcp_notes.php
@@ -173,13 +173,13 @@ class mcp_notes
}
// Generate the appropriate user information for the user we are looking at
- if (!function_exists('get_user_avatar'))
+ if (!function_exists('phpbb_get_user_avatar'))
{
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
}
$rank_title = $rank_img = '';
- $avatar_img = get_user_avatar($userrow['user_avatar'], $userrow['user_avatar_type'], $userrow['user_avatar_width'], $userrow['user_avatar_height']);
+ $avatar_img = phpbb_get_user_avatar($userrow);
$limit_days = array(0 => $user->lang['ALL_ENTRIES'], 1 => $user->lang['1_DAY'], 7 => $user->lang['7_DAYS'], 14 => $user->lang['2_WEEKS'], 30 => $user->lang['1_MONTH'], 90 => $user->lang['3_MONTHS'], 180 => $user->lang['6_MONTHS'], 365 => $user->lang['1_YEAR']);
$sort_by_text = array('a' => $user->lang['SORT_USERNAME'], 'b' => $user->lang['SORT_DATE'], 'c' => $user->lang['SORT_IP'], 'd' => $user->lang['SORT_ACTION']);
diff --git a/phpBB/includes/mcp/mcp_warn.php b/phpBB/includes/mcp/mcp_warn.php
index 6a8fb4c5d5..4ef477775d 100644
--- a/phpBB/includes/mcp/mcp_warn.php
+++ b/phpBB/includes/mcp/mcp_warn.php
@@ -304,13 +304,13 @@ class mcp_warn
$message = smiley_text($message);
// Generate the appropriate user information for the user we are looking at
- if (!function_exists('get_user_avatar'))
+ if (!function_exists('phpbb_get_user_avatar'))
{
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
}
get_user_rank($user_row['user_rank'], $user_row['user_posts'], $rank_title, $rank_img, $rank_img_src);
- $avatar_img = get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height']);
+ $avatar_img = phpbb_get_user_avatar($user_row);
$template->assign_vars(array(
'U_POST_ACTION' => $this->u_action,
@@ -409,13 +409,13 @@ class mcp_warn
}
// Generate the appropriate user information for the user we are looking at
- if (!function_exists('get_user_avatar'))
+ if (!function_exists('phpbb_get_user_avatar'))
{
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
}
get_user_rank($user_row['user_rank'], $user_row['user_posts'], $rank_title, $rank_img, $rank_img_src);
- $avatar_img = get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height']);
+ $avatar_img = phpbb_get_user_avatar($user_row);
// OK, they didn't submit a warning so lets build the page for them to do so
$template->assign_vars(array(
diff --git a/phpBB/includes/notification/exception.php b/phpBB/includes/notification/exception.php
new file mode 100644
index 0000000000..a52d6fdc57
--- /dev/null
+++ b/phpBB/includes/notification/exception.php
@@ -0,0 +1,29 @@
+<?php
+/**
+*
+* @package notifications
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Notifications exception
+*
+* @package notifications
+*/
+class phpbb_notification_exception extends \Exception
+{
+ public function __toString()
+ {
+ return $this->getMessage();
+ }
+}
diff --git a/phpBB/includes/notification/manager.php b/phpBB/includes/notification/manager.php
index ff83d4bb37..97833710c0 100644
--- a/phpBB/includes/notification/manager.php
+++ b/phpBB/includes/notification/manager.php
@@ -36,6 +36,9 @@ class phpbb_notification_manager
/** @var phpbb_db_driver */
protected $db;
+ /** @var phpbb_cache_service */
+ protected $cache;
+
/** @var phpbb_user */
protected $user;
@@ -70,7 +73,7 @@ class phpbb_notification_manager
* @param string $user_notifications_table
* @return phpbb_notification_manager
*/
- public function __construct($notification_types, $notification_methods, $phpbb_container, phpbb_user_loader $user_loader, phpbb_db_driver $db, $user, $phpbb_root_path, $php_ext, $notification_types_table, $notifications_table, $user_notifications_table)
+ public function __construct($notification_types, $notification_methods, $phpbb_container, phpbb_user_loader $user_loader, phpbb_db_driver $db, phpbb_cache_service $cache, $user, $phpbb_root_path, $php_ext, $notification_types_table, $notifications_table, $user_notifications_table)
{
$this->notification_types = $notification_types;
$this->notification_methods = $notification_methods;
@@ -78,6 +81,7 @@ class phpbb_notification_manager
$this->user_loader = $user_loader;
$this->db = $db;
+ $this->cache = $cache;
$this->user = $user;
$this->phpbb_root_path = $phpbb_root_path;
@@ -145,7 +149,7 @@ class phpbb_notification_manager
FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
WHERE n.user_id = ' . (int) $options['user_id'] . '
AND n.notification_read = 0
- AND nt.notification_type = n.item_type
+ AND nt.notification_type_id = n.notification_type_id
AND nt.notification_type_enabled = 1';
$result = $this->db->sql_query($sql);
$unread_count = (int) $this->db->sql_fetchfield('unread_count', $result);
@@ -158,7 +162,7 @@ class phpbb_notification_manager
$sql = 'SELECT COUNT(n.notification_id) AS total_count
FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
WHERE n.user_id = ' . (int) $options['user_id'] . '
- AND nt.notification_type = n.item_type
+ AND nt.notification_type_id = n.notification_type_id
AND nt.notification_type_enabled = 1';
$result = $this->db->sql_query($sql);
$total_count = (int) $this->db->sql_fetchfield('total_count', $result);
@@ -170,11 +174,11 @@ class phpbb_notification_manager
$rowset = array();
// Get the main notifications
- $sql = 'SELECT n.*
+ $sql = 'SELECT n.*, nt.notification_type_name
FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
WHERE n.user_id = ' . (int) $options['user_id'] .
(($options['notification_id']) ? ((is_array($options['notification_id'])) ? ' AND ' . $this->db->sql_in_set('n.notification_id', $options['notification_id']) : ' AND n.notification_id = ' . (int) $options['notification_id']) : '') . '
- AND nt.notification_type = n.item_type
+ AND nt.notification_type_id = n.notification_type_id
AND nt.notification_type_enabled = 1
ORDER BY n.' . $this->db->sql_escape($options['order_by']) . ' ' . $this->db->sql_escape($options['order_dir']);
$result = $this->db->sql_query_limit($sql, $options['limit'], $options['start']);
@@ -188,12 +192,12 @@ class phpbb_notification_manager
// Get all unread notifications
if ($unread_count && $options['all_unread'] && !empty($rowset))
{
- $sql = 'SELECT n.*
+ $sql = 'SELECT n.*, nt.notification_type_name
FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
WHERE n.user_id = ' . (int) $options['user_id'] . '
AND n.notification_read = 0
AND ' . $this->db->sql_in_set('n.notification_id', array_keys($rowset), true) . '
- AND nt.notification_type = n.item_type
+ AND nt.notification_type_id = n.notification_type_id
AND nt.notification_type_enabled = 1
ORDER BY n.' . $this->db->sql_escape($options['order_by']) . ' ' . $this->db->sql_escape($options['order_dir']);
$result = $this->db->sql_query_limit($sql, $options['limit'], $options['start']);
@@ -207,17 +211,17 @@ class phpbb_notification_manager
foreach ($rowset as $row)
{
- $notification = $this->get_item_type_class($row['item_type'], $row);
+ $notification = $this->get_item_type_class($row['notification_type_name'], $row);
// Array of user_ids to query all at once
$user_ids = array_merge($user_ids, $notification->users_to_query());
// Some notification types also require querying additional tables themselves
- if (!isset($load_special[$row['item_type']]))
+ if (!isset($load_special[$row['notification_type_name']]))
{
- $load_special[$row['item_type']] = array();
+ $load_special[$row['notification_type_name']] = array();
}
- $load_special[$row['item_type']] = array_merge($load_special[$row['item_type']], $notification->get_load_special());
+ $load_special[$row['notification_type_name']] = array_merge($load_special[$row['notification_type_name']], $notification->get_load_special());
$notifications[$row['notification_id']] = $notification;
}
@@ -243,19 +247,22 @@ class phpbb_notification_manager
/**
* Mark notifications read
*
- * @param bool|string|array $item_type Type identifier or array of item types (only acceptable if the $data is identical for the specified types). False to mark read for all item types
+ * @param bool|string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types). False to mark read for all item types
* @param bool|int|array $item_id Item id or array of item ids. False to mark read for all item ids
* @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
* @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
*/
- public function mark_notifications_read($item_type, $item_id, $user_id, $time = false)
+ public function mark_notifications_read($notification_type_name, $item_id, $user_id, $time = false)
{
$time = ($time !== false) ? $time : time();
$sql = 'UPDATE ' . $this->notifications_table . "
SET notification_read = 1
WHERE notification_time <= " . (int) $time .
- (($item_type !== false) ? ' AND ' . (is_array($item_type) ? $this->db->sql_in_set('item_type', $item_type) : " item_type = '" . $this->db->sql_escape($item_type) . "'") : '') .
+ (($notification_type_name !== false) ? ' AND ' .
+ (is_array($notification_type_name) ? $this->db->sql_in_set('notification_type_id', $this->get_notification_type_ids($notification_type_name)) : 'notification_type_id = ' . $this->get_notification_type_id($notification_type_name))
+ : '') .
+ (($user_id !== false) ? ' AND ' . (is_array($user_id) ? $this->db->sql_in_set('user_id', $user_id) : 'user_id = ' . (int) $user_id) : '') .
(($item_id !== false) ? ' AND ' . (is_array($item_id) ? $this->db->sql_in_set('item_id', $item_id) : 'item_id = ' . (int) $item_id) : '');
$this->db->sql_query($sql);
}
@@ -263,29 +270,21 @@ class phpbb_notification_manager
/**
* Mark notifications read from a parent identifier
*
- * @param string|array $item_type Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
+ * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
* @param bool|int|array $item_parent_id Item parent id or array of item parent ids. False to mark read for all item parent ids
* @param bool|int|array $user_id User id or array of user ids. False to mark read for all user ids
* @param bool|int $time Time at which to mark all notifications prior to as read. False to mark all as read. (Default: False)
*/
- public function mark_notifications_read_by_parent($item_type, $item_parent_id, $user_id, $time = false)
+ public function mark_notifications_read_by_parent($notification_type_name, $item_parent_id, $user_id, $time = false)
{
- if (is_array($item_type))
- {
- foreach ($item_type as $type)
- {
- $this->mark_notifications_read_by_parent($type, $item_parent_id, $user_id, $time);
- }
-
- return;
- }
-
$time = ($time !== false) ? $time : time();
$sql = 'UPDATE ' . $this->notifications_table . "
SET notification_read = 1
- WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
- AND notification_time <= " . (int) $time .
+ WHERE notification_time <= " . (int) $time .
+ (($notification_type_name !== false) ? ' AND ' .
+ (is_array($notification_type_name) ? $this->db->sql_in_set('notification_type_id', $this->get_notification_type_ids($notification_type_name)) : 'notification_type_id = ' . $this->get_notification_type_id($notification_type_name))
+ : '') .
(($item_parent_id !== false) ? ' AND ' . (is_array($item_parent_id) ? $this->db->sql_in_set('item_parent_id', $item_parent_id) : 'item_parent_id = ' . (int) $item_parent_id) : '') .
(($user_id !== false) ? ' AND ' . (is_array($user_id) ? $this->db->sql_in_set('user_id', $user_id) : 'user_id = ' . (int) $user_id) : '');
$this->db->sql_query($sql);
@@ -311,7 +310,7 @@ class phpbb_notification_manager
/**
* Add a notification
*
- * @param string|array $item_type Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
+ * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
* Note: If you send an array of types, any user who could receive multiple notifications from this single item will only receive
* a single notification. If they MUST receive multiple notifications, call this function multiple times instead of sending an array
* @param array $data Data specific for this type that will be inserted
@@ -319,18 +318,18 @@ class phpbb_notification_manager
* ignore_users array of data to specify which users should not receive certain types of notifications
* @return array Information about what users were notified and how they were notified
*/
- public function add_notifications($item_type, $data, array $options = array())
+ public function add_notifications($notification_type_name, $data, array $options = array())
{
$options = array_merge(array(
'ignore_users' => array(),
), $options);
- if (is_array($item_type))
+ if (is_array($notification_type_name))
{
$notified_users = array();
$temp_options = $options;
- foreach ($item_type as $type)
+ foreach ($notification_type_name as $type)
{
$temp_options['ignore_users'] = $options['ignore_users'] + $notified_users;
$notified_users += $this->add_notifications($type, $data, $temp_options);
@@ -339,12 +338,12 @@ class phpbb_notification_manager
return $notified_users;
}
- $item_id = $this->get_item_type_class($item_type)->get_item_id($data);
+ $item_id = $this->get_item_type_class($notification_type_name)->get_item_id($data);
// find out which users want to receive this type of notification
- $notify_users = $this->get_item_type_class($item_type)->find_users_for_notification($data, $options);
+ $notify_users = $this->get_item_type_class($notification_type_name)->find_users_for_notification($data, $options);
- $this->add_notifications_for_users($item_type, $data, $notify_users);
+ $this->add_notifications_for_users($notification_type_name, $data, $notify_users);
return $notify_users;
}
@@ -352,15 +351,15 @@ class phpbb_notification_manager
/**
* Add a notification for specific users
*
- * @param string|array $item_type Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
+ * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
* @param array $data Data specific for this type that will be inserted
* @param array $notify_users User list to notify
*/
- public function add_notifications_for_users($item_type, $data, $notify_users)
+ public function add_notifications_for_users($notification_type_name, $data, $notify_users)
{
- if (is_array($item_type))
+ if (is_array($notification_type_name))
{
- foreach ($item_type as $type)
+ foreach ($notification_type_name as $type)
{
$this->add_notifications_for_users($type, $data, $notify_users);
}
@@ -368,28 +367,12 @@ class phpbb_notification_manager
return;
}
- $sql = 'SELECT notification_type
- FROM ' . $this->notification_types_table . "
- WHERE notification_type = '" . $this->db->sql_escape($item_type) . "'";
- $result = $this->db->sql_query($sql);
+ $notification_type_id = $this->get_notification_type_id($notification_type_name);
- if ($this->db->sql_fetchrow($result) === false)
- {
- // Does not exist in the database, must add the item type
- $sql = 'INSERT INTO ' . $this->notification_types_table . ' ' . $this->db->sql_build_array('INSERT', array(
- 'notification_type' => $item_type,
- 'notification_type_enabled' => 1,
- ));
- $this->db->sql_query($sql);
- }
-
- $this->db->sql_freeresult($result);
-
- $item_id = $this->get_item_type_class($item_type)->get_item_id($data);
+ $item_id = $this->get_item_type_class($notification_type_name)->get_item_id($data);
$user_ids = array();
$notification_objects = $notification_methods = array();
- $new_rows = array();
// Never send notifications to the anonymous user!
unset($notify_users[ANONYMOUS]);
@@ -397,10 +380,10 @@ class phpbb_notification_manager
// Make sure not to send new notifications to users who've already been notified about this item
// This may happen when an item was added, but now new users are able to see the item
$sql = 'SELECT n.user_id
- FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . " nt
- WHERE n.item_type = '" . $this->db->sql_escape($item_type) . "'
- AND n.item_id = " . (int) $item_id . '
- AND nt.notification_type = n.item_type
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
+ WHERE n.notification_type_id = ' . (int) $notification_type_id . '
+ AND n.item_id = ' . (int) $item_id . '
+ AND nt.notification_type_id = n.notification_type_id
AND nt.notification_type_enabled = 1';
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
@@ -415,19 +398,21 @@ class phpbb_notification_manager
}
// Allow notifications to perform actions before creating the insert array (such as run a query to cache some data needed for all notifications)
- $notification = $this->get_item_type_class($item_type);
+ $notification = $this->get_item_type_class($notification_type_name);
$pre_create_data = $notification->pre_create_insert_array($data, $notify_users);
unset($notification);
+ $insert_buffer = new phpbb_db_sql_insert_buffer($this->db, $this->notifications_table);
+
// Go through each user so we can insert a row in the DB and then notify them by their desired means
foreach ($notify_users as $user => $methods)
{
- $notification = $this->get_item_type_class($item_type);
+ $notification = $this->get_item_type_class($notification_type_name);
$notification->user_id = (int) $user;
- // Store the creation array in our new rows that will be inserted later
- $new_rows[] = $notification->create_insert_array($data, $pre_create_data);
+ // Insert notification row using buffer.
+ $insert_buffer->insert($notification->create_insert_array($data, $pre_create_data));
// Users are needed to send notifications
$user_ids = array_merge($user_ids, $notification->users_to_query());
@@ -447,8 +432,7 @@ class phpbb_notification_manager
}
}
- // insert into the db
- $this->db->sql_multi_insert($this->notifications_table, $new_rows);
+ $insert_buffer->flush();
// We need to load all of the users to send notifications
$this->user_loader->load_users($user_ids);
@@ -463,14 +447,14 @@ class phpbb_notification_manager
/**
* Update a notification
*
- * @param string|array $item_type Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
+ * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $data is identical for the specified types)
* @param array $data Data specific for this type that will be updated
*/
- public function update_notifications($item_type, $data)
+ public function update_notifications($notification_type_name, $data)
{
- if (is_array($item_type))
+ if (is_array($notification_type_name))
{
- foreach ($item_type as $type)
+ foreach ($notification_type_name as $type)
{
$this->update_notifications($type, $data);
}
@@ -478,7 +462,7 @@ class phpbb_notification_manager
return;
}
- $notification = $this->get_item_type_class($item_type);
+ $notification = $this->get_item_type_class($notification_type_name);
// Allow the notifications class to over-ride the update_notifications functionality
if (method_exists($notification, 'update_notifications'))
@@ -490,28 +474,29 @@ class phpbb_notification_manager
}
}
+ $notification_type_id = $this->get_notification_type_id($notification_type_name);
$item_id = $notification->get_item_id($data);
$update_array = $notification->create_update_array($data);
$sql = 'UPDATE ' . $this->notifications_table . '
- SET ' . $this->db->sql_build_array('UPDATE', $update_array) . "
- WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
- AND item_id = " . (int) $item_id;
+ SET ' . $this->db->sql_build_array('UPDATE', $update_array) . '
+ WHERE notification_type_id = ' . (int) $notification_type_id . '
+ AND item_id = ' . (int) $item_id;
$this->db->sql_query($sql);
}
/**
* Delete a notification
*
- * @param string|array $item_type Type identifier or array of item types (only acceptable if the $item_id is identical for the specified types)
+ * @param string|array $notification_type_name Type identifier or array of item types (only acceptable if the $item_id is identical for the specified types)
* @param int|array $item_id Identifier within the type (or array of ids)
* @param array $data Data specific for this type that will be updated
*/
- public function delete_notifications($item_type, $item_id)
+ public function delete_notifications($notification_type_name, $item_id)
{
- if (is_array($item_type))
+ if (is_array($notification_type_name))
{
- foreach ($item_type as $type)
+ foreach ($notification_type_name as $type)
{
$this->delete_notifications($type, $item_id);
}
@@ -519,9 +504,11 @@ class phpbb_notification_manager
return;
}
- $sql = 'DELETE FROM ' . $this->notifications_table . "
- WHERE item_type = '" . $this->db->sql_escape($item_type) . "'
- AND " . (is_array($item_id) ? $this->db->sql_in_set('item_id', $item_id) : 'item_id = ' . (int) $item_id);
+ $notification_type_id = $this->get_notification_type_id($notification_type_name);
+
+ $sql = 'DELETE FROM ' . $this->notifications_table . '
+ WHERE notification_type_id = ' . (int) $notification_type_id . '
+ AND ' . (is_array($item_id) ? $this->db->sql_in_set('item_id', $item_id) : 'item_id = ' . (int) $item_id);
$this->db->sql_query($sql);
}
@@ -654,7 +641,8 @@ class phpbb_notification_manager
{
if ($method !== '')
{
- $this->add_subscription($item_type, $item_type, '', $user_id);
+ // Make sure to subscribe them to the base subscription
+ $this->add_subscription($item_type, $item_id, '', $user_id);
}
$user_id = ($user_id === false) ? $this->user->data['user_id'] : $user_id;
@@ -754,13 +742,13 @@ class phpbb_notification_manager
* is disabled so that all those notifications are hidden and do not
* cause errors
*
- * @param string $item_type Type identifier of the subscription
+ * @param string $notification_type_name Type identifier of the subscription
*/
- public function disable_notifications($item_type)
+ public function disable_notifications($notification_type_name)
{
$sql = 'UPDATE ' . $this->notification_types_table . "
SET notification_type_enabled = 0
- WHERE notification_type = '" . $this->db->sql_escape($item_type) . "'";
+ WHERE notification_type_name = '" . $this->db->sql_escape($notification_type_name) . "'";
$this->db->sql_query($sql);
}
@@ -770,17 +758,21 @@ class phpbb_notification_manager
* This should be called when an extension which has notification types
* is purged so that all those notifications are removed
*
- * @param string $item_type Type identifier of the subscription
+ * @param string $notification_type_name Type identifier of the subscription
*/
- public function purge_notifications($item_type)
+ public function purge_notifications($notification_type_name)
{
- $sql = 'DELETE FROM ' . $this->notifications_table . "
- WHERE item_type = '" . $this->db->sql_escape($item_type) . "'";
+ $notification_type_id = $this->get_notification_type_id($notification_type_name);
+
+ $sql = 'DELETE FROM ' . $this->notifications_table . '
+ WHERE notification_type_id = ' . (int) $notification_type_id;
$this->db->sql_query($sql);
- $sql = 'DELETE FROM ' . $this->notification_types_table . "
- WHERE notification_type = '" . $this->db->sql_escape($item_type) . "'";
+ $sql = 'DELETE FROM ' . $this->notification_types_table . '
+ WHERE notification_type_id = ' . (int) $notification_type_id;
$this->db->sql_query($sql);
+
+ $this->cache->destroy('notification_type_ids');
}
/**
@@ -790,13 +782,13 @@ class phpbb_notification_manager
* that was disabled is re-enabled so that all those notifications that
* were hidden are shown again
*
- * @param string $item_type Type identifier of the subscription
+ * @param string $notification_type_name Type identifier of the subscription
*/
- public function enable_notifications($item_type)
+ public function enable_notifications($notification_type_name)
{
$sql = 'UPDATE ' . $this->notification_types_table . "
SET notification_type_enabled = 1
- WHERE notification_type = '" . $this->db->sql_escape($item_type) . "'";
+ WHERE notification_type_name = '" . $this->db->sql_escape($notification_type_name) . "'";
$this->db->sql_query($sql);
}
@@ -815,11 +807,11 @@ class phpbb_notification_manager
/**
* Helper to get the notifications item type class and set it up
*/
- public function get_item_type_class($item_type, $data = array())
+ public function get_item_type_class($notification_type_name, $data = array())
{
- $item_type = (strpos($item_type, 'notification.type.') === 0) ? $item_type : 'notification.type.' . $item_type;
+ $notification_type_name = (strpos($notification_type_name, 'notification.type.') === 0) ? $notification_type_name : 'notification.type.' . $notification_type_name;
- $item = $this->load_object($item_type);
+ $item = $this->load_object($notification_type_name);
$item->set_initial_data($data);
@@ -850,4 +842,69 @@ class phpbb_notification_manager
return $object;
}
+
+ /**
+ * Get the notification type id from the name
+ *
+ * @param string $notification_type_name The name
+ * @return int the notification_type_id
+ */
+ public function get_notification_type_id($notification_type_name)
+ {
+ $notification_type_ids = $this->cache->get('notification_type_ids');
+
+ if ($notification_type_ids === false)
+ {
+ $notification_type_ids = array();
+
+ $sql = 'SELECT notification_type_id, notification_type_name
+ FROM ' . $this->notification_types_table;
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $notification_type_ids[$row['notification_type_name']] = (int) $row['notification_type_id'];
+ }
+ $this->db->sql_freeresult($result);
+
+ $this->cache->put('notification_type_ids', $notification_type_ids);
+ }
+
+ if (!isset($notification_type_ids[$notification_type_name]))
+ {
+ if (!isset($this->notification_types[$notification_type_name]) && !isset($this->notification_types['notification.type.' . $notification_type_name]))
+ {
+ throw new phpbb_notification_exception($this->user->lang('NOTIFICATION_TYPE_NOT_EXIST', $notification_type_name));
+ }
+
+ $sql = 'INSERT INTO ' . $this->notification_types_table . ' ' . $this->db->sql_build_array('INSERT', array(
+ 'notification_type_name' => $notification_type_name,
+ 'notification_type_enabled' => 1,
+ ));
+ $this->db->sql_query($sql);
+
+ $notification_type_ids[$notification_type_name] = (int) $this->db->sql_nextid();
+
+ $this->cache->put('notification_type_ids', $notification_type_ids);
+ }
+
+ return $notification_type_ids[$notification_type_name];
+ }
+
+ /**
+ * Get notification type ids (as an array)
+ *
+ * @param array $notification_type_names Array of strings
+ * @return array Array of integers
+ */
+ public function get_notification_type_ids(array $notification_type_names)
+ {
+ $notification_type_ids = array();
+
+ foreach ($notification_type_names as $name)
+ {
+ $notification_type_ids[$name] = $this->get_notification_type_id($name);
+ }
+
+ return $notification_type_ids;
+ }
}
diff --git a/phpBB/includes/notification/method/base.php b/phpBB/includes/notification/method/base.php
index 22418c9be8..b633956d01 100644
--- a/phpBB/includes/notification/method/base.php
+++ b/phpBB/includes/notification/method/base.php
@@ -30,7 +30,7 @@ abstract class phpbb_notification_method_base implements phpbb_notification_meth
/** @var phpbb_db_driver */
protected $db;
- /** @var phpbb_cache_service */
+ /** @var phpbb_cache_driver_interface */
protected $cache;
/** @var phpbb_template */
diff --git a/phpBB/includes/notification/method/email.php b/phpBB/includes/notification/method/email.php
index 429dfda2ba..571b0ec656 100644
--- a/phpBB/includes/notification/method/email.php
+++ b/phpBB/includes/notification/method/email.php
@@ -21,7 +21,7 @@ if (!defined('IN_PHPBB'))
*
* @package notifications
*/
-class phpbb_notification_method_email extends phpbb_notification_method_base
+class phpbb_notification_method_email extends phpbb_notification_method_messenger_base
{
/**
* Get notification method name
@@ -34,27 +34,12 @@ class phpbb_notification_method_email extends phpbb_notification_method_base
}
/**
- * Notify method (since jabber gets sent through the same messenger, we let the jabber class inherit from this to reduce code duplication)
- *
- * @var mixed
- */
- protected $notify_method = NOTIFY_EMAIL;
-
- /**
- * Base directory to prepend to the email template name
- *
- * @var string
- */
- protected $email_template_base_dir = '';
-
- /**
* Is this method available for the user?
* This is checked on the notifications options
*/
public function is_available()
{
- // Email is always available
- return true;
+ return $this->config['email_enable'] && $this->user->data['user_email'];
}
/**
@@ -62,68 +47,6 @@ class phpbb_notification_method_email extends phpbb_notification_method_base
*/
public function notify()
{
- if (!sizeof($this->queue))
- {
- return;
- }
-
- // Load all users we want to notify (we need their email address)
- $user_ids = $users = array();
- foreach ($this->queue as $notification)
- {
- $user_ids[] = $notification->user_id;
- }
-
- // We do not send emails to banned users
- if (!function_exists('phpbb_get_banned_user_ids'))
- {
- include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
- }
- $banned_users = phpbb_get_banned_user_ids($user_ids);
-
- // Load all the users we need
- $this->user_loader->load_users($user_ids);
-
- // Load the messenger
- if (!class_exists('messenger'))
- {
- include($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext);
- }
- $messenger = new messenger();
- $board_url = generate_board_url();
-
- // Time to go through the queue and send emails
- foreach ($this->queue as $notification)
- {
- if ($notification->get_email_template() === false)
- {
- continue;
- }
-
- $user = $this->user_loader->get_user($notification->user_id);
-
- if ($user['user_type'] == USER_IGNORE || in_array($notification->user_id, $banned_users))
- {
- continue;
- }
-
- $messenger->template($this->email_template_base_dir . $notification->get_email_template(), $user['user_lang']);
-
- $messenger->to($user['user_email'], $user['username']);
-
- $messenger->assign_vars(array_merge(array(
- 'USERNAME' => $user['username'],
-
- 'U_NOTIFICATION_SETTINGS' => generate_board_url() . '/ucp.' . $this->php_ext . '?i=ucp_notifications',
- ), $notification->get_email_template_variables()));
-
- $messenger->send($this->notify_method);
- }
-
- // Save the queue in the messenger class (has to be called or these emails could be lost?)
- $messenger->save_queue();
-
- // We're done, empty the queue
- $this->empty_queue();
+ return $this->notify_using_messenger(NOTIFY_EMAIL);
}
}
diff --git a/phpBB/includes/notification/method/jabber.php b/phpBB/includes/notification/method/jabber.php
index e3eb571fbc..d3b756d020 100644
--- a/phpBB/includes/notification/method/jabber.php
+++ b/phpBB/includes/notification/method/jabber.php
@@ -21,7 +21,7 @@ if (!defined('IN_PHPBB'))
*
* @package notifications
*/
-class phpbb_notification_method_jabber extends phpbb_notification_method_email
+class phpbb_notification_method_jabber extends phpbb_notification_method_messenger_base
{
/**
* Get notification method name
@@ -34,26 +34,12 @@ class phpbb_notification_method_jabber extends phpbb_notification_method_email
}
/**
- * Notify method (since jabber gets sent through the same messenger, we let the jabber class inherit from this to reduce code duplication)
- *
- * @var mixed
- */
- protected $notify_method = NOTIFY_IM;
-
- /**
- * Base directory to prepend to the email template name
- *
- * @var string
- */
- protected $email_template_base_dir = 'short/';
-
- /**
* Is this method available for the user?
* This is checked on the notifications options
*/
public function is_available()
{
- return ($this->global_available() && $this->user->data['jabber']);
+ return ($this->global_available() && $this->user->data['user_jabber']);
}
/**
@@ -62,7 +48,13 @@ class phpbb_notification_method_jabber extends phpbb_notification_method_email
*/
public function global_available()
{
- return ($this->config['jab_enable'] && @extension_loaded('xml'));
+ return !(
+ empty($this->config['jab_enable']) ||
+ empty($this->config['jab_host']) ||
+ empty($this->config['jab_username']) ||
+ empty($this->config['jab_password']) ||
+ !@extension_loaded('xml')
+ );
}
public function notify()
@@ -72,6 +64,6 @@ class phpbb_notification_method_jabber extends phpbb_notification_method_email
return;
}
- return parent::notify();
+ return $this->notify_using_messenger(NOTIFY_IM, 'short/');
}
}
diff --git a/phpBB/includes/notification/method/messenger_base.php b/phpBB/includes/notification/method/messenger_base.php
new file mode 100644
index 0000000000..4966aa94bc
--- /dev/null
+++ b/phpBB/includes/notification/method/messenger_base.php
@@ -0,0 +1,100 @@
+<?php
+/**
+*
+* @package notifications
+* @copyright (c) 2012 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+/**
+* Abstract notification method handling email and jabber notifications
+* using the phpBB messenger.
+*
+* @package notifications
+*/
+abstract class phpbb_notification_method_messenger_base extends phpbb_notification_method_base
+{
+ /**
+ * Notify using phpBB messenger
+ *
+ * @param int $notify_method Notify method for messenger (e.g. NOTIFY_IM)
+ * @param string $template_dir_prefix Base directory to prepend to the email template name
+ *
+ * @return null
+ */
+ protected function notify_using_messenger($notify_method, $template_dir_prefix = '')
+ {
+ if (empty($this->queue))
+ {
+ return;
+ }
+
+ // Load all users we want to notify (we need their email address)
+ $user_ids = $users = array();
+ foreach ($this->queue as $notification)
+ {
+ $user_ids[] = $notification->user_id;
+ }
+
+ // We do not send emails to banned users
+ if (!function_exists('phpbb_get_banned_user_ids'))
+ {
+ include($this->phpbb_root_path . 'includes/functions_user.' . $this->php_ext);
+ }
+ $banned_users = phpbb_get_banned_user_ids($user_ids);
+
+ // Load all the users we need
+ $this->user_loader->load_users($user_ids);
+
+ // Load the messenger
+ if (!class_exists('messenger'))
+ {
+ include($this->phpbb_root_path . 'includes/functions_messenger.' . $this->php_ext);
+ }
+ $messenger = new messenger();
+ $board_url = generate_board_url();
+
+ // Time to go through the queue and send emails
+ foreach ($this->queue as $notification)
+ {
+ if ($notification->get_email_template() === false)
+ {
+ continue;
+ }
+
+ $user = $this->user_loader->get_user($notification->user_id);
+
+ if ($user['user_type'] == USER_IGNORE || in_array($notification->user_id, $banned_users))
+ {
+ continue;
+ }
+
+ $messenger->template($template_dir_prefix . $notification->get_email_template(), $user['user_lang']);
+
+ $messenger->set_addresses($user);
+
+ $messenger->assign_vars(array_merge(array(
+ 'USERNAME' => $user['username'],
+
+ 'U_NOTIFICATION_SETTINGS' => generate_board_url() . '/ucp.' . $this->php_ext . '?i=ucp_notifications',
+ ), $notification->get_email_template_variables()));
+
+ $messenger->send($notify_method);
+ }
+
+ // Save the queue in the messenger class (has to be called or these emails could be lost?)
+ $messenger->save_queue();
+
+ // We're done, empty the queue
+ $this->empty_queue();
+ }
+}
diff --git a/phpBB/includes/notification/type/base.php b/phpBB/includes/notification/type/base.php
index 600ef7c965..46517f1c9b 100644
--- a/phpBB/includes/notification/type/base.php
+++ b/phpBB/includes/notification/type/base.php
@@ -30,7 +30,7 @@ abstract class phpbb_notification_type_base implements phpbb_notification_type_i
/** @var phpbb_db_driver */
protected $db;
- /** @var phpbb_cache_service */
+ /** @var phpbb_cache_driver_interface */
protected $cache;
/** @var phpbb_template */
@@ -69,10 +69,18 @@ abstract class phpbb_notification_type_base implements phpbb_notification_type_i
public static $notification_option = false;
/**
+ * The notification_type_id, set upon creation of the class
+ * This is the notification_type_id from the notification_types table
+ *
+ * @var int
+ */
+ protected $notification_type_id;
+
+ /**
* Indentification data
- * item_type - Type of the item (translates to the notification type)
- * item_id - ID of the item (e.g. post_id, msg_id)
- * item_parent_id - Parent item id (ex: for topic => forum_id, for post => topic_id, etc)
+ * notification_type_id - ID of the item type (auto generated, from notification types table)
+ * item_id - ID of the item (e.g. post_id, msg_id)
+ * item_parent_id - Parent item id (ex: for topic => forum_id, for post => topic_id, etc)
* user_id
* notification_read
* notification_time
@@ -124,6 +132,8 @@ abstract class phpbb_notification_type_base implements phpbb_notification_type_i
public function set_notification_manager(phpbb_notification_manager $notification_manager)
{
$this->notification_manager = $notification_manager;
+
+ $this->notification_type_id = $this->notification_manager->get_notification_type_id($this->get_type());
}
/**
@@ -211,7 +221,7 @@ abstract class phpbb_notification_type_base implements phpbb_notification_type_i
// Defaults
$this->data = array_merge(array(
'item_id' => static::get_item_id($type_data),
- 'item_type' => $this->get_type(),
+ 'notification_type_id' => $this->notification_type_id,
'item_parent_id' => static::get_item_parent_id($type_data),
'notification_time' => time(),
@@ -460,7 +470,7 @@ abstract class phpbb_notification_type_base implements phpbb_notification_type_i
$this->notification_read = (bool) !$unread;
$where = array(
- "item_type = '" . $this->db->sql_escape($this->item_type) . "'",
+ 'notification_type_id = ' . (int) $this->notification_type_id,
'item_id = ' . (int) $this->item_id,
'user_id = ' . (int) $this->user_id,
);
diff --git a/phpBB/includes/notification/type/bookmark.php b/phpBB/includes/notification/type/bookmark.php
index 4e48a967d0..ae2e75d3eb 100644
--- a/phpBB/includes/notification/type/bookmark.php
+++ b/phpBB/includes/notification/type/bookmark.php
@@ -89,6 +89,7 @@ class phpbb_notification_type_bookmark extends phpbb_notification_type_post
{
return array();
}
+ sort($users);
$auth_read = $this->auth->acl_get_list($users, 'f_read', $post['forum_id']);
@@ -102,11 +103,11 @@ class phpbb_notification_type_bookmark extends phpbb_notification_type_post
// Try to find the users who already have been notified about replies and have not read the topic since and just update their notifications
$update_notifications = array();
$sql = 'SELECT n.*
- FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . " nt
- WHERE n.item_type = '" . $this->get_type() . "'
- AND n.item_parent_id = " . (int) self::get_item_parent_id($post) . '
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
+ WHERE n.notification_type_id = ' . (int) $this->notification_type_id . '
+ AND n.item_parent_id = ' . (int) self::get_item_parent_id($post) . '
AND n.notification_read = 0
- AND nt.notification_type = n.item_type
+ AND nt.notification_type_id = n.notification_type_id
AND nt.notification_type_enabled = 1';
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
diff --git a/phpBB/includes/notification/type/post.php b/phpBB/includes/notification/type/post.php
index ddfa720e5e..9207fd866e 100644
--- a/phpBB/includes/notification/type/post.php
+++ b/phpBB/includes/notification/type/post.php
@@ -106,11 +106,26 @@ class phpbb_notification_type_post extends phpbb_notification_type_base
}
$this->db->sql_freeresult($result);
+ $sql = 'SELECT user_id
+ FROM ' . FORUMS_WATCH_TABLE . '
+ WHERE forum_id = ' . (int) $post['forum_id'] . '
+ AND notify_status = ' . NOTIFY_YES . '
+ AND user_id <> ' . (int) $post['poster_id'];
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $users[] = $row['user_id'];
+ }
+ $this->db->sql_freeresult($result);
+
if (empty($users))
{
return array();
}
+ $users = array_unique($users);
+ sort($users);
+
$auth_read = $this->auth->acl_get_list($users, 'f_read', $post['forum_id']);
if (empty($auth_read))
@@ -123,11 +138,11 @@ class phpbb_notification_type_post extends phpbb_notification_type_base
// Try to find the users who already have been notified about replies and have not read the topic since and just update their notifications
$update_notifications = array();
$sql = 'SELECT n.*
- FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . " nt
- WHERE n.item_type = '" . $this->get_type() . "'
- AND n.item_parent_id = " . (int) self::get_item_parent_id($post) . '
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
+ WHERE n.notification_type_id = ' . (int) $this->notification_type_id . '
+ AND n.item_parent_id = ' . (int) self::get_item_parent_id($post) . '
AND n.notification_read = 0
- AND nt.notification_type = n.item_type
+ AND nt.notification_type_id = n.notification_type_id
AND nt.notification_type_enabled = 1';
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
@@ -216,7 +231,7 @@ class phpbb_notification_type_post extends phpbb_notification_type_base
}
else
{
- $username = $this->user_loader->get_username($this->get_data('poster_id'), 'no_profile');
+ $username = $this->user_loader->get_username($this->get_data('poster_id'), 'username');
}
return array(
diff --git a/phpBB/includes/notification/type/post_in_queue.php b/phpBB/includes/notification/type/post_in_queue.php
index 1c29bee3cd..bc4b15cdc3 100644
--- a/phpBB/includes/notification/type/post_in_queue.php
+++ b/phpBB/includes/notification/type/post_in_queue.php
@@ -64,9 +64,9 @@ class phpbb_notification_type_post_in_queue extends phpbb_notification_type_post
*/
public function is_available()
{
- $m_approve = $this->auth->acl_getf($this->permission, true);
+ $has_permission = $this->auth->acl_getf($this->permission, true);
- return (!empty($m_approve));
+ return (!empty($has_permission));
}
/**
@@ -82,7 +82,7 @@ class phpbb_notification_type_post_in_queue extends phpbb_notification_type_post
'ignore_users' => array(),
), $options);
- // 0 is for global
+ // 0 is for global moderator permissions
$auth_approve = $this->auth->acl_get_list(false, $this->permission, array($post['forum_id'], 0));
if (empty($auth_approve))
@@ -90,9 +90,26 @@ class phpbb_notification_type_post_in_queue extends phpbb_notification_type_post
return array();
}
- $auth_approve[$post['forum_id']] = array_unique(array_merge($auth_approve[$post['forum_id']], $auth_approve[0]));
+ $has_permission = array();
- return $this->check_user_notification_options($auth_approve[$post['forum_id']][$this->permission], array_merge($options, array(
+ if (isset($auth_approve[$post['forum_id']][$this->permission]))
+ {
+ $has_permission = $auth_approve[$post['forum_id']][$this->permission];
+ }
+
+ if (isset($auth_approve[0][$this->permission]))
+ {
+ $has_permission = array_unique(array_merge($has_permission, $auth_approve[0][$this->permission]));
+ }
+ sort($has_permission);
+
+ $auth_read = $this->auth->acl_get_list($has_permission, 'f_read', $post['forum_id']);
+ if (empty($auth_read))
+ {
+ return array();
+ }
+
+ return $this->check_user_notification_options($auth_read[$post['forum_id']]['f_read'], array_merge($options, array(
'item_type' => self::$notification_option['id'],
)));
}
diff --git a/phpBB/includes/notification/type/quote.php b/phpBB/includes/notification/type/quote.php
index 5453b267c8..0ed13f36fb 100644
--- a/phpBB/includes/notification/type/quote.php
+++ b/phpBB/includes/notification/type/quote.php
@@ -108,6 +108,7 @@ class phpbb_notification_type_quote extends phpbb_notification_type_post
{
return array();
}
+ sort($users);
$auth_read = $this->auth->acl_get_list($users, 'f_read', $post['forum_id']);
@@ -121,11 +122,11 @@ class phpbb_notification_type_quote extends phpbb_notification_type_post
// Try to find the users who already have been notified about replies and have not read the topic since and just update their notifications
$update_notifications = array();
$sql = 'SELECT n.*
- FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . " nt
- WHERE n.item_type = '" . $this->get_type() . "'
- AND n.item_parent_id = " . (int) self::get_item_parent_id($post) . '
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
+ WHERE n.notification_type_id = ' . (int) $this->notification_type_id . '
+ AND n.item_parent_id = ' . (int) self::get_item_parent_id($post) . '
AND n.notification_read = 0
- AND nt.notification_type = n.item_type
+ AND nt.notification_type_id = n.notification_type_id
AND nt.notification_type_enabled = 1';
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
@@ -153,10 +154,10 @@ class phpbb_notification_type_quote extends phpbb_notification_type_post
{
$old_notifications = array();
$sql = 'SELECT n.user_id
- FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . " nt
- WHERE n.item_type = '" . $this->get_type() . "'
- AND n.item_id = " . self::get_item_id($post) . '
- AND nt.notification_type = n.item_type
+ FROM ' . $this->notifications_table . ' n, ' . $this->notification_types_table . ' nt
+ WHERE n.notification_type_id = ' . (int) $this->notification_type_id . '
+ AND n.item_id = ' . self::get_item_id($post) . '
+ AND nt.notification_type_id = n.notification_type_id
AND nt.notification_type_enabled = 1';
$result = $this->db->sql_query($sql);
while ($row = $this->db->sql_fetchrow($result))
@@ -184,9 +185,9 @@ class phpbb_notification_type_quote extends phpbb_notification_type_post
// Remove the necessary notifications
if (!empty($remove_notifications))
{
- $sql = 'DELETE FROM ' . $this->notifications_table . "
- WHERE item_type = '" . $this->get_type() . "'
- AND item_id = " . self::get_item_id($post) . '
+ $sql = 'DELETE FROM ' . $this->notifications_table . '
+ WHERE notification_type_id = ' . (int) $this->notification_type_id . '
+ AND item_id = ' . self::get_item_id($post) . '
AND ' . $this->db->sql_in_set('user_id', $remove_notifications);
$this->db->sql_query($sql);
}
diff --git a/phpBB/includes/notification/type/topic.php b/phpBB/includes/notification/type/topic.php
index 2549b29409..22436d3fb1 100644
--- a/phpBB/includes/notification/type/topic.php
+++ b/phpBB/includes/notification/type/topic.php
@@ -178,7 +178,7 @@ class phpbb_notification_type_topic extends phpbb_notification_type_base
}
else
{
- $username = $this->user_loader->get_username($this->get_data('poster_id'), 'no_profile');
+ $username = $this->user_loader->get_username($this->get_data('poster_id'), 'username');
}
return array(
diff --git a/phpBB/includes/notification/type/topic_in_queue.php b/phpBB/includes/notification/type/topic_in_queue.php
index dc0b9f9869..f735e10c00 100644
--- a/phpBB/includes/notification/type/topic_in_queue.php
+++ b/phpBB/includes/notification/type/topic_in_queue.php
@@ -53,13 +53,20 @@ class phpbb_notification_type_topic_in_queue extends phpbb_notification_type_top
);
/**
+ * Permission to check for (in find_users_for_notification)
+ *
+ * @var string Permission name
+ */
+ protected $permission = 'm_approve';
+
+ /**
* Is available
*/
public function is_available()
{
- $m_approve = $this->auth->acl_getf('m_approve', true);
+ $has_permission = $this->auth->acl_getf($this->permission, true);
- return (!empty($m_approve));
+ return (!empty($has_permission));
}
/**
@@ -75,7 +82,7 @@ class phpbb_notification_type_topic_in_queue extends phpbb_notification_type_top
'ignore_users' => array(),
), $options);
- // 0 is for global
+ // 0 is for global moderator permissions
$auth_approve = $this->auth->acl_get_list(false, 'm_approve', array($topic['forum_id'], 0));
if (empty($auth_approve))
@@ -83,9 +90,26 @@ class phpbb_notification_type_topic_in_queue extends phpbb_notification_type_top
return array();
}
- $auth_approve[$topic['forum_id']] = array_unique(array_merge($auth_approve[$topic['forum_id']], $auth_approve[0]));
+ $has_permission = array();
+
+ if (isset($auth_approve[$topic['forum_id']][$this->permission]))
+ {
+ $has_permission = $auth_approve[$topic['forum_id']][$this->permission];
+ }
+
+ if (isset($auth_approve[0][$this->permission]))
+ {
+ $has_permission = array_unique(array_merge($has_permission, $auth_approve[0][$this->permission]));
+ }
+ sort($has_permission);
+
+ $auth_read = $this->auth->acl_get_list($has_permission, 'f_read', $topic['forum_id']);
+ if (empty($auth_read))
+ {
+ return array();
+ }
- return $this->check_user_notification_options($auth_approve[$topic['forum_id']]['m_approve'], array_merge($options, array(
+ return $this->check_user_notification_options($auth_read[$topic['forum_id']]['f_read'], array_merge($options, array(
'item_type' => self::$notification_option['id'],
)));
}
diff --git a/phpBB/includes/search/fulltext_native.php b/phpBB/includes/search/fulltext_native.php
index c9f33054fc..b9c784ea67 100644
--- a/phpBB/includes/search/fulltext_native.php
+++ b/phpBB/includes/search/fulltext_native.php
@@ -1819,11 +1819,11 @@ class phpbb_search_fulltext_native extends phpbb_search_base
</dl>
<dl>
<dt><label for="fulltext_native_min_chars">' . $this->user->lang['MIN_SEARCH_CHARS'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['MIN_SEARCH_CHARS_EXPLAIN'] . '</span></dt>
- <dd><input id="fulltext_native_min_chars" type="text" size="3" maxlength="3" name="config[fulltext_native_min_chars]" value="' . (int) $this->config['fulltext_native_min_chars'] . '" /></dd>
+ <dd><input id="fulltext_native_min_chars" type="number" size="3" maxlength="3" min="0" max="255" name="config[fulltext_native_min_chars]" value="' . (int) $this->config['fulltext_native_min_chars'] . '" /></dd>
</dl>
<dl>
<dt><label for="fulltext_native_max_chars">' . $this->user->lang['MAX_SEARCH_CHARS'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['MAX_SEARCH_CHARS_EXPLAIN'] . '</span></dt>
- <dd><input id="fulltext_native_max_chars" type="text" size="3" maxlength="3" name="config[fulltext_native_max_chars]" value="' . (int) $this->config['fulltext_native_max_chars'] . '" /></dd>
+ <dd><input id="fulltext_native_max_chars" type="number" size="3" maxlength="3" min="0" max="255" name="config[fulltext_native_max_chars]" value="' . (int) $this->config['fulltext_native_max_chars'] . '" /></dd>
</dl>
<dl>
<dt><label for="fulltext_native_common_thres">' . $this->user->lang['COMMON_WORD_THRESHOLD'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['COMMON_WORD_THRESHOLD_EXPLAIN'] . '</span></dt>
diff --git a/phpBB/includes/search/fulltext_postgres.php b/phpBB/includes/search/fulltext_postgres.php
index eeb628b18f..496a29f5a3 100644
--- a/phpBB/includes/search/fulltext_postgres.php
+++ b/phpBB/includes/search/fulltext_postgres.php
@@ -214,7 +214,7 @@ class phpbb_search_fulltext_postgres extends phpbb_search_base
{
if ($terms == 'all')
{
- $match = array('#\sand\s#iu', '#\sor\s#iu', '#\snot\s#iu', '#\+#', '#-#', '#\|#');
+ $match = array('#\sand\s#iu', '#\sor\s#iu', '#\snot\s#iu', '#(^|\s)\+#', '#(^|\s)-#', '#(^|\s)\|#');
$replace = array(' +', ' |', ' -', ' +', ' -', ' |');
$keywords = preg_replace($match, $replace, $keywords);
@@ -970,11 +970,11 @@ class phpbb_search_fulltext_postgres extends phpbb_search_base
</dl>
<dl>
<dt><label for="fulltext_postgres_min_word_len">' . $this->user->lang['FULLTEXT_POSTGRES_MIN_WORD_LEN'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_POSTGRES_MIN_WORD_LEN_EXPLAIN'] . '</span></dt>
- <dd><input id="fulltext_postgres_min_word_len" type="text" size="3" maxlength="3" name="config[fulltext_postgres_min_word_len]" value="' . (int) $this->config['fulltext_postgres_min_word_len'] . '" /></dd>
+ <dd><input id="fulltext_postgres_min_word_len" type="number" size="3" maxlength="3" min="0" max="255" name="config[fulltext_postgres_min_word_len]" value="' . (int) $this->config['fulltext_postgres_min_word_len'] . '" /></dd>
</dl>
<dl>
<dt><label for="fulltext_postgres_max_word_len">' . $this->user->lang['FULLTEXT_POSTGRES_MAX_WORD_LEN'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_POSTGRES_MAX_WORD_LEN_EXPLAIN'] . '</span></dt>
- <dd><input id="fulltext_postgres_max_word_len" type="text" size="3" maxlength="3" name="config[fulltext_postgres_max_word_len]" value="' . (int) $this->config['fulltext_postgres_max_word_len'] . '" /></dd>
+ <dd><input id="fulltext_postgres_max_word_len" type="number" size="3" maxlength="3" min="0" max="255" name="config[fulltext_postgres_max_word_len]" value="' . (int) $this->config['fulltext_postgres_max_word_len'] . '" /></dd>
</dl>
';
diff --git a/phpBB/includes/search/fulltext_sphinx.php b/phpBB/includes/search/fulltext_sphinx.php
index 48445d0794..63e35eb4af 100644
--- a/phpBB/includes/search/fulltext_sphinx.php
+++ b/phpBB/includes/search/fulltext_sphinx.php
@@ -258,13 +258,13 @@ class phpbb_search_fulltext_sphinx
$config_object = new phpbb_search_sphinx_config($this->config_file_data);
$config_data = array(
'source source_phpbb_' . $this->id . '_main' => array(
- array('type', $this->dbtype),
+ array('type', $this->dbtype . ' # mysql or pgsql'),
// This config value sql_host needs to be changed incase sphinx and sql are on different servers
- array('sql_host', $dbhost),
+ array('sql_host', $dbhost . ' # SQL server host sphinx connects to'),
array('sql_user', $dbuser),
array('sql_pass', $dbpasswd),
array('sql_db', $dbname),
- array('sql_port', $dbport),
+ array('sql_port', $dbport . ' # optional, default is 3306 for mysql and 5432 for pgsql'),
array('sql_query_pre', 'SET NAMES \'utf8\''),
array('sql_query_pre', 'UPDATE ' . SPHINX_TABLE . ' SET max_doc_id = (SELECT MAX(post_id) FROM ' . POSTS_TABLE . ') WHERE counter_id = 1'),
array('sql_query_range', 'SELECT MIN(post_id), MAX(post_id) FROM ' . POSTS_TABLE . ''),
@@ -888,11 +888,11 @@ class phpbb_search_fulltext_sphinx
</dl>
<dl>
<dt><label for="fulltext_sphinx_port">' . $this->user->lang['FULLTEXT_SPHINX_PORT'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_SPHINX_PORT_EXPLAIN'] . '</span></dt>
- <dd><input id="fulltext_sphinx_port" type="text" size="4" maxlength="10" name="config[fulltext_sphinx_port]" value="' . $this->config['fulltext_sphinx_port'] . '" /></dd>
+ <dd><input id="fulltext_sphinx_port" type="number" size="4" maxlength="10" name="config[fulltext_sphinx_port]" value="' . $this->config['fulltext_sphinx_port'] . '" /></dd>
</dl>
<dl>
<dt><label for="fulltext_sphinx_indexer_mem_limit">' . $this->user->lang['FULLTEXT_SPHINX_INDEXER_MEM_LIMIT'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_SPHINX_INDEXER_MEM_LIMIT_EXPLAIN'] . '</span></dt>
- <dd><input id="fulltext_sphinx_indexer_mem_limit" type="text" size="4" maxlength="10" name="config[fulltext_sphinx_indexer_mem_limit]" value="' . $this->config['fulltext_sphinx_indexer_mem_limit'] . '" /> ' . $this->user->lang['MIB'] . '</dd>
+ <dd><input id="fulltext_sphinx_indexer_mem_limit" type="number" size="4" maxlength="10" name="config[fulltext_sphinx_indexer_mem_limit]" value="' . $this->config['fulltext_sphinx_indexer_mem_limit'] . '" /> ' . $this->user->lang['MIB'] . '</dd>
</dl>
<dl>
<dt><label for="fulltext_sphinx_config_file">' . $this->user->lang['FULLTEXT_SPHINX_CONFIG_FILE'] . $this->user->lang['COLON'] . '</label><br /><span>' . $this->user->lang['FULLTEXT_SPHINX_CONFIG_FILE_EXPLAIN'] . '</span></dt>
diff --git a/phpBB/includes/search/sphinx/config_variable.php b/phpBB/includes/search/sphinx/config_variable.php
index 35abe281cb..2c1d35a49c 100644
--- a/phpBB/includes/search/sphinx/config_variable.php
+++ b/phpBB/includes/search/sphinx/config_variable.php
@@ -75,6 +75,6 @@ class phpbb_search_sphinx_config_variable
*/
function to_string()
{
- return "\t" . $this->name . ' = ' . str_replace("\n", "\\\n", $this->value) . ' ' . $this->comment . "\n";
+ return "\t" . $this->name . ' = ' . str_replace("\n", " \\\n", $this->value) . ' ' . $this->comment . "\n";
}
}
diff --git a/phpBB/includes/style/extension_path_provider.php b/phpBB/includes/style/extension_path_provider.php
index 6976a45ed0..ec1d85f821 100644
--- a/phpBB/includes/style/extension_path_provider.php
+++ b/phpBB/includes/style/extension_path_provider.php
@@ -40,17 +40,22 @@ class phpbb_style_extension_path_provider extends phpbb_extension_provider imple
*/
protected $base_path_provider;
+ /** @var string */
+ protected $phpbb_root_path;
+
/**
* Constructor stores extension manager
*
* @param phpbb_extension_manager $extension_manager phpBB extension manager
* @param phpbb_style_path_provider $base_path_provider A simple path provider
* to provide paths to be located in extensions
+ * @param string $phpbb_root_path phpBB root path
*/
- public function __construct(phpbb_extension_manager $extension_manager, phpbb_style_path_provider $base_path_provider)
+ public function __construct(phpbb_extension_manager $extension_manager, phpbb_style_path_provider $base_path_provider, $phpbb_root_path)
{
parent::__construct($extension_manager);
$this->base_path_provider = $base_path_provider;
+ $this->phpbb_root_path = $phpbb_root_path;
}
/**
@@ -91,10 +96,23 @@ class phpbb_style_extension_path_provider extends phpbb_extension_provider imple
$directories['style'][] = $path;
if ($path && !phpbb_is_absolute($path))
{
+ // Remove phpBB root path from the style path,
+ // so the finder is able to find extension styles,
+ // when the root path is not ./
+ if (strpos($path, $this->phpbb_root_path) === 0)
+ {
+ $path = substr($path, strlen($this->phpbb_root_path));
+ }
+
$result = $finder->directory('/' . $this->ext_dir_prefix . $path)
->get_directories(true, false, true);
foreach ($result as $ext => $ext_path)
{
+ // Make sure $ext_path has no ending slash
+ if (substr($ext_path, -1) === '/')
+ {
+ $ext_path = substr($ext_path, 0, -1);
+ }
$directories[$ext][] = $ext_path;
}
}
diff --git a/phpBB/includes/template/compile.php b/phpBB/includes/template/compile.php
index fcdaf7abda..76cb3011df 100644
--- a/phpBB/includes/template/compile.php
+++ b/phpBB/includes/template/compile.php
@@ -33,6 +33,13 @@ class phpbb_template_compile
private $filter_params;
/**
+ * Array of default parameters
+ *
+ * @var array
+ */
+ private $default_filter_params;
+
+ /**
* Constructor.
*
* @param bool $allow_php Whether PHP code will be allowed in templates (inline PHP code, PHP tag and INCLUDEPHP tag)
@@ -44,18 +51,40 @@ class phpbb_template_compile
*/
public function __construct($allow_php, $style_names, $locator, $phpbb_root_path, $extension_manager = null, $user = null)
{
- $this->filter_params = array(
- 'allow_php' => $allow_php,
- 'style_names' => $style_names,
- 'locator' => $locator,
+ $this->filter_params = $this->default_filter_params = array(
+ 'allow_php' => $allow_php,
+ 'style_names' => $style_names,
+ 'locator' => $locator,
'phpbb_root_path' => $phpbb_root_path,
'extension_manager' => $extension_manager,
- 'user' => $user,
+ 'user' => $user,
'template_compile' => $this,
+ 'cleanup' => true,
);
}
/**
+ * Set filter parameters
+ *
+ * @param array $params Array of parameters (will be merged onto $this->filter_params)
+ */
+ public function set_filter_params($params)
+ {
+ $this->filter_params = array_merge(
+ $this->filter_params,
+ $params
+ );
+ }
+
+ /**
+ * Reset filter parameters to their default settings
+ */
+ public function reset_filter_params()
+ {
+ $this->filter_params = $this->default_filter_params;
+ }
+
+ /**
* Compiles template in $source_file and writes compiled template to
* cache directory
*
diff --git a/phpBB/includes/template/filter.php b/phpBB/includes/template/filter.php
index f73ad28ba1..f2bd442010 100644
--- a/phpBB/includes/template/filter.php
+++ b/phpBB/includes/template/filter.php
@@ -76,6 +76,14 @@ class phpbb_template_filter extends php_user_filter
private $allow_php;
/**
+ * Whether cleanup will be performed on resulting code, see compile()
+ * (Preserve whitespace)
+ *
+ * @var bool
+ */
+ private $cleanup = true;
+
+ /**
* Resource locator.
*
* @var phpbb_template_locator
@@ -183,6 +191,7 @@ class phpbb_template_filter extends php_user_filter
$this->phpbb_root_path = $this->params['phpbb_root_path'];
$this->style_names = $this->params['style_names'];
$this->extension_manager = $this->params['extension_manager'];
+ $this->cleanup = $this->params['cleanup'];
if (isset($this->params['user']))
{
$this->user = $this->params['user'];
@@ -223,9 +232,16 @@ class phpbb_template_filter extends php_user_filter
$data = preg_replace('~<!-- ENDPHP -->.*?$~', '', $data);
}
- /*
+ if ($this->cleanup)
+ {
+ /*
+
Preserve whitespace.
- PHP removes a newline after the closing tag (if it's there). This is by design.
+ PHP removes a newline after the closing tag (if it's there).
+ This is by design:
+
+ http://www.php.net/manual/en/language.basic-syntax.phpmode.php
+ http://www.php.net/manual/en/language.basic-syntax.instruction-separation.php
Consider the following template:
@@ -234,24 +250,27 @@ class phpbb_template_filter extends php_user_filter
some content
<!-- ENDIF -->
- If we were to simply preserve all whitespace, we could simply replace all "?>" tags
- with "?>\n".
- Doing that, would add additional newlines to the compiled tempalte in place of the
- IF and ENDIF statements. These newlines are unwanted (and one is conditional).
- The IF and ENDIF are usually on their own line for ease of reading.
+ If we were to simply preserve all whitespace, we could simply
+ replace all "?>" tags with "?>\n".
+ Doing that, would add additional newlines to the compiled
+ template in place of the IF and ENDIF statements. These
+ newlines are unwanted (and one is conditional). The IF and
+ ENDIF are usually on their own line for ease of reading.
- This replacement preserves newlines only for statements that aren't the only statement on a line.
- It will NOT preserve newlines at the end of statements in the above examle.
+ This replacement preserves newlines only for statements that
+ are not the only statement on a line. It will NOT preserve
+ newlines at the end of statements in the above example.
It will preserve newlines in situations like:
<!-- IF condition -->inline content<!-- ENDIF -->
+ */
- */
+ $data = preg_replace('~(?<!^)(<\?php.+(?<!/\*\*/)\?>)$~m', "$1\n", $data);
+ $data = str_replace('/**/?>', "?>\n", $data);
+ $data = str_replace('?><?php', '', $data);
+ }
- $data = preg_replace('~(?<!^)(<\?php.+(?<!/\*\*/)\?>)$~m', "$1\n", $data);
- $data = str_replace('/**/?>', "?>\n", $data);
- $data = str_replace('?><?php', '', $data);
return $data;
}
@@ -329,6 +348,10 @@ class phpbb_template_filter extends php_user_filter
return '<?php ' . $this->compile_tag_define($matches[2], false) . ' ?>';
break;
+ case 'ENDDEFINE':
+ return '<?php ' . $this->compile_tag_enddefine() . ' ?>';
+ break;
+
case 'INCLUDE':
return '<?php ' . $this->compile_tag_include($matches[2]) . ' ?>';
break;
@@ -833,6 +856,16 @@ class phpbb_template_filter extends php_user_filter
$match = array();
preg_match('#^((?:' . self::REGEX_NS . '\.)+)?\$(?=[A-Z])([A-Z0-9_\-]*)(?: = (.*?))?$#', $tag_args, $match);
+ if (!empty($match[2]) && !isset($match[3]) && $op)
+ {
+ // DEFINE tag with ENDDEFINE
+ $array = "\$_tpldata['DEFINE']['.vars']";
+ $code = 'ob_start(); ';
+ $code .= "if (!isset($array)) { $array = array(); } ";
+ $code .= "{$array}[] = '{$match[2]}'";
+ return $code;
+ }
+
if (empty($match[2]) || (!isset($match[3]) && $op))
{
return '';
@@ -843,12 +876,37 @@ class phpbb_template_filter extends php_user_filter
return 'unset(' . (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ');';
}
- $parsed_statement = implode(' ', $this->compile_expression($match[3]));
+ /*
+ * Define tags that contain template variables (enclosed in curly brackets)
+ * need to be treated differently.
+ */
+ if (substr($match[3], 1, 1) == '{' && substr($match[3], -2, 1) == '}')
+ {
+ $parsed_statement = implode(' ', $this->compile_expression(substr($match[3], 2, -2)));
+ }
+ else
+ {
+ $parsed_statement = implode(' ', $this->compile_expression($match[3]));
+ }
return (($match[1]) ? $this->generate_block_data_ref(substr($match[1], 0, -1), true, true) . '[\'' . $match[2] . '\']' : '$_tpldata[\'DEFINE\'][\'.\'][\'' . $match[2] . '\']') . ' = ' . $parsed_statement . ';';
}
/**
+ * Compile ENDDEFINE tag
+ *
+ * @return string compiled template code
+ */
+ private function compile_tag_enddefine()
+ {
+ $array = "\$_tpldata['DEFINE']['.vars']";
+ $code = "if (!isset($array) || !sizeof($array)) { trigger_error('ENDDEFINE tag without DEFINE in ' . basename(__FILE__), E_USER_ERROR); }";
+ $code .= "\$define_var = array_pop($array); ";
+ $code .= "\$_tpldata['DEFINE']['.'][\$define_var] = ob_get_clean();";
+ return $code;
+ }
+
+ /**
* Compile INCLUDE tag
*
* @param string $tag_args Expression given with INCLUDE in source template
@@ -950,8 +1008,14 @@ class phpbb_template_filter extends php_user_filter
$all_compiled = '';
foreach ($files as $file)
{
+ $this->template_compile->set_filter_params(array(
+ 'cleanup' => false,
+ ));
+
$compiled = $this->template_compile->compile_file($file);
+ $this->template_compile->reset_filter_params();
+
if ($compiled === false)
{
if ($this->user)
diff --git a/phpBB/includes/tree/interface.php b/phpBB/includes/tree/interface.php
new file mode 100644
index 0000000000..cc8aab2115
--- /dev/null
+++ b/phpBB/includes/tree/interface.php
@@ -0,0 +1,122 @@
+<?php
+/**
+*
+* @package tree
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+interface phpbb_tree_interface
+{
+ /**
+ * Inserts an item into the database table and into the tree.
+ *
+ * @param array $item The item to be added
+ * @return array Array with item data as set in the database
+ */
+ public function insert(array $additional_data);
+
+ /**
+ * Delete an item from the tree and from the database table
+ *
+ * Also deletes the subtree from the tree and from the database table
+ *
+ * @param int $item_id The item to be deleted
+ * @return array Item ids that have been deleted
+ */
+ public function delete($item_id);
+
+ /**
+ * Move an item by a given delta
+ *
+ * An item is only moved up/down within the same parent. If the delta is
+ * larger then the number of children, the item is moved to the top/bottom
+ * of the list of children within this parent.
+ *
+ * @param int $item_id The item to be moved
+ * @param int $delta Number of steps to move this item, < 0 => down, > 0 => up
+ * @return bool True if the item was moved
+ */
+ public function move($item_id, $delta);
+
+ /**
+ * Move an item down by 1
+ *
+ * @param int $item_id The item to be moved
+ * @return bool True if the item was moved
+ */
+ public function move_down($item_id);
+
+ /**
+ * Move an item up by 1
+ *
+ * @param int $item_id The item to be moved
+ * @return bool True if the item was moved
+ */
+ public function move_up($item_id);
+
+ /**
+ * Moves all children of one item to another item
+ *
+ * If the new parent already has children, the new children are appended
+ * to the list.
+ *
+ * @param int $current_parent_id The current parent item
+ * @param int $new_parent_id The new parent item
+ * @return bool True if any items where moved
+ */
+ public function move_children($current_parent_id, $new_parent_id);
+
+ /**
+ * Change parent item
+ *
+ * Moves the item to the bottom of the new parent's list of children
+ *
+ * @param int $item_id The item to be moved
+ * @param int $new_parent_id The new parent item
+ * @return bool True if the parent was set successfully
+ */
+ public function change_parent($item_id, $new_parent_id);
+
+ /**
+ * Get all items that are either ancestors or descendants of the item
+ *
+ * @param int $item_id Id of the item to retrieve the ancestors/descendants from
+ * @param bool $order_asc Order the items ascendingly (most outer ancestor first)
+ * @param bool $include_item Should the item matching the given item id be included in the list as well
+ * @return array Array of items (containing all columns from the item table)
+ * ID => Item data
+ */
+ public function get_path_and_subtree_data($item_id, $order_asc, $include_item);
+
+ /**
+ * Get all of the item's ancestors
+ *
+ * @param int $item_id Id of the item to retrieve the ancestors from
+ * @param bool $order_asc Order the items ascendingly (most outer ancestor first)
+ * @param bool $include_item Should the item matching the given item id be included in the list as well
+ * @return array Array of items (containing all columns from the item table)
+ * ID => Item data
+ */
+ public function get_path_data($item_id, $order_asc, $include_item);
+
+ /**
+ * Get all of the item's descendants
+ *
+ * @param int $item_id Id of the item to retrieve the descendants from
+ * @param bool $order_asc Order the items ascendingly
+ * @param bool $include_item Should the item matching the given item id be included in the list as well
+ * @return array Array of items (containing all columns from the item table)
+ * ID => Item data
+ */
+ public function get_subtree_data($item_id, $order_asc, $include_item);
+}
diff --git a/phpBB/includes/tree/nestedset.php b/phpBB/includes/tree/nestedset.php
new file mode 100644
index 0000000000..4d851a87a8
--- /dev/null
+++ b/phpBB/includes/tree/nestedset.php
@@ -0,0 +1,850 @@
+<?php
+/**
+*
+* @package tree
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+abstract class phpbb_tree_nestedset implements phpbb_tree_interface
+{
+ /** @var phpbb_db_driver */
+ protected $db;
+
+ /** @var phpbb_lock_db */
+ protected $lock;
+
+ /** @var string */
+ protected $table_name;
+
+ /**
+ * Prefix for the language keys returned by exceptions
+ * @var string
+ */
+ protected $message_prefix = '';
+
+ /**
+ * Column names in the table
+ * @var string
+ */
+ protected $column_item_id = 'item_id';
+ protected $column_left_id = 'left_id';
+ protected $column_right_id = 'right_id';
+ protected $column_parent_id = 'parent_id';
+ protected $column_item_parents = 'item_parents';
+
+ /**
+ * Additional SQL restrictions
+ * Allows to have multiple nested sets in one table
+ * @var string
+ */
+ protected $sql_where = '';
+
+ /**
+ * List of item properties to be cached in the item_parents column
+ * @var array
+ */
+ protected $item_basic_data = array('*');
+
+ /**
+ * Construct
+ *
+ * @param phpbb_db_driver $db Database connection
+ * @param phpbb_lock_db $lock Lock class used to lock the table when moving forums around
+ * @param string $table_name Table name
+ * @param string $message_prefix Prefix for the messages thrown by exceptions
+ * @param string $sql_where Additional SQL restrictions for the queries
+ * @param array $item_basic_data Array with basic item data that is stored in item_parents
+ * @param array $columns Array with column names to overwrite
+ */
+ public function __construct(phpbb_db_driver $db, phpbb_lock_db $lock, $table_name, $message_prefix = '', $sql_where = '', $item_basic_data = array(), $columns = array())
+ {
+ $this->db = $db;
+ $this->lock = $lock;
+
+ $this->table_name = $table_name;
+ $this->message_prefix = $message_prefix;
+ $this->sql_where = $sql_where;
+ $this->item_basic_data = (!empty($item_basic_data)) ? $item_basic_data : array('*');
+
+ if (!empty($columns))
+ {
+ foreach ($columns as $column => $name)
+ {
+ $column_name = 'column_' . $column;
+ $this->$column_name = $name;
+ }
+ }
+ }
+
+ /**
+ * Returns additional sql where restrictions
+ *
+ * @param string $operator SQL operator that needs to be prepended to sql_where,
+ * if it is not empty.
+ * @param string $column_prefix Prefix that needs to be prepended to column names
+ * @return string Returns additional where statements to narrow down the tree,
+ * prefixed with operator and prepended column_prefix to column names
+ */
+ public function get_sql_where($operator = 'AND', $column_prefix = '')
+ {
+ return (!$this->sql_where) ? '' : $operator . ' ' . sprintf($this->sql_where, $column_prefix);
+ }
+
+ /**
+ * Acquires a lock on the item table
+ *
+ * @return bool True if the lock was acquired, false if it has been acquired previously
+ *
+ * @throws RuntimeException If the lock could not be acquired
+ */
+ protected function acquire_lock()
+ {
+ if ($this->lock->owns_lock())
+ {
+ return false;
+ }
+
+ if (!$this->lock->acquire())
+ {
+ throw new RuntimeException($this->message_prefix . 'LOCK_FAILED_ACQUIRE');
+ }
+
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function insert(array $additional_data)
+ {
+ $item_data = $this->reset_nestedset_values($additional_data);
+
+ $sql = 'INSERT INTO ' . $this->table_name . ' ' . $this->db->sql_build_array('INSERT', $item_data);
+ $this->db->sql_query($sql);
+
+ $item_data[$this->column_item_id] = (int) $this->db->sql_nextid();
+
+ return array_merge($item_data, $this->add_item_to_nestedset($item_data[$this->column_item_id]));
+ }
+
+ /**
+ * Add an item which already has a database row at the end of the tree
+ *
+ * @param int $item_id The item to be added
+ * @return array Array with updated data, if the item was added successfully
+ * Empty array otherwise
+ */
+ protected function add_item_to_nestedset($item_id)
+ {
+ $sql = 'SELECT MAX(' . $this->column_right_id . ') AS ' . $this->column_right_id . '
+ FROM ' . $this->table_name . '
+ ' . $this->get_sql_where('WHERE');
+ $result = $this->db->sql_query($sql);
+ $current_max_right_id = (int) $this->db->sql_fetchfield($this->column_right_id);
+ $this->db->sql_freeresult($result);
+
+ $update_item_data = array(
+ $this->column_parent_id => 0,
+ $this->column_left_id => $current_max_right_id + 1,
+ $this->column_right_id => $current_max_right_id + 2,
+ $this->column_item_parents => '',
+ );
+
+ $sql = 'UPDATE ' . $this->table_name . '
+ SET ' . $this->db->sql_build_array('UPDATE', $update_item_data) . '
+ WHERE ' . $this->column_item_id . ' = ' . (int) $item_id . '
+ AND ' . $this->column_parent_id . ' = 0
+ AND ' . $this->column_left_id . ' = 0
+ AND ' . $this->column_right_id . ' = 0';
+ $this->db->sql_query($sql);
+
+ return ($this->db->sql_affectedrows() == 1) ? $update_item_data : array();
+ }
+
+ /**
+ * Remove an item from the tree without deleting it from the database
+ *
+ * Also removes all subitems from the tree without deleting them from the database either
+ *
+ * @param int $item_id The item to be deleted
+ * @return array Item ids that have been removed
+ */
+ protected function remove_item_from_nestedset($item_id)
+ {
+ $item_id = (int) $item_id;
+ if (!$item_id)
+ {
+ throw new OutOfBoundsException($this->message_prefix . 'INVALID_ITEM');
+ }
+
+ $items = $this->get_subtree_data($item_id);
+ $item_ids = array_keys($items);
+
+ if (empty($items) || !isset($items[$item_id]))
+ {
+ throw new OutOfBoundsException($this->message_prefix . 'INVALID_ITEM');
+ }
+
+ $this->remove_subset($item_ids, $items[$item_id]);
+
+ return $item_ids;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function delete($item_id)
+ {
+ $removed_items = $this->remove_item_from_nestedset($item_id);
+
+ $sql = 'DELETE FROM ' . $this->table_name . '
+ WHERE ' . $this->db->sql_in_set($this->column_item_id, $removed_items) . '
+ ' . $this->get_sql_where('AND');
+ $this->db->sql_query($sql);
+
+ return $removed_items;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function move($item_id, $delta)
+ {
+ if ($delta == 0)
+ {
+ return false;
+ }
+
+ $this->acquire_lock();
+
+ $action = ($delta > 0) ? 'move_up' : 'move_down';
+ $delta = abs($delta);
+
+ // Keep $this->get_sql_where() here, to ensure we are in the right tree.
+ $sql = 'SELECT *
+ FROM ' . $this->table_name . '
+ WHERE ' . $this->column_item_id . ' = ' . (int) $item_id . '
+ ' . $this->get_sql_where();
+ $result = $this->db->sql_query_limit($sql, $delta);
+ $item = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if (!$item)
+ {
+ $this->lock->release();
+ throw new OutOfBoundsException($this->message_prefix . 'INVALID_ITEM');
+ }
+
+ /**
+ * Fetch all the siblings between the item's current spot
+ * and where we want to move it to. If there are less than $delta
+ * siblings between the current spot and the target then the
+ * item will move as far as possible
+ */
+ $sql = "SELECT {$this->column_item_id}, {$this->column_parent_id}, {$this->column_left_id}, {$this->column_right_id}, {$this->column_item_parents}
+ FROM " . $this->table_name . '
+ WHERE ' . $this->column_parent_id . ' = ' . (int) $item[$this->column_parent_id] . '
+ ' . $this->get_sql_where() . '
+ AND ';
+
+ if ($action == 'move_up')
+ {
+ $sql .= $this->column_right_id . ' < ' . (int) $item[$this->column_right_id] . ' ORDER BY ' . $this->column_right_id . ' DESC';
+ }
+ else
+ {
+ $sql .= $this->column_left_id . ' > ' . (int) $item[$this->column_left_id] . ' ORDER BY ' . $this->column_left_id . ' ASC';
+ }
+
+ $result = $this->db->sql_query_limit($sql, $delta);
+
+ $target = false;
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $target = $row;
+ }
+ $this->db->sql_freeresult($result);
+
+ if (!$target)
+ {
+ $this->lock->release();
+ // The item is already on top or bottom
+ return false;
+ }
+
+ /**
+ * $left_id and $right_id define the scope of the items that are affected by the move.
+ * $diff_up and $diff_down are the values to substract or add to each item's left_id
+ * and right_id in order to move them up or down.
+ * $move_up_left and $move_up_right define the scope of the items that are moving
+ * up. Other items in the scope of ($left_id, $right_id) are considered to move down.
+ */
+ if ($action == 'move_up')
+ {
+ $left_id = (int) $target[$this->column_left_id];
+ $right_id = (int) $item[$this->column_right_id];
+
+ $diff_up = (int) $item[$this->column_left_id] - (int) $target[$this->column_left_id];
+ $diff_down = (int) $item[$this->column_right_id] + 1 - (int) $item[$this->column_left_id];
+
+ $move_up_left = (int) $item[$this->column_left_id];
+ $move_up_right = (int) $item[$this->column_right_id];
+ }
+ else
+ {
+ $left_id = (int) $item[$this->column_left_id];
+ $right_id = (int) $target[$this->column_right_id];
+
+ $diff_up = (int) $item[$this->column_right_id] + 1 - (int) $item[$this->column_left_id];
+ $diff_down = (int) $target[$this->column_right_id] - (int) $item[$this->column_right_id];
+
+ $move_up_left = (int) $item[$this->column_right_id] + 1;
+ $move_up_right = (int) $target[$this->column_right_id];
+ }
+
+ // Now do the dirty job
+ $sql = 'UPDATE ' . $this->table_name . '
+ SET ' . $this->column_left_id . ' = ' . $this->column_left_id . ' + CASE
+ WHEN ' . $this->column_left_id . " BETWEEN {$move_up_left} AND {$move_up_right} THEN -{$diff_up}
+ ELSE {$diff_down}
+ END,
+ " . $this->column_right_id . ' = ' . $this->column_right_id . ' + CASE
+ WHEN ' . $this->column_right_id . " BETWEEN {$move_up_left} AND {$move_up_right} THEN -{$diff_up}
+ ELSE {$diff_down}
+ END
+ WHERE
+ " . $this->column_left_id . " BETWEEN {$left_id} AND {$right_id}
+ AND " . $this->column_right_id . " BETWEEN {$left_id} AND {$right_id}
+ " . $this->get_sql_where();
+ $this->db->sql_query($sql);
+
+ $this->lock->release();
+
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function move_down($item_id)
+ {
+ return $this->move($item_id, -1);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function move_up($item_id)
+ {
+ return $this->move($item_id, 1);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function move_children($current_parent_id, $new_parent_id)
+ {
+ $current_parent_id = (int) $current_parent_id;
+ $new_parent_id = (int) $new_parent_id;
+
+ if ($current_parent_id == $new_parent_id)
+ {
+ return false;
+ }
+
+ if (!$current_parent_id)
+ {
+ throw new OutOfBoundsException($this->message_prefix . 'INVALID_ITEM');
+ }
+
+ $this->acquire_lock();
+
+ $item_data = $this->get_subtree_data($current_parent_id);
+ if (!isset($item_data[$current_parent_id]))
+ {
+ $this->lock->release();
+ throw new OutOfBoundsException($this->message_prefix . 'INVALID_ITEM');
+ }
+
+ $current_parent = $item_data[$current_parent_id];
+ unset($item_data[$current_parent_id]);
+ $move_items = array_keys($item_data);
+
+ if (($current_parent[$this->column_right_id] - $current_parent[$this->column_left_id]) <= 1)
+ {
+ $this->lock->release();
+ return false;
+ }
+
+ if (in_array($new_parent_id, $move_items))
+ {
+ $this->lock->release();
+ throw new OutOfBoundsException($this->message_prefix . 'INVALID_PARENT');
+ }
+
+ $diff = sizeof($move_items) * 2;
+ $sql_exclude_moved_items = $this->db->sql_in_set($this->column_item_id, $move_items, true);
+
+ $this->db->sql_transaction('begin');
+
+ $this->remove_subset($move_items, $current_parent, false, true);
+
+ if ($new_parent_id)
+ {
+ // Retrieve new-parent again, it may have been changed...
+ $sql = 'SELECT *
+ FROM ' . $this->table_name . '
+ WHERE ' . $this->column_item_id . ' = ' . $new_parent_id;
+ $result = $this->db->sql_query($sql);
+ $new_parent = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if (!$new_parent)
+ {
+ $this->db->sql_transaction('rollback');
+ $this->lock->release();
+ throw new OutOfBoundsException($this->message_prefix . 'INVALID_PARENT');
+ }
+
+ $new_right_id = $this->prepare_adding_subset($move_items, $new_parent, true);
+
+ if ($new_right_id > $current_parent[$this->column_right_id])
+ {
+ $diff = ' + ' . ($new_right_id - $current_parent[$this->column_right_id]);
+ }
+ else
+ {
+ $diff = ' - ' . abs($new_right_id - $current_parent[$this->column_right_id]);
+ }
+ }
+ else
+ {
+ $sql = 'SELECT MAX(' . $this->column_right_id . ') AS ' . $this->column_right_id . '
+ FROM ' . $this->table_name . '
+ WHERE ' . $sql_exclude_moved_items . '
+ ' . $this->get_sql_where('AND');
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $diff = ' + ' . ($row[$this->column_right_id] - $current_parent[$this->column_left_id]);
+ }
+
+ $sql = 'UPDATE ' . $this->table_name . '
+ SET ' . $this->column_left_id . ' = ' . $this->column_left_id . $diff . ',
+ ' . $this->column_right_id . ' = ' . $this->column_right_id . $diff . ',
+ ' . $this->column_parent_id . ' = ' . $this->db->sql_case($this->column_parent_id . ' = ' . $current_parent_id, $new_parent_id, $this->column_parent_id) . ',
+ ' . $this->column_item_parents . " = ''
+ WHERE " . $this->db->sql_in_set($this->column_item_id, $move_items) . '
+ ' . $this->get_sql_where('AND');
+ $this->db->sql_query($sql);
+
+ $this->db->sql_transaction('commit');
+ $this->lock->release();
+
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function change_parent($item_id, $new_parent_id)
+ {
+ $item_id = (int) $item_id;
+ $new_parent_id = (int) $new_parent_id;
+
+ if ($item_id == $new_parent_id)
+ {
+ return false;
+ }
+
+ if (!$item_id)
+ {
+ throw new OutOfBoundsException($this->message_prefix . 'INVALID_ITEM');
+ }
+
+ $this->acquire_lock();
+
+ $item_data = $this->get_subtree_data($item_id);
+ if (!isset($item_data[$item_id]))
+ {
+ $this->lock->release();
+ throw new OutOfBoundsException($this->message_prefix . 'INVALID_ITEM');
+ }
+
+ $item = $item_data[$item_id];
+ $move_items = array_keys($item_data);
+
+ if (in_array($new_parent_id, $move_items))
+ {
+ $this->lock->release();
+ throw new OutOfBoundsException($this->message_prefix . 'INVALID_PARENT');
+ }
+
+ $diff = sizeof($move_items) * 2;
+ $sql_exclude_moved_items = $this->db->sql_in_set($this->column_item_id, $move_items, true);
+
+ $this->db->sql_transaction('begin');
+
+ $this->remove_subset($move_items, $item, false, true);
+
+ if ($new_parent_id)
+ {
+ // Retrieve new-parent again, it may have been changed...
+ $sql = 'SELECT *
+ FROM ' . $this->table_name . '
+ WHERE ' . $this->column_item_id . ' = ' . $new_parent_id;
+ $result = $this->db->sql_query($sql);
+ $new_parent = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ if (!$new_parent)
+ {
+ $this->db->sql_transaction('rollback');
+ $this->lock->release();
+ throw new OutOfBoundsException($this->message_prefix . 'INVALID_PARENT');
+ }
+
+ $new_right_id = $this->prepare_adding_subset($move_items, $new_parent, true);
+
+ if ($new_right_id > (int) $item[$this->column_right_id])
+ {
+ $diff = ' + ' . ($new_right_id - (int) $item[$this->column_right_id] - 1);
+ }
+ else
+ {
+ $diff = ' - ' . abs($new_right_id - (int) $item[$this->column_right_id] - 1);
+ }
+ }
+ else
+ {
+ $sql = 'SELECT MAX(' . $this->column_right_id . ') AS ' . $this->column_right_id . '
+ FROM ' . $this->table_name . '
+ WHERE ' . $sql_exclude_moved_items . '
+ ' . $this->get_sql_where('AND');
+ $result = $this->db->sql_query($sql);
+ $row = $this->db->sql_fetchrow($result);
+ $this->db->sql_freeresult($result);
+
+ $diff = ' + ' . ($row[$this->column_right_id] - (int) $item[$this->column_left_id] + 1);
+ }
+
+ $sql = 'UPDATE ' . $this->table_name . '
+ SET ' . $this->column_left_id . ' = ' . $this->column_left_id . $diff . ',
+ ' . $this->column_right_id . ' = ' . $this->column_right_id . $diff . ',
+ ' . $this->column_parent_id . ' = ' . $this->db->sql_case($this->column_item_id . ' = ' . $item_id, $new_parent_id, $this->column_parent_id) . ',
+ ' . $this->column_item_parents . " = ''
+ WHERE " . $this->db->sql_in_set($this->column_item_id, $move_items) . '
+ ' . $this->get_sql_where('AND');
+ $this->db->sql_query($sql);
+
+ $this->db->sql_transaction('commit');
+ $this->lock->release();
+
+ return true;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function get_path_and_subtree_data($item_id, $order_asc = true, $include_item = true)
+ {
+ $condition = 'i2.' . $this->column_left_id . ' BETWEEN i1.' . $this->column_left_id . ' AND i1.' . $this->column_right_id . '
+ OR i1.' . $this->column_left_id . ' BETWEEN i2.' . $this->column_left_id . ' AND i2.' . $this->column_right_id;
+
+ return $this->get_set_of_nodes_data($item_id, $condition, $order_asc, $include_item);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function get_path_data($item_id, $order_asc = true, $include_item = true)
+ {
+ $condition = 'i1.' . $this->column_left_id . ' BETWEEN i2.' . $this->column_left_id . ' AND i2.' . $this->column_right_id . '';
+
+ return $this->get_set_of_nodes_data($item_id, $condition, $order_asc, $include_item);
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function get_subtree_data($item_id, $order_asc = true, $include_item = true)
+ {
+ $condition = 'i2.' . $this->column_left_id . ' BETWEEN i1.' . $this->column_left_id . ' AND i1.' . $this->column_right_id . '';
+
+ return $this->get_set_of_nodes_data($item_id, $condition, $order_asc, $include_item);
+ }
+
+ /**
+ * Get items that are related to the given item by the condition
+ *
+ * @param int $item_id Id of the item to retrieve the node set from
+ * @param string $condition Query string restricting the item list
+ * @param bool $order_asc Order the items ascending by their left_id
+ * @param bool $include_item Should the item matching the given item id be included in the list as well
+ * @return array Array of items (containing all columns from the item table)
+ * ID => Item data
+ */
+ protected function get_set_of_nodes_data($item_id, $condition, $order_asc = true, $include_item = true)
+ {
+ $rows = array();
+
+ $sql = 'SELECT i2.*
+ FROM ' . $this->table_name . ' i1
+ LEFT JOIN ' . $this->table_name . " i2
+ ON (($condition) " . $this->get_sql_where('AND', 'i2.') . ')
+ WHERE i1.' . $this->column_item_id . ' = ' . (int) $item_id . '
+ ' . $this->get_sql_where('AND', 'i1.') . '
+ ORDER BY i2.' . $this->column_left_id . ' ' . ($order_asc ? 'ASC' : 'DESC');
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ if (!$include_item && $item_id == $row[$this->column_item_id])
+ {
+ continue;
+ }
+
+ $rows[(int) $row[$this->column_item_id]] = $row;
+ }
+ $this->db->sql_freeresult($result);
+
+ return $rows;
+ }
+
+ /**
+ * Get basic data of all parent items
+ *
+ * Basic data is defined in the $item_basic_data property.
+ * Data is cached in the item_parents column in the item table
+ *
+ * @param array $item The item to get the path from
+ * @return array Array of items (containing basic columns from the item table)
+ * ID => Item data
+ */
+ public function get_path_basic_data(array $item)
+ {
+ $parents = array();
+ if ($item[$this->column_parent_id])
+ {
+ if (!$item[$this->column_item_parents])
+ {
+ $sql = 'SELECT ' . implode(', ', $this->item_basic_data) . '
+ FROM ' . $this->table_name . '
+ WHERE ' . $this->column_left_id . ' < ' . (int) $item[$this->column_left_id] . '
+ AND ' . $this->column_right_id . ' > ' . (int) $item[$this->column_right_id] . '
+ ' . $this->get_sql_where('AND') . '
+ ORDER BY ' . $this->column_left_id . ' ASC';
+ $result = $this->db->sql_query($sql);
+
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ $parents[$row[$this->column_item_id]] = $row;
+ }
+ $this->db->sql_freeresult($result);
+
+ $item_parents = serialize($parents);
+
+ $sql = 'UPDATE ' . $this->table_name . '
+ SET ' . $this->column_item_parents . " = '" . $this->db->sql_escape($item_parents) . "'
+ WHERE " . $this->column_parent_id . ' = ' . (int) $item[$this->column_parent_id];
+ $this->db->sql_query($sql);
+ }
+ else
+ {
+ $parents = unserialize($item[$this->column_item_parents]);
+ }
+ }
+
+ return $parents;
+ }
+
+ /**
+ * Remove a subset from the nested set
+ *
+ * @param array $subset_items Subset of items to remove
+ * @param array $bounding_item Item containing the right bound of the subset
+ * @param bool $set_subset_zero Should the parent, left and right id of the items be set to 0, or kept unchanged?
+ * In case of removing an item from the tree, we should the values to 0
+ * In case of moving an item, we shouldkeep the original values, in order to allow "+ diff" later
+ * @return null
+ */
+ protected function remove_subset(array $subset_items, array $bounding_item, $set_subset_zero = true)
+ {
+ $acquired_new_lock = $this->acquire_lock();
+
+ $diff = sizeof($subset_items) * 2;
+ $sql_subset_items = $this->db->sql_in_set($this->column_item_id, $subset_items);
+ $sql_not_subset_items = $this->db->sql_in_set($this->column_item_id, $subset_items, true);
+
+ $sql_is_parent = $this->column_left_id . ' <= ' . (int) $bounding_item[$this->column_right_id] . '
+ AND ' . $this->column_right_id . ' >= ' . (int) $bounding_item[$this->column_right_id];
+
+ $sql_is_right = $this->column_left_id . ' > ' . (int) $bounding_item[$this->column_right_id];
+
+ $set_left_id = $this->db->sql_case($sql_is_right, $this->column_left_id . ' - ' . $diff, $this->column_left_id);
+ $set_right_id = $this->db->sql_case($sql_is_parent . ' OR ' . $sql_is_right, $this->column_right_id . ' - ' . $diff, $this->column_right_id);
+
+ if ($set_subset_zero)
+ {
+ $set_left_id = $this->db->sql_case($sql_subset_items, 0, $set_left_id);
+ $set_right_id = $this->db->sql_case($sql_subset_items, 0, $set_right_id);
+ }
+
+ $sql = 'UPDATE ' . $this->table_name . '
+ SET ' . (($set_subset_zero) ? $this->column_parent_id . ' = ' . $this->db->sql_case($sql_subset_items, 0, $this->column_parent_id) . ',' : '') . '
+ ' . $this->column_left_id . ' = ' . $set_left_id . ',
+ ' . $this->column_right_id . ' = ' . $set_right_id . '
+ ' . ((!$set_subset_zero) ? ' WHERE ' . $sql_not_subset_items . ' ' . $this->get_sql_where('AND') : $this->get_sql_where('WHERE'));
+ $this->db->sql_query($sql);
+
+ if ($acquired_new_lock)
+ {
+ $this->lock->release();
+ }
+ }
+
+ /**
+ * Prepare adding a subset to the nested set
+ *
+ * @param array $subset_items Subset of items to add
+ * @param array $new_parent Item containing the right bound of the new parent
+ * @return int New right id of the parent item
+ */
+ protected function prepare_adding_subset(array $subset_items, array $new_parent)
+ {
+ $diff = sizeof($subset_items) * 2;
+ $sql_not_subset_items = $this->db->sql_in_set($this->column_item_id, $subset_items, true);
+
+ $set_left_id = $this->db->sql_case($this->column_left_id . ' > ' . (int) $new_parent[$this->column_right_id], $this->column_left_id . ' + ' . $diff, $this->column_left_id);
+ $set_right_id = $this->db->sql_case($this->column_right_id . ' >= ' . (int) $new_parent[$this->column_right_id], $this->column_right_id . ' + ' . $diff, $this->column_right_id);
+
+ $sql = 'UPDATE ' . $this->table_name . '
+ SET ' . $this->column_left_id . ' = ' . $set_left_id . ',
+ ' . $this->column_right_id . ' = ' . $set_right_id . '
+ WHERE ' . $sql_not_subset_items . '
+ ' . $this->get_sql_where('AND');
+ $this->db->sql_query($sql);
+
+ return $new_parent[$this->column_right_id] + $diff;
+ }
+
+ /**
+ * Resets values required for the nested set system
+ *
+ * @param array $item Original item data
+ * @return array Original item data + nested set defaults
+ */
+ protected function reset_nestedset_values(array $item)
+ {
+ $item_data = array_merge($item, array(
+ $this->column_parent_id => 0,
+ $this->column_left_id => 0,
+ $this->column_right_id => 0,
+ $this->column_item_parents => '',
+ ));
+
+ unset($item_data[$this->column_item_id]);
+
+ return $item_data;
+ }
+
+ /**
+ * Regenerate left/right ids from parent/child relationship
+ *
+ * This method regenerates the left/right ids for the tree based on
+ * the parent/child relations. This function executes three queries per
+ * item, so it should only be called, when the set has one of the following
+ * problems:
+ * - The set has a duplicated value inside the left/right id chain
+ * - The set has a missing value inside the left/right id chain
+ * - The set has items that do not have a left/right id set
+ *
+ * When regenerating the items, the items are sorted by parent id and their
+ * current left id, so the current child/parent relationships are kept
+ * and running the function on a working set will not change the order.
+ *
+ * @param int $new_id First left_id to be used (should start with 1)
+ * @param int $parent_id parent_id of the current set (default = 0)
+ * @param bool $reset_ids Should we reset all left_id/right_id on the first call?
+ * @return int $new_id The next left_id/right_id that should be used
+ */
+ public function regenerate_left_right_ids($new_id, $parent_id = 0, $reset_ids = false)
+ {
+ if ($acquired_new_lock = $this->acquire_lock())
+ {
+ $this->db->sql_transaction('begin');
+
+ if (!$reset_ids)
+ {
+ $sql = 'UPDATE ' . $this->table_name . '
+ SET ' . $this->column_item_parents . " = ''
+ " . $this->get_sql_where('WHERE');
+ $this->db->sql_query($sql);
+ }
+ }
+
+ if ($reset_ids)
+ {
+ $sql = 'UPDATE ' . $this->table_name . '
+ SET ' . $this->db->sql_build_array('UPDATE', array(
+ $this->column_left_id => 0,
+ $this->column_right_id => 0,
+ $this->column_item_parents => '',
+ )) . '
+ ' . $this->get_sql_where('WHERE');
+ $this->db->sql_query($sql);
+ }
+
+ $sql = 'SELECT *
+ FROM ' . $this->table_name . '
+ WHERE ' . $this->column_parent_id . ' = ' . (int) $parent_id . '
+ ' . $this->get_sql_where('AND') . '
+ ORDER BY ' . $this->column_left_id . ', ' . $this->column_item_id . ' ASC';
+ $result = $this->db->sql_query($sql);
+ while ($row = $this->db->sql_fetchrow($result))
+ {
+ // First we update the left_id for this module
+ if ($row[$this->column_left_id] != $new_id)
+ {
+ $sql = 'UPDATE ' . $this->table_name . '
+ SET ' . $this->db->sql_build_array('UPDATE', array($this->column_left_id => $new_id)) . '
+ WHERE ' . $this->column_item_id . ' = ' . (int) $row[$this->column_item_id];
+ $this->db->sql_query($sql);
+ }
+ $new_id++;
+
+ // Then we go through any children and update their left/right id's
+ $new_id = $this->regenerate_left_right_ids($new_id, $row[$this->column_item_id]);
+
+ // Then we come back and update the right_id for this module
+ if ($row[$this->column_right_id] != $new_id)
+ {
+ $sql = 'UPDATE ' . $this->table_name . '
+ SET ' . $this->db->sql_build_array('UPDATE', array($this->column_right_id => $new_id)) . '
+ WHERE ' . $this->column_item_id . ' = ' . (int) $row[$this->column_item_id];
+ $this->db->sql_query($sql);
+ }
+ $new_id++;
+ }
+ $this->db->sql_freeresult($result);
+
+ if ($acquired_new_lock)
+ {
+ $this->db->sql_transaction('commit');
+ $this->lock->release();
+ }
+
+ return $new_id;
+ }
+}
diff --git a/phpBB/includes/tree/nestedset_forum.php b/phpBB/includes/tree/nestedset_forum.php
new file mode 100644
index 0000000000..ff09ef55d0
--- /dev/null
+++ b/phpBB/includes/tree/nestedset_forum.php
@@ -0,0 +1,46 @@
+<?php
+/**
+*
+* @package tree
+* @copyright (c) 2013 phpBB Group
+* @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License v2
+*
+*/
+
+/**
+* @ignore
+*/
+if (!defined('IN_PHPBB'))
+{
+ exit;
+}
+
+class phpbb_tree_nestedset_forum extends phpbb_tree_nestedset
+{
+ /**
+ * Construct
+ *
+ * @param phpbb_db_driver $db Database connection
+ * @param phpbb_lock_db $lock Lock class used to lock the table when moving forums around
+ * @param string $table_name Table name
+ */
+ public function __construct(phpbb_db_driver $db, phpbb_lock_db $lock, $table_name)
+ {
+ parent::__construct(
+ $db,
+ $lock,
+ $table_name,
+ 'FORUM_NESTEDSET_',
+ '',
+ array(
+ 'forum_id',
+ 'forum_name',
+ 'forum_type',
+ ),
+ array(
+ 'item_id' => 'forum_id',
+ 'item_parents' => 'forum_parents',
+ )
+ );
+ }
+}
diff --git a/phpBB/includes/ucp/info/ucp_profile.php b/phpBB/includes/ucp/info/ucp_profile.php
index 3581a7f533..e974cea713 100644
--- a/phpBB/includes/ucp/info/ucp_profile.php
+++ b/phpBB/includes/ucp/info/ucp_profile.php
@@ -21,7 +21,7 @@ class ucp_profile_info
'modes' => array(
'profile_info' => array('title' => 'UCP_PROFILE_PROFILE_INFO', 'auth' => 'acl_u_chgprofileinfo', 'cat' => array('UCP_PROFILE')),
'signature' => array('title' => 'UCP_PROFILE_SIGNATURE', 'auth' => 'acl_u_sig', 'cat' => array('UCP_PROFILE')),
- 'avatar' => array('title' => 'UCP_PROFILE_AVATAR', 'auth' => 'cfg_allow_avatar && (cfg_allow_avatar_local || cfg_allow_avatar_remote || cfg_allow_avatar_upload || cfg_allow_avatar_remote_upload)', 'cat' => array('UCP_PROFILE')),
+ 'avatar' => array('title' => 'UCP_PROFILE_AVATAR', 'auth' => 'cfg_allow_avatar', 'cat' => array('UCP_PROFILE')),
'reg_details' => array('title' => 'UCP_PROFILE_REG_DETAILS', 'auth' => '', 'cat' => array('UCP_PROFILE')),
'autologin_keys'=> array('title' => 'UCP_PROFILE_AUTOLOGIN_KEYS', 'auth' => '', 'cat' => array('UCP_PROFILE')),
),
diff --git a/phpBB/includes/ucp/ucp_activate.php b/phpBB/includes/ucp/ucp_activate.php
index 577761dfde..898dacd831 100644
--- a/phpBB/includes/ucp/ucp_activate.php
+++ b/phpBB/includes/ucp/ucp_activate.php
@@ -114,7 +114,7 @@ class ucp_activate
$messenger->template('admin_welcome_activated', $user_row['user_lang']);
- $messenger->to($user_row['user_email'], $user_row['username']);
+ $messenger->set_addresses($user_row);
$messenger->anti_abuse_headers($config, $user);
diff --git a/phpBB/includes/ucp/ucp_groups.php b/phpBB/includes/ucp/ucp_groups.php
index b9a06bc3b4..efc88e6e37 100644
--- a/phpBB/includes/ucp/ucp_groups.php
+++ b/phpBB/includes/ucp/ucp_groups.php
@@ -27,7 +27,7 @@ class ucp_groups
{
global $config, $phpbb_root_path, $phpEx, $phpbb_admin_path;
global $db, $user, $auth, $cache, $template;
- global $request;
+ global $request, $phpbb_container;
$user->add_lang('groups');
@@ -212,8 +212,7 @@ class ucp_groups
{
$messenger->template('group_request', $row['user_lang']);
- $messenger->to($row['user_email'], $row['username']);
- $messenger->im($row['user_jabber'], $row['username']);
+ $messenger->set_addresses($row);
$messenger->assign_vars(array(
'USERNAME' => htmlspecialchars_decode($row['username']),
@@ -438,7 +437,7 @@ class ucp_groups
$group_name = $group_row['group_name'];
$group_type = $group_row['group_type'];
- $avatar_img = (!empty($group_row['group_avatar'])) ? get_user_avatar($group_row['group_avatar'], $group_row['group_avatar_type'], $group_row['group_avatar_width'], $group_row['group_avatar_height'], 'GROUP_AVATAR') : '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />';
+ $avatar = phpbb_get_group_avatar($group_row, 'GROUP_AVATAR', true);
$template->assign_vars(array(
'GROUP_NAME' => ($group_type == GROUP_SPECIAL) ? $user->lang['G_' . $group_name] : $group_name,
@@ -447,8 +446,8 @@ class ucp_groups
'GROUP_DESC_DISP' => generate_text_for_display($group_row['group_desc'], $group_row['group_desc_uid'], $group_row['group_desc_bitfield'], $group_row['group_desc_options']),
'GROUP_TYPE' => $group_row['group_type'],
- 'AVATAR' => $avatar_img,
- 'AVATAR_IMAGE' => $avatar_img,
+ 'AVATAR' => (empty($avatar) ? '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />' : $avatar),
+ 'AVATAR_IMAGE' => (empty($avatar) ? '<img src="' . $phpbb_admin_path . 'images/no_avatar.gif" alt="" />' : $avatar),
'AVATAR_WIDTH' => (isset($group_row['group_avatar_width'])) ? $group_row['group_avatar_width'] : '',
'AVATAR_HEIGHT' => (isset($group_row['group_avatar_height'])) ? $group_row['group_avatar_height'] : '',
));
@@ -483,10 +482,20 @@ class ucp_groups
$error = array();
- $avatar_select = basename(request_var('avatar_select', ''));
- $category = basename(request_var('category', ''));
+ // Setup avatar data for later
+ $avatars_enabled = false;
+ $avatar_drivers = null;
+ $avatar_data = null;
+ $avatar_error = array();
- $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $file_uploads) ? true : false;
+ if ($config['allow_avatar'])
+ {
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers();
+
+ // This is normalised data, without the group_ prefix
+ $avatar_data = phpbb_avatar_manager::clean_row($group_row);
+ }
// Did we submit?
if ($update)
@@ -507,88 +516,40 @@ class ucp_groups
'max_recipients'=> request_var('group_max_recipients', 0),
);
- $data['uploadurl'] = request_var('uploadurl', '');
- $data['remotelink'] = request_var('remotelink', '');
- $data['width'] = request_var('width', '');
- $data['height'] = request_var('height', '');
- $delete = request_var('delete', '');
-
- $uploadfile = $request->file('uploadfile');
- if (!empty($uploadfile['tmp_name']) || $data['uploadurl'] || $data['remotelink'])
+ if ($config['allow_avatar'])
{
- // Avatar stuff
- $var_ary = array(
- 'uploadurl' => array('string', true, 5, 255),
- 'remotelink' => array('string', true, 5, 255),
- 'width' => array('string', true, 1, 3),
- 'height' => array('string', true, 1, 3),
- );
+ // Handle avatar
+ $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', ''));
+ $config_name = preg_replace('#^avatar\.driver.#', '', $driver_name);
- if (!($error = validate_data($data, $var_ary)))
+ if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete'))
{
- $data['user_id'] = "g$group_id";
+ $driver = $phpbb_avatar_manager->get_driver($driver_name);
+ $result = $driver->process_form($request, $template, $user, $avatar_data, $avatar_error);
- if ((!empty($uploadfile['tmp_name']) || $data['uploadurl']) && $can_upload)
+ if ($result && empty($avatar_error))
{
- list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_upload($data, $error);
- }
- else if ($data['remotelink'])
- {
- list($submit_ary['avatar_type'], $submit_ary['avatar'], $submit_ary['avatar_width'], $submit_ary['avatar_height']) = avatar_remote($data, $error);
- }
- }
- }
- else if ($avatar_select && $config['allow_avatar_local'])
- {
- // check avatar gallery
- if (is_dir($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category))
- {
- $submit_ary['avatar_type'] = AVATAR_GALLERY;
+ $result['avatar_type'] = $driver_name;
- list($submit_ary['avatar_width'], $submit_ary['avatar_height']) = getimagesize($phpbb_root_path . $config['avatar_gallery_path'] . '/' . $category . '/' . $avatar_select);
- $submit_ary['avatar'] = $category . '/' . $avatar_select;
- }
- }
- else if ($delete)
- {
- $submit_ary['avatar'] = '';
- $submit_ary['avatar_type'] = $submit_ary['avatar_width'] = $submit_ary['avatar_height'] = 0;
- }
- else if ($data['width'] && $data['height'])
- {
- // Only update the dimensions?
- if ($config['avatar_max_width'] || $config['avatar_max_height'])
- {
- if ($data['width'] > $config['avatar_max_width'] || $data['height'] > $config['avatar_max_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
+ $submit_ary = array_merge($submit_ary, $result);
}
}
-
- if (!sizeof($error))
+ else
{
- if ($config['avatar_min_width'] || $config['avatar_min_height'])
+ if ($driver = $phpbb_avatar_manager->get_driver($user->data['user_avatar_type']))
{
- if ($data['width'] < $config['avatar_min_width'] || $data['height'] < $config['avatar_min_height'])
- {
- $error[] = phpbb_avatar_error_wrong_size($data['width'], $data['height']);
- }
+ $driver->delete($avatar_data);
}
- }
- if (!sizeof($error))
- {
- $submit_ary['avatar_width'] = $data['width'];
- $submit_ary['avatar_height'] = $data['height'];
+ // Removing the avatar
+ $submit_ary['avatar_type'] = '';
+ $submit_ary['avatar'] = '';
+ $submit_ary['avatar_width'] = 0;
+ $submit_ary['avatar_height'] = 0;
}
- }
- if ((isset($submit_ary['avatar']) && $submit_ary['avatar'] && (!isset($group_row['group_avatar']))) || $delete)
- {
- if (isset($group_row['group_avatar']) && $group_row['group_avatar'])
- {
- avatar_delete('group', $group_row, true);
- }
+ // Merge any avatars errors into the primary error array
+ $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error));
}
if (!check_form_key('ucp_groups'))
@@ -596,6 +557,13 @@ class ucp_groups
$error[] = $user->lang['FORM_INVALID'];
}
+ // Validate submitted colour value
+ if ($colour_error = validate_data($submit_ary, array('colour' => array('hex_colour', true))))
+ {
+ // Replace "error" string with its real, localised form
+ $error = array_merge($error, array_map(array(&$user, 'lang'), $colour_error));
+ }
+
if (!sizeof($error))
{
// Only set the rank, colour, etc. if it's changed or if we're adding a new
@@ -607,7 +575,7 @@ class ucp_groups
'rank' => 'int',
'colour' => 'string',
'avatar' => 'string',
- 'avatar_type' => 'int',
+ 'avatar_type' => 'string',
'avatar_width' => 'int',
'avatar_height' => 'int',
'receive_pm' => 'int',
@@ -683,28 +651,51 @@ class ucp_groups
$type_closed = ($group_type == GROUP_CLOSED) ? ' checked="checked"' : '';
$type_hidden = ($group_type == GROUP_HIDDEN) ? ' checked="checked"' : '';
- $display_gallery = (isset($_POST['display_gallery'])) ? true : false;
-
- if ($config['allow_avatar'] && $config['allow_avatar_local'] && $display_gallery)
+ // Load up stuff for avatars
+ if ($config['allow_avatar'])
{
- avatar_gallery($category, $avatar_select, 4);
+ $avatars_enabled = false;
+ $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $avatar_data['avatar_type']));
+
+ foreach ($avatar_drivers as $current_driver)
+ {
+ $driver = $phpbb_avatar_manager->get_driver($current_driver);
+
+ $avatars_enabled = true;
+ $template->set_filenames(array(
+ 'avatar' => $driver->get_template_name(),
+ ));
+
+ if ($driver->prepare_form($request, $template, $user, $avatar_data, $avatar_error))
+ {
+ $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver);
+ $driver_upper = strtoupper($driver_name);
+ $template->assign_block_vars('avatar_drivers', array(
+ 'L_TITLE' => $user->lang($driver_upper . '_TITLE'),
+ 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'),
+
+ 'DRIVER' => $driver_name,
+ 'SELECTED' => $current_driver == $selected_driver,
+ 'OUTPUT' => $template->assign_display('avatar'),
+ ));
+ }
+ }
}
- $avatars_enabled = ($config['allow_avatar'] && (($can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) || ($config['allow_avatar_local'] || $config['allow_avatar_remote']))) ? true : false;
+ if (!$update)
+ {
+ // Merge any avatars errors into the primary error array
+ $error = array_merge($error, $phpbb_avatar_manager->localize_errors($user, $avatar_error));
+ }
$template->assign_vars(array(
'S_EDIT' => true,
'S_INCLUDE_SWATCH' => true,
- 'S_FORM_ENCTYPE' => ($config['allow_avatar'] && $can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) ? ' enctype="multipart/form-data"' : '',
+ 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"',
'S_ERROR' => (sizeof($error)) ? true : false,
'S_SPECIAL_GROUP' => ($group_type == GROUP_SPECIAL) ? true : false,
- 'S_AVATARS_ENABLED' => $avatars_enabled,
- 'S_DISPLAY_GALLERY' => ($config['allow_avatar'] && $config['allow_avatar_local'] && !$display_gallery) ? true : false,
- 'S_IN_GALLERY' => ($config['allow_avatar_local'] && $display_gallery) ? true : false,
-
- 'S_UPLOAD_AVATAR_FILE' => ($config['allow_avatar'] && $config['allow_avatar_upload'] && $can_upload) ? true : false,
- 'S_UPLOAD_AVATAR_URL' => ($config['allow_avatar'] && $config['allow_avatar_remote_upload'] && $can_upload) ? true : false,
- 'S_LINK_AVATAR' => ($config['allow_avatar'] && $config['allow_avatar_remote']) ? true : false,
+ 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled),
+ 'S_GROUP_MANAGE' => true,
'ERROR_MSG' => (sizeof($error)) ? implode('<br />', $error) : '',
'GROUP_RECEIVE_PM' => (isset($group_row['group_receive_pm']) && $group_row['group_receive_pm']) ? ' checked="checked"' : '',
@@ -717,7 +708,6 @@ class ucp_groups
'S_DESC_SMILIES_CHECKED'=> $group_desc_data['allow_smilies'],
'S_RANK_OPTIONS' => $rank_options,
- 'AVATAR_MAX_FILESIZE' => $config['avatar_filesize'],
'GROUP_TYPE_FREE' => GROUP_FREE,
'GROUP_TYPE_OPEN' => GROUP_OPEN,
diff --git a/phpBB/includes/ucp/ucp_notifications.php b/phpBB/includes/ucp/ucp_notifications.php
index 338c921e94..72c41776b3 100644
--- a/phpBB/includes/ucp/ucp_notifications.php
+++ b/phpBB/includes/ucp/ucp_notifications.php
@@ -200,6 +200,10 @@ class ucp_notifications
}
}
}
+
+ $template->assign_vars(array(
+ strtoupper($block) . '_COLS' => sizeof($notification_methods) + 2,
+ ));
}
/**
diff --git a/phpBB/includes/ucp/ucp_pm_compose.php b/phpBB/includes/ucp/ucp_pm_compose.php
index c2d12d17c2..e0e7a46494 100644
--- a/phpBB/includes/ucp/ucp_pm_compose.php
+++ b/phpBB/includes/ucp/ucp_pm_compose.php
@@ -265,19 +265,16 @@ function compose_pm($id, $mode, $action, $user_folders = array())
// Passworded forum?
if ($post['forum_id'])
{
- $sql = 'SELECT forum_password
+ $sql = 'SELECT forum_id, forum_name, forum_password
FROM ' . FORUMS_TABLE . '
WHERE forum_id = ' . (int) $post['forum_id'];
$result = $db->sql_query($sql);
- $forum_password = (string) $db->sql_fetchfield('forum_password');
+ $forum_data = $db->sql_fetchrow($result);
$db->sql_freeresult($result);
- if ($forum_password)
+ if (!empty($forum_data['forum_password']))
{
- login_forum_box(array(
- 'forum_id' => $post['forum_id'],
- 'forum_password' => $forum_password,
- ));
+ login_forum_box($forum_data);
}
}
}
diff --git a/phpBB/includes/ucp/ucp_pm_viewmessage.php b/phpBB/includes/ucp/ucp_pm_viewmessage.php
index c85b05f144..b7d2dd6821 100644
--- a/phpBB/includes/ucp/ucp_pm_viewmessage.php
+++ b/phpBB/includes/ucp/ucp_pm_viewmessage.php
@@ -94,8 +94,7 @@ function view_message($id, $mode, $folder_id, $msg_id, $folder, $message_row)
// Editing information
if ($message_row['message_edit_count'] && $config['display_last_edited'])
{
- $l_edit_time_total = ($message_row['message_edit_count'] == 1) ? $user->lang['EDITED_TIME_TOTAL'] : $user->lang['EDITED_TIMES_TOTAL'];
- $l_edited_by = '<br /><br />' . sprintf($l_edit_time_total, (!$message_row['message_edit_user']) ? $message_row['username'] : $message_row['message_edit_user'], $user->format_date($message_row['message_edit_time'], false, true), $message_row['message_edit_count']);
+ $l_edited_by = '<br /><br />' . $user->lang('EDITED_TIMES_TOTAL', (int) $message_row['message_edit_count'], (!$message_row['message_edit_user']) ? $message_row['username'] : $message_row['message_edit_user'], $user->format_date($message_row['message_edit_time'], false, true));
}
else
{
@@ -371,12 +370,12 @@ function get_user_information($user_id, $user_row)
}
}
- if (!function_exists('get_user_avatar'))
+ if (!function_exists('phpbb_get_user_avatar'))
{
include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
}
- $user_row['avatar'] = ($user->optionget('viewavatars')) ? get_user_avatar($user_row['user_avatar'], $user_row['user_avatar_type'], $user_row['user_avatar_width'], $user_row['user_avatar_height']) : '';
+ $user_row['avatar'] = ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($user_row) : '';
get_user_rank($user_row['user_rank'], $user_row['user_posts'], $user_row['rank_title'], $user_row['rank_image'], $user_row['rank_image_src']);
diff --git a/phpBB/includes/ucp/ucp_profile.php b/phpBB/includes/ucp/ucp_profile.php
index e7cea06a45..55df5f610c 100644
--- a/phpBB/includes/ucp/ucp_profile.php
+++ b/phpBB/includes/ucp/ucp_profile.php
@@ -28,8 +28,9 @@ class ucp_profile
function main($id, $mode)
{
- global $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx;
+ global $cache, $config, $db, $user, $auth, $template, $phpbb_root_path, $phpEx;
global $request;
+ global $phpbb_container;
$user->add_lang('posting');
@@ -174,8 +175,7 @@ class ucp_profile
while ($row = $db->sql_fetchrow($result))
{
$messenger->template('admin_activate', $row['user_lang']);
- $messenger->to($row['user_email'], $row['username']);
- $messenger->im($row['user_jabber'], $row['username']);
+ $messenger->set_addresses($row);
$messenger->assign_vars(array(
'USERNAME' => htmlspecialchars_decode($data['username']),
@@ -549,78 +549,129 @@ class ucp_profile
break;
case 'avatar':
+ if (!function_exists('phpbb_get_user_avatar'))
+ {
+ include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ }
- include($phpbb_root_path . 'includes/functions_display.' . $phpEx);
+ add_form_key('ucp_avatar');
- $display_gallery = request_var('display_gallery', '0');
- $avatar_select = basename(request_var('avatar_select', ''));
- $category = basename(request_var('category', ''));
+ $avatars_enabled = false;
- $can_upload = (file_exists($phpbb_root_path . $config['avatar_path']) && phpbb_is_writable($phpbb_root_path . $config['avatar_path']) && $auth->acl_get('u_chgavatar') && (@ini_get('file_uploads') || strtolower(@ini_get('file_uploads')) == 'on')) ? true : false;
+ if ($config['allow_avatar'] && $auth->acl_get('u_chgavatar'))
+ {
+ $phpbb_avatar_manager = $phpbb_container->get('avatar.manager');
+ $avatar_drivers = $phpbb_avatar_manager->get_enabled_drivers();
- add_form_key('ucp_avatar');
+ // This is normalised data, without the user_ prefix
+ $avatar_data = phpbb_avatar_manager::clean_row($user->data);
- if ($submit)
- {
- if (check_form_key('ucp_avatar'))
+ if ($submit)
{
- if (avatar_process_user($error, false, $can_upload))
+ if (check_form_key('ucp_avatar'))
{
- meta_refresh(3, $this->u_action);
- $message = $user->lang['PROFILE_UPDATED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>');
- trigger_error($message);
+ $driver_name = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', ''));
+
+ if (in_array($driver_name, $avatar_drivers) && !$request->is_set_post('avatar_delete'))
+ {
+ $driver = $phpbb_avatar_manager->get_driver($driver_name);
+ $result = $driver->process_form($request, $template, $user, $avatar_data, $error);
+
+ if ($result && empty($error))
+ {
+ // Success! Lets save the result in the database
+ $result = array(
+ 'user_avatar_type' => $driver_name,
+ 'user_avatar' => $result['avatar'],
+ 'user_avatar_width' => $result['avatar_width'],
+ 'user_avatar_height' => $result['avatar_height'],
+ );
+
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET ' . $db->sql_build_array('UPDATE', $result) . '
+ WHERE user_id = ' . (int) $user->data['user_id'];
+
+ $db->sql_query($sql);
+
+ meta_refresh(3, $this->u_action);
+ $message = $user->lang['PROFILE_UPDATED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>');
+ trigger_error($message);
+ }
+ }
+ else
+ {
+ if ($driver = $phpbb_avatar_manager->get_driver($user->data['user_avatar_type']))
+ {
+ $driver->delete($avatar_data);
+ }
+
+ $result = array(
+ 'user_avatar' => '',
+ 'user_avatar_type' => '',
+ 'user_avatar_width' => 0,
+ 'user_avatar_height' => 0,
+ );
+
+ $sql = 'UPDATE ' . USERS_TABLE . '
+ SET ' . $db->sql_build_array('UPDATE', $result) . '
+ WHERE user_id = ' . (int) $user->data['user_id'];
+
+ $db->sql_query($sql);
+
+ meta_refresh(3, $this->u_action);
+ $message = $user->lang['PROFILE_UPDATED'] . '<br /><br />' . sprintf($user->lang['RETURN_UCP'], '<a href="' . $this->u_action . '">', '</a>');
+ trigger_error($message);
+ }
+ }
+ else
+ {
+ $error[] = 'FORM_INVALID';
}
}
- else
+
+ $selected_driver = $phpbb_avatar_manager->clean_driver_name($request->variable('avatar_driver', $user->data['user_avatar_type']));
+
+ foreach ($avatar_drivers as $current_driver)
{
- $error[] = 'FORM_INVALID';
+ $driver = $phpbb_avatar_manager->get_driver($current_driver);
+
+ $avatars_enabled = true;
+ $template->set_filenames(array(
+ 'avatar' => $driver->get_template_name(),
+ ));
+
+ if ($driver->prepare_form($request, $template, $user, $avatar_data, $error))
+ {
+ $driver_name = $phpbb_avatar_manager->prepare_driver_name($current_driver);
+ $driver_upper = strtoupper($driver_name);
+
+ $template->assign_block_vars('avatar_drivers', array(
+ 'L_TITLE' => $user->lang($driver_upper . '_TITLE'),
+ 'L_EXPLAIN' => $user->lang($driver_upper . '_EXPLAIN'),
+
+ 'DRIVER' => $driver_name,
+ 'SELECTED' => $current_driver == $selected_driver,
+ 'OUTPUT' => $template->assign_display('avatar'),
+ ));
+ }
}
- // Replace "error" strings with their real, localised form
- $error = array_map(array($user, 'lang'), $error);
}
- if (!$config['allow_avatar'] && $user->data['user_avatar_type'])
- {
- $error[] = $user->lang['AVATAR_NOT_ALLOWED'];
- }
- else if ((($user->data['user_avatar_type'] == AVATAR_UPLOAD) && !$config['allow_avatar_upload']) ||
- (($user->data['user_avatar_type'] == AVATAR_REMOTE) && !$config['allow_avatar_remote']) ||
- (($user->data['user_avatar_type'] == AVATAR_GALLERY) && !$config['allow_avatar_local']))
- {
- $error[] = $user->lang['AVATAR_TYPE_NOT_ALLOWED'];
- }
+ // Replace "error" strings with their real, localised form
+ $error = $phpbb_avatar_manager->localize_errors($user, $error);
+
+ $avatar = phpbb_get_user_avatar($user->data, 'USER_AVATAR', true);
$template->assign_vars(array(
'ERROR' => (sizeof($error)) ? implode('<br />', $error) : '',
- 'AVATAR' => get_user_avatar($user->data['user_avatar'], $user->data['user_avatar_type'], $user->data['user_avatar_width'], $user->data['user_avatar_height'], 'USER_AVATAR', true),
- 'AVATAR_SIZE' => $config['avatar_filesize'],
-
- 'U_GALLERY' => append_sid("{$phpbb_root_path}ucp.$phpEx", 'i=profile&amp;mode=avatar&amp;display_gallery=1'),
+ 'AVATAR' => $avatar,
- 'S_FORM_ENCTYPE' => ($can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) ? ' enctype="multipart/form-data"' : '',
+ 'S_FORM_ENCTYPE' => ' enctype="multipart/form-data"',
'L_AVATAR_EXPLAIN' => phpbb_avatar_explanation_string(),
- ));
- if ($config['allow_avatar'] && $display_gallery && $auth->acl_get('u_chgavatar') && $config['allow_avatar_local'])
- {
- avatar_gallery($category, $avatar_select, 4);
- }
- else if ($config['allow_avatar'])
- {
- $avatars_enabled = (($can_upload && ($config['allow_avatar_upload'] || $config['allow_avatar_remote_upload'])) || ($auth->acl_get('u_chgavatar') && ($config['allow_avatar_local'] || $config['allow_avatar_remote']))) ? true : false;
-
- $template->assign_vars(array(
- 'AVATAR_WIDTH' => request_var('width', $user->data['user_avatar_width']),
- 'AVATAR_HEIGHT' => request_var('height', $user->data['user_avatar_height']),
-
- 'S_AVATARS_ENABLED' => $avatars_enabled,
- 'S_UPLOAD_AVATAR_FILE' => ($can_upload && $config['allow_avatar_upload']) ? true : false,
- 'S_UPLOAD_AVATAR_URL' => ($can_upload && $config['allow_avatar_remote_upload']) ? true : false,
- 'S_LINK_AVATAR' => ($auth->acl_get('u_chgavatar') && $config['allow_avatar_remote']) ? true : false,
- 'S_DISPLAY_GALLERY' => ($auth->acl_get('u_chgavatar') && $config['allow_avatar_local']) ? true : false)
- );
- }
+ 'S_AVATARS_ENABLED' => ($config['allow_avatar'] && $avatars_enabled),
+ ));
break;
diff --git a/phpBB/includes/ucp/ucp_register.php b/phpBB/includes/ucp/ucp_register.php
index c57aec00a0..70fbfe46fb 100644
--- a/phpBB/includes/ucp/ucp_register.php
+++ b/phpBB/includes/ucp/ucp_register.php
@@ -384,8 +384,7 @@ class ucp_register
while ($row = $db->sql_fetchrow($result))
{
$messenger->template('admin_activate', $row['user_lang']);
- $messenger->to($row['user_email'], $row['username']);
- $messenger->im($row['user_jabber'], $row['username']);
+ $messenger->set_addresses($row);
$messenger->assign_vars(array(
'USERNAME' => htmlspecialchars_decode($data['username']),
@@ -457,6 +456,7 @@ class ucp_register
'S_LANG_OPTIONS' => language_select($data['lang']),
'S_TZ_OPTIONS' => $timezone_selects['tz_select'],
'S_TZ_DATE_OPTIONS' => $timezone_selects['tz_dates'],
+ 'S_TZ_PRESELECT' => !$submit,
'S_CONFIRM_REFRESH' => ($config['enable_confirm'] && $config['confirm_refresh']) ? true : false,
'S_REGISTRATION' => true,
'S_COPPA' => $coppa,
diff --git a/phpBB/includes/ucp/ucp_remind.php b/phpBB/includes/ucp/ucp_remind.php
index 4f65ed1866..ff7ab53736 100644
--- a/phpBB/includes/ucp/ucp_remind.php
+++ b/phpBB/includes/ucp/ucp_remind.php
@@ -29,6 +29,11 @@ class ucp_remind
global $config, $phpbb_root_path, $phpEx;
global $db, $user, $auth, $template;
+ if (!$config['allow_password_reset'])
+ {
+ trigger_error($user->lang('UCP_PASSWORD_RESET_DISABLED', '<a href="mailto:' . htmlspecialchars($config['board_contact']) . '">', '</a>'));
+ }
+
$username = request_var('username', '', true);
$email = strtolower(request_var('email', ''));
$submit = (isset($_POST['submit'])) ? true : false;
@@ -94,8 +99,7 @@ class ucp_remind
$messenger->template('user_activate_passwd', $user_row['user_lang']);
- $messenger->to($user_row['user_email'], $user_row['username']);
- $messenger->im($user_row['user_jabber'], $user_row['username']);
+ $messenger->set_addresses($user_row);
$messenger->assign_vars(array(
'USERNAME' => htmlspecialchars_decode($user_row['username']),
diff --git a/phpBB/includes/ucp/ucp_resend.php b/phpBB/includes/ucp/ucp_resend.php
index 5f1e3a92c3..ab396cdec9 100644
--- a/phpBB/includes/ucp/ucp_resend.php
+++ b/phpBB/includes/ucp/ucp_resend.php
@@ -91,7 +91,7 @@ class ucp_resend
if ($config['require_activation'] == USER_ACTIVATION_SELF || $coppa)
{
$messenger->template(($coppa) ? 'coppa_resend_inactive' : 'user_resend_inactive', $user_row['user_lang']);
- $messenger->to($user_row['user_email'], $user_row['username']);
+ $messenger->set_addresses($user_row);
$messenger->anti_abuse_headers($config, $user);
@@ -126,8 +126,7 @@ class ucp_resend
while ($row = $db->sql_fetchrow($result))
{
$messenger->template('admin_activate', $row['user_lang']);
- $messenger->to($row['user_email'], $row['username']);
- $messenger->im($row['user_jabber'], $row['username']);
+ $messenger->set_addresses($row);
$messenger->anti_abuse_headers($config, $user);
diff --git a/phpBB/includes/user.php b/phpBB/includes/user.php
index 9ddd806b27..5530fe3f03 100644
--- a/phpBB/includes/user.php
+++ b/phpBB/includes/user.php
@@ -215,7 +215,7 @@ class phpbb_user extends phpbb_session
if (!$this->style)
{
- trigger_error('Could not get style data', E_USER_ERROR);
+ trigger_error('NO_STYLE_DATA', E_USER_ERROR);
}
// Now parse the cfg file and cache it
diff --git a/phpBB/includes/user_loader.php b/phpBB/includes/user_loader.php
index 77128d6570..37bf9648c1 100644
--- a/phpBB/includes/user_loader.php
+++ b/phpBB/includes/user_loader.php
@@ -70,8 +70,8 @@ class phpbb_user_loader
{
$user_ids[] = ANONYMOUS;
- // Load the users
- $user_ids = array_unique($user_ids);
+ // Make user_ids unique and convert to integer.
+ $user_ids = array_map('intval', array_unique($user_ids));
// Do not load users we already have in $this->users
$user_ids = array_diff($user_ids, array_keys($this->users));
diff --git a/phpBB/install/database_update.php b/phpBB/install/database_update.php
index 4938ef0f87..b20ca1e4ea 100644
--- a/phpBB/install/database_update.php
+++ b/phpBB/install/database_update.php
@@ -41,10 +41,12 @@ if (!function_exists('phpbb_require_updated'))
}
}
-function phpbb_end_update($cache)
+function phpbb_end_update($cache, $config)
{
$cache->purge();
+ $config->increment('assets_version', 1);
+
?>
</p>
</div>
@@ -93,7 +95,7 @@ require($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);
set_error_handler(defined('PHPBB_MSG_HANDLER') ? PHPBB_MSG_HANDLER : 'msg_handler');
// Setup class loader first
-$phpbb_class_loader = new phpbb_class_loader('phpbb_', "{$phpbb_root_path}includes/", ".$phpEx");
+$phpbb_class_loader = new phpbb_class_loader('phpbb_', "{$phpbb_root_path}includes/", $phpEx);
$phpbb_class_loader->register();
// Set up container (must be done here because extensions table may not exist)
@@ -123,6 +125,7 @@ $request = $phpbb_container->get('request');
$user = $phpbb_container->get('user');
$auth = $phpbb_container->get('auth');
$db = $phpbb_container->get('dbal.conn');
+$phpbb_log = $phpbb_container->get('log');
// make sure request_var uses this request instance
request_var('', 0, false, false, $request); // "dependency injection" for a function
@@ -210,7 +213,13 @@ if (!$db_tools->sql_table_exists($table_prefix . 'migrations'))
}
$migrator = $phpbb_container->get('migrator');
-$migrator->load_migrations($phpbb_root_path . 'includes/db/migration/data/');
+$phpbb_extension_manager = $phpbb_container->get('ext.manager');
+$finder = $phpbb_extension_manager->get_finder();
+
+$migrations = $finder
+ ->core_path('includes/db/migration/data/')
+ ->get_classes();
+$migrator->set_migrations($migrations);
// What is a safe limit of execution time? Half the max execution time should be safe.
$safe_time_limit = (ini_get('max_execution_time') / 2);
@@ -225,19 +234,39 @@ while (!$migrator->finished())
{
echo $e->getLocalisedMessage($user);
- phpbb_end_update($cache);
+ phpbb_end_update($cache, $config);
}
- echo $migrator->last_run_migration['name'] . '<br />';
+ $state = array_merge(array(
+ 'migration_schema_done' => false,
+ 'migration_data_done' => false,
+ ),
+ $migrator->last_run_migration['state']
+ );
+
+ if (isset($migrator->last_run_migration['effectively_installed']) && $migrator->last_run_migration['effectively_installed'])
+ {
+ echo $user->lang('MIGRATION_EFFECTIVELY_INSTALLED', $migrator->last_run_migration['name']) . '<br />';
+ }
+ else
+ {
+ if ($state['migration_data_done'])
+ {
+ echo $user->lang('MIGRATION_DATA_DONE', $migrator->last_run_migration['name']) . '<br />';
+ }
+ else if ($state['migration_schema_done'])
+ {
+ echo $user->lang('MIGRATION_SCHEMA_DONE', $migrator->last_run_migration['name']) . '<br />';
+ }
+ }
// Are we approaching the time limit? If so we want to pause the update and continue after refreshing
if ((time() - $update_start_time) >= $safe_time_limit)
{
- //echo '<meta http-equiv="refresh" content="0;url=' . str_replace('&', '&amp;', append_sid($phpbb_root_path . 'test.' . $phpEx)) . '" />';
echo $user->lang['DATABASE_UPDATE_NOT_COMPLETED'] . '<br />';
- echo '<a href="' . append_sid($phpbb_root_path . 'test.' . $phpEx) . '">' . $user->lang['DATABASE_UPDATE_CONTINUE'] . '</a>';
+ echo '<a href="' . append_sid($phpbb_root_path . 'install/database_update.' . $phpEx, 'type=' . $request->variable('type', 0) . '&amp;language=' . $user->lang['USER_LANG']) . '">' . $user->lang['DATABASE_UPDATE_CONTINUE'] . '</a>';
- phpbb_end_update($cache);
+ phpbb_end_update($cache, $config);
}
}
@@ -246,6 +275,17 @@ if ($orig_version != $config['version'])
add_log('admin', 'LOG_UPDATE_DATABASE', $orig_version, $config['version']);
}
-echo $user->lang['DATABASE_UPDATE_COMPLETE'];
+echo $user->lang['DATABASE_UPDATE_COMPLETE'] . '<br />';
+
+if ($request->variable('type', 0))
+{
+ echo $user->lang['INLINE_UPDATE_SUCCESSFUL'] . '<br /><br />';
+ echo '<a href="' . append_sid($phpbb_root_path . 'install/index.' . $phpEx, 'mode=update&amp;sub=file_check&amp;language=' . $user->lang['USER_LANG']) . '" class="button1">' . $user->lang['CONTINUE_UPDATE_NOW'] . '</a>';
+}
+else
+{
+ echo '<div class="errorbox">' . $user->lang['UPDATE_FILES_NOTICE'] . '</div>';
+ echo $user->lang['COMPLETE_LOGIN_TO_BOARD'];
+}
-phpbb_end_update($cache);
+phpbb_end_update($cache, $config);
diff --git a/phpBB/install/index.php b/phpBB/install/index.php
index a03fda6395..f745f51974 100644
--- a/phpBB/install/index.php
+++ b/phpBB/install/index.php
@@ -90,9 +90,9 @@ include($phpbb_root_path . 'includes/utf/utf_tools.' . $phpEx);
require($phpbb_root_path . 'includes/functions_install.' . $phpEx);
// Setup class loader first
-$phpbb_class_loader = new phpbb_class_loader('phpbb_', "{$phpbb_root_path}includes/", ".$phpEx");
+$phpbb_class_loader = new phpbb_class_loader('phpbb_', "{$phpbb_root_path}includes/", $phpEx);
$phpbb_class_loader->register();
-$phpbb_class_loader_ext = new phpbb_class_loader('phpbb_ext_', "{$phpbb_root_path}ext/", ".$phpEx");
+$phpbb_class_loader_ext = new phpbb_class_loader('phpbb_ext_', "{$phpbb_root_path}ext/", $phpEx);
$phpbb_class_loader_ext->register();
// Set up container
@@ -373,6 +373,7 @@ class module
'L_SKIP' => $lang['SKIP'],
'PAGE_TITLE' => $this->get_page_title(),
'T_IMAGE_PATH' => htmlspecialchars($phpbb_admin_path) . 'images/',
+ 'T_JQUERY_LINK' => $phpbb_root_path . 'assets/javascript/jquery.js',
'S_CONTENT_DIRECTION' => $lang['DIRECTION'],
'S_CONTENT_FLOW_BEGIN' => ($lang['DIRECTION'] == 'ltr') ? 'left' : 'right',
@@ -666,6 +667,21 @@ class module
{
case 'text':
case 'password':
+ // HTML5 text-like input types
+ case 'color':
+ case 'date':
+ case 'time':
+ case 'datetime':
+ case 'datetime-local':
+ case 'email':
+ case 'month':
+ case 'number':
+ case 'range':
+ case 'search':
+ case 'tel':
+ case 'url':
+ case 'week':
+
$size = (int) $tpl_type[1];
$maxlength = (int) $tpl_type[2];
diff --git a/phpBB/install/install_convert.php b/phpBB/install/install_convert.php
index 15202768b8..6198efe4c7 100644
--- a/phpBB/install/install_convert.php
+++ b/phpBB/install/install_convert.php
@@ -2065,7 +2065,7 @@ class install_convert extends module
// Because we should not rely on correct settings, we simply use the relative path here directly.
$template->assign_vars(array(
'S_REFRESH' => true,
- 'META' => '<meta http-equiv="refresh" content="5;url=' . $url . '" />')
+ 'META' => '<meta http-equiv="refresh" content="5; url=' . $url . '" />')
);
}
}
diff --git a/phpBB/install/install_install.php b/phpBB/install/install_install.php
index f0280acc40..5bf3f572d9 100644
--- a/phpBB/install/install_install.php
+++ b/phpBB/install/install_install.php
@@ -53,7 +53,7 @@ class install_install extends module
function main($mode, $sub)
{
global $lang, $template, $language, $phpbb_root_path, $phpEx;
- global $phpbb_container, $cache;
+ global $phpbb_container, $cache, $phpbb_log;
switch ($sub)
{
@@ -105,8 +105,9 @@ class install_install extends module
// Create a normal container now
$phpbb_container = phpbb_create_default_container($phpbb_root_path, $phpEx);
- // Sets the global $cache variable
+ // Sets the global variables
$cache = $phpbb_container->get('cache');
+ $phpbb_log = $phpbb_container->get('log');
$this->build_search_index($mode, $sub);
$this->add_modules($mode, $sub);
@@ -114,7 +115,7 @@ class install_install extends module
$this->add_bots($mode, $sub);
$this->email_admin($mode, $sub);
$this->disable_avatars_if_unwritable();
- $this->populate_migrations($phpbb_container->get('migrator'), $phpbb_root_path);
+ $this->populate_migrations($phpbb_container->get('ext.manager'), $phpbb_container->get('migrator'));
// Remove the lock file
@unlink($phpbb_root_path . 'cache/install_lock');
@@ -1021,8 +1022,8 @@ class install_install extends module
}
// Replace backslashes and doubled slashes (could happen on some proxy setups)
- $name = str_replace(array('\\', '//', '/install'), '/', $name);
- $data['script_path'] = trim(dirname($name));
+ $name = str_replace(array('\\', '//'), '/', $name);
+ $data['script_path'] = trim(dirname(dirname($name)));
}
foreach ($this->advanced_config_options as $config_key => $vars)
@@ -1888,12 +1889,17 @@ class install_install extends module
* "installs" means it adds all migrations to the migrations table, but does not
* perform any of the actions in the migrations.
*
+ * @param phpbb_extension_manager $extension_manager
* @param phpbb_db_migrator $migrator
- * @param string $phpbb_root_path
*/
- function populate_migrations($migrator, $phpbb_root_path)
+ function populate_migrations($extension_manager, $migrator)
{
- $migrator->populate_migrations_from_directory($phpbb_root_path . 'includes/db/migration/data/');
+ $finder = $extension_manager->get_finder();
+
+ $migrations = $finder
+ ->core_path('includes/db/migration/data/')
+ ->get_classes();
+ $migrator->populate_migrations($migrations);
}
/**
@@ -1971,7 +1977,7 @@ class install_install extends module
'admin_name' => array('lang' => 'ADMIN_USERNAME', 'type' => 'text:25:100', 'explain' => true),
'admin_pass1' => array('lang' => 'ADMIN_PASSWORD', 'type' => 'password:25:100', 'explain' => true),
'admin_pass2' => array('lang' => 'ADMIN_PASSWORD_CONFIRM', 'type' => 'password:25:100', 'explain' => false),
- 'board_email' => array('lang' => 'CONTACT_EMAIL', 'type' => 'text:25:100', 'explain' => false),
+ 'board_email' => array('lang' => 'CONTACT_EMAIL', 'type' => 'email:25:100', 'explain' => false),
);
var $advanced_config_options = array(
'legend1' => 'ACP_EMAIL_SETTINGS',
diff --git a/phpBB/install/install_update.php b/phpBB/install/install_update.php
index bfceed6b17..aa1bd0fa35 100644
--- a/phpBB/install/install_update.php
+++ b/phpBB/install/install_update.php
@@ -72,7 +72,13 @@ class install_update extends module
function main($mode, $sub)
{
global $phpbb_style, $template, $phpEx, $phpbb_root_path, $user, $db, $config, $cache, $auth, $language;
- global $request, $phpbb_admin_path, $phpbb_adm_relative_path;
+ global $request, $phpbb_admin_path, $phpbb_adm_relative_path, $phpbb_container;
+
+ // Create a normal container now
+ $phpbb_container = phpbb_create_default_container($phpbb_root_path, $phpEx);
+
+ // Writes into global $cache
+ $cache = $phpbb_container->get('cache');
$this->tpl_name = 'install_update';
$this->page_title = 'UPDATE_INSTALLATION';
diff --git a/phpBB/install/schemas/firebird_schema.sql b/phpBB/install/schemas/firebird_schema.sql
index d0f8d8e70f..a64b8eeffc 100644
--- a/phpBB/install/schemas/firebird_schema.sql
+++ b/phpBB/install/schemas/firebird_schema.sql
@@ -222,6 +222,15 @@ ALTER TABLE phpbb_config ADD PRIMARY KEY (config_name);;
CREATE INDEX phpbb_config_is_dynamic ON phpbb_config(is_dynamic);;
+# Table: 'phpbb_config_text'
+CREATE TABLE phpbb_config_text (
+ config_name VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
+ config_value BLOB SUB_TYPE TEXT CHARACTER SET NONE DEFAULT '' NOT NULL
+);;
+
+ALTER TABLE phpbb_config_text ADD PRIMARY KEY (config_name);;
+
+
# Table: 'phpbb_confirm'
CREATE TABLE phpbb_confirm (
confirm_id CHAR(32) CHARACTER SET NONE DEFAULT '' NOT NULL,
@@ -445,7 +454,7 @@ CREATE TABLE phpbb_groups (
group_desc_uid VARCHAR(8) CHARACTER SET NONE DEFAULT '' NOT NULL,
group_display INTEGER DEFAULT 0 NOT NULL,
group_avatar VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
- group_avatar_type INTEGER DEFAULT 0 NOT NULL,
+ group_avatar_type VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
group_avatar_width INTEGER DEFAULT 0 NOT NULL,
group_avatar_height INTEGER DEFAULT 0 NOT NULL,
group_rank INTEGER DEFAULT 0 NOT NULL,
@@ -454,8 +463,7 @@ CREATE TABLE phpbb_groups (
group_receive_pm INTEGER DEFAULT 0 NOT NULL,
group_message_limit INTEGER DEFAULT 0 NOT NULL,
group_max_recipients INTEGER DEFAULT 0 NOT NULL,
- group_legend INTEGER DEFAULT 0 NOT NULL,
- group_teampage INTEGER DEFAULT 0 NOT NULL
+ group_legend INTEGER DEFAULT 0 NOT NULL
);;
ALTER TABLE phpbb_groups ADD PRIMARY KEY (group_id);;
@@ -634,17 +642,30 @@ END;;
# Table: 'phpbb_notification_types'
CREATE TABLE phpbb_notification_types (
- notification_type VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
+ notification_type_id INTEGER NOT NULL,
+ notification_type_name VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
notification_type_enabled INTEGER DEFAULT 1 NOT NULL
);;
-ALTER TABLE phpbb_notification_types ADD PRIMARY KEY (notification_type, notification_type_enabled);;
+ALTER TABLE phpbb_notification_types ADD PRIMARY KEY (notification_type_id);;
+
+CREATE UNIQUE INDEX phpbb_notification_types_type ON phpbb_notification_types(notification_type_name);;
+
+CREATE GENERATOR phpbb_notification_types_gen;;
+SET GENERATOR phpbb_notification_types_gen TO 0;;
+
+CREATE TRIGGER t_phpbb_notification_types FOR phpbb_notification_types
+BEFORE INSERT
+AS
+BEGIN
+ NEW.notification_type_id = GEN_ID(phpbb_notification_types_gen, 1);
+END;;
# Table: 'phpbb_notifications'
CREATE TABLE phpbb_notifications (
notification_id INTEGER NOT NULL,
- item_type VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
+ notification_type_id INTEGER DEFAULT 0 NOT NULL,
item_id INTEGER DEFAULT 0 NOT NULL,
item_parent_id INTEGER DEFAULT 0 NOT NULL,
user_id INTEGER DEFAULT 0 NOT NULL,
@@ -655,7 +676,7 @@ CREATE TABLE phpbb_notifications (
ALTER TABLE phpbb_notifications ADD PRIMARY KEY (notification_id);;
-CREATE INDEX phpbb_notifications_item_ident ON phpbb_notifications(item_type, item_id);;
+CREATE INDEX phpbb_notifications_item_ident ON phpbb_notifications(notification_type_id, item_id);;
CREATE INDEX phpbb_notifications_user ON phpbb_notifications(user_id, notification_read);;
CREATE GENERATOR phpbb_notifications_gen;;
@@ -1165,6 +1186,29 @@ BEGIN
END;;
+# Table: 'phpbb_teampage'
+CREATE TABLE phpbb_teampage (
+ teampage_id INTEGER NOT NULL,
+ group_id INTEGER DEFAULT 0 NOT NULL,
+ teampage_name VARCHAR(255) CHARACTER SET UTF8 DEFAULT '' NOT NULL COLLATE UNICODE,
+ teampage_position INTEGER DEFAULT 0 NOT NULL,
+ teampage_parent INTEGER DEFAULT 0 NOT NULL
+);;
+
+ALTER TABLE phpbb_teampage ADD PRIMARY KEY (teampage_id);;
+
+
+CREATE GENERATOR phpbb_teampage_gen;;
+SET GENERATOR phpbb_teampage_gen TO 0;;
+
+CREATE TRIGGER t_phpbb_teampage FOR phpbb_teampage
+BEFORE INSERT
+AS
+BEGIN
+ NEW.teampage_id = GEN_ID(phpbb_teampage_gen, 1);
+END;;
+
+
# Table: 'phpbb_topics'
CREATE TABLE phpbb_topics (
topic_id INTEGER NOT NULL,
@@ -1335,7 +1379,7 @@ CREATE TABLE phpbb_users (
user_allow_massemail INTEGER DEFAULT 1 NOT NULL,
user_options INTEGER DEFAULT 230271 NOT NULL,
user_avatar VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
- user_avatar_type INTEGER DEFAULT 0 NOT NULL,
+ user_avatar_type VARCHAR(255) CHARACTER SET NONE DEFAULT '' NOT NULL,
user_avatar_width INTEGER DEFAULT 0 NOT NULL,
user_avatar_height INTEGER DEFAULT 0 NOT NULL,
user_sig BLOB SUB_TYPE TEXT CHARACTER SET UTF8 DEFAULT '' NOT NULL,
diff --git a/phpBB/install/schemas/mssql_schema.sql b/phpBB/install/schemas/mssql_schema.sql
index 3f6c694f32..8465dc4d72 100644
--- a/phpBB/install/schemas/mssql_schema.sql
+++ b/phpBB/install/schemas/mssql_schema.sql
@@ -294,6 +294,23 @@ GO
/*
+ Table: 'phpbb_config_text'
+*/
+CREATE TABLE [phpbb_config_text] (
+ [config_name] [varchar] (255) DEFAULT ('') NOT NULL ,
+ [config_value] [text] DEFAULT ('') NOT NULL
+) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
+GO
+
+ALTER TABLE [phpbb_config_text] WITH NOCHECK ADD
+ CONSTRAINT [PK_phpbb_config_text] PRIMARY KEY CLUSTERED
+ (
+ [config_name]
+ ) ON [PRIMARY]
+GO
+
+
+/*
Table: 'phpbb_confirm'
*/
CREATE TABLE [phpbb_confirm] (
@@ -553,7 +570,7 @@ CREATE TABLE [phpbb_groups] (
[group_desc_uid] [varchar] (8) DEFAULT ('') NOT NULL ,
[group_display] [int] DEFAULT (0) NOT NULL ,
[group_avatar] [varchar] (255) DEFAULT ('') NOT NULL ,
- [group_avatar_type] [int] DEFAULT (0) NOT NULL ,
+ [group_avatar_type] [varchar] (255) DEFAULT ('') NOT NULL ,
[group_avatar_width] [int] DEFAULT (0) NOT NULL ,
[group_avatar_height] [int] DEFAULT (0) NOT NULL ,
[group_rank] [int] DEFAULT (0) NOT NULL ,
@@ -562,8 +579,7 @@ CREATE TABLE [phpbb_groups] (
[group_receive_pm] [int] DEFAULT (0) NOT NULL ,
[group_message_limit] [int] DEFAULT (0) NOT NULL ,
[group_max_recipients] [int] DEFAULT (0) NOT NULL ,
- [group_legend] [int] DEFAULT (0) NOT NULL ,
- [group_teampage] [int] DEFAULT (0) NOT NULL
+ [group_legend] [int] DEFAULT (0) NOT NULL
) ON [PRIMARY]
GO
@@ -777,7 +793,8 @@ GO
Table: 'phpbb_notification_types'
*/
CREATE TABLE [phpbb_notification_types] (
- [notification_type] [varchar] (255) DEFAULT ('') NOT NULL ,
+ [notification_type_id] [int] IDENTITY (1, 1) NOT NULL ,
+ [notification_type_name] [varchar] (255) DEFAULT ('') NOT NULL ,
[notification_type_enabled] [int] DEFAULT (1) NOT NULL
) ON [PRIMARY]
GO
@@ -785,18 +802,20 @@ GO
ALTER TABLE [phpbb_notification_types] WITH NOCHECK ADD
CONSTRAINT [PK_phpbb_notification_types] PRIMARY KEY CLUSTERED
(
- [notification_type],
- [notification_type_enabled]
+ [notification_type_id]
) ON [PRIMARY]
GO
+CREATE UNIQUE INDEX [type] ON [phpbb_notification_types]([notification_type_name]) ON [PRIMARY]
+GO
+
/*
Table: 'phpbb_notifications'
*/
CREATE TABLE [phpbb_notifications] (
[notification_id] [int] IDENTITY (1, 1) NOT NULL ,
- [item_type] [varchar] (255) DEFAULT ('') NOT NULL ,
+ [notification_type_id] [int] DEFAULT (0) NOT NULL ,
[item_id] [int] DEFAULT (0) NOT NULL ,
[item_parent_id] [int] DEFAULT (0) NOT NULL ,
[user_id] [int] DEFAULT (0) NOT NULL ,
@@ -813,7 +832,7 @@ ALTER TABLE [phpbb_notifications] WITH NOCHECK ADD
) ON [PRIMARY]
GO
-CREATE INDEX [item_ident] ON [phpbb_notifications]([item_type], [item_id]) ON [PRIMARY]
+CREATE INDEX [item_ident] ON [phpbb_notifications]([notification_type_id], [item_id]) ON [PRIMARY]
GO
CREATE INDEX [user] ON [phpbb_notifications]([user_id], [notification_read]) ON [PRIMARY]
@@ -1417,6 +1436,26 @@ GO
/*
+ Table: 'phpbb_teampage'
+*/
+CREATE TABLE [phpbb_teampage] (
+ [teampage_id] [int] IDENTITY (1, 1) NOT NULL ,
+ [group_id] [int] DEFAULT (0) NOT NULL ,
+ [teampage_name] [varchar] (255) DEFAULT ('') NOT NULL ,
+ [teampage_position] [int] DEFAULT (0) NOT NULL ,
+ [teampage_parent] [int] DEFAULT (0) NOT NULL
+) ON [PRIMARY]
+GO
+
+ALTER TABLE [phpbb_teampage] WITH NOCHECK ADD
+ CONSTRAINT [PK_phpbb_teampage] PRIMARY KEY CLUSTERED
+ (
+ [teampage_id]
+ ) ON [PRIMARY]
+GO
+
+
+/*
Table: 'phpbb_topics'
*/
CREATE TABLE [phpbb_topics] (
@@ -1640,7 +1679,7 @@ CREATE TABLE [phpbb_users] (
[user_allow_massemail] [int] DEFAULT (1) NOT NULL ,
[user_options] [int] DEFAULT (230271) NOT NULL ,
[user_avatar] [varchar] (255) DEFAULT ('') NOT NULL ,
- [user_avatar_type] [int] DEFAULT (0) NOT NULL ,
+ [user_avatar_type] [varchar] (255) DEFAULT ('') NOT NULL ,
[user_avatar_width] [int] DEFAULT (0) NOT NULL ,
[user_avatar_height] [int] DEFAULT (0) NOT NULL ,
[user_sig] [text] DEFAULT ('') NOT NULL ,
diff --git a/phpBB/install/schemas/mysql_40_schema.sql b/phpBB/install/schemas/mysql_40_schema.sql
index 42196fe8c3..37e4e66ad7 100644
--- a/phpBB/install/schemas/mysql_40_schema.sql
+++ b/phpBB/install/schemas/mysql_40_schema.sql
@@ -157,6 +157,14 @@ CREATE TABLE phpbb_config (
);
+# Table: 'phpbb_config_text'
+CREATE TABLE phpbb_config_text (
+ config_name varbinary(255) DEFAULT '' NOT NULL,
+ config_value mediumblob NOT NULL,
+ PRIMARY KEY (config_name)
+);
+
+
# Table: 'phpbb_confirm'
CREATE TABLE phpbb_confirm (
confirm_id binary(32) DEFAULT '' NOT NULL,
@@ -317,7 +325,7 @@ CREATE TABLE phpbb_groups (
group_desc_uid varbinary(8) DEFAULT '' NOT NULL,
group_display tinyint(1) UNSIGNED DEFAULT '0' NOT NULL,
group_avatar varbinary(255) DEFAULT '' NOT NULL,
- group_avatar_type tinyint(2) DEFAULT '0' NOT NULL,
+ group_avatar_type varbinary(255) DEFAULT '' NOT NULL,
group_avatar_width smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
group_avatar_height smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
group_rank mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
@@ -327,7 +335,6 @@ CREATE TABLE phpbb_groups (
group_message_limit mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
group_max_recipients mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
group_legend mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
- group_teampage mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
PRIMARY KEY (group_id),
KEY group_legend_name (group_legend, group_name(255))
);
@@ -445,16 +452,18 @@ CREATE TABLE phpbb_modules (
# Table: 'phpbb_notification_types'
CREATE TABLE phpbb_notification_types (
- notification_type varbinary(255) DEFAULT '' NOT NULL,
+ notification_type_id smallint(4) UNSIGNED NOT NULL auto_increment,
+ notification_type_name varbinary(255) DEFAULT '' NOT NULL,
notification_type_enabled tinyint(1) UNSIGNED DEFAULT '1' NOT NULL,
- PRIMARY KEY (notification_type, notification_type_enabled)
+ PRIMARY KEY (notification_type_id),
+ UNIQUE type (notification_type_name)
);
# Table: 'phpbb_notifications'
CREATE TABLE phpbb_notifications (
- notification_id mediumint(8) UNSIGNED NOT NULL auto_increment,
- item_type varbinary(255) DEFAULT '' NOT NULL,
+ notification_id int(10) UNSIGNED NOT NULL auto_increment,
+ notification_type_id smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
item_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
item_parent_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
user_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
@@ -462,7 +471,7 @@ CREATE TABLE phpbb_notifications (
notification_time int(11) UNSIGNED DEFAULT '1' NOT NULL,
notification_data blob NOT NULL,
PRIMARY KEY (notification_id),
- KEY item_ident (item_type, item_id),
+ KEY item_ident (notification_type_id, item_id),
KEY user (user_id, notification_read)
);
@@ -813,6 +822,17 @@ CREATE TABLE phpbb_styles (
);
+# Table: 'phpbb_teampage'
+CREATE TABLE phpbb_teampage (
+ teampage_id mediumint(8) UNSIGNED NOT NULL auto_increment,
+ group_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ teampage_name blob NOT NULL,
+ teampage_position mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ teampage_parent mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ PRIMARY KEY (teampage_id)
+);
+
+
# Table: 'phpbb_topics'
CREATE TABLE phpbb_topics (
topic_id mediumint(8) UNSIGNED NOT NULL auto_increment,
@@ -969,7 +989,7 @@ CREATE TABLE phpbb_users (
user_allow_massemail tinyint(1) UNSIGNED DEFAULT '1' NOT NULL,
user_options int(11) UNSIGNED DEFAULT '230271' NOT NULL,
user_avatar varbinary(255) DEFAULT '' NOT NULL,
- user_avatar_type tinyint(2) DEFAULT '0' NOT NULL,
+ user_avatar_type varbinary(255) DEFAULT '' NOT NULL,
user_avatar_width smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
user_avatar_height smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
user_sig mediumblob NOT NULL,
diff --git a/phpBB/install/schemas/mysql_41_schema.sql b/phpBB/install/schemas/mysql_41_schema.sql
index c3424bc79b..ff0f315f93 100644
--- a/phpBB/install/schemas/mysql_41_schema.sql
+++ b/phpBB/install/schemas/mysql_41_schema.sql
@@ -157,6 +157,14 @@ CREATE TABLE phpbb_config (
) CHARACTER SET `utf8` COLLATE `utf8_bin`;
+# Table: 'phpbb_config_text'
+CREATE TABLE phpbb_config_text (
+ config_name varchar(255) DEFAULT '' NOT NULL,
+ config_value mediumtext NOT NULL,
+ PRIMARY KEY (config_name)
+) CHARACTER SET `utf8` COLLATE `utf8_bin`;
+
+
# Table: 'phpbb_confirm'
CREATE TABLE phpbb_confirm (
confirm_id char(32) DEFAULT '' NOT NULL,
@@ -317,7 +325,7 @@ CREATE TABLE phpbb_groups (
group_desc_uid varchar(8) DEFAULT '' NOT NULL,
group_display tinyint(1) UNSIGNED DEFAULT '0' NOT NULL,
group_avatar varchar(255) DEFAULT '' NOT NULL,
- group_avatar_type tinyint(2) DEFAULT '0' NOT NULL,
+ group_avatar_type varchar(255) DEFAULT '' NOT NULL,
group_avatar_width smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
group_avatar_height smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
group_rank mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
@@ -327,7 +335,6 @@ CREATE TABLE phpbb_groups (
group_message_limit mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
group_max_recipients mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
group_legend mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
- group_teampage mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
PRIMARY KEY (group_id),
KEY group_legend_name (group_legend, group_name)
) CHARACTER SET `utf8` COLLATE `utf8_bin`;
@@ -445,16 +452,18 @@ CREATE TABLE phpbb_modules (
# Table: 'phpbb_notification_types'
CREATE TABLE phpbb_notification_types (
- notification_type varchar(255) DEFAULT '' NOT NULL,
+ notification_type_id smallint(4) UNSIGNED NOT NULL auto_increment,
+ notification_type_name varchar(255) DEFAULT '' NOT NULL,
notification_type_enabled tinyint(1) UNSIGNED DEFAULT '1' NOT NULL,
- PRIMARY KEY (notification_type, notification_type_enabled)
+ PRIMARY KEY (notification_type_id),
+ UNIQUE type (notification_type_name)
) CHARACTER SET `utf8` COLLATE `utf8_bin`;
# Table: 'phpbb_notifications'
CREATE TABLE phpbb_notifications (
- notification_id mediumint(8) UNSIGNED NOT NULL auto_increment,
- item_type varchar(255) DEFAULT '' NOT NULL,
+ notification_id int(10) UNSIGNED NOT NULL auto_increment,
+ notification_type_id smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
item_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
item_parent_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
user_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
@@ -462,7 +471,7 @@ CREATE TABLE phpbb_notifications (
notification_time int(11) UNSIGNED DEFAULT '1' NOT NULL,
notification_data text NOT NULL,
PRIMARY KEY (notification_id),
- KEY item_ident (item_type, item_id),
+ KEY item_ident (notification_type_id, item_id),
KEY user (user_id, notification_read)
) CHARACTER SET `utf8` COLLATE `utf8_bin`;
@@ -813,6 +822,17 @@ CREATE TABLE phpbb_styles (
) CHARACTER SET `utf8` COLLATE `utf8_bin`;
+# Table: 'phpbb_teampage'
+CREATE TABLE phpbb_teampage (
+ teampage_id mediumint(8) UNSIGNED NOT NULL auto_increment,
+ group_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ teampage_name varchar(255) DEFAULT '' NOT NULL,
+ teampage_position mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ teampage_parent mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
+ PRIMARY KEY (teampage_id)
+) CHARACTER SET `utf8` COLLATE `utf8_bin`;
+
+
# Table: 'phpbb_topics'
CREATE TABLE phpbb_topics (
topic_id mediumint(8) UNSIGNED NOT NULL auto_increment,
@@ -969,7 +989,7 @@ CREATE TABLE phpbb_users (
user_allow_massemail tinyint(1) UNSIGNED DEFAULT '1' NOT NULL,
user_options int(11) UNSIGNED DEFAULT '230271' NOT NULL,
user_avatar varchar(255) DEFAULT '' NOT NULL,
- user_avatar_type tinyint(2) DEFAULT '0' NOT NULL,
+ user_avatar_type varchar(255) DEFAULT '' NOT NULL,
user_avatar_width smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
user_avatar_height smallint(4) UNSIGNED DEFAULT '0' NOT NULL,
user_sig mediumtext NOT NULL,
diff --git a/phpBB/install/schemas/oracle_schema.sql b/phpBB/install/schemas/oracle_schema.sql
index 5dfb6ee243..11f245869d 100644
--- a/phpBB/install/schemas/oracle_schema.sql
+++ b/phpBB/install/schemas/oracle_schema.sql
@@ -332,6 +332,17 @@ CREATE INDEX phpbb_config_is_dynamic ON phpbb_config (is_dynamic)
/
/*
+ Table: 'phpbb_config_text'
+*/
+CREATE TABLE phpbb_config_text (
+ config_name varchar2(255) DEFAULT '' ,
+ config_value clob DEFAULT '' ,
+ CONSTRAINT pk_phpbb_config_text PRIMARY KEY (config_name)
+)
+/
+
+
+/*
Table: 'phpbb_confirm'
*/
CREATE TABLE phpbb_confirm (
@@ -610,7 +621,7 @@ CREATE TABLE phpbb_groups (
group_desc_uid varchar2(8) DEFAULT '' ,
group_display number(1) DEFAULT '0' NOT NULL,
group_avatar varchar2(255) DEFAULT '' ,
- group_avatar_type number(2) DEFAULT '0' NOT NULL,
+ group_avatar_type varchar2(255) DEFAULT '' ,
group_avatar_width number(4) DEFAULT '0' NOT NULL,
group_avatar_height number(4) DEFAULT '0' NOT NULL,
group_rank number(8) DEFAULT '0' NOT NULL,
@@ -620,7 +631,6 @@ CREATE TABLE phpbb_groups (
group_message_limit number(8) DEFAULT '0' NOT NULL,
group_max_recipients number(8) DEFAULT '0' NOT NULL,
group_legend number(8) DEFAULT '0' NOT NULL,
- group_teampage number(8) DEFAULT '0' NOT NULL,
CONSTRAINT pk_phpbb_groups PRIMARY KEY (group_id)
)
/
@@ -860,10 +870,28 @@ END;
Table: 'phpbb_notification_types'
*/
CREATE TABLE phpbb_notification_types (
- notification_type varchar2(255) DEFAULT '' ,
+ notification_type_id number(4) NOT NULL,
+ notification_type_name varchar2(255) DEFAULT '' ,
notification_type_enabled number(1) DEFAULT '1' NOT NULL,
- CONSTRAINT pk_phpbb_notification_types PRIMARY KEY (notification_type, notification_type_enabled)
+ CONSTRAINT pk_phpbb_notification_types PRIMARY KEY (notification_type_id),
+ CONSTRAINT u_phpbb_type UNIQUE (notification_type_name)
+)
+/
+
+
+CREATE SEQUENCE phpbb_notification_types_seq
+/
+
+CREATE OR REPLACE TRIGGER t_phpbb_notification_types
+BEFORE INSERT ON phpbb_notification_types
+FOR EACH ROW WHEN (
+ new.notification_type_id IS NULL OR new.notification_type_id = 0
)
+BEGIN
+ SELECT phpbb_notification_types_seq.nextval
+ INTO :new.notification_type_id
+ FROM dual;
+END;
/
@@ -871,8 +899,8 @@ CREATE TABLE phpbb_notification_types (
Table: 'phpbb_notifications'
*/
CREATE TABLE phpbb_notifications (
- notification_id number(8) NOT NULL,
- item_type varchar2(255) DEFAULT '' ,
+ notification_id number(10) NOT NULL,
+ notification_type_id number(4) DEFAULT '0' NOT NULL,
item_id number(8) DEFAULT '0' NOT NULL,
item_parent_id number(8) DEFAULT '0' NOT NULL,
user_id number(8) DEFAULT '0' NOT NULL,
@@ -883,7 +911,7 @@ CREATE TABLE phpbb_notifications (
)
/
-CREATE INDEX phpbb_notifications_item_ident ON phpbb_notifications (item_type, item_id)
+CREATE INDEX phpbb_notifications_item_ident ON phpbb_notifications (notification_type_id, item_id)
/
CREATE INDEX phpbb_notifications_user ON phpbb_notifications (user_id, notification_read)
/
@@ -1542,6 +1570,36 @@ END;
/*
+ Table: 'phpbb_teampage'
+*/
+CREATE TABLE phpbb_teampage (
+ teampage_id number(8) NOT NULL,
+ group_id number(8) DEFAULT '0' NOT NULL,
+ teampage_name varchar2(765) DEFAULT '' ,
+ teampage_position number(8) DEFAULT '0' NOT NULL,
+ teampage_parent number(8) DEFAULT '0' NOT NULL,
+ CONSTRAINT pk_phpbb_teampage PRIMARY KEY (teampage_id)
+)
+/
+
+
+CREATE SEQUENCE phpbb_teampage_seq
+/
+
+CREATE OR REPLACE TRIGGER t_phpbb_teampage
+BEFORE INSERT ON phpbb_teampage
+FOR EACH ROW WHEN (
+ new.teampage_id IS NULL OR new.teampage_id = 0
+)
+BEGIN
+ SELECT phpbb_teampage_seq.nextval
+ INTO :new.teampage_id
+ FROM dual;
+END;
+/
+
+
+/*
Table: 'phpbb_topics'
*/
CREATE TABLE phpbb_topics (
@@ -1747,7 +1805,7 @@ CREATE TABLE phpbb_users (
user_allow_massemail number(1) DEFAULT '1' NOT NULL,
user_options number(11) DEFAULT '230271' NOT NULL,
user_avatar varchar2(255) DEFAULT '' ,
- user_avatar_type number(2) DEFAULT '0' NOT NULL,
+ user_avatar_type varchar2(255) DEFAULT '' ,
user_avatar_width number(4) DEFAULT '0' NOT NULL,
user_avatar_height number(4) DEFAULT '0' NOT NULL,
user_sig clob DEFAULT '' ,
diff --git a/phpBB/install/schemas/postgres_schema.sql b/phpBB/install/schemas/postgres_schema.sql
index 07ca7f1e95..fea5700167 100644
--- a/phpBB/install/schemas/postgres_schema.sql
+++ b/phpBB/install/schemas/postgres_schema.sql
@@ -270,6 +270,16 @@ CREATE TABLE phpbb_config (
CREATE INDEX phpbb_config_is_dynamic ON phpbb_config (is_dynamic);
/*
+ Table: 'phpbb_config_text'
+*/
+CREATE TABLE phpbb_config_text (
+ config_name varchar(255) DEFAULT '' NOT NULL,
+ config_value TEXT DEFAULT '' NOT NULL,
+ PRIMARY KEY (config_name)
+);
+
+
+/*
Table: 'phpbb_confirm'
*/
CREATE TABLE phpbb_confirm (
@@ -463,7 +473,7 @@ CREATE TABLE phpbb_groups (
group_desc_uid varchar(8) DEFAULT '' NOT NULL,
group_display INT2 DEFAULT '0' NOT NULL CHECK (group_display >= 0),
group_avatar varchar(255) DEFAULT '' NOT NULL,
- group_avatar_type INT2 DEFAULT '0' NOT NULL,
+ group_avatar_type varchar(255) DEFAULT '' NOT NULL,
group_avatar_width INT2 DEFAULT '0' NOT NULL CHECK (group_avatar_width >= 0),
group_avatar_height INT2 DEFAULT '0' NOT NULL CHECK (group_avatar_height >= 0),
group_rank INT4 DEFAULT '0' NOT NULL CHECK (group_rank >= 0),
@@ -473,7 +483,6 @@ CREATE TABLE phpbb_groups (
group_message_limit INT4 DEFAULT '0' NOT NULL CHECK (group_message_limit >= 0),
group_max_recipients INT4 DEFAULT '0' NOT NULL CHECK (group_max_recipients >= 0),
group_legend INT4 DEFAULT '0' NOT NULL CHECK (group_legend >= 0),
- group_teampage INT4 DEFAULT '0' NOT NULL CHECK (group_teampage >= 0),
PRIMARY KEY (group_id)
);
@@ -614,12 +623,16 @@ CREATE INDEX phpbb_modules_class_left_id ON phpbb_modules (module_class, left_id
/*
Table: 'phpbb_notification_types'
*/
+CREATE SEQUENCE phpbb_notification_types_seq;
+
CREATE TABLE phpbb_notification_types (
- notification_type varchar(255) DEFAULT '' NOT NULL,
+ notification_type_id INT2 DEFAULT nextval('phpbb_notification_types_seq'),
+ notification_type_name varchar(255) DEFAULT '' NOT NULL,
notification_type_enabled INT2 DEFAULT '1' NOT NULL CHECK (notification_type_enabled >= 0),
- PRIMARY KEY (notification_type, notification_type_enabled)
+ PRIMARY KEY (notification_type_id)
);
+CREATE UNIQUE INDEX phpbb_notification_types_type ON phpbb_notification_types (notification_type_name);
/*
Table: 'phpbb_notifications'
@@ -628,7 +641,7 @@ CREATE SEQUENCE phpbb_notifications_seq;
CREATE TABLE phpbb_notifications (
notification_id INT4 DEFAULT nextval('phpbb_notifications_seq'),
- item_type varchar(255) DEFAULT '' NOT NULL,
+ notification_type_id INT2 DEFAULT '0' NOT NULL CHECK (notification_type_id >= 0),
item_id INT4 DEFAULT '0' NOT NULL CHECK (item_id >= 0),
item_parent_id INT4 DEFAULT '0' NOT NULL CHECK (item_parent_id >= 0),
user_id INT4 DEFAULT '0' NOT NULL CHECK (user_id >= 0),
@@ -638,7 +651,7 @@ CREATE TABLE phpbb_notifications (
PRIMARY KEY (notification_id)
);
-CREATE INDEX phpbb_notifications_item_ident ON phpbb_notifications (item_type, item_id);
+CREATE INDEX phpbb_notifications_item_ident ON phpbb_notifications (notification_type_id, item_id);
CREATE INDEX phpbb_notifications_user ON phpbb_notifications (user_id, notification_read);
/*
@@ -1056,6 +1069,21 @@ CREATE TABLE phpbb_styles (
CREATE UNIQUE INDEX phpbb_styles_style_name ON phpbb_styles (style_name);
/*
+ Table: 'phpbb_teampage'
+*/
+CREATE SEQUENCE phpbb_teampage_seq;
+
+CREATE TABLE phpbb_teampage (
+ teampage_id INT4 DEFAULT nextval('phpbb_teampage_seq'),
+ group_id INT4 DEFAULT '0' NOT NULL CHECK (group_id >= 0),
+ teampage_name varchar(255) DEFAULT '' NOT NULL,
+ teampage_position INT4 DEFAULT '0' NOT NULL CHECK (teampage_position >= 0),
+ teampage_parent INT4 DEFAULT '0' NOT NULL CHECK (teampage_parent >= 0),
+ PRIMARY KEY (teampage_id)
+);
+
+
+/*
Table: 'phpbb_topics'
*/
CREATE SEQUENCE phpbb_topics_seq;
@@ -1229,7 +1257,7 @@ CREATE TABLE phpbb_users (
user_allow_massemail INT2 DEFAULT '1' NOT NULL CHECK (user_allow_massemail >= 0),
user_options INT4 DEFAULT '230271' NOT NULL CHECK (user_options >= 0),
user_avatar varchar(255) DEFAULT '' NOT NULL,
- user_avatar_type INT2 DEFAULT '0' NOT NULL,
+ user_avatar_type varchar(255) DEFAULT '' NOT NULL,
user_avatar_width INT2 DEFAULT '0' NOT NULL CHECK (user_avatar_width >= 0),
user_avatar_height INT2 DEFAULT '0' NOT NULL CHECK (user_avatar_height >= 0),
user_sig TEXT DEFAULT '' NOT NULL,
diff --git a/phpBB/install/schemas/schema_data.sql b/phpBB/install/schemas/schema_data.sql
index d145aa37fc..355981721e 100644
--- a/phpBB/install/schemas/schema_data.sql
+++ b/phpBB/install/schemas/schema_data.sql
@@ -9,6 +9,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('active_sessions',
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_attachments', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_autologin', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_avatar', '1');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_avatar_gravatar', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_avatar_local', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_avatar_remote', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_avatar_upload', '1');
@@ -17,6 +18,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_bbcode', '1'
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_birthdays', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_bookmarks', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_emailreuse', '0');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_password_reset', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_forum_notify', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_mass_pm', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('allow_name_chars', 'USERNAME_CHARS_ANY');
@@ -58,6 +60,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('board_email', 'add
INSERT INTO phpbb_config (config_name, config_value) VALUES ('board_email_form', '0');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('board_email_sig', '{L_CONFIG_BOARD_EMAIL_SIG}');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('board_hide_emails', '1');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('board_index_text', '');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('board_timezone', 'UTC');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('browser_check', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('bump_interval', '10');
@@ -172,7 +175,7 @@ INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_cpf_viewtopic
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_db_lastread', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_db_track', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_jquery_cdn', '0');
-INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_jquery_url', '//ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js');
+INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_jquery_url', '//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_jumpbox', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_moderators', '1');
INSERT INTO phpbb_config (config_name, config_value) VALUES ('load_notifications', '1');
@@ -461,13 +464,17 @@ INSERT INTO phpbb_users (user_type, group_id, username, username_clean, user_reg
INSERT INTO phpbb_users (user_type, group_id, username, username_clean, user_regdate, user_password, user_email, user_lang, user_style, user_rank, user_colour, user_posts, user_permissions, user_ip, user_birthday, user_lastpage, user_last_confirm_key, user_post_sortby_type, user_post_sortby_dir, user_topic_sortby_type, user_topic_sortby_dir, user_avatar, user_sig, user_sig_bbcode_uid, user_from, user_icq, user_aim, user_yim, user_msnm, user_jabber, user_website, user_occ, user_interests, user_actkey, user_newpasswd) VALUES (3, 5, 'Admin', 'admin', 0, '21232f297a57a5a743894a0e4a801fc3', 'admin@yourdomain.com', 'en', 1, 1, 'AA0000', 1, '', '', '', '', '', 't', 'a', 't', 'd', '', '', '', '', '', '', '', '', '', '', '', '', '', '');
# -- Groups
-INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_teampage, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('GUESTS', 3, 0, '', 0, 0, '', '', '', 5);
-INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_teampage, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('REGISTERED', 3, 0, '', 0, 0, '', '', '', 5);
-INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_teampage, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('REGISTERED_COPPA', 3, 0, '', 0, 0, '', '', '', 5);
-INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_teampage, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('GLOBAL_MODERATORS', 3, 0, '00AA00', 2, 2, '', '', '', 0);
-INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_teampage, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('ADMINISTRATORS', 3, 1, 'AA0000', 1, 1, '', '', '', 0);
-INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_teampage, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('BOTS', 3, 0, '9E8DA7', 0, 0, '', '', '', 5);
-INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_teampage, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('NEWLY_REGISTERED', 3, 0, '', 0, 0, '', '', '', 5);
+INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('GUESTS', 3, 0, '', 0, '', '', '', 5);
+INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('REGISTERED', 3, 0, '', 0, '', '', '', 5);
+INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('REGISTERED_COPPA', 3, 0, '', 0, '', '', '', 5);
+INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('GLOBAL_MODERATORS', 3, 0, '00AA00', 2, '', '', '', 0);
+INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('ADMINISTRATORS', 3, 1, 'AA0000', 1, '', '', '', 0);
+INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('BOTS', 3, 0, '9E8DA7', 0, '', '', '', 5);
+INSERT INTO phpbb_groups (group_name, group_type, group_founder_manage, group_colour, group_legend, group_avatar, group_desc, group_desc_uid, group_max_recipients) VALUES ('NEWLY_REGISTERED', 3, 0, '', 0, '', '', '', 5);
+
+# -- Teampage
+INSERT INTO phpbb_teampage (group_id, teampage_name, teampage_position, teampage_parent) VALUES (5, '', 1, 0);
+INSERT INTO phpbb_teampage (group_id, teampage_name, teampage_position, teampage_parent) VALUES (4, '', 2, 0);
# -- User -> Group
INSERT INTO phpbb_user_group (group_id, user_id, user_pending, group_leader) VALUES (1, 1, 0, 0);
@@ -772,9 +779,9 @@ INSERT INTO phpbb_extensions (group_id, extension) VALUES (9, 'ogg');
INSERT INTO phpbb_extensions (group_id, extension) VALUES (9, 'ogm');
# User Notification Options (for first user)
-INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('phpbb_notification_type_post', 0, 2, '');
-INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('phpbb_notification_type_post', 0, 2, 'phpbb_notification_method_email');
-INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('phpbb_notification_type_topic', 0, 2, '');
-INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('phpbb_notification_type_topic', 0, 2, 'phpbb_notification_method_email');
+INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('post', 0, 2, '');
+INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('post', 0, 2, 'email');
+INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('topic', 0, 2, '');
+INSERT INTO phpbb_user_notifications (item_type, item_id, user_id, method) VALUES('topic', 0, 2, 'email');
# POSTGRES COMMIT #
diff --git a/phpBB/install/schemas/sqlite_schema.sql b/phpBB/install/schemas/sqlite_schema.sql
index 5274e08cca..02ffb9a857 100644
--- a/phpBB/install/schemas/sqlite_schema.sql
+++ b/phpBB/install/schemas/sqlite_schema.sql
@@ -154,6 +154,14 @@ CREATE TABLE phpbb_config (
CREATE INDEX phpbb_config_is_dynamic ON phpbb_config (is_dynamic);
+# Table: 'phpbb_config_text'
+CREATE TABLE phpbb_config_text (
+ config_name varchar(255) NOT NULL DEFAULT '',
+ config_value mediumtext(16777215) NOT NULL DEFAULT '',
+ PRIMARY KEY (config_name)
+);
+
+
# Table: 'phpbb_confirm'
CREATE TABLE phpbb_confirm (
confirm_id char(32) NOT NULL DEFAULT '',
@@ -309,7 +317,7 @@ CREATE TABLE phpbb_groups (
group_desc_uid varchar(8) NOT NULL DEFAULT '',
group_display INTEGER UNSIGNED NOT NULL DEFAULT '0',
group_avatar varchar(255) NOT NULL DEFAULT '',
- group_avatar_type tinyint(2) NOT NULL DEFAULT '0',
+ group_avatar_type varchar(255) NOT NULL DEFAULT '',
group_avatar_width INTEGER UNSIGNED NOT NULL DEFAULT '0',
group_avatar_height INTEGER UNSIGNED NOT NULL DEFAULT '0',
group_rank INTEGER UNSIGNED NOT NULL DEFAULT '0',
@@ -318,8 +326,7 @@ CREATE TABLE phpbb_groups (
group_receive_pm INTEGER UNSIGNED NOT NULL DEFAULT '0',
group_message_limit INTEGER UNSIGNED NOT NULL DEFAULT '0',
group_max_recipients INTEGER UNSIGNED NOT NULL DEFAULT '0',
- group_legend INTEGER UNSIGNED NOT NULL DEFAULT '0',
- group_teampage INTEGER UNSIGNED NOT NULL DEFAULT '0'
+ group_legend INTEGER UNSIGNED NOT NULL DEFAULT '0'
);
CREATE INDEX phpbb_groups_group_legend_name ON phpbb_groups (group_legend, group_name);
@@ -432,16 +439,17 @@ CREATE INDEX phpbb_modules_class_left_id ON phpbb_modules (module_class, left_id
# Table: 'phpbb_notification_types'
CREATE TABLE phpbb_notification_types (
- notification_type varchar(255) NOT NULL DEFAULT '',
- notification_type_enabled INTEGER UNSIGNED NOT NULL DEFAULT '1',
- PRIMARY KEY (notification_type, notification_type_enabled)
+ notification_type_id INTEGER PRIMARY KEY NOT NULL ,
+ notification_type_name varchar(255) NOT NULL DEFAULT '',
+ notification_type_enabled INTEGER UNSIGNED NOT NULL DEFAULT '1'
);
+CREATE UNIQUE INDEX phpbb_notification_types_type ON phpbb_notification_types (notification_type_name);
# Table: 'phpbb_notifications'
CREATE TABLE phpbb_notifications (
notification_id INTEGER PRIMARY KEY NOT NULL ,
- item_type varchar(255) NOT NULL DEFAULT '',
+ notification_type_id INTEGER UNSIGNED NOT NULL DEFAULT '0',
item_id INTEGER UNSIGNED NOT NULL DEFAULT '0',
item_parent_id INTEGER UNSIGNED NOT NULL DEFAULT '0',
user_id INTEGER UNSIGNED NOT NULL DEFAULT '0',
@@ -450,7 +458,7 @@ CREATE TABLE phpbb_notifications (
notification_data text(65535) NOT NULL DEFAULT ''
);
-CREATE INDEX phpbb_notifications_item_ident ON phpbb_notifications (item_type, item_id);
+CREATE INDEX phpbb_notifications_item_ident ON phpbb_notifications (notification_type_id, item_id);
CREATE INDEX phpbb_notifications_user ON phpbb_notifications (user_id, notification_read);
# Table: 'phpbb_poll_options'
@@ -787,6 +795,16 @@ CREATE TABLE phpbb_styles (
CREATE UNIQUE INDEX phpbb_styles_style_name ON phpbb_styles (style_name);
+# Table: 'phpbb_teampage'
+CREATE TABLE phpbb_teampage (
+ teampage_id INTEGER PRIMARY KEY NOT NULL ,
+ group_id INTEGER UNSIGNED NOT NULL DEFAULT '0',
+ teampage_name varchar(255) NOT NULL DEFAULT '',
+ teampage_position INTEGER UNSIGNED NOT NULL DEFAULT '0',
+ teampage_parent INTEGER UNSIGNED NOT NULL DEFAULT '0'
+);
+
+
# Table: 'phpbb_topics'
CREATE TABLE phpbb_topics (
topic_id INTEGER PRIMARY KEY NOT NULL ,
@@ -942,7 +960,7 @@ CREATE TABLE phpbb_users (
user_allow_massemail INTEGER UNSIGNED NOT NULL DEFAULT '1',
user_options INTEGER UNSIGNED NOT NULL DEFAULT '230271',
user_avatar varchar(255) NOT NULL DEFAULT '',
- user_avatar_type tinyint(2) NOT NULL DEFAULT '0',
+ user_avatar_type varchar(255) NOT NULL DEFAULT '',
user_avatar_width INTEGER UNSIGNED NOT NULL DEFAULT '0',
user_avatar_height INTEGER UNSIGNED NOT NULL DEFAULT '0',
user_sig mediumtext(16777215) NOT NULL DEFAULT '',
diff --git a/phpBB/language/en/acp/board.php b/phpBB/language/en/acp/board.php
index 1b99c87938..ce15dfefb4 100644
--- a/phpBB/language/en/acp/board.php
+++ b/phpBB/language/en/acp/board.php
@@ -37,6 +37,8 @@ if (empty($lang) || !is_array($lang))
// Board Settings
$lang = array_merge($lang, array(
'ACP_BOARD_SETTINGS_EXPLAIN' => 'Here you can determine the basic operation of your board, give it a fitting name and description, and among other settings adjust the default values for timezone and language.',
+ 'BOARD_INDEX_TEXT' => 'Board index text',
+ 'BOARD_INDEX_TEXT_EXPLAIN' => 'This text is displayed as the board index in the board’s breadcrumbs. If not specified, it will default to “Board index”.',
'CUSTOM_DATEFORMAT' => 'Custom…',
'DEFAULT_DATE_FORMAT' => 'Date format',
'DEFAULT_DATE_FORMAT_EXPLAIN' => 'The date format is the same as the PHP <code>date</code> function.',
@@ -99,6 +101,7 @@ $lang = array_merge($lang, array(
'ALLOW_AVATARS' => 'Enable avatars',
'ALLOW_AVATARS_EXPLAIN' => 'Allow general usage of avatars;<br />If you disable avatars in general or avatars of a certain mode, the disabled avatars will no longer be shown on the board, but users will still be able to download their own avatars in the User Control Panel.',
+ 'ALLOW_GRAVATAR' => 'Enable gravatar avatars',
'ALLOW_LOCAL' => 'Enable gallery avatars',
'ALLOW_REMOTE' => 'Enable remote avatars',
'ALLOW_REMOTE_EXPLAIN' => 'Avatars linked to from another website.',
@@ -451,6 +454,8 @@ $lang = array_merge($lang, array(
'ALL' => 'All',
'ALLOW_AUTOLOGIN' => 'Allow "Remember Me" logins',
'ALLOW_AUTOLOGIN_EXPLAIN' => 'Determines whether users are given "Remember Me" option when they visit the board.',
+ 'ALLOW_PASSWORD_RESET' => 'Allow password reset ("Forgot Password")',
+ 'ALLOW_PASSWORD_RESET_EXPLAIN' => 'Determines whether or not users are able to use the "I forgot my password" link on the login page to recover their account. If you use an external authentication mechanism you may wish to disable this feature.',
'AUTOLOGIN_LENGTH' => '"Remember Me" login key expiration length (in days)',
'AUTOLOGIN_LENGTH_EXPLAIN' => 'Number of days after which "Remember Me" login keys are removed or zero to disable.',
'BROWSER_VALID' => 'Validate browser',
diff --git a/phpBB/language/en/acp/groups.php b/phpBB/language/en/acp/groups.php
index a5c0af933c..58101e5f60 100644
--- a/phpBB/language/en/acp/groups.php
+++ b/phpBB/language/en/acp/groups.php
@@ -36,6 +36,7 @@ if (empty($lang) || !is_array($lang))
$lang = array_merge($lang, array(
'ACP_GROUPS_MANAGE_EXPLAIN' => 'From this panel you can administer all your usergroups. You can delete, create and edit existing groups. Furthermore, you may choose group leaders, toggle open/hidden/closed group status and set the group name and description.',
+ 'ADD_GROUP_CATEGORY' => 'Add category',
'ADD_USERS' => 'Add users',
'ADD_USERS_EXPLAIN' => 'Here you can add new users to the group. You may select whether this group becomes the new default for the selected users. Additionally you can define them as group leaders. Please enter each username on a separate line.',
@@ -50,6 +51,7 @@ $lang = array_merge($lang, array(
'GROUP_APPROVED' => 'Approved members',
'GROUP_AVATAR' => 'Group avatar',
'GROUP_AVATAR_EXPLAIN' => 'This image will be displayed in the Group Control Panel.',
+ 'GROUP_CATEGORY_NAME' => 'Category name',
'GROUP_CLOSED' => 'Closed',
'GROUP_COLOR' => 'Group colour',
'GROUP_COLOR_EXPLAIN' => 'Defines the colour members’ usernames will appear in, leave blank for user default.',
@@ -130,6 +132,7 @@ $lang = array_merge($lang, array(
'SPECIAL_GROUPS' => 'Pre-defined groups',
'SPECIAL_GROUPS_EXPLAIN' => 'Pre-defined groups are special groups, they cannot be deleted or directly modified. However you can still add users and alter basic settings.',
+ 'TEAMPAGE' => 'Teampage',
'TEAMPAGE_DISP_ALL' => 'All memberships',
'TEAMPAGE_DISP_DEFAULT' => 'User’s default group only',
'TEAMPAGE_DISP_FIRST' => 'First membership only',
diff --git a/phpBB/language/en/acp/prune.php b/phpBB/language/en/acp/prune.php
index fcc085205b..3e890182c0 100644
--- a/phpBB/language/en/acp/prune.php
+++ b/phpBB/language/en/acp/prune.php
@@ -51,7 +51,7 @@ $lang = array_merge($lang, array(
'LAST_ACTIVE_EXPLAIN' => 'Enter a date in <kbd>YYYY-MM-DD</kbd> format. Enter <kbd>0000-00-00</kbd> to prune users who never logged in, <em>Before</em> and <em>After</em> conditions will be ignored.',
'POSTS_ON_QUEUE' => 'Posts Awaiting Approval',
- 'PRUNE_USERS_GROUP_EXPLAIN' => 'Selects all members of the group for pruning.',
+ 'PRUNE_USERS_GROUP_EXPLAIN' => 'Limit to users within the selected group.',
'PRUNE_USERS_LIST' => 'Users to be pruned',
'PRUNE_USERS_LIST_DELETE' => 'With the selected critera for pruning users the following accounts will be removed. You can remove individual users from the deletion list by unchecking the box next to their username.',
'PRUNE_USERS_LIST_DEACTIVATE' => 'With the selected critera for pruning users the following accounts will be deactivated. You can remove individual users from the deactivation list by unchecking the box next to their username.',
diff --git a/phpBB/language/en/captcha_recaptcha.php b/phpBB/language/en/captcha_recaptcha.php
index c72957ca16..3d91a9d110 100644
--- a/phpBB/language/en/captcha_recaptcha.php
+++ b/phpBB/language/en/captcha_recaptcha.php
@@ -46,4 +46,5 @@ $lang = array_merge($lang, array(
'RECAPTCHA_PRIVATE_EXPLAIN' => 'Your private reCaptcha key. Keys can be obtained on <a href="http://www.google.com/recaptcha">www.google.com/recaptcha</a>.',
'RECAPTCHA_EXPLAIN' => 'In an effort to prevent automatic submissions, we require that you enter both of the words displayed into the text field underneath.',
+ 'RECAPTCHA_SOCKET_ERROR' => 'There was a problem connecting to the RECAPTCHA service: could not open socket. Try again later.',
));
diff --git a/phpBB/language/en/common.php b/phpBB/language/en/common.php
index b4ed2f74f3..cdfd3416f5 100644
--- a/phpBB/language/en/common.php
+++ b/phpBB/language/en/common.php
@@ -70,6 +70,9 @@ $lang = array_merge($lang, array(
'AIM' => 'AIM',
'AJAX_ERROR_TITLE' => 'AJAX error',
'AJAX_ERROR_TEXT' => 'Something went wrong when processing your request.',
+ 'AJAX_ERROR_TEXT_ABORT' => 'User aborted request.',
+ 'AJAX_ERROR_TEXT_TIMEOUT' => 'Your request timed out; please try again.',
+ 'AJAX_ERROR_TEXT_PARSERERROR' => 'Something went wrong with the request and the server returned an invalid reply.',
'ALLOWED' => 'Allowed',
'ALL_FILES' => 'All files',
'ALL_FORUMS' => 'All forums',
@@ -313,6 +316,7 @@ $lang = array_merge($lang, array(
'IN' => 'in',
'INDEX' => 'Index page',
'INFORMATION' => 'Information',
+ 'INSECURE_REDIRECT' => 'Tried to redirect to potentially insecure url.',
'INTERESTS' => 'Interests',
'INVALID_DIGEST_CHALLENGE' => 'Invalid digest challenge.',
'INVALID_EMAIL_LOG' => '<strong>%s</strong> possibly an invalid email address?',
@@ -359,6 +363,7 @@ $lang = array_merge($lang, array(
'LOGOUT_USER' => 'Logout [ %s ]',
'LOG_ME_IN' => 'Remember me',
+ 'MAIN' => 'Main',
'MARK' => 'Mark',
'MARK_ALL' => 'Mark all',
'MARK_FORUMS_READ' => 'Mark forums read',
@@ -422,6 +427,7 @@ $lang = array_merge($lang, array(
'NOTIFICATION_TOPIC_APPROVED' => 'Your topic "%2$s" in the forum "%3$s" was approved.',
'NOTIFICATION_TOPIC_DISAPPROVED' => 'Your topic "%1$s" was disapproved for reason: "%2$s".',
'NOTIFICATION_TOPIC_IN_QUEUE' => 'A new topic titled "%2$s" was posted by %1$s and needs approval.',
+ 'NOTIFICATION_TYPE_NOT_EXIST' => 'The notification type "%s" is missing from the file system.',
'NOTIFY_ADMIN' => 'Please notify the board administrator or webmaster.',
'NOTIFY_ADMIN_EMAIL' => 'Please notify the board administrator or webmaster: <a href="mailto:%1$s">%1$s</a>',
'NO_ACCESS_ATTACHMENT' => 'You are not allowed to access this file.',
@@ -430,6 +436,8 @@ $lang = array_merge($lang, array(
'NO_AUTH_ADMIN' => 'Access to the Administration Control Panel is not allowed as you do not have administrative permissions.',
'NO_AUTH_ADMIN_USER_DIFFER' => 'You are not able to re-authenticate as a different user.',
'NO_AUTH_OPERATION' => 'You do not have the necessary permissions to complete this operation.',
+ 'NO_AVATARS' => 'No avatars currently available',
+ 'NO_AVATAR_SELECTED' => 'You have not selected any avatar.',
'NO_CONNECT_TO_SMTP_HOST' => 'Could not connect to smtp host : %1$s : %2$s',
'NO_BIRTHDAYS' => 'No birthdays today',
'NO_EMAIL_MESSAGE' => 'Email message was blank.',
@@ -451,6 +459,7 @@ $lang = array_merge($lang, array(
'NO_POSTS_TIME_FRAME' => 'No posts exist inside this topic for the selected time frame.',
'NO_FEED_ENABLED' => 'Feeds are not available on this board.',
'NO_FEED' => 'The requested feed is not available.',
+ 'NO_STYLE_DATA' => 'Could not get style data',
'NO_SUBJECT' => 'No subject specified', // Used for posts having no subject defined but displayed within management pages.
'NO_SUCH_SEARCH_MODULE' => 'The specified search backend doesn’t exist.',
'NO_SUPPORTED_AUTH_METHODS' => 'No supported authentication methods.',
@@ -810,6 +819,7 @@ $lang = array_merge($lang, array(
'WHO_IS_ONLINE' => 'Who is online',
'WRONG_PASSWORD' => 'You entered an incorrect password.',
+ 'WRONG_DATA_COLOUR' => 'The colour value you entered is invalid.',
'WRONG_DATA_ICQ' => 'The number you entered is not a valid ICQ number.',
'WRONG_DATA_JABBER' => 'The name you entered is not a valid Jabber account name.',
'WRONG_DATA_LANG' => 'The language you specified is not valid.',
diff --git a/phpBB/language/en/email/post_approved.txt b/phpBB/language/en/email/post_approved.txt
index e715b54026..a02dba142a 100644
--- a/phpBB/language/en/email/post_approved.txt
+++ b/phpBB/language/en/email/post_approved.txt
@@ -10,5 +10,4 @@ If you want to view the post, click the following link:
If you want to view the topic, click the following link:
{U_VIEW_TOPIC}
-
{EMAIL_SIG} \ No newline at end of file
diff --git a/phpBB/language/en/email/post_disapproved.txt b/phpBB/language/en/email/post_disapproved.txt
index 2f8a8381cb..9b2ee643ff 100644
--- a/phpBB/language/en/email/post_disapproved.txt
+++ b/phpBB/language/en/email/post_disapproved.txt
@@ -8,5 +8,4 @@ The following reason was given for the disapproval:
{REASON}
-
{EMAIL_SIG}
diff --git a/phpBB/language/en/email/post_in_queue.txt b/phpBB/language/en/email/post_in_queue.txt
index 8d56ce6c4d..941f070d37 100644
--- a/phpBB/language/en/email/post_in_queue.txt
+++ b/phpBB/language/en/email/post_in_queue.txt
@@ -1,4 +1,4 @@
-Subject: Topic reply notification - "{TOPIC_TITLE}"
+Subject: Post moderation notification - "{TOPIC_TITLE}"
Hello {USERNAME},
@@ -10,8 +10,4 @@ If you want to view the post, click the following link:
If you want to view the topic, click the following link:
{U_TOPIC}
-If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
-
-{U_NOTIFICATION_SETTINGS}
-
{EMAIL_SIG}
diff --git a/phpBB/language/en/email/report_closed.txt b/phpBB/language/en/email/report_closed.txt
index eb7ef22b5e..f248018f9a 100644
--- a/phpBB/language/en/email/report_closed.txt
+++ b/phpBB/language/en/email/report_closed.txt
@@ -4,5 +4,4 @@ Hello {USERNAME},
You are receiving this notification because the report you filed on the post "{POST_SUBJECT}" in "{TOPIC_TITLE}" at "{SITENAME}" was handled by a moderator or by an administrator. The report was afterwards closed. If you have further questions contact {CLOSER_NAME} with a personal message.
-
-{EMAIL_SIG} \ No newline at end of file
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/report_deleted.txt b/phpBB/language/en/email/report_deleted.txt
index 4292ca2239..9a30ea2ddd 100644
--- a/phpBB/language/en/email/report_deleted.txt
+++ b/phpBB/language/en/email/report_deleted.txt
@@ -4,5 +4,4 @@ Hello {USERNAME},
You are receiving this notification because the report you filed on the post "{POST_SUBJECT}" in "{TOPIC_TITLE}" at "{SITENAME}" was deleted by a moderator or by an administrator.
-
-{EMAIL_SIG} \ No newline at end of file
+{EMAIL_SIG}
diff --git a/phpBB/language/en/email/report_pm.txt b/phpBB/language/en/email/report_pm.txt
index 66ae82d074..a101a014ff 100644
--- a/phpBB/language/en/email/report_pm.txt
+++ b/phpBB/language/en/email/report_pm.txt
@@ -1,4 +1,4 @@
-Subject: Topic reply notification - "{TOPIC_TITLE}"
+Subject: Private Message report - "{TOPIC_TITLE}"
Hello {USERNAME},
@@ -7,8 +7,4 @@ You are receiving this notification because a Private Message titled "{SUBJECT}"
If you want to view the report, click the following link:
{U_VIEW_REPORT}
-If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
-
-{U_NOTIFICATION_SETTINGS}
-
{EMAIL_SIG}
diff --git a/phpBB/language/en/email/report_post.txt b/phpBB/language/en/email/report_post.txt
index 46983be1ed..8eb24ec6af 100644
--- a/phpBB/language/en/email/report_post.txt
+++ b/phpBB/language/en/email/report_post.txt
@@ -1,4 +1,4 @@
-Subject: Topic reply notification - "{TOPIC_TITLE}"
+Subject: Post report - "{TOPIC_TITLE}"
Hello {USERNAME},
@@ -10,8 +10,4 @@ If you want to view the report, click the following link:
If you want to view the post, click the following link:
{U_VIEW_POST}
-If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
-
-{U_NOTIFICATION_SETTINGS}
-
{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/post_approved.txt b/phpBB/language/en/email/short/post_approved.txt
index e715b54026..a02dba142a 100644
--- a/phpBB/language/en/email/short/post_approved.txt
+++ b/phpBB/language/en/email/short/post_approved.txt
@@ -10,5 +10,4 @@ If you want to view the post, click the following link:
If you want to view the topic, click the following link:
{U_VIEW_TOPIC}
-
{EMAIL_SIG} \ No newline at end of file
diff --git a/phpBB/language/en/email/short/post_disapproved.txt b/phpBB/language/en/email/short/post_disapproved.txt
index 2f8a8381cb..9b2ee643ff 100644
--- a/phpBB/language/en/email/short/post_disapproved.txt
+++ b/phpBB/language/en/email/short/post_disapproved.txt
@@ -8,5 +8,4 @@ The following reason was given for the disapproval:
{REASON}
-
{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/post_in_queue.txt b/phpBB/language/en/email/short/post_in_queue.txt
index 8d56ce6c4d..941f070d37 100644
--- a/phpBB/language/en/email/short/post_in_queue.txt
+++ b/phpBB/language/en/email/short/post_in_queue.txt
@@ -1,4 +1,4 @@
-Subject: Topic reply notification - "{TOPIC_TITLE}"
+Subject: Post moderation notification - "{TOPIC_TITLE}"
Hello {USERNAME},
@@ -10,8 +10,4 @@ If you want to view the post, click the following link:
If you want to view the topic, click the following link:
{U_TOPIC}
-If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
-
-{U_NOTIFICATION_SETTINGS}
-
{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/report_pm.txt b/phpBB/language/en/email/short/report_pm.txt
index 66ae82d074..a101a014ff 100644
--- a/phpBB/language/en/email/short/report_pm.txt
+++ b/phpBB/language/en/email/short/report_pm.txt
@@ -1,4 +1,4 @@
-Subject: Topic reply notification - "{TOPIC_TITLE}"
+Subject: Private Message report - "{TOPIC_TITLE}"
Hello {USERNAME},
@@ -7,8 +7,4 @@ You are receiving this notification because a Private Message titled "{SUBJECT}"
If you want to view the report, click the following link:
{U_VIEW_REPORT}
-If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
-
-{U_NOTIFICATION_SETTINGS}
-
{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/report_post.txt b/phpBB/language/en/email/short/report_post.txt
index 46983be1ed..8eb24ec6af 100644
--- a/phpBB/language/en/email/short/report_post.txt
+++ b/phpBB/language/en/email/short/report_post.txt
@@ -1,4 +1,4 @@
-Subject: Topic reply notification - "{TOPIC_TITLE}"
+Subject: Post report - "{TOPIC_TITLE}"
Hello {USERNAME},
@@ -10,8 +10,4 @@ If you want to view the report, click the following link:
If you want to view the post, click the following link:
{U_VIEW_POST}
-If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
-
-{U_NOTIFICATION_SETTINGS}
-
{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/topic_approved.txt b/phpBB/language/en/email/short/topic_approved.txt
index 0b09918b89..60c7ef4c09 100644
--- a/phpBB/language/en/email/short/topic_approved.txt
+++ b/phpBB/language/en/email/short/topic_approved.txt
@@ -7,5 +7,4 @@ You are receiving this notification because your topic "{TOPIC_TITLE}" at "{SITE
If you want to view the topic, click the following link:
{U_VIEW_TOPIC}
-
{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/topic_disapproved.txt b/phpBB/language/en/email/short/topic_disapproved.txt
index a4bd9c151e..9c821e2bba 100644
--- a/phpBB/language/en/email/short/topic_disapproved.txt
+++ b/phpBB/language/en/email/short/topic_disapproved.txt
@@ -8,5 +8,4 @@ The following reason was given for the disapproval:
{REASON}
-
{EMAIL_SIG}
diff --git a/phpBB/language/en/email/short/topic_in_queue.txt b/phpBB/language/en/email/short/topic_in_queue.txt
index ae8f9e2484..706dddf64f 100644
--- a/phpBB/language/en/email/short/topic_in_queue.txt
+++ b/phpBB/language/en/email/short/topic_in_queue.txt
@@ -1,4 +1,4 @@
-Subject: Topic reply notification - "{TOPIC_TITLE}"
+Subject: Topic moderation notification - "{TOPIC_TITLE}"
Hello {USERNAME},
@@ -10,8 +10,4 @@ If you want to view the topic, click the following link:
If you want to view the forum, click the following link:
{U_FORUM}
-If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
-
-{U_NOTIFICATION_SETTINGS}
-
{EMAIL_SIG}
diff --git a/phpBB/language/en/email/topic_approved.txt b/phpBB/language/en/email/topic_approved.txt
index 0b09918b89..60c7ef4c09 100644
--- a/phpBB/language/en/email/topic_approved.txt
+++ b/phpBB/language/en/email/topic_approved.txt
@@ -7,5 +7,4 @@ You are receiving this notification because your topic "{TOPIC_TITLE}" at "{SITE
If you want to view the topic, click the following link:
{U_VIEW_TOPIC}
-
{EMAIL_SIG}
diff --git a/phpBB/language/en/email/topic_disapproved.txt b/phpBB/language/en/email/topic_disapproved.txt
index a4bd9c151e..9c821e2bba 100644
--- a/phpBB/language/en/email/topic_disapproved.txt
+++ b/phpBB/language/en/email/topic_disapproved.txt
@@ -8,5 +8,4 @@ The following reason was given for the disapproval:
{REASON}
-
{EMAIL_SIG}
diff --git a/phpBB/language/en/email/topic_in_queue.txt b/phpBB/language/en/email/topic_in_queue.txt
index ae8f9e2484..706dddf64f 100644
--- a/phpBB/language/en/email/topic_in_queue.txt
+++ b/phpBB/language/en/email/topic_in_queue.txt
@@ -1,4 +1,4 @@
-Subject: Topic reply notification - "{TOPIC_TITLE}"
+Subject: Topic moderation notification - "{TOPIC_TITLE}"
Hello {USERNAME},
@@ -10,8 +10,4 @@ If you want to view the topic, click the following link:
If you want to view the forum, click the following link:
{U_FORUM}
-If you no longer wish to receive updates about replies to bookmarks, please update your notification settings here:
-
-{U_NOTIFICATION_SETTINGS}
-
{EMAIL_SIG}
diff --git a/phpBB/language/en/email/user_reactivate_account.txt b/phpBB/language/en/email/user_reactivate_account.txt
index 7e25018f4d..385c09f4c5 100644
--- a/phpBB/language/en/email/user_reactivate_account.txt
+++ b/phpBB/language/en/email/user_reactivate_account.txt
@@ -15,5 +15,4 @@ Please visit the following link to reactivate your account:
{U_ACTIVATE}
-
{EMAIL_SIG} \ No newline at end of file
diff --git a/phpBB/language/en/email/user_resend_inactive.txt b/phpBB/language/en/email/user_resend_inactive.txt
index 7879b914b9..b9b95ce9e5 100644
--- a/phpBB/language/en/email/user_resend_inactive.txt
+++ b/phpBB/language/en/email/user_resend_inactive.txt
@@ -14,7 +14,6 @@ Please visit the following link in order to activate your account:
{U_ACTIVATE}
-
Thank you for registering.
{EMAIL_SIG} \ No newline at end of file
diff --git a/phpBB/language/en/mcp.php b/phpBB/language/en/mcp.php
index eaa2d7e3a5..29f418183f 100644
--- a/phpBB/language/en/mcp.php
+++ b/phpBB/language/en/mcp.php
@@ -250,6 +250,8 @@ $lang = array_merge($lang, array(
'ONLY_TOPIC' => 'Only topic “%s”',
'OTHER_USERS' => 'Other users posting from this IP',
+ 'QUICKMOD_ACTION_NOT_ALLOWED' => "%s not allowed as quickmod",
+
'PM_REPORT_CLOSED_SUCCESS' => 'The selected PM report has been closed successfully.',
'PM_REPORT_DELETED_SUCCESS' => 'The selected PM report has been deleted successfully.',
'PM_REPORTED_SUCCESS' => 'This private message has been successfully reported.',
diff --git a/phpBB/language/en/migrator.php b/phpBB/language/en/migrator.php
index 84074c391c..f94c27be8c 100644
--- a/phpBB/language/en/migrator.php
+++ b/phpBB/language/en/migrator.php
@@ -35,21 +35,20 @@ if (empty($lang) || !is_array($lang))
// in a url you again do not need to specify an order e.g., 'Click %sHERE%s' is fine
$lang = array_merge($lang, array(
- 'CONFIG_ALREADY_EXIST' => 'The config setting "%s" unexpectedly already exists.',
'CONFIG_NOT_EXIST' => 'The config setting "%s" unexpectedly does not exist.',
'GROUP_NOT_EXIST' => 'The group "%s" unexpectedly does not exist.',
+ 'MIGRATION_DATA_DONE' => 'Installed Data: %s',
+ 'MIGRATION_EFFECTIVELY_INSTALLED' => 'Migration already effectively installed (skipped): %s',
'MIGRATION_EXCEPTION_ERROR' => 'Something went wrong during the request and an exception was thrown. The changes made before the error occurred were reversed to the best of our abilities, but you should check the board for errors.',
'MIGRATION_NOT_FULFILLABLE' => 'The migration "%1$s" is not fulfillable, missing migration "%2$s".',
+ 'MIGRATION_SCHEMA_DONE' => 'Installed Schema: %s',
- 'MODULE_ALREADY_EXIST' => 'The module "%s" unexpectedly already exists.',
'MODULE_ERROR' => 'An error occured while creating a module: %s',
'MODULE_INFO_FILE_NOT_EXIST' => 'A required module info file is missing: %2$s',
'MODULE_NOT_EXIST' => 'A required module does not exist: %s',
- 'MODULE_NOT_REMOVABLE' => 'Module %1$s was unable to be removed: %2$s',
- 'PERMISSION_ALREADY_EXIST' => 'The permission setting "%s" unexpectedly already exists.',
'PERMISSION_NOT_EXIST' => 'The permission setting "%s" unexpectedly does not exist.',
'ROLE_NOT_EXIST' => 'The permission role "%s" unexpectedly does not exist.',
diff --git a/phpBB/language/en/posting.php b/phpBB/language/en/posting.php
index f5478dded5..7651ff2b63 100644
--- a/phpBB/language/en/posting.php
+++ b/phpBB/language/en/posting.php
@@ -161,7 +161,7 @@ $lang = array_merge($lang, array(
'PLACE_INLINE' => 'Place inline',
'POLL_DELETE' => 'Delete poll',
'POLL_FOR' => 'Run poll for',
- 'POLL_FOR_EXPLAIN' => 'Enter 0 or leave blank for a never ending poll.',
+ 'POLL_FOR_EXPLAIN' => 'Enter 0 for a never ending poll.',
'POLL_MAX_OPTIONS' => 'Options per user',
'POLL_MAX_OPTIONS_EXPLAIN' => 'This is the number of options each user may select when voting.',
'POLL_OPTIONS' => 'Poll options',
@@ -211,7 +211,7 @@ $lang = array_merge($lang, array(
'SMILIES_ARE_ON' => 'Smilies are <em>ON</em>',
'STICKY_ANNOUNCE_TIME_LIMIT'=> 'Sticky/Announcement time limit',
'STICK_TOPIC_FOR' => 'Stick topic for',
- 'STICK_TOPIC_FOR_EXPLAIN' => 'Enter 0 or leave blank for a never ending Sticky/Announcement. Please note that this number is relative to the date of the post.',
+ 'STICK_TOPIC_FOR_EXPLAIN' => 'Enter 0 for a never ending Sticky/Announcement. Please note that this number is relative to the date of the post.',
'STYLES_TIP' => 'Tip: Styles can be applied quickly to selected text.',
'TOO_FEW_CHARS' => 'Your message contains too few characters.',
diff --git a/phpBB/language/en/ucp.php b/phpBB/language/en/ucp.php
index c8b0686a5b..a91b6b84d5 100644
--- a/phpBB/language/en/ucp.php
+++ b/phpBB/language/en/ucp.php
@@ -89,12 +89,22 @@ $lang = array_merge($lang, array(
'ATTACHMENT_DELETED' => 'Attachment successfully deleted.',
'AUTOLOGIN_SESSION_KEYS_DELETED'=> 'The selected "Remember Me" login keys were successfully deleted.',
'AVATAR_CATEGORY' => 'Category',
+ 'AVATAR_DRIVER_GRAVATAR_TITLE' => 'Gravatar',
+ 'AVATAR_DRIVER_GRAVATAR_EXPLAIN'=> 'Gravatar is a service that allows you to maintain the same avatar across multiple websites. Visit <a href="http://www.gravatar.com/">Gravatar</a> for more information.',
+ 'AVATAR_DRIVER_LOCAL_TITLE' => 'Gallery avatar',
+ 'AVATAR_DRIVER_LOCAL_EXPLAIN' => 'You can choose your avatar from a locally available set of avatars.',
+ 'AVATAR_DRIVER_REMOTE_TITLE' => 'Remote avatar',
+ 'AVATAR_DRIVER_REMOTE_EXPLAIN' => 'Link to avatar images from another website.',
+ 'AVATAR_DRIVER_UPLOAD_TITLE' => 'Upload avatar',
+ 'AVATAR_DRIVER_UPLOAD_EXPLAIN' => 'Upload your own custom avatar.',
'AVATAR_EXPLAIN' => 'Maximum dimensions; width: %1$s, height: %2$s, file size: %3$.2f KiB.',
'AVATAR_FEATURES_DISABLED' => 'The avatar functionality is currently disabled.',
'AVATAR_GALLERY' => 'Local gallery',
'AVATAR_GENERAL_UPLOAD_ERROR' => 'Could not upload avatar to %s.',
'AVATAR_NOT_ALLOWED' => 'Your avatar cannot be displayed because avatars have been disallowed.',
'AVATAR_PAGE' => 'Page',
+ 'AVATAR_SELECT' => 'Select your avatar',
+ 'AVATAR_TYPE' => 'Avatar type',
'AVATAR_TYPE_NOT_ALLOWED' => 'Your current avatar cannot be displayed because its type has been disallowed.',
'BACK_TO_DRAFTS' => 'Back to saved drafts',
@@ -235,6 +245,11 @@ $lang = array_merge($lang, array(
'GLOBAL_ANNOUNCEMENT' => 'Global announcement',
+ 'GRAVATAR_AVATAR_EMAIL' => 'Gravatar email',
+ 'GRAVATAR_AVATAR_EMAIL_EXPLAIN' => 'Enter the email address you used for registering your account on <a href="http://www.gravatar.com/">Gravatar</a>.',
+ 'GRAVATAR_AVATAR_SIZE' => 'Avatar dimensions',
+ 'GRAVATAR_AVATAR_SIZE_EXPLAIN' => 'Specify the width and height of the avatar, leave blank to attempt automatic verification.',
+
'HIDE_ONLINE' => 'Hide my online status',
'HIDE_ONLINE_EXPLAIN' => 'Changing this setting won’t become effective until your next visit to the board.',
'HOLD_NEW_MESSAGES' => 'Do not accept new messages (New messages will be held back until enough space is available)',
@@ -506,6 +521,7 @@ $lang = array_merge($lang, array(
'UCP_USERGROUPS_MEMBER' => 'Edit memberships',
'UCP_USERGROUPS_MANAGE' => 'Manage groups',
+ 'UCP_PASSWORD_RESET_DISABLED' => 'The password reset functionality has been disabled. If you need help accessing your account, please contact the %sBoard Administrator%s',
'UCP_REGISTER_DISABLE' => 'Creating a new account is currently not possible.',
'UCP_REMIND' => 'Send password',
'UCP_RESEND' => 'Send activation email',
diff --git a/phpBB/mcp.php b/phpBB/mcp.php
index d04a297cf9..c36faad74b 100644
--- a/phpBB/mcp.php
+++ b/phpBB/mcp.php
@@ -182,7 +182,7 @@ if ($quickmod)
break;
default:
- trigger_error("$action not allowed as quickmod", E_USER_ERROR);
+ trigger_error($user->lang('QUICKMOD_ACTION_NOT_ALLOWED', $action), E_USER_ERROR);
break;
}
}
diff --git a/phpBB/memberlist.php b/phpBB/memberlist.php
index e222d4478d..7ecf332720 100644
--- a/phpBB/memberlist.php
+++ b/phpBB/memberlist.php
@@ -71,21 +71,28 @@ switch ($mode)
$page_title = $user->lang['THE_TEAM'];
$template_html = 'memberlist_leaders.html';
+ $sql = 'SELECT *
+ FROM ' . TEAMPAGE_TABLE . '
+ ORDER BY teampage_position ASC';
+ $result = $db->sql_query($sql, 3600);
+ $teampage_data = $db->sql_fetchrowset($result);
+ $db->sql_freeresult($result);
+
$sql_ary = array(
- 'SELECT' => 'g.group_id, g.group_name, g.group_colour, g.group_type, g.group_teampage, ug.user_id as ug_user_id',
+ 'SELECT' => 'g.group_id, g.group_name, g.group_colour, g.group_type, ug.user_id as ug_user_id, t.teampage_id',
'FROM' => array(GROUPS_TABLE => 'g'),
'LEFT_JOIN' => array(
array(
+ 'FROM' => array(TEAMPAGE_TABLE => 't'),
+ 'ON' => 't.group_id = g.group_id',
+ ),
+ array(
'FROM' => array(USER_GROUP_TABLE => 'ug'),
'ON' => 'ug.group_id = g.group_id AND ug.user_pending = 0 AND ug.user_id = ' . (int) $user->data['user_id'],
),
),
-
- 'WHERE' => '',
-
- 'ORDER_BY' => 'g.group_teampage ASC',
);
$result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary));
@@ -104,7 +111,7 @@ switch ($mode)
$row['u_group'] = append_sid("{$phpbb_root_path}memberlist.$phpEx", 'mode=group&amp;g=' . $row['group_id']);
}
- if ($row['group_teampage'])
+ if ($row['teampage_id'])
{
// Only put groups into the array we want to display.
// We are fetching all groups, to ensure we got all data for default groups.
@@ -139,7 +146,7 @@ switch ($mode)
$result = $db->sql_query($db->sql_build_query('SELECT', $sql_ary));
- $user_ary = array();
+ $user_ary = $user_ids = $group_users = array();
while ($row = $db->sql_fetchrow($result))
{
$row['forums'] = '';
@@ -150,11 +157,13 @@ switch ($mode)
}
$db->sql_freeresult($result);
- if ($config['teampage_forums'])
+ $user_ids = array_unique($user_ids);
+
+ if (!empty($user_ids) && $config['teampage_forums'])
{
$template->assign_var('S_DISPLAY_MODERATOR_FORUMS', true);
// Get all moderators
- $perm_ary = $auth->acl_get_list(array_unique($user_ids), array('m_'), false);
+ $perm_ary = $auth->acl_get_list($user_ids, array('m_'), false);
foreach ($perm_ary as $forum_id => $forum_ary)
{
@@ -204,11 +213,27 @@ switch ($mode)
}
}
- foreach ($groups_ary as $group_id => $group_data)
+ $parent_team = 0;
+ foreach ($teampage_data as $team_data)
{
- if ($group_data['group_teampage'])
+ // If this team entry has no group, it's a category
+ if (!$team_data['group_id'])
{
$template->assign_block_vars('group', array(
+ 'GROUP_NAME' => $team_data['teampage_name'],
+ ));
+
+ $parent_team = (int) $team_data['teampage_id'];
+ continue;
+ }
+
+ $group_data = $groups_ary[(int) $team_data['group_id']];
+ $group_id = (int) $team_data['group_id'];
+
+ if (!$team_data['teampage_parent'])
+ {
+ // If the group does not have a parent category, we display the groupname as category
+ $template->assign_block_vars('group', array(
'GROUP_NAME' => $group_data['group_name'],
'GROUP_COLOR' => $group_data['group_colour'],
'U_GROUP' => $group_data['u_group'],
@@ -223,7 +248,7 @@ switch ($mode)
if (isset($user_ary[$user_id]))
{
$row = $user_ary[$user_id];
- if ($config['teampage_memberships'] == 1 && ($group_id != $groups_ary[$row['default_group']]['group_id']) && $groups_ary[$row['default_group']]['group_teampage'])
+ if ($config['teampage_memberships'] == 1 && ($group_id != $groups_ary[$row['default_group']]['group_id']) && $groups_ary[$row['default_group']]['teampage_id'])
{
// Display users in their primary group, instead of the first group, when it is displayed on the teampage.
continue;
@@ -351,7 +376,7 @@ switch ($mode)
$messenger->subject(htmlspecialchars_decode($subject));
$messenger->replyto($user->data['user_email']);
- $messenger->im($row['user_jabber'], $row['username']);
+ $messenger->set_addresses($row);
$messenger->assign_vars(array(
'BOARD_CONTACT' => $config['board_contact'],
@@ -549,7 +574,7 @@ switch ($mode)
$member['user_sig'] = smiley_text($member['user_sig']);
}
- $poster_avatar = get_user_avatar($member['user_avatar'], $member['user_avatar_type'], $member['user_avatar_width'], $member['user_avatar_height']);
+ $poster_avatar = phpbb_get_user_avatar($member);
// We need to check if the modules 'zebra' ('friends' & 'foes' mode), 'notes' ('user_notes' mode) and 'warn' ('warn_user' mode) are accessible to decide if we can display appropriate links
$zebra_enabled = $friends_enabled = $foes_enabled = $user_notes_enabled = $warn_user_enabled = false;
@@ -1234,8 +1259,7 @@ switch ($mode)
break;
}
- // Misusing the avatar function for displaying group avatars...
- $avatar_img = get_user_avatar($group_row['group_avatar'], $group_row['group_avatar_type'], $group_row['group_avatar_width'], $group_row['group_avatar_height'], 'GROUP_AVATAR');
+ $avatar_img = phpbb_get_group_avatar($group_row);
// ... same for group rank
$rank_title = $rank_img = $rank_img_src = '';
@@ -1728,7 +1752,7 @@ function show_profile($data, $user_notes_enabled = false, $warn_user_enabled = f
'A_USERNAME' => addslashes(get_username_string('username', $user_id, $username, $data['user_colour'])),
- 'AVATAR_IMG' => get_user_avatar($data['user_avatar'], $data['user_avatar_type'], $data['user_avatar_width'], $data['user_avatar_height']),
+ 'AVATAR_IMG' => phpbb_get_user_avatar($data),
'ONLINE_IMG' => (!$config['load_onlinetrack']) ? '' : (($online) ? $user->img('icon_user_online', 'ONLINE') : $user->img('icon_user_offline', 'OFFLINE')),
'S_ONLINE' => ($config['load_onlinetrack'] && $online) ? true : false,
'RANK_IMG' => $rank_img,
diff --git a/phpBB/posting.php b/phpBB/posting.php
index d32f7e33d9..c6b9ff4cce 100644
--- a/phpBB/posting.php
+++ b/phpBB/posting.php
@@ -228,6 +228,7 @@ if ($post_data['forum_password'])
{
login_forum_box(array(
'forum_id' => $forum_id,
+ 'forum_name' => $post_data['forum_name'],
'forum_password' => $post_data['forum_password'])
);
}
diff --git a/phpBB/styles/prosilver/template/ajax.js b/phpBB/styles/prosilver/template/ajax.js
index 0b587ac561..2528b96ece 100644
--- a/phpBB/styles/prosilver/template/ajax.js
+++ b/phpBB/styles/prosilver/template/ajax.js
@@ -39,7 +39,7 @@ phpbb.addAjaxCallback('mark_forums_read', function(res) {
// Mark topics read if we are watching a category and showing active topics
if ($('#active_topics').length) {
- phpbb.ajaxCallbacks['mark_topics_read'].call(this, res, false);
+ phpbb.ajaxCallbacks.mark_topics_read.call(this, res, false);
}
// Update mark forums read links
@@ -75,7 +75,7 @@ phpbb.addAjaxCallback('mark_topics_read', function(res, update_topic_links) {
$.each(iconsArray, function(unreadClass, readClass) {
$.each(iconsState, function(key, value) {
// Only topics can be hot
- if ((value == '_hot' || value == '_hot_mine') && unreadClass != 'topic_unread') {
+ if ((value === '_hot' || value === '_hot_mine') && unreadClass !== 'topic_unread') {
return true;
}
classMap[unreadClass + value] = readClass + value;
@@ -217,7 +217,7 @@ $('#quick-mod-select').change(function () {
*/
$('#member_search').click(function () {
$('#memberlist_search').slideToggle('fast');
- phpbb.ajax_callbacks['alt_text'].call(this);
+ phpbb.ajax_callbacks.alt_text.call(this);
// Focus on the username textbox if it's available and displayed
if ($('#memberlist_search').is(':visible')) {
$('#username').focus();
@@ -225,4 +225,13 @@ $('#member_search').click(function () {
return false;
});
+/**
+* Automatically resize textarea
+*/
+$(document).ready(function() {
+ phpbb.resizeTextArea($('textarea:not(#message-box textarea, .no-auto-resize)'), {minHeight: 75, maxHeight: 250});
+ phpbb.resizeTextArea($('#message-box textarea'));
+});
+
+
})(jQuery); // Avoid conflicts with other libraries
diff --git a/phpBB/styles/prosilver/template/avatars.js b/phpBB/styles/prosilver/template/avatars.js
new file mode 100644
index 0000000000..26ea24c0db
--- /dev/null
+++ b/phpBB/styles/prosilver/template/avatars.js
@@ -0,0 +1,15 @@
+(function($) { // Avoid conflicts with other libraries
+
+"use strict";
+
+function avatarHide() {
+ $('#avatar_options > div').hide();
+
+ var selected = $('#avatar_driver').val();
+ $('#avatar_option_' + selected).show();
+}
+
+avatarHide();
+$('#avatar_driver').bind('change', avatarHide);
+
+})(jQuery); // Avoid conflicts with other libraries
diff --git a/phpBB/styles/prosilver/template/confirm_body.html b/phpBB/styles/prosilver/template/confirm_body.html
index cddbdee391..bf575c20fa 100644
--- a/phpBB/styles/prosilver/template/confirm_body.html
+++ b/phpBB/styles/prosilver/template/confirm_body.html
@@ -1,3 +1,15 @@
+<!-- IF S_AJAX_REQUEST -->
+
+ <h3>{MESSAGE_TITLE}</h3>
+ <p>{MESSAGE_TEXT}</p>
+
+ <fieldset class="submit-buttons">
+ <input type="button" name="confirm" value="{L_YES}" class="button2" />&nbsp;
+ <input type="button" name="cancel" value="{L_NO}" class="button2" />
+ </fieldset>
+
+<!-- ELSE -->
+
<!-- INCLUDE overall_header.html -->
<form id="confirm" action="{S_CONFIRM_ACTION}" method="post">
@@ -6,10 +18,10 @@
<h2>{MESSAGE_TITLE}</h2>
<p>{MESSAGE_TEXT}</p>
-
+
<fieldset class="submit-buttons">
{S_HIDDEN_FIELDS}
- <input type="submit" name="confirm" value="{L_YES}" class="button2" />&nbsp;
+ <input type="submit" name="confirm" value="{L_YES}" class="button2" />&nbsp;
<input type="submit" name="cancel" value="{L_NO}" class="button2" />
</fieldset>
@@ -18,3 +30,5 @@
</form>
<!-- INCLUDE overall_footer.html -->
+
+<!-- ENDIF -->
diff --git a/phpBB/styles/prosilver/template/custom_profile_fields.html b/phpBB/styles/prosilver/template/custom_profile_fields.html
index 9c627a509d..7de97f64cb 100644
--- a/phpBB/styles/prosilver/template/custom_profile_fields.html
+++ b/phpBB/styles/prosilver/template/custom_profile_fields.html
@@ -21,11 +21,11 @@
<!-- END bool -->
<!-- BEGIN int -->
-<input type="text" class="inputbox autowidth" name="{int.FIELD_IDENT}" id="{int.FIELD_IDENT}" size="{int.FIELD_LENGTH}" value="{int.FIELD_VALUE}" />
+<input type="number" min="{int.FIELD_MINLEN}" max="{int.FIELD_MAXLEN}" class="inputbox autowidth" name="{int.FIELD_IDENT}" id="{int.FIELD_IDENT}" size="{int.FIELD_LENGTH}" value="{int.FIELD_VALUE}" />
<!-- END int -->
<!-- BEGIN date -->
-<label for="{date.FIELD_IDENT}_day">{L_DAY}{L_COLON} <select name="{date.FIELD_IDENT}_day" id="{date.FIELD_IDENT}_day">{date.S_DAY_OPTIONS}</select></label>
-<label for="{date.FIELD_IDENT}_month">{L_MONTH}{L_COLON} <select name="{date.FIELD_IDENT}_month" id="{date.FIELD_IDENT}_month">{date.S_MONTH_OPTIONS}</select></label>
+<label for="{date.FIELD_IDENT}_day">{L_DAY}{L_COLON} <select name="{date.FIELD_IDENT}_day" id="{date.FIELD_IDENT}_day">{date.S_DAY_OPTIONS}</select></label>
+<label for="{date.FIELD_IDENT}_month">{L_MONTH}{L_COLON} <select name="{date.FIELD_IDENT}_month" id="{date.FIELD_IDENT}_month">{date.S_MONTH_OPTIONS}</select></label>
<label for="{date.FIELD_IDENT}_year">{L_YEAR}{L_COLON} <select name="{date.FIELD_IDENT}_year" id="{date.FIELD_IDENT}_year">{date.S_YEAR_OPTIONS}</select></label>
<!-- END date -->
diff --git a/phpBB/styles/prosilver/template/editor.js b/phpBB/styles/prosilver/template/editor.js
index c16b0ef703..fd4c68adfe 100644
--- a/phpBB/styles/prosilver/template/editor.js
+++ b/phpBB/styles/prosilver/template/editor.js
@@ -6,22 +6,21 @@
// Startup variables
var imageTag = false;
var theSelection = false;
-
var bbcodeEnabled = true;
+
// Check for Browser & Platform for PC & IE specific bits
// More details from: http://www.mozilla.org/docs/web-developer/sniffer/browser_type.html
var clientPC = navigator.userAgent.toLowerCase(); // Get client info
-var clientVer = parseInt(navigator.appVersion); // Get browser version
+var clientVer = parseInt(navigator.appVersion, 10); // Get browser version
-var is_ie = ((clientPC.indexOf('msie') != -1) && (clientPC.indexOf('opera') == -1));
-var is_win = ((clientPC.indexOf('win') != -1) || (clientPC.indexOf('16bit') != -1));
+var is_ie = ((clientPC.indexOf('msie') !== -1) && (clientPC.indexOf('opera') === -1));
+var is_win = ((clientPC.indexOf('win') !== -1) || (clientPC.indexOf('16bit') !== -1));
var baseHeight;
/**
* Shows the help messages in the helpline window
*/
-function helpline(help)
-{
+function helpline(help) {
document.forms[form_name].helpbox.value = help_line[help];
}
@@ -29,28 +28,22 @@ function helpline(help)
* Fix a bug involving the TextRange object. From
* http://www.frostjedi.com/terra/scripts/demo/caretBug.html
*/
-function initInsertions()
-{
+function initInsertions() {
var doc;
- if (document.forms[form_name])
- {
+ if (document.forms[form_name]) {
doc = document;
- }
- else
- {
+ } else {
doc = opener.document;
}
var textarea = doc.forms[form_name].elements[text_name];
- if (is_ie && typeof(baseHeight) != 'number')
- {
+ if (is_ie && typeof(baseHeight) !== 'number') {
textarea.focus();
baseHeight = doc.selection.createRange().duplicate().boundingHeight;
- if (!document.forms[form_name])
- {
+ if (!document.forms[form_name]) {
document.body.focus();
}
}
@@ -59,14 +52,10 @@ function initInsertions()
/**
* bbstyle
*/
-function bbstyle(bbnumber)
-{
- if (bbnumber != -1)
- {
+function bbstyle(bbnumber) {
+ if (bbnumber !== -1) {
bbfontstyle(bbtags[bbnumber], bbtags[bbnumber+1]);
- }
- else
- {
+ } else {
insert_text('[*]');
document.forms[form_name].elements[text_name].focus();
}
@@ -75,53 +64,47 @@ function bbstyle(bbnumber)
/**
* Apply bbcodes
*/
-function bbfontstyle(bbopen, bbclose)
-{
+function bbfontstyle(bbopen, bbclose) {
theSelection = false;
var textarea = document.forms[form_name].elements[text_name];
textarea.focus();
- if ((clientVer >= 4) && is_ie && is_win)
- {
+ if ((clientVer >= 4) && is_ie && is_win) {
// Get text selection
theSelection = document.selection.createRange().text;
- if (theSelection)
- {
+ if (theSelection) {
// Add tags around selection
document.selection.createRange().text = bbopen + theSelection + bbclose;
document.forms[form_name].elements[text_name].focus();
theSelection = '';
return;
}
- }
- else if (document.forms[form_name].elements[text_name].selectionEnd && (document.forms[form_name].elements[text_name].selectionEnd - document.forms[form_name].elements[text_name].selectionStart > 0))
- {
+ } else if (document.forms[form_name].elements[text_name].selectionEnd
+ && (document.forms[form_name].elements[text_name].selectionEnd - document.forms[form_name].elements[text_name].selectionStart > 0)) {
mozWrap(document.forms[form_name].elements[text_name], bbopen, bbclose);
document.forms[form_name].elements[text_name].focus();
theSelection = '';
return;
}
-
+
//The new position for the cursor after adding the bbcode
var caret_pos = getCaretPosition(textarea).start;
- var new_pos = caret_pos + bbopen.length;
+ var new_pos = caret_pos + bbopen.length;
// Open tag
insert_text(bbopen + bbclose);
// Center the cursor when we don't have a selection
// Gecko and proper browsers
- if (!isNaN(textarea.selectionStart))
- {
+ if (!isNaN(textarea.selectionStart)) {
textarea.selectionStart = new_pos;
textarea.selectionEnd = new_pos;
- }
+ }
// IE
- else if (document.selection)
- {
+ else if (document.selection) {
var range = textarea.createTextRange();
range.move("character", new_pos);
range.select();
@@ -135,51 +118,41 @@ function bbfontstyle(bbopen, bbclose)
/**
* Insert text at position
*/
-function insert_text(text, spaces, popup)
-{
+function insert_text(text, spaces, popup) {
var textarea;
-
- if (!popup)
- {
+
+ if (!popup) {
textarea = document.forms[form_name].elements[text_name];
- }
- else
- {
+ } else {
textarea = opener.document.forms[form_name].elements[text_name];
}
- if (spaces)
- {
+
+ if (spaces) {
text = ' ' + text + ' ';
}
// Since IE9, IE also has textarea.selectionStart, but it still needs to be treated the old way.
// Therefore we simply add a !is_ie here until IE fixes the text-selection completely.
- if (!isNaN(textarea.selectionStart) && !is_ie)
- {
+ if (!isNaN(textarea.selectionStart) && !is_ie) {
var sel_start = textarea.selectionStart;
var sel_end = textarea.selectionEnd;
mozWrap(textarea, text, '');
textarea.selectionStart = sel_start + text.length;
textarea.selectionEnd = sel_end + text.length;
- }
- else if (textarea.createTextRange && textarea.caretPos)
- {
- if (baseHeight != textarea.caretPos.boundingHeight)
- {
+ } else if (textarea.createTextRange && textarea.caretPos) {
+ if (baseHeight !== textarea.caretPos.boundingHeight) {
textarea.focus();
storeCaret(textarea);
}
var caret_pos = textarea.caretPos;
- caret_pos.text = caret_pos.text.charAt(caret_pos.text.length - 1) == ' ' ? caret_pos.text + text + ' ' : caret_pos.text + text;
- }
- else
- {
+ caret_pos.text = caret_pos.text.charAt(caret_pos.text.length - 1) === ' ' ? caret_pos.text + text + ' ' : caret_pos.text + text;
+ } else {
textarea.value = textarea.value + text;
}
- if (!popup)
- {
+
+ if (!popup) {
textarea.focus();
}
}
@@ -187,8 +160,7 @@ function insert_text(text, spaces, popup)
/**
* Add inline attachment at position
*/
-function attach_inline(index, filename)
-{
+function attach_inline(index, filename) {
insert_text('[attachment=' + index + ']' + filename + '[/attachment]');
document.forms[form_name].elements[text_name].focus();
}
@@ -196,79 +168,57 @@ function attach_inline(index, filename)
/**
* Add quote text to message
*/
-function addquote(post_id, username, l_wrote)
-{
+function addquote(post_id, username, l_wrote) {
var message_name = 'message_' + post_id;
var theSelection = '';
var divarea = false;
+ var i;
- if (l_wrote === undefined)
- {
+ if (l_wrote === undefined) {
// Backwards compatibility
l_wrote = 'wrote';
}
- if (document.all)
- {
+ if (document.all) {
divarea = document.all[message_name];
- }
- else
- {
+ } else {
divarea = document.getElementById(message_name);
}
// Get text selection - not only the post content :(
// IE9 must use the document.selection method but has the *.getSelection so we just force no IE
- if (window.getSelection && !is_ie && !window.opera)
- {
+ if (window.getSelection && !is_ie && !window.opera) {
theSelection = window.getSelection().toString();
- }
- else if (document.getSelection && !is_ie)
- {
+ } else if (document.getSelection && !is_ie) {
theSelection = document.getSelection();
- }
- else if (document.selection)
- {
+ } else if (document.selection) {
theSelection = document.selection.createRange().text;
}
- if (theSelection == '' || typeof theSelection == 'undefined' || theSelection == null)
- {
- if (divarea.innerHTML)
- {
+ if (theSelection === '' || typeof theSelection === 'undefined' || theSelection === null) {
+ if (divarea.innerHTML) {
theSelection = divarea.innerHTML.replace(/<br>/ig, '\n');
theSelection = theSelection.replace(/<br\/>/ig, '\n');
theSelection = theSelection.replace(/&lt\;/ig, '<');
theSelection = theSelection.replace(/&gt\;/ig, '>');
theSelection = theSelection.replace(/&amp\;/ig, '&');
theSelection = theSelection.replace(/&nbsp\;/ig, ' ');
- }
- else if (document.all)
- {
+ } else if (document.all) {
theSelection = divarea.innerText;
- }
- else if (divarea.textContent)
- {
+ } else if (divarea.textContent) {
theSelection = divarea.textContent;
- }
- else if (divarea.firstChild.nodeValue)
- {
+ } else if (divarea.firstChild.nodeValue) {
theSelection = divarea.firstChild.nodeValue;
}
}
- if (theSelection)
- {
- if (bbcodeEnabled)
- {
+ if (theSelection) {
+ if (bbcodeEnabled) {
insert_text('[quote="' + username + '"]' + theSelection + '[/quote]');
- }
- else
- {
+ } else {
insert_text(username + ' ' + l_wrote + ':' + '\n');
var lines = split_lines(theSelection);
- for (i = 0; i < lines.length; i++)
- {
+ for (i = 0; i < lines.length; i++) {
insert_text('> ' + lines[i] + '\n');
}
}
@@ -277,54 +227,47 @@ function addquote(post_id, username, l_wrote)
return;
}
-function split_lines(text)
-{
+function split_lines(text) {
var lines = text.split('\n');
var splitLines = new Array();
var j = 0;
- for(i = 0; i < lines.length; i++)
- {
- if (lines[i].length <= 80)
- {
+ var i;
+
+ for(i = 0; i < lines.length; i++) {
+ if (lines[i].length <= 80) {
splitLines[j] = lines[i];
j++;
- }
- else
- {
+ } else {
var line = lines[i];
- do
- {
- var splitAt = line.indexOf(' ', 80);
-
- if (splitAt == -1)
- {
+ var splitAt;
+ do {
+ splitAt = line.indexOf(' ', 80);
+
+ if (splitAt === -1) {
splitLines[j] = line;
j++;
- }
- else
- {
+ } else {
splitLines[j] = line.substring(0, splitAt);
line = line.substring(splitAt);
j++;
}
}
- while(splitAt != -1);
+ while(splitAt !== -1);
}
}
return splitLines;
}
+
/**
* From http://www.massless.org/mozedit/
*/
-function mozWrap(txtarea, open, close)
-{
- var selLength = (typeof(txtarea.textLength) == 'undefined') ? txtarea.value.length : txtarea.textLength;
+function mozWrap(txtarea, open, close) {
+ var selLength = (typeof(txtarea.textLength) === 'undefined') ? txtarea.value.length : txtarea.textLength;
var selStart = txtarea.selectionStart;
var selEnd = txtarea.selectionEnd;
var scrollTop = txtarea.scrollTop;
- if (selEnd == 1 || selEnd == 2)
- {
+ if (selEnd === 1 || selEnd === 2) {
selEnd = selLength;
}
@@ -345,10 +288,8 @@ function mozWrap(txtarea, open, close)
* Insert at Caret position. Code from
* http://www.faqts.com/knowledge_base/view.phtml/aid/1052/fid/130
*/
-function storeCaret(textEl)
-{
- if (textEl.createTextRange)
- {
+function storeCaret(textEl) {
+ if (textEl.createTextRange) {
textEl.caretPos = document.selection.createRange().duplicate();
}
}
@@ -356,11 +297,13 @@ function storeCaret(textEl)
/**
* Color pallette
*/
-function colorPalette(dir, width, height)
-{
- var r = 0, g = 0, b = 0;
- var numberList = new Array(6);
- var color = '';
+function colorPalette(dir, width, height) {
+ var r = 0,
+ g = 0,
+ b = 0,
+ numberList = new Array(6);
+ color = '',
+ html = '';
numberList[0] = '00';
numberList[1] = '40';
@@ -368,92 +311,185 @@ function colorPalette(dir, width, height)
numberList[3] = 'BF';
numberList[4] = 'FF';
- document.writeln('<table cellspacing="1" cellpadding="0" border="0">');
+ html += '<table cellspacing="1" cellpadding="0" border="0">';
- for (r = 0; r < 5; r++)
- {
- if (dir == 'h')
- {
- document.writeln('<tr>');
+ for (r = 0; r < 5; r++) {
+ if (dir == 'h') {
+ html += '<tr>';
}
- for (g = 0; g < 5; g++)
- {
- if (dir == 'v')
- {
- document.writeln('<tr>');
+ for (g = 0; g < 5; g++) {
+ if (dir == 'v') {
+ html += '<tr>';
}
-
- for (b = 0; b < 5; b++)
- {
+
+ for (b = 0; b < 5; b++) {
color = String(numberList[r]) + String(numberList[g]) + String(numberList[b]);
- document.write('<td bgcolor="#' + color + '" style="width: ' + width + 'px; height: ' + height + 'px;">');
- document.write('<a href="#" onclick="bbfontstyle(\'[color=#' + color + ']\', \'[/color]\'); return false;"><img src="images/spacer.gif" width="' + width + '" height="' + height + '" alt="#' + color + '" title="#' + color + '" /></a>');
- document.writeln('</td>');
+ html += '<td bgcolor="#' + color + '" style="width: ' + width + 'px; height: ' + height + 'px;">';
+ html += '<a href="#" onclick="bbfontstyle(\'[color=#' + color + ']\', \'[/color]\'); return false;" style="display: block; width: ' + width + 'px; height: ' + height + 'px; " alt="#' + color + '" title="#' + color + '"></a>';
+ html += '</td>';
}
- if (dir == 'v')
- {
- document.writeln('</tr>');
+ if (dir == 'v') {
+ html += '</tr>';
}
}
- if (dir == 'h')
- {
- document.writeln('</tr>');
+ if (dir == 'h') {
+ html += '</tr>';
}
}
- document.writeln('</table>');
+ html += '</table>';
+ return html;
}
+(function($) {
+ $(document).ready(function() {
+ $('#color_palette_placeholder').each(function() {
+ $(this).html(colorPalette('h', 15, 12));
+ });
+ });
+})(jQuery);
/**
* Caret Position object
*/
-function caretPosition()
-{
+function caretPosition() {
var start = null;
var end = null;
}
-
/**
* Get the caret position in an textarea
*/
-function getCaretPosition(txtarea)
-{
+function getCaretPosition(txtarea) {
var caretPos = new caretPosition();
-
+
// simple Gecko/Opera way
- if(txtarea.selectionStart || txtarea.selectionStart == 0)
- {
+ if (txtarea.selectionStart || txtarea.selectionStart === 0) {
caretPos.start = txtarea.selectionStart;
caretPos.end = txtarea.selectionEnd;
}
// dirty and slow IE way
- else if(document.selection)
- {
-
+ else if (document.selection) {
// get current selection
var range = document.selection.createRange();
// a new selection of the whole textarea
var range_all = document.body.createTextRange();
range_all.moveToElementText(txtarea);
-
+
// calculate selection start point by moving beginning of range_all to beginning of range
var sel_start;
- for (sel_start = 0; range_all.compareEndPoints('StartToStart', range) < 0; sel_start++)
- {
+ for (sel_start = 0; range_all.compareEndPoints('StartToStart', range) < 0; sel_start++) {
range_all.moveStart('character', 1);
}
-
+
txtarea.sel_start = sel_start;
-
+
// we ignore the end value for IE, this is already dirty enough and we don't need it
caretPos.start = txtarea.sel_start;
- caretPos.end = txtarea.sel_start;
+ caretPos.end = txtarea.sel_start;
}
return caretPos;
}
+
+/**
+* Allow to use tab character when typing code
+* Keep indentation of last line of code when typing code
+*/
+(function($) {
+ $(document).ready(function() {
+ var doc, textarea, startTags, endTags;
+
+ // find textarea, make sure browser supports necessary functions
+ if (document.forms[form_name]) {
+ doc = document;
+ } else {
+ doc = opener.document;
+ }
+
+ if (!doc.forms[form_name]) {
+ return;
+ }
+
+ textarea = doc.forms[form_name].elements[text_name];
+ if (!textarea || typeof textarea.selectionStart !== 'number') {
+ return;
+ }
+
+ // list of allowed start and end bbcode code tags, in lower case
+ startTags = ['[code]', '[code='];
+ endTags = ['[/code]'];
+
+ function inTag() {
+ var start = textarea.selectionStart,
+ lastEnd = -1,
+ lastStart = -1,
+ i, index, value;
+
+ value = textarea.value.toLowerCase();
+
+ for (i = 0; i < startTags.length; i++) {
+ var tagLength = startTags[i].length;
+ if (start >= tagLength) {
+ index = value.lastIndexOf(startTags[i], start - tagLength);
+ lastStart = Math.max(lastStart, index);
+ }
+ }
+ if (lastStart == -1) return false;
+
+ if (start > 0) {
+ for (i = 0; i < endTags.length; i++) {
+ index = value.lastIndexOf(endTags[i], start - 1);
+ lastEnd = Math.max(lastEnd, index);
+ }
+ }
+
+ return (lastEnd < lastStart);
+ }
+
+ function getLastLine() {
+ var start = textarea.selectionStart,
+ value = textarea.value,
+ index = value.lastIndexOf("\n", start - 1);
+ return value.substring(index + 1, start);
+ }
+
+ function appendCode(code) {
+ var start = textarea.selectionStart,
+ end = textarea.selectionEnd,
+ value = textarea.value;
+ textarea.value = value.substr(0, start) + code + value.substr(end);
+ textarea.selectionStart = textarea.selectionEnd = start + code.length;
+ }
+
+ $(textarea).on('keydown', function(event) {
+ var key = event.keyCode || event.which;
+
+ // intercept tabs
+ if (key == 9) {
+ if (inTag()) {
+ appendCode("\t");
+ event.preventDefault();
+ return;
+ }
+ }
+
+ // intercept new line characters
+ if (key == 13) {
+ if (inTag()) {
+ var lastLine = getLastLine(),
+ code = '' + /^\s*/g.exec(lastLine);
+ if (code.length > 0) {
+ appendCode("\n" + code);
+ event.preventDefault();
+ return;
+ }
+ }
+ }
+ });
+ });
+})(jQuery);
+
diff --git a/phpBB/styles/prosilver/template/forum_fn.js b/phpBB/styles/prosilver/template/forum_fn.js
index 995b4b0ab7..bb29f00490 100644
--- a/phpBB/styles/prosilver/template/forum_fn.js
+++ b/phpBB/styles/prosilver/template/forum_fn.js
@@ -3,12 +3,18 @@
*/
/**
+* Find a member
+*/
+function find_username(url) {
+ popup(url, 760, 570, '_usersearch');
+ return false;
+}
+
+/**
* Window popup
*/
-function popup(url, width, height, name)
-{
- if (!name)
- {
+function popup(url, width, height, name) {
+ if (!name) {
name = '_popup';
}
@@ -19,18 +25,13 @@ function popup(url, width, height, name)
/**
* Jump to page
*/
-function jumpto()
-{
+function jumpto() {
var page = prompt(jump_page, on_page);
- if (page !== null && !isNaN(page) && page == Math.floor(page) && page > 0)
- {
- if (base_url.indexOf('?') == -1)
- {
+ if (page !== null && !isNaN(page) && page == Math.floor(page) && page > 0) {
+ if (base_url.indexOf('?') === -1) {
document.location.href = base_url + '?start=' + ((page - 1) * per_page);
- }
- else
- {
+ } else {
document.location.href = base_url.replace(/&amp;/g, '&') + '&start=' + ((page - 1) * per_page);
}
}
@@ -40,21 +41,17 @@ function jumpto()
* Mark/unmark checklist
* id = ID of parent container, name = name prefix, state = state [true/false]
*/
-function marklist(id, name, state)
-{
+function marklist(id, name, state) {
var parent = document.getElementById(id) || document[id];
- if (!parent)
- {
+ if (!parent) {
return;
}
var rb = parent.getElementsByTagName('input');
-
- for (var r = 0; r < rb.length; r++)
- {
- if (rb[r].name.substr(0, name.length) == name)
- {
+
+ for (var r = 0; r < rb.length; r++) {
+ if (rb[r].name.substr(0, name.length) === name) {
rb[r].checked = state;
}
}
@@ -64,25 +61,23 @@ function marklist(id, name, state)
* Resize viewable area for attached image or topic review panel (possibly others to come)
* e = element
*/
-function viewableArea(e, itself)
-{
- if (!e) return;
- if (!itself)
- {
+function viewableArea(e, itself) {
+ if (!e) {
+ return;
+ }
+
+ if (!itself) {
e = e.parentNode;
}
-
- if (!e.vaHeight)
- {
+
+ if (!e.vaHeight) {
// Store viewable area height before changing style to auto
e.vaHeight = e.offsetHeight;
e.vaMaxHeight = e.style.maxHeight;
e.style.height = 'auto';
e.style.maxHeight = 'none';
e.style.overflow = 'visible';
- }
- else
- {
+ } else {
// Restore viewable area height to the default
e.style.height = e.vaHeight + 'px';
e.style.overflow = 'auto';
@@ -96,53 +91,41 @@ function viewableArea(e, itself)
* s[-1,0,1] = hide,toggle display,show
* type = string: inline, block, inline-block or other CSS "display" type
*/
-function dE(n, s, type)
-{
- if (!type)
- {
+function dE(n, s, type) {
+ if (!type) {
type = 'block';
}
var e = document.getElementById(n);
- if (!s)
- {
- s = (e.style.display == '' || e.style.display == type) ? -1 : 1;
+ if (!s) {
+ s = (e.style.display === '' || e.style.display === type) ? -1 : 1;
}
- e.style.display = (s == 1) ? type : 'none';
+ e.style.display = (s === 1) ? type : 'none';
}
/**
* Alternate display of subPanels
*/
-function subPanels(p)
-{
+function subPanels(p) {
var i, e, t;
- if (typeof(p) == 'string')
- {
+ if (typeof(p) === 'string') {
show_panel = p;
}
- for (i = 0; i < panels.length; i++)
- {
+ for (i = 0; i < panels.length; i++) {
e = document.getElementById(panels[i]);
t = document.getElementById(panels[i] + '-tab');
- if (e)
- {
- if (panels[i] == show_panel)
- {
+ if (e) {
+ if (panels[i] === show_panel) {
e.style.display = 'block';
- if (t)
- {
+ if (t) {
t.className = 'activetab';
}
- }
- else
- {
+ } else {
e.style.display = 'none';
- if (t)
- {
+ if (t) {
t.className = '';
}
}
@@ -153,14 +136,10 @@ function subPanels(p)
/**
* Call print preview
*/
-function printPage()
-{
- if (is_ie)
- {
+function printPage() {
+ if (is_ie) {
printPreview();
- }
- else
- {
+ } else {
window.print();
}
}
@@ -169,70 +148,60 @@ function printPage()
* Show/hide groups of blocks
* c = CSS style name
* e = checkbox element
-* t = toggle dispay state (used to show 'grip-show' image in the profile block when hiding the profiles)
+* t = toggle dispay state (used to show 'grip-show' image in the profile block when hiding the profiles)
*/
-function displayBlocks(c, e, t)
-{
- var s = (e.checked == true) ? 1 : -1;
+function displayBlocks(c, e, t) {
+ var s = (e.checked === true) ? 1 : -1;
- if (t)
- {
+ if (t) {
s *= -1;
}
var divs = document.getElementsByTagName("DIV");
- for (var d = 0; d < divs.length; d++)
- {
- if (divs[d].className.indexOf(c) == 0)
- {
- divs[d].style.display = (s == 1) ? 'none' : 'block';
+ for (var d = 0; d < divs.length; d++) {
+ if (divs[d].className.indexOf(c) === 0) {
+ divs[d].style.display = (s === 1) ? 'none' : 'block';
}
}
}
-function selectCode(a)
-{
+function selectCode(a) {
// Get ID of code block
var e = a.parentNode.parentNode.getElementsByTagName('CODE')[0];
+ var s, r;
// Not IE and IE9+
- if (window.getSelection)
- {
- var s = window.getSelection();
+ if (window.getSelection) {
+ s = window.getSelection();
// Safari
- if (s.setBaseAndExtent)
- {
+ if (s.setBaseAndExtent) {
s.setBaseAndExtent(e, 0, e, e.innerText.length - 1);
}
// Firefox and Opera
- else
- {
+ else {
// workaround for bug # 42885
- if (window.opera && e.innerHTML.substring(e.innerHTML.length - 4) == '<BR>')
- {
+ if (window.opera && e.innerHTML.substring(e.innerHTML.length - 4) === '<BR>') {
e.innerHTML = e.innerHTML + '&nbsp;';
}
- var r = document.createRange();
+ r = document.createRange();
r.selectNodeContents(e);
s.removeAllRanges();
s.addRange(r);
}
}
// Some older browsers
- else if (document.getSelection)
- {
- var s = document.getSelection();
- var r = document.createRange();
+ else if (document.getSelection) {
+ s = document.getSelection();
+ r = document.createRange();
r.selectNodeContents(e);
s.removeAllRanges();
s.addRange(r);
}
// IE
- else if (document.selection)
- {
- var r = document.body.createTextRange();
+ else if (document.selection) {
+ r = document.body.createTextRange();
r.moveToElementText(e);
r.select();
}
@@ -242,25 +211,22 @@ function selectCode(a)
* Play quicktime file by determining it's width/height
* from the displayed rectangle area
*/
-function play_qt_file(obj)
-{
+function play_qt_file(obj) {
var rectangle = obj.GetRectangle();
+ var width, height;
- if (rectangle)
- {
+ if (rectangle) {
rectangle = rectangle.split(',');
- var x1 = parseInt(rectangle[0]);
- var x2 = parseInt(rectangle[2]);
- var y1 = parseInt(rectangle[1]);
- var y2 = parseInt(rectangle[3]);
-
- var width = (x1 < 0) ? (x1 * -1) + x2 : x2 - x1;
- var height = (y1 < 0) ? (y1 * -1) + y2 : y2 - y1;
- }
- else
- {
- var width = 200;
- var height = 0;
+ var x1 = parseInt(rectangle[0], 10);
+ var x2 = parseInt(rectangle[2], 10);
+ var y1 = parseInt(rectangle[1], 10);
+ var y2 = parseInt(rectangle[3], 10);
+
+ width = (x1 < 0) ? (x1 * -1) + x2 : x2 - x1;
+ height = (y1 < 0) ? (y1 * -1) + y2 : y2 - y1;
+ } else {
+ width = 200;
+ height = 0;
}
obj.width = width;
@@ -274,21 +240,21 @@ function play_qt_file(obj)
* Check if the nodeName of elem is name
* @author jQuery
*/
-function is_node_name(elem, name)
-{
- return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
+function is_node_name(elem, name) {
+ return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
}
/**
* Check if elem is in array, return position
* @author jQuery
*/
-function is_in_array(elem, array)
-{
- for (var i = 0, length = array.length; i < length; i++)
+function is_in_array(elem, array) {
+ for (var i = 0, length = array.length; i < length; i++) {
// === is correct (IE)
- if (array[i] === elem)
+ if (array[i] === elem) {
return i;
+ }
+ }
return -1;
}
@@ -298,23 +264,26 @@ function is_in_array(elem, array)
* Not used, but may come in handy for those not using JQuery
* @author jQuery.find, Meik Sievertsen
*/
-function find_in_tree(node, tag, type, class_name)
-{
+function find_in_tree(node, tag, type, class_name) {
var result, element, i = 0, length = node.childNodes.length;
- for (element = node.childNodes[0]; i < length; element = node.childNodes[++i])
- {
- if (!element || element.nodeType != 1) continue;
+ for (element = node.childNodes[0]; i < length; element = node.childNodes[++i]) {
+ if (!element || element.nodeType !== 1) {
+ continue;
+ }
- if ((!tag || is_node_name(element, tag)) && (!type || element.type == type) && (!class_name || is_in_array(class_name, (element.className || element).toString().split(/\s+/)) > -1))
- {
+ if ((!tag || is_node_name(element, tag)) && (!type || element.type === type)
+ && (!class_name || is_in_array(class_name, (element.className || element).toString().split(/\s+/)) > -1)) {
return element;
}
- if (element.childNodes.length)
+ if (element.childNodes.length) {
result = find_in_tree(element, tag, type, class_name);
+ }
- if (result) return result;
+ if (result) {
+ return result;
+ }
}
}
@@ -324,26 +293,23 @@ var last_key_entered = '';
/**
* Check event key
*/
-function phpbb_check_key(event)
-{
+function phpbb_check_key(event) {
// Keycode is array down or up?
- if (event.keyCode && (event.keyCode == 40 || event.keyCode == 38))
+ if (event.keyCode && (event.keyCode === 40 || event.keyCode === 38)) {
in_autocomplete = true;
+ }
// Make sure we are not within an "autocompletion" field
- if (in_autocomplete)
- {
+ if (in_autocomplete) {
// If return pressed and key changed we reset the autocompletion
- if (!last_key_entered || last_key_entered == event.which)
- {
+ if (!last_key_entered || last_key_entered === event.which) {
in_autocompletion = false;
return true;
}
}
// Keycode is not return, then return. ;)
- if (event.which != 13)
- {
+ if (event.which !== 13) {
last_key_entered = event.which;
return true;
}
@@ -354,34 +320,37 @@ function phpbb_check_key(event)
/**
* Usually used for onkeypress event, to submit a form on enter
*/
-function submit_default_button(event, selector, class_name)
-{
+function submit_default_button(event, selector, class_name) {
// Add which for key events
- if (!event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode))
+ if (!event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode)) {
event.which = event.charCode || event.keyCode;
+ }
- if (phpbb_check_key(event))
+ if (phpbb_check_key(event)) {
return true;
+ }
- var current = selector['parentNode'];
+ var current = selector.parentNode;
// Search parent form element
- while (current && (!current.nodeName || current.nodeType != 1 || !is_node_name(current, 'form')) && current != document)
- current = current['parentNode'];
+ while (current && (!current.nodeName || current.nodeType !== 1 || !is_node_name(current, 'form')) && current !== document) {
+ current = current.parentNode;
+ }
// Find the input submit button with the class name
//current = find_in_tree(current, 'input', 'submit', class_name);
var input_tags = current.getElementsByTagName('input');
current = false;
- for (var i = 0, element = input_tags[0]; i < input_tags.length; element = input_tags[++i])
- {
- if (element.type == 'submit' && is_in_array(class_name, (element.className || element).toString().split(/\s+/)) > -1)
+ for (var i = 0, element = input_tags[0]; i < input_tags.length; element = input_tags[++i]) {
+ if (element.type === 'submit' && is_in_array(class_name, (element.className || element).toString().split(/\s+/)) > -1) {
current = element;
+ }
}
- if (!current)
+ if (!current) {
return true;
+ }
// Submit form
current.focus();
@@ -394,46 +363,25 @@ function submit_default_button(event, selector, class_name)
* The jQuery snippet used is based on http://greatwebguy.com/programming/dom/default-html-button-submit-on-enter-with-jquery/
* The non-jQuery code is a mimick of the jQuery code ;)
*/
-function apply_onkeypress_event()
-{
- // jQuery code in case jQuery is used
- if (jquery_present)
- {
- jQuery('form input[type=text], form input[type=password]').live('keypress', function (e)
- {
- var default_button = jQuery(this).parents('form').find('input[type=submit].default-submit-action');
-
- if (!default_button || default_button.length <= 0)
- return true;
-
- if (phpbb_check_key(e))
- return true;
-
- if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13))
- {
- default_button.click();
- return false;
- }
+function apply_onkeypress_event() {
+ jQuery('form input[type=text], form input[type=password]').on('keypress', function (e) {
+ var default_button = jQuery(this).parents('form').find('input[type=submit].default-submit-action');
+ if (!default_button || default_button.length <= 0) {
return true;
- });
-
- return;
- }
+ }
- var input_tags = document.getElementsByTagName('input');
+ if (phpbb_check_key(e)) {
+ return true;
+ }
- for (var i = 0, element = input_tags[0]; i < input_tags.length ; element = input_tags[++i])
- {
- if (element.type == 'text' || element.type == 'password')
- {
- // onkeydown is possible too
- element.onkeypress = function (evt) { submit_default_button((evt || window.event), this, 'default-submit-action'); };
+ if ((e.which && e.which === 13) || (e.keyCode && e.keyCode === 13)) {
+ default_button.click();
+ return false;
}
- }
+
+ return true;
+ });
}
-/**
-* Detect JQuery existance. We currently do not deliver it, but some styles do, so why not benefit from it. ;)
-*/
-var jquery_present = typeof jQuery == 'function';
+jQuery(document).ready(apply_onkeypress_event);
diff --git a/phpBB/styles/prosilver/template/forumlist_body.html b/phpBB/styles/prosilver/template/forumlist_body.html
index 539ed047c9..0c67de76ec 100644
--- a/phpBB/styles/prosilver/template/forumlist_body.html
+++ b/phpBB/styles/prosilver/template/forumlist_body.html
@@ -13,7 +13,7 @@
<ul class="topiclist">
<li class="header">
<dl class="icon">
- <dt><!-- IF forumrow.S_IS_CAT --><a href="{forumrow.U_VIEWFORUM}">{forumrow.FORUM_NAME}</a><!-- ELSE -->{L_FORUM}<!-- ENDIF --></dt>
+ <dt><div class="list-inner"><!-- IF forumrow.S_IS_CAT --><a href="{forumrow.U_VIEWFORUM}">{forumrow.FORUM_NAME}</a><!-- ELSE -->{L_FORUM}<!-- ENDIF --></div></dt>
<dd class="topics">{L_TOPICS}</dd>
<dd class="posts">{L_POSTS}</dd>
<dd class="lastpost"><span>{L_LAST_POST}</span></dd>
@@ -27,20 +27,22 @@
<li class="row">
<dl class="icon {forumrow.FORUM_IMG_STYLE}">
<dt title="{forumrow.FORUM_FOLDER_IMG_ALT}">
- <!-- IF S_ENABLE_FEEDS and forumrow.S_FEED_ENABLED --><!-- <a class="feed-icon-forum" title="{L_FEED} - {forumrow.FORUM_NAME}" href="{U_FEED}?f={forumrow.FORUM_ID}"><img src="{T_THEME_PATH}/images/feed.gif" alt="{L_FEED} - {forumrow.FORUM_NAME}" /></a> --><!-- ENDIF -->
+ <div class="list-inner">
+ <!-- IF S_ENABLE_FEEDS and forumrow.S_FEED_ENABLED --><!-- <a class="feed-icon-forum" title="{L_FEED} - {forumrow.FORUM_NAME}" href="{U_FEED}?f={forumrow.FORUM_ID}"><img src="{T_THEME_PATH}/images/feed.gif" alt="{L_FEED} - {forumrow.FORUM_NAME}" /></a> --><!-- ENDIF -->
- <!-- IF forumrow.FORUM_IMAGE --><span class="forum-image">{forumrow.FORUM_IMAGE}</span><!-- ENDIF -->
- <a href="{forumrow.U_VIEWFORUM}" class="forumtitle">{forumrow.FORUM_NAME}</a><br />
- {forumrow.FORUM_DESC}
- <!-- IF forumrow.MODERATORS -->
- <br /><strong>{forumrow.L_MODERATOR_STR}{L_COLON}</strong> {forumrow.MODERATORS}
- <!-- ENDIF -->
- <!-- IF .forumrow.subforum and forumrow.S_LIST_SUBFORUMS -->
- <br /><strong>{forumrow.L_SUBFORUM_STR}</strong>
- <!-- BEGIN subforum -->
- <a href="{forumrow.subforum.U_SUBFORUM}" class="subforum<!-- IF forumrow.subforum.S_UNREAD --> unread<!-- ELSE --> read<!-- ENDIF -->" title="<!-- IF forumrow.subforum.UNREAD -->{L_UNREAD_POSTS}<!-- ELSE -->{L_NO_UNREAD_POSTS}<!-- ENDIF -->">{forumrow.subforum.SUBFORUM_NAME}</a><!-- IF not forumrow.subforum.S_LAST_ROW -->,<!-- ENDIF -->
- <!-- END subforum -->
- <!-- ENDIF -->
+ <!-- IF forumrow.FORUM_IMAGE --><span class="forum-image">{forumrow.FORUM_IMAGE}</span><!-- ENDIF -->
+ <a href="{forumrow.U_VIEWFORUM}" class="forumtitle">{forumrow.FORUM_NAME}</a><br />
+ {forumrow.FORUM_DESC}
+ <!-- IF forumrow.MODERATORS -->
+ <br /><strong>{forumrow.L_MODERATOR_STR}{L_COLON}</strong> {forumrow.MODERATORS}
+ <!-- ENDIF -->
+ <!-- IF .forumrow.subforum and forumrow.S_LIST_SUBFORUMS -->
+ <br /><strong>{forumrow.L_SUBFORUM_STR}</strong>
+ <!-- BEGIN subforum -->
+ <a href="{forumrow.subforum.U_SUBFORUM}" class="subforum<!-- IF forumrow.subforum.S_UNREAD --> unread<!-- ELSE --> read<!-- ENDIF -->" title="<!-- IF forumrow.subforum.UNREAD -->{L_UNREAD_POSTS}<!-- ELSE -->{L_NO_UNREAD_POSTS}<!-- ENDIF -->">{forumrow.subforum.SUBFORUM_NAME}</a><!-- IF not forumrow.subforum.S_LAST_ROW -->,<!-- ENDIF -->
+ <!-- END subforum -->
+ <!-- ENDIF -->
+ </div>
</dt>
<!-- IF forumrow.CLICKS -->
<dd class="redirect"><span>{L_REDIRECTS}{L_COLON} {forumrow.CLICKS}</span></dd>
diff --git a/phpBB/styles/prosilver/template/login_forum.html b/phpBB/styles/prosilver/template/login_forum.html
index 63f0b2e0f7..c83a625b3f 100644
--- a/phpBB/styles/prosilver/template/login_forum.html
+++ b/phpBB/styles/prosilver/template/login_forum.html
@@ -1,31 +1,36 @@
<!-- INCLUDE overall_header.html -->
-<h2 class="solo">{L_LOGIN} {FORUM_NAME}</h2>
+<!-- IF FORUM_NAME --><h2><a href="{U_VIEW_FORUM}">{FORUM_NAME}</a></h2><!-- ENDIF -->
<form id="login_forum" method="post" action="{S_LOGIN_ACTION}">
{S_FORM_TOKEN}
<div class="panel">
<div class="inner">
- <p>{L_LOGIN_FORUM}</p>
-
- <fieldset class="fields2">
- <!-- IF LOGIN_ERROR -->
- <dl>
- <dt>&nbsp;</dt>
- <dd class="error">{LOGIN_ERROR}</dd>
- </dl>
- <!-- ENDIF -->
- <dl>
- <dt><label for="password">{L_PASSWORD}{L_COLON}</label></dt>
- <dd><input class="inputbox narrow" type="password" name="password" id="password" size="25" tabindex="1" /></dd>
- </dl>
- <dl class="fields2">
- <dt>&nbsp;</dt>
- <dd>{S_HIDDEN_FIELDS}<input type="submit" name="login" id="login" class="button1" value="{L_LOGIN}" tabindex="2" /></dd>
- </dl>
- {S_LOGIN_REDIRECT}
- </fieldset>
+ <div class="content">
+ <h2>{L_LOGIN}</h2>
+
+ <p>{L_LOGIN_FORUM}</p>
+
+ <fieldset class="fields1">
+ <!-- IF LOGIN_ERROR -->
+ <dl>
+ <dt>&nbsp;</dt>
+ <dd class="error">{LOGIN_ERROR}</dd>
+ </dl>
+ <!-- ENDIF -->
+
+ <dl>
+ <dt><label for="password">{L_PASSWORD}{L_COLON}</label></dt>
+ <dd><input type="password" tabindex="1" id="password" name="password" size="25" class="inputbox narrow" /></dd>
+ </dl>
+ {S_LOGIN_REDIRECT}
+ <dl>
+ <dt>&nbsp;</dt>
+ <dd>{S_HIDDEN_FIELDS}<input type="submit" name="login" id="login" class="button1" value="{L_LOGIN}" tabindex="2" /></dd>
+ </dl>
+ </fieldset>
+ </div>
</div>
</div>
diff --git a/phpBB/styles/prosilver/template/mcp_approve.html b/phpBB/styles/prosilver/template/mcp_approve.html
index faa88aefc7..6c8215c7c6 100644
--- a/phpBB/styles/prosilver/template/mcp_approve.html
+++ b/phpBB/styles/prosilver/template/mcp_approve.html
@@ -1,3 +1,30 @@
+<!-- IF S_AJAX_REQUEST -->
+
+ <h3>{MESSAGE_TITLE}</h3>
+ <p>{MESSAGE_TEXT}</p>
+
+ <!-- IF S_NOTIFY_POSTER -->
+ <label><input type="checkbox" name="notify_poster" checked="checked" /> <!-- IF S_APPROVE -->{L_NOTIFY_POSTER_APPROVAL}<!-- ELSE -->{L_NOTIFY_POSTER_DISAPPROVAL}<!-- ENDIF --></label>
+ <!-- ENDIF -->
+
+ <!-- IF not S_APPROVE -->
+ <label><strong>{L_DISAPPROVE_REASON}{L_COLON}</strong>
+ <select name="reason_id">
+ <!-- BEGIN reason --><option value="{reason.ID}"<!-- IF reason.S_SELECTED --> selected="selected"<!-- ENDIF -->>{reason.DESCRIPTION}</option><!-- END reason -->
+ </select></label>
+
+ <label><strong>{L_MORE_INFO}{L_COLON}</strong><br /><span>{L_CAN_LEAVE_BLANK}</span>
+ <textarea class="inputbox" name="reason" id="reason" rows="4" cols="40">{REASON}</textarea>
+ </label>
+ <!-- ENDIF -->
+
+ <fieldset class="submit-buttons">
+ <input type="button" name="confirm" value="{YES_VALUE}" class="button1" />&nbsp;
+ <input type="button" name="cancel" value="{L_NO}" class="button2" />
+ </fieldset>
+
+<!-- ELSE -->
+
<!-- INCLUDE overall_header.html -->
<form id="confirm" action="{S_CONFIRM_ACTION}" method="post">
@@ -51,3 +78,4 @@
</form>
<!-- INCLUDE overall_footer.html -->
+<!-- ENDIF -->
diff --git a/phpBB/styles/prosilver/template/mcp_forum.html b/phpBB/styles/prosilver/template/mcp_forum.html
index e559f178f2..ac686932b7 100644
--- a/phpBB/styles/prosilver/template/mcp_forum.html
+++ b/phpBB/styles/prosilver/template/mcp_forum.html
@@ -24,22 +24,24 @@
<!-- ENDIF -->
<!-- IF .topicrow -->
- <ul class="topiclist">
+ <ul class="topiclist<!-- IF S_MERGE_SELECT --> missing-column<!-- ENDIF -->">
<li class="header">
<dl class="icon">
- <dt>{L_TOPICS}</dt>
+ <dt><div class="list-inner">{L_TOPICS}</div></dt>
<dd class="posts">{L_REPLIES}</dd>
<dd class="lastpost"><span>{L_LAST_POST}</span></dd>
<!-- IF not S_MERGE_SELECT --><dd class="mark">{L_MARK}</dd><!-- ENDIF -->
</dl>
</li>
</ul>
- <ul class="topiclist cplist">
+ <ul class="topiclist cplist<!-- IF S_MERGE_SELECT --> missing-column<!-- ENDIF -->">
<!-- BEGIN topicrow -->
<li class="row<!-- IF topicrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF --><!-- IF topicrow.S_TOPIC_REPORTED --> reported<!-- ENDIF -->">
<dl class="icon {topicrow.TOPIC_IMG_STYLE}">
<dt <!-- IF topicrow.TOPIC_ICON_IMG -->style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF -->>
+ <div class="list-inner">
+
<!-- IF topicrow.S_SELECT_TOPIC --><a href="{topicrow.U_SELECT_TOPIC}" class="topictitle">[ {L_SELECT_MERGE} ]</a>&nbsp;&nbsp; <!-- ENDIF -->
<a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a>
<!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.UNAPPROVED_IMG}</a> <!-- ENDIF -->
@@ -60,7 +62,10 @@
</ul>
</div>
<!-- ENDIF -->
- <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->{L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} &raquo; {topicrow.FIRST_POST_TIME} </dt>
+ <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->{L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} &raquo; {topicrow.FIRST_POST_TIME}
+
+ </div>
+ </dt>
<dd class="posts">{topicrow.REPLIES} <dfn>{L_REPLIES}</dfn></dd>
<dd class="lastpost"><span><dfn>{L_LAST_POST} </dfn>{L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL}<br />{topicrow.LAST_POST_TIME}</span>
</dd>
diff --git a/phpBB/styles/prosilver/template/mcp_front.html b/phpBB/styles/prosilver/template/mcp_front.html
index 57e57d8254..e88b7c62df 100644
--- a/phpBB/styles/prosilver/template/mcp_front.html
+++ b/phpBB/styles/prosilver/template/mcp_front.html
@@ -13,22 +13,24 @@
<p>{L_UNAPPROVED_TOTAL}</p>
<!-- IF .unapproved -->
- <ul class="topiclist">
+ <ul class="topiclist two-long-columns">
<li class="header">
<dl>
- <dt>{L_VIEW_DETAILS}</dt>
+ <dt><div class="list-inner">{L_VIEW_DETAILS}</div></dt>
<dd class="moderation"><span>{L_TOPIC} &amp; {L_FORUM}</span></dd>
</dl>
</li>
</ul>
- <ul class="topiclist cplist">
+ <ul class="topiclist cplist two-long-columns">
<!-- BEGIN unapproved -->
<li class="row<!-- IF unapproved.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl>
<dt>
- <a href="{unapproved.U_POST_DETAILS}" class="topictitle">{unapproved.SUBJECT}</a> {unapproved.ATTACH_ICON_IMG}<br />
- {L_POSTED} {L_POST_BY_AUTHOR} {unapproved.AUTHOR_FULL} &raquo; {unapproved.POST_TIME}
+ <div class="list-inner">
+ <a href="{unapproved.U_POST_DETAILS}" class="topictitle">{unapproved.SUBJECT}</a> {unapproved.ATTACH_ICON_IMG}<br />
+ {L_POSTED} {L_POST_BY_AUTHOR} {unapproved.AUTHOR_FULL} &raquo; {unapproved.POST_TIME}
+ </div>
</dt>
<dd class="moderation"><span>
{L_TOPIC}{L_COLON} <a href="{unapproved.U_TOPIC}">{unapproved.TOPIC_TITLE}</a> [<a href="{unapproved.U_MCP_TOPIC}">{L_MODERATE}</a>]<br />
@@ -65,22 +67,24 @@
<p>{L_REPORTS_TOTAL}</p>
<!-- IF .report -->
- <ul class="topiclist">
+ <ul class="topiclist two-long-columns">
<li class="header">
<dl>
- <dt>{L_VIEW_DETAILS}</dt>
+ <dt><div class="list-inner">{L_VIEW_DETAILS}</div></dt>
<dd class="moderation"><span>{L_REPORTER} &amp; {L_FORUM}</span></dd>
</dl>
</li>
</ul>
- <ul class="topiclist cplist">
+ <ul class="topiclist cplist two-long-columns">
<!-- BEGIN report -->
<li class="row<!-- IF report.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl>
<dt>
- <a href="{report.U_POST_DETAILS}#reports" class="topictitle">{report.SUBJECT}</a> {report.ATTACH_ICON_IMG}<br />
- <span>{L_POSTED} {L_POST_BY_AUTHOR} {report.AUTHOR_FULL} &raquo; {report.POST_TIME}</span>
+ <div class="list-inner">
+ <a href="{report.U_POST_DETAILS}#reports" class="topictitle">{report.SUBJECT}</a> {report.ATTACH_ICON_IMG}<br />
+ <span>{L_POSTED} {L_POST_BY_AUTHOR} {report.AUTHOR_FULL} &raquo; {report.POST_TIME}</span>
+ </div>
</dt>
<dd class="moderation">
<span>{L_REPORTED} {L_POST_BY_AUTHOR} {report.REPORTER_FULL} {L_REPORTED_ON_DATE} {report.REPORT_TIME}<br />
@@ -104,23 +108,25 @@
<p>{L_PM_REPORTS_TOTAL}</p>
<!-- IF .pm_report -->
- <ul class="topiclist">
+ <ul class="topiclist two-long-columns">
<li class="header">
<dl>
- <dt>{L_VIEW_DETAILS}</dt>
+ <dt><div class="list-inner">{L_VIEW_DETAILS}</div></dt>
<dd class="moderation"><span>{L_REPORTER}</span></dd>
</dl>
</li>
</ul>
- <ul class="topiclist cplist">
+ <ul class="topiclist cplist two-long-columns">
<!-- BEGIN pm_report -->
- <li class="row<!-- IF report.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
+ <li class="row<!-- IF pm_report.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl>
<dt>
- <a href="{pm_report.U_PM_DETAILS}" class="topictitle">{pm_report.PM_SUBJECT}</a> {pm_report.ATTACH_ICON_IMG}<br />
- <span>{L_MESSAGE_BY_AUTHOR} {pm_report.PM_AUTHOR_FULL} &raquo; {pm_report.PM_TIME}</span><br />
- <span>{L_MESSAGE_TO} {pm_report.RECIPIENTS}</span>
+ <div class="list-inner">
+ <a href="{pm_report.U_PM_DETAILS}" class="topictitle">{pm_report.PM_SUBJECT}</a> {pm_report.ATTACH_ICON_IMG}<br />
+ <span>{L_MESSAGE_BY_AUTHOR} {pm_report.PM_AUTHOR_FULL} &raquo; {pm_report.PM_TIME}</span><br />
+ <span>{L_MESSAGE_TO} {pm_report.RECIPIENTS}</span>
+ </div>
</dt>
<dd class="moderation">
<span>{L_REPORTED} {L_POST_BY_AUTHOR} {pm_report.REPORTER_FULL} {L_REPORTED_ON_DATE} {pm_report.REPORT_TIME}</span>
diff --git a/phpBB/styles/prosilver/template/mcp_logs.html b/phpBB/styles/prosilver/template/mcp_logs.html
index 9e4a6f272e..c9db4e8afa 100644
--- a/phpBB/styles/prosilver/template/mcp_logs.html
+++ b/phpBB/styles/prosilver/template/mcp_logs.html
@@ -9,7 +9,7 @@
<ul class="linklist">
<li class="leftside">
- {L_SEARCH_KEYWORDS}{L_COLON} <input type="text" class="inputbox autowidth" name="keywords" value="{S_KEYWORDS}" />&nbsp;<input type="submit" class="button2" name="filter" value="{L_SEARCH}" />
+ {L_SEARCH_KEYWORDS}{L_COLON} <input type="search" class="inputbox autowidth" name="keywords" value="{S_KEYWORDS}" />&nbsp;<input type="submit" class="button2" name="filter" value="{L_SEARCH}" />
</li>
<li class="rightside pagination">
<!-- IF TOTAL -->{TOTAL} &bull; <!-- ENDIF -->
diff --git a/phpBB/styles/prosilver/template/mcp_move.html b/phpBB/styles/prosilver/template/mcp_move.html
index d7a4f3d798..c2ee25f0d9 100644
--- a/phpBB/styles/prosilver/template/mcp_move.html
+++ b/phpBB/styles/prosilver/template/mcp_move.html
@@ -1,3 +1,34 @@
+<!-- IF S_AJAX_REQUEST -->
+
+ <h3>{MESSAGE_TITLE}</h3>
+ <p>{MESSAGE_TEXT}</p>
+
+ <!-- IF ADDITIONAL_MSG --><p>{ADDITIONAL_MSG}</p><!-- ENDIF -->
+
+ <label>
+ <strong>{L_SELECT_DESTINATION_FORUM}{L_COLON}</strong>
+ <select name="to_forum_id">{S_FORUM_SELECT}</select>
+ </label>
+
+ <!-- IF S_CAN_LEAVE_SHADOW -->
+ <label for="move_leave_shadow">
+ <input type="checkbox" name="move_leave_shadow" id="move_leave_shadow" />{L_LEAVE_SHADOW}
+ </label>
+ <!-- ENDIF -->
+
+ <!-- IF S_CAN_LOCK_TOPIC -->
+ <label for="move_lock_topics">
+ <input type="checkbox" name="move_lock_topics" id="move_lock_topics" />{L_LOCK_TOPIC}
+ </label>
+ <!-- ENDIF -->
+
+ <fieldset class="submit-buttons">
+ <input type="button" name="confirm" value="{YES_VALUE}" class="button1" />&nbsp;
+ <input type="button" name="cancel" value="{L_NO}" class="button2" />
+ </fieldset>
+
+<!-- ELSE -->
+
<!-- INCLUDE overall_header.html -->
<form id="confirm" action="{S_CONFIRM_ACTION}" method="post">
@@ -35,3 +66,4 @@
</form>
<!-- INCLUDE overall_footer.html -->
+<!-- ENDIF -->
diff --git a/phpBB/styles/prosilver/template/mcp_notes_user.html b/phpBB/styles/prosilver/template/mcp_notes_user.html
index 3bbbd10f12..328d12a04f 100644
--- a/phpBB/styles/prosilver/template/mcp_notes_user.html
+++ b/phpBB/styles/prosilver/template/mcp_notes_user.html
@@ -52,7 +52,7 @@
<ul class="linklist">
<li class="leftside">
- {L_SEARCH_KEYWORDS}{L_COLON} <input type="text" class="inputbox autowidth" name="keywords" value="{S_KEYWORDS}" />&nbsp;<input type="submit" class="button2" name="filter" value="{L_SEARCH}" />
+ {L_SEARCH_KEYWORDS}{L_COLON} <input type="search" class="inputbox autowidth" name="keywords" value="{S_KEYWORDS}" />&nbsp;<input type="submit" class="button2" name="filter" value="{L_SEARCH}" />
</li>
<li class="rightside pagination">
<!-- IF TOTAL_REPORTS -->{TOTAL_REPORTS} &bull; <!-- ENDIF -->
diff --git a/phpBB/styles/prosilver/template/mcp_queue.html b/phpBB/styles/prosilver/template/mcp_queue.html
index 847151a01e..4d20804e66 100644
--- a/phpBB/styles/prosilver/template/mcp_queue.html
+++ b/phpBB/styles/prosilver/template/mcp_queue.html
@@ -26,16 +26,16 @@
<!-- ENDIF -->
</li>
</ul>
- <ul class="topiclist">
+ <ul class="topiclist missing-column">
<li class="header">
<dl>
- <dt><!-- IF S_TOPICS -->{L_TOPIC}<!-- ELSE -->{L_POST}<!-- ENDIF --></dt>
+ <dt><div class="list-inner"><!-- IF S_TOPICS -->{L_TOPIC}<!-- ELSE -->{L_POST}<!-- ENDIF --></div></dt>
<dd class="moderation"><span><!-- IF not S_TOPICS -->{L_TOPIC} &amp; <!-- ENDIF -->{L_FORUM}</span></dd>
<dd class="mark">{L_MARK}</dd>
</dl>
</li>
</ul>
- <ul class="topiclist cplist">
+ <ul class="topiclist cplist missing-column">
<!-- BEGIN postrow -->
@@ -46,8 +46,10 @@
<li class="row<!-- IF postrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl>
<dt>
- <a href="{postrow.U_VIEW_DETAILS}" class="topictitle">{postrow.POST_SUBJECT}</a> {postrow.ATTACH_ICON_IMG}<br />
- <span>{L_POSTED} {L_POST_BY_AUTHOR} {postrow.POST_AUTHOR_FULL} &raquo; {postrow.POST_TIME}</span>
+ <div class="list-inner">
+ <a href="{postrow.U_VIEW_DETAILS}" class="topictitle">{postrow.POST_SUBJECT}</a> {postrow.ATTACH_ICON_IMG}<br />
+ <span>{L_POSTED} {L_POST_BY_AUTHOR} {postrow.POST_AUTHOR_FULL} &raquo; {postrow.POST_TIME}</span>
+ </div>
</dt>
<dd class="moderation">
<span>
diff --git a/phpBB/styles/prosilver/template/mcp_reports.html b/phpBB/styles/prosilver/template/mcp_reports.html
index ea9a4edd6f..9a70b4a62a 100644
--- a/phpBB/styles/prosilver/template/mcp_reports.html
+++ b/phpBB/styles/prosilver/template/mcp_reports.html
@@ -28,33 +28,37 @@
<!-- ENDIF -->
</li>
</ul>
- <ul class="topiclist">
+ <ul class="topiclist missing-column">
<li class="header">
<dl>
- <dt>{L_VIEW_DETAILS}</dt>
+ <dt><div class="list-inner">{L_VIEW_DETAILS}</div></dt>
<dd class="moderation"><span>{L_REPORTER}<!-- IF not S_PM --> &amp; {L_FORUM}<!-- ENDIF --></span></dd>
<dd class="mark">{L_MARK}</dd>
</dl>
</li>
</ul>
- <ul class="topiclist cplist">
+ <ul class="topiclist cplist missing-column">
<!-- BEGIN postrow -->
<li class="row<!-- IF postrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl>
<!-- IF S_PM -->
<dt>
- <a href="{postrow.U_VIEW_DETAILS}" class="topictitle">{postrow.PM_SUBJECT}</a> {postrow.ATTACH_ICON_IMG}<br />
- <span>{L_MESSAGE_BY_AUTHOR} {postrow.PM_AUTHOR_FULL} &raquo; {postrow.PM_TIME}</span><br />
- <span>{L_MESSAGE_TO} {postrow.RECIPIENTS}</span>
+ <div class="list-inner">
+ <a href="{postrow.U_VIEW_DETAILS}" class="topictitle">{postrow.PM_SUBJECT}</a> {postrow.ATTACH_ICON_IMG}<br />
+ <span>{L_MESSAGE_BY_AUTHOR} {postrow.PM_AUTHOR_FULL} &raquo; {postrow.PM_TIME}</span><br />
+ <span>{L_MESSAGE_TO} {postrow.RECIPIENTS}</span>
+ </div>
</dt>
<dd class="moderation">
<span>{postrow.REPORTER_FULL} &laquo; {postrow.REPORT_TIME}</span>
</dd>
<!-- ELSE -->
<dt>
- <a href="{postrow.U_VIEW_DETAILS}" class="topictitle">{postrow.POST_SUBJECT}</a> {postrow.ATTACH_ICON_IMG}<br />
- <span>{L_POSTED} {L_POST_BY_AUTHOR} {postrow.POST_AUTHOR_FULL} &raquo; {postrow.POST_TIME}</span>
+ <div class="list-inner">
+ <a href="{postrow.U_VIEW_DETAILS}" class="topictitle">{postrow.POST_SUBJECT}</a> {postrow.ATTACH_ICON_IMG}<br />
+ <span>{L_POSTED} {L_POST_BY_AUTHOR} {postrow.POST_AUTHOR_FULL} &raquo; {postrow.POST_TIME}</span>
+ </div>
</dt>
<dd class="moderation">
<span>{postrow.REPORTER_FULL} &laquo; {postrow.REPORT_TIME}<br />
diff --git a/phpBB/styles/prosilver/template/mcp_topic.html b/phpBB/styles/prosilver/template/mcp_topic.html
index a89fd8a171..8dfee55cbf 100644
--- a/phpBB/styles/prosilver/template/mcp_topic.html
+++ b/phpBB/styles/prosilver/template/mcp_topic.html
@@ -43,7 +43,7 @@ onload_functions.push('subPanels()');
<fieldset id="display-panel" class="fields2">
<dl>
<dt><label for="posts_per_page">{L_POSTS_PER_PAGE}{L_COLON}</label><br /><span>{L_POSTS_PER_PAGE_EXPLAIN}</span></dt>
- <dd><input class="inputbox autowidth" type="text" name="posts_per_page" id="posts_per_page" size="6" value="{POSTS_PER_PAGE}" /></dd>
+ <dd><input class="inputbox autowidth" type="number" min="1" name="posts_per_page" id="posts_per_page" size="6" value="{POSTS_PER_PAGE}" /></dd>
</dl>
<dl>
<dt><label>{L_DISPLAY_POSTS}{L_COLON}</label></dt>
@@ -80,7 +80,7 @@ onload_functions.push('subPanels()');
<dl>
<dt><label for="to_topic_id">{L_MERGE_TOPIC_ID}{L_COLON}</label></dt>
<dd>
- <input class="inputbox autowidth" type="text" size="6" name="to_topic_id" id="to_topic_id" value="{TO_TOPIC_ID}" />
+ <input class="inputbox autowidth" type="number" min="0" size="6" name="to_topic_id" id="to_topic_id" value="{TO_TOPIC_ID}" />
<a href="{U_SELECT_TOPIC}" >{L_SELECT_TOPIC}</a>
</dd>
<!-- IF TO_TOPIC_INFO --><dd>{TO_TOPIC_INFO}</dd><!-- ENDIF -->
@@ -141,9 +141,9 @@ onload_functions.push('subPanels()');
<ul class="linklist">
<li class="rightside pagination">
<!-- IF TOTAL_POSTS --> {TOTAL_POSTS} &bull; <!-- ENDIF -->
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
{PAGE_NUMBER}
<!-- ENDIF -->
</li>
diff --git a/phpBB/styles/prosilver/template/memberlist_email.html b/phpBB/styles/prosilver/template/memberlist_email.html
index c40a5f1a8b..218402a9e9 100644
--- a/phpBB/styles/prosilver/template/memberlist_email.html
+++ b/phpBB/styles/prosilver/template/memberlist_email.html
@@ -22,7 +22,7 @@
<!-- ELSE -->
<dl>
<dt><label for="email">{L_EMAIL_ADDRESS}{L_COLON}</label></dt>
- <dd><input class="inputbox autowidth" type="text" name="email" id="email" size="50" maxlength="100" tabindex="2" value="{EMAIL}" /></dd>
+ <dd><input class="inputbox autowidth" type="email" name="email" id="email" size="50" maxlength="100" tabindex="2" value="{EMAIL}" /></dd>
</dl>
<dl>
<dt><label for="name">{L_REAL_NAME}{L_COLON}</label></dt>
diff --git a/phpBB/styles/prosilver/template/memberlist_search.html b/phpBB/styles/prosilver/template/memberlist_search.html
index 9de3ccf41b..61bfd630ff 100644
--- a/phpBB/styles/prosilver/template/memberlist_search.html
+++ b/phpBB/styles/prosilver/template/memberlist_search.html
@@ -89,7 +89,7 @@ function insert_single(user)
<!-- ENDIF -->
<dl>
<dt><label for="count">{L_POSTS}{L_COLON}</label></dt>
- <dd><select name="count_select">{S_COUNT_OPTIONS}</select> <input class="inputbox medium" type="text" name="count" id="count" value="{COUNT}" /></dd>
+ <dd><select name="count_select">{S_COUNT_OPTIONS}</select> <input class="inputbox medium" type="number" min="0" name="count" id="count" value="{COUNT}" /></dd>
</dl>
<!-- IF S_IP_SEARCH_ALLOWED -->
<dl>
diff --git a/phpBB/styles/prosilver/template/overall_footer.html b/phpBB/styles/prosilver/template/overall_footer.html
index 322d745501..ba0412ddd3 100644
--- a/phpBB/styles/prosilver/template/overall_footer.html
+++ b/phpBB/styles/prosilver/template/overall_footer.html
@@ -29,9 +29,9 @@
<!-- IF U_ACP --><br /><strong><a href="{U_ACP}">{L_ACP}</a></strong><!-- ENDIF -->
</div>
- <div id="darkenwrapper" data-ajax-error-title="{L_AJAX_ERROR_TITLE}" data-ajax-error-text="{L_AJAX_ERROR_TEXT}">
+ <div id="darkenwrapper" data-ajax-error-title="{L_AJAX_ERROR_TITLE}" data-ajax-error-text="{L_AJAX_ERROR_TEXT}" data-ajax-error-text-abort="{L_AJAX_ERROR_TEXT_ABORT}" data-ajax-error-text-timeout="{L_AJAX_ERROR_TEXT_TIMEOUT}" data-ajax-error-text-parsererror="{L_AJAX_ERROR_TEXT_PARSERERROR}">
<div id="darken">&nbsp;</div>
- <div class="jalert" id="loadingalert"><h3>{L_LOADING}</h3><p>{L_PLEASE_WAIT}</p></div>
+ <div class="phpbb_alert" id="loadingalert"><h3>{L_LOADING}</h3><p>{L_PLEASE_WAIT}</p></div>
</div>
<div id="phpbb_alert" class="phpbb_alert" data-l-err="{L_ERROR}" data-l-timeout-processing-req="{L_TIMEOUT_PROCESSING_REQ}">
@@ -40,9 +40,7 @@
</div>
<div id="phpbb_confirm" class="phpbb_alert">
<a href="#" class="alert_close"></a>
- <p class="alert_text"></p>
- <input type="button" class="button1" value="{L_YES}" />&nbsp;
- <input type="button" class="button2" value="{L_NO}" />
+ <div class="alert_text"></div>
</div>
</div>
@@ -55,6 +53,7 @@
<script type="text/javascript" src="{T_JQUERY_LINK}"></script>
<!-- IF S_JQUERY_FALLBACK --><script type="text/javascript">window.jQuery || document.write(unescape('%3Cscript src="{T_ASSETS_PATH}/javascript/jquery.js?assets_version={T_ASSETS_VERSION}" type="text/javascript"%3E%3C/script%3E'));</script><!-- ENDIF -->
+<script type="text/javascript" src="{T_SUPER_TEMPLATE_PATH}/forum_fn.js?assets_version={T_ASSETS_VERSION}"></script>
<script type="text/javascript" src="{T_ASSETS_PATH}/javascript/core.js?assets_version={T_ASSETS_VERSION}"></script>
<!-- INCLUDEJS template/ajax.js -->
{SCRIPTS}
diff --git a/phpBB/styles/prosilver/template/overall_header.html b/phpBB/styles/prosilver/template/overall_header.html
index a53e0f8d60..3c98edec79 100644
--- a/phpBB/styles/prosilver/template/overall_header.html
+++ b/phpBB/styles/prosilver/template/overall_header.html
@@ -41,15 +41,6 @@
<!-- ENDIF -->
/**
- * Find a member
- */
- function find_username(url)
- {
- popup(url, 760, 570, '_usersearch');
- return false;
- }
-
- /**
* New function for handling multiple calls to window.onload and window.unload by pentapenguin
*/
window.onload = function()
@@ -70,7 +61,6 @@
// ]]>
</script>
-<script type="text/javascript" src="{T_SUPER_TEMPLATE_PATH}/forum_fn.js?assets_version={T_ASSETS_VERSION}"></script>
<link href="{T_THEME_PATH}/print.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet" type="text/css" media="print" title="printonly" />
<link href="{T_STYLESHEET_LINK}" rel="stylesheet" type="text/css" media="screen, projection" />
@@ -106,7 +96,7 @@
<div id="search-box">
<form action="{U_SEARCH}" method="get" id="search">
<fieldset>
- <input name="keywords" id="keywords" type="text" maxlength="128" title="{L_SEARCH_KEYWORDS}" class="inputbox search" value="<!-- IF SEARCH_WORDS-->{SEARCH_WORDS}<!-- ELSE -->{L_SEARCH_MINI}<!-- ENDIF -->" onclick="if(this.value=='{LA_SEARCH_MINI}')this.value='';" onblur="if(this.value=='')this.value='{LA_SEARCH_MINI}';" />
+ <input name="keywords" id="keywords" type="search" maxlength="128" title="{L_SEARCH_KEYWORDS}" class="inputbox search" value="{SEARCH_WORDS}" placeholder="{L_SEARCH_MINI}" />
<input class="button2" value="{L_SEARCH}" type="submit" /><br />
<a href="{U_SEARCH}" title="{L_SEARCH_ADV_EXPLAIN}">{L_SEARCH_ADV}</a> {S_SEARCH_HIDDEN_FIELDS}
</fieldset>
@@ -137,8 +127,8 @@
<!-- IF not S_IS_BOT and S_USER_LOGGED_IN -->
<ul class="linklist leftside">
<!-- IF S_NOTIFICATIONS_DISPLAY -->
- <li>
- [ <a href="{U_VIEW_ALL_NOTIFICATIONS}" id="notification_list_button">{NOTIFICATIONS_COUNT}</a> ] &bull;
+ <li class="icon-notification">
+ <a href="{U_VIEW_ALL_NOTIFICATIONS}" id="notification_list_button">{NOTIFICATIONS_COUNT}</a>
<div id="notification_list" class="notification_list">
<div class="pointer"><div class="pointer_inner"></div></div>
<div class="header">
diff --git a/phpBB/styles/prosilver/template/posting_buttons.html b/phpBB/styles/prosilver/template/posting_buttons.html
index 8e87407757..fadbc9b3ca 100644
--- a/phpBB/styles/prosilver/template/posting_buttons.html
+++ b/phpBB/styles/prosilver/template/posting_buttons.html
@@ -35,37 +35,30 @@
var panels = new Array('options-panel', 'attach-panel', 'poll-panel');
var show_panel = 'options-panel';
+ function change_palette()
+ {
+ dE('colour_palette');
+ e = document.getElementById('colour_palette');
+
+ if (e.style.display == 'block')
+ {
+ document.getElementById('bbpalette').value = '{LA_FONT_COLOR_HIDE}';
+ }
+ else
+ {
+ document.getElementById('bbpalette').value = '{LA_FONT_COLOR}';
+ }
+ }
// ]]>
</script>
-<script type="text/javascript" src="{T_SUPER_TEMPLATE_PATH}/editor.js"></script>
+<!-- INCLUDEJS template/editor.js -->
<!-- IF S_BBCODE_ALLOWED -->
<div id="colour_palette" style="display: none;">
<dl style="clear: left;">
<dt><label>{L_FONT_COLOR}{L_COLON}</label></dt>
- <dd>
- <script type="text/javascript">
- // <![CDATA[
- function change_palette()
- {
- dE('colour_palette');
- e = document.getElementById('colour_palette');
-
- if (e.style.display == 'block')
- {
- document.getElementById('bbpalette').value = '{LA_FONT_COLOR_HIDE}';
- }
- else
- {
- document.getElementById('bbpalette').value = '{LA_FONT_COLOR}';
- }
- }
-
- colorPalette('h', 15, 10);
- // ]]>
- </script>
- </dd>
+ <dd id="color_palette_placeholder"></dd>
</dl>
</div>
diff --git a/phpBB/styles/prosilver/template/posting_editor.html b/phpBB/styles/prosilver/template/posting_editor.html
index 8156968098..3eac8fb03a 100644
--- a/phpBB/styles/prosilver/template/posting_editor.html
+++ b/phpBB/styles/prosilver/template/posting_editor.html
@@ -1,9 +1,3 @@
-<script type="text/javascript">
-// <![CDATA[
- onload_functions.push(apply_onkeypress_event);
-// ]]>
-</script>
-
<fieldset class="fields1">
<!-- IF ERROR --><p class="error">{ERROR}</p><!-- ENDIF -->
@@ -250,7 +244,7 @@
<!-- IF S_TOPIC_TYPE_ANNOUNCE or S_TOPIC_TYPE_STICKY -->
<dl>
<dt><label for="topic_time_limit">{L_STICK_TOPIC_FOR}{L_COLON}</label></dt>
- <dd><label for="topic_time_limit"><input type="text" name="topic_time_limit" id="topic_time_limit" size="3" maxlength="3" value="{TOPIC_TIME_LIMIT}" class="inputbox autowidth" /> {L_DAYS}</label></dd>
+ <dd><label for="topic_time_limit"><input type="number" min="0" max="999" name="topic_time_limit" id="topic_time_limit" size="3" maxlength="3" value="{TOPIC_TIME_LIMIT}" class="inputbox autowidth" /> {L_DAYS}</label></dd>
<dd>{L_STICK_TOPIC_FOR_EXPLAIN}</dd>
</dl>
<!-- ENDIF -->
diff --git a/phpBB/styles/prosilver/template/posting_poll_body.html b/phpBB/styles/prosilver/template/posting_poll_body.html
index 5d6e01e997..5bb7e1a3df 100644
--- a/phpBB/styles/prosilver/template/posting_poll_body.html
+++ b/phpBB/styles/prosilver/template/posting_poll_body.html
@@ -26,18 +26,18 @@
<dl>
<dt><label for="poll_max_options">{L_POLL_MAX_OPTIONS}{L_COLON}</label></dt>
- <dd><input type="text" name="poll_max_options" id="poll_max_options" size="3" maxlength="3" value="{POLL_MAX_OPTIONS}" class="inputbox autowidth" /></dd>
+ <dd><input type="number" min="1" max="999" name="poll_max_options" id="poll_max_options" size="3" maxlength="3" value="{POLL_MAX_OPTIONS}" class="inputbox autowidth" /></dd>
<dd>{L_POLL_MAX_OPTIONS_EXPLAIN}</dd>
</dl>
<dl>
<dt><label for="poll_length">{L_POLL_FOR}{L_COLON}</label></dt>
- <dd><label for="poll_length"><input type="text" name="poll_length" id="poll_length" size="3" maxlength="3" value="{POLL_LENGTH}" class="inputbox autowidth" /> {L_DAYS}</label></dd>
+ <dd><label for="poll_length"><input type="number" min="0" max="999" name="poll_length" id="poll_length" size="3" maxlength="3" value="{POLL_LENGTH}" class="inputbox autowidth" /> {L_DAYS}</label></dd>
<dd>{L_POLL_FOR_EXPLAIN}</dd>
</dl>
<!-- IF S_POLL_VOTE_CHANGE -->
<hr class="dashed" />
-
+
<dl>
<dt><label for="poll_vote_change">{L_POLL_VOTE_CHANGE}{L_COLON}</label></dt>
<dd><label for="poll_vote_change"><input type="checkbox" id="poll_vote_change" name="poll_vote_change"{VOTE_CHANGE_CHECKED} /> {L_POLL_VOTE_CHANGE_EXPLAIN}</label></dd>
diff --git a/phpBB/styles/prosilver/template/search_body.html b/phpBB/styles/prosilver/template/search_body.html
index dee080def5..fedbdc6642 100644
--- a/phpBB/styles/prosilver/template/search_body.html
+++ b/phpBB/styles/prosilver/template/search_body.html
@@ -19,13 +19,13 @@
<fieldset>
<dl>
<dt><label for="keywords">{L_SEARCH_KEYWORDS}{L_COLON}</label><br /><span>{L_SEARCH_KEYWORDS_EXPLAIN}</span></dt>
- <dd><input type="text" class="inputbox" name="keywords" id="keywords" size="40" title="{L_SEARCH_KEYWORDS}" /></dd>
+ <dd><input type="search" class="inputbox" name="keywords" id="keywords" size="40" title="{L_SEARCH_KEYWORDS}" /></dd>
<dd><label for="terms1"><input type="radio" name="terms" id="terms1" value="all" checked="checked" /> {L_SEARCH_ALL_TERMS}</label></dd>
<dd><label for="terms2"><input type="radio" name="terms" id="terms2" value="any" /> {L_SEARCH_ANY_TERMS}</label></dd>
</dl>
<dl>
<dt><label for="author">{L_SEARCH_AUTHOR}{L_COLON}</label><br /><span>{L_SEARCH_AUTHOR_EXPLAIN}</span></dt>
- <dd><input type="text" class="inputbox" name="author" id="author" size="40" title="{L_SEARCH_AUTHOR}" /></dd>
+ <dd><input type="search" class="inputbox" name="author" id="author" size="40" title="{L_SEARCH_AUTHOR}" /></dd>
</dl>
</fieldset>
diff --git a/phpBB/styles/prosilver/template/search_results.html b/phpBB/styles/prosilver/template/search_results.html
index 62b7c61eb3..1132e5295a 100644
--- a/phpBB/styles/prosilver/template/search_results.html
+++ b/phpBB/styles/prosilver/template/search_results.html
@@ -19,7 +19,7 @@
<!-- IF SEARCH_MATCHES -->
<div class="search-box">
<!-- IF SEARCH_IN_RESULTS -->
- <label for="add_keywords">{L_SEARCH_IN_RESULTS}{L_COLON} <input type="text" name="add_keywords" id="add_keywords" value="" class="inputbox narrow" /></label>
+ <label for="add_keywords">{L_SEARCH_IN_RESULTS}{L_COLON} <input type="search" name="add_keywords" id="add_keywords" value="" class="inputbox narrow" /></label>
<input class="button2" type="submit" name="submit" value="{L_SEARCH}" />
<!-- ENDIF -->
</div>
@@ -48,7 +48,7 @@
<ul class="topiclist">
<li class="header">
<dl class="icon">
- <dt>{L_TOPICS}</dt>
+ <dt><div class="list-inner">{L_TOPICS}</div></dt>
<dd class="posts">{L_REPLIES}</dd>
<dd class="views">{L_VIEWS}</dd>
<dd class="lastpost"><span>{L_LAST_POST}</span></dd>
@@ -60,26 +60,30 @@
<!-- BEGIN searchresults -->
<li class="row<!-- IF searchresults.S_ROW_COUNT is even --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl class="icon {searchresults.TOPIC_IMG_STYLE}">
- <dt <!-- IF searchresults.TOPIC_ICON_IMG -->style="background-image: url({T_ICONS_PATH}{searchresults.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF -->>
- <!-- IF searchresults.S_UNREAD_TOPIC --><a href="{searchresults.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF -->
- <a href="{searchresults.U_VIEW_TOPIC}" class="topictitle">{searchresults.TOPIC_TITLE}</a> {searchresults.ATTACH_ICON_IMG}
- <!-- IF searchresults.S_TOPIC_UNAPPROVED or searchresults.S_POSTS_UNAPPROVED --><a href="{searchresults.U_MCP_QUEUE}">{searchresults.UNAPPROVED_IMG}</a> <!-- ENDIF -->
- <!-- IF searchresults.S_TOPIC_REPORTED --><a href="{searchresults.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --><br />
- <!-- IF .searchresults.pagination -->
- <div class="pagination">
- <ul>
- <!-- BEGIN pagination -->
- <!-- IF searchresults.pagination.S_IS_PREV -->
- <!-- ELSEIF searchresults.pagination.S_IS_CURRENT --><li class="active"><span>{searchresults.pagination.PAGE_NUMBER}</span></li>
- <!-- ELSEIF searchresults.pagination.S_IS_ELLIPSIS --><li class="ellipsis"><span>{L_ELLIPSIS}</span></li>
- <!-- ELSEIF searchresults.pagination.S_IS_NEXT -->
- <!-- ELSE --><li><a href="{searchresults.pagination.PAGE_URL}">{searchresults.pagination.PAGE_NUMBER}</a></li>
- <!-- ENDIF -->
- <!-- END pagination -->
- </ul>
+ <dt <!-- IF searchresults.TOPIC_ICON_IMG -->style="background-image: url({T_ICONS_PATH}{searchresults.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF --> title="{searchresults.TOPIC_FOLDER_IMG_ALT}">
+ <div class="list-inner">
+
+ <!-- IF searchresults.S_UNREAD_TOPIC --><a href="{searchresults.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF -->
+ <a href="{searchresults.U_VIEW_TOPIC}" class="topictitle">{searchresults.TOPIC_TITLE}</a> {searchresults.ATTACH_ICON_IMG}
+ <!-- IF searchresults.S_TOPIC_UNAPPROVED or searchresults.S_POSTS_UNAPPROVED --><a href="{searchresults.U_MCP_QUEUE}">{searchresults.UNAPPROVED_IMG}</a> <!-- ENDIF -->
+ <!-- IF searchresults.S_TOPIC_REPORTED --><a href="{searchresults.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --><br />
+ <!-- IF .searchresults.pagination -->
+ <div class="pagination">
+ <ul>
+ <!-- BEGIN pagination -->
+ <!-- IF searchresults.pagination.S_IS_PREV -->
+ <!-- ELSEIF searchresults.pagination.S_IS_CURRENT --><li class="active"><span>{searchresults.pagination.PAGE_NUMBER}</span></li>
+ <!-- ELSEIF searchresults.pagination.S_IS_ELLIPSIS --><li class="ellipsis"><span>{L_ELLIPSIS}</span></li>
+ <!-- ELSEIF searchresults.pagination.S_IS_NEXT -->
+ <!-- ELSE --><li><a href="{searchresults.pagination.PAGE_URL}">{searchresults.pagination.PAGE_NUMBER}</a></li>
+ <!-- ENDIF -->
+ <!-- END pagination -->
+ </ul>
+ </div>
+ <!-- ENDIF -->
+ {L_POST_BY_AUTHOR} {searchresults.TOPIC_AUTHOR_FULL} &raquo; {searchresults.FIRST_POST_TIME} &raquo; {L_IN} <a href="{searchresults.U_VIEW_FORUM}">{searchresults.FORUM_TITLE}</a>
+
</div>
- <!-- ENDIF -->
- {L_POST_BY_AUTHOR} {searchresults.TOPIC_AUTHOR_FULL} &raquo; {searchresults.FIRST_POST_TIME} &raquo; {L_IN} <a href="{searchresults.U_VIEW_FORUM}">{searchresults.FORUM_TITLE}</a>
</dt>
<dd class="posts">{searchresults.TOPIC_REPLIES}</dd>
<dd class="views">{searchresults.TOPIC_VIEWS}</dd>
diff --git a/phpBB/styles/prosilver/template/simple_footer.html b/phpBB/styles/prosilver/template/simple_footer.html
index ec189304fc..144ae8e462 100644
--- a/phpBB/styles/prosilver/template/simple_footer.html
+++ b/phpBB/styles/prosilver/template/simple_footer.html
@@ -8,6 +8,7 @@
<script type="text/javascript" src="{T_JQUERY_LINK}"></script>
<!-- IF S_JQUERY_FALLBACK --><script type="text/javascript">window.jQuery || document.write(unescape('%3Cscript src="{T_ASSETS_PATH}/javascript/jquery.js?assets_version={T_ASSETS_VERSION}" type="text/javascript"%3E%3C/script%3E'));</script><!-- ENDIF -->
+<script type="text/javascript" src="{T_SUPER_TEMPLATE_PATH}/forum_fn.js?assets_version={T_ASSETS_VERSION}"></script>
{SCRIPTS}
<!-- EVENT simple_footer_after -->
diff --git a/phpBB/styles/prosilver/template/simple_header.html b/phpBB/styles/prosilver/template/simple_header.html
index 88b2c0c025..667698c371 100644
--- a/phpBB/styles/prosilver/template/simple_header.html
+++ b/phpBB/styles/prosilver/template/simple_header.html
@@ -40,7 +40,6 @@
// ]]>
</script>
-<script type="text/javascript" src="{T_SUPER_TEMPLATE_PATH}/forum_fn.js?assets_version={T_ASSETS_VERSION}"></script>
<link href="{T_THEME_PATH}/print.css?assets_version={T_ASSETS_VERSION}" rel="stylesheet" type="text/css" media="print" title="printonly" />
<link href="{T_STYLESHEET_LINK}" rel="stylesheet" type="text/css" media="screen, projection" />
diff --git a/phpBB/styles/prosilver/template/timezone.js b/phpBB/styles/prosilver/template/timezone.js
index af8206d12d..e0d3da9ff7 100644
--- a/phpBB/styles/prosilver/template/timezone.js
+++ b/phpBB/styles/prosilver/template/timezone.js
@@ -1,5 +1,7 @@
(function($) { // Avoid conflicts with other libraries
+"use strict";
+
$('#tz_date').change(function() {
phpbb.timezoneSwitchDate(false);
});
@@ -13,7 +15,7 @@ $(document).ready(
);
$(document).ready(
- phpbb.timezonePreselectSelect($('#tz_select_date_suggest').attr('data-is-registration') == 'true')
+ phpbb.timezonePreselectSelect($('#tz_select_date_suggest').attr('timezone-preselect') === 'true')
);
})(jQuery); // Avoid conflicts with other libraries
diff --git a/phpBB/styles/prosilver/template/timezone_option.html b/phpBB/styles/prosilver/template/timezone_option.html
index 320b9b7121..a77e82f9a1 100644
--- a/phpBB/styles/prosilver/template/timezone_option.html
+++ b/phpBB/styles/prosilver/template/timezone_option.html
@@ -6,7 +6,7 @@
<option value="">{L_SELECT_CURRENT_TIME}</option>
{S_TZ_DATE_OPTIONS}
</select>
- <input type="button" id="tz_select_date_suggest" class="button2" style="display: none;" data-is-registration="<!-- IF S_REGISTRATION -->true<!-- ELSE -->false<!-- ENDIF -->" data-l-suggestion="{L_TIMEZONE_DATE_SUGGESTION}" value="{L_TIMEZONE_DATE_SUGGESTION}" />
+ <input type="button" id="tz_select_date_suggest" class="button2" style="display: none;" timezone-preselect="<!-- IF S_TZ_PRESELECT -->true<!-- ELSE -->false<!-- ENDIF -->" data-l-suggestion="{L_TIMEZONE_DATE_SUGGESTION}" value="{L_TIMEZONE_DATE_SUGGESTION}" />
</dd>
<!-- ENDIF -->
<dd>
diff --git a/phpBB/styles/prosilver/template/ucp_attachments.html b/phpBB/styles/prosilver/template/ucp_attachments.html
index 478b14ab86..6e1bdfdd57 100644
--- a/phpBB/styles/prosilver/template/ucp_attachments.html
+++ b/phpBB/styles/prosilver/template/ucp_attachments.html
@@ -24,7 +24,7 @@
<ul class="topiclist">
<li class="header">
<dl>
- <dt style="width: 40%"><a href="{U_SORT_FILENAME}">{L_FILENAME}</a></dt>
+ <dt><div class="list-inner"><a href="{U_SORT_FILENAME}">{L_FILENAME}</a></div></dt>
<dd class="extra"><a href="{U_SORT_DOWNLOADS}">{L_DOWNLOADS}</a></dd>
<dd class="time"><span><a href="{U_SORT_POST_TIME}">{L_POST_TIME}</a></span></dd>
<dd class="mark">{L_MARK}</dd>
@@ -36,8 +36,12 @@
<!-- BEGIN attachrow -->
<li class="row<!-- IF attachrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl>
- <dt style="width: 40%"><a href="{attachrow.U_VIEW_ATTACHMENT}" class="topictitle">{attachrow.FILENAME}</a> ({attachrow.SIZE})<br />
- <!-- IF attachrow.S_IN_MESSAGE -->{L_PM}{L_COLON} <!-- ELSE -->{L_TOPIC}{L_COLON} <!-- ENDIF --><a href="{attachrow.U_VIEW_TOPIC}">{attachrow.TOPIC_TITLE}</a></dt>
+ <dt>
+ <div class="list-inner">
+ <a href="{attachrow.U_VIEW_ATTACHMENT}" class="topictitle">{attachrow.FILENAME}</a> ({attachrow.SIZE})<br />
+ <!-- IF attachrow.S_IN_MESSAGE -->{L_PM}{L_COLON} <!-- ELSE -->{L_TOPIC}{L_COLON} <!-- ENDIF --><a href="{attachrow.U_VIEW_TOPIC}">{attachrow.TOPIC_TITLE}</a>
+ </div>
+ </dt>
<dd class="extra">{attachrow.DOWNLOAD_COUNT}</dd>
<dd class="time"><span>{attachrow.POST_TIME}</span></dd>
<dd class="mark"><input type="checkbox" name="attachment[{attachrow.ATTACH_ID}]" value="1" /></dd>
diff --git a/phpBB/styles/prosilver/template/ucp_avatar_options.html b/phpBB/styles/prosilver/template/ucp_avatar_options.html
index 850a1412a0..e7f4a48e11 100644
--- a/phpBB/styles/prosilver/template/ucp_avatar_options.html
+++ b/phpBB/styles/prosilver/template/ucp_avatar_options.html
@@ -1,4 +1,3 @@
-
<div class="panel">
<div class="inner">
<!-- IF not S_AVATARS_ENABLED -->
@@ -7,64 +6,45 @@
<fieldset>
<!-- IF ERROR --><p class="error">{ERROR}</p><!-- ENDIF -->
- <dl>
- <dt><label>{L_CURRENT_IMAGE}{L_COLON}</label><br /><span>{L_AVATAR_EXPLAIN}</span></dt>
- <dd><!-- IF AVATAR -->{AVATAR}<!-- ELSE --><img src="{T_THEME_PATH}/images/no_avatar.gif" alt="" /><!-- ENDIF --></dd>
- <dd><label for="delete"><input type="checkbox" name="delete" id="delete" /> {L_DELETE_AVATAR}</label></dd>
- </dl>
-
- <!-- IF S_UPLOAD_AVATAR_FILE -->
<dl>
- <dt><label for="uploadfile">{L_UPLOAD_AVATAR_FILE}{L_COLON}</label></dt>
- <dd><input type="hidden" name="MAX_FILE_SIZE" value="{AVATAR_SIZE}" /><input type="file" name="uploadfile" id="uploadfile" class="inputbox autowidth" /></dd>
- </dl>
- <!-- ENDIF -->
-
- <!-- IF S_UPLOAD_AVATAR_URL -->
- <dl>
- <dt><label for="uploadurl">{L_UPLOAD_AVATAR_URL}{L_COLON}</label><br /><span>{L_UPLOAD_AVATAR_URL_EXPLAIN}</span></dt>
- <dd><input type="text" name="uploadurl" id="uploadurl" value="{AVATAR_URL}" class="inputbox" /></dd>
- </dl>
- <!-- ENDIF -->
-
- <!-- IF S_LINK_AVATAR -->
- <dl>
- <dt><label for="remotelink">{L_LINK_REMOTE_AVATAR}{L_COLON}</label><br /><span>{L_LINK_REMOTE_AVATAR_EXPLAIN}</span></dt>
- <dd><input type="text" name="remotelink" id="remotelink" value="{AVATAR_REMOTE}" class="inputbox" /></dd>
+ <dt><label>{L_CURRENT_IMAGE}{L_COLON}</label><br /><span>{L_AVATAR_EXPLAIN}</span></dt>
+ <dd><!-- IF AVATAR -->{AVATAR}<!-- ELSE --><img src="{T_THEME_PATH}/images/no_avatar.gif" alt="" /><!-- ENDIF --></dd>
+ <dd><label for="avatar_delete"><input type="checkbox" name="avatar_delete" id="avatar_delete" /> {L_DELETE_AVATAR}</label></dd>
</dl>
+ </fieldset>
+ <h3>{L_AVATAR_SELECT}</h3>
+ <fieldset>
<dl>
- <dt><label for="width">{L_LINK_REMOTE_SIZE}{L_COLON}</label><br /><span>{L_LINK_REMOTE_SIZE_EXPLAIN}</span></dt>
- <dd>
- <label for="width"><input type="text" name="width" id="width" size="3" value="{AVATAR_WIDTH}" class="inputbox autowidth" /> {L_PIXEL}</label> &times;&nbsp;
- <label for="height"><input type="text" name="height" id="height" size="3" value="{AVATAR_HEIGHT}" class="inputbox autowidth" /> {L_PIXEL}</label>
- </dd>
+ <dt><label>{L_AVATAR_TYPE}{L_COLON}</label></dt>
+ <dd><select name="avatar_driver" id="avatar_driver">
+ <option value="">{L_NO_AVATAR_CATEGORY}</option>
+ <!-- BEGIN avatar_drivers -->
+ <option value="{avatar_drivers.DRIVER}"<!-- IF avatar_drivers.SELECTED --> selected="selected"<!-- ENDIF -->>{avatar_drivers.L_TITLE}</option>
+ <!-- END avatar_drivers -->
+ </select></dd>
</dl>
- <!-- ENDIF -->
</fieldset>
+ <div id="avatar_options">
+<!-- BEGIN avatar_drivers -->
+ <div id="avatar_option_{avatar_drivers.DRIVER}">
+ <noscript>
+ <h3 class="avatar_section_header">{avatar_drivers.L_TITLE}</h3>
+ </noscript>
+ <p>{avatar_drivers.L_EXPLAIN}</p>
- <!-- IF S_IN_AVATAR_GALLERY -->
- </div>
+ <fieldset>
+ {avatar_drivers.OUTPUT}
+ </fieldset>
</div>
-
- <div class="panel">
- <div class="inner">
-
- <h3>{L_AVATAR_GALLERY}</h3>
-
- <fieldset>
- <label for="category">{L_AVATAR_CATEGORY}{L_COLON} <select name="category" id="category">{S_CAT_OPTIONS}</select></label>
- <input type="submit" value="{L_GO}" name="display_gallery" class="button2" />
- <input type="submit" name="cancel" value="{L_CANCEL}" class="button2" />
- </fieldset>
-
- <div id="gallery">
- <!-- BEGIN avatar_row --><!-- BEGIN avatar_column -->
- <label for="av-{avatar_row.S_ROW_COUNT}-{avatar_row.avatar_column.S_ROW_COUNT}"><img src="{avatar_row.avatar_column.AVATAR_IMAGE}" alt="" /><br />
- <input type="radio" name="avatar_select" id="av-{avatar_row.S_ROW_COUNT}-{avatar_row.avatar_column.S_ROW_COUNT}" value="{avatar_row.avatar_column.AVATAR_FILE}" /></label>
- <!-- END avatar_column --><!-- END avatar_row -->
- </div>
-
- <!-- ENDIF -->
-
+<!-- END avatar_drivers -->
+ </div>
+<!-- IF not S_GROUP_MANAGE -->
+ <fieldset class="submit-buttons">
+ <input type="reset" value="{L_RESET}" name="reset" class="button2" /> &nbsp;
+ <input type="submit" name="submit" value="{L_SUBMIT}" class="button1" />
+ </fieldset>
+<!-- ENDIF -->
</div>
</div>
+
+<!-- INCLUDEJS template/avatars.js -->
diff --git a/phpBB/styles/prosilver/template/ucp_avatar_options_gravatar.html b/phpBB/styles/prosilver/template/ucp_avatar_options_gravatar.html
new file mode 100644
index 0000000000..88e0e69f53
--- /dev/null
+++ b/phpBB/styles/prosilver/template/ucp_avatar_options_gravatar.html
@@ -0,0 +1,25 @@
+<script type="text/javascript">
+// <![CDATA[
+
+onload_functions.push(function() {
+ $('#avatar_gravatar_email').bind('keyup', function () {
+ $('#avatar_gravatar_width').val('');
+ $('#avatar_gravatar_height').val('');
+ $('#avatar_gravatar_email').unbind('keyup');
+ });
+});
+
+// ]]>
+</script>
+
+<dl>
+ <dt><label for="avatar_gravatar_email">{L_GRAVATAR_AVATAR_EMAIL}{L_COLON}</label><br /><span>{L_GRAVATAR_AVATAR_EMAIL_EXPLAIN}</span></dt>
+ <dd><input type="email" name="avatar_gravatar_email" id="avatar_gravatar_email" value="{AVATAR_GRAVATAR_EMAIL}" class="inputbox" /></dd>
+</dl>
+<dl>
+ <dt><label for="avatar_gravatar_width">{L_GRAVATAR_AVATAR_SIZE}{L_COLON}</label><br /><span>{L_GRAVATAR_AVATAR_SIZE_EXPLAIN}</span></dt>
+ <dd>
+ <label for="avatar_gravatar_width"><input type="text" name="avatar_gravatar_width" id="avatar_gravatar_width" size="3" value="{AVATAR_GRAVATAR_WIDTH}" class="inputbox autowidth" /> {L_PIXEL}</label> &times;&nbsp;
+ <label for="avatar_gravatar_height"><input type="text" name="avatar_gravatar_height" id="avatar_gravatar_height" size="3" value="{AVATAR_GRAVATAR_HEIGHT}" class="inputbox autowidth" /> {L_PIXEL}</label>
+ </dd>
+</dl>
diff --git a/phpBB/styles/prosilver/template/ucp_avatar_options_local.html b/phpBB/styles/prosilver/template/ucp_avatar_options_local.html
new file mode 100644
index 0000000000..3946b9d269
--- /dev/null
+++ b/phpBB/styles/prosilver/template/ucp_avatar_options_local.html
@@ -0,0 +1,20 @@
+<!-- IF .avatar_local_cats -->
+<label for="category">{L_AVATAR_CATEGORY}{L_COLON} <select name="avatar_local_cat" id="category">
+<option value="">{L_NO_AVATAR_CATEGORY}</option>
+<!-- BEGIN avatar_local_cats -->
+<option value="{avatar_local_cats.NAME}"<!-- IF avatar_local_cats.SELECTED --> selected="selected"<!-- ENDIF -->>{avatar_local_cats.NAME}</option>
+<!-- END avatar_local_cats -->
+</select></label>
+<input type="submit" value="{L_GO}" name="avatar_local_go" class="button2" />
+
+<div id="gallery">
+<!-- BEGIN avatar_local_row -->
+<!-- BEGIN avatar_local_col -->
+ <label for="av-{avatar_local_row.S_ROW_COUNT}-{avatar_local_row.avatar_local_col.S_ROW_COUNT}"><img src="{avatar_local_row.avatar_local_col.AVATAR_IMAGE}" alt="" /><br />
+ <input type="radio" name="avatar_local_file" id="av-{avatar_local_row.S_ROW_COUNT}-{avatar_local_row.avatar_local_col.S_ROW_COUNT}" value="{avatar_local_row.avatar_local_col.AVATAR_FILE}" /></label>
+<!-- END avatar_local_col -->
+<!-- END avatar_local_row -->
+</div>
+<!-- ELSE -->
+<p><strong>{L_NO_AVATARS}</strong></p>
+<!-- ENDIF -->
diff --git a/phpBB/styles/prosilver/template/ucp_avatar_options_remote.html b/phpBB/styles/prosilver/template/ucp_avatar_options_remote.html
new file mode 100644
index 0000000000..59adf10058
--- /dev/null
+++ b/phpBB/styles/prosilver/template/ucp_avatar_options_remote.html
@@ -0,0 +1,25 @@
+<script type="text/javascript">
+// <![CDATA[
+
+onload_functions.push(function() {
+ $('#avatar_remote_url').bind('keyup', function () {
+ $('#avatar_remote_width').val('');
+ $('#avatar_remote_height').val('');
+ $('#avatar_remote_url').unbind('keyup');
+ });
+});
+
+// ]]>
+</script>
+
+<dl>
+ <dt><label for="avatar_remote_url">{L_LINK_REMOTE_AVATAR}{L_COLON}</label><br /><span>{L_LINK_REMOTE_AVATAR_EXPLAIN}</span></dt>
+ <dd><input type="url" name="avatar_remote_url" id="avatar_remote_url" value="{AVATAR_REMOTE_URL}" class="inputbox" /></dd>
+</dl>
+<dl>
+ <dt><label for="avatar_remote_width">{L_LINK_REMOTE_SIZE}{L_COLON}</label><br /><span>{L_LINK_REMOTE_SIZE_EXPLAIN}</span></dt>
+ <dd>
+ <label for="avatar_remote_width"><input type="text" name="avatar_remote_width" id="avatar_remote_width" size="3" value="{AVATAR_REMOTE_WIDTH}" class="inputbox autowidth" /> {L_PIXEL}</label> &times;&nbsp;
+ <label for="avatar_remote_height"><input type="text" name="avatar_remote_height" id="avatar_remote_height" size="3" value="{AVATAR_REMOTE_HEIGHT}" class="inputbox autowidth" /> {L_PIXEL}</label>
+ </dd>
+</dl>
diff --git a/phpBB/styles/prosilver/template/ucp_avatar_options_upload.html b/phpBB/styles/prosilver/template/ucp_avatar_options_upload.html
new file mode 100644
index 0000000000..63a734ea7d
--- /dev/null
+++ b/phpBB/styles/prosilver/template/ucp_avatar_options_upload.html
@@ -0,0 +1,11 @@
+<dl>
+ <dt><label for="avatar_upload_file">{L_UPLOAD_AVATAR_FILE}{L_COLON}</label></dt>
+ <dd><input type="hidden" name="MAX_FILE_SIZE" value="{AVATAR_UPLOAD_SIZE}" /><input type="file" name="avatar_upload_file" id="avatar_upload_file" class="inputbox autowidth" /></dd>
+</dl>
+
+<!-- IF S_UPLOAD_AVATAR_URL -->
+ <dl>
+ <dt><label for="avatar_upload_url">{L_UPLOAD_AVATAR_URL}{L_COLON}</label><br /><span>{L_UPLOAD_AVATAR_URL_EXPLAIN}</span></dt>
+ <dd><input type="url" name="avatar_upload_url" id="avatar_upload_url" value="" class="inputbox" /></dd>
+ </dl>
+<!-- ENDIF -->
diff --git a/phpBB/styles/prosilver/template/ucp_groups_manage.html b/phpBB/styles/prosilver/template/ucp_groups_manage.html
index 6b017ea3fa..a785d18082 100644
--- a/phpBB/styles/prosilver/template/ucp_groups_manage.html
+++ b/phpBB/styles/prosilver/template/ucp_groups_manage.html
@@ -6,19 +6,18 @@
<div class="panel">
<div class="inner">
-
+
+ <!-- IF S_ERROR -->
+ <fieldset>
+ <p class="error">{ERROR_MSG}</p>
+ </fieldset>
+ <!-- ENDIF -->
+
<p>{L_GROUPS_EXPLAIN}</p>
<!-- IF S_EDIT -->
<h3>{L_GROUP_DETAILS}</h3>
-
- <!-- IF S_ERROR -->
- <div class="errorbox">
- <h3>{L_WARNING}</h3>
- <p>{ERROR_MSG}</p>
- </div>
- <!-- ENDIF -->
-
+
<fieldset>
<dl>
<dt><label for="group_name">{L_GROUP_NAME}{L_COLON}</label></dt>
@@ -55,7 +54,7 @@
<fieldset>
<dl>
<dt><label for="group_colour">{L_GROUP_COLOR}{L_COLON}</label><br /><span>{L_GROUP_COLOR_EXPLAIN}</span></dt>
- <dd><input name="group_colour" type="text" id="group_colour" value="{GROUP_COLOUR}" size="7" maxlength="7" class="inputbox narrow" /> <span style="background-color: {GROUP_COLOUR};">&nbsp;&nbsp;&nbsp;</span> [ <a href="{U_SWATCH}" onclick="popup(this.href, 636, 150, '_swatch'); return false;">{L_COLOUR_SWATCH}</a> ]</dd>
+ <dd><input name="group_colour" type="text" id="group_colour" value="{GROUP_COLOUR}" size="6" maxlength="6" class="inputbox narrow" /> <span style="background-color: {GROUP_COLOUR};">&nbsp;&nbsp;&nbsp;</span> [ <a href="{U_SWATCH}" onclick="popup(this.href, 636, 150, '_swatch'); return false;">{L_COLOUR_SWATCH}</a> ]</dd>
</dl>
<dl>
<dt><label for="group_rank">{L_GROUP_RANK}{L_COLON}</label></dt>
@@ -70,9 +69,7 @@
<fieldset class="submit-buttons">
{S_HIDDEN_FIELDS}
- <!-- IF S_DISPLAY_GALLERY --><input type="submit" name="display_gallery" value="{L_DISPLAY_GALLERY}" class="button2" />&nbsp; <!-- ENDIF -->
- <!-- IF S_IN_AVATAR_GALLERY --><input type="submit" name="cancel" value="{L_CANCEL}" class="button2" />&nbsp; <!-- ELSE -->
- <input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp; <!-- ENDIF -->
+ <input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
<input type="submit" name="update" value="{L_SUBMIT}" class="button1" />
{S_FORM_TOKEN}
</fieldset>
@@ -209,21 +206,25 @@
<!-- ELSE -->
<!-- IF .leader -->
- <ul class="topiclist">
+ <ul class="topiclist two-long-columns">
<li class="header">
<dl>
- <dt>{L_GROUP_LEADER}</dt>
+ <dt><div class="list-inner">{L_GROUP_LEADER}</div></dt>
<dd class="info"><span>{L_OPTIONS}</span></dd>
</dl>
</li>
</ul>
- <ul class="topiclist cplist">
+ <ul class="topiclist cplist two-long-columns">
<!-- BEGIN leader -->
<li class="row<!-- IF attachrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl>
- <dt><a href="{leader.U_EDIT}" class="topictitle"<!-- IF leader.GROUP_COLOUR --> style="color: #{leader.GROUP_COLOUR};"<!-- ENDIF -->>{leader.GROUP_NAME}</a>
- <!-- IF leader.GROUP_DESC --><br />{leader.GROUP_DESC}<!-- ENDIF --></dt>
+ <dt>
+ <div class="list-inner">
+ <a href="{leader.U_EDIT}" class="topictitle"<!-- IF leader.GROUP_COLOUR --> style="color: #{leader.GROUP_COLOUR};"<!-- ENDIF -->>{leader.GROUP_NAME}</a>
+ <!-- IF leader.GROUP_DESC --><br />{leader.GROUP_DESC}<!-- ENDIF -->
+ </div>
+ </dt>
<dd class="option"><span><a href="{leader.U_EDIT}" >{L_EDIT}</a></span></dd>
<dd class="option"><span><a href="{leader.U_LIST}">{L_GROUP_LIST}</a></span></dd>
</dl>
diff --git a/phpBB/styles/prosilver/template/ucp_groups_membership.html b/phpBB/styles/prosilver/template/ucp_groups_membership.html
index bf266208f2..d7df3b02c2 100644
--- a/phpBB/styles/prosilver/template/ucp_groups_membership.html
+++ b/phpBB/styles/prosilver/template/ucp_groups_membership.html
@@ -10,15 +10,15 @@
<p>{L_GROUPS_EXPLAIN}</p>
<!-- DEFINE $SHOW_BUTTONS = 0 -->
<!-- IF .leader -->
- <ul class="topiclist">
+ <ul class="topiclist two-columns">
<li class="header">
<dl>
- <dt>{L_GROUP_LEADER}</dt>
+ <dt><div class="list-inner">{L_GROUP_LEADER}</div></dt>
<dd class="mark">{L_SELECT}</dd>
</dl>
</li>
</ul>
- <ul class="topiclist cplist">
+ <ul class="topiclist cplist two-columns">
<!-- BEGIN leader -->
<!-- IF not leader.GROUP_SPECIAL -->
@@ -26,10 +26,13 @@
<!-- ENDIF -->
<li class="row<!-- IF leader.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl>
- <dt><!-- IF S_CHANGE_DEFAULT --><input title="{L_CHANGE_DEFAULT_GROUP}" type="radio" name="default"<!-- IF leader.S_GROUP_DEFAULT --> checked="checked"<!-- ENDIF --> value="{leader.GROUP_ID}" /> <!-- ENDIF -->
- <a href="{leader.U_VIEW_GROUP}" class="forumtitle"<!-- IF leader.GROUP_COLOUR --> style="color:#{leader.GROUP_COLOUR}"<!-- ENDIF -->>{leader.GROUP_NAME}</a>
- <!-- IF leader.GROUP_DESC --><br />{leader.GROUP_DESC}<!-- ENDIF -->
- <!-- IF not leader.GROUP_SPECIAL --><br /><i>{leader.GROUP_STATUS}</i><!-- ENDIF -->
+ <dt>
+ <div class="list-inner">
+ <!-- IF S_CHANGE_DEFAULT --><input title="{L_CHANGE_DEFAULT_GROUP}" type="radio" name="default"<!-- IF leader.S_GROUP_DEFAULT --> checked="checked"<!-- ENDIF --> value="{leader.GROUP_ID}" /> <!-- ENDIF -->
+ <a href="{leader.U_VIEW_GROUP}" class="forumtitle"<!-- IF leader.GROUP_COLOUR --> style="color:#{leader.GROUP_COLOUR}"<!-- ENDIF -->>{leader.GROUP_NAME}</a>
+ <!-- IF leader.GROUP_DESC --><br />{leader.GROUP_DESC}<!-- ENDIF -->
+ <!-- IF not leader.GROUP_SPECIAL --><br /><i>{leader.GROUP_STATUS}</i><!-- ENDIF -->
+ </div>
</dt>
<dd class="mark"><input type="radio" name="selected" value="{leader.GROUP_ID}" <!-- IF leader.GROUP_SPECIAL -->disabled="disabled"<!-- ENDIF --> /></dd>
</dl>
@@ -39,15 +42,15 @@
<!-- ENDIF -->
<!-- IF .member -->
- <ul class="topiclist">
+ <ul class="topiclist two-columns">
<li class="header">
<dl>
- <dt>{L_GROUP_MEMBER}</dt>
+ <dt><div class="list-inner">{L_GROUP_MEMBER}</div></dt>
<dd class="mark">{L_SELECT}</dd>
</dl>
</li>
</ul>
- <ul class="topiclist cplist">
+ <ul class="topiclist cplist two-columns">
<!-- BEGIN member -->
<!-- IF not member.GROUP_SPECIAL -->
@@ -55,10 +58,13 @@
<!-- ENDIF -->
<li class="row<!-- IF member.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl>
- <dt><!-- IF S_CHANGE_DEFAULT --><input title="{L_CHANGE_DEFAULT_GROUP}" type="radio" name="default"<!-- IF member.S_GROUP_DEFAULT --> checked="checked"<!-- ENDIF --> value="{member.GROUP_ID}" /> <!-- ENDIF -->
- <a href="{member.U_VIEW_GROUP}" class="forumtitle"<!-- IF member.GROUP_COLOUR --> style="color:#{member.GROUP_COLOUR}"<!-- ENDIF -->>{member.GROUP_NAME}</a>
- <!-- IF member.GROUP_DESC --><br />{member.GROUP_DESC}<!-- ENDIF -->
- <!-- IF not member.GROUP_SPECIAL --><br /><i>{member.GROUP_STATUS}</i><!-- ENDIF -->
+ <dt>
+ <div class="list-inner">
+ <!-- IF S_CHANGE_DEFAULT --><input title="{L_CHANGE_DEFAULT_GROUP}" type="radio" name="default"<!-- IF member.S_GROUP_DEFAULT --> checked="checked"<!-- ENDIF --> value="{member.GROUP_ID}" /> <!-- ENDIF -->
+ <a href="{member.U_VIEW_GROUP}" class="forumtitle"<!-- IF member.GROUP_COLOUR --> style="color:#{member.GROUP_COLOUR}"<!-- ENDIF -->>{member.GROUP_NAME}</a>
+ <!-- IF member.GROUP_DESC --><br />{member.GROUP_DESC}<!-- ENDIF -->
+ <!-- IF not member.GROUP_SPECIAL --><br /><i>{member.GROUP_STATUS}</i><!-- ENDIF -->
+ </div>
</dt>
<dd class="mark"><input type="radio" name="selected" value="{member.GROUP_ID}" <!-- IF member.GROUP_SPECIAL -->disabled="disabled"<!-- ENDIF --> /></dd>
</dl>
@@ -72,15 +78,15 @@
<!-- IF .pending -->
<div class="panel">
<div class="inner">
- <ul class="topiclist">
+ <ul class="topiclist two-columns">
<li class="header">
<dl>
- <dt>{L_GROUP_PENDING}</dt>
+ <dt><div class="list-inner">{L_GROUP_PENDING}</div></dt>
<dd class="mark">{L_SELECT}</dd>
</dl>
</li>
</ul>
- <ul class="topiclist cplist">
+ <ul class="topiclist cplist two-columns">
<!-- BEGIN pending -->
<!-- IF not pending.GROUP_SPECIAL -->
@@ -89,9 +95,11 @@
<li class="row<!-- IF pending.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl>
<dt>
- <a href="{pending.U_VIEW_GROUP}" class="forumtitle"<!-- IF pending.GROUP_COLOUR --> style="color:#{pending.GROUP_COLOUR}"<!-- ENDIF -->>{pending.GROUP_NAME}</a>
- <!-- IF pending.GROUP_DESC --><br />{pending.GROUP_DESC}<!-- ENDIF -->
- <!-- IF not pending.GROUP_SPECIAL --><br /><i>{pending.GROUP_STATUS}</i><!-- ENDIF -->
+ <div class="list-inner">
+ <a href="{pending.U_VIEW_GROUP}" class="forumtitle"<!-- IF pending.GROUP_COLOUR --> style="color:#{pending.GROUP_COLOUR}"<!-- ENDIF -->>{pending.GROUP_NAME}</a>
+ <!-- IF pending.GROUP_DESC --><br />{pending.GROUP_DESC}<!-- ENDIF -->
+ <!-- IF not pending.GROUP_SPECIAL --><br /><i>{pending.GROUP_STATUS}</i><!-- ENDIF -->
+ </div>
</dt>
<dd class="mark"><input type="radio" name="selected" value="{pending.GROUP_ID}" <!-- IF pending.GROUP_SPECIAL -->disabled="disabled"<!-- ENDIF --> /></dd>
</dl>
@@ -104,15 +112,15 @@
<!-- IF .nonmember -->
<div class="panel">
<div class="inner">
- <ul class="topiclist">
+ <ul class="topiclist two-columns">
<li class="header">
<dl>
- <dt>{L_GROUP_NONMEMBER}</dt>
+ <dt><div class="list-inner">{L_GROUP_NONMEMBER}</div></dt>
<dd class="mark">{L_SELECT}</dd>
</dl>
</li>
</ul>
- <ul class="topiclist cplist">
+ <ul class="topiclist cplist two-columns">
<!-- BEGIN nonmember -->
<!-- IF nonmember.S_CAN_JOIN -->
@@ -121,9 +129,11 @@
<li class="row<!-- IF nonmember.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl>
<dt>
- <a href="{nonmember.U_VIEW_GROUP}" class="forumtitle"<!-- IF nonmember.GROUP_COLOUR --> style="color:#{nonmember.GROUP_COLOUR}"<!-- ENDIF -->>{nonmember.GROUP_NAME}</a>
- <!-- IF nonmember.GROUP_DESC --><br />{nonmember.GROUP_DESC}<!-- ENDIF -->
- <!-- IF not nonmember.GROUP_SPECIAL --><br /><i>{nonmember.GROUP_STATUS}</i><!-- ENDIF -->
+ <div class="list-inner">
+ <a href="{nonmember.U_VIEW_GROUP}" class="forumtitle"<!-- IF nonmember.GROUP_COLOUR --> style="color:#{nonmember.GROUP_COLOUR}"<!-- ENDIF -->>{nonmember.GROUP_NAME}</a>
+ <!-- IF nonmember.GROUP_DESC --><br />{nonmember.GROUP_DESC}<!-- ENDIF -->
+ <!-- IF not nonmember.GROUP_SPECIAL --><br /><i>{nonmember.GROUP_STATUS}</i><!-- ENDIF -->
+ </div>
</dt>
<dd class="mark"><input type="radio" name="selected" value="{nonmember.GROUP_ID}" <!-- IF not nonmember.S_CAN_JOIN -->disabled="disabled"<!-- ENDIF --> /></dd>
</dl>
diff --git a/phpBB/styles/prosilver/template/ucp_main_bookmarks.html b/phpBB/styles/prosilver/template/ucp_main_bookmarks.html
index 8707a749c1..017fadad77 100644
--- a/phpBB/styles/prosilver/template/ucp_main_bookmarks.html
+++ b/phpBB/styles/prosilver/template/ucp_main_bookmarks.html
@@ -14,43 +14,48 @@
<!-- ELSE -->
<!-- IF .topicrow -->
- <ul class="topiclist">
+ <ul class="topiclist missing-column">
<li class="header">
<dl class="icon">
- <dt>{L_BOOKMARKS}</dt>
+ <dt><div class="list-inner">{L_BOOKMARKS}</div></dt>
<dd class="lastpost"><span>{L_LAST_POST}</span></dd>
+ <dd class="mark">{L_MARK}</dd>
</dl>
</li>
</ul>
- <ul class="topiclist cplist">
+ <ul class="topiclist cplist missing-column">
<!-- BEGIN topicrow -->
<li class="row<!-- IF topicrow.S_TOPIC_REPORTED --> reported<!-- ELSEIF topicrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<!-- IF topicrow.S_DELETED_TOPIC -->
- <dl><dt><strong>{L_DELETED_TOPIC}</strong></dt>
- <dd class="mark"><input type="checkbox" name="t[{topicrow.TOPIC_ID}]" id="t{topicrow.TOPIC_ID}" /></dd>
+ <dl>
+ <dt><div class="list-inner"><strong>{L_DELETED_TOPIC}</strong></div></dt>
+ <dd class="lastpost"><span>&nbsp;</span></dd>
+ <dd class="mark"><input type="checkbox" name="t[{topicrow.TOPIC_ID}]" id="t{topicrow.TOPIC_ID}" /></dd>
</dl>
<!-- ELSE -->
<dl class="icon {topicrow.TOPIC_IMG_STYLE}">
<dt<!-- IF topicrow.TOPIC_ICON_IMG --> style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF --> title="{topicrow.TOPIC_FOLDER_IMG_ALT}">
- <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a>
- <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.UNAPPROVED_IMG}</a> <!-- ENDIF -->
- <!-- IF topicrow.S_TOPIC_REPORTED --><a href="{topicrow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --><br />
- <!-- IF .topicrow.pagination -->
- <div class="pagination">
- <ul>
- <!-- BEGIN pagination -->
- <!-- IF topicrow.pagination.S_IS_PREV -->
- <!-- ELSEIF topicrow.pagination.S_IS_CURRENT --><li class="active"><span>{topicrow.pagination.PAGE_NUMBER}</span></li>
- <!-- ELSEIF topicrow.pagination.S_IS_ELLIPSIS --><li class="ellipsis"><span>{L_ELLIPSIS}</span></li>
- <!-- ELSEIF topicrow.pagination.S_IS_NEXT -->
- <!-- ELSE --><li><a href="{topicrow.pagination.PAGE_URL}">{topicrow.pagination.PAGE_NUMBER}</a></li>
- <!-- ENDIF -->
- <!-- END pagination -->
- </ul>
+ <div class="list-inner">
+ <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a>
+ <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.UNAPPROVED_IMG}</a> <!-- ENDIF -->
+ <!-- IF topicrow.S_TOPIC_REPORTED --><a href="{topicrow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --><br />
+ <!-- IF .topicrow.pagination -->
+ <div class="pagination">
+ <ul>
+ <!-- BEGIN pagination -->
+ <!-- IF topicrow.pagination.S_IS_PREV -->
+ <!-- ELSEIF topicrow.pagination.S_IS_CURRENT --><li class="active"><span>{topicrow.pagination.PAGE_NUMBER}</span></li>
+ <!-- ELSEIF topicrow.pagination.S_IS_ELLIPSIS --><li class="ellipsis"><span>{L_ELLIPSIS}</span></li>
+ <!-- ELSEIF topicrow.pagination.S_IS_NEXT -->
+ <!-- ELSE --><li><a href="{topicrow.pagination.PAGE_URL}">{topicrow.pagination.PAGE_NUMBER}</a></li>
+ <!-- ENDIF -->
+ <!-- END pagination -->
+ </ul>
+ </div>
+ <!-- ENDIF -->
+ <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->{L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} &raquo; {topicrow.FIRST_POST_TIME}
</div>
- <!-- ENDIF -->
- <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->{L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} &raquo; {topicrow.FIRST_POST_TIME}
</dt>
<dd class="lastpost"><span><dfn>{L_LAST_POST} </dfn>{L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL}
<a href="{topicrow.U_LAST_POST}">{LAST_POST_IMG}</a> <br />{topicrow.LAST_POST_TIME}</span>
diff --git a/phpBB/styles/prosilver/template/ucp_main_drafts.html b/phpBB/styles/prosilver/template/ucp_main_drafts.html
index a99c52cbfc..723186e20c 100644
--- a/phpBB/styles/prosilver/template/ucp_main_drafts.html
+++ b/phpBB/styles/prosilver/template/ucp_main_drafts.html
@@ -24,26 +24,28 @@
<!-- ELSE -->
<!-- IF .draftrow -->
- <ul class="topiclist">
+ <ul class="topiclist missing-column">
<li class="header">
<dl>
- <dt>{L_DRAFT_TITLE}</dt>
+ <dt><div class="list-inner">{L_DRAFT_TITLE}</div></dt>
<dd class="info"><span>{L_SAVE_DATE}</span></dd>
<dd class="mark">{L_MARK}</dd>
</dl>
</li>
</ul>
- <ul class="topiclist cplist">
+ <ul class="topiclist cplist missing-column">
<!-- BEGIN draftrow -->
<li class="row<!-- IF draftrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl>
<dt>
- <a class="topictitle" href="{draftrow.U_VIEW_EDIT}">{draftrow.DRAFT_SUBJECT}</a><br />
- <!-- IF draftrow.S_LINK_TOPIC -->{L_TOPIC}{L_COLON} <a href="{draftrow.U_VIEW}">{draftrow.TITLE}</a>
- <!-- ELSEIF draftrow.S_LINK_FORUM -->{L_FORUM}{L_COLON} <a href="{draftrow.U_VIEW}">{draftrow.TITLE}</a>
- <!-- ELSEIF S_PRIVMSGS -->
- <!-- ELSE -->{L_NO_TOPIC_FORUM}<!-- ENDIF -->
+ <div class="list-inner">
+ <a class="topictitle" href="{draftrow.U_VIEW_EDIT}">{draftrow.DRAFT_SUBJECT}</a><br />
+ <!-- IF draftrow.S_LINK_TOPIC -->{L_TOPIC}{L_COLON} <a href="{draftrow.U_VIEW}">{draftrow.TITLE}</a>
+ <!-- ELSEIF draftrow.S_LINK_FORUM -->{L_FORUM}{L_COLON} <a href="{draftrow.U_VIEW}">{draftrow.TITLE}</a>
+ <!-- ELSEIF S_PRIVMSGS -->
+ <!-- ELSE -->{L_NO_TOPIC_FORUM}<!-- ENDIF -->
+ </div>
</dt>
<dd class="info"><span>{draftrow.DATE}<br /><!-- IF draftrow.U_INSERT --><a href="{draftrow.U_INSERT}">{L_LOAD_DRAFT}</a> &bull; <!-- ENDIF --><a href="{draftrow.U_VIEW_EDIT}">{L_VIEW_EDIT}</a></span></dd>
<dd class="mark"><input type="checkbox" name="d[{draftrow.DRAFT_ID}]" id="d{draftrow.DRAFT_ID}" /></dd>
diff --git a/phpBB/styles/prosilver/template/ucp_main_front.html b/phpBB/styles/prosilver/template/ucp_main_front.html
index b92ca7c8e2..1e26e43772 100644
--- a/phpBB/styles/prosilver/template/ucp_main_front.html
+++ b/phpBB/styles/prosilver/template/ucp_main_front.html
@@ -10,27 +10,29 @@
<!-- IF .topicrow -->
<h3>{L_IMPORTANT_NEWS}</h3>
- <ul class="topiclist cplist">
+ <ul class="topiclist cplist two-long-columns">
<!-- BEGIN topicrow -->
<li class="row<!-- IF topicrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl class="icon {topicrow.TOPIC_IMG_STYLE}">
<dt <!-- IF topicrow.TOPIC_ICON_IMG -->style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF -->>
- <!-- IF topicrow.S_UNREAD --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a><br />
- <!-- IF .topicrow.pagination -->
- <div class="pagination">
- <ul>
- <!-- BEGIN pagination -->
- <!-- IF topicrow.pagination.S_IS_PREV -->
- <!-- ELSEIF topicrow.pagination.S_IS_CURRENT --><li class="active"><span>{topicrow.pagination.PAGE_NUMBER}</span></li>
- <!-- ELSEIF topicrow.pagination.S_IS_ELLIPSIS --><li class="ellipsis"><span>{L_ELLIPSIS}</span></li>
- <!-- ELSEIF topicrow.pagination.S_IS_NEXT -->
- <!-- ELSE --><li><a href="{topicrow.pagination.PAGE_URL}">{topicrow.pagination.PAGE_NUMBER}</a></li>
- <!-- ENDIF -->
- <!-- END pagination -->
- </ul>
+ <div class="list-inner">
+ <!-- IF topicrow.S_UNREAD --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a><br />
+ <!-- IF .topicrow.pagination -->
+ <div class="pagination">
+ <ul>
+ <!-- BEGIN pagination -->
+ <!-- IF topicrow.pagination.S_IS_PREV -->
+ <!-- ELSEIF topicrow.pagination.S_IS_CURRENT --><li class="active"><span>{topicrow.pagination.PAGE_NUMBER}</span></li>
+ <!-- ELSEIF topicrow.pagination.S_IS_ELLIPSIS --><li class="ellipsis"><span>{L_ELLIPSIS}</span></li>
+ <!-- ELSEIF topicrow.pagination.S_IS_NEXT -->
+ <!-- ELSE --><li><a href="{topicrow.pagination.PAGE_URL}">{topicrow.pagination.PAGE_NUMBER}</a></li>
+ <!-- ENDIF -->
+ <!-- END pagination -->
+ </ul>
+ </div>
+ <!-- ENDIF -->
+ <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->{L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} &raquo; {topicrow.FIRST_POST_TIME}
</div>
- <!-- ENDIF -->
- <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->{L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} &raquo; {topicrow.FIRST_POST_TIME}
</dt>
<dd class="lastpost"><span>{L_LAST_POST} {L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL}
<a href="{topicrow.U_LAST_POST}">{LAST_POST_IMG}</a> <br />{topicrow.LAST_POST_TIME}</span>
diff --git a/phpBB/styles/prosilver/template/ucp_main_subscribed.html b/phpBB/styles/prosilver/template/ucp_main_subscribed.html
index 11957aa90d..90fa76cefc 100644..100755
--- a/phpBB/styles/prosilver/template/ucp_main_subscribed.html
+++ b/phpBB/styles/prosilver/template/ucp_main_subscribed.html
@@ -9,21 +9,21 @@
<p>{L_WATCHED_EXPLAIN}</p>
<!-- IF .forumrow -->
- <ul class="topiclist">
+ <ul class="topiclist missing-column">
<li class="header">
<dl class="icon">
- <dt>{L_WATCHED_FORUMS}</dt>
- <dd class="lastpost">{L_LAST_POST}</dd>
+ <dt><div class="list-inner">{L_WATCHED_FORUMS}</div></dt>
+ <dd class="lastpost"><span>{L_LAST_POST}</span></dd>
<dd class="mark">{L_MARK}</dd>
</dl>
</li>
</ul>
- <ul class="topiclist cplist">
+ <ul class="topiclist cplist missing-column">
<!-- BEGIN forumrow -->
<li class="row<!-- IF forumrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl class="icon {forumrow.FORUM_IMG_STYLE}">
- <dt><a href="{forumrow.U_VIEWFORUM}" class="forumtitle">{forumrow.FORUM_NAME}</a><br />{forumrow.FORUM_DESC}</dt>
+ <dt><div class="list-inner"><a href="{forumrow.U_VIEWFORUM}" class="forumtitle">{forumrow.FORUM_NAME}</a><br />{forumrow.FORUM_DESC}</div></dt>
<dd class="lastpost"><!-- IF forumrow.LAST_POST_TIME --><span><dfn>{L_LAST_POST} </dfn>{L_POST_BY_AUTHOR} {forumrow.LAST_POST_AUTHOR_FULL}
<a href="{topicrow.U_LAST_POST}">{LAST_POST_IMG}</a> <br />{forumrow.LAST_POST_TIME}</span>
<!-- ELSE -->{L_NO_POSTS}<br />&nbsp;<!-- ENDIF -->
@@ -34,43 +34,53 @@
<!-- END forumrow -->
</ul>
<!-- ELSEIF S_FORUM_NOTIFY -->
+ <ul class="topiclist">
+ <li class="header">
+ <dl class="icon">
+ <dt>{L_WATCHED_FORUMS}</dt>
+ </dl>
+ </li>
+ </ul>
<p><strong>{L_NO_WATCHED_FORUMS}</strong></p>
<!-- ENDIF -->
+ <br />
<!-- IF .topicrow -->
- <ul class="topiclist">
+ <ul class="topiclist missing-column">
<li class="header">
<dl class="icon">
- <dt>{L_WATCHED_TOPICS}</dt>
- <dd class="lastpost">{L_LAST_POST}</dd>
+ <dt><div class="list-inner">{L_WATCHED_TOPICS}</div></dt>
+ <dd class="lastpost"><span>{L_LAST_POST}</span></dd>
<dd class="mark">{L_MARK}</dd>
</dl>
</li>
</ul>
- <ul class="topiclist cplist">
+ <ul class="topiclist cplist missing-column">
<!-- BEGIN topicrow -->
<li class="row<!-- IF topicrow.S_TOPIC_REPORTED --> reported<!-- ELSEIF topicrow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl class="icon {topicrow.TOPIC_IMG_STYLE}">
<dt<!-- IF topicrow.TOPIC_ICON_IMG --> style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF --> title="{topicrow.TOPIC_FOLDER_IMG_ALT}">
- <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a>
- <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.UNAPPROVED_IMG}</a> <!-- ENDIF -->
- <!-- IF topicrow.S_TOPIC_REPORTED --><a href="{topicrow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --><br />
- <!-- IF .topicrow.pagination -->
- <div class="pagination">
- <ul>
- <!-- BEGIN pagination -->
- <!-- IF topicrow.pagination.S_IS_PREV -->
- <!-- ELSEIF topicrow.pagination.S_IS_CURRENT --><li class="active"><span>{topicrow.pagination.PAGE_NUMBER}</span></li>
- <!-- ELSEIF topicrow.pagination.S_IS_ELLIPSIS --><li class="ellipsis"><span>{L_ELLIPSIS}</span></li>
- <!-- ELSEIF topicrow.pagination.S_IS_NEXT -->
- <!-- ELSE --><li><a href="{topicrow.pagination.PAGE_URL}">{topicrow.pagination.PAGE_NUMBER}</a></li>
- <!-- ENDIF -->
- <!-- END pagination -->
- </ul>
+ <div class="list-inner">
+ <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a>
+ <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.UNAPPROVED_IMG}</a> <!-- ENDIF -->
+ <!-- IF topicrow.S_TOPIC_REPORTED --><a href="{topicrow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --><br />
+ <!-- IF .topicrow.pagination -->
+ <div class="pagination">
+ <ul>
+ <!-- BEGIN pagination -->
+ <!-- IF topicrow.pagination.S_IS_PREV -->
+ <!-- ELSEIF topicrow.pagination.S_IS_CURRENT --><li class="active"><span>{topicrow.pagination.PAGE_NUMBER}</span></li>
+ <!-- ELSEIF topicrow.pagination.S_IS_ELLIPSIS --><li class="ellipsis"><span>{L_ELLIPSIS}</span></li>
+ <!-- ELSEIF topicrow.pagination.S_IS_NEXT -->
+ <!-- ELSE --><li><a href="{topicrow.pagination.PAGE_URL}">{topicrow.pagination.PAGE_NUMBER}</a></li>
+ <!-- ENDIF -->
+ <!-- END pagination -->
+ </ul>
+ </div>
+ <!-- ENDIF -->
+ <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->{L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} &raquo; {topicrow.FIRST_POST_TIME}
</div>
- <!-- ENDIF -->
- <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->{L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} &raquo; {topicrow.FIRST_POST_TIME}
</dt>
<dd class="lastpost"><span><dfn>{L_LAST_POST} </dfn>{L_POST_BY_AUTHOR} {topicrow.LAST_POST_AUTHOR_FULL}
<a href="{topicrow.U_LAST_POST}">{LAST_POST_IMG}</a> <br />{topicrow.LAST_POST_TIME}</span>
@@ -83,14 +93,21 @@
<ul class="linklist">
<li class="rightside pagination">
<!-- IF TOTAL_TOPICS --> {TOTAL_TOPICS} &bull; <!-- ENDIF -->
- <!-- IF .pagination -->
+ <!-- IF .pagination -->
<!-- INCLUDE pagination.html -->
- <!-- ELSE -->
+ <!-- ELSE -->
{PAGE_NUMBER}
<!-- ENDIF -->
</li>
</ul>
<!-- ELSEIF S_TOPIC_NOTIFY -->
+ <ul class="topiclist">
+ <li class="header">
+ <dl class="icon">
+ <dt>{L_WATCHED_TOPICS}</dt>
+ </dl>
+ </li>
+ </ul>
<p><strong>{L_NO_WATCHED_TOPICS}</strong></p>
<!-- ENDIF -->
diff --git a/phpBB/styles/prosilver/template/ucp_notifications.html b/phpBB/styles/prosilver/template/ucp_notifications.html
index a2d558d0ca..6a1d3b8de4 100644
--- a/phpBB/styles/prosilver/template/ucp_notifications.html
+++ b/phpBB/styles/prosilver/template/ucp_notifications.html
@@ -9,45 +9,37 @@
<p>{TITLE_EXPLAIN}</p>
<!-- IF MODE == 'notification_options' -->
- <ul class="topiclist">
- <li class="header">
- <dl>
- <dt>{L_NOTIFICATION_TYPE}</dt>
- <!-- BEGIN notification_methods -->
- <dd class="mark">{notification_methods.NAME}</dd>
- <!-- END notification_methods -->
- <dd class="mark">{L_NOTIFICATIONS}</dd>
- </dl>
- </li>
- </ul>
- <ul class="topiclist cplist">
-
- <!-- BEGIN notification_types -->
- <!-- IF notification_types.GROUP_NAME -->
- <li class="row bg3">
- <dl>
- <dt>
- {notification_types.GROUP_NAME}
- </dt>
- </dl>
- </li>
- <!-- ELSE -->
- <li class="row<!-- IF notification_types.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
- <dl>
- <dt>
+ <table class="table1" cellspacing="1">
+ <thead>
+ <th>{L_NOTIFICATION_TYPE}</th>
+ <!-- BEGIN notification_methods -->
+ <th class="mark">{notification_methods.NAME}</th>
+ <!-- END notification_methods -->
+ <th class="mark">{L_NOTIFICATIONS}</th>
+ </thead>
+ <tbody>
+ <!-- BEGIN notification_types -->
+ <!-- IF notification_types.GROUP_NAME -->
+ <tr class="bg3">
+ <td colspan="{NOTIFICATION_TYPES_COLS}">{notification_types.GROUP_NAME}</td>
+ </tr>
+ <!-- ELSE -->
+ <tr class="<!-- IF notification_types.S_ROW_COUNT is odd -->bg1<!-- ELSE -->bg2<!-- ENDIF -->">
+ <td>
{notification_types.NAME}
<!-- IF notification_types.EXPLAIN --><br />&nbsp; &nbsp;{notification_types.EXPLAIN}<!-- ENDIF -->
- </dt>
+ </td>
<!-- BEGIN notification_methods -->
- <dd class="mark"><input type="checkbox" name="{notification_types.TYPE}_{notification_methods.METHOD}"<!-- IF notification_methods.SUBSCRIBED --> checked="checked"<!-- ENDIF --> /> <dfn>{notification_methods.NAME}</dfn></dd>
+ <td class="mark"><input type="checkbox" name="{notification_types.TYPE}_{notification_methods.METHOD}"<!-- IF notification_methods.SUBSCRIBED --> checked="checked"<!-- ENDIF --> /></td>
<!-- END notification_methods -->
- <dd class="mark"><input type="checkbox" name="{notification_types.TYPE}_notification"<!-- IF notification_types.SUBSCRIBED --> checked="checked"<!-- ENDIF --> /> <dfn>{notification_methods.NAME}</dfn></dd>
- </dl>
- </li>
- <!-- ENDIF -->
- <!-- END notification_types -->
- </ul>
+ <td class="mark"><input type="checkbox" name="{notification_types.TYPE}_notification"<!-- IF notification_types.SUBSCRIBED --> checked="checked"<!-- ENDIF --> /></td>
+ </tr>
+ <!-- ENDIF -->
+ <!-- END notification_types -->
+ </tbody>
+ </table>
<!-- ELSE -->
+ <!-- IF .notification_list -->
<!-- IF .pagination or TOTAL_COUNT -->
<div class="topic-actions">
<div class="pagination">
@@ -63,35 +55,32 @@
<!-- ENDIF -->
<div class="notification_list">
- <ul class="topiclist">
+ <ul class="topiclist two-columns">
<li class="header">
<dl>
- <dt>{L_NOTIFICATIONS}</dt>
+ <dt><div class="list-inner">{L_NOTIFICATIONS}</div></dt>
<dd class="mark">{L_MARK_READ}</dd>
</dl>
</li>
- <!-- IF not .notifications -->
- <li>
- <dl>
- <dt>{L_NO_NOTIFICATIONS}</dt>
- </dl>
- </li>
- <!-- ENDIF -->
+ </ul>
+ <ul class="topiclist cplist two-columns">
<!-- BEGIN notification_list -->
<li class="row<!-- IF notification_list.UNREAD --> bg3<!-- ELSE --><!-- IF notification_list.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF --><!-- ENDIF -->">
<dl>
<dt>
- <!-- IF notification_list.URL --><a href="<!-- IF notification_list.UNREAD -->{notification_list.U_MARK_READ}<!-- ELSE -->{notification_list.URL}<!-- ENDIF -->"><!-- ENDIF -->
- {notification_list.AVATAR}
- <div class="notifications">
- <p class="notifications_title">{notification_list.FORMATTED_TITLE}</p>
- <p class="notifications_time">&raquo; {notification_list.TIME}</p>
+ <div class="list-inner">
+ <!-- IF notification_list.URL --><a href="<!-- IF notification_list.UNREAD -->{notification_list.U_MARK_READ}<!-- ELSE -->{notification_list.URL}<!-- ENDIF -->"><!-- ENDIF -->
+ {notification_list.AVATAR}
+ <div class="notifications">
+ <p class="notifications_title">{notification_list.FORMATTED_TITLE}</p>
+ <p class="notifications_time">&raquo; {notification_list.TIME}</p>
- <!-- IF not notification_list.URL and notification_list.U_MARK_READ -->
- <p><a href="{notification_list.U_MARK_READ}">{L_MARK_READ}</a></p>
- <!-- ENDIF -->
- </div>
- <!-- IF notification_list.URL --></a><!-- ENDIF -->
+ <!-- IF not notification_list.URL and notification_list.U_MARK_READ -->
+ <p><a href="{notification_list.U_MARK_READ}">{L_MARK_READ}</a></p>
+ <!-- ENDIF -->
+ </div>
+ <!-- IF notification_list.URL --></a><!-- ENDIF -->
+ </div>
</dt>
<dd class="mark">&nbsp;<!-- IF notification_list.UNREAD --><input type="checkbox" name="mark[]" value="{notification_list.NOTIFICATION_ID}" /> <dfn>{L_MARK_READ}</dfn><!-- ENDIF -->&nbsp;</dd>
@@ -114,15 +103,19 @@
</div>
<!-- ENDIF -->
+ <!-- ELSE -->
+ <p><strong>{L_NO_NOTIFICATIONS}</strong></p>
+ <!-- ENDIF -->
+
<!-- ENDIF -->
</div>
</div>
-<!-- IF .notifications -->
+<!-- IF .notification_types or .notification_list -->
<fieldset class="display-actions">
<input type="hidden" name="form_time" value="{FORM_TIME}" />
{S_HIDDEN_FIELDS}
- <input type="submit" name="submit" value="{L_MARK_READ}" class="button1" />
+ <input type="submit" name="submit" value="<!-- IF MODE == 'notification_options' -->{L_SUBMIT}<!-- ELSE -->{L_MARK_READ}<!-- ENDIF -->" class="button1" />
<div><a href="#" onclick="$('#ucp input:checkbox').attr('checked', true); return false;">{L_MARK_ALL}</a> &bull; <a href="#" onclick="$('#ucp input:checkbox').attr('checked', false); return false;">{L_UNMARK_ALL}</a></div>
{S_FORM_TOKEN}
</fieldset>
diff --git a/phpBB/styles/prosilver/template/ucp_pm_history.html b/phpBB/styles/prosilver/template/ucp_pm_history.html
index 6abc9b1402..3d886b1c3d 100644
--- a/phpBB/styles/prosilver/template/ucp_pm_history.html
+++ b/phpBB/styles/prosilver/template/ucp_pm_history.html
@@ -24,7 +24,7 @@
<h3><a href="{history_row.U_VIEW_MESSAGE}" <!-- IF history_row.S_CURRENT_MSG -->class="current"<!-- ENDIF -->>{history_row.SUBJECT}</a></h3>
<p class="author">{history_row.MINI_POST_IMG} {L_SENT_AT}{L_COLON} <strong>{history_row.SENT_DATE}</strong><br />
{L_MESSAGE_BY_AUTHOR} {history_row.MESSAGE_AUTHOR_FULL}</p>
- <div class="content">{history_row.MESSAGE}</div>
+ <div class="content"><!-- IF history_row.MESSAGE -->{history_row.MESSAGE}<!-- ELSE --><span class="error">{L_MESSAGE_REMOVED_FROM_OUTBOX}</span><!-- ENDIF --></div>
<div id="message_{history_row.MSG_ID}" style="display: none;">{history_row.DECODED_MESSAGE}</div>
</div>
diff --git a/phpBB/styles/prosilver/template/ucp_pm_viewfolder.html b/phpBB/styles/prosilver/template/ucp_pm_viewfolder.html
index 96668284eb..00b735fae6 100644
--- a/phpBB/styles/prosilver/template/ucp_pm_viewfolder.html
+++ b/phpBB/styles/prosilver/template/ucp_pm_viewfolder.html
@@ -45,20 +45,21 @@
<!-- ENDIF -->
<!-- IF .messagerow -->
- <ul class="topiclist">
+ <ul class="topiclist two-columns">
<li class="header">
<dl>
- <dt>{L_MESSAGE}</dt>
+ <dt><div class="list-inner">{L_MESSAGE}</div></dt>
<dd class="mark">{L_MARK}</dd>
</dl>
</li>
</ul>
- <ul class="topiclist cplist pmlist">
+ <ul class="topiclist cplist pmlist two-columns">
<!-- BEGIN messagerow -->
<li class="row<!-- IF messagerow.S_ROW_COUNT is odd --> bg1<!-- ELSE --> bg2<!-- ENDIF --><!-- IF messagerow.PM_CLASS --> {messagerow.PM_CLASS}<!-- ENDIF -->">
<dl class="icon {messagerow.FOLDER_IMG_STYLE}">
<dt<!-- IF messagerow.PM_ICON_URL and S_PM_ICONS --> style="background-image: url({messagerow.PM_ICON_URL}); background-repeat: no-repeat;"<!-- ENDIF -->>
+ <div class="list-inner">
<!-- IF messagerow.S_PM_DELETED -->
<a href="{messagerow.U_REMOVE_PM}" class="topictitle">{L_DELETE_MESSAGE}</a><br />
@@ -72,6 +73,8 @@
<!-- IF messagerow.S_PM_REPORTED --><a href="{messagerow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --> {messagerow.ATTACH_ICON_IMG}<br />
<!-- IF S_SHOW_RECIPIENTS -->{L_MESSAGE_TO} {messagerow.RECIPIENTS}<!-- ELSE -->{L_MESSAGE_BY_AUTHOR} {messagerow.MESSAGE_AUTHOR_FULL} &raquo; {messagerow.SENT_TIME}<!-- ENDIF -->
+
+ </div>
</dt>
<!-- IF S_SHOW_RECIPIENTS --><dd class="info"><span>{L_SENT_AT}{L_COLON} {messagerow.SENT_TIME}</span></dd><!-- ENDIF -->
<!-- IF S_UNREAD --><dd class="info"><!-- IF messagerow.FOLDER --><a href="{messagerow.U_FOLDER}">{messagerow.FOLDER}</a><!-- ELSE -->{L_UNKNOWN_FOLDER}<!-- ENDIF --></dd><!-- ENDIF -->
diff --git a/phpBB/styles/prosilver/template/ucp_profile_avatar.html b/phpBB/styles/prosilver/template/ucp_profile_avatar.html
index a25c43a588..8157d8c15b 100644
--- a/phpBB/styles/prosilver/template/ucp_profile_avatar.html
+++ b/phpBB/styles/prosilver/template/ucp_profile_avatar.html
@@ -6,14 +6,8 @@
<!-- INCLUDE ucp_avatar_options.html -->
-<fieldset class="submit-buttons">
- {S_HIDDEN_FIELDS}
- <!-- IF S_DISPLAY_GALLERY --><input type="submit" name="display_gallery" value="{L_DISPLAY_GALLERY}" class="button2" />&nbsp; <!-- ENDIF -->
- <!-- IF S_IN_AVATAR_GALLERY --><input type="submit" name="cancel" value="{L_CANCEL}" class="button2" />&nbsp; <!-- ELSE -->
- <input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp; <!-- ENDIF -->
- <input type="submit" name="submit" value="{L_SUBMIT}" class="button1" />
- {S_FORM_TOKEN}
-</fieldset>
+{S_HIDDEN_FIELDS}
+{S_FORM_TOKEN}
</form>
<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/prosilver/template/ucp_profile_profile_info.html b/phpBB/styles/prosilver/template/ucp_profile_profile_info.html
index 03d89e8590..3578c29e8e 100644
--- a/phpBB/styles/prosilver/template/ucp_profile_profile_info.html
+++ b/phpBB/styles/prosilver/template/ucp_profile_profile_info.html
@@ -20,7 +20,7 @@
</dl>
<dl>
<dt><label for="msn">{L_UCP_MSNM}{L_COLON}</label></dt>
- <dd><input type="text" name="msn" id="msn" maxlength="255" value="{MSN}" class="inputbox" /></dd>
+ <dd><input type="email" name="msn" id="msn" maxlength="255" value="{MSN}" class="inputbox" /></dd>
</dl>
<dl>
<dt><label for="yim">{L_UCP_YIM}{L_COLON}</label></dt>
@@ -28,11 +28,11 @@
</dl>
<dl>
<dt><label for="jabber">{L_UCP_JABBER}{L_COLON}</label></dt>
- <dd><input type="text" name="jabber" id="jabber" maxlength="255" value="{JABBER}" class="inputbox" /></dd>
+ <dd><input type="email" name="jabber" id="jabber" maxlength="255" value="{JABBER}" class="inputbox" /></dd>
</dl>
<dl>
<dt><label for="website">{L_WEBSITE}{L_COLON}</label></dt>
- <dd><input type="text" name="website" id="website" maxlength="255" value="{WEBSITE}" class="inputbox" /></dd>
+ <dd><input type="url" name="website" id="website" maxlength="255" value="{WEBSITE}" class="inputbox" /></dd>
</dl>
<dl>
<dt><label for="location">{L_LOCATION}{L_COLON}</label></dt>
@@ -50,8 +50,8 @@
<dl>
<dt><label for="bday_day">{L_BIRTHDAY}{L_COLON}</label><br /><span>{L_BIRTHDAY_EXPLAIN}</span></dt>
<dd>
- <label for="bday_day">{L_DAY}{L_COLON} <select name="bday_day" id="bday_day" style="width: 4em;">{S_BIRTHDAY_DAY_OPTIONS}</select></label>
- <label for="bday_month">{L_MONTH}{L_COLON} <select name="bday_month" id="bday_month" style="width: 4em;">{S_BIRTHDAY_MONTH_OPTIONS}</select></label>
+ <label for="bday_day">{L_DAY}{L_COLON} <select name="bday_day" id="bday_day" style="width: 4em;">{S_BIRTHDAY_DAY_OPTIONS}</select></label>
+ <label for="bday_month">{L_MONTH}{L_COLON} <select name="bday_month" id="bday_month" style="width: 4em;">{S_BIRTHDAY_MONTH_OPTIONS}</select></label>
<label for="bday_year">{L_YEAR}{L_COLON} <select name="bday_year" id="bday_year" style="width: 6em;">{S_BIRTHDAY_YEAR_OPTIONS}</select></label>
</dd>
</dl>
@@ -70,7 +70,7 @@
</div>
<fieldset class="submit-buttons">
- {S_HIDDEN_FIELDS}<input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
+ {S_HIDDEN_FIELDS}<input type="reset" value="{L_RESET}" name="reset" class="button2" />&nbsp;
<input type="submit" name="submit" value="{L_SUBMIT}" class="button1" />
{S_FORM_TOKEN}
</fieldset>
diff --git a/phpBB/styles/prosilver/template/ucp_profile_reg_details.html b/phpBB/styles/prosilver/template/ucp_profile_reg_details.html
index c014e54250..699be4a27e 100644
--- a/phpBB/styles/prosilver/template/ucp_profile_reg_details.html
+++ b/phpBB/styles/prosilver/template/ucp_profile_reg_details.html
@@ -18,7 +18,7 @@
</dl>
<dl>
<dt><label for="email">{L_EMAIL_ADDRESS}{L_COLON}</label></dt>
- <dd><!-- IF S_CHANGE_EMAIL --><input type="text" name="email" id="email" maxlength="100" value="{EMAIL}" class="inputbox" title="{L_EMAIL_ADDRESS}" /><!-- ELSE --><strong>{EMAIL}</strong><!-- ENDIF --></dd>
+ <dd><!-- IF S_CHANGE_EMAIL --><input type="email" name="email" id="email" maxlength="100" value="{EMAIL}" class="inputbox" title="{L_EMAIL_ADDRESS}" /><!-- ELSE --><strong>{EMAIL}</strong><!-- ENDIF --></dd>
</dl>
<!-- IF S_CHANGE_PASSWORD -->
<dl>
diff --git a/phpBB/styles/prosilver/template/ucp_register.html b/phpBB/styles/prosilver/template/ucp_register.html
index db95e5ba13..fc469eff36 100644
--- a/phpBB/styles/prosilver/template/ucp_register.html
+++ b/phpBB/styles/prosilver/template/ucp_register.html
@@ -10,11 +10,6 @@
document.forms['register'].change_lang.value = lang_iso;
document.forms['register'].submit.click();
}
-
- <!-- IF CAPTCHA_TEMPLATE and S_CONFIRM_REFRESH -->
- onload_functions.push(apply_onkeypress_event);
- <!-- ENDIF -->
-
// ]]>
</script>
@@ -36,7 +31,7 @@
</dl>
<dl>
<dt><label for="email">{L_EMAIL_ADDRESS}{L_COLON}</label></dt>
- <dd><input type="text" tabindex="2" name="email" id="email" size="25" maxlength="100" value="{EMAIL}" class="inputbox autowidth" title="{L_EMAIL_ADDRESS}" /></dd>
+ <dd><input type="email" tabindex="2" name="email" id="email" size="25" maxlength="100" value="{EMAIL}" class="inputbox autowidth" title="{L_EMAIL_ADDRESS}" /></dd>
</dl>
<dl>
<dt><label for="new_password">{L_PASSWORD}{L_COLON}</label><br /><span>{L_PASSWORD_EXPLAIN}</span></dt>
diff --git a/phpBB/styles/prosilver/template/ucp_remind.html b/phpBB/styles/prosilver/template/ucp_remind.html
index b957bd4fe4..0ab1251d9e 100644
--- a/phpBB/styles/prosilver/template/ucp_remind.html
+++ b/phpBB/styles/prosilver/template/ucp_remind.html
@@ -15,7 +15,7 @@
</dl>
<dl>
<dt><label for="email">{L_EMAIL_ADDRESS}{L_COLON}</label><br /><span>{L_EMAIL_REMIND}</span></dt>
- <dd><input class="inputbox narrow" type="text" name="email" id="email" size="25" maxlength="100" /></dd>
+ <dd><input class="inputbox narrow" type="email" name="email" id="email" size="25" maxlength="100" /></dd>
</dl>
<dl>
<dt>&nbsp;</dt>
diff --git a/phpBB/styles/prosilver/template/ucp_resend.html b/phpBB/styles/prosilver/template/ucp_resend.html
index 6b1b2d84e2..7713efe521 100644
--- a/phpBB/styles/prosilver/template/ucp_resend.html
+++ b/phpBB/styles/prosilver/template/ucp_resend.html
@@ -16,7 +16,7 @@
</dl>
<dl>
<dt><label for="email">{L_EMAIL_ADDRESS}{L_COLON}</label><br /><span>{L_EMAIL_REMIND}</span></dt>
- <dd><input class="inputbox narrow" type="text" name="email" id="email" size="25" maxlength="100" /></dd>
+ <dd><input class="inputbox narrow" type="email" name="email" id="email" size="25" maxlength="100" /></dd>
</dl>
<dl>
<dt>&nbsp;</dt>
diff --git a/phpBB/styles/prosilver/template/viewforum_body.html b/phpBB/styles/prosilver/template/viewforum_body.html
index 38566dece0..dd16b27988 100644
--- a/phpBB/styles/prosilver/template/viewforum_body.html
+++ b/phpBB/styles/prosilver/template/viewforum_body.html
@@ -47,7 +47,7 @@
<div class="search-box">
<form method="get" id="forum-search" action="{S_SEARCHBOX_ACTION}">
<fieldset>
- <input class="inputbox search tiny" type="text" name="keywords" id="search_keywords" size="20" value="{L_SEARCH_FORUM}" onclick="if (this.value == '{LA_SEARCH_FORUM}') this.value = '';" onblur="if (this.value == '') this.value = '{LA_SEARCH_FORUM}';" />
+ <input class="inputbox search tiny" type="search" name="keywords" id="search_keywords" size="20" placeholder="{L_SEARCH_FORUM}" />
<input class="button2" type="submit" value="{L_SEARCH}" />
{S_SEARCH_LOCAL_HIDDEN_FIELDS}
</fieldset>
@@ -130,7 +130,7 @@
<ul class="topiclist">
<li class="header">
<dl class="icon">
- <dt<!-- IF S_DISPLAY_ACTIVE --> id="active_topics"<!-- ENDIF -->><!-- IF S_DISPLAY_ACTIVE -->{L_ACTIVE_TOPICS}<!-- ELSEIF topicrow.S_TOPIC_TYPE_SWITCH and (topicrow.S_POST_ANNOUNCE or topicrow.S_POST_GLOBAL) -->{L_ANNOUNCEMENTS}<!-- ELSE -->{L_TOPICS}<!-- ENDIF --></dt>
+ <dt<!-- IF S_DISPLAY_ACTIVE --> id="active_topics"<!-- ENDIF -->><div class="list-inner"><!-- IF S_DISPLAY_ACTIVE -->{L_ACTIVE_TOPICS}<!-- ELSEIF topicrow.S_TOPIC_TYPE_SWITCH and (topicrow.S_POST_ANNOUNCE or topicrow.S_POST_GLOBAL) -->{L_ANNOUNCEMENTS}<!-- ELSE -->{L_TOPICS}<!-- ENDIF --></div></dt>
<dd class="posts">{L_REPLIES}</dd>
<dd class="views">{L_VIEWS}</dd>
<dd class="lastpost"><span>{L_LAST_POST}</span></dd>
@@ -142,25 +142,28 @@
<li class="row<!-- IF topicrow.S_ROW_COUNT is even --> bg1<!-- ELSE --> bg2<!-- ENDIF --><!-- IF topicrow.S_POST_GLOBAL --> global-announce<!-- ENDIF --><!-- IF topicrow.S_POST_ANNOUNCE --> announce<!-- ENDIF --><!-- IF topicrow.S_POST_STICKY --> sticky<!-- ENDIF --><!-- IF topicrow.S_TOPIC_REPORTED --> reported<!-- ENDIF -->">
<dl class="icon {topicrow.TOPIC_IMG_STYLE}">
- <dt<!-- IF topicrow.TOPIC_ICON_IMG and S_TOPIC_ICONS --> style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF --> title="{topicrow.TOPIC_FOLDER_IMG_ALT}"><!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a>
- <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.UNAPPROVED_IMG}</a> <!-- ENDIF -->
- <!-- IF topicrow.S_TOPIC_REPORTED --><a href="{topicrow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --><br />
- <!-- IF .topicrow.pagination -->
- <div class="pagination">
- <ul>
- <!-- BEGIN pagination -->
- <!-- IF topicrow.pagination.S_IS_PREV -->
- <!-- ELSEIF topicrow.pagination.S_IS_CURRENT --><li class="active"><span>{topicrow.pagination.PAGE_NUMBER}</span></li>
- <!-- ELSEIF topicrow.pagination.S_IS_ELLIPSIS --><li class="ellipsis"><span>{L_ELLIPSIS}</span></li>
- <!-- ELSEIF topicrow.pagination.S_IS_NEXT -->
- <!-- ELSE --><li><a href="{topicrow.pagination.PAGE_URL}">{topicrow.pagination.PAGE_NUMBER}</a></li>
- <!-- ENDIF -->
- <!-- END pagination -->
- </ul>
+ <dt<!-- IF topicrow.TOPIC_ICON_IMG and S_TOPIC_ICONS --> style="background-image: url({T_ICONS_PATH}{topicrow.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF --> title="{topicrow.TOPIC_FOLDER_IMG_ALT}">
+ <div class="list-inner">
+ <!-- IF topicrow.S_UNREAD_TOPIC --><a href="{topicrow.U_NEWEST_POST}">{NEWEST_POST_IMG}</a> <!-- ENDIF --><a href="{topicrow.U_VIEW_TOPIC}" class="topictitle">{topicrow.TOPIC_TITLE}</a>
+ <!-- IF topicrow.S_TOPIC_UNAPPROVED or topicrow.S_POSTS_UNAPPROVED --><a href="{topicrow.U_MCP_QUEUE}">{topicrow.UNAPPROVED_IMG}</a> <!-- ENDIF -->
+ <!-- IF topicrow.S_TOPIC_REPORTED --><a href="{topicrow.U_MCP_REPORT}">{REPORTED_IMG}</a><!-- ENDIF --><br />
+ <!-- IF .topicrow.pagination -->
+ <div class="pagination">
+ <ul>
+ <!-- BEGIN pagination -->
+ <!-- IF topicrow.pagination.S_IS_PREV -->
+ <!-- ELSEIF topicrow.pagination.S_IS_CURRENT --><li class="active"><span>{topicrow.pagination.PAGE_NUMBER}</span></li>
+ <!-- ELSEIF topicrow.pagination.S_IS_ELLIPSIS --><li class="ellipsis"><span>{L_ELLIPSIS}</span></li>
+ <!-- ELSEIF topicrow.pagination.S_IS_NEXT -->
+ <!-- ELSE --><li><a href="{topicrow.pagination.PAGE_URL}">{topicrow.pagination.PAGE_NUMBER}</a></li>
+ <!-- ENDIF -->
+ <!-- END pagination -->
+ </ul>
+ </div>
+ <!-- ENDIF -->
+ <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->{L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} &raquo; {topicrow.FIRST_POST_TIME}
+ <!-- IF topicrow.S_POST_GLOBAL and FORUM_ID != topicrow.FORUM_ID --> &raquo; {L_IN} <a href="{topicrow.U_VIEW_FORUM}">{topicrow.FORUM_NAME}</a><!-- ENDIF -->
</div>
- <!-- ENDIF -->
- <!-- IF topicrow.ATTACH_ICON_IMG -->{topicrow.ATTACH_ICON_IMG} <!-- ENDIF -->{L_POST_BY_AUTHOR} {topicrow.TOPIC_AUTHOR_FULL} &raquo; {topicrow.FIRST_POST_TIME}
- <!-- IF topicrow.S_POST_GLOBAL and FORUM_ID != topicrow.FORUM_ID --> &raquo; {L_IN} <a href="{topicrow.U_VIEW_FORUM}">{topicrow.FORUM_NAME}</a><!-- ENDIF -->
</dt>
<dd class="posts">{topicrow.REPLIES} <dfn>{L_REPLIES}</dfn></dd>
<dd class="views">{topicrow.VIEWS} <dfn>{L_VIEWS}</dfn></dd>
diff --git a/phpBB/styles/prosilver/template/viewtopic_body.html b/phpBB/styles/prosilver/template/viewtopic_body.html
index c9a6882b6f..5f999ade0c 100644
--- a/phpBB/styles/prosilver/template/viewtopic_body.html
+++ b/phpBB/styles/prosilver/template/viewtopic_body.html
@@ -37,7 +37,7 @@
<div class="search-box">
<form method="get" id="topic-search" action="{S_SEARCHBOX_ACTION}">
<fieldset>
- <input class="inputbox search tiny" type="text" name="keywords" id="search_keywords" size="20" value="{L_SEARCH_TOPIC}" onclick="if(this.value=='{LA_SEARCH_TOPIC}')this.value='';" onblur="if(this.value=='')this.value='{LA_SEARCH_TOPIC}';" />
+ <input class="inputbox search tiny" type="search" name="keywords" id="search_keywords" size="20" placeholder="{L_SEARCH_TOPIC}" />
<input class="button2" type="submit" value="{L_SEARCH}" />
{S_SEARCH_LOCAL_HIDDEN_FIELDS}
</fieldset>
@@ -301,6 +301,7 @@
<!-- ENDIF -->
</div>
+<!-- EVENT viewtopic_body_footer_before -->
<!-- INCLUDE jumpbox.html -->
<!-- IF .quickmod -->
diff --git a/phpBB/styles/prosilver/theme/bidi.css b/phpBB/styles/prosilver/theme/bidi.css
index 5cff0a811b..f617428565 100644
--- a/phpBB/styles/prosilver/theme/bidi.css
+++ b/phpBB/styles/prosilver/theme/bidi.css
@@ -268,8 +268,45 @@
left: 0;
}
-.rtl ul.topiclist dt {
+.rtl ul.topiclist dt, .rtl li.header dt {
float: right;
+ margin-right: 0;
+ margin-left: -410px;
+}
+
+.rtl ul.topiclist.missing-column dt {
+ margin-right: 0;
+ margin-left: -330px;
+}
+
+.rtl ul.topiclist.two-long-columns dt {
+ margin-right: 0;
+ margin-left: -250px;
+}
+
+.rtl ul.topiclist.two-columns dt {
+ margin-right: 0;
+ margin-left: -80px;
+}
+
+.rtl ul.topiclist dt .list-inner {
+ margin-right: 0;
+ margin-left: 410px;
+}
+
+.rtl ul.topiclist.missing-column dt .list-inner {
+ margin-right: 0;
+ margin-left: 330px;
+}
+
+.rtl ul.topiclist.two-long-columns dt .list-inner {
+ margin-right: 0;
+ margin-left: 250px;
+}
+
+.rtl ul.topiclist.two-columns dt .list-inner {
+ margin-right: 0;
+ margin-left: 80px;
}
.rtl ul.topiclist dl {
@@ -308,31 +345,24 @@
background-position: 99.5% 50%;
}
-.rtl li.header dl.icon dt {
+.rtl li.header dl.icon dt .list-inner {
/* Tweak for headers alignment when folder icon used */
padding-right: 0;
padding-left: 50px;
}
.rtl dl.icon dt {
- padding-left: 0;
- padding-right: 45px; /* Space for folder icon */
background-position: 99.5% 95%; /* Position of topic icon */
}
-.rtl dd.lastpost span, .rtl ul.topiclist dd.searchby span, .rtl ul.topiclist dd.info span, .rtl ul.topiclist dd.time span, .rtl dd.redirect span, .rtl dd.moderation span {
+.rtl dl.icon dt .list-inner {
padding-left: 0;
- padding-right: 5px;
-}
-
-.rtl dd.mark {
- float: left !important;
+ padding-right: 45px; /* Space for folder icon */
}
-.rtl ul.topiclist dd.searchextra {
- margin-left: 0;
- margin-right: 5px;
- border-right: none;
+.rtl dd.lastpost span, .rtl ul.topiclist dd.info span, .rtl ul.topiclist dd.time span, .rtl dd.redirect span, .rtl dd.moderation span {
+ padding-left: 0;
+ padding-right: 5px;
}
/* Post body styles
diff --git a/phpBB/styles/prosilver/theme/buttons.css b/phpBB/styles/prosilver/theme/buttons.css
index c3210887b6..09021c771f 100644
--- a/phpBB/styles/prosilver/theme/buttons.css
+++ b/phpBB/styles/prosilver/theme/buttons.css
@@ -97,6 +97,19 @@ a.sendemail {
padding: 1px 0 0 17px;
}
+.icon-notification:before, .icon-notification:after {
+ display: inline;
+ font: inherit;
+}
+
+.icon-notification:before {
+ content: '[';
+}
+
+.icon-notification:after {
+ content: ']';
+}
+
/* Poster profile icons
----------------------------------------*/
ul.profile-icons {
diff --git a/phpBB/styles/prosilver/theme/colours.css b/phpBB/styles/prosilver/theme/colours.css
index baff88d6b7..7d0462be1b 100644
--- a/phpBB/styles/prosilver/theme/colours.css
+++ b/phpBB/styles/prosilver/theme/colours.css
@@ -406,11 +406,6 @@ li.header dt, li.header dd {
color: #FFFFFF;
}
-/* Forum list column styles */
-ul.topiclist dd.searchextra {
- color: #333333;
-}
-
/* Post body styles
----------------------------------------*/
.postbody {
@@ -1000,6 +995,14 @@ fieldset.quick-login input.inputbox {
color: #333333;
}
+.inputbox:-moz-placeholder {
+ color: #333333;
+}
+
+.inputbox::-webkit-input-placeholder {
+ color: #333333;
+}
+
.inputbox:hover {
border-color: #11A3EA;
}
@@ -1009,6 +1012,15 @@ fieldset.quick-login input.inputbox {
color: #0F4987;
}
+.inputbox:focus:-moz-placeholder {
+ color: transparent;
+}
+
+.inputbox:focus::-webkit-input-placeholder {
+ color: transparent;
+}
+
+
/* Form button styles
---------------------------------------- */
diff --git a/phpBB/styles/prosilver/theme/common.css b/phpBB/styles/prosilver/theme/common.css
index 02d891ab6a..26ec23b2e6 100644
--- a/phpBB/styles/prosilver/theme/common.css
+++ b/phpBB/styles/prosilver/theme/common.css
@@ -476,6 +476,8 @@ dl.details dd {
margin-bottom: 5px;
float: left;
width: 65%;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
.clearfix, #tabs, #minitabs, fieldset dl, ul.topiclist dl, dl.polls {
@@ -548,9 +550,9 @@ li.pagination ul {
border: 1px solid transparent;
position: fixed;
display: none;
- top: 40%;
- left: 35%;
- width: 30%;
+ top: 150px;
+ left: 25%;
+ width: 50%;
z-index: 50;
padding: 25px;
padding: 0 25px 20px 25px;
@@ -576,6 +578,20 @@ li.pagination ul {
padding-bottom: 8px;
}
+.phpbb_alert label {
+ display: block;
+ margin: 8px 0;
+ padding-bottom: 8px;
+}
+
+.phpbb_alert div.alert_text > p,
+.phpbb_alert div.alert_text > label,
+.phpbb_alert div.alert_text > select,
+.phpbb_alert div.alert_text > textarea,
+.phpbb_alert div.alert_text > input {
+ font-size: 1.1em;
+}
+
#darkenwrapper {
display: none;
}
diff --git a/phpBB/styles/prosilver/theme/content.css b/phpBB/styles/prosilver/theme/content.css
index b6012f8a63..b6db4c7230 100644
--- a/phpBB/styles/prosilver/theme/content.css
+++ b/phpBB/styles/prosilver/theme/content.css
@@ -25,20 +25,53 @@ ul.topiclist li.row dl {
padding: 2px 0;
}
-ul.topiclist dt {
+ul.topiclist dt, ul.topiclist dd {
display: block;
float: left;
- width: 50%;
+}
+
+ul.topiclist dt {
+ width: 100%;
+ margin-right: -410px;
font-size: 1.1em;
+}
+
+ul.topiclist.missing-column dt {
+ margin-right: -330px;
+}
+
+ul.topiclist.two-long-columns dt {
+ margin-right: -250px;
+}
+
+ul.topiclist.two-columns dt {
+ margin-right: -80px;
+}
+
+ul.topiclist dt .list-inner {
+ margin-right: 410px;
padding-left: 5px;
padding-right: 5px;
}
+ul.topiclist.missing-column dt .list-inner {
+ margin-right: 330px;
+}
+
+ul.topiclist.two-long-columns dt .list-inner {
+ margin-right: 250px;
+}
+
+ul.topiclist.two-columns dt .list-inner {
+ margin-right: 80px;
+}
+
ul.topiclist dd {
- display: block;
- float: left;
border-left: 1px solid transparent;
padding: 4px 0;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
}
ul.topiclist dfn {
@@ -85,17 +118,26 @@ li.header dt, li.header dd {
li.header dt {
font-weight: bold;
+ width: 100%;
+ margin-right: -410px;
+}
+
+li.header dt .list-inner {
+ margin-right: 410px;
}
li.header dd {
- margin-left: 1px;
+ padding-left: 1px;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
}
-li.header dl.icon {
+li.header dl.icon dt, li.header dl.icon dd {
min-height: 0;
}
-li.header dl.icon dt {
+li.header dl.icon dt .list-inner {
/* Tweak for headers alignment when folder icon used */
padding-left: 0;
padding-right: 50px;
@@ -103,19 +145,25 @@ li.header dl.icon dt {
/* Forum list column styles */
dl.icon {
- min-height: 35px;
background-position: 10px 50%; /* Position of folder icon */
background-repeat: no-repeat;
}
dl.icon dt {
- padding-left: 45px; /* Space for folder icon */
background-repeat: no-repeat;
background-position: 5px 95%; /* Position of topic icon */
}
-dd.posts, dd.topics, dd.views {
- width: 8%;
+dl.icon dt .list-inner {
+ padding-left: 45px; /* Space for folder icon */
+}
+
+dl.icon dt, dl.icon dd {
+ min-height: 40px;
+}
+
+dd.posts, dd.topics, dd.views, dd.extra, dd.mark {
+ width: 80px;
text-align: center;
line-height: 2.2em;
font-size: 1.2em;
@@ -133,73 +181,35 @@ dl.icon dt li {
list-style-type: inherit;
}
-dd.lastpost {
- width: 25%;
+dd.lastpost, dd.redirect, dd.moderation, dd.time, dd.info {
+ width: 250px;
font-size: 1.1em;
}
dd.redirect {
- font-size: 1.1em;
line-height: 2.5em;
}
-dd.moderation {
- font-size: 1.1em;
-}
-
-dd.lastpost span, ul.topiclist dd.searchby span, ul.topiclist dd.info span, ul.topiclist dd.time span, dd.redirect span, dd.moderation span {
- display: block;
- padding-left: 5px;
-}
-
dd.time {
- width: auto;
line-height: 200%;
- font-size: 1.1em;
}
-dd.extra {
- width: 12%;
- line-height: 200%;
- text-align: center;
- font-size: 1.1em;
+dd.lastpost span, ul.topiclist dd.info span, ul.topiclist dd.time span, dd.redirect span, dd.moderation span {
+ display: block;
+ padding-left: 5px;
}
-dd.mark {
- float: right !important;
- width: 9%;
- text-align: center;
+dd.extra, dd.mark {
line-height: 200%;
- font-size: 1.2em;
-}
-
-dd.info {
- width: 30%;
}
dd.option {
- width: 15%;
+ width: 125px;
line-height: 200%;
text-align: center;
font-size: 1.1em;
}
-dd.searchby {
- width: 47%;
- font-size: 1.1em;
- line-height: 1em;
-}
-
-ul.topiclist dd.searchextra {
- margin-left: 5px;
- padding: 0.2em 0;
- font-size: 1.1em;
- border-left: none;
- clear: both;
- width: 98%;
- overflow: hidden;
-}
-
/* Container for post/reply buttons and pagination */
.topic-actions {
margin-bottom: 3px;
@@ -669,6 +679,11 @@ fieldset.polls dd div {
margin-left: 8px;
}
+.postprofile dd {
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
.postprofile strong {
font-weight: normal;
}
diff --git a/phpBB/styles/prosilver/theme/forms.css b/phpBB/styles/prosilver/theme/forms.css
index 8829211934..b66544acf7 100644
--- a/phpBB/styles/prosilver/theme/forms.css
+++ b/phpBB/styles/prosilver/theme/forms.css
@@ -286,6 +286,15 @@ textarea.inputbox {
width: auto !important;
}
+input[type="search"] {
+ -webkit-appearance: textfield;
+ -webkit-box-sizing: content-box;
+}
+
+input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-results-button, input[type="search"]::-webkit-search-results-decoration {
+ display: none;
+}
+
/* Form button styles
---------------------------------------- */
input.button1, input.button2 {
diff --git a/phpBB/styles/prosilver/theme/tweaks.css b/phpBB/styles/prosilver/theme/tweaks.css
index cd6865f66f..89510aa32f 100644
--- a/phpBB/styles/prosilver/theme/tweaks.css
+++ b/phpBB/styles/prosilver/theme/tweaks.css
@@ -29,4 +29,21 @@ dl.details dd {
/* Headerbar height fix for IE7 */
#site-description p {
*margin-bottom: 1.0em;
-} \ No newline at end of file
+}
+
+/* Forum list column styles for IE7 */
+dl.icon dt, dl.icon dd {
+ *min-height: 32px;
+}
+
+dd.posts, dd.topics, dd.views, dd.extra, dd.mark {
+ *width: 79px;
+}
+
+dd.lastpost, dd.redirect, dd.moderation, dd.time, dd.info {
+ *width: 249px;
+}
+
+dd.option {
+ *width: 124px;
+}
diff --git a/phpBB/styles/subsilver2/template/avatars.js b/phpBB/styles/subsilver2/template/avatars.js
new file mode 100644
index 0000000000..146aca94d3
--- /dev/null
+++ b/phpBB/styles/subsilver2/template/avatars.js
@@ -0,0 +1,15 @@
+(function($) { // Avoid conflicts with other libraries
+
+"use strict";
+
+function avatarHide() {
+ $('.[class^="avatar_option_"]').hide();
+
+ var selected = $('#avatar_driver').val();
+ $('.avatar_option_' + selected).show();
+}
+
+avatarHide();
+$('#avatar_driver').bind('change', avatarHide);
+
+})(jQuery); // Avoid conflicts with other libraries
diff --git a/phpBB/styles/subsilver2/template/confirm_body.html b/phpBB/styles/subsilver2/template/confirm_body.html
index 7516196b3c..1712017c38 100644
--- a/phpBB/styles/subsilver2/template/confirm_body.html
+++ b/phpBB/styles/subsilver2/template/confirm_body.html
@@ -9,7 +9,7 @@
<th>{MESSAGE_TITLE}</th>
</tr>
<tr>
- <td class="row1" align="center"><br /><p class="gen">{MESSAGE_TEXT}</p><br />{S_HIDDEN_FIELDS}<input type="submit" name="confirm" value="{YES_VALUE}" class="btnmain" />&nbsp;&nbsp;<input type="submit" name="cancel" value="{L_NO}" class="btnlite" /></td>
+ <td class="row1" align="center"><br /><p class="gen">{MESSAGE_TEXT}</p><br />{S_HIDDEN_FIELDS}<input type="submit" name="confirm" value="{YES_VALUE}" class="btnlite" />&nbsp;&nbsp;<input type="submit" name="cancel" value="{L_NO}" class="btnlite" /></td>
</tr>
</table>
diff --git a/phpBB/styles/subsilver2/template/custom_profile_fields.html b/phpBB/styles/subsilver2/template/custom_profile_fields.html
index 2853722064..3dabedda06 100644
--- a/phpBB/styles/subsilver2/template/custom_profile_fields.html
+++ b/phpBB/styles/subsilver2/template/custom_profile_fields.html
@@ -21,7 +21,7 @@
<!-- END bool -->
<!-- BEGIN int -->
- <input type="text" class="post" name="{int.FIELD_IDENT}" size="{int.FIELD_LENGTH}" value="{int.FIELD_VALUE}" />
+ <input type="number" min="{int.FIELD_MINLEN}" max="{int.FIELD_MAXLEN}" class="post" name="{int.FIELD_IDENT}" size="{int.FIELD_LENGTH}" value="{int.FIELD_VALUE}" />
<!-- END int -->
<!-- BEGIN date -->
diff --git a/phpBB/styles/subsilver2/template/editor.js b/phpBB/styles/subsilver2/template/editor.js
index 151cf53ff1..93506b8d4a 100644
--- a/phpBB/styles/subsilver2/template/editor.js
+++ b/phpBB/styles/subsilver2/template/editor.js
@@ -11,18 +11,16 @@ var bbcodeEnabled = true;
// Check for Browser & Platform for PC & IE specific bits
// More details from: http://www.mozilla.org/docs/web-developer/sniffer/browser_type.html
var clientPC = navigator.userAgent.toLowerCase(); // Get client info
-var clientVer = parseInt(navigator.appVersion); // Get browser version
-
-var is_ie = ((clientPC.indexOf('msie') != -1) && (clientPC.indexOf('opera') == -1));
-var is_win = ((clientPC.indexOf('win') != -1) || (clientPC.indexOf('16bit') != -1));
+var clientVer = parseInt(navigator.appVersion, 10); // Get browser version
+var is_ie = ((clientPC.indexOf('msie') !== -1) && (clientPC.indexOf('opera') === -1));
+var is_win = ((clientPC.indexOf('win') !== -1) || (clientPC.indexOf('16bit') !== -1));
var baseHeight;
/**
* Shows the help messages in the helpline window
*/
-function helpline(help)
-{
+function helpline(help) {
document.forms[form_name].helpbox.value = help_line[help];
}
@@ -30,27 +28,22 @@ function helpline(help)
* Fix a bug involving the TextRange object. From
* http://www.frostjedi.com/terra/scripts/demo/caretBug.html
*/
-function initInsertions()
-{
+function initInsertions() {
var doc;
- if (document.forms[form_name])
- {
+ if (document.forms[form_name]) {
doc = document;
- }
- else
- {
+ } else {
doc = opener.document;
}
var textarea = doc.forms[form_name].elements[text_name];
- if (is_ie && typeof(baseHeight) != 'number')
- {
+
+ if (is_ie && typeof(baseHeight) !== 'number') {
textarea.focus();
baseHeight = doc.selection.createRange().duplicate().boundingHeight;
- if (!document.forms[form_name])
- {
+ if (!document.forms[form_name]) {
document.body.focus();
}
}
@@ -59,14 +52,10 @@ function initInsertions()
/**
* bbstyle
*/
-function bbstyle(bbnumber)
-{
- if (bbnumber != -1)
- {
+function bbstyle(bbnumber) {
+ if (bbnumber !== -1) {
bbfontstyle(bbtags[bbnumber], bbtags[bbnumber+1]);
- }
- else
- {
+ } else {
insert_text('[*]');
document.forms[form_name].elements[text_name].focus();
}
@@ -75,36 +64,32 @@ function bbstyle(bbnumber)
/**
* Apply bbcodes
*/
-function bbfontstyle(bbopen, bbclose)
-{
+function bbfontstyle(bbopen, bbclose) {
theSelection = false;
-
+
var textarea = document.forms[form_name].elements[text_name];
textarea.focus();
- if ((clientVer >= 4) && is_ie && is_win)
- {
+ if ((clientVer >= 4) && is_ie && is_win) {
// Get text selection
theSelection = document.selection.createRange().text;
- if (theSelection)
- {
+ if (theSelection) {
// Add tags around selection
document.selection.createRange().text = bbopen + theSelection + bbclose;
document.forms[form_name].elements[text_name].focus();
theSelection = '';
return;
}
- }
- else if (document.forms[form_name].elements[text_name].selectionEnd && (document.forms[form_name].elements[text_name].selectionEnd - document.forms[form_name].elements[text_name].selectionStart > 0))
- {
+ } else if (document.forms[form_name].elements[text_name].selectionEnd
+ && (document.forms[form_name].elements[text_name].selectionEnd - document.forms[form_name].elements[text_name].selectionStart > 0)) {
mozWrap(document.forms[form_name].elements[text_name], bbopen, bbclose);
document.forms[form_name].elements[text_name].focus();
theSelection = '';
return;
}
-
+
//The new position for the cursor after adding the bbcode
var caret_pos = getCaretPosition(textarea).start;
var new_pos = caret_pos + bbopen.length;
@@ -114,14 +99,12 @@ function bbfontstyle(bbopen, bbclose)
// Center the cursor when we don't have a selection
// Gecko and proper browsers
- if (!isNaN(textarea.selectionStart))
- {
+ if (!isNaN(textarea.selectionStart)) {
textarea.selectionStart = new_pos;
textarea.selectionEnd = new_pos;
- }
+ }
// IE
- else if (document.selection)
- {
+ else if (document.selection) {
var range = textarea.createTextRange();
range.move("character", new_pos);
range.select();
@@ -135,62 +118,49 @@ function bbfontstyle(bbopen, bbclose)
/**
* Insert text at position
*/
-function insert_text(text, spaces, popup)
-{
+function insert_text(text, spaces, popup) {
var textarea;
-
- if (!popup)
- {
+
+ if (!popup) {
textarea = document.forms[form_name].elements[text_name];
- }
- else
- {
+ } else {
textarea = opener.document.forms[form_name].elements[text_name];
}
- if (spaces)
- {
+
+ if (spaces) {
text = ' ' + text + ' ';
}
// Since IE9, IE also has textarea.selectionStart, but it still needs to be treated the old way.
// Therefore we simply add a !is_ie here until IE fixes the text-selection completely.
- if (!isNaN(textarea.selectionStart) && !is_ie)
- {
+ if (!isNaN(textarea.selectionStart) && !is_ie) {
var sel_start = textarea.selectionStart;
var sel_end = textarea.selectionEnd;
mozWrap(textarea, text, '');
textarea.selectionStart = sel_start + text.length;
textarea.selectionEnd = sel_end + text.length;
- }
-
- else if (textarea.createTextRange && textarea.caretPos)
- {
- if (baseHeight != textarea.caretPos.boundingHeight)
- {
+ } else if (textarea.createTextRange && textarea.caretPos) {
+ if (baseHeight !== textarea.caretPos.boundingHeight) {
textarea.focus();
storeCaret(textarea);
- }
+ }
+
var caret_pos = textarea.caretPos;
- caret_pos.text = caret_pos.text.charAt(caret_pos.text.length - 1) == ' ' ? caret_pos.text + text + ' ' : caret_pos.text + text;
-
- }
- else
- {
+ caret_pos.text = caret_pos.text.charAt(caret_pos.text.length - 1) === ' ' ? caret_pos.text + text + ' ' : caret_pos.text + text;
+ } else {
textarea.value = textarea.value + text;
}
- if (!popup)
- {
- textarea.focus();
- }
+ if (!popup) {
+ textarea.focus();
+ }
}
/**
* Add inline attachment at position
*/
-function attach_inline(index, filename)
-{
+function attach_inline(index, filename) {
insert_text('[attachment=' + index + ']' + filename + '[/attachment]');
document.forms[form_name].elements[text_name].focus();
}
@@ -198,79 +168,57 @@ function attach_inline(index, filename)
/**
* Add quote text to message
*/
-function addquote(post_id, username, l_wrote)
-{
+function addquote(post_id, username, l_wrote) {
var message_name = 'message_' + post_id;
var theSelection = '';
var divarea = false;
+ var i;
- if (l_wrote === undefined)
- {
+ if (l_wrote === undefined) {
// Backwards compatibility
l_wrote = 'wrote';
}
- if (document.all)
- {
+ if (document.all) {
divarea = document.all[message_name];
- }
- else
- {
+ } else {
divarea = document.getElementById(message_name);
}
// Get text selection - not only the post content :(
// IE9 must use the document.selection method but has the *.getSelection so we just force no IE
- if (window.getSelection && !is_ie && !window.opera)
- {
+ if (window.getSelection && !is_ie && !window.opera) {
theSelection = window.getSelection().toString();
- }
- else if (document.getSelection && !is_ie)
- {
+ } else if (document.getSelection && !is_ie) {
theSelection = document.getSelection();
- }
- else if (document.selection)
- {
+ } else if (document.selection) {
theSelection = document.selection.createRange().text;
}
- if (theSelection == '' || typeof theSelection == 'undefined' || theSelection == null)
- {
- if (divarea.innerHTML)
- {
+ if (theSelection === '' || typeof theSelection === 'undefined' || theSelection === null) {
+ if (divarea.innerHTML) {
theSelection = divarea.innerHTML.replace(/<br>/ig, '\n');
theSelection = theSelection.replace(/<br\/>/ig, '\n');
theSelection = theSelection.replace(/&lt\;/ig, '<');
theSelection = theSelection.replace(/&gt\;/ig, '>');
theSelection = theSelection.replace(/&amp\;/ig, '&');
theSelection = theSelection.replace(/&nbsp\;/ig, ' ');
- }
- else if (document.all)
- {
+ } else if (document.all) {
theSelection = divarea.innerText;
- }
- else if (divarea.textContent)
- {
+ } else if (divarea.textContent) {
theSelection = divarea.textContent;
- }
- else if (divarea.firstChild.nodeValue)
- {
+ } else if (divarea.firstChild.nodeValue) {
theSelection = divarea.firstChild.nodeValue;
}
}
- if (theSelection)
- {
- if (bbcodeEnabled)
- {
+ if (theSelection) {
+ if (bbcodeEnabled) {
insert_text('[quote="' + username + '"]' + theSelection + '[/quote]');
- }
- else
- {
+ } else {
insert_text(username + ' ' + l_wrote + ':' + '\n');
var lines = split_lines(theSelection);
- for (i = 0; i < lines.length; i++)
- {
+ for (i = 0; i < lines.length; i++) {
insert_text('> ' + lines[i] + '\n');
}
}
@@ -279,39 +227,32 @@ function addquote(post_id, username, l_wrote)
return;
}
-
-function split_lines(text)
-{
+function split_lines(text) {
var lines = text.split('\n');
var splitLines = new Array();
var j = 0;
- for(i = 0; i < lines.length; i++)
- {
- if (lines[i].length <= 80)
- {
+ var i;
+
+ for(i = 0; i < lines.length; i++) {
+ if (lines[i].length <= 80) {
splitLines[j] = lines[i];
j++;
- }
- else
- {
+ } else {
var line = lines[i];
- do
- {
- var splitAt = line.indexOf(' ', 80);
-
- if (splitAt == -1)
- {
+ var splitAt;
+ do {
+ splitAt = line.indexOf(' ', 80);
+
+ if (splitAt === -1) {
splitLines[j] = line;
j++;
- }
- else
- {
+ } else {
splitLines[j] = line.substring(0, splitAt);
line = line.substring(splitAt);
j++;
}
}
- while(splitAt != -1);
+ while(splitAt !== -1);
}
}
return splitLines;
@@ -320,15 +261,13 @@ function split_lines(text)
/**
* From http://www.massless.org/mozedit/
*/
-function mozWrap(txtarea, open, close)
-{
- var selLength = (typeof(txtarea.textLength) == 'undefined') ? txtarea.value.length : txtarea.textLength;
+function mozWrap(txtarea, open, close) {
+ var selLength = (typeof(txtarea.textLength) === 'undefined') ? txtarea.value.length : txtarea.textLength;
var selStart = txtarea.selectionStart;
var selEnd = txtarea.selectionEnd;
var scrollTop = txtarea.scrollTop;
- if (selEnd == 1 || selEnd == 2)
- {
+ if (selEnd === 1 || selEnd === 2) {
selEnd = selLength;
}
@@ -349,10 +288,8 @@ function mozWrap(txtarea, open, close)
* Insert at Caret position. Code from
* http://www.faqts.com/knowledge_base/view.phtml/aid/1052/fid/130
*/
-function storeCaret(textEl)
-{
- if (textEl.createTextRange)
- {
+function storeCaret(textEl) {
+ if (textEl.createTextRange) {
textEl.caretPos = document.selection.createRange().duplicate();
}
}
@@ -360,8 +297,7 @@ function storeCaret(textEl)
/**
* Color pallette
*/
-function colorPalette(dir, width, height)
-{
+function colorPalette(dir, width, height) {
var r = 0, g = 0, b = 0;
var numberList = new Array(6);
var color = '';
@@ -374,85 +310,71 @@ function colorPalette(dir, width, height)
document.writeln('<table cellspacing="1" cellpadding="0" border="0">');
- for (r = 0; r < 5; r++)
- {
- if (dir == 'h')
- {
+ for (r = 0; r < 5; r++) {
+ if (dir === 'h') {
document.writeln('<tr>');
}
- for (g = 0; g < 5; g++)
- {
- if (dir == 'v')
- {
+ for (g = 0; g < 5; g++) {
+ if (dir === 'v') {
document.writeln('<tr>');
}
-
- for (b = 0; b < 5; b++)
- {
+
+ for (b = 0; b < 5; b++) {
color = String(numberList[r]) + String(numberList[g]) + String(numberList[b]);
document.write('<td bgcolor="#' + color + '" style="width: ' + width + 'px; height: ' + height + 'px;">');
document.write('<a href="#" onclick="bbfontstyle(\'[color=#' + color + ']\', \'[/color]\'); return false;"><img src="images/spacer.gif" width="' + width + '" height="' + height + '" alt="#' + color + '" title="#' + color + '" /></a>');
document.writeln('</td>');
}
- if (dir == 'v')
- {
+ if (dir === 'v') {
document.writeln('</tr>');
}
}
- if (dir == 'h')
- {
+ if (dir === 'h') {
document.writeln('</tr>');
}
}
document.writeln('</table>');
}
-
/**
* Caret Position object
*/
-function caretPosition()
-{
+function caretPosition() {
var start = null;
var end = null;
}
-
/**
* Get the caret position in an textarea
*/
-function getCaretPosition(txtarea)
-{
+function getCaretPosition(txtarea) {
var caretPos = new caretPosition();
-
+
// simple Gecko/Opera way
- if(txtarea.selectionStart || txtarea.selectionStart == 0)
- {
+ if (txtarea.selectionStart || txtarea.selectionStart === 0) {
caretPos.start = txtarea.selectionStart;
caretPos.end = txtarea.selectionEnd;
}
// dirty and slow IE way
- else if(document.selection)
- {
+ else if (document.selection) {
// get current selection
var range = document.selection.createRange();
// a new selection of the whole textarea
var range_all = document.body.createTextRange();
range_all.moveToElementText(txtarea);
-
+
// calculate selection start point by moving beginning of range_all to beginning of range
var sel_start;
- for (sel_start = 0; range_all.compareEndPoints('StartToStart', range) < 0; sel_start++)
- {
+ for (sel_start = 0; range_all.compareEndPoints('StartToStart', range) < 0; sel_start++) {
range_all.moveStart('character', 1);
}
-
+
txtarea.sel_start = sel_start;
-
+
// we ignore the end value for IE, this is already dirty enough and we don't need it
caretPos.start = txtarea.sel_start;
caretPos.end = txtarea.sel_start;
diff --git a/phpBB/styles/subsilver2/template/login_forum.html b/phpBB/styles/subsilver2/template/login_forum.html
index c9b2c7277e..9a141fc295 100644
--- a/phpBB/styles/subsilver2/template/login_forum.html
+++ b/phpBB/styles/subsilver2/template/login_forum.html
@@ -1,5 +1,13 @@
<!-- INCLUDE overall_header.html -->
+<!-- IF FORUM_NAME -->
+ <div id="pageheader">
+ <h2><a class="titles" href="{U_VIEW_FORUM}">{FORUM_NAME}</a></h2>
+ </div>
+
+ <br clear="all" /><br />
+<!-- ENDIF -->
+
<div id="pagecontent">
<form name="login_forum" method="post" action="{S_LOGIN_ACTION}">
diff --git a/phpBB/styles/subsilver2/template/mcp_jumpbox.html b/phpBB/styles/subsilver2/template/mcp_jumpbox.html
deleted file mode 100644
index e6ef4ecdad..0000000000
--- a/phpBB/styles/subsilver2/template/mcp_jumpbox.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!-- Note: no longer in use... -->
-
-<form name="jumpbox" method="get" action="{S_JUMPBOX_ACTION}">
-
- {HIDDEN_FIELDS_FOR_JUMPBOX}
- <span class="gensmall">{L_JUMP_TO}{L_COLON}</span>&nbsp;<select name="f" onChange="if(this.options[this.selectedIndex].value != -1 && this.options[this.selectedIndex].value != document.jumpbox.current_f.value){ document.forms['jumpbox'].submit() }">
-
-<!-- IF S_ENABLE_SELECT_ALL -->
- <option value="0">{L_ALL_FORUMS}</option>
-<!-- ELSE -->
- <option value="-1">{L_SELECT_FORUM}</option>
-<!-- ENDIF -->
-
-<!-- BEGIN options -->
- <option value="{options.VALUE}"<!-- IF options.VALUE eq -1 --> class="disabled-option"<!-- ENDIF -->{options.SELECTED}/>{options.TEXT}</option>
-<!-- BEGINELSE -->
-<!-- END options -->
-</select>&nbsp;<input type="hidden" name="current_f" value="{S_CURRENT_FORUM}" /><input name="jumpbox" class="btnlite" type="submit" value="{L_GO}" onclick="if(document.jumpbox.f.value == -1){return false;}" />
-</form>
diff --git a/phpBB/styles/subsilver2/template/mcp_topic.html b/phpBB/styles/subsilver2/template/mcp_topic.html
index 431d8d0e6c..014d8b9468 100644
--- a/phpBB/styles/subsilver2/template/mcp_topic.html
+++ b/phpBB/styles/subsilver2/template/mcp_topic.html
@@ -42,7 +42,7 @@
</tr>
<tr>
<td class="row1" nowrap="nowrap"><span class="gen">{L_MERGE_TOPIC_ID}</span></td>
- <td class="row2" colspan="2"><input class="post" type="text" size="6" name="to_topic_id" value="{TO_TOPIC_ID}" /> <a href="{U_SELECT_TOPIC}">{L_SELECT_TOPIC}</a></td>
+ <td class="row2" colspan="2"><input class="post" type="number" min="0" size="6" name="to_topic_id" value="{TO_TOPIC_ID}" /> <a href="{U_SELECT_TOPIC}">{L_SELECT_TOPIC}</a></td>
</tr>
<!-- IF TO_TOPIC_INFO -->
<tr>
@@ -55,7 +55,7 @@
</tr>
<tr>
<td class="row1" nowrap="nowrap"><span class="gen">{L_POSTS_PER_PAGE}</span><br /><span class="gensmall">{L_POSTS_PER_PAGE_EXPLAIN}</span></td>
- <td class="row2" colspan="2"><input class="post" type="text" name="posts_per_page" size="6" value="{POSTS_PER_PAGE}" /></td>
+ <td class="row2" colspan="2"><input class="post" type="number" min="1" name="posts_per_page" size="6" value="{POSTS_PER_PAGE}" /></td>
</tr>
<tr>
<td class="cat" colspan="3" align="center"><span class="gensmall">{L_DISPLAY_POSTS}{L_COLON}</span> {S_SELECT_SORT_DAYS}&nbsp;<span class="gensmall">{L_SORT_BY}</span> {S_SELECT_SORT_KEY} {S_SELECT_SORT_DIR}&nbsp;<input class="btnlite" type="submit" name="sort" value="{L_GO}" /></td>
diff --git a/phpBB/styles/subsilver2/template/memberlist_email.html b/phpBB/styles/subsilver2/template/memberlist_email.html
index 8e535ae80d..88289e53bf 100644
--- a/phpBB/styles/subsilver2/template/memberlist_email.html
+++ b/phpBB/styles/subsilver2/template/memberlist_email.html
@@ -25,7 +25,7 @@
<!-- ELSE -->
<tr>
<td class="row1" width="35%"><b class="genmed">{L_EMAIL_ADDRESS}</b></td>
- <td class="row2"><input class="post" type="text" name="email" size="50" maxlength="100" value="{EMAIL}" /></td>
+ <td class="row2"><input class="post" type="email" name="email" size="50" maxlength="100" value="{EMAIL}" /></td>
</tr>
<tr>
<td class="row1" width="35%"><b class="genmed">{L_REAL_NAME}</b></td>
diff --git a/phpBB/styles/subsilver2/template/memberlist_search.html b/phpBB/styles/subsilver2/template/memberlist_search.html
index c0434d8110..484bbd85e8 100644
--- a/phpBB/styles/subsilver2/template/memberlist_search.html
+++ b/phpBB/styles/subsilver2/template/memberlist_search.html
@@ -35,7 +35,7 @@
{
opener.document.forms['{S_FORM_NAME}'].{S_FIELD_NAME}.value = user;
self.close();
- }
+ }
/**
* Mark/unmark checklist
@@ -51,7 +51,7 @@
}
var rb = parent.getElementsByTagName('input');
-
+
for (var r = 0; r < rb.length; r++)
{
if (rb[r].name.substr(0, name.length) == name)
@@ -82,7 +82,7 @@
<tr>
<!-- IF S_EMAIL_SEARCH_ALLOWED -->
<td class="row1"><b class="genmed">{L_EMAIL}{L_COLON}</b></td>
- <td class="row2"><input class="post" type="text" name="email" value="{EMAIL}" /></td>
+ <td class="row2"><input class="post" type="email" name="email" value="{EMAIL}" /></td>
<!-- ELSE -->
<td colspan="2" class="row1">&nbsp;</td>
<!-- ENDIF -->
@@ -107,7 +107,7 @@
</tr>
<tr>
<td class="row1"><b class="genmed">{L_POSTS}{L_COLON}</b></td>
- <td class="row2"><select name="count_select">{S_COUNT_OPTIONS}</select> <input class="post" type="text" name="count" value="{COUNT}" /></td>
+ <td class="row2"><select name="count_select">{S_COUNT_OPTIONS}</select> <input class="post" type="number" min="0" name="count" value="{COUNT}" /></td>
<td class="row1"><b class="genmed">{L_JABBER}{L_COLON}</b></td>
<td class="row2"><input class="post" type="text" name="jabber" value="{JABBER}" /></td>
</tr>
diff --git a/phpBB/styles/subsilver2/template/posting_body.html b/phpBB/styles/subsilver2/template/posting_body.html
index 39f8f876ba..4feb4e955a 100644
--- a/phpBB/styles/subsilver2/template/posting_body.html
+++ b/phpBB/styles/subsilver2/template/posting_body.html
@@ -322,7 +322,7 @@
<!-- IF S_TOPIC_TYPE_ANNOUNCE or S_TOPIC_TYPE_STICKY -->
<tr>
<td class="row1"><b class="genmed">{L_STICK_TOPIC_FOR}{L_COLON}</b><br /><span class="gensmall">{L_STICKY_ANNOUNCE_TIME_LIMIT}</span></td>
- <td class="row2"><input class="post" type="text" name="topic_time_limit" size="3" maxlength="3" value="{TOPIC_TIME_LIMIT}" />&nbsp;<b class="gen">{L_DAYS}</b> <span class="gensmall">{L_STICK_TOPIC_FOR_EXPLAIN}</span></td>
+ <td class="row2"><input class="post" type="number" min="0" max="999" name="topic_time_limit" size="3" maxlength="3" value="{TOPIC_TIME_LIMIT}" />&nbsp;<b class="gen">{L_DAYS}</b> <span class="gensmall">{L_STICK_TOPIC_FOR_EXPLAIN}</span></td>
</tr>
<!-- ENDIF -->
diff --git a/phpBB/styles/subsilver2/template/posting_poll_body.html b/phpBB/styles/subsilver2/template/posting_poll_body.html
index c41741ac51..67996eaf33 100644
--- a/phpBB/styles/subsilver2/template/posting_poll_body.html
+++ b/phpBB/styles/subsilver2/template/posting_poll_body.html
@@ -15,11 +15,11 @@
</tr>
<tr>
<td class="row1"><b class="genmed">{L_POLL_MAX_OPTIONS}{L_COLON}</b><br /><span class="gensmall">{L_POLL_MAX_OPTIONS_EXPLAIN}</span></td>
- <td class="row2"><input class="post" type="text" name="poll_max_options" size="3" maxlength="3" value="{POLL_MAX_OPTIONS}" /></td>
+ <td class="row2"><input class="post" type="number" min="1" max="999" name="poll_max_options" size="3" maxlength="3" value="{POLL_MAX_OPTIONS}" /></td>
</tr>
<tr>
<td class="row1"><b class="genmed">{L_POLL_FOR}{L_COLON}</b></td>
- <td class="row2"><input class="post" type="text" name="poll_length" size="3" maxlength="3" value="{POLL_LENGTH}" />&nbsp;<b class="gen">{L_DAYS}</b> <span class="gensmall">{L_POLL_FOR_EXPLAIN}</span></td>
+ <td class="row2"><input class="post" type="number" min="0" max="999" name="poll_length" size="3" maxlength="3" value="{POLL_LENGTH}" />&nbsp;<b class="gen">{L_DAYS}</b> <span class="gensmall">{L_POLL_FOR_EXPLAIN}</span></td>
</tr>
<!-- IF S_POLL_VOTE_CHANGE -->
<tr>
diff --git a/phpBB/styles/subsilver2/template/timezone.js b/phpBB/styles/subsilver2/template/timezone.js
index af8206d12d..c5829c0bb1 100644
--- a/phpBB/styles/subsilver2/template/timezone.js
+++ b/phpBB/styles/subsilver2/template/timezone.js
@@ -1,5 +1,7 @@
(function($) { // Avoid conflicts with other libraries
+"use strict";
+
$('#tz_date').change(function() {
phpbb.timezoneSwitchDate(false);
});
@@ -13,7 +15,7 @@ $(document).ready(
);
$(document).ready(
- phpbb.timezonePreselectSelect($('#tz_select_date_suggest').attr('data-is-registration') == 'true')
+ phpbb.timezonePreselectSelect($('#tz_select_date_suggest').attr('timezone-preselect') == 'true')
);
})(jQuery); // Avoid conflicts with other libraries
diff --git a/phpBB/styles/subsilver2/template/timezone_option.html b/phpBB/styles/subsilver2/template/timezone_option.html
index 7fa310b1bc..26ba2388c9 100644
--- a/phpBB/styles/subsilver2/template/timezone_option.html
+++ b/phpBB/styles/subsilver2/template/timezone_option.html
@@ -7,7 +7,7 @@
<option value="">{L_SELECT_CURRENT_TIME}</option>
{S_TZ_DATE_OPTIONS}
</select><br />
- <input type="button" id="tz_select_date_suggest" class="btnlite" style="display: none;" data-is-registration="<!-- IF S_REGISTRATION -->true<!-- ELSE -->false<!-- ENDIF -->" data-l-suggestion="{L_TIMEZONE_DATE_SUGGESTION}" value="{L_TIMEZONE_DATE_SUGGESTION}" />
+ <input type="button" id="tz_select_date_suggest" class="btnlite" style="display: none;" timezone-preselect="<!-- IF S_TZ_PRESELECT -->true<!-- ELSE -->false<!-- ENDIF -->" data-l-suggestion="{L_TIMEZONE_DATE_SUGGESTION}" value="{L_TIMEZONE_DATE_SUGGESTION}" />
</div>
<!-- ENDIF -->
<select name="tz" id="timezone" class="autowidth tz_select">
diff --git a/phpBB/styles/subsilver2/template/ucp_avatar_options_gravatar.html b/phpBB/styles/subsilver2/template/ucp_avatar_options_gravatar.html
new file mode 100644
index 0000000000..b8840e0aab
--- /dev/null
+++ b/phpBB/styles/subsilver2/template/ucp_avatar_options_gravatar.html
@@ -0,0 +1,13 @@
+<table class="tablebg" width="100%" cellspacing="1">
+ <tr>
+ <td class="row1" width="35%"><b class="genmed">{L_GRAVATAR_AVATAR_EMAIL}{L_COLON}</b><br /><span class="gensmall">{L_GRAVATAR_AVATAR_EMAIL_EXPLAIN}</span></td>
+ <td class="row2"><input type="text" name="avatar_gravatar_email" id="avatar_gravatar_email" value="{AVATAR_GRAVATAR_EMAIL}" class="inputbox" /></td>
+ </tr>
+ <tr>
+ <td class="row1" width="35%"><b class="genmed">{L_GRAVATAR_AVATAR_SIZE}{L_COLON}</b><br /><span class="gensmall">{L_GRAVATAR_AVATAR_SIZE_EXPLAIN}</span></td>
+ <td class="row2">
+ <input type="text" name="avatar_gravatar_width" id="avatar_gravatar_width" size="3" value="{AVATAR_GRAVATAR_WIDTH}" class="inputbox autowidth" /> {L_PIXEL} &times;&nbsp;
+ <input type="text" name="avatar_gravatar_height" id="avatar_gravatar_height" size="3" value="{AVATAR_GRAVATAR_HEIGHT}" class="inputbox autowidth" /> {L_PIXEL}
+ </td>
+ </tr>
+</table>
diff --git a/phpBB/styles/subsilver2/template/ucp_avatar_options_local.html b/phpBB/styles/subsilver2/template/ucp_avatar_options_local.html
new file mode 100644
index 0000000000..87e5608fec
--- /dev/null
+++ b/phpBB/styles/subsilver2/template/ucp_avatar_options_local.html
@@ -0,0 +1,39 @@
+<table class="tablebg" width="100%" cellspacing="1">
+ <!-- IF .avatar_local_cats -->
+ <tr>
+ <td class="cat" colspan="2" align="center" valign="middle"><span class="genmed">{L_AVATAR_CATEGORY}{L_COLON} </span><select name="avatar_local_cat" id="category">
+ <option value="">{L_NO_AVATAR_CATEGORY}</option>
+ <!-- BEGIN avatar_local_cats -->
+ <option value="{avatar_local_cats.NAME}"<!-- IF avatar_local_cats.SELECTED --> selected="selected"<!-- ENDIF -->>{avatar_local_cats.NAME}</option>
+ <!-- END avatar_local_cats -->
+ </select>&nbsp; <input class="btnlite" tabindex="0" type="submit" value="{L_GO}" name="avatar_local_go" />
+ </td>
+ </tr>
+ <tr>
+ <td class="row1" colspan="2" align="center">
+ <table cellspacing="1" cellpadding="4" border="0">
+ <!-- BEGIN avatar_local_row -->
+ <tr>
+ <!-- BEGIN avatar_local_col -->
+ <td class="row1" align="center"><img src="{avatar_local_col.avatar_local_col.AVATAR_IMAGE}" alt="{avatar_local_col.avatar_local_col.AVATAR_NAME}" title="{avatar_local_col.avatar_local_col.AVATAR_NAME}" /></td>
+ <!-- END avatar_local_col -->
+ </tr>
+ <tr>
+ <!-- BEGIN avatar_local_option -->
+ <td class="row2" align="center"><input type="radio" class="radio" name="avatar_local_file" value="{avatar_local_col.avatar_local_option.S_OPTIONS_AVATAR}" /></td>
+ <!-- END avatar_local_option -->
+ </tr>
+ <!-- BEGINELSE -->
+ <tr>
+ <td class="row1" colspan="2">{L_NO_AVATAR_CATEGORY}</td>
+ </tr>
+ <!-- END avatar_local_col -->
+ </table>
+ </td>
+ </tr>
+ <!-- ELSE -->
+ <tr>
+ <td class="row1" colspan="2"><strong>{L_NO_AVATARS}</strong></td>
+ </tr>
+ <!-- ENDIF -->
+</table>
diff --git a/phpBB/styles/subsilver2/template/ucp_avatar_options_remote.html b/phpBB/styles/subsilver2/template/ucp_avatar_options_remote.html
new file mode 100644
index 0000000000..50ebb9b93d
--- /dev/null
+++ b/phpBB/styles/subsilver2/template/ucp_avatar_options_remote.html
@@ -0,0 +1,10 @@
+<table class="tablebg" width="100%" cellspacing="1">
+ <tr>
+ <td class="row1" width="35%"><b class="genmed">{L_LINK_REMOTE_AVATAR}{L_COLON} </b><br /><span class="gensmall">{L_LINK_REMOTE_AVATAR_EXPLAIN}</span></td>
+ <td class="row2"><input class="post" type="text" name="avatar_remote_url" size="40" value="{AVATAR_REMOTE_URL}" /></td>
+ </tr>
+ <tr>
+ <td class="row1" width="35%"><b class="genmed">{L_LINK_REMOTE_SIZE}{L_COLON} </b><br /><span class="gensmall">{L_LINK_REMOTE_SIZE_EXPLAIN}</span></td>
+ <td class="row2"><input class="post" type="text" name="avatar_remote_width" size="3" value="{AVATAR_REMOTE_WIDTH}" /> <span class="gen">{L_PIXEL} &times; </span> <input class="post" type="text" name="avatar_remote_height" size="3" value="{AVATAR_REMOTE_HEIGHT}" /> <span class="gen">{L_PIXEL}</span></td>
+ </tr>
+</table>
diff --git a/phpBB/styles/subsilver2/template/ucp_avatar_options_upload.html b/phpBB/styles/subsilver2/template/ucp_avatar_options_upload.html
new file mode 100644
index 0000000000..6b813baeaa
--- /dev/null
+++ b/phpBB/styles/subsilver2/template/ucp_avatar_options_upload.html
@@ -0,0 +1,12 @@
+<table class="tablebg" width="100%" cellspacing="1">
+ <tr>
+ <td class="row1" width="35%"><b class="genmed">{L_UPLOAD_AVATAR_FILE}{L_COLON} </b></td>
+ <td class="row2"><input type="hidden" name="MAX_FILE_SIZE" value="{AVATAR_SIZE}" /><input class="post" type="file" name="avatar_upload_file" /></td>
+ </tr>
+<!-- IF S_UPLOAD_AVATAR_URL -->
+ <tr>
+ <td class="row1" width="35%"><b class="genmed">{L_UPLOAD_AVATAR_URL}{L_COLON} </b><br /><span class="gensmall">{L_UPLOAD_AVATAR_URL_EXPLAIN}</span></td>
+ <td class="row2"><input class="post" type="text" name="avatar_upload_url" size="40" value="" /></td>
+ </tr>
+<!-- ENDIF -->
+</table>
diff --git a/phpBB/styles/subsilver2/template/ucp_groups_manage.html b/phpBB/styles/subsilver2/template/ucp_groups_manage.html
index 12319c9e4e..8064e1e6e9 100644
--- a/phpBB/styles/subsilver2/template/ucp_groups_manage.html
+++ b/phpBB/styles/subsilver2/template/ucp_groups_manage.html
@@ -60,74 +60,43 @@
</tr>
<tr>
<td class="row1" width="35%"><label>{L_CURRENT_IMAGE}{L_COLON}</label><br /><span>{L_AVATAR_EXPLAIN}</span></td>
- <td class="row2">{AVATAR_IMAGE}<br /><br /><input type="checkbox" class="radio" name="delete" />&nbsp;<span>{L_DELETE_AVATAR}</span></td>
+ <td class="row2">{AVATAR_IMAGE}<br /><br /><input type="checkbox" class="radio" name="avatar_delete" />&nbsp;<span>{L_DELETE_AVATAR}</span></td>
</tr>
- <!-- IF not S_IN_AVATAR_GALLERY -->
- <!-- IF S_UPLOAD_AVATAR_FILE -->
- <tr>
- <td class="row1" width="35%"><label for="uploadfile">{L_UPLOAD_AVATAR_FILE}{L_COLON}</label></td>
- <td class="row2"><input type="hidden" name="MAX_FILE_SIZE" value="{AVATAR_MAX_FILESIZE}" /><input type="file" id="uploadfile" name="uploadfile" /></td>
- </tr>
- <!-- ENDIF -->
- <!-- IF S_UPLOAD_AVATAR_URL -->
- <tr>
- <td class="row1" width="35%"><label for="uploadurl">{L_UPLOAD_AVATAR_URL}{L_COLON}</label><br /><span>{L_UPLOAD_AVATAR_URL_EXPLAIN}</span></td>
- <td class="row2"><input name="uploadurl" type="text" id="uploadurl" value="" /></td>
- </tr>
- <!-- ENDIF -->
- <!-- IF S_LINK_AVATAR -->
- <tr>
- <td class="row1" width="35%"><label for="remotelink">{L_LINK_REMOTE_AVATAR}{L_COLON}</label><br /><span>{L_LINK_REMOTE_AVATAR_EXPLAIN}</span></td>
- <td class="row2"><input name="remotelink" type="text" id="remotelink" value="" /></td>
- </tr>
- <tr>
- <td class="row1" width="35%"><label for="width">{L_LINK_REMOTE_SIZE}{L_COLON}</label><br /><span>{L_LINK_REMOTE_SIZE_EXPLAIN}</span></td>
- <td class="row2"><input name="width" type="text" id="width" size="3" value="{AVATAR_WIDTH}" /> <span>px X </span> <input type="text" name="height" size="3" value="{AVATAR_HEIGHT}" /> <span>px</span></td>
- </tr>
- <!-- ENDIF -->
- <!-- IF S_DISPLAY_GALLERY -->
- <tr>
- <td class="row1" width="35%"><label>{L_AVATAR_GALLERY}{L_COLON}</label></td>
- <td class="row2"><input class="btnmain" type="submit" name="display_gallery" value="{L_DISPLAY_GALLERY}" /></td>
- </tr>
- <!-- ENDIF -->
- <!-- ELSE -->
-
- <tr>
- <th colspan="2">{L_AVATAR_GALLERY}</th>
- </tr>
- <tr>
- <td class="row1" width="35%"><label for="category">{L_AVATAR_CATEGORY}{L_COLON}</label></td>
- <td class="row2"><select name="category" id="category">{S_CAT_OPTIONS}</select>&nbsp;<input class="btnmain" type="submit" value="{L_GO}" name="display_gallery" /></td>
- </tr>
- <tr>
- <td class="row1" width="35%">
- <table cellspacing="1">
- <!-- BEGIN avatar_row -->
- <tr>
- <!-- BEGIN avatar_column -->
- <td class="row1" style="text-align: center;"><img src="{avatar_row.avatar_column.AVATAR_IMAGE}" alt="{avatar_row.avatar_column.AVATAR_NAME}" title="{avatar_row.avatar_column.AVATAR_NAME}" /></td>
- <!-- END avatar_column -->
- </tr>
- <tr>
- <!-- BEGIN avatar_option_column -->
- <td class="row2" style="text-align: center;"><input type="radio" class="radio" name="avatar_select" value="{avatar_row.avatar_option_column.S_OPTIONS_AVATAR}" /></td>
- <!-- END avatar_option_column -->
- </tr>
- <!-- END avatar_row -->
- </table>
- </td>
- <td class="row2"><input class="btnmain" type="submit" name="cancel" value="{L_CANCEL}" /></td>
- </tr>
-
- <!-- ENDIF -->
+<!-- IF not S_AVATARS_ENABLED -->
+ <tr>
+ <td class="row3" colspan="2" align="center">{L_AVATAR_FEATURES_DISABLED}</td>
+ </tr>
+<!-- ENDIF -->
+ <tr>
+ <th colspan="2">{L_AVATAR_SELECT}</th>
+ </tr>
+ <tr>
+ <td class="row1" width="35%"><b class="genmed">{L_AVATAR_TYPE}{L_COLON}</b></td>
+ <td class="row2">
+ <select name="avatar_driver" id="avatar_driver">
+ <option value="">{L_NO_AVATAR_CATEGORY}</option>
+ <!-- BEGIN avatar_drivers -->
+ <option value="{avatar_drivers.DRIVER}"<!-- IF avatar_drivers.SELECTED --> selected="selected"<!-- ENDIF -->>{avatar_drivers.L_TITLE}</option>
+ <!-- END avatar_drivers -->
+ </select></td>
+ </tr>
+<!-- BEGIN avatar_drivers -->
+ <tr class="avatar_option_{avatar_drivers.DRIVER}">
+ <td class="row1" width="35%" colspan="2"><noscript><b class="genmed">{avatar_drivers.L_TITLE} </b><br /></noscript>{avatar_drivers.L_EXPLAIN}</span></td>
+ </tr>
+ <tr class="avatar_option_{avatar_drivers.DRIVER}">
+ <td colspan="2" style="padding: 0">{avatar_drivers.OUTPUT}</td>
+ </tr>
+<!-- END avatar_drivers -->
<tr>
- <td class="cat" colspan="2" align="center"><input class="btnlite" type="submit" id="submit" name="update" value="{L_SUBMIT}" />&nbsp;
+ <td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input class="btnlite" type="submit" id="submit" name="update" value="{L_SUBMIT}" />&nbsp;
<input class="btnmain" type="reset" id="reset" name="reset" value="{L_RESET}" /></td>
</tr>
</table>
+<!-- INCLUDEJS template/avatars.js -->
+
<!-- ELSEIF S_LIST -->
<h1>{L_GROUP_MEMBERS}</h1>
diff --git a/phpBB/styles/subsilver2/template/ucp_notifications.html b/phpBB/styles/subsilver2/template/ucp_notifications.html
index 1a1fda4c17..d85584d20e 100644
--- a/phpBB/styles/subsilver2/template/ucp_notifications.html
+++ b/phpBB/styles/subsilver2/template/ucp_notifications.html
@@ -2,145 +2,137 @@
<form id="ucp" method="post" action="{S_UCP_ACTION}"{S_FORM_ENCTYPE}>
-<table width="100%" cellspacing="1">
+<!-- IF MODE == 'notification_options' -->
+ <table width="100%" cellspacing="1">
<tr>
- <th colspan="4">{TITLE}</th>
+ <th colspan="{NOTIFICATION_TYPES_COLS}">{TITLE}</th>
</tr>
<tr>
- <td class="row1" colspan="4" align="center"><span class="genmed">{TITLE_EXPLAIN}</span></td>
+ <td class="row1" colspan="{NOTIFICATION_TYPES_COLS}" align="center"><span class="genmed">{TITLE_EXPLAIN}</span></td>
+ </tr>
+ <tr>
+ <th>{L_NOTIFICATION_TYPE}</th>
+ <th width="10%">{L_NOTIFICATIONS}</th>
+ <!-- BEGIN notification_methods -->
+ <th width="10%">{notification_methods.NAME}</th>
+ <!-- END notification_methods -->
</tr>
- <!-- IF MODE == 'notification_options' -->
- <tr>
- <th>{L_NOTIFICATION_TYPE}</th>
- <th width="10%">{L_NOTIFICATIONS}</th>
- <!-- BEGIN notification_methods -->
- <th width="10%">{notification_methods.NAME}</th>
- <!-- END notification_methods -->
- </tr>
- <!-- BEGIN notification_types -->
- <!-- IF notification_types.GROUP_NAME -->
- <tr>
- <td class="row3" colspan="3">{notification_types.GROUP_NAME}</td>
- </tr>
- <!-- ELSE -->
- <!-- IF notification_types.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
- <td>
- {notification_types.NAME}
- <!-- IF notification_types.EXPLAIN --><br />&nbsp; &nbsp;{notification_types.EXPLAIN}<!-- ENDIF -->
- </td>
- <td align="center"><input type="checkbox" name="{notification_types.TYPE}_notification"<!-- IF notification_types.SUBSCRIBED --> checked="checked"<!-- ENDIF --> /></td>
- <!-- BEGIN notification_methods -->
- <td align="center"><input type="checkbox" name="{notification_types.TYPE}_{notification_methods.METHOD}"<!-- IF notification_methods.SUBSCRIBED --> checked="checked"<!-- ENDIF --> /></td>
- <!-- END notification_methods -->
- </tr>
- <!-- ENDIF -->
- <!-- END notification_types -->
- <tr>
- <td class="cat" colspan="3" align="center">
- <input type="hidden" name="form_time" value="{FORM_TIME}" />
- {S_HIDDEN_FIELDS}
- <input class="btnmain" type="submit" name="submit" value="{L_SUBMIT}" />&nbsp;&nbsp;
- <input class="btnlite" type="reset" value="{L_RESET}" name="reset" />
- {S_FORM_TOKEN}
- </td>
- </tr>
- <!-- ELSE -->
+ <!-- BEGIN notification_types -->
+ <!-- IF notification_types.GROUP_NAME -->
+ <tr>
+ <td class="row3" colspan="{NOTIFICATION_TYPES_COLS}">{notification_types.GROUP_NAME}</td>
+ </tr>
+ <!-- ELSE -->
+ <!-- IF notification_types.S_ROW_COUNT is even --><tr class="row1"><!-- ELSE --><tr class="row2"><!-- ENDIF -->
+ <td>
+ {notification_types.NAME}
+ <!-- IF notification_types.EXPLAIN --><br />&nbsp; &nbsp;{notification_types.EXPLAIN}<!-- ENDIF -->
+ </td>
+ <td align="center"><input type="checkbox" name="{notification_types.TYPE}_notification"<!-- IF notification_types.SUBSCRIBED --> checked="checked"<!-- ENDIF --> /></td>
+ <!-- BEGIN notification_methods -->
+ <td align="center"><input type="checkbox" name="{notification_types.TYPE}_{notification_methods.METHOD}"<!-- IF notification_methods.SUBSCRIBED --> checked="checked"<!-- ENDIF --> /></td>
+ <!-- END notification_methods -->
+ </tr>
+ <!-- ENDIF -->
+ <!-- END notification_types -->
+ <tr>
+ <td class="cat" colspan="{NOTIFICATION_TYPES_COLS}" align="center">
+ <input type="hidden" name="form_time" value="{FORM_TIME}" />
+ {S_HIDDEN_FIELDS}
+ <input class="btnmain" type="submit" name="submit" value="{L_SUBMIT}" />&nbsp;&nbsp;
+ <input class="btnlite" type="reset" value="{L_RESET}" name="reset" />
+ {S_FORM_TOKEN}
+ </td>
+ </tr>
+ </table>
+<!-- ELSE -->
+ <table class="tablebg" width="100%" cellspacing="1" cellpadding="0">
<tr>
- <td>
- <table class="tablebg" width="100%" cellspacing="1" cellpadding="0">
+ <td class="row1">
+ <table border="0" cellspacing="0" cellpadding="0" width="100%">
<tr>
- <td class="row1">
- <table border="0" cellspacing="0" cellpadding="0" width="100%">
- <tr>
- <td align="{S_CONTENT_FLOW_BEGIN}">
- <!-- IF TOTAL_COUNT -->
- <table width="100%" cellspacing="1">
- <tr>
- <td class="nav" valign="middle" nowrap="nowrap">&nbsp;{PAGE_NUMBER}</td>
- <td class="gensmall" nowrap="nowrap" width="100%">&nbsp;[ <b>{TOTAL_COUNT}</b> ]&nbsp;</td>
- </tr>
- </table>
- <!-- ENDIF -->
- </td>
- <td align="{S_CONTENT_FLOW_END}"><!-- INCLUDE pagination.html --></td>
- </tr>
- </table>
+ <td align="{S_CONTENT_FLOW_BEGIN}">
+ <!-- IF TOTAL_COUNT -->
+ <table width="100%" cellspacing="1">
+ <tr>
+ <td class="nav" valign="middle" nowrap="nowrap">&nbsp;{PAGE_NUMBER}</td>
+ <td class="gensmall" nowrap="nowrap" width="100%">&nbsp;[ <b>{TOTAL_COUNT}</b> ]&nbsp;</td>
+ </tr>
+ </table>
+ <!-- ENDIF -->
</td>
+ <td align="{S_CONTENT_FLOW_END}"><!-- INCLUDE pagination.html --></td>
</tr>
</table>
+ </td>
+ </tr>
+ </table>
- <div style="padding: 2px;"></div>
-
- <div class="notification_list">
- <table class="tablebg" width="100%" cellspacing="1">
- <tr>
- <td class="cat" colspan="3">
- <table width="100%" cellspacing="0">
- <tr class="nav">
- <td align="{S_CONTENT_FLOW_END}" valign="middle"><!-- IF U_MARK_ALL --><a href="{U_MARK_ALL}">{L_NOTIFICATIONS_MARK_ALL_READ}</a><!-- ENDIF --></td>
- </tr>
- </table>
- </td>
- </tr>
- <tr>
- <th colspan="2">{L_NOTIFICATIONS}</th>
- <th width="15%">{L_MARK_READ}</th>
- </tr>
- <!-- BEGIN notification_list -->
- <tr class="row<!-- IF notification_list.UNREAD -->3<!-- ELSEIF notification_list.S_ROW_COUNT is even -->1<!-- ELSE -->2<!-- ENDIF -->">
- <!-- IF notification_list.AVATAR -->
- <td width="50px">
- {notification_list.AVATAR}
- </td>
- <td valign="top">
- <!-- ELSE -->
- <td colspan="2" valign="top" height="50px">
- <!-- ENDIF -->
- <span class="gen">
- <!-- IF notification_list.URL --><a href="<!-- IF notification_list.UNREAD -->{notification_list.U_MARK_READ}<!-- ELSE -->{notification_list.URL}<!-- ENDIF -->"><!-- ENDIF -->
- <strong>{notification_list.FORMATTED_TITLE}</strong>
- <!-- IF notification_list.URL --></a><!-- ENDIF --><br />
- &raquo; {notification_list.TIME}
- </span>
- </td>
- <td align="center">
- <!-- IF notification_list.UNREAD --><input type="checkbox" name="mark[]" value="{notification_list.NOTIFICATION_ID}" /><!-- ENDIF -->
- </td>
- </tr>
- <!-- END notification_list -->
- <tr>
- <td class="cat" colspan="3" align="center">
- <input type="hidden" name="form_time" value="{FORM_TIME}" />
- {S_HIDDEN_FIELDS}
- <input class="btnmain" type="submit" name="submit" value="{L_MARK_READ}" />
- {S_FORM_TOKEN}
- </td>
+ <div class="notification_list">
+ <table class="tablebg" width="100%" cellspacing="1">
+ <tr>
+ <td class="cat" colspan="3">
+ <table width="100%" cellspacing="0">
+ <tr class="nav">
+ <td align="{S_CONTENT_FLOW_END}" valign="middle"><!-- IF U_MARK_ALL --><a href="{U_MARK_ALL}">{L_NOTIFICATIONS_MARK_ALL_READ}</a><!-- ENDIF --></td>
</tr>
</table>
- </div>
-
- <div style="padding: 2px;"></div>
+ </td>
+ </tr>
+ <tr>
+ <th colspan="2">{L_NOTIFICATIONS}</th>
+ <th width="15%">{L_MARK_READ}</th>
+ </tr>
+ <!-- BEGIN notification_list -->
+ <tr class="row<!-- IF notification_list.UNREAD -->3<!-- ELSEIF notification_list.S_ROW_COUNT is even -->1<!-- ELSE -->2<!-- ENDIF -->">
+ <!-- IF notification_list.AVATAR -->
+ <td width="50px">
+ {notification_list.AVATAR}
+ </td>
+ <td valign="top">
+ <!-- ELSE -->
+ <td colspan="2" valign="top" height="50px">
+ <!-- ENDIF -->
+ <span class="gen">
+ <!-- IF notification_list.URL --><a href="<!-- IF notification_list.UNREAD -->{notification_list.U_MARK_READ}<!-- ELSE -->{notification_list.URL}<!-- ENDIF -->"><!-- ENDIF -->
+ <strong>{notification_list.FORMATTED_TITLE}</strong>
+ <!-- IF notification_list.URL --></a><!-- ENDIF --><br />
+ &raquo; {notification_list.TIME}
+ </span>
+ </td>
+ <td align="center">
+ <!-- IF notification_list.UNREAD --><input type="checkbox" name="mark[]" value="{notification_list.NOTIFICATION_ID}" /><!-- ENDIF -->
+ </td>
+ </tr>
+ <!-- END notification_list -->
+ <tr>
+ <td class="cat" colspan="3" align="center">
+ <input type="hidden" name="form_time" value="{FORM_TIME}" />
+ {S_HIDDEN_FIELDS}
+ <input class="btnmain" type="submit" name="submit" value="{L_MARK_READ}" />
+ {S_FORM_TOKEN}
+ </td>
+ </tr>
+ </table>
+ </div>
- <!-- IF .pagination -->
- <table class="tablebg" width="100%" cellspacing="1" cellpadding="0">
- <tr>
- <td class="row1">
- <table border="0" cellspacing="0" cellpadding="0" width="100%">
- <tr>
- <td align="{S_CONTENT_FLOW_BEGIN}">
- <!-- INCLUDE pagination.html -->
- </td>
- </tr>
- </table>
- </td>
- </tr>
+ <!-- IF .pagination -->
+ <table class="tablebg" width="100%" cellspacing="1" cellpadding="0">
+ <tr>
+ <td class="row1">
+ <table border="0" cellspacing="0" cellpadding="0" width="100%">
+ <tr>
+ <td align="{S_CONTENT_FLOW_BEGIN}">
+ <!-- INCLUDE pagination.html -->
+ </td>
+ </tr>
</table>
- <!-- ENDIF -->
- </td>
- </tr>
+ </td>
+ </tr>
+ </table>
<!-- ENDIF -->
-</table>
+<!-- ENDIF -->
<!-- IF .notifications -->
<div class="gensmall" style="float: {S_CONTENT_FLOW_END}; padding-top: 2px;"><b><a href="#" onclick="$('#ucp input:checkbox').attr('checked', true); return false;">{L_MARK_ALL}</a> :: <a href="#" onclick="$('#ucp input:checkbox').attr('checked', false); return false;">{L_UNMARK_ALL}</a></b></div>
diff --git a/phpBB/styles/subsilver2/template/ucp_pm_history.html b/phpBB/styles/subsilver2/template/ucp_pm_history.html
index 0cbbf33fbe..4f2b627b50 100644
--- a/phpBB/styles/subsilver2/template/ucp_pm_history.html
+++ b/phpBB/styles/subsilver2/template/ucp_pm_history.html
@@ -37,7 +37,7 @@
<td valign="top">
<table width="100%" cellspacing="0" cellpadding="2">
<tr>
- <td><div class="postbody">{history_row.MESSAGE}</div><div id="message_{history_row.MSG_ID}" style="display: none;">{history_row.DECODED_MESSAGE}</div></td>
+ <td><div class="postbody"><!-- IF history_row.MESSAGE -->{history_row.MESSAGE}<!-- ELSE --><span class="error">{L_MESSAGE_REMOVED_FROM_OUTBOX}</span><!-- ENDIF --></div><div id="message_{history_row.MSG_ID}" style="display: none;">{history_row.DECODED_MESSAGE}</div></td>
</tr>
</table>
</td>
diff --git a/phpBB/styles/subsilver2/template/ucp_profile_avatar.html b/phpBB/styles/subsilver2/template/ucp_profile_avatar.html
index 160f8a2399..697cceabb9 100644
--- a/phpBB/styles/subsilver2/template/ucp_profile_avatar.html
+++ b/phpBB/styles/subsilver2/template/ucp_profile_avatar.html
@@ -9,10 +9,10 @@
<td class="row3" colspan="2" align="center"><span class="gensmall error">{ERROR}</span></td>
</tr>
<!-- ENDIF -->
-<tr>
+<tr>
<td class="row1" width="35%"><b class="genmed">{L_CURRENT_IMAGE}{L_COLON} </b><br /><span class="gensmall">{L_AVATAR_EXPLAIN}</span></td>
<td class="row2" align="center"><br />
- <!-- IF AVATAR -->{AVATAR}<br /><br /><input type="checkbox" class="radio" name="delete" />&nbsp;<span class="gensmall">{L_DELETE_AVATAR}</span>
+ <!-- IF AVATAR -->{AVATAR}<br /><br /><input type="checkbox" class="radio" name="avatar_delete" />&nbsp;<span class="gensmall">{L_DELETE_AVATAR}</span>
<!-- ELSE --><img src="{T_THEME_PATH}/images/no_avatar.gif" alt="" />
<!-- ENDIF --></td>
</tr>
@@ -21,67 +21,33 @@
<td class="row3" colspan="2" align="center">{L_AVATAR_FEATURES_DISABLED}</td>
</tr>
<!-- ENDIF -->
-<!-- IF S_UPLOAD_AVATAR_FILE -->
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_UPLOAD_AVATAR_FILE}{L_COLON} </b></td>
- <td class="row2"><input type="hidden" name="MAX_FILE_SIZE" value="{AVATAR_SIZE}" /><input class="post" type="file" name="uploadfile" /></td>
- </tr>
-<!-- ENDIF -->
-<!-- IF S_UPLOAD_AVATAR_URL -->
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_UPLOAD_AVATAR_URL}{L_COLON} </b><br /><span class="gensmall">{L_UPLOAD_AVATAR_URL_EXPLAIN}</span></td>
- <td class="row2"><input class="post" type="text" name="uploadurl" size="40" value="{AVATAR_URL}" /></td>
- </tr>
-<!-- ENDIF -->
-<!-- IF S_LINK_AVATAR -->
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_LINK_REMOTE_AVATAR}{L_COLON} </b><br /><span class="gensmall">{L_LINK_REMOTE_AVATAR_EXPLAIN}</span></td>
- <td class="row2"><input class="post" type="text" name="remotelink" size="40" value="{AVATAR_REMOTE}" /></td>
- </tr>
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_LINK_REMOTE_SIZE}{L_COLON} </b><br /><span class="gensmall">{L_LINK_REMOTE_SIZE_EXPLAIN}</span></td>
- <td class="row2"><input class="post" type="text" name="width" size="3" value="{AVATAR_WIDTH}" /> <span class="gen">{L_PIXEL} &times; </span> <input class="post" type="text" name="height" size="3" value="{AVATAR_HEIGHT}" /> <span class="gen">{L_PIXEL}</span></td>
- </tr>
-<!-- ENDIF -->
-<!-- IF S_DISPLAY_GALLERY -->
- <tr>
- <td class="row1" width="35%"><b class="genmed">{L_AVATAR_GALLERY}{L_COLON} </b></td>
- <td class="row2"><strong><a href="{U_GALLERY}">{L_DISPLAY_GALLERY}</a></strong></td>
- </tr>
-<!-- ENDIF -->
-
-<!-- IF S_IN_AVATAR_GALLERY -->
- <tr>
- <th colspan="2">{L_AVATAR_GALLERY}</th>
- </tr>
- <tr>
- <td class="cat" colspan="2" align="center" valign="middle"><span class="genmed">{L_AVATAR_CATEGORY}{L_COLON} </span><select name="category">{S_CAT_OPTIONS}</select>&nbsp; <input class="btnlite" tabindex="0" type="submit" value="{L_GO}" name="display_gallery" /></td>
- </tr>
- <tr>
- <td class="row1" colspan="2" align="center">
- <table cellspacing="1" cellpadding="4" border="0">
- <!-- BEGIN avatar_row -->
- <tr>
- <!-- BEGIN avatar_column -->
- <td class="row1" align="center"><img src="{avatar_row.avatar_column.AVATAR_IMAGE}" alt="{avatar_row.avatar_column.AVATAR_NAME}" title="{avatar_row.avatar_column.AVATAR_NAME}" /></td>
- <!-- END avatar_column -->
- </tr>
- <tr>
- <!-- BEGIN avatar_option_column -->
- <td class="row2" align="center"><input type="radio" class="radio" name="avatar_select" value="{avatar_row.avatar_option_column.S_OPTIONS_AVATAR}" /></td>
- <!-- END avatar_option_column -->
- </tr>
- <!-- END avatar_row -->
- </table>
- </td>
+ <tr>
+ <th colspan="2">{L_AVATAR_SELECT}</th>
</tr>
-<!-- ENDIF -->
+ <tr>
+ <td class="row1" width="35%"><b class="genmed">{L_AVATAR_TYPE}{L_COLON}</b></td>
+ <td class="row2">
+ <select name="avatar_driver" id="avatar_driver">
+ <option value="">{L_NO_AVATAR_CATEGORY}</option>
+ <!-- BEGIN avatar_drivers -->
+ <option value="{avatar_drivers.DRIVER}"<!-- IF avatar_drivers.SELECTED --> selected="selected"<!-- ENDIF -->>{avatar_drivers.L_TITLE}</option>
+ <!-- END avatar_drivers -->
+ </select></td>
+ </tr>
+<!-- BEGIN avatar_drivers -->
+ <tr class="avatar_option_{avatar_drivers.DRIVER}">
+ <td class="row1" width="35%" colspan="2"><noscript><b class="genmed">{avatar_drivers.L_TITLE} </b><br /></noscript>{avatar_drivers.L_EXPLAIN}</span></td>
+ </tr>
+ <tr class="avatar_option_{avatar_drivers.DRIVER}">
+ <td colspan="2" style="padding: 0">{avatar_drivers.OUTPUT}</td>
+ </tr>
+<!-- END avatar_drivers -->
-<!-- IF S_DISPLAY_GALLERY or S_IN_AVATAR_GALLERY or S_LINK_AVATAR or S_UPLOAD_AVATAR_URL or S_UPLOAD_AVATAR_FILE or AVATAR -->
<tr>
<td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input class="btnmain" type="submit" name="submit" value="{L_SUBMIT}" />&nbsp;&nbsp;<!-- IF S_IN_AVATAR_GALLERY --><input class="btnlite" type="submit" name="cancel" value="{L_CANCEL}" /><!-- ELSE --><input class="btnlite" type="reset" value="{L_RESET}" name="reset" /><!-- ENDIF --></td>
</tr>
-<!-- ENDIF -->
</table>
+<!-- INCLUDEJS template/avatars.js -->
+
<!-- INCLUDE ucp_footer.html -->
diff --git a/phpBB/styles/subsilver2/template/ucp_profile_profile_info.html b/phpBB/styles/subsilver2/template/ucp_profile_profile_info.html
index 19259aebc8..2df41fa29e 100644
--- a/phpBB/styles/subsilver2/template/ucp_profile_profile_info.html
+++ b/phpBB/styles/subsilver2/template/ucp_profile_profile_info.html
@@ -9,53 +9,53 @@
<td class="row3" colspan="2" align="center"><span class="gensmall error">{ERROR}</span></td>
</tr>
<!-- ENDIF -->
-<tr>
+<tr>
<td class="row1" colspan="2"><span class="gensmall">{L_PROFILE_INFO_NOTICE}</span></td>
</tr>
-<tr>
+<tr>
<td class="row1" width="35%"><b class="genmed">{L_UCP_ICQ}{L_COLON} </b></td>
<td class="row2"><input class="post" type="text" name="icq" size="30" maxlength="15" value="{ICQ}" /></td>
</tr>
-<tr>
+<tr>
<td class="row1" width="35%"><b class="genmed">{L_UCP_AIM}{L_COLON} </b></td>
<td class="row2"><input class="post" type="text" name="aim" size="30" maxlength="255" value="{AIM}" /></td>
</tr>
-<tr>
+<tr>
<td class="row1" width="35%"><b class="genmed">{L_UCP_MSNM}{L_COLON} </b></td>
- <td class="row2"><input class="post" type="text" name="msn" size="30" maxlength="255" value="{MSN}" /></td>
+ <td class="row2"><input class="post" type="email" name="msn" size="30" maxlength="255" value="{MSN}" /></td>
</tr>
-<tr>
+<tr>
<td class="row1" width="35%"><b class="genmed">{L_UCP_YIM}{L_COLON} </b></td>
- <td class="row2"><input class="post" type="text" name="yim" size="30" maxlength="255" value="{YIM}" /></td>
+ <td class="row2"><input class="post" type="email" name="yim" size="30" maxlength="255" value="{YIM}" /></td>
</tr>
-<tr>
+<tr>
<td class="row1" width="35%"><b class="genmed">{L_UCP_JABBER}{L_COLON} </b></td>
<td class="row2"><input class="post" type="text" name="jabber" size="30" maxlength="255" value="{JABBER}" /></td>
</tr>
-<tr>
+<tr>
<td class="row1" width="35%"><b class="genmed">{L_WEBSITE}{L_COLON} </b></td>
- <td class="row2"><input class="post" type="text" name="website" size="30" maxlength="255" value="{WEBSITE}" /></td>
+ <td class="row2"><input class="post" type="url" name="website" size="30" maxlength="255" value="{WEBSITE}" /></td>
</tr>
-<tr>
+<tr>
<td class="row1" width="35%"><b class="genmed">{L_LOCATION}{L_COLON} </b></td>
<td class="row2"><input class="post" type="text" name="location" size="30" maxlength="100" value="{LOCATION}" /></td>
</tr>
-<tr>
+<tr>
<td class="row1" width="35%"><b class="genmed">{L_OCCUPATION}{L_COLON} </b></td>
<td class="row2"><textarea class="post" name="occupation" rows="3" cols="30">{OCCUPATION}</textarea></td>
</tr>
-<tr>
+<tr>
<td class="row1" width="35%"><b class="genmed">{L_INTERESTS}{L_COLON} </b></td>
<td class="row2"><textarea class="post" name="interests" rows="3" cols="30">{INTERESTS}</textarea></td>
</tr>
<!-- IF S_BIRTHDAYS_ENABLED -->
- <tr>
+ <tr>
<td class="row1" width="35%"><b class="genmed">{L_BIRTHDAY}{L_COLON} </b><br /><span class="gensmall">{L_BIRTHDAY_EXPLAIN}</span></td>
<td class="row2"><span class="genmed">{L_DAY}{L_COLON}</span> <select name="bday_day">{S_BIRTHDAY_DAY_OPTIONS}</select> <span class="genmed">{L_MONTH}{L_COLON}</span> <select name="bday_month">{S_BIRTHDAY_MONTH_OPTIONS}</select> <span class="genmed">{L_YEAR}{L_COLON}</span> <select name="bday_year">{S_BIRTHDAY_YEAR_OPTIONS}</select></td>
</tr>
<!-- ENDIF -->
<!-- BEGIN profile_fields -->
- <tr>
+ <tr>
<td class="row1" width="35%">
<b class="genmed">{profile_fields.LANG_NAME}{L_COLON} </b>
<!-- IF profile_fields.S_REQUIRED --><b>*</b><!-- ENDIF -->
diff --git a/phpBB/styles/subsilver2/template/ucp_profile_reg_details.html b/phpBB/styles/subsilver2/template/ucp_profile_reg_details.html
index 5b65fdb8af..6944a62764 100644
--- a/phpBB/styles/subsilver2/template/ucp_profile_reg_details.html
+++ b/phpBB/styles/subsilver2/template/ucp_profile_reg_details.html
@@ -20,7 +20,7 @@
</tr>
<tr>
<td class="row1" width="35%"><b class="genmed">{L_EMAIL_ADDRESS}{L_COLON} </b></td>
- <td class="row2"><!-- IF S_CHANGE_EMAIL --><input type="text" class="post" name="email" size="30" maxlength="100" value="{EMAIL}" /><!-- ELSE --><b class="gen">{EMAIL}</b><!-- ENDIF --></td>
+ <td class="row2"><!-- IF S_CHANGE_EMAIL --><input type="email" class="post" name="email" size="30" maxlength="100" value="{EMAIL}" /><!-- ELSE --><b class="gen">{EMAIL}</b><!-- ENDIF --></td>
</tr>
<!-- IF S_CHANGE_PASSWORD -->
<tr>
diff --git a/phpBB/styles/subsilver2/template/ucp_register.html b/phpBB/styles/subsilver2/template/ucp_register.html
index 01808dfc69..3392c557a2 100644
--- a/phpBB/styles/subsilver2/template/ucp_register.html
+++ b/phpBB/styles/subsilver2/template/ucp_register.html
@@ -39,7 +39,7 @@
</tr>
<tr>
<td class="row1"><b class="genmed">{L_EMAIL_ADDRESS}{L_COLON} </b></td>
- <td class="row2"><input class="post" type="text" name="email" size="25" maxlength="100" value="{EMAIL}" /></td>
+ <td class="row2"><input class="post" type="email" name="email" size="25" maxlength="100" value="{EMAIL}" /></td>
</tr>
<tr>
<td class="row1"><b class="genmed">{L_PASSWORD}{L_COLON} </b><br /><span class="gensmall">{L_PASSWORD_EXPLAIN}</span></td>
diff --git a/phpBB/styles/subsilver2/template/ucp_remind.html b/phpBB/styles/subsilver2/template/ucp_remind.html
index 5151ccfad3..f7fde4b3be 100644
--- a/phpBB/styles/subsilver2/template/ucp_remind.html
+++ b/phpBB/styles/subsilver2/template/ucp_remind.html
@@ -14,7 +14,7 @@
</tr>
<tr>
<td class="row1"><b class="genmed">{L_EMAIL_ADDRESS}{L_COLON} </b><br /><span class="gensmall">{L_EMAIL_REMIND}</span></td>
- <td class="row2"><input type="text" class="post" name="email" size="25" maxlength="100" value="{EMAIL}" /></td>
+ <td class="row2"><input type="email" class="post" name="email" size="25" maxlength="100" value="{EMAIL}" /></td>
</tr>
<tr>
<td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input type="submit" name="submit" value="{L_SUBMIT}" class="btnmain" />&nbsp;&nbsp;<input type="reset" value="{L_RESET}" name="reset" class="btnlite" /></td>
diff --git a/phpBB/styles/subsilver2/template/ucp_resend.html b/phpBB/styles/subsilver2/template/ucp_resend.html
index 7e88f6ede2..62e7e96d6b 100644
--- a/phpBB/styles/subsilver2/template/ucp_resend.html
+++ b/phpBB/styles/subsilver2/template/ucp_resend.html
@@ -14,7 +14,7 @@
</tr>
<tr>
<td class="row1"><b class="genmed">{L_EMAIL_ADDRESS}{L_COLON} </b><br /><span class="gensmall">{L_EMAIL_REMIND}</span></td>
- <td class="row2"><input type="text" class="post" name="email" size="25" maxlength="100" value="{EMAIL}" /></td>
+ <td class="row2"><input type="email" class="post" name="email" size="25" maxlength="100" value="{EMAIL}" /></td>
</tr>
<tr>
<td class="cat" colspan="2" align="center">{S_HIDDEN_FIELDS}<input type="submit" name="submit" value="{L_SUBMIT}" class="btnmain" />&nbsp;&nbsp;<input type="reset" value="{L_RESET}" name="reset" class="btnlite" /></td>
diff --git a/phpBB/styles/subsilver2/template/viewtopic_body.html b/phpBB/styles/subsilver2/template/viewtopic_body.html
index 9e6377022a..b561b99abd 100644
--- a/phpBB/styles/subsilver2/template/viewtopic_body.html
+++ b/phpBB/styles/subsilver2/template/viewtopic_body.html
@@ -328,6 +328,7 @@
<!-- INCLUDE quickreply_editor.html -->
<!-- ENDIF -->
+<!-- EVENT viewtopic_body_footer_before -->
<!-- INCLUDE breadcrumbs.html -->
<!-- IF S_DISPLAY_ONLINE_LIST -->
diff --git a/phpBB/viewtopic.php b/phpBB/viewtopic.php
index bd2c7bea77..59ef7bbc80 100644
--- a/phpBB/viewtopic.php
+++ b/phpBB/viewtopic.php
@@ -1083,7 +1083,7 @@ while ($row = $db->sql_fetchrow($result))
'sig_bbcode_bitfield' => '',
'online' => false,
- 'avatar' => ($user->optionget('viewavatars')) ? get_user_avatar($row['user_avatar'], $row['user_avatar_type'], $row['user_avatar_width'], $row['user_avatar_height']) : '',
+ 'avatar' => ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($row) : '',
'rank_title' => '',
'rank_image' => '',
'rank_image_src' => '',
@@ -1149,7 +1149,7 @@ while ($row = $db->sql_fetchrow($result))
'viewonline' => $row['user_allow_viewonline'],
'allow_pm' => $row['user_allow_pm'],
- 'avatar' => ($user->optionget('viewavatars')) ? get_user_avatar($row['user_avatar'], $row['user_avatar_type'], $row['user_avatar_width'], $row['user_avatar_height']) : '',
+ 'avatar' => ($user->optionget('viewavatars')) ? phpbb_get_user_avatar($row) : '',
'age' => '',
'rank_title' => '',