]> git.openstreetmap.org Git - osqa.git/blob - forum/skins/default/templates/osqaadmin/nodeman.html
Bulk management changes:
[osqa.git] / forum / skins / default / templates / osqaadmin / nodeman.html
1 {% extends basetemplate %}
2
3 {% load i18n user_tags extra_tags %}
4
5 {% block adminjs %}
6     <script type="text/javascript">
7         $(function() {
8             var $form = $('#changelist-search');
9
10             $('#all-node-type-link').click(function() {
11                 $('#type-filter-container').find('input').remove();
12                 $form.submit();
13             });
14
15             $('.node-type-link').click(function() {
16                 var link_type = $(this).attr('href').substring(1);
17
18                 if ($('#type-filter-container').find('input[value=' + link_type + ']').length == 0) {
19                     $('#type-filter-container').append($("<input name=\"node_type\" type=\"hidden\" value=\"" + link_type + "\" />"));
20                 } else {
21                     $('#type-filter-container').find('input[value=' + link_type + ']').remove();
22                 }
23
24                 $form.submit();                
25             });
26
27             $('#all-state-link').click(function() {
28                 $('#state-filter-container').find('input').remove();
29                 $form.submit();
30             });
31
32             $('.state-type-link').click(function() {
33                 var state_type = $(this).attr('href').substring(1);
34
35                 if ($('#state-filter-container').find('input[value=' + state_type + ']').length == 0) {
36                     $('#state-filter-container').append($("<input name=\"state_type\" type=\"hidden\" value=\"" + state_type + "\" />"));
37                 } else {
38                     $('#state-filter-container').find('input[value=' + state_type + ']').remove();
39                 }
40
41                 $form.submit();
42             });
43
44             $('.action-select').change(function() {
45                 $('#action-toggle').removeAttr('checked');
46                 var $tr = $(this).parents('tr');
47                 if ($(this).attr('checked')) {
48                     $tr.addClass('selected');
49                 } else {
50                     $tr.removeClass('selected');
51                 }
52             }).change();
53
54             $('#action-toggle').change(function() {
55                 var $rows = $('#result_list').find('tbody').find('tr');
56                 var $boxes = $('#result_list').find('tbody').find('input');
57
58                 if ($(this).attr('checked')) {
59                     $rows.addClass('selected');
60                     $boxes.attr('checked', 'checked')
61                 } else {
62                     $rows.removeClass('selected');
63                     $boxes.removeAttr('checked');
64                 }
65             });
66
67             $('#author-selector').autocomplete('{% url matching_users %}', {
68                 minChars: 1,
69                 matchContains: true,
70                 max: 10,
71
72                 formatItem: function(row, i, max, value) {
73                     return row[1] + ' (' + row[2] + ' {% trans "rep" %})';
74                 },
75
76                 formatResult: function(row, i, max, value){
77                     return row[1];
78                 }
79             });
80
81             $('#author-selector').result(function(event, data, formatted) {
82                 if ($('#author-filter-container').find('input[value=' + data[0] + ']').length == 0) {
83                     $('#author-filter-container').append($("<input name=\"authors\" type=\"hidden\" value=\"" + data[0] + "\" />"));
84                     $form.submit();
85                 }
86             });
87
88             $('.author-filter-remover').click(function() {
89                 var id = $(this).attr('rel');
90                 if ($('#author-filter-container').find('input[value=' + id + ']').length > 0) {
91                     $('#author-filter-container').find('input[value=' + id + ']').remove();
92                     $form.submit();
93                 }
94             });
95
96             $('#tag-selector').autocomplete('{% url matching_tags %}', {
97                 minChars: 1,
98                 matchContains: true,
99                 max: 10,
100
101                 formatItem: function(row, i, max, value) {
102                     return row[1] + ' (' + row[2] + ' {% trans "uses" %})';
103                 },
104
105                 formatResult: function(row, i, max, value){
106                     return row[1];
107                 }
108             });
109
110             $('#tag-selector').result(function(event, data, formatted) {
111                 if ($('#tag-filter-container').find('input[value=' + data[0] + ']').length == 0) {
112                     $('#tag-filter-container').append($("<input name=\"tags\" type=\"hidden\" value=\"" + data[0] + "\" />"));
113                     $form.submit();
114                 }
115             });
116
117             $('.tag-filter-remover').click(function() {
118                 var id = $(this).attr('rel');
119                 if ($('#tag-filter-container').find('input[value=' + id + ']').length > 0) {
120                     $('#tag-filter-container').find('input[value=' + id + ']').remove();
121                     $form.submit();
122                 }
123             });
124
125             $('#filter-name-box').one('focus', function() {
126                 $(this).val('');
127                 $(this).css('color', 'black');
128             });
129
130             $('#filter-name-box').keyup(function() {
131                 if ($(this).val().trim().length > 0) {
132                     $('#save-filter-button').removeAttr('disabled');
133                     $('#save-filter-button').css('color', 'black');
134                 } else {
135                     $('#save-filter-button').css('color', '#AAA');
136                     $('#save-filter-button').attr('disabled', 'disabled');
137                 }
138             });
139
140             var resize_data = null;
141
142             $('.col-resizer').mousedown(function(e) {
143                 var $to_resize = $(this).prev();
144
145                 resize_data = {
146                     resizer: $(this),
147                     to_resize: $to_resize,
148                     start_width: $to_resize.innerWidth(),
149                     x_start: e.pageX,
150                 }
151             });
152
153             $('body').mousemove(function(e) {
154                 if (resize_data != null) {
155                     var new_size = (resize_data.start_width - (resize_data.x_start - e.pageX)) + 'px';
156                     resize_data.to_resize.css({'max-width': new_size, 'min-width': new_size})
157                     resize_data.resizer.css('max-width', '3px');
158                 }
159             });
160
161             $('body').mouseup(function() {
162                 if (resize_data != null)
163                     resize_data = null;
164             });
165
166             $('#filter-panel-header').click(function() {
167                 $('#filter-panel').slideToggle();
168             });
169
170             $('#state-filter-type').change(function() {
171                 $('#state-filter-type-hidden').val($(this).val());
172                 $form.submit();
173             });
174             
175             $('#reset-text-filter').click(function() {
176                 $('#text-filter-input').val('');
177                 $form.submit();
178                 return false;
179             });
180         });
181     </script>
182     <style>
183         #toolbar ul li {
184             list-style-type: none;
185             display: inline;
186             margin-right: 12px;
187         }
188
189         #result_list tr.row1 td.deleted {
190             background-color: #FDD;
191         }
192
193         #result_list tr.row2 td.deleted {
194             background-color: #FEE;
195         }
196
197         #result_list tr.row1 td.accepted {
198             background-color: #DFD;
199         }
200
201         #result_list tr.row2 td.accepted {
202             background-color: #EFD;
203         }
204
205         span.question-deleted {
206             text-decoration: line-through;
207         }
208
209         .col-resizer {
210             width: 2px;
211             min-width: 2px;
212             min-width: 2px;
213             cursor: col-resize;
214             padding: 0 0 0 0;
215         }
216     </style>
217     <script type="text/javascript">window.__admin_media_prefix__ = "{{ settings.ADMIN_MEDIA_PREFIX }}";</script>
218     <link href="{{ settings.ADMIN_MEDIA_PREFIX }}css/base.css" rel="stylesheet" type="text/css" media="screen" />
219     <script type="text/javascript">
220     /* gettext identity library */
221
222     function gettext(msgid) { return msgid; }
223     function ngettext(singular, plural, count) { return (count == 1) ? singular : plural; }
224     function gettext_noop(msgid) { return msgid; }
225
226     function interpolate(fmt, obj, named) {
227       if (named) {
228         return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])});
229       } else {
230         return fmt.replace(/%s/g, function(match){return String(obj.shift())});
231       }
232     }
233
234     /* formatting library */
235
236     var formats = new Array();
237
238     formats['DATETIME_FORMAT'] = 'N j, Y, P';
239     formats['DATE_FORMAT'] = 'N j, Y';
240     formats['DECIMAL_SEPARATOR'] = '.';
241     formats['MONTH_DAY_FORMAT'] = 'F j';
242     formats['NUMBER_GROUPING'] = '0';
243     formats['TIME_FORMAT'] = 'P';
244     formats['FIRST_DAY_OF_WEEK'] = '0';
245     formats['TIME_INPUT_FORMATS'] = ['%H:%M:%S', '%H:%M'];
246     formats['THOUSAND_SEPARATOR'] = ',';
247     formats['DATE_INPUT_FORMATS'] = ['%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', '%b %d %Y', '%b %d, %Y', '%d %b %Y', '%d %b, %Y', '%B %d %Y', '%B %d, %Y', '%d %B %Y', '%d %B, %Y'];
248     formats['YEAR_MONTH_FORMAT'] = 'F Y';
249     formats['SHORT_DATE_FORMAT'] = 'm/d/Y';
250     formats['SHORT_DATETIME_FORMAT'] = 'm/d/Y P';
251     formats['DATETIME_INPUT_FORMATS'] = ['%Y-%m-%d %H:%M:%S', '%Y-%m-%d %H:%M', '%Y-%m-%d', '%m/%d/%Y %H:%M:%S', '%m/%d/%Y %H:%M', '%m/%d/%Y', '%m/%d/%y %H:%M:%S', '%m/%d/%y %H:%M', '%m/%d/%y'];
252
253     function get_format(format_type) {
254         var value = formats[format_type];
255         if (typeof(value) == 'undefined') {
256           return msgid;
257         } else {
258           return value;
259         }
260     }
261     
262     </script>
263     <script type="text/javascript" src="{{ settings.ADMIN_MEDIA_PREFIX }}js/core.js"></script>
264 {% endblock %}
265
266 {% block subtitle %}
267     {% trans "Node manager" %}
268 {% endblock %}
269 {% block description %}
270     {% trans "Nodes bulk management" %}
271 {% endblock %}
272
273 {% block admincontent %}
274     <div id="changelist" class="module filtered">
275         <div id="toolbar">
276             <form method="get" action="" id="changelist-search">
277             <div>
278                 <div>
279                     <label><img alt="Search" src="{{ settings.ADMIN_MEDIA_PREFIX }}img/admin/icon_searchbox.png"></label>
280                     <input type="text" size="40" name="text" id="text-filter-input" value="{{ text }}">
281                     <input type="submit" value="{% trans "Search" %}">
282                     {% if text %}
283                         <small><a href="#" id="reset-text-filter">{% trans "reset text filter" %}</a></small>
284                     {% endif %}
285                     <br />
286                     <ul>
287                         <li>
288                             <label>
289                                 <input type="radio" name="text_in" value="title"{% ifequal text_in "title" %} checked="checked"{% endifequal %} />
290                             {% trans "Title" %}</label>
291                         </li>
292                         <li>
293                             <label>
294                                 <input type="radio" name="text_in" value="body"{% ifequal text_in "body" %} checked="checked"{% endifequal %} />
295                             {% trans "Body" %}</label>
296                         </li>
297                         <li>
298                             <label>
299                                 <input type="radio" name="text_in" value="both"{% ifequal text_in "both" %} checked="checked"{% endifequal %} />
300                             {% trans "Title and Body" %}</label>
301                        </li>
302                     </ul>
303                 </div>
304             </div>
305             <input type="hidden" name="sort" value="{{ nodes.paginator.current_sort }}" />
306             <input type="hidden" id="state-filter-type-hidden" name="state_filter_type" value="" />
307             <div style="display: none;" id="author-filter-container">
308                 {% for u in authors %}
309                 <input name="authors" type="hidden" value="{{ u.id }}" />
310                 {% endfor %}
311             </div>
312             <div style="display: none;" id="tag-filter-container">
313                 {% for t in tags %}
314                 <input name="tags" type="hidden" value="{{ t.id }}" />
315                 {% endfor %}
316             </div>
317             <div id="type-filter-container" style="display: none;">
318                 {% for type in type_filter %}
319                 <input name="node_type" type="hidden" value="{{ type }}" />
320                 {% endfor %}
321             </div>
322             <div id="state-filter-container" style="display: none;">
323                 {% for type in state_filter %}
324                 <input name="state_type" type="hidden" value="{{ type }}" />
325                 {% endfor %}
326             </div>
327             </form>
328         </div>
329         <div id="changelist-filter">
330             <h2 id="filter-panel-header">{% trans "Filter" %}<small> ({% trans "Click to show/hide" %})</small></h2>
331             <div id="filter-panel">
332             <h3>{% trans "By type" %}</h3>
333             <ul>
334                 <li {% if not type_filter %} class="selected"{% endif %}>
335                     <a id="all-node-type-link" href="#all" title="{% trans "click to clear the type filter" %}">{% trans "all" %}</a>
336                 </li>
337                 {% for type, name in node_types %}
338                 <li{% if type in type_filter %} class="selected" title="{% trans "click to remove from the filter" %}"{% else %} title="{% trans "click to add to the filter" %}"{% endif %}>
339                     <a class="node-type-link" href="#{{ type }}">{{ name }}</a>
340                 </li>
341                 {% endfor %}
342             </ul>
343             <h3>{% trans "By state" %}</h3>
344             <ul>
345                 <li {% if not state_filter %} class="selected"{% endif %}>
346                     <a id="all-state-link" href="#any" title="{% trans "click to clear the state filter" %}">{% trans "any" %}</a>
347                 </li>
348                 {% for state_type in state_types %}
349                     <li{% if state_type in state_filter %} class="selected" title="{% trans "click to remove from the filter" %}"{% else %} title="{% trans "click to add to the filter" %}"{% endif %}>
350                         <a class="state-type-link" href="#{{ state_type }}">{{ state_type }}</a>
351                     </li>
352                 {% endfor %}
353                 <li>
354                     <select id="state-filter-type">
355                         <option value="any"{% ifequal state_filter_type "any" %} selected="selected"{% endifequal %}>{% trans "Match any selected" %}</option>
356                         <option value="all"{% ifequal state_filter_type "all" %} selected="selected"{% endifequal %}>{% trans "Match all selected" %}</option>
357                     </select>
358                 </li>
359             </ul>
360             <h3>{% trans "By author(s)" %}</h3>
361             {% if not authors.count %}
362                 <small>{% trans "No users selected, use the box bellow to add users to the filter." %}</small>
363             {% else %}
364                 <ul>
365                     {% for u in authors %}
366                         <li class="selected">
367                             <img class="author-filter-remover" rel="{{ u.id }}" src="{% media "/media/images/close-small-dark.png" %}">
368                             {{ u.decorated_name }} ({{ u.reputation }})
369                         </li>
370                     {% endfor %}
371                 </ul>
372                 <small>{% trans "Click on the cross next to a user name to remove it from the filter." %}</small>
373             {% endif %}
374             <input type="text" size="20" autocomplete="off" id="author-selector" />
375
376             <h3>{% trans "By tag(s)" %}</h3>
377             {% if not tags.count %}
378                 <small>{% trans "No tags selected, use the box bellow to add tags to the filter." %}</small>
379             {% else %}
380                 <ul>
381                     {% for t in tags %}
382                         <li class="selected">
383                             <img class="tag-filter-remover" rel="{{ t.id }}" src="{% media "/media/images/close-small-dark.png" %}">
384                             {{ t.name }} ({{ t.used_count }})
385                         </li>
386                     {% endfor %}
387                 </ul>
388                 <small>{% trans "Click on the cross next to a tag name to remove it from the filter." %}</small>
389             {% endif %}
390             <input type="text" size="20" autocomplete="off" id="tag-selector" />
391
392             <h3>{% trans "Pre defined" %}</h3>
393             {% if not settings.NODE_MAN_FILTERS %}
394                 <small>{% trans "There are no saved filters. Click bellow to add." %}</small>
395             {% endif %}
396             <ul id="pre-filter-container">
397                 {% for name, uri in settings.NODE_MAN_FILTERS %}
398                 <li class="selected"><a href="{% url admin_tools "nodeman" %}?{{ uri }}">{{ name }}</a></li>
399                 {% endfor %}
400             </ul>
401             <form action="" method="POST">
402                 <input name="filter_name" type="text" size="20" id="filter-name-box" style="color: #AAA;" value="{% trans "Filter name..." %}" />
403                 <button name="save_filter" value="0" style="color: #AAA;" title="{% trans "Click to save the current filter" %}" id="save-filter-button" disabled="disabled" class="button">{% trans "Save" %}</button>
404             </form>
405
406             {% comment %}<h3>{% trans "Show" %}</h3>
407             <form action="" method="get">
408                 <div>{{ show_form.show }}</div>
409                 <input type="submit" value="{% trans "Refresh" %}" />
410             </form>{% endcomment %}
411             </div>
412         </div>
413         <form id="changelist-form" method="POST" action="">
414             <div class="actions">
415                 <label>
416                     {% trans "Action" %}:
417                     <select name="action">
418                         <option selected="selected" value="">---------</option>
419                         <option value="delete_selected">{% trans "Mark deleted" %}</option>
420                         <option value="undelete_selected">{% trans "Undelete" %}</option>
421                         <option value="hard_delete_selected">{% trans "Delete completelly" %}</option>
422                         <option value="close_selected">{% trans "Close (questions only)" %}</option>
423                     </select>
424                 </label>
425                 <button value="0" name="execute" title="{% trans "Run the selected action" %}" class="button" type="submit">{% trans "Go" %}</button>
426             </div>
427             <table id="result_list" cellspacing="0">
428                 <thead>
429                     <tr>
430                         {% declare %}
431                             current_sort = nodes.paginator.current_sort
432                             added_at = current_sort == "added_at" and "ascending" or (current_sort == "added_at_asc" and "descending" or "")
433                             author = current_sort == "author" and "ascending" or (current_sort == "author_asc" and "descending" or "")
434                             score = current_sort == "score" and "ascending" or (current_sort == "score_asc" and "descending" or "")
435                             act_at = current_sort == "act_at" and "ascending" or (current_sort == "act_at_asc" and "descending" or "")
436                             act_by = current_sort == "act_by" and "ascending" or (current_sort == "act_by_asc" and "descending" or "")
437
438                             added_at_link = current_sort == "added_at" and nodes.paginator.added_at_asc_sort_link or nodes.paginator.added_at_sort_link
439                             author_link = current_sort == "author_asc" and nodes.paginator.author_sort_link or nodes.paginator.author_asc_sort_link
440                             score_link = current_sort == "score" and nodes.paginator.score_asc_sort_link or nodes.paginator.score_sort_link
441                             act_at_link = current_sort == "act_at" and nodes.paginator.act_at_asc_sort_link or nodes.paginator.act_at_sort_link
442                             act_by_link = current_sort == "act_by_asc" and nodes.paginator.act_by_sort_link or nodes.paginator.act_by_asc_sort_link
443                         {% enddeclare %}
444                         {% spaceless %}
445                         <th class="action-checkbox-column">
446                             <input type="checkbox" id="action-toggle" style="display: inline;" />
447                         </th>                        
448                         <th>{% trans "Type" %}</th>
449                         <th>{% trans "Summary" %}</th>
450                         <th class="col-resizer"></th>
451                         <th>{% trans "State" %}</th>
452                         <th class="sorted {{ author }}">
453                             <a href="{{ author_link }}">{% trans "Author" %}</a>
454                         </th>
455                         <th class="sorted {{ added_at }}">
456                             <a href="{{ added_at_link }}">{% trans "Added at" %}</a>
457                         </th>
458                         <!--<th class="sorted {{ score }}">
459                             <a href="{{ score_link }}">{% trans "Score" %}</a>
460                         </th>-->
461                         <th class="sorted {{ act_by }}">
462                             <a href="{{ act_by_link }}">{% trans "Last activity by" %}</a>
463                         </th>
464                         <th class="sorted {{ act_at }}">
465                             <a href="{{ act_at_link }}">{% trans "Last activity at" %}</a>
466                         </th>
467                         <th>{% trans "Tags" %}</th>
468                         {% endspaceless %}
469                     </tr>
470                 </thead>
471                 <tbody>
472                 {% with filter_form.state_type.data as state_type %}
473                 {% for node in nodes.paginator.page %}
474                     <tr class="{% cycle 'row1' 'row2' %}">
475                         <td><input type="checkbox" name="_selected_node" value="{{ node.id }}" class="action-select"></td>
476                         <td>{{ node.friendly_name }}</td>
477                         {% declare %}
478                             is_root = node.abs_parent == None
479                             title = is_root and node.title or node.abs_parent.title
480
481                             anchor = "<strong>%s</strong>" % html.hyperlink(node.get_absolute_url(), title)
482                             anchor = ((not is_root) and node.abs_parent.nis.deleted) and "<span class=\"question-deleted\">%s</span>" % anchor or anchor
483                             anchor = is_root and anchor or "(%s)" % anchor
484                             anchor = html.mark_safe(anchor)
485
486                             td_class = ""
487                             td_class = node.nis.accepted and "accepted" or td_class
488                             td_class = node.nis.deleted and "deleted" or td_class
489                         {% enddeclare %}
490                         <td class="{{ td_class }}" colspan="2">
491                             {{ anchor }}<br />
492                             {{ node.summary }}
493                         </td>
494                         <td>
495                             {% for state in node.states.all %}
496                             <b>{{ state.state_type }}</b> {% diff_date state.action.at %} {% trans "by" %}
497                             <a target="_blank" href="{{ state.action.by.get_absolute_url }}">{{ state.action.by.decorated_name }}</a><br />
498                             {% endfor %}
499                         </td>
500                         <td><a href="{{ node.author.get_absolute_url  }}">{{ node.author.decorated_name }}</a></td>
501                         <td>{% diff_date node.added_at %}</td>
502                         <!--<td>{{ node.score }}</td>-->
503                         <td><a href="{{ node.last_activity_by.get_absolute_url  }}">{{ node.last_activity_by.decorated_name }}</a></td>
504                         <td>{% diff_date node.last_activity_at %}</td>
505                         <td>
506                             {% for t in node.tags.all %}
507                                 {% if t in tags %}<b>{{ t.name }}</b>
508                                 {% else %}{{ t.name }}{% endif %}
509                             {% endfor %}
510                         </td>
511                     </tr>
512                 {% endfor %}
513                 {% endwith %}
514                 </tbody>
515             </table>
516             {{ nodes.paginator.page_numbers }}
517         </form>
518     </div>
519 {% endblock %}