]> git.proxmox.com Git - pmg-gui.git/blame - js/mobile/quarantineview.js
quarantines: add support for a theme toggle
[pmg-gui.git] / js / mobile / quarantineview.js
CommitLineData
43f0b189
DC
1class QuarantineView extends Component {
2 constructor(config = {}) {
3 config.tpl = config.tpl || `
4 <div class="view view-quarantine">
5 <div data-name="quarantine-list" class="page">
6 <div class="navbar">
7 <div class="navbar-inner">
8 <div class="left">
f07b75b0
TL
9 <img class="logo-navbar" style="padding: 0 10px"
10 src="pve2/images/logo-128.png" height=32 />
43f0b189
DC
11 </div>
12 <div class="title">Mail Gateway</div>
13 </div>
14 </div>
15 <div class="settings-form elevation-5 fab-morph-target">
a827641e 16 <div class="block-title block-title-medium">` + gettext("Range") + `</div>
43f0b189
DC
17 <div class="list no-hairlines-md">
18 <ul>
19 <li class="item-content item-input">
20 <div class="item-inner">
fbc1a05b 21 <div class="item-title item-label">` + gettext("Since") + `</div>
43f0b189
DC
22 <div class="item-input-wrap">
23 <input type="date" name="from" placeholder="from" required validate>
24 </div>
25 </div>
26 </li>
27 <li class="item-content item-input">
28 <div class="item-inner">
fbc1a05b 29 <div class="item-title item-label">` + gettext("Until") + `</div>
43f0b189
DC
30 <div class="item-input-wrap">
31 <input type="date" name="to" placeholder="to" required validate>
32 </div>
33 </div>
34 </li>
35 </ul>
a827641e 36 <a class="button fab-close range-form">` + gettext("OK") + `</a>
43f0b189
DC
37 </div>
38 </div>
39 <div class="fab fab-morph fab-right-bottom" data-morph-to=".settings-form">
40 <a href="#">
41 <i class="icon f7-icons ios-only">calendar</i>
42 <i class="icon material-icons md-only">date_range</i>
43 </a>
44 </div>
45 <div class="toolbar subscription toolbar-hidden toolbar-bottom">
46 <div class="toolbar-inner">
47 <a class="button subscription">
48 <i class="icon f7-icons ios-only color-yellow">alert</i>
49 <i class="icon material-icons md-only color-yellow">warning</i>
50 <span class="subscription-text">
a827641e 51 ` + gettext("No valid subscription") + `
43f0b189
DC
52 </span>
53 </a>
54 </div>
55 </div>
56 <div class="page-content ptr-content">
57 <div class="ptr-preloader">
58 <div class="preloader"></div>
59 <div class="ptr-arrow"></div>
60 </div>
61 <div class="list virtual-list"></div>
62 </div>
63 </div>
64 </div>`;
65 config.itemTemplate = config.itemTemplate || `
66 <li class="swipeout">
67 <div class="swipeout-content">
68 <a href="/mail/{{id}}/" class="item-link item-content">
69 <div class="item-inner">
70 <div class="item-title">
71 <div class="item-header">{{escape from}}</div>
72 {{escape subject}}
73 </div>
74 <div class="item-after">Score: {{js "this.spamlevel || 0"}}</div>
75 </div>
76 </a>
77 </div>
78 <div class="swipeout-actions-left">
79 <a href="/mail/{{id}}/deliver" class="color-green swipeout-close">
80 <i class="icon f7-icons ios-only">paper_plane</i>
81 <i class="icon material-icons md-only">send</i>
a827641e 82 &nbsp;` + gettext("Deliver") + `
43f0b189
DC
83 </a>
84 <a href="/mail/{{id}}/whitelist" class="swipeout-close">
85 <i class="icon f7-icons ios-only">check</i>
86 <i class="icon material-icons md-only">check</i>
a827641e 87 &nbsp;` + gettext("Whitelist") + `
43f0b189
DC
88 </a>
89 </div>
90 <div class="swipeout-actions-right">
91 <a href="/mail/{{id}}/blacklist" class="color-orange swipeout-close">
92 <i class="icon f7-icons ios-only">close</i>
93 <i class="icon material-icons md-only">close</i>
a827641e 94 &nbsp;` + gettext("Blacklist") + `
43f0b189
DC
95 </a>
96 <a href="/mail/{{id}}/delete" class="color-red swipeout-close">
97 <i class="icon f7-icons ios-only">trash</i>
98 <i class="icon material-icons md-only">delete</i>
a827641e 99 &nbsp;` + gettext("Delete") + `
43f0b189
DC
100 </a>
101 </div>
102 </li>`;
103 config.dividerTemplate = config.dividerTemplate ||
104 '<li class="item-divider">{{group}}</li>';
105 super(config);
106
107 var me = this;
108
109 me._compiledItemTemplate = Template7.compile(me.config.itemTemplate);
110 me._compiledDividerTemplate = Template7.compile(me.config.dividerTemplate);
111 me.skelTpl = `
112 <li class="skeleton-text skeleton-effect-fade">
113 <a href="#" class="item-content item-link">
114 <div class="item-inner">
115 <div class="item-title">
116 <div class="item-header">_______________________</div>
117 ____ ______ __ _______ ____ _______ _______ ___
118 </div>
119 <div class="item-after">Score: 15</div>
120 </div>
121 </a>
122 </li>`;
123 me.skelDividerTpl = '<li class="item-divider skeleton-text">____-__-__</li>';
124 me.setEndtime(new Date());
125 let startdate = new Date();
126 startdate.setDate(startdate.getDate() - 7);
127 me.setStarttime(startdate);
128
129 // add to dom
130 $$(me.config.target || '#app').append(me.getEl());
131
132 $$(document).on('page:init', '.page[data-name=quarantine-list]', (e, page) => {
133 me.vList = app.virtualList.create({
134 el: '.virtual-list',
135 items: [],
136 renderItem: function(item) {
137 return me._renderItem(item);
138 },
7a0d8540
DC
139 height: function(item) {
140 return me._calculateHeight(item);
141 },
c87d46fb 142 emptyTemplate: '<div class="empty">No data in database</div>',
43f0b189
DC
143 });
144
145 // setup pull to refresh
f07b75b0 146 $$('.ptr-content').on('ptr:refresh', (ev) => {
43f0b189
DC
147 me.setItems([
148 { skel: true, divider: true },
149 { skel: true },
150 { skel: true },
151 { skel: true },
152 { skel: true, divider: true },
153 { skel: true },
154 { skel: true },
155 { skel: true },
156 { skel: true },
157 { skel: true },
158 { skel: true },
159 { skel: true },
160 ]);
161 me.load().then(data => {
162 me.setItems(data, {
163 sorter: {
164 property: 'time',
165 numeric: true,
c87d46fb 166 direction: 'DESC',
43f0b189 167 },
c87d46fb 168 grouperFn: (val) => PMG.Utils.unixToIso(val.time),
43f0b189
DC
169 });
170 }).catch(PMG.Utils.showError).then(() => {
f07b75b0 171 ev.detail();
43f0b189
DC
172 });
173 });
174
175 // process query parameters
176 let { mail, action, date, username, ticket } = PMG.Utils.extractParams();
177 if (date) {
178 me.setStarttime(date);
179 }
180
181 // setup range form
182 $$('input[name=from]').val(PMG.Utils.unixToIso(me.starttime));
183 $$('input[name=to]').val(PMG.Utils.unixToIso(me.endtime));
184
185 $$('.fab').on('fab:close', () => {
186 let fromChanged = me.setStarttime($$('input[name=from]').val());
187 let toChanged = me.setEndtime($$('input[name=to]').val());
188 if (fromChanged || toChanged) {
189 app.ptr.refresh();
190 }
191 });
192
193 // check login
194
195 let loginInfo = { username, ticket };
196 let showPopup = (username && ticket) || !PMG.Utils.authOK();
197 me._loginScreen = new LoginScreen({ loginInfo });
198
199 me._loginScreen.open().then(data => {
200 me._loginScreen.close();
201 PMG.Utils.setLoginInfo(data);
202 return PMG.Utils.getSubscriptionInfo();
c87d46fb 203 }).then(data => PMG.Utils.checkSubscription(data, showPopup)).then(data => {
43f0b189
DC
204 app.ptr.refresh();
205 if (mail) {
206 let url = "/mail/" + mail + "/" + (action || "");
207 me._view.router.navigate(url);
208 }
209 }).catch(PMG.Utils.showError);
210 });
211
212 me._view = app.views.create('.view-quarantine', {
213 main: me.config.mainView !== undefined ? me.config.mainView : true,
214 url: '/',
215 pushState: true,
c87d46fb 216 pushStateAnimateOnLoad: true,
43f0b189
DC
217 });
218 }
219 setStarttime(starttime) {
220 var me = this;
221 let date = starttime;
222 if (!(starttime instanceof Date)) {
223 // we assume an ISO string
f07b75b0
TL
224 if (starttime === '') {
225 return null;
43f0b189
DC
226 }
227 date = new Date(PMG.Utils.isoToUnix(starttime)*1000);
228 }
229 // starttime is at beginning of date
c87d46fb 230 date.setHours(0, 0, 0, 0);
43f0b189
DC
231 let result = Math.round(date.getTime()/1000);
232 if (result !== me.starttime) {
233 me.starttime = result;
234 return true;
235 }
c87d46fb 236 return false;
43f0b189
DC
237 }
238 setEndtime(endtime) {
239 var me = this;
240 let date = endtime;
241 if (!(endtime instanceof Date)) {
f07b75b0
TL
242 if (endtime === '') {
243 return null;
43f0b189
DC
244 }
245 // we assume an ISO string
246 date = new Date(PMG.Utils.isoToUnix(endtime)*1000);
247 }
248 // endtime is at the end of the day
249 date.setHours(23, 59, 59);
250 let result = Math.round(date.getTime()/1000);
251 if (result !== me.endtime) {
252 me.endtime = result;
253 return true;
254 }
255 return false;
256 }
7a0d8540
DC
257 _calculateHeight(item) {
258 var me = this;
259
260 let height = 48; // default
261
262 if (typeof item === 'object') {
263 let type = app.theme + '-' + (item.divider? "divider" : 'item');
264 switch (type) {
265 case 'md-divider':
266 height = 48;
267 break;
268 case 'md-item':
269 height = 54;
270 break;
271 case 'ios-divider':
272 height = 31;
273 break;
274 case 'ios-item':
275 height = 53;
276 break;
c87d46fb 277 default:
7a0d8540
DC
278 }
279 }
280
281 return height;
282 }
43f0b189
DC
283 _renderItem(item) {
284 var me = this;
285
c87d46fb 286 if (typeof item === 'object') {
43f0b189
DC
287 if (item.skel) {
288 return item.divider? me.skelDividerTpl : me.skelTpl;
289 } else if (item.divider) {
290 return me._compiledDividerTemplate(item);
291 } else {
292 return me._compiledItemTemplate(item);
293 }
294 }
295
296 return item.toString();
297 }
298 setItems(items, options) {
299 var me = this;
300 if (options && options.sorter) {
301 if (options.sorter.sorterFn) {
302 items.sort(options.sorter.sorterFn);
303 } else {
304 let prop = options.sorter.property;
305 let numeric = options.sorter.numeric;
306 let dir = options.sorter.direction === "ASC" ? 1 : -1;
c87d46fb 307 items.sort((a, b) => {
43f0b189
DC
308 let result;
309
310 if (numeric) {
311 result = a[prop] - b[prop];
312 } else {
c87d46fb 313 result = a[prop] === b[prop] ? 0 : a[prop] < b[prop] ? 1 : -1;
43f0b189
DC
314 }
315
316 return result * dir;
317 });
318 }
319 }
320 me.vList.replaceAllItems(items);
321 if (options && options.grouperFn) {
322 let lastgroup;
323 let offset = 0;
324 for (let i = 0; i+offset < items.length; i++) {
325 let item = items[i+offset];
326 let curgroup = options.grouperFn(item);
f07b75b0 327 if (curgroup !== lastgroup) {
c87d46fb 328 me.vList.insertItemBefore(i+offset++, {
43f0b189 329 divider: true,
c87d46fb 330 group: curgroup,
43f0b189
DC
331 });
332 lastgroup = curgroup;
333 }
334 }
335 }
336 }
337 load() {
338 var me = this;
339 return new Promise(function(resolve, reject) {
340 app.request({
341 url: '/api2/json/quarantine/spam',
342 data: {
343 starttime: me.starttime,
c87d46fb 344 endtime: me.endtime,
43f0b189
DC
345 },
346 dataType: 'json',
347 success: (response, status, xhr) => {
348 resolve(response.data);
349 },
350 error: xhr => {
351 reject(xhr);
c87d46fb 352 },
43f0b189
DC
353 });
354 });
355 }
356}
357