From empty
To version 1.1
edited by superadmin
on 2017/11/28 14:52
Change comment: Install extension [org.xwiki.platform:xwiki-platform-messagestream-ui/9.9]

Summary

Details

Page properties
Title
... ... @@ -1,0 +1,1 @@
1 +Message Sender Macro
Parent
... ... @@ -1,0 +1,1 @@
1 +Main.WebHome
Author
... ... @@ -1,1 +1,1 @@
1 -XWiki.XWikiGuest
1 +xwiki:XWiki.superadmin
Hidden
... ... @@ -1,1 +1,1 @@
1 -false
1 +true
Content
... ... @@ -1,0 +1,1 @@
1 +{{messageSender/}}
XWiki.JavaScriptExtension[0]
Caching policy
... ... @@ -1,0 +1,1 @@
1 +long
Code
... ... @@ -1,0 +1,138 @@
1 +#set ($userSuggestScope = 'local')
2 +#if ($services.wiki.user && $services.wiki.user.userScope != "LOCAL_ONLY")
3 + #set ($userSuggestScope = 'global')
4 +#end
5 +var XWiki = (function (XWiki) {
6 +// Start XWiki augmentation.
7 +/**
8 + * Extends the UserPicker in order to display the selected user/group inline after the target text input.
9 + */
10 +var CustomUserPicker = Class.create(XWiki.widgets.UserPicker, {
11 + // @Override
12 + _createSelectionManager: function($super, options) {
13 + var selectionManager = $super(Object.extend(options, {
14 + listInsertionPosition : 'after',
15 + acceptFreeText : false
16 + }));
17 + // Overwrite the way the selected item is displayed.
18 + selectionManager.displayItem = function(suggestion) {
19 + var targetInfo = new Element('span').update(suggestion.info).insert(this.createDeleteTool());
20 + var targetClass = this.suggest.sources[0].script.indexOf('uorg=group') > 0 ? 'target-group' : 'target-user';
21 + return new Element('li', {'class': targetClass}).insert(targetInfo).insert(this.createItemInput(suggestion));
22 + }.bind(selectionManager);
23 + return selectionManager;
24 + }
25 +});
26 +
27 +XWiki.MessageStream = Class.create({
28 + targetsWithName : ['user', 'group'],
29 + suggestParameters : {
30 + user : {
31 + script: '$doc.getURL("get", "xpage=uorgsuggest&uorg=user&wiki=${userSuggestScope}")&',
32 + noresults: "$escapetool.javascript($services.localization.render('core.widgets.userPicker.noResults'))"
33 + },
34 + group : {
35 + script: "$doc.getURL('get', 'xpage=uorgsuggest&uorg=group')&",
36 + noresults: "$escapetool.javascript($services.localization.render('core.widgets.groupPicker.noResults'))"
37 + }
38 + },
39 + initialize : function() {
40 + this.prepareForms();
41 + this.enhanceSelect();
42 + },
43 + prepareTargetInput : function(event, element) {
44 + var targetType = element.options[element.selectedIndex].value;
45 + element.className = targetType;
46 + if (!element.__targetNameInput) {return;}
47 + if (this.targetsWithName.indexOf(targetType) < 0) {
48 + element.__targetNameInput.addClassName('hidden');
49 + if (element.__targetNameInput.__x_suggest) {
50 + element.__targetNameInput.__x_suggest.detach();
51 + }
52 + } else {
53 + // Focus the text input so that the place-holder value is cleared if present. Otherwise the user picker will treat
54 + // the place-holder value as if it was typed by the user and will automatically select the corresponding suggestion.
55 + element.__targetNameInput.removeClassName('hidden').activate();
56 + // Defer the creation of the user picker to allow the focus listeners to be called first (in order to clear the
57 + // place-holder value).
58 + this.suggestParameters[targetType] && function() {
59 + new CustomUserPicker(element.__targetNameInput, this.suggestParameters[targetType]);
60 + }.bind(this).defer();
61 + }
62 + },
63 + enhanceSelect: function () {
64 + $$('.messagestream select[name="visibilityLevel"]').each(function(element) {
65 + element.addClassName(element.options[element.selectedIndex].value);
66 + element.__targetNameInput = element.up('.messagestream').down('input[name="targetName"]');
67 + if (element.__targetNameInput && this.targetsWithName.indexOf(element.options[element.selectedIndex].value) < 0) {
68 + element.__targetNameInput.addClassName('hidden');
69 + }
70 + element.observe('change', this.prepareTargetInput.bindAsEventListener(this, element));
71 + this.prepareTargetInput(null, element);
72 + }.bind(this));
73 + },
74 + prepareForms: function() {
75 + $$('.messagestream form').each(function(msForm) {
76 + msForm.action = msForm.action.replace(/xredirect=.*$/, 'xpage=plain')
77 + msForm.observe('submit', function(event) {
78 + event.stop();
79 + if (msForm._disabled == true || msForm.down('textarea').value.strip() == '') {
80 + return;
81 + }
82 + new Ajax.Request(
83 + msForm.action, {
84 + parameters: msForm.serialize(true),
85 + onCreate: function() {
86 + msForm._disabled = true;
87 + msForm._notification = new XWiki.widgets.Notification("$services.localization.render('xe.activity.messages.submit.inProgress')", 'inprogress');
88 + },
89 + onSuccess: function() {
90 + if (msForm) {
91 + msForm.messagestream_message.value = '';
92 + }
93 + if (msForm && msForm._notification) {
94 + msForm._notification.hide();
95 + }
96 + msForm._notification = new XWiki.widgets.Notification("$services.localization.render('xe.activity.messages.submit.success')", 'done');
97 +
98 + document.fire('xwiki:activity:newActivity', msForm);
99 + },
100 + onFailure: function(response) {
101 + var failureReason = '';
102 + if (response.statusText == '' /* No response */ || response.status == 12031 /* In IE */) {
103 + failureReason = 'Server not responding';
104 + } else {
105 + failureReason = response.statusText;
106 + }
107 + if (msForm) {
108 + msForm._disabled = false
109 + if (msForm._notification) {
110 + msForm._notification.hide();
111 + }
112 + msForm._notification = new XWiki.widgets.Notification("$services.localization.render('xe.activity.messages.submit.failed'): " + failureReason, 'error');
113 + }
114 + },
115 + on1223 : function(response) { /*SUCCESS*/
116 + response.request.options.onSuccess(response);
117 + },
118 + on0 : function(response) { /*FAILURE*/
119 + response.request.options.onFailure(response);
120 + },
121 + onComplete: function() {
122 + msForm._disabled = false;
123 + }.bind(this)
124 + }
125 + );
126 + }.bindAsEventListener(this));
127 + }.bind(this));
128 + }
129 +});
130 +
131 +var init = function() {
132 + return new XWiki.MessageStream();
133 +};
134 +(XWiki.domIsLoaded && init()) || document.observe('xwiki:dom:loaded', init);
135 +
136 +// End XWiki augmentation.
137 +return XWiki;
138 +}(XWiki || {}));
Name
... ... @@ -1,0 +1,1 @@
1 +User status update
Parse content
... ... @@ -1,0 +1,1 @@
1 +Yes
Use this extension
... ... @@ -1,0 +1,1 @@
1 +onDemand
XWiki.StyleSheetExtension[0]
Caching policy
... ... @@ -1,0 +1,1 @@
1 +long
Code
... ... @@ -1,0 +1,29 @@
1 +#template('colorThemeInit.vm')
2 +
3 +.messagestream-tools {
4 + position: relative;
5 + margin: .5em 0 1em;
6 +}
7 +.messagestream-tools .accepted-suggestions {
8 + display: inline;
9 +}
10 +.messagestream-tools .accepted-suggestions .target-user,
11 +.messagestream-tools .accepted-suggestions .target-group {
12 + background: none no-repeat scroll left center transparent;
13 + display: inline-block;
14 + margin-right: 1em;
15 + padding: 0 1px 0 18px;
16 +}
17 +.messagestream-tools .accepted-suggestions .target-user {
18 + background-image: url("$xwiki.getSkinFile('icons/silk/user.png')");
19 +}
20 +.messagestream-tools .accepted-suggestions .target-group {
21 + background-image: url("$xwiki.getSkinFile('icons/silk/group.png')");
22 +}
23 +.messagestream select {
24 + width: auto;
25 +}
26 +.messagestream input.targetName {
27 + margin-right: .3em;
28 + width: auto;
29 +}
Content Type
... ... @@ -1,0 +1,1 @@
1 +CSS
Name
... ... @@ -1,0 +1,1 @@
1 +Message stream form styling
Parse content
... ... @@ -1,0 +1,1 @@
1 +Yes
Use this extension
... ... @@ -1,0 +1,1 @@
1 +onDemand
XWiki.WikiMacroClass[0]
Macro code
... ... @@ -1,0 +1,185 @@
1 +{{velocity output='false'}}
2 +#* Duplicate code (from Main.Activity) START *#
3 +##
4 +## User status configuration
5 +## -------------------------------------------------------------
6 +#set ($config = 'XWiki.MessageStreamConfig')
7 +#set ($configClass = $xwiki.getDocument($config).getxWikiClass())
8 +#set ($isMessageStreamActive = $services.messageStream.isActive())
9 +
10 +#set ($currentUser = $services.model.serialize($xcontext.userReference, 'default'))
11 +
12 +#set ($activityActionsMap = {
13 + 'publicMessage': 'icons/silk/user_comment.png',
14 + 'personalMessage': 'icons/silk/user_comment.png',
15 + 'directMessage': 'icons/silk/user_go.png',
16 + 'groupMessage': 'icons/silk/group_go.png'
17 +})
18 +##
19 +#**
20 + * Display user avatar and action message
21 + *#
22 +#macro(activitySnapshot $eventUser $eventType)
23 + <span class='activitySnapshot'>
24 + #if ($eventUser != 'XWiki.XWikiGuest')
25 + <a href="$xwiki.getURL($eventUser)">#smallUserAvatar("$!eventUser")</a>
26 + #else
27 + #smallUserAvatar("$!eventUser")
28 + #end
29 + <img class='activityActionAvatar' src="$xwiki.getSkinFile($activityActionsMap.get($eventType), true)" alt="$services.localization.render("xe.activity.action.${eventType}", [$relatedEventsNo])" title="$services.localization.render("xe.activity.action.${eventType}", [$relatedEventsNo])" />
30 + </span>
31 +#end
32 +##
33 +#* Duplicate code END *#
34 +##
35 +## Skin Extensions
36 +##--------------------------------------------------------------
37 +#set ($discard = $xwiki.jsfx.use('uicomponents/suggest/suggestPicker.js'))
38 +#set ($discard = $xwiki.jsfx.use('uicomponents/widgets/userpicker/userPicker.js'))
39 +#set ($discard = $xwiki.ssx.use('Main.Activity'))
40 +#set ($discard = $xwiki.ssx.use('Main.MessageSenderMacro'))
41 +#set ($discard = $xwiki.jsx.use('Main.MessageSenderMacro'))
42 +{{/velocity}}
43 +
44 +{{velocity}}
45 +#if ($isMessageStreamActive)
46 + #set ($xredirect = $doc.getURL($xcontext.action, $!{request.queryString}))
47 + #set ($errorMessageKeyPrefix = "messageSender.post.error.")
48 + #set ($errorMessage = $request.session.getAttribute("${errorMessageKeyPrefix}${xredirect}"))
49 + #if ("$!errorMessage" != '')
50 + ## Clean the error and display the message.
51 + #set ($discard = $request.session.removeAttribute("${errorMessageKeyPrefix}${xredirect}"))
52 + {{error}}$errorMessage{{/error}}
53 +
54 + ##
55 + ## Handle postMessage action here so that the macro can be self contained.
56 + ##
57 + #elseif ("$!{request.xaction}" != '')
58 + #if ("$!{request.xaction}" == 'postMessage')
59 + #if(!$services.csrf.isTokenValid(${request.form_token}))
60 + #set($redirectURL = $services.csrf.getResubmissionURL())
61 + $response.sendRedirect($redirectURL)
62 + #else
63 + #set ($message = "$!{request.messagestream_message.trim()}")
64 + #if ($message == '')
65 + ## Do nothing with empty messages
66 + #if ("$!{request.xredirect}" != '')
67 + $response.sendRedirect(${request.xredirect})
68 + #end
69 + #else
70 + #set ($success = false)
71 + #if (!$isGuest)
72 + #set ($messageType = "$!{request.visibilityLevel}")
73 + #if ($messageType == 'everyone')
74 + #set ($success = $services.messageStream.postPublicMessage($message))
75 + #elseif ($messageType == 'followers')
76 + #set ($success = $services.messageStream.postPersonalMessage($message))
77 + #elseif ($messageType == 'group')
78 + #set ($success = $services.messageStream.postMessageToGroup($message, $services.model.resolveDocument("$!{request.targetName}")))
79 + #elseif ($messageType == 'user')
80 + #set ($success = $services.messageStream.postDirectMessageToUser($message, $services.model.resolveDocument("$!{request.targetName}")))
81 + #end
82 + #end
83 + #if (!$success)
84 + #if ($request.xpage == 'plain')
85 + #if ($isGuest)
86 + $response.setStatus(401)## Unauthorized
87 + #else
88 + $response.setStatus(403)## Forbidden
89 + #end
90 + $services.localization.render('xe.activity.messages.submit.failed')
91 + #elseif ("$!{request.xredirect}" != '')
92 + ## Pass the error message in the xredirect so that we display it in the calling page and not in the macro page.
93 + $request.session.setAttribute("${errorMessageKeyPrefix}${request.xredirect}", $services.localization.render('xe.activity.messages.submit.failed'))
94 + $response.sendRedirect($request.xredirect)
95 + #else
96 + {{error}}$services.localization.render('xe.activity.messages.submit.failed'){{/error}}
97 +
98 + #end
99 + #elseif ("$!{request.xredirect}" != '')
100 + $response.sendRedirect(${request.xredirect})
101 + #elseif ($request.xpage == 'plain')
102 + ## Just print something for confirmation.
103 + $services.localization.render('xe.activity.messages.submit.success')
104 + #end
105 + #end
106 + #end
107 + #end
108 + #end
109 + ##
110 + ## Display the UI. Don't display it for AJAX calls and guests.
111 + ##
112 + #if ($request.xpage != 'plain' && !$isGuest)
113 + ## When this macro is displayed in edit/inline mode, we disable the inputs and no longer display the form (because it would clash with the main form of inline edit).
114 + #set ($inEditMode = ($xcontext.action == 'inline' || $xcontext.action == 'edit'))
115 + #set ($actionQueryString = "xredirect=$escapetool.url($xredirect)")
116 + {{html}}
117 + ## Wrap the form in a div so that the layout is preserved in inline mode (where the form is stripped by the rendering).
118 + <div class='messagestream activityUser xform'>
119 + #if (!$inEditMode)
120 + <form action="${xwiki.getURL('Main.MessageSenderMacro', 'view', $!{actionQueryString})}" method='post'>
121 + #end
122 + <div class='activityContent'>
123 + #if(!$inEditMode)
124 + ## CSRF prevention
125 + <input type="hidden" name="form_token" value="$!{services.csrf.getToken()}" />
126 + <input type='hidden' name='xaction' value='postMessage' />
127 + #end
128 + #activitySnapshot($xcontext.user, 'personalMessage')
129 + <div class='messagestream-data'>
130 + <textarea name='messagestream_message' rows='3' cols='40'#if($inEditMode) disabled='disabled'#end></textarea>
131 + </div>
132 + <div class='messagestream-tools'>
133 + #set ($possibleTargets = $xcontext.macro.params.get('visibilityOptions').split('\s*,\s*'))
134 + #if (!$possibleTargets)
135 + #set ($possibleTargets = $configClass.get('visibilityLevel').getListValues())
136 + #end
137 + ##
138 + #set ($targetName = $xcontext.macro.params.get('visibilityParameter'))
139 + ##
140 + #set ($defaultTarget = $xcontext.macro.params.get('visibility'))
141 + #if (!$defaultTarget)
142 + #if ($doc.getObject('XWiki.XWikiGroups'))
143 + #set ($defaultTarget = 'group')
144 + #set ($targetName = $doc.prefixedFullName)
145 + #elseif ($doc.getObject('XWiki.XWikiUsers'))
146 + #if ($doc.prefixedFullName == $currentUser)
147 + #set ($defaultTarget = 'followers')
148 + #else
149 + #set ($defaultTarget = 'user')
150 + #set ($targetName = $doc.prefixedFullName)
151 + #end
152 + #else
153 + #set ($defaultTarget = 'everyone')
154 + #end
155 + #end
156 + <label>$services.localization.render('xe.activity.messages.visibility')
157 + <select name='visibilityLevel'#if($inEditMode) disabled='disabled'#end>
158 + #foreach ($target in $possibleTargets)
159 + <option value="${target}"#if ($defaultTarget == $target) selected='selected'#end>$services.localization.render("XWiki.MessageStreamConfig_visibilityLevel_${target}")</option>
160 + #end
161 + </select>
162 + </label>
163 + <label for="targetName$!{targetNameCounter}">
164 + <span class='hidden'>Name:</span>
165 + <input type="text" name="targetName" id="targetName$!targetNameCounter" class="targetName withTip useTitleAsTip" value="$!targetName" size="15"
166 + title="$services.localization.render('xe.activity.messages.visibility.targetName.tip')" #if ($inEditMode) disabled="disabled"#end/>
167 + </label>
168 + #if (!$targetNameCounter)
169 + #set ($targetNameCounter = 1)
170 + #else
171 + #set ($targetNameCounter = $targetNameCounter + 1)
172 + #end
173 + </div>
174 + <div class='messagestream-buttons'>
175 + <span class='butonwrapper'><input type='submit' value="$services.localization.render('xe.activity.messages.submit')" class='button'#if($inEditMode) disabled='disabled'#end/></span>
176 + </div>
177 + </div>
178 + #if (!$inEditMode)
179 + </form>
180 + #end
181 + </div>
182 + {{/html}}
183 + #end
184 +#end
185 +{{/velocity}}
Macro content type
... ... @@ -1,0 +1,1 @@
1 +No content
Default category
... ... @@ -1,0 +1,1 @@
1 +Social
Macro description
... ... @@ -1,0 +1,1 @@
1 +A control that allows users to enter messages that are handled by the MessageStream module.
Macro id
... ... @@ -1,0 +1,1 @@
1 +messageSender
Macro name
... ... @@ -1,0 +1,1 @@
1 +Message Sender
Supports inline mode
... ... @@ -1,0 +1,1 @@
1 +No
Macro visibility
... ... @@ -1,0 +1,1 @@
1 +Current Wiki
XWiki.WikiMacroParameterClass[0]
Parameter description
... ... @@ -1,0 +1,5 @@
1 +Default selected visibility when the macro is displayed.
2 +
3 +If not specified, it is determined automatically based on the page where the macro is used.
4 +
5 +Valid values are: 'everyone', 'followers', 'group' or 'user'.
Parameter name
... ... @@ -1,0 +1,1 @@
1 +visibility
XWiki.WikiMacroParameterClass[1]
Parameter description
... ... @@ -1,0 +1,1 @@
1 +Some visibility levels (like 'user' and 'group') accept a parameter. In the case of the 2 mentioned levels, the value can be a serialized reference of a user or a group document.
Parameter name
... ... @@ -1,0 +1,1 @@
1 +visibilityParameter
XWiki.WikiMacroParameterClass[2]
Parameter description
... ... @@ -1,0 +1,3 @@
1 +Comma separated list of visibility options that the macro should allow the user to choose from.
2 +
3 +This list should be a sublist of the defualt ones: 'everyone', 'followers', 'group', 'user'.
Parameter name
... ... @@ -1,0 +1,1 @@
1 +visibilityOptions