<
From version < 2.1 >
edited by Administrator
on 2017/04/21 12:06
To version < 4.1 >
edited by Administrator
on 2018/04/19 10:35
>
Change comment: Install extension [com.xwiki.store:application-store-ui-1.7.1]

Summary

Details

Page properties
Title
... ... @@ -1,1 +1,0 @@
1 -Pricing tab
Hidden
... ... @@ -1,1 +1,1 @@
1 -false
1 +true
Content
... ... @@ -1,46 +1,307 @@
1 -{{velocity}}
2 -= Extension price =
3 -#if("$!price" == '' && $hasAdmin)
1 +{{include reference="Store.Code.Macros" /}}
4 4  
5 - {{error}}Admin error: The price field is empty. Please set a price for this extension in the **Store.PayingApps.Code.PayingAppsClass**.{{/error}}
3 +{{velocity output="false"}}
4 +#macro (getPriceMatrix $skus)
5 + #set ($priceMatrix = {
6 + 'columns': $collectionstool.sortedSet,
7 + 'rows': $collectionstool.orderedMap
8 + })
9 + #foreach ($sku in $skus)
10 + #set ($support = "$!sku.support")
11 + #set ($users = $mathtool.toNumber($sku.users))
12 + #set ($price = "$!sku.price")
13 + #if ($support && $users && $price)
14 + #set ($pricePerUsers = $priceMatrix.rows.get($support))
15 + #if (!$pricePerUsers)
16 + #set ($pricePerUsers = {})
17 + #set ($discard = $priceMatrix.rows.put($support, $pricePerUsers))
18 + #end
19 + #set ($discard = $pricePerUsers.put($users, $price))
20 + #set ($discard = $priceMatrix.columns.add($users))
21 + #end
22 + #end
23 +#end
6 6  
7 - #set($price = "{{{--}}}")
25 +#macro (findSKUMatchingCurrentLicense $priceMatrix $minUserCount $currentLicenseDetails)
26 + #set ($skuMatchingCurrentLicense = $NULL)
27 + #if ($priceMatrix.rows.containsKey($currentLicenseDetails.support))
28 + ## Select the best match for the specified support level.
29 + #foreach ($column in $priceMatrix.columns)
30 + #set ($price = $priceMatrix.rows.get($currentLicenseDetails.support).get($column))
31 + #if ($price && $column >= $mathtool.max($minUserCount, $currentLicenseDetails.maxUserCount))
32 + #set ($skuMatchingCurrentLicense = "$currentLicenseDetails.support,$column")
33 + #break
34 + #end
35 + #end
36 + #end
37 + #if (!$skuMatchingCurrentLicense)
38 + ## Select the best match for the specified user limit.
39 + #foreach ($entry in $priceMatrix.rows.entrySet())
40 + #foreach ($column in $priceMatrix.columns)
41 + #set ($price = $entry.value.get($column))
42 + #if ($price && $column >= $mathtool.max($minUserCount, $currentLicenseDetails.maxUserCount))
43 + #set ($skuMatchingCurrentLicense = "$entry.key,$column")
44 + #break
45 + #end
46 + #end
47 + #if ($skuMatchingCurrentLicense)
48 + #break
49 + #end
50 + #end
51 + #end
8 8  #end
9 9  
10 -This application costs **$price euros/year** and you get the following:
54 +#macro (displayPriceMatrix $priceMatrix $minUserCount $currentLicenseDetails $readOnly)
55 + <table class="prices">
56 + <tr>
57 + <th class="legend">$escapetool.xml($services.localization.render('store.buyLicense.support'))
58 + / $escapetool.xml($services.localization.render('store.buyLicense.users'))</th>
59 + #foreach ($column in $priceMatrix.columns)
60 + <th class="users#if ($column < $minUserCount) disabled#end"
61 + title="$escapetool.xml($services.localization.render('store.buyLicense.users.hint', [$column]))"
62 + >$escapetool.xml($column)<span class="icon">$services.icon.renderHTML('user')</span></th>
63 + #end
64 + </tr>
65 + #set ($selectedSKU = $NULL)
66 + #if (!$readOnly && $currentLicenseDetails)
67 + #findSKUMatchingCurrentLicense($priceMatrix $minUserCount $currentLicenseDetails)
68 + #set ($selectedSKU = $skuMatchingCurrentLicense)
69 + #end
70 + #foreach ($entry in $priceMatrix.rows.entrySet())
71 + <tr class="support-$escapetool.xml($entry.key)">
72 + <th><a tabindex="0" role="button" data-toggle="popover" data-trigger="focus" data-html="true"
73 + title="$escapetool.xml($services.localization.render("store.buyLicense.support.${entry.key}.title"))"
74 + data-content="$escapetool.xml($services.localization.render(
75 + "store.buyLicense.support.${entry.key}.description"))"
76 + >$escapetool.xml($services.localization.render("store.buyLicense.support.$entry.key"))<span
77 + class="icon">$services.icon.renderHTML('info')</span></a></th>
78 + #foreach ($column in $priceMatrix.columns)
79 + #set ($price = $entry.value.get($column))
80 + #if ($price)
81 + #set ($sku = "$entry.key,$column")
82 + #set ($disabled = $column < $minUserCount)
83 + #if (!$disabled && !$selectedSKU && !$readOnly)
84 + #set ($selectedSKU = $sku)
85 + #end
86 + <td class="price price-euro#if ($disabled) disabled#elseif ($selectedSKU == $sku) active#end"
87 + data-support="$escapetool.xml($entry.key)" data-users="$escapetool.xml($column)">
88 + <label>#if (!$readOnly)<input type="radio" name="sku" value="$escapetool.xml($sku)" required="required"
89 + #if ($disabled)disabled="disabled"#elseif ($selectedSKU == $sku)checked="checked"#end
90 + />#end$escapetool.xml($price)</label>
91 + </td>
92 + #else
93 + <td/>
94 + #end
95 + #end
96 + </tr>
97 + #end
98 + </table>
99 +#end
11 11  
12 - (% class="col-xs-12 col-lg-12" id="benefits" %) (((
13 - (% class="col-xs-12 col-s-4 col-lg-4" %) (((
14 - image:key.png
15 - == 1 year license ==
16 - By purchasing an XWiki Application License, you'll benefit from it during one year.
17 - )))
18 - (% class="col-xs-12 col-s-4 col-lg-4" %) (((
19 - image:recycle.png
20 - == Free updates ==
21 - You benefit from all the application updates during one year. You are always up to date.
22 - )))
23 - (% class="col-xs-12 col-s-4 col-lg-4" %) (((
24 - image:tool.png
25 - == Support included ==
26 - If you are facing an issue, you can reach the XWiki support. Our team is always available to help.
27 - )))
28 - )))
101 +#macro (getLicenseDetails)
102 + #set ($licenseDetails = {})
103 + #foreach ($name in ['firstName', 'lastName', 'email', 'instanceId'])
104 + #set ($discard = $licenseDetails.put($name, $request.session.getAttribute("com.xwiki.store.buyer.$name")))
105 + #end
106 + #set ($licenseDetails.featureId = $doc.getValue('id'))
107 + #set ($licenseDetails.extensionVersion = $request.version)
108 + #if ("$!licenseDetails.extensionVersion" == '')
109 + ## Use the latest stable version.
110 + #set ($versions = $services.extension.resolveVersions($licenseDetails.featureId, 0, -1))
111 + ## The versions are returned in ascending order and we want the latest.
112 + ## Note that we can't access the last item directly. We're forced to iterate.
113 + #foreach ($version in $versions)
114 + #if ($version.type == 'STABLE')
115 + #set ($licenseDetails.extensionVersion = $version.value)
116 + #end
117 + #end
118 + #end
119 + #set ($licenseDetails.licenseType = 'paid')
120 +#end
29 29  
30 -{{comment}}
31 -* __1 year license__: By purchasing an XWiki Application License, you'll benefit from it during one year.
32 -* __Free updates__: You benefit from all the application updates during one year. You are always up to date.
33 -* __Support included__: If you are facing an issue, you can reach the [[XWiki support>>mailto:support@xwiki.com]]. Our team is always available to help.
34 -{{/comment}}
122 +#macro (benefits)
123 + <p>What do you get when you purchase an XWiki extension?</p>
124 + <div class="row" id="benefits">
125 + <div class="col-xs-12 col-sm-4">
126 + <div class="icon">$services.icon.renderHTML('key')</div>
127 + <h2>1 year license</h2>
128 + <p>By purchasing an XWiki extension license, you'll benefit from it during one year.</p>
129 + </div>
130 + <div class="col-xs-12 col-sm-4">
131 + <div class="icon">$services.icon.renderHTML('refresh')</div>
132 + <h2>Free updates</h2>
133 + <p>You benefit from all the extension updates during one year. You are always up to date.</p>
134 + </div>
135 + <div class="col-xs-12 col-sm-4">
136 + <div class="icon">$services.icon.renderHTML('wrench')</div>
137 + <h2>Support included</h2>
138 + <p>If you are facing an issue, you can reach the XWiki support. Our team is always available to help.</p>
139 + </div>
140 + </div>
141 +#end
35 35  
36 -== VAT information ==
143 +#macro (getCurrentLicense $licenseDetails)
144 + ## Get the best license for the specified instance and feature.
145 + #set ($currentLicenseDetails = $NULL)
146 + #getLicenseQuery($licenseDetails.instanceId $licenseDetails.featureId $query)
147 + #set ($results = $query.setLimit(1).execute())
148 + #if ($results && $results.size() > 0)
149 + #set ($currentLicenseDetailsDocument = $xwiki.getDocument($results[0]))
150 + #set ($oldLicenseDetails = $licenseDetails)
151 + #readLicenseDetailsFromDocument($currentLicenseDetailsDocument)
152 + ## Check if the best license is still active.
153 + #if ($licenseDetails.expirationDate && $licenseDetails.expirationDate.time > $datetool.date.time)
154 + #set ($currentLicenseDetails = $licenseDetails)
155 + #end
156 + #set ($licenseDetails = $oldLicenseDetails)
157 + #end
158 +#end
37 37  
38 -* If you are in the EU and have a VAT number there is no VAT to add to the price
39 -* If you are in the EU and don't have a VAT number there is the VAT of your country to add to the price
40 -* If you are outside the EU there is no VAT to add to the price
160 +#macro (displayCurrentLicense $currentLicenseDetails)
161 + #if ($currentLicenseDetails)
162 + <dt>
163 + <label>$escapetool.xml($services.localization.render('store.buyLicense.currentLicense'))</label>
164 + </dt>
165 + <dd>
166 + ##
167 + ## Extension name
168 + ##
169 + #if ("$!currentLicenseDetails.extensionName" == '')
170 + #getLicensedExtension($currentLicenseDetails)
171 + #if ($extension)
172 + #set ($currentLicenseDetails.extensionName = $extension.name)
173 + #else
174 + #set ($currentLicenseDetails.extensionName = $currentLicenseDetails.featureId)
175 + #end
176 + #end
177 + ##
178 + ## User limit
179 + ##
180 + #set ($LONG_MAX_VALUE = $mathtool.pow(2,63))
181 + #if (!$currentLicenseDetails.maxUserCount || $currentLicenseDetails.maxUserCount == $LONG_MAX_VALUE)
182 + ## Unlimited user count.
183 + #set ($currentLicenseDetails.maxUserCount = -1)
184 + #end
185 + ##
186 + ## Days left
187 + ##
188 + #set ($remainingTime = $currentLicenseDetails.expirationDate.time - $datetool.date.time)
189 + #set ($daysLeft = $xwiki.jodatime.getDuration($remainingTime).standardDays)
190 + ##
191 + ## Support
192 + ##
193 + #if ("$!currentLicenseDetails.support" != '')
194 + #set ($support = $services.localization.render("store.buyLicense.support.$currentLicenseDetails.support"))
195 + $escapetool.xml($services.localization.render('store.buyLicense.currentLicense.summary',
196 + [$currentLicenseDetails.extensionName, $support, $currentLicenseDetails.maxUserCount, $daysLeft]))
197 + #else
198 + <div class="text-info">
199 + $services.icon.renderHTML('info')
200 + $escapetool.xml($services.localization.render('store.buyLicense.currentLicense.summaryWithoutSupport',
201 + [$currentLicenseDetails.extensionName, $currentLicenseDetails.maxUserCount, $daysLeft]))
202 + </div>
203 + <p class="xHint">$escapetool.xml($services.localization.render('store.buyLicense.currentLicense.hint'))</p>
204 + #end
205 + </dd>
206 + #end
207 +#end
41 41  
42 -== How to buy ==
209 +#macro (buyLicenseForm $licenseDetails $priceMatrix $minUserCount)
210 + <form id="buyLicense" class="xform" action="" method="post">
211 + <p>Fill in the form below to get your license.</p>
212 + <div class="hidden">
213 + <input type="hidden" name="instanceId" value="$!escapetool.xml($licenseDetails.instanceId)"/>
214 + <input type="hidden" name="featureId" value="$!escapetool.xml($licenseDetails.featureId)"/>
215 + <input type="hidden" name="extensionVersion" value="$!escapetool.xml($licenseDetails.extensionVersion)"/>
216 + </div>
217 + <dl>
218 + <dt>
219 + <label>$escapetool.xml($services.localization.render('store.buyLicense.buyer'))</label>
220 + </dt>
221 + <dd>
222 + $!licenseDetails.firstName $!licenseDetails.lastName, $licenseDetails.email
223 + <a href="#editBuyer" class="editBuyer"
224 + title="$escapetool.xml($services.localization.render('store.buyLicense.buyer.edit'))"
225 + >$services.icon.renderHTML('pencil')</a>
226 + </dd>
227 + <dt class="hidden">
228 + <label for="firstName">
229 + $escapetool.xml($services.localization.render('store.buyLicense.firstName'))
230 + </label>
231 + </dt>
232 + <dd class="hidden">
233 + <input type="text" name="firstName" id="firstName" value="$!escapetool.xml($licenseDetails.firstName)"
234 + required="required"/>
235 + </dd>
236 + <dt class="hidden">
237 + <label for="lastName">
238 + $escapetool.xml($services.localization.render('store.buyLicense.lastName'))
239 + </label>
240 + </dt>
241 + <dd class="hidden">
242 + <input type="text" name="lastName" id="lastName" value="$!escapetool.xml($licenseDetails.lastName)"
243 + required="required"/>
244 + </dd>
245 + <dt class="hidden">
246 + <label for="email">
247 + $escapetool.xml($services.localization.render('store.buyLicense.email'))
248 + </label>
249 + <span class="xHint">
250 + $escapetool.xml($services.localization.render('store.buyLicense.email.hint'))
251 + </span>
252 + </dt>
253 + <dd class="hidden">
254 + <input type="email" name="email" id="email" value="$!escapetool.xml($licenseDetails.email)"
255 + class="form-control" required="required"/>
256 + </dd>
257 + #getCurrentLicense($licenseDetails)
258 + #displayCurrentLicense($currentLicenseDetails)
259 + <dt>
260 + <label>$escapetool.xml($services.localization.render('store.buyLicense.options'))</label>
261 + <span class="xHint">$escapetool.xml($services.localization.render('store.buyLicense.options.hint'))</span>
262 + </dt>
263 + <dd>
264 + #displayPriceMatrix($priceMatrix $minUserCount $currentLicenseDetails)
265 + </dd>
266 + </dl>
267 + #benefits
268 + <p>
269 + <input type="submit" class="button btn-success"#if (!$selectedSKU) disabled="disabled" #end
270 + value="$escapetool.xml($services.localization.render('store.buyLicense.submit'))"/>
271 + </p>
272 + </form>
273 +#end
43 43  
44 -## Note: this is temporary until we implement the buy button
45 -To buy, (% id='install' %)[[install this extension from inside your XWiki instance and follow the instructions>>path:#installation]](%%).
275 +#macro (accessPurchaseOrderForm $licenseDetails)
276 + <form id="accessPurchaseOrder" class="hidden" action="$services.extension.store.activePurchaseOrderURL" method="post">
277 + <input type="hidden" name="instanceId" value="$!escapetool.xml($licenseDetails.instanceId)"/>
278 + <input type="hidden" name="email" value="$!escapetool.xml($licenseDetails.email)"/>
279 + <input type="submit"/>
280 + </form>
281 +#end
46 46  {{/velocity}}
283 +
284 +{{velocity}}
285 +{{html clean="false"}}
286 +#set ($discard = $xwiki.ssx.use('Store.Content.Pricing'))
287 +#set ($discard = $xwiki.jsx.use('Store.Content.Pricing'))
288 +#getLicenseDetails
289 +#getPriceMatrix($prices.skus)
290 +#set ($minUserCount = $request.session.getAttribute('com.xwiki.store.buyer.userCount'))
291 +#if (!$minUserCount)
292 + #set ($minUserCount = 1)
293 +#end
294 +#if ("$!licenseDetails.instanceId" != '')
295 + #buyLicenseForm($licenseDetails $priceMatrix $minUserCount)
296 + #accessPurchaseOrderForm($licenseDetails)
297 +#else
298 + <h2>Options</h2>
299 + <p>The price varies depending on the support level and the number of users.</p>
300 + #displayPriceMatrix($priceMatrix $minUserCount $NULL true)
301 + <h2>Benefits</h2>
302 + #benefits
303 + <h2>How to Buy</h2>
304 + <p>To buy, install this extension from inside your XWiki instance and <a href="#installation">follow the instructions</a>.</p>
305 +#end
306 +{{/html}}
307 +{{/velocity}}
key.png
Author
... ... @@ -1,1 +1,0 @@
1 -XWiki.Admin
Size
... ... @@ -1,1 +1,0 @@
1 -1.9 KB
Content
recycle.png
Author
... ... @@ -1,1 +1,0 @@
1 -XWiki.Admin
Size
... ... @@ -1,1 +1,0 @@
1 -1.9 KB
Content
tool.png
Author
... ... @@ -1,1 +1,0 @@
1 -XWiki.Admin
Size
... ... @@ -1,1 +1,0 @@
1 -1.9 KB
Content
XWiki.JavaScriptExtension[0]
Caching policy
... ... @@ -1,0 +1,1 @@
1 +long
Code
... ... @@ -1,0 +1,57 @@
1 +require(['jquery', 'bootstrap'], function($) {
2 + // Activate the support information.
3 + $('table.prices [data-toggle="popover"]').popover();
4 +
5 + // Manage the selected SKU from the price matrix.
6 + var updateSelectedSKU = function() {
7 + $(this).closest('table.prices').find('td.price.active').removeClass('active');
8 + $(this).closest('td.price').toggleClass('active');
9 + }
10 + $('form table.prices td.price input:checked').each(updateSelectedSKU);
11 + $('form table.prices').on('change', 'td.price input[type="radio"]', updateSelectedSKU);
12 +
13 + var showBuyerFields = function(editBuyerLink) {
14 + editBuyerLink.closest('dd').hide().prev('dt').hide()
15 + .nextAll('.hidden').removeClass('hidden')
16 + .first().css('margin-top', 0);
17 + };
18 +
19 + // Edit buyer details link.
20 + $('a.editBuyer').click(function (event) {
21 + event.preventDefault();
22 + showBuyerFields($(this));
23 + });
24 +
25 + // We need to register the event directly on the input field because it doesn't bubble up.
26 + $('form#buyLicense input').on('invalid', function() {
27 + if ($(this).is(':hidden')) {
28 + showBuyerFields($(this).closest('form').find('a.editBuyer'));
29 + }
30 + });
31 +
32 + $('form#buyLicense').submit(function(event) {
33 + event.preventDefault();
34 + var buyLicenseForm = $(this);
35 + var submitButton = buyLicenseForm.find('input[type="submit"]').prop('disabled', true);
36 + var progressNotification = new XWiki.widgets.Notification($jsontool.serialize($services.localization.render(
37 + 'store.buyLicense.submit.inProgress')), 'inprogress');
38 + var url = new XWiki.Document('BuyLicense', 'Store').getURL('get', 'outputSyntax=plain');
39 + $.post(url, buyLicenseForm.serialize()).done(function(result) {
40 + if (result && result.order) {
41 + progressNotification.replace(new XWiki.widgets.Notification($jsontool.serialize(
42 + $services.localization.render('store.buyLicense.submit.done')), 'done'));
43 + var accessPurchaseOrderForm = $('form#accessPurchaseOrder');
44 + accessPurchaseOrderForm.find('input[name="email"]').val(buyLicenseForm.find('input[name="email"]').val());
45 + accessPurchaseOrderForm.submit();
46 + } else {
47 + progressNotification.replace(new XWiki.widgets.Notification($jsontool.serialize(
48 + $services.localization.render('store.buyLicense.submit.failed')), 'error'));
49 + }
50 + }).fail(function() {
51 + progressNotification.replace(new XWiki.widgets.Notification($jsontool.serialize(
52 + $services.localization.render('store.buyLicense.submit.failed')), 'error'));
53 + }).always(function() {
54 + submitButton.prop('disabled', false);
55 + });
56 + });
57 +});
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,21 @@
1 +table.prices a[data-toggle="popover"] {
2 + color: inherit;
3 + text-decoration: none;
4 +}
5 +
6 +table.prices th span.icon {
7 + margin-left: .3em;
8 +}
9 +
10 +table.prices th.users,
11 +table.prices td.price {
12 + text-align: right;
13 +}
14 +
15 +table.prices td.price-euro label {
16 + display: block;
17 +}
18 +
19 +table.prices td.price-euro label:after {
20 + content: ' \20ac';
21 +}
Content Type
... ... @@ -1,0 +1,1 @@
1 +CSS
Parse content
... ... @@ -1,0 +1,1 @@
1 +No
Use this extension
... ... @@ -1,0 +1,1 @@
1 +onDemand
XWiki SAS Copyright © 2024