2 * User-related classes.
4 * @author Alexander Ebert
5 * @copyright 2001-2014 WoltLab GmbH
6 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
12 * @param boolean isQuickLogin
14 WCF
.User
.Login
= Class
.extend({
19 _loginSubmitButton
: null,
28 * password input container
31 _passwordContainer
: null,
40 * cookie input container
43 _useCookiesContainer
: null,
46 * Initializes the user login
48 * @param boolean isQuickLogin
50 init: function(isQuickLogin
) {
51 this._loginSubmitButton
= $('#loginSubmitButton');
52 this._password
= $('#password'),
53 this._passwordContainer
= this._password
.parents('dl');
54 this._useCookies
= $('#useCookies');
55 this._useCookiesContainer
= this._useCookies
.parents('dl');
57 var $loginForm
= $('#loginForm');
58 $loginForm
.find('input[name=action]').change($.proxy(this._change
, this));
61 WCF
.User
.QuickLogin
.init();
66 * Handle toggle between login and register.
70 _change: function(event
) {
71 if ($(event
.currentTarget
).val() === 'register') {
72 this._setState(false, WCF
.Language
.get('wcf.user.button.register'));
75 this._setState(true, WCF
.Language
.get('wcf.user.button.login'));
82 * @param boolean enable
83 * @param string buttonTitle
85 _setState: function(enable
, buttonTitle
) {
87 this._password
.enable();
88 this._passwordContainer
.removeClass('disabled');
89 this._useCookies
.enable();
90 this._useCookiesContainer
.removeClass('disabled');
93 this._password
.disable();
94 this._passwordContainer
.addClass('disabled');
95 this._useCookies
.disable();
96 this._useCookiesContainer
.addClass('disabled');
99 this._loginSubmitButton
.val(buttonTitle
);
106 WCF
.User
.QuickLogin
= {
114 * login message container
120 * Initializes the quick login box
123 $('.loginLink').click($.proxy(this._render
, this));
125 // prepend protocol and hostname
126 $('#loginForm input[name=url]').val(function(index
, value
) {
127 return window
.location
.protocol
+ '//' + window
.location
.host
+ value
;
132 * Displays the quick login box with a info message
134 * @param string message
136 show: function(message
) {
138 if (this._loginMessage
=== null) {
139 this._loginMessage
= $('<p class="info" />').hide().prependTo($('#loginForm > form'));
142 this._loginMessage
.show().text(message
);
144 else if (this._loginMessage
!== null) {
145 this._loginMessage
.hide();
154 * @param jQuery.Event event
156 _render: function(event
) {
157 if (event
!== undefined) {
158 event
.preventDefault();
161 if (this._dialog
=== null) {
162 this._dialog
= $('#loginForm').wcfDialog({
163 title
: WCF
.Language
.get('wcf.user.login')
165 this._dialog
.find('#username').focus();
168 this._dialog
.wcfDialog('open');
174 * UserProfile namespace
176 WCF
.User
.Profile
= {};
179 * Shows the activity point list for users.
181 WCF
.User
.Profile
.ActivityPointList
= {
183 * list of cached templates
195 * initialization state
202 * @var WCF.Action.Proxy
207 * Initializes the WCF.User.Profile.ActivityPointList class.
216 this._proxy
= new WCF
.Action
.Proxy({
217 success
: $.proxy(this._success
, this)
222 WCF
.DOMNodeInsertedHandler
.addCallback('WCF.User.Profile.ActivityPointList', $.proxy(this._init
, this));
224 this._didInit
= true;
228 * Initializes display for activity points.
231 $('.activityPointsDisplay').removeClass('activityPointsDisplay').click($.proxy(this._click
, this));
235 * Shows or loads the activity point for selected user.
237 * @param object event
239 _click: function(event
) {
240 var $userID
= $(event
.currentTarget
).data('userID');
242 if (this._cache
[$userID
] === undefined) {
243 this._proxy
.setOption('data', {
244 actionName
: 'getDetailedActivityPointList',
245 className
: 'wcf\\data\\user\\UserProfileAction',
246 objectIDs
: [ $userID
]
248 this._proxy
.sendRequest();
256 * Displays activity points for given user.
258 * @param integer userID
260 _show: function(userID
) {
261 if (this._dialog
=== null) {
262 this._dialog
= $('<div>' + this._cache
[userID
] + '</div>').hide().appendTo(document
.body
);
263 this._dialog
.wcfDialog({
264 title
: WCF
.Language
.get('wcf.user.activityPoint')
268 this._dialog
.html(this._cache
[userID
]);
269 this._dialog
.wcfDialog('open');
274 * Handles successful AJAX requests.
277 * @param string textStatus
278 * @param jQuery jqXHR
280 _success: function(data
, textStatus
, jqXHR
) {
281 this._cache
[data
.returnValues
.userID
] = data
.returnValues
.template
;
282 this._show(data
.returnValues
.userID
);
287 * Provides methods to follow an user.
289 * @param integer userID
290 * @param boolean following
292 WCF
.User
.Profile
.Follow
= Class
.extend({
300 * true if following current user
306 * action proxy object
307 * @var WCF.Action.Proxy
318 * Creates a new follow object.
320 * @param integer userID
321 * @param boolean following
323 init: function (userID
, following
) {
324 this._following
= following
;
325 this._userID
= userID
;
326 this._proxy
= new WCF
.Action
.Proxy({
327 success
: $.proxy(this._success
, this)
330 this._createButton();
335 * Creates the (un-)follow button
337 _createButton: function () {
338 this._button
= $('<li id="followUser"><a class="button jsTooltip" title="'+WCF
.Language
.get('wcf.user.button.'+(this._following
? 'un' : '')+'follow')+'"><span class="icon icon16 icon-plus"></span> <span class="invisible">'+WCF
.Language
.get('wcf.user.button.'+(this._following
? 'un' : '')+'follow')+'</span></a></li>').prependTo($('#profileButtonContainer'));
339 this._button
.click($.proxy(this._execute
, this));
343 * Follows or unfollows an user.
345 _execute: function () {
346 var $actionName
= (this._following
) ? 'unfollow' : 'follow';
347 this._proxy
.setOption('data', {
348 'actionName': $actionName
,
349 'className': 'wcf\\data\\user\\follow\\UserFollowAction',
356 this._proxy
.sendRequest();
360 * Displays current follow state.
362 _showButton: function () {
363 if (this._following
) {
364 this._button
.find('.button').data('tooltip', WCF
.Language
.get('wcf.user.button.unfollow')).addClass('active').children('.icon').removeClass('icon-plus').addClass('icon-minus');
367 this._button
.find('.button').data('tooltip', WCF
.Language
.get('wcf.user.button.follow')).removeClass('active').children('.icon').removeClass('icon-minus').addClass('icon-plus');
372 * Update object state on success.
375 * @param string textStatus
376 * @param jQuery jqXHR
378 _success: function (data
, textStatus
, jqXHR
) {
379 this._following
= data
.returnValues
.following
;
382 var $notification
= new WCF
.System
.Notification();
383 $notification
.show();
388 * Provides methods to manage ignored users.
390 * @param integer userID
391 * @param boolean isIgnoredUser
393 WCF
.User
.Profile
.IgnoreUser
= Class
.extend({
404 _isIgnoredUser
: false,
408 * @var WCF.Action.Proxy
419 * Initializes methods to manage an ignored user.
421 * @param integer userID
422 * @param boolean isIgnoredUser
424 init: function(userID
, isIgnoredUser
) {
425 this._userID
= userID
;
426 this._isIgnoredUser
= isIgnoredUser
;
429 this._proxy
= new WCF
.Action
.Proxy({
430 success
: $.proxy(this._success
, this)
434 this._updateButton();
435 this._button
.click($.proxy(this._click
, this));
439 * Handle clicks, might cause 'ignore' or 'unignore' to be triggered.
442 var $action
= (this._isIgnoredUser
) ? 'unignore' : 'ignore';
444 this._proxy
.setOption('data', {
446 className
: 'wcf\\data\\user\\ignore\\UserIgnoreAction',
449 ignoreUserID
: this._userID
454 this._proxy
.sendRequest();
458 * Updates button label and function upon successful request.
461 * @param string textStatus
462 * @param jQuery jqXHR
464 _success: function(data
, textStatus
, jqXHR
) {
465 this._isIgnoredUser
= data
.returnValues
.isIgnoredUser
;
466 this._updateButton();
468 var $notification
= new WCF
.System
.Notification();
469 $notification
.show();
473 * Updates button label and inserts it if not exists.
475 _updateButton: function() {
476 if (this._button
=== null) {
477 this._button
= $('<li id="ignoreUser"><a class="button jsTooltip" title="'+WCF
.Language
.get('wcf.user.button.'+(this._isIgnoredUser
? 'un' : '')+'ignore')+'"><span class="icon icon16 icon-ban-circle"></span> <span class="invisible">'+WCF
.Language
.get('wcf.user.button.'+(this._isIgnoredUser
? 'un' : '')+'ignore')+'</span></a></li>').prependTo($('#profileButtonContainer'));
480 this._button
.find('.button').data('tooltip', WCF
.Language
.get('wcf.user.button.' + (this._isIgnoredUser
? 'un' : '') + 'ignore'));
481 if (this._isIgnoredUser
) this._button
.find('.button').addClass('active').children('.icon').removeClass('icon-ban-circle').addClass('icon-circle-blank');
482 else this._button
.find('.button').removeClass('active').children('.icon').removeClass('icon-circle-blank').addClass('icon-ban-circle');
487 * Provides methods to load tab menu content upon request.
489 WCF
.User
.Profile
.TabMenu
= Class
.extend({
500 _profileContent
: null,
504 * @var WCF.Action.Proxy
515 * Initializes the tab menu loader.
517 * @param integer userID
519 init: function(userID
) {
520 this._profileContent
= $('#profileContent');
521 this._userID
= userID
;
523 var $activeMenuItem
= this._profileContent
.data('active');
524 var $enableProxy
= false;
526 // fetch content state
527 this._profileContent
.find('div.tabMenuContent').each($.proxy(function(index
, container
) {
528 var $containerID
= $(container
).wcfIdentify();
530 if ($activeMenuItem
=== $containerID
) {
531 this._hasContent
[$containerID
] = true;
534 this._hasContent
[$containerID
] = false;
539 // enable loader if at least one container is empty
541 this._proxy
= new WCF
.Action
.Proxy({
542 success
: $.proxy(this._success
, this)
545 this._profileContent
.bind('wcftabsbeforeactivate', $.proxy(this._loadContent
, this));
550 * Prepares to load content once tabs are being switched.
552 * @param object event
555 _loadContent: function(event
, ui
) {
556 var $panel
= $(ui
.newPanel
);
557 var $containerID
= $panel
.attr('id');
559 if (!this._hasContent
[$containerID
]) {
560 this._proxy
.setOption('data', {
561 actionName
: 'getContent',
562 className
: 'wcf\\data\\user\\profile\\menu\\item\\UserProfileMenuItemAction',
565 containerID
: $containerID
,
566 menuItem
: $panel
.data('menuItem'),
571 this._proxy
.sendRequest();
576 * Shows previously requested content.
579 * @param string textStatus
580 * @param jQuery jqXHR
582 _success: function(data
, textStatus
, jqXHR
) {
583 var $containerID
= data
.returnValues
.containerID
;
584 this._hasContent
[$containerID
] = true;
587 var $content
= this._profileContent
.find('#' + $containerID
);
588 $('<div>' + data
.returnValues
.template
+ '</div>').hide().appendTo($content
);
591 $content
.children('div').wcfBlindIn();
596 * User profile inline editor.
598 * @param integer userID
599 * @param boolean editOnInit
601 WCF
.User
.Profile
.Editor
= Class
.extend({
609 * list of interface buttons
622 * @var WCF.Action.Proxy
639 * Initializes the WCF.User.Profile.Editor object.
641 * @param integer userID
642 * @param boolean editOnInit
644 init: function(userID
, editOnInit
) {
645 this._actionName
= '';
646 this._cachedTemplate
= '';
647 this._tab
= $('#about');
648 this._userID
= userID
;
649 this._proxy
= new WCF
.Action
.Proxy({
650 success
: $.proxy(this._success
, this)
655 // begin editing on page load
662 * Initializes interface buttons.
664 _initButtons: function() {
665 var $buttonContainer
= $('#profileButtonContainer');
669 beginEdit
: $('<li><a class="button"><span class="icon icon16 icon-pencil" /> <span>' + WCF
.Language
.get('wcf.user.editProfile') + '</span></a></li>').click($.proxy(this._beginEdit
, this)).appendTo($buttonContainer
)
676 _beginEdit: function() {
677 this._actionName
= 'beginEdit';
678 this._buttons
.beginEdit
.hide();
679 $('#profileContent').wcfTabs('select', 'about');
682 this._proxy
.setOption('data', {
683 actionName
: 'beginEdit',
684 className
: 'wcf\\data\\user\\UserProfileAction',
685 objectIDs
: [ this._userID
]
687 this._proxy
.sendRequest();
691 * Saves input values.
694 this._actionName
= 'save';
697 var $regExp
= /values\[([a-zA-Z0-9._-]+)\]/;
699 this._tab
.find('input, textarea, select').each(function(index
, element
) {
700 var $element
= $(element
);
702 if ($element
.getTagName() === 'input') {
703 var $type
= $element
.attr('type');
705 if (($type
=== 'radio' || $type
=== 'checkbox') && !$element
.prop('checked')) {
710 var $name
= $element
.attr('name');
711 if ($regExp
.test($name
)) {
712 $values
[RegExp
.$1] = $element
.val();
716 this._proxy
.setOption('data', {
718 className
: 'wcf\\data\\user\\UserProfileAction',
719 objectIDs
: [ this._userID
],
724 this._proxy
.sendRequest();
728 * Restores back to default view.
730 _restore: function() {
731 this._actionName
= 'restore';
732 this._buttons
.beginEdit
.show();
734 this._destroyCKEditor();
736 this._tab
.html(this._cachedTemplate
).children().css({ height
: 'auto' });
740 * Handles successful AJAX requests.
743 * @param string textStatus
744 * @param jQuery jqXHR
746 _success: function(data
, textStatus
, jqXHR
) {
747 switch (this._actionName
) {
749 this._prepareEdit(data
);
753 // save was successful, show parsed template
754 if (data
.returnValues
.success
) {
755 this._cachedTemplate
= data
.returnValues
.template
;
759 this._prepareEdit(data
, true);
766 * Prepares editing mode.
769 * @param boolean disableCache
771 _prepareEdit: function(data
, disableCache
) {
772 this._destroyCKEditor();
776 this._tab
.html(function(index
, oldHTML
) {
777 if (disableCache
!== true) {
778 self
._cachedTemplate
= oldHTML
;
781 return data
.returnValues
.template
;
784 // block autocomplete
785 this._tab
.find('input[type=text]').attr('autocomplete', 'off');
787 // bind event listener
788 this._tab
.find('.formSubmit > button[data-type=save]').click($.proxy(this._save
, this));
789 this._tab
.find('.formSubmit > button[data-type=restore]').click($.proxy(this._restore
, this));
790 this._tab
.find('input').keyup(function(event
) {
791 if (event
.which
=== 13) { // Enter
794 event
.preventDefault();
801 * Destroys all CKEditor instances within current tab.
803 _destroyCKEditor: function() {
804 // destroy all CKEditor instances
805 this._tab
.find('textarea + .cke').each(function(index
, container
) {
806 var $instanceName
= $(container
).attr('id').replace(/cke_/, '');
807 if (CKEDITOR
.instances
[$instanceName
]) {
808 CKEDITOR
.instances
[$instanceName
].destroy();
815 * Namespace for registration functions.
817 WCF
.User
.Registration
= {};
820 * Validates the password.
822 * @param jQuery element
823 * @param jQuery confirmElement
824 * @param object options
826 WCF
.User
.Registration
.Validation
= Class
.extend({
840 * confirmation input element
843 _confirmElement
: null,
852 * list of error messages
858 * list of additional options
865 * @var WCF.Action.Proxy
870 * Initializes the validation.
872 * @param jQuery element
873 * @param jQuery confirmElement
874 * @param object options
876 init: function(element
, confirmElement
, options
) {
877 this._element
= element
;
878 this._element
.blur($.proxy(this._blur
, this));
879 this._confirmElement
= confirmElement
|| null;
881 if (this._confirmElement
!== null) {
882 this._confirmElement
.blur($.proxy(this._blurConfirm
, this));
885 options
= options
|| { };
886 this._setOptions(options
);
888 this._proxy
= new WCF
.Action
.Proxy({
889 success
: $.proxy(this._success
, this),
890 showLoadingOverlay
: false
893 this._setErrorMessages();
897 * Sets additional options
899 _setOptions: function(options
) { },
902 * Sets error messages.
904 _setErrorMessages: function() {
905 this._errorMessages
= {
912 * Validates once focus on input is lost.
914 * @param object event
916 _blur: function(event
) {
917 var $value
= this._element
.val();
919 return this._showError(this._element
, WCF
.Language
.get('wcf.global.form.error.empty'));
922 if (this._confirmElement
!== null) {
923 var $confirmValue
= this._confirmElement
.val();
924 if ($confirmValue
!= '' && $value
!= $confirmValue
) {
925 return this._showError(this._confirmElement
, this._errorMessages
.notEqual
);
929 if (!this._validateOptions()) {
933 this._proxy
.setOption('data', {
934 actionName
: this._actionName
,
935 className
: this._className
,
936 parameters
: this._getParameters()
938 this._proxy
.sendRequest();
942 * Returns a list of parameters.
946 _getParameters: function() {
951 * Validates input by options.
955 _validateOptions: function() {
960 * Validates value once confirmation input focus is lost.
962 * @param object event
964 _blurConfirm: function(event
) {
965 var $value
= this._confirmElement
.val();
967 return this._showError(this._confirmElement
, WCF
.Language
.get('wcf.global.form.error.empty'));
974 * Handles AJAX responses.
977 * @param string textStatus
978 * @param jQuery jqXHR
980 _success: function(data
, textStatus
, jqXHR
) {
981 if (data
.returnValues
.isValid
) {
982 this._showSuccess(this._element
);
983 if (this._confirmElement
!== null && this._confirmElement
.val()) {
984 this._showSuccess(this._confirmElement
);
988 this._showError(this._element
, WCF
.Language
.get(this._errorMessages
.ajaxError
+ data
.returnValues
.error
));
993 * Shows an error message.
995 * @param jQuery element
996 * @param string message
998 _showError: function(element
, message
) {
999 element
.parent().parent().addClass('formError').removeClass('formSuccess');
1001 var $innerError
= element
.parent().find('small.innerError');
1002 if (!$innerError
.length
) {
1003 $innerError
= $('<small />').addClass('innerError').insertAfter(element
);
1006 $innerError
.text(message
);
1010 * Displays a success message.
1012 * @param jQuery element
1014 _showSuccess: function(element
) {
1015 element
.parent().parent().addClass('formSuccess').removeClass('formError');
1016 element
.next('small.innerError').remove();
1021 * Username validation for registration.
1023 * @see WCF.User.Registration.Validation
1025 WCF
.User
.Registration
.Validation
.Username
= WCF
.User
.Registration
.Validation
.extend({
1027 * @see WCF.User.Registration.Validation._actionName
1029 _actionName
: 'validateUsername',
1032 * @see WCF.User.Registration.Validation._className
1034 _className
: 'wcf\\data\\user\\UserRegistrationAction',
1037 * @see WCF.User.Registration.Validation._setOptions()
1039 _setOptions: function(options
) {
1040 this._options
= $.extend(true, {
1047 * @see WCF.User.Registration.Validation._setErrorMessages()
1049 _setErrorMessages: function() {
1050 this._errorMessages
= {
1051 ajaxError
: 'wcf.user.username.error.'
1056 * @see WCF.User.Registration.Validation._validateOptions()
1058 _validateOptions: function() {
1059 var $value
= this._element
.val();
1060 if ($value
.length
< this._options
.minlength
|| $value
.length
> this._options
.maxlength
) {
1061 this._showError(this._element
, WCF
.Language
.get('wcf.user.username.error.notValid'));
1069 * @see WCF.User.Registration.Validation._getParameters()
1071 _getParameters: function() {
1073 username
: this._element
.val()
1079 * Email validation for registration.
1081 * @see WCF.User.Registration.Validation
1083 WCF
.User
.Registration
.Validation
.EmailAddress
= WCF
.User
.Registration
.Validation
.extend({
1085 * @see WCF.User.Registration.Validation._actionName
1087 _actionName
: 'validateEmailAddress',
1090 * @see WCF.User.Registration.Validation._className
1092 _className
: 'wcf\\data\\user\\UserRegistrationAction',
1095 * @see WCF.User.Registration.Validation._getParameters()
1097 _getParameters: function() {
1099 email
: this._element
.val()
1104 * @see WCF.User.Registration.Validation._setErrorMessages()
1106 _setErrorMessages: function() {
1107 this._errorMessages
= {
1108 ajaxError
: 'wcf.user.email.error.',
1109 notEqual
: WCF
.Language
.get('wcf.user.confirmEmail.error.notEqual')
1115 * Password validation for registration.
1117 * @see WCF.User.Registration.Validation
1119 WCF
.User
.Registration
.Validation
.Password
= WCF
.User
.Registration
.Validation
.extend({
1121 * @see WCF.User.Registration.Validation._actionName
1123 _actionName
: 'validatePassword',
1126 * @see WCF.User.Registration.Validation._className
1128 _className
: 'wcf\\data\\user\\UserRegistrationAction',
1131 * @see WCF.User.Registration.Validation._getParameters()
1133 _getParameters: function() {
1135 password
: this._element
.val()
1140 * @see WCF.User.Registration.Validation._setErrorMessages()
1142 _setErrorMessages: function() {
1143 this._errorMessages
= {
1144 ajaxError
: 'wcf.user.password.error.',
1145 notEqual
: WCF
.Language
.get('wcf.user.confirmPassword.error.notEqual')
1151 * Toggles input fields for lost password form.
1153 WCF
.User
.Registration
.LostPassword
= Class
.extend({
1167 * Initializes LostPassword-form class.
1170 // bind input fields
1171 this._email
= $('#emailInput');
1172 this._username
= $('#usernameInput');
1174 // bind event listener
1175 this._email
.keyup($.proxy(this._checkEmail
, this));
1176 this._username
.keyup($.proxy(this._checkUsername
, this));
1178 if ($.browser
.mozilla
&& $.browser
.touch
) {
1179 this._email
.on('input', $.proxy(this._checkEmail
, this));
1180 this._username
.on('input', $.proxy(this._checkUsername
, this));
1183 // toggle fields on init
1185 this._checkUsername();
1189 * Checks for content in email field and toggles username.
1191 _checkEmail: function() {
1192 if (this._email
.val() == '') {
1193 this._username
.enable();
1194 this._username
.parents('dl:eq(0)').removeClass('disabled');
1197 this._username
.disable();
1198 this._username
.parents('dl:eq(0)').addClass('disabled');
1203 * Checks for content in username field and toggles email.
1205 _checkUsername: function() {
1206 if (this._username
.val() == '') {
1207 this._email
.enable();
1208 this._email
.parents('dl:eq(0)').removeClass('disabled');
1211 this._email
.disable();
1212 this._email
.parents('dl:eq(0)').addClass('disabled');
1218 * Notification system for WCF.
1220 * @author Alexander Ebert
1221 * @copyright 2001-2014 WoltLab GmbH
1222 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
1224 WCF
.Notification
= {};
1227 * Loads notification for the user panel.
1229 * @see WCF.UserPanel
1231 WCF
.Notification
.UserPanel
= WCF
.UserPanel
.extend({
1234 * @var WCF.Action.Proxy
1239 * link to show all notifications
1245 * @see WCF.UserPanel.init()
1247 init: function(showAllLink
) {
1248 this._noItems
= 'wcf.user.notification.noMoreNotifications';
1249 this._proxy
= new WCF
.Action
.Proxy({
1250 success
: $.proxy(this._success
, this)
1252 this._showAllLink
= showAllLink
;
1254 this._super('userNotifications');
1256 // update page title
1257 if (this._container
.data('count')) {
1258 document
.title
= '(' + this._container
.data('count') + ') ' + document
.title
;
1263 * @see WCF.UserPanel._addDefaultItems()
1265 _addDefaultItems: function(dropdownMenu
) {
1266 this._addDivider(dropdownMenu
);
1267 if (this._container
.data('count')) {
1268 $('<li><a href="' + this._showAllLink
+ '">' + WCF
.Language
.get('wcf.user.notification.showAll') + '</a></li>').appendTo(dropdownMenu
);
1269 this._addDivider(dropdownMenu
);
1271 $('<li id="userNotificationsMarkAllAsConfirmed"><a>' + WCF
.Language
.get('wcf.user.notification.markAllAsConfirmed') + '</a></li>').click($.proxy(this._markAllAsConfirmed
, this)).appendTo(dropdownMenu
);
1275 * @see WCF.UserPanel._getParameters()
1277 _getParameters: function() {
1279 actionName
: 'getOutstandingNotifications',
1280 className
: 'wcf\\data\\user\\notification\\UserNotificationAction'
1285 * @see WCF.UserPanel._after()
1287 _after: function(dropdownMenu
) {
1288 WCF
.Dropdown
.getDropdownMenu(this._container
.wcfIdentify()).children('li.jsNotificationItem').click($.proxy(this._markAsConfirmed
, this));
1292 * Marks a notification as confirmed.
1294 * @param object event
1296 _markAsConfirmed: function(event
) {
1297 this._proxy
.setOption('data', {
1298 actionName
: 'markAsConfirmed',
1299 className
: 'wcf\\data\\user\\notification\\UserNotificationAction',
1301 notificationID
: $(event
.currentTarget
).data('notificationID')
1304 this._proxy
.sendRequest();
1308 * Marks all notifications as confirmed.
1310 _markAllAsConfirmed: function() {
1311 WCF
.System
.Confirmation
.show(WCF
.Language
.get('wcf.user.notification.markAllAsConfirmed.confirmMessage'), $.proxy(function(action
) {
1312 if (action
=== 'confirm') {
1313 this._proxy
.setOption('data', {
1314 actionName
: 'markAllAsConfirmed',
1315 className
: 'wcf\\data\\user\\notification\\UserNotificationAction'
1317 this._proxy
.sendRequest();
1323 * @see WCF.UserPanel._success()
1325 _success: function(data
, textStatus
, jqXHR
) {
1326 switch (data
.actionName
) {
1327 case 'markAllAsConfirmed':
1328 $('.jsNotificationItem').remove();
1329 // remove notification count
1330 document
.title
= document
.title
.replace(/^\(([0-9]+)\) /, '');
1332 case 'getOutstandingNotifications':
1333 if (!data
.returnValues
|| !data
.returnValues
.template
) {
1334 $('#userNotificationsMarkAllAsConfirmed').prev('.dropdownDivider').remove();
1335 $('#userNotificationsMarkAllAsConfirmed').remove();
1338 this._super(data
, textStatus
, jqXHR
);
1341 case 'markAsConfirmed':
1342 WCF
.Dropdown
.getDropdownMenu(this._container
.wcfIdentify()).children('li.jsNotificationItem').each(function(index
, item
) {
1343 var $item
= $(item
);
1344 if (data
.returnValues
.notificationID
== $item
.data('notificationID')) {
1345 window
.location
= $item
.data('link');
1355 * Handles notification list actions.
1357 WCF
.Notification
.List
= Class
.extend({
1359 * notification count
1365 * list of notification items
1372 * @var WCF.Action.Proxy
1377 * Initializes the notification list.
1380 var $containers
= $('li.jsNotificationItem');
1381 if (!$containers
.length
) {
1385 $containers
.each($.proxy(function(index
, container
) {
1386 var $container
= $(container
);
1387 this._items
[$container
.data('notificationID')] = $container
;
1389 $container
.find('.jsMarkAsConfirmed').data('notificationID', $container
.data('notificationID')).click($.proxy(this._click
, this));
1390 $container
.find('p').html(function(index
, oldHTML
) {
1391 return '<a>' + oldHTML
+ '</a>';
1392 }).children('a').data('notificationID', $container
.data('notificationID')).click($.proxy(this._clickLink
, this));
1395 this._badge
= $('.jsNotificationsBadge:eq(0)');
1396 this._proxy
= new WCF
.Action
.Proxy({
1397 success
: $.proxy(this._success
, this)
1400 // mark all as confirmed button
1401 $('.contentNavigation .jsMarkAllAsConfirmed').click($.proxy(this._markAllAsConfirmed
, this));
1405 * Handles clicks on the text link.
1407 * @param object event
1409 _clickLink: function(event
) {
1410 this._items
[$(event
.currentTarget
).data('notificationID')].data('redirect', true);
1415 * Handles button actions.
1417 * @param object event
1419 _click: function(event
) {
1420 this._proxy
.setOption('data', {
1421 actionName
: 'markAsConfirmed',
1422 className
: 'wcf\\data\\user\\notification\\UserNotificationAction',
1424 notificationID
: $(event
.currentTarget
).data('notificationID')
1427 this._proxy
.sendRequest();
1431 * Marks all notifications as confirmed.
1433 _markAllAsConfirmed: function() {
1434 WCF
.System
.Confirmation
.show(WCF
.Language
.get('wcf.user.notification.markAllAsConfirmed.confirmMessage'), $.proxy(function(action
) {
1435 if (action
=== 'confirm') {
1436 this._proxy
.setOption('data', {
1437 actionName
: 'markAllAsConfirmed',
1438 className
: 'wcf\\data\\user\\notification\\UserNotificationAction'
1440 this._proxy
.sendRequest();
1446 * Handles successful button actions.
1448 * @param object data
1449 * @param string textStatus
1450 * @param jQuery jqXHR
1452 _success: function(data
, textStatus
, jqXHR
) {
1453 switch (data
.actionName
) {
1454 case 'markAllAsConfirmed':
1455 window
.location
.reload();
1458 case 'markAsConfirmed':
1459 var $item
= this._items
[data
.returnValues
.notificationID
];
1460 if ($item
.data('redirect')) {
1461 window
.location
= $item
.data('link');
1465 this._items
[data
.returnValues
.notificationID
].remove();
1466 delete this._items
[data
.returnValues
.notificationID
];
1468 // reduce badge count
1469 this._badge
.html(data
.returnValues
.totalCount
);
1471 // remove previous notification count
1472 document
.title
= document
.title
.replace(/^\(([0-9]+)\) /, '');
1474 // update page title
1475 if (data
.returnValues
.totalCount
> 0) {
1476 document
.title
= '(' + data
.returnValues
.totalCount
+ ') ' + document
.title
;
1484 * Signature preview.
1486 * @see WCF.Message.Preview
1488 WCF
.User
.SignaturePreview
= WCF
.Message
.Preview
.extend({
1490 * @see WCF.Message.Preview._handleResponse()
1492 _handleResponse: function(data
) {
1493 // get preview container
1494 var $preview
= $('#previewContainer');
1495 if (!$preview
.length
) {
1496 $preview
= $('<fieldset id="previewContainer"><legend>' + WCF
.Language
.get('wcf.global.preview') + '</legend><div></div></fieldset>').insertBefore($('#signatureContainer')).wcfFadeIn();
1499 $preview
.children('div').first().html(data
.returnValues
.message
);
1504 * Loads recent activity events once the user scrolls to the very bottom.
1506 * @param integer userID
1508 WCF
.User
.RecentActivityLoader
= Class
.extend({
1516 * true if list should be filtered by followed users
1519 _filteredByFollowedUsers
: false,
1522 * button to load next events
1529 * @var WCF.Action.Proxy
1540 * Initializes a new RecentActivityLoader object.
1542 * @param integer userID
1543 * @param boolean filteredByFollowedUsers
1545 init: function(userID
, filteredByFollowedUsers
) {
1546 this._container
= $('#recentActivities');
1547 this._filteredByFollowedUsers
= (filteredByFollowedUsers
=== true);
1548 this._userID
= userID
;
1550 if (this._userID
!== null && !this._userID
) {
1551 console
.debug("[WCF.User.RecentActivityLoader] Invalid parameter 'userID' given.");
1555 this._proxy
= new WCF
.Action
.Proxy({
1556 success
: $.proxy(this._success
, this)
1559 this._loadButton
= $('<li class="recentActivitiesMore"><button class="small">' + WCF
.Language
.get('wcf.user.recentActivity.more') + '</button></li>').appendTo(this._container
);
1560 this._loadButton
= this._loadButton
.children('button').click($.proxy(this._click
, this));
1564 * Loads next activity events.
1566 _click: function() {
1567 this._loadButton
.enable();
1570 lastEventTime
: this._container
.data('lastEventTime')
1573 $parameters
.userID
= this._userID
;
1575 else if (this._filteredByFollowedUsers
) {
1576 $parameters
.filteredByFollowedUsers
= 1;
1579 this._proxy
.setOption('data', {
1581 className
: 'wcf\\data\\user\\activity\\event\\UserActivityEventAction',
1582 parameters
: $parameters
1584 this._proxy
.sendRequest();
1588 * Handles successful AJAX requests.
1590 * @param object data
1591 * @param string textStatus
1592 * @param jQuery jqXHR
1594 _success: function(data
, textStatus
, jqXHR
) {
1595 if (data
.returnValues
.template
) {
1596 $(data
.returnValues
.template
).insertBefore(this._loadButton
.parent());
1598 this._container
.data('lastEventTime', data
.returnValues
.lastEventTime
);
1599 this._loadButton
.enable();
1602 $('<small>' + WCF
.Language
.get('wcf.user.recentActivity.noMoreEntries') + '</small>').appendTo(this._loadButton
.parent());
1603 this._loadButton
.remove();
1609 * Loads user profile previews.
1613 WCF
.User
.ProfilePreview
= WCF
.Popover
.extend({
1616 * @var WCF.Action.Proxy
1621 * list of user profiles
1627 * @see WCF.Popover.init()
1630 this._super('.userLink');
1632 this._proxy
= new WCF
.Action
.Proxy({
1633 showLoadingOverlay
: false
1638 * @see WCF.Popover._loadContent()
1640 _loadContent: function() {
1641 var $element
= $('#' + this._activeElementID
);
1642 var $userID
= $element
.data('userID');
1644 if (this._userProfiles
[$userID
]) {
1645 // use cached user profile
1646 this._insertContent(this._activeElementID
, this._userProfiles
[$userID
], true);
1649 this._proxy
.setOption('data', {
1650 actionName
: 'getUserProfile',
1651 className
: 'wcf\\data\\user\\UserProfileAction',
1652 objectIDs
: [ $userID
]
1655 var $elementID
= this._activeElementID
;
1657 this._proxy
.setOption('success', function(data
, textStatus
, jqXHR
) {
1658 // cache user profile
1659 self
._userProfiles
[$userID
] = data
.returnValues
.template
;
1661 // show user profile
1662 self
._insertContent($elementID
, data
.returnValues
.template
, true);
1664 this._proxy
.setOption('failure', function(data
, jqXHR
, textStatus
, errorThrown
) {
1665 // cache user profile
1666 self
._userProfiles
[$userID
] = data
.message
;
1668 // show user profile
1669 self
._insertContent($elementID
, data
.message
, true);
1673 this._proxy
.sendRequest();
1679 * Initalizes WCF.User.Action namespace.
1681 WCF
.User
.Action
= {};
1684 * Handles user follow and unfollow links.
1686 WCF
.User
.Action
.Follow
= Class
.extend({
1688 * list with elements containing follow and unfollow buttons
1691 _containerList
: null,
1694 * CSS selector for follow buttons
1697 _followButtonSelector
: '.jsFollowButton',
1700 * id of the user that is currently being followed/unfollowed
1706 * Initializes new WCF.User.Action.Follow object.
1708 * @param array containerList
1709 * @param string followButtonSelector
1711 init: function(containerList
, followButtonSelector
) {
1712 if (!containerList
.length
) {
1715 this._containerList
= containerList
;
1717 if (followButtonSelector
) {
1718 this._followButtonSelector
= followButtonSelector
;
1722 this._proxy
= new WCF
.Action
.Proxy({
1723 success
: $.proxy(this._success
, this)
1726 // bind event listeners
1727 this._containerList
.each($.proxy(function(index
, container
) {
1728 $(container
).find(this._followButtonSelector
).click($.proxy(this._click
, this));
1733 * Handles a click on a follow or unfollow button.
1735 * @param object event
1737 _click: function(event
) {
1738 var link
= $(event
.target
);
1739 if (!link
.is('a')) {
1740 link
= link
.closest('a');
1742 this._userID
= link
.data('objectID');
1744 this._proxy
.setOption('data', {
1745 'actionName': link
.data('following') ? 'unfollow' : 'follow',
1746 'className': 'wcf\\data\\user\\follow\\UserFollowAction',
1749 userID
: this._userID
1753 this._proxy
.sendRequest();
1757 * Handles the successful (un)following of a user.
1759 * @param object data
1760 * @param string textStatus
1761 * @param jQuery jqXHR
1763 _success: function(data
, textStatus
, jqXHR
) {
1764 this._containerList
.each($.proxy(function(index
, container
) {
1765 var button
= $(container
).find(this._followButtonSelector
).get(0);
1767 if (button
&& $(button
).data('objectID') == this._userID
) {
1770 // toogle icon title
1771 if (data
.returnValues
.following
) {
1772 button
.data('tooltip', WCF
.Language
.get('wcf.user.button.unfollow')).children('.icon').removeClass('icon-plus').addClass('icon-minus');
1775 button
.data('tooltip', WCF
.Language
.get('wcf.user.button.follow')).children('.icon').removeClass('icon-minus').addClass('icon-plus');
1778 button
.data('following', data
.returnValues
.following
);
1784 var $notification
= new WCF
.System
.Notification();
1785 $notification
.show();
1790 * Handles user ignore and unignore links.
1792 WCF
.User
.Action
.Ignore
= Class
.extend({
1794 * list with elements containing ignore and unignore buttons
1797 _containerList
: null,
1800 * CSS selector for ignore buttons
1803 _ignoreButtonSelector
: '.jsIgnoreButton',
1806 * id of the user that is currently being ignored/unignored
1812 * Initializes new WCF.User.Action.Ignore object.
1814 * @param array containerList
1815 * @param string ignoreButtonSelector
1817 init: function(containerList
, ignoreButtonSelector
) {
1818 if (!containerList
.length
) {
1821 this._containerList
= containerList
;
1823 if (ignoreButtonSelector
) {
1824 this._ignoreButtonSelector
= ignoreButtonSelector
;
1828 this._proxy
= new WCF
.Action
.Proxy({
1829 success
: $.proxy(this._success
, this)
1832 // bind event listeners
1833 this._containerList
.each($.proxy(function(index
, container
) {
1834 $(container
).find(this._ignoreButtonSelector
).click($.proxy(this._click
, this));
1839 * Handles a click on a ignore or unignore button.
1841 * @param object event
1843 _click: function(event
) {
1844 var link
= $(event
.target
);
1845 if (!link
.is('a')) {
1846 link
= link
.closest('a');
1848 this._userID
= link
.data('objectID');
1850 this._proxy
.setOption('data', {
1851 'actionName': link
.data('ignored') ? 'unignore' : 'ignore',
1852 'className': 'wcf\\data\\user\\ignore\\UserIgnoreAction',
1855 ignoreUserID
: this._userID
1859 this._proxy
.sendRequest();
1863 * Handles the successful (un)ignoring of a user.
1865 * @param object data
1866 * @param string textStatus
1867 * @param jQuery jqXHR
1869 _success: function(data
, textStatus
, jqXHR
) {
1870 this._containerList
.each($.proxy(function(index
, container
) {
1871 var button
= $(container
).find(this._ignoreButtonSelector
).get(0);
1873 if (button
&& $(button
).data('objectID') == this._userID
) {
1876 // toogle icon title
1877 if (data
.returnValues
.isIgnoredUser
) {
1878 button
.data('tooltip', WCF
.Language
.get('wcf.user.button.unignore')).children('.icon').removeClass('icon-ban-circle').addClass('icon-circle-blank');
1881 button
.data('tooltip', WCF
.Language
.get('wcf.user.button.ignore')).children('.icon').removeClass('icon-circle-blank').addClass('icon-ban-circle');
1884 button
.data('ignored', data
.returnValues
.isIgnoredUser
);
1890 var $notification
= new WCF
.System
.Notification();
1891 $notification
.show();
1896 * Namespace for avatar functions.
1898 WCF
.User
.Avatar
= {};
1901 * Handles cropping an avatar.
1903 WCF
.User
.Avatar
.Crop
= Class
.extend({
1905 * current crop setting in x-direction
1911 * current crop setting in y-direction
1917 * avatar crop dialog
1923 * action proxy to send the crop AJAX requests
1924 * @var WCF.Action.Proxy
1929 * maximum size of thumbnails
1932 MAX_THUMBNAIL_SIZE
: 128,
1935 * Creates a new instance of WCF.User.Avatar.Crop.
1937 * @param integer avatarID
1939 init: function(avatarID
) {
1940 this._avatarID
= avatarID
;
1945 this._dialog
= null;
1947 // check if object already had been initialized
1949 this._proxy
= new WCF
.Action
.Proxy({
1950 success
: $.proxy(this._success
, this)
1954 $('.userAvatarCrop').click($.proxy(this._showCropDialog
, this));
1958 * Destroys the avatar crop interface.
1960 destroy: function() {
1961 this._dialog
.remove();
1965 * Sends AJAX request to crop avatar.
1967 * @param object event
1969 _crop: function(event
) {
1970 this._proxy
.setOption('data', {
1971 actionName
: 'cropAvatar',
1972 className
: 'wcf\\data\\user\\avatar\\UserAvatarAction',
1973 objectIDs
: [ this._avatarID
],
1979 this._proxy
.sendRequest();
1983 * Initializes the dialog after a successful 'getCropDialog' request.
1985 * @param object data
1987 _getCropDialog: function(data
) {
1988 if (!this._dialog
) {
1989 this._dialog
= $('<div />').hide().appendTo(document
.body
);
1990 this._dialog
.wcfDialog({
1991 title
: WCF
.Language
.get('wcf.user.avatar.type.custom.crop')
1995 this._dialog
.html(data
.returnValues
.template
);
1996 this._dialog
.find('button[data-type="save"]').click($.proxy(this._crop
, this));
1998 this._cropX
= data
.returnValues
.cropX
;
1999 this._cropY
= data
.returnValues
.cropY
;
2001 var $image
= $('#userAvatarCropSelection > img');
2002 $('#userAvatarCropSelection').css({
2003 height
: $image
.height() + 'px',
2004 width
: $image
.width() + 'px'
2006 $('#userAvatarCropOverlaySelection').css({
2007 'background-image': 'url(' + $image
.attr('src') + ')',
2008 'background-position': -this._cropX
+ 'px ' + -this._cropY
+ 'px',
2009 'left': this._cropX
+ 'px',
2010 'top': this._cropY
+ 'px'
2012 containment
: 'parent',
2013 drag
: $.proxy(this._updateSelection
, this),
2014 stop
: $.proxy(this._updateSelection
, this)
2017 this._dialog
.find('button[data-type="save"]').click($.proxy(this._save
, this));
2019 this._dialog
.wcfDialog('render');
2023 * Shows the cropping dialog.
2025 _showCropDialog: function() {
2026 if (!this._dialog
) {
2027 this._proxy
.setOption('data', {
2028 actionName
: 'getCropDialog',
2029 className
: 'wcf\\data\\user\\avatar\\UserAvatarAction',
2030 objectIDs
: [ this._avatarID
]
2032 this._proxy
.sendRequest();
2035 this._dialog
.wcfDialog('open');
2040 * Handles successful AJAX request.
2042 * @param object data
2043 * @param string textStatus
2044 * @param jQuery jqXHR
2046 _success: function(data
, textStatus
, jqXHR
) {
2047 switch (data
.actionName
) {
2048 case 'getCropDialog':
2049 this._getCropDialog(data
);
2053 $('#avatarUpload > dt > img').replaceWith($('<img src="' + data
.returnValues
.url
+ '" alt="" class="userAvatarCrop jsTooltip" title="' + WCF
.Language
.get('wcf.user.avatar.type.custom.crop') + '" />').css({
2056 }).click($.proxy(this._showCropDialog
, this)));
2058 WCF
.DOMNodeInsertedHandler
.execute();
2060 this._dialog
.wcfDialog('close');
2062 var $notification
= new WCF
.System
.Notification();
2063 $notification
.show();
2069 * Updates the current crop selection if the selection overlay is dragged.
2071 * @param object event
2074 _updateSelection: function(event
, ui
) {
2075 this._cropX
= ui
.position
.left
;
2076 this._cropY
= ui
.position
.top
;
2078 $('#userAvatarCropOverlaySelection').css({
2079 'background-position': -ui
.position
.left
+ 'px ' + -ui
.position
.top
+ 'px'
2085 * Avatar upload function
2089 WCF
.User
.Avatar
.Upload
= WCF
.Upload
.extend({
2091 * handles cropping the avatar
2092 * @var WCF.User.Avatar.Crop
2097 * user id of avatar owner
2103 * Initalizes a new WCF.User.Avatar.Upload object.
2105 * @param integer userID
2106 * @param WCF.User.Avatar.Crop avatarCrop
2108 init: function(userID
, avatarCrop
) {
2109 this._super($('#avatarUpload > dd > div'), undefined, 'wcf\\data\\user\\avatar\\UserAvatarAction');
2110 this._userID
= userID
|| 0;
2111 this._avatarCrop
= avatarCrop
;
2113 $('#avatarForm input[type=radio]').change(function() {
2114 if ($(this).val() == 'custom') {
2115 $('#avatarUpload > dd > div').show();
2118 $('#avatarUpload > dd > div').hide();
2121 if (!$('#avatarForm input[type=radio][value=custom]:checked').length
) {
2122 $('#avatarUpload > dd > div').hide();
2127 * @see WCF.Upload._initFile()
2129 _initFile: function(file
) {
2130 return $('#avatarUpload > dt > img');
2134 * @see WCF.Upload._success()
2136 _success: function(uploadID
, data
) {
2137 if (data
.returnValues
.url
) {
2138 this._updateImage(data
.returnValues
.url
, data
.returnValues
.canCrop
);
2140 if (data
.returnValues
.canCrop
) {
2141 if (!this._avatarCrop
) {
2142 this._avatarCrop
= new WCF
.User
.Avatar
.Crop(data
.returnValues
.avatarID
);
2145 this._avatarCrop
.init(data
.returnValues
.avatarID
);
2148 else if (this._avatarCrop
) {
2149 this._avatarCrop
.destroy();
2150 this._avatarCrop
= null;
2154 $('#avatarUpload > dd > .innerError').remove();
2156 // show success message
2157 var $notification
= new WCF
.System
.Notification(WCF
.Language
.get('wcf.user.avatar.upload.success'));
2158 $notification
.show();
2160 else if (data
.returnValues
.errorType
) {
2162 this._getInnerErrorElement().text(WCF
.Language
.get('wcf.user.avatar.upload.error.' + data
.returnValues
.errorType
));
2167 * Updates the displayed avatar image.
2170 * @param boolean canCrop
2172 _updateImage: function(url
, canCrop
) {
2173 $('#avatarUpload > dt > img').remove();
2174 var $image
= $('<img src="' + url
+ '" alt="" />').css({
2176 'max-height': '96px',
2177 'max-width': '96px',
2181 $image
.addClass('userAvatarCrop').addClass('jsTooltip');
2182 $image
.attr('title', WCF
.Language
.get('wcf.user.avatar.type.custom.crop'));
2185 $('#avatarUpload > dt').prepend($image
);
2187 WCF
.DOMNodeInsertedHandler
.execute();
2191 * Returns the inner error element.
2195 _getInnerErrorElement: function() {
2196 var $span
= $('#avatarUpload > dd > .innerError');
2197 if (!$span
.length
) {
2198 $span
= $('<small class="innerError"></span>');
2199 $('#avatarUpload > dd').append($span
);
2206 * @see WCF.Upload._getParameters()
2208 _getParameters: function() {
2210 userID
: this._userID
2216 * Generic implementation for grouped user lists.
2218 * @param string className
2219 * @param string dialogTitle
2220 * @param object additionalParameters
2222 WCF
.User
.List
= Class
.extend({
2224 * list of additional parameters
2227 _additionalParameters
: { },
2230 * list of cached pages
2267 * @var WCF.Action.Proxy
2272 * Initializes a new grouped user list.
2274 * @param string className
2275 * @param string dialogTitle
2276 * @param object additionalParameters
2278 init: function(className
, dialogTitle
, additionalParameters
) {
2279 this._additionalParameters
= additionalParameters
|| { };
2281 this._className
= className
;
2282 this._dialog
= null;
2283 this._dialogTitle
= dialogTitle
;
2284 this._pageCount
= 0;
2287 this._proxy
= new WCF
.Action
.Proxy({
2288 success
: $.proxy(this._success
, this)
2293 * Opens the dialog overlay.
2301 * Displays the specified page.
2303 * @param object event
2304 * @param object data
2306 _showPage: function(event
, data
) {
2307 if (data
&& data
.activePage
) {
2308 this._pageNo
= data
.activePage
;
2311 if (this._pageCount
!= 0 && (this._pageNo
< 1 || this._pageNo
> this._pageCount
)) {
2312 console
.debug("[WCF.User.List] Cannot access page " + this._pageNo
+ " of " + this._pageCount
);
2316 if (this._cache
[this._pageNo
]) {
2317 var $dialogCreated
= false;
2318 if (this._dialog
=== null) {
2319 //this._dialog = $('<div id="userList' + this._className.hashCode() + '" style="min-width: 600px;" />').hide().appendTo(document.body);
2320 this._dialog
= $('<div id="userList' + this._className
.hashCode() + '" />').hide().appendTo(document
.body
);
2321 $dialogCreated
= true;
2324 // remove current view
2325 this._dialog
.empty();
2328 this._dialog
.html(this._cache
[this._pageNo
]);
2331 if (this._pageCount
> 1) {
2332 this._dialog
.find('.jsPagination').wcfPages({
2333 activePage
: this._pageNo
,
2334 maxPage
: this._pageCount
2335 }).bind('wcfpagesswitched', $.proxy(this._showPage
, this));
2339 if ($dialogCreated
) {
2340 this._dialog
.wcfDialog({
2341 title
: this._dialogTitle
2345 this._dialog
.wcfDialog('open').wcfDialog('render');
2349 this._additionalParameters
.pageNo
= this._pageNo
;
2351 // load template via AJAX
2352 this._proxy
.setOption('data', {
2353 actionName
: 'getGroupedUserList',
2354 className
: this._className
,
2355 interfaceName
: 'wcf\\data\\IGroupedUserListAction',
2356 parameters
: this._additionalParameters
2358 this._proxy
.sendRequest();
2363 * Handles successful AJAX requests.
2365 * @param object data
2366 * @param string textStatus
2367 * @param jQuery jqXHR
2369 _success: function(data
, textStatus
, jqXHR
) {
2370 if (data
.returnValues
.pageCount
) {
2371 this._pageCount
= data
.returnValues
.pageCount
;
2374 this._cache
[this._pageNo
] = data
.returnValues
.template
;
2380 * Namespace for object watch functions.
2382 WCF
.User
.ObjectWatch
= {};
2385 * Handles subscribe/unsubscribe links.
2387 WCF
.User
.ObjectWatch
.Subscribe
= Class
.extend({
2389 * CSS selector for subscribe buttons
2392 _buttonSelector
: '.jsSubscribeButton',
2407 * system notification
2408 * @var WCF.System.Notification
2410 _notification
: null,
2413 * WCF.User.ObjectWatch.Subscribe object.
2416 this._buttons
= { };
2417 this._notification
= null;
2420 this._proxy
= new WCF
.Action
.Proxy({
2421 success
: $.proxy(this._success
, this)
2424 // bind event listeners
2425 $(this._buttonSelector
).each($.proxy(function(index
, button
) {
2426 var $button
= $(button
);
2427 var $objectID
= $button
.data('objectID');
2428 this._buttons
[$objectID
] = $button
.click($.proxy(this._click
, this));
2433 * Handles a click on a subscribe button.
2435 * @param object event
2437 _click: function(event
) {
2438 var $button
= $(event
.currentTarget
);
2440 this._proxy
.setOption('data', {
2441 actionName
: 'manageSubscription',
2442 className
: 'wcf\\data\\user\\object\\watch\\UserObjectWatchAction',
2444 objectID
: $button
.data('objectID'),
2445 objectType
: $button
.data('objectType')
2448 this._proxy
.sendRequest();
2452 * Handles successful AJAX requests.
2454 * @param object data
2455 * @param string textStatus
2456 * @param jQuery jqXHR
2458 _success: function(data
, textStatus
, jqXHR
) {
2459 if (data
.actionName
=== 'manageSubscription') {
2460 if (this._dialog
=== null) {
2461 this._dialog
= $('<div>' + data
.returnValues
.template
+ '</div>').hide().appendTo(document
.body
);
2462 this._dialog
.wcfDialog({
2463 title
: WCF
.Language
.get('wcf.user.objectWatch.manageSubscription')
2467 this._dialog
.html(data
.returnValues
.template
);
2468 this._dialog
.wcfDialog('open');
2471 // bind event listener
2472 this._dialog
.find('.formSubmit > .jsButtonSave').data('objectID', data
.returnValues
.objectID
).click($.proxy(this._save
, this));
2473 var $enableNotification
= this._dialog
.find('input[name=enableNotification]').disable();
2475 // toggle subscription
2476 this._dialog
.find('input[name=subscribe]').change(function(event
) {
2477 var $input
= $(event
.currentTarget
);
2478 if ($input
.val() == 1) {
2479 $enableNotification
.enable();
2482 $enableNotification
.disable();
2487 var $selectedOption
= this._dialog
.find('input[name=subscribe]:checked');
2488 if ($selectedOption
.length
&& $selectedOption
.val() == 1) {
2489 $enableNotification
.enable();
2492 else if (data
.actionName
=== 'saveSubscription' && this._dialog
.is(':visible')) {
2493 this._dialog
.wcfDialog('close');
2495 if (this._notification
=== null) {
2496 this._notification
= new WCF
.System
.Notification(WCF
.Language
.get('wcf.global.success.edit'));
2499 this._notification
.show();
2504 * Saves the subscription.
2506 * @param object event
2508 _save: function(event
) {
2509 var $button
= this._buttons
[$(event
.currentTarget
).data('objectID')];
2510 var $subscribe
= this._dialog
.find('input[name=subscribe]:checked').val();
2511 var $enableNotification
= (this._dialog
.find('input[name=enableNotification]').is(':checked')) ? 1 : 0;
2513 this._proxy
.setOption('data', {
2514 actionName
: 'saveSubscription',
2515 className
: 'wcf\\data\\user\\object\\watch\\UserObjectWatchAction',
2517 enableNotification
: $enableNotification
,
2518 objectID
: $button
.data('objectID'),
2519 objectType
: $button
.data('objectType'),
2520 subscribe
: $subscribe
2523 this._proxy
.sendRequest();
2528 * Handles inline editing of users.
2530 WCF
.User
.InlineEditor
= WCF
.InlineEditor
.extend({
2532 * list of permissions
2538 * @see WCF.InlineEditor._execute()
2540 _execute: function(elementID
, optionName
) {
2541 if (!this._validate(elementID
, optionName
)) {
2546 var $element
= $('#' + elementID
);
2547 switch (optionName
) {
2549 case 'enableAvatar':
2550 case 'enableSignature':
2551 switch (optionName
) {
2556 case 'enableAvatar':
2557 $data
.disableAvatar
= 0;
2560 case 'enableSignature':
2561 $data
.disableSignature
= 0;
2565 this._proxy
.setOption('data', {
2566 actionName
: optionName
,
2567 className
: 'wcf\\data\\user\\UserAction',
2568 objectIDs
: [ $element
.data('objectID') ]
2570 this._proxy
.sendRequest();
2574 case 'disableAvatar':
2575 case 'disableSignature':
2576 if (optionName
== 'ban') {
2580 $data
[optionName
] = 1;
2583 this._showReasonDialog($element
.data('objectID'), optionName
);
2587 window
.location
= this._getTriggerElement($element
).attr('href');
2591 if ($.getLength($data
)) {
2592 this._updateData
.push({
2594 elementID
: elementID
,
2600 * Executes an action with a reason.
2602 * @param integer userID
2603 * @param string optionName
2604 * @param string reason
2606 _executeReasonAction: function(userID
, optionName
, reason
) {
2607 var $parameters
= { };
2608 $parameters
[optionName
+ WCF
.String
.ucfirst('reason')] = reason
;
2610 this._proxy
.setOption('data', {
2611 actionName
: optionName
,
2612 className
: 'wcf\\data\\user\\UserAction',
2613 objectIDs
: [ userID
],
2614 parameters
: $parameters
2616 this._proxy
.sendRequest();
2620 * Returns a specific permission.
2622 * @param string permission
2625 _getPermission: function(permission
) {
2626 if (this._permissions
[permission
]) {
2627 return this._permissions
[permission
];
2634 * @see WCF.InlineEditor._getTriggerElement()
2636 _getTriggerElement: function(element
) {
2637 return element
.find('.jsUserInlineEditor');
2641 * @see WCF.InlineEditor._setOptions()
2643 _setOptions: function() {
2646 { label
: WCF
.Language
.get('wcf.user.ban'), optionName
: 'ban' },
2647 { label
: WCF
.Language
.get('wcf.user.unban'), optionName
: 'unban' },
2650 { label
: WCF
.Language
.get('wcf.user.disableAvatar'), optionName
: 'disableAvatar' },
2651 { label
: WCF
.Language
.get('wcf.user.enableAvatar'), optionName
: 'enableAvatar' },
2653 // disabling signature
2654 { label
: WCF
.Language
.get('wcf.user.disableSignature'), optionName
: 'disableSignature' },
2655 { label
: WCF
.Language
.get('wcf.user.enableSignature'), optionName
: 'enableSignature' },
2658 { optionName
: 'divider' },
2661 { label
: WCF
.Language
.get('wcf.user.edit'), optionName
: 'advanced' }
2666 * @see WCF.InlineEditor._show()
2668 _show: function(event
) {
2669 var $element
= $(event
.currentTarget
);
2670 var $elementID
= $element
.data('elementID');
2672 if (!this._dropdowns
[$elementID
]) {
2673 var $dropdownMenu
= $element
.next('.dropdownMenu');
2675 if ($dropdownMenu
) {
2676 this._dropdowns
[$elementID
] = $dropdownMenu
;
2677 WCF
.Dropdown
.initDropdown(this._getTriggerElement(this._elements
[$elementID
]), true);
2681 return this._super(event
);
2685 * Shows the dialog to enter a reason for executing the option with the
2688 * @param string optionName
2690 _showReasonDialog: function(userID
, optionName
) {
2691 var $languageItem
= 'wcf.user.' + optionName
+ '.reason.description';
2692 var $reasonDescription
= WCF
.Language
.get($languageItem
);
2694 WCF
.System
.Confirmation
.show(WCF
.Language
.get('wcf.user.' + optionName
+ '.confirmMessage'), $.proxy(function(action
) {
2695 if (action
=== 'confirm') {
2696 this._executeReasonAction(userID
, optionName
, $('#wcfSystemConfirmationContent').find('textarea').val());
2698 }, this), { }, $('<fieldset><dl><dt>' + WCF
.Language
.get('wcf.global.reason') + '</dt><dd><textarea cols="40" rows="4" />' + ($reasonDescription
!= $languageItem
? '<small>' + $reasonDescription
+ '</small>' : '') + '</dd></dl></fieldset>'));
2702 * @see WCF.InlineEditor._updateState()
2704 _updateState: function(data
) {
2705 this._notification
.show();
2707 for (var $i
= 0, $length
= this._updateData
.length
; $i
< $length
; $i
++) {
2708 var $data
= this._updateData
[$i
];
2709 var $element
= $('#' + $data
.elementID
);
2711 for (var $property
in $data
.data
) {
2712 $element
.data($property
, $data
.data
[$property
]);
2718 * @see WCF.InlineEditor._validate()
2720 _validate: function(elementID
, optionName
) {
2721 var $user
= $('#' + elementID
);
2723 switch (optionName
) {
2726 if (!this._getPermission('canBanUser')) {
2730 if (optionName
== 'ban') {
2731 return !$user
.data('banned');
2734 return $user
.data('banned');
2738 case 'disableAvatar':
2739 case 'enableAvatar':
2740 if (!this._getPermission('canDisableAvatar')) {
2744 if (optionName
== 'disableAvatar') {
2745 return !$user
.data('disableAvatar');
2748 return $user
.data('disableAvatar');
2752 case 'disableSignature':
2753 case 'enableSignature':
2754 if (!this._getPermission('canDisableSignature')) {
2758 if (optionName
== 'disableSignature') {
2759 return !$user
.data('disableSignature');
2762 return $user
.data('disableSignature');
2767 return this._getPermission('canEditUser');
2775 * Sets a permission.
2777 * @param string permission
2778 * @param integer value
2780 setPermission: function(permission
, value
) {
2781 this._permissions
[permission
] = value
;
2787 * @param object permissions
2789 setPermissions: function(permissions
) {
2790 for (var $permission
in permissions
) {
2791 this.setPermission($permission
, permissions
[$permission
]);