Commits

Diego Búrigo Zacarão committed c43d026

Added filtering feature back to Lotte (#378)

  • Participants
  • Parent commits 89e82b1

Comments (0)

Files changed (4)

transifex/site_media/js/web_editor.js

         // Hack to always have a total percentage sum of 100%:
         num = get_total_sum() - get_total("translated") - get_total("fuzzy");
     }
-    return Math.floor(num * 100 / get_total_sum());
+    total_sum = get_total_sum();
+    if ( total_sum == 0 ) {
+        return 0
+    }
+    return Math.floor(num * 100 / total_sum);
+
 }
 
 function update_total(w) {
 
     // Actions for show/hide translated entries
     $("input[name='only_translated']").change(function(){
-          toggle_entries('translated')
-    })
-
-    // Making translated entries hidden by default
-    //$("input[name='only_translated']").attr('checked', false);
-    //    toggle_entries('translated')
+        $("#filter_entries").attr('value', 'true')
+         $(this).closest("form").submit();
+    });
 
     // Actions for show/hide fuzzy entries
-    $("input[name='only_fuzzy']").change(function () {
-          toggle_entries('fuzzy')
-    })
+    $("input[name='only_fuzzy']").change(function(){
+        $("#filter_entries").attr('value', 'true')
+        $(this).closest("form").submit();
+    });
 
     // Actions for show/hide untranslated entries
-    $("input[name='only_untranslated']").change(function () {
-         toggle_entries('untranslated')
-    })
-
-    // Hide check fields for show/hide translated/fuzzy/untranslated fields
-    $("input[name*='only_']").hide()
+    $("input[name='only_untranslated']").change(function(){
+        $("#filter_entries").attr('value', 'true')
+        $(this).closest("form").submit();
+    });
 
     // Actions for show/hide contexts
     $("input[name='toggle_contexts']").change(function(){
         toggle_contexts()
-    })
-    toggle_contexts()
+    });
+    toggle_contexts();
 
     // Copy source string button 
     $('span.copy_source').click(function(){

transifex/templates/webtrans/transfile_edit.html

 </fieldset>
 
   <table class="definition stats_totals">
+  <input id="filter_entries" type="hidden" name="filter_entries"/>
   <tr>
     <th class="translated">{% trans "Translated" %}</th>
       <td id="total_translated">{{ pofile.trans }}</td>
   </table>
 {% endif %}
 
-  <h3>{% trans "Live translation" %}</h3>
-
   {% if form_message %}
     <p class="message i16 bell">{{ form_message }}</p>
   {% endif %}
 
-  <span>{% blocktrans %}Page {{step}} of {{step_count}}{% endblocktrans %}</span>
   {% txpaginate '' po_entries step ENTRIES_PER_PAGE 6 paginated_po_entries %}
   {% include 'pagination.html' %}
 
 
   <p class="submit">
   {% if perms.projects.submit_file or can_submit_file %}
-  <input type="submit" class="i16 submit" name="submit" value="{% trans "Submit translations" %}" />
+  <input type="submit" class="i16 submit" name="submit_file" value="{% trans "Submit translations" %}" />
   {% endif %}
   <input type="submit" class="i16 send_file" name="submit_for_review" value="{% trans "Send for Review" %}">
   </p>

transifex/webtrans/forms.py

     """
     def __init__(self, po_entries, *args, **kwargs):
         super(TranslationForm, self).__init__(*args, **kwargs)
-        for k, entry in enumerate(po_entries):
-            status = _guess_entry_status(entry, k, kwargs.get('data', None))
-            attrs = {'class': '%s msgstr_field_%s' % (status, k)}
+        if po_entries:
+            for k, entry in enumerate(po_entries):
+                status = _guess_entry_status(entry, k, kwargs.get('data', None))
+                attrs = {'class': '%s msgstr_field_%s' % (status, k)}
 
-            if 'fuzzy' in entry.flags:
-                fuzzy=True
-            else:
-                fuzzy=False
+                if 'fuzzy' in entry.flags:
+                    fuzzy=True
+                else:
+                    fuzzy=False
 
-            if entry.msgid_plural:
-                message_keys = entry.msgstr_plural.keys()
-                message_keys.sort()
-                messages = [entry.msgstr_plural[key] for key in message_keys]
-                msgstr_field = PluralMessageField(
-                    entry=entry,
-                    initial=messages,
-                    help_text=self.help_text(entry),
-                    label=_get_label([polib.escape(entry.msgid),
-                        polib.escape(entry.msgid_plural)]),
-                    attrs=attrs,
-                    required=False,
-                )
-            else:
-                msgstr_field = MessageField(
-                    entry=entry,
-                    initial=polib.escape(entry.msgstr),
-                    help_text=self.help_text(entry),
-                    attrs=attrs,
-                    label=_get_label([polib.escape(entry.msgid)]),
-                    required=False,
+                if entry.msgid_plural:
+                    message_keys = entry.msgstr_plural.keys()
+                    message_keys.sort()
+                    messages = [entry.msgstr_plural[key] for key in message_keys]
+                    msgstr_field = PluralMessageField(
+                        entry=entry,
+                        initial=messages,
+                        help_text=self.help_text(entry),
+                        label=_get_label([polib.escape(entry.msgid),
+                            polib.escape(entry.msgid_plural)]),
+                        attrs=attrs,
+                        required=False,
                     )
-            msgid_field = MessageField(entry=entry, widget=forms.HiddenInput,
-                initial=polib.escape(entry.msgid))
-            fuzzy_field = forms.BooleanField(required=False, initial=fuzzy)
+                else:
+                    msgstr_field = MessageField(
+                        entry=entry,
+                        initial=polib.escape(entry.msgstr),
+                        help_text=self.help_text(entry),
+                        attrs=attrs,
+                        label=_get_label([polib.escape(entry.msgid)]),
+                        required=False,
+                        )
+                msgid_field = MessageField(entry=entry, widget=forms.HiddenInput,
+                    initial=polib.escape(entry.msgid))
+                fuzzy_field = forms.BooleanField(required=False, initial=fuzzy)
 
-            self.fields['msgid_field_%s' % k] = msgid_field
-            self.fields['fuzzy_field_%s' % k] = fuzzy_field
-            self.fields['msgstr_field_%s' % k] = msgstr_field
+                self.fields['msgid_field_%s' % k] = msgid_field
+                self.fields['fuzzy_field_%s' % k] = fuzzy_field
+                self.fields['msgstr_field_%s' % k] = msgstr_field
 
     def help_text(self, entry):
         """Return the comments of a field."""

transifex/webtrans/wizards.py

 from django.utils.hashcompat import md5_constructor
 from django.utils.translation import ugettext as _
 
-from authority.views import permission_denied
 from projects.models import Component
-from projects.permissions.project import ProjectPermission
 from translations.models import POFile
 from txcommon.formtools.wizards import SessionWizard
 from webtrans.forms import TranslationForm
         component = get_object_or_404(Component, slug=component_slug,
                                       project__slug=project_slug)
         pofile = get_object_or_404(POFile, filename=filename, component=component)
-        
-        step = int(request.POST.get(self.step_field_name, 0))
+        self.step = int(request.POST.get(self.step_field_name, 0))
+
+        # Getting session
+        self.key =  md5_constructor('%s%s%s' % 
+            (request.user.pk, component.pk, pofile.pk)).hexdigest()
+        self._storage = request.session.setdefault(self.key, {})
 
         # Initializing TranslationForm vars
         self.pofile = pofile
-        self.po_entries = component.trans.get_po_entries(filename)
+        self.po_entries = self.get_stored_po_entries()
+        if not self.po_entries:
+            self.po_entries = component.trans.get_po_entries(filename)
+            self.po_entries_changed = False
+        else:
+            self.po_entries_changed = True
+
+        # Get stored filters
+        f = self.get_stored_filters()
+
+        # Getting filtering settings
+        if f:
+            self.only_translated = f['only_translated']
+            self.only_fuzzy = f['only_fuzzy']
+            self.only_untranslated = f['only_untranslated']
+        else: # Default values
+            self.only_translated = False
+            self.only_fuzzy = True
+            self.only_untranslated = True
+            self.store_filters(self.only_translated, self.only_fuzzy, 
+                self.only_untranslated)
+
+        # Getting po_entries based on the filter settings
+        self.po_entries_list = self.filter_po_entries()
         
-        # Drop obsolete entries from the list
-        obsoletes = len(self.po_entries.obsolete_entries())
-        if obsoletes > 0:
-            self.po_entries_list = self.po_entries[:-obsoletes]
-        else:
-            self.po_entries_list = self.po_entries
+        if 'extra_context' in kwargs:
+            self.extra_context.update(kwargs['extra_context'])
 
-        # Initializing TransFormWizard vars
-        self.key =  md5_constructor('%s%s%s' % 
-            (request.user.pk, component.pk, self.pofile.pk)).hexdigest()
-        self.form_list = [TranslationForm for c in chunks(self.po_entries_list, 
-            self.ENTRIES_PER_PAGE)]
-
-        self.extra_context.update({'pofile': self.pofile, 
-            'po_entries': self.po_entries_list, 
-            'ENTRIES_PER_PAGE': self.ENTRIES_PER_PAGE,
-            'WEBTRANS_SUGGESTIONS': settings.WEBTRANS_SUGGESTIONS,
-            'toggle_contexts': request.POST.get('toggle_contexts', None),
-            #'only_translated': request.POST.get('only_translated', None),
-            #'only_fuzzy': request.POST.get('only_fuzzy', None),
-            #'only_untranslated': request.POST.get('only_untranslated', None),
-            'initial_entries_count':(self.next_step(request, step) * 
-                                     self.ENTRIES_PER_PAGE),
-            })
-
-        super(TransFormWizard, self).init(request)
 
     def __call__(self, request, *args, **kwargs):
         """
         This method acts like a view.
-        
+
         It was necessary to change a bit the normal behavior of this method,
         due the fact we only want to validate step forms displayed to the users 
         and, also, to be able to submit the form without pass throught all the 
         steps.
-        
+
         """
         self.init(request, *args, **kwargs)
 
         step = self.current_step(request)
         if request.method == 'POST':
+            
+            # Store the data and files for the related step right away
             self.store(step, request.POST, request.FILES)
+            
+            # Get the form instance
             form = self.form_for(step)
-            # Validate the form whenever a POST is sent, it includes the
-            # navegation between the pages
+            
+            # Validate the current form
             if not form.is_valid():
                 return self.render(request, step, form)
-            # Submit whenever the 'submit' button is pressed
-            if 'submit' in request.POST or 'submit_for_review' in request.POST:
-                return self.finish(request)
+
+            # In case it changed, store the entire updated pofile in the session
+            if form.has_changed():
+                self.update_po_entries(form)
+                self.store_po_entries(self.po_entries)
+
+            # Submit whenever the 'submit_file' or 'submit_for_review' button 
+            # are pressed
+            if 'submit_file' in request.POST or \
+                'submit_for_review' in request.POST:
+                return self.done(request)
+
+            # Make sure the current page is never greater than the total number 
+            # of pages of the wizard
+            if step >= self.num_steps():
+                step = self.num_steps()-1 if self.num_steps()-1 >= 0 else 0
+
             return self.render(request, self.next_step(request, step))
         return self.render(request, step)
 
     def get_template(self, step):
         return 'webtrans/transfile_edit.html'
 
+    def num_steps(self):
+        """Total number of steps in the wizard."""
+        return len(list(chunks(self.po_entries_list, self.ENTRIES_PER_PAGE)))
+
     def next_step(self, request, step):
         """Given the request and the current step, calculate the next step."""
         if 'next' in request.POST:
             return step - 1
         return step
 
+    def form_for(self, step):
+        """
+        Get the data out of storage and return a form for it, or, if no data is 
+        in storage for this step, create the default form.
+        """
+        if 'steps' in self._storage:
+            data, files = self._storage['steps'].get(step, (None, None))
+        else: 
+            data, files = (None, None)
+        return self.make_form(step, data, files)
+
     def make_form(self, step, data=None, files=None):
-        """Create the default form for step."""
+        """Create a form for step based on the filtered po_entries_list."""
         prefix = self.get_prefix(step)
         if step in self.initial:
             initial = self.initial[step]
         else:
             initial = None
-        
-        # Get po entries for the chuck in a specific possition (step)
+
+        # Get po_entries for the chuck in a specific possition (step)
         po_entries = specific_chunk(self.po_entries_list, step, self.ENTRIES_PER_PAGE)
 
-        # Return the form instance initialized with the data populated from the,
-        # case the form for this step was already displayed
-        return self.form_list[step](po_entries, data=data, files=files, 
+        # Return the form instance initialized with the data populated, in case
+        # it was passed by parameter
+        return TranslationForm(po_entries, data=data, files=files, 
             prefix=prefix, initial=initial)
 
-    def finish(self, request):
+    def filter_po_entries(self):
+        """Filter the po_entries based on the parameters."""
+
+        # Drop obsolete entries from the list
+        ob = len(self.po_entries.obsolete_entries())
+        entries = self.po_entries if ob==0 else self.po_entries[:-ob]
+
+        # Filtering
+        po_entries_list = []
+        for entry in entries:
+            if entry.translated():
+                if self.only_translated:
+                    po_entries_list.append(entry)
+            elif 'fuzzy' in entry.flags:
+                if self.only_fuzzy:
+                    po_entries_list.append(entry)
+            elif entry.msgstr == '':
+                if self.only_untranslated:
+                    po_entries_list.append(entry)
+        return po_entries_list
+
+    def store_filters(self, only_translated, only_fuzzy, only_untranslated):
+        """Store the filter options in the session."""
+        self._storage['filters'] = {'only_translated': only_translated,
+                                    'only_fuzzy': only_fuzzy,
+                                    'only_untranslated': only_untranslated}
+
+    def get_stored_filters(self):
+        """Get the stored filter options from the session."""
+        if self._storage:
+            return self._storage.get('filters', None)
+
+    def store_po_entries(self, po_entries):
+        """Store the po_entries in the session."""
+        self._storage['po_entries'] = po_entries
+        self.po_entries_changed = True
+
+    def get_stored_po_entries(self):
+        """Get the po_entries stored from the session."""
+        if self._storage:
+            return self._storage.get('po_entries', None)
+
+    def update_po_entries(self, form):
         """
-        Called when submitting the wizard, this method identifies the forms that
-        are valid and that some field has changed, putting those in a list and 
-        calling the method ``done``.
+        Update po_entries, which is a polib.POFile object, with the changed 
+        form data.
         """
-        valid_forms = []
-        forms = [self.form_for(step) for step in range(self.num_steps())]
-        for form in forms:
-            if form.is_valid() and form.has_changed():
-                valid_forms.append(form) 
-        return self.done(request, valid_forms)
+        for fieldname in form.fields.keys():
+            if 'msgid_field_' in fieldname:
+                nkey = fieldname.split('msgid_field_')[1]
+                msgstr_field = 'msgstr_field_%s' % nkey
+                fuzzy_field = 'fuzzy_field_%s' % nkey
 
-    def done(self, request, form_list):
+                if msgstr_field in form.changed_data or \
+                    fuzzy_field in form.changed_data:
+
+                    msgid_value = form.cleaned_data['msgid_field_%s' % nkey]
+                    entry = self.po_entries.find(unescape(msgid_value))
+
+                    msgstr_value = form.cleaned_data['msgstr_field_%s' % nkey]
+                    try:
+                        entry.msgstr = unescape(msgstr_value)
+                    except AttributeError:
+                        for i, value in enumerate(msgstr_value):
+                            entry.msgstr_plural['%s' % i]=unescape(value)
+
+                    # Taking care of fuzzies flags
+                    if form.cleaned_data.get('fuzzy_field_%s' % nkey, None):
+                        if 'fuzzy' not in entry.flags:
+                            entry.flags.append('fuzzy')
+                    else:
+                        if 'fuzzy' in entry.flags:
+                            entry.flags.remove('fuzzy')
+
+    def store(self, step, data, files):
         """
-        Method responsible for handling the final list of validated forms, that
-        actually have changed, after submitting the wizard.
+        Store the data that was sent to a step.
+        """
+        if 'steps' in self._storage:
+            self._storage['steps'].update({step: (data, files)})
+        else:
+            self._storage['steps'] = {step: (data, files)}
+
+    def render(self, request, step, form=None, context=None):
+        """
+        Called to render a specific step.
+        You may pass 'form' manually in case you want a form that has been error-checked.
+        If you don't give 'form', it will be retreived from storage.
+        """
+        # Get filter settings from the form
+        if request.method == 'POST' and not form:
+            only_translated = request.POST.get('only_translated', None)
+            only_fuzzy = request.POST.get('only_fuzzy', None)
+            only_untranslated = request.POST.get('only_untranslated', None)
+
+            # If filter changed
+            if only_translated != self.only_translated or \
+                only_fuzzy != self.only_fuzzy or \
+                only_untranslated  != self.only_untranslated:
+
+                self.only_translated = only_translated
+                self.only_fuzzy = only_fuzzy
+                self.only_untranslated = only_untranslated
+
+                # Store the current filters
+                self.store_filters(self.only_translated, self.only_fuzzy, 
+                    self.only_untranslated)
+
+                if 'steps' in self._storage:
+                    del self._storage['steps']
+
+                # Getting po_entries based on the filter settings
+                self.po_entries_list = self.filter_po_entries()#self.only_translated, 
+                    #self.only_fuzzy, self.only_untranslated)
+
+                self.number_steps = len(list(chunks(self.po_entries_list, 
+                    self.ENTRIES_PER_PAGE)))
+
+        self.extra_context.update({'pofile': self.pofile, 
+            'po_entries': self.po_entries_list, 
+            'ENTRIES_PER_PAGE': self.ENTRIES_PER_PAGE,
+            'WEBTRANS_SUGGESTIONS': settings.WEBTRANS_SUGGESTIONS,
+            'toggle_contexts': request.POST.get('toggle_contexts', None),
+            'only_translated': self.only_translated,
+            'only_fuzzy': self.only_fuzzy,
+            'only_untranslated': self.only_untranslated,
+            'initial_entries_count':(self.next_step(request, self.step) * 
+                                     self.ENTRIES_PER_PAGE),
+            })
+
+        self.save_step(step)
+        self.commit_storage(request)
+        context = context or {}
+        context.update(self.extra_context)
+        return render_to_response(self.get_template(step), dict(context,
+            step0=step,
+            step=step + 1,
+            step_count=self.num_steps(),
+            form=form or self.form_for(step),
+        ), context_instance=RequestContext(request))
+
+    def done(self, request):
+        """
+        Method responsible for handling the final submittion of the wizard.
         """
         from projects.views.component import component_submit_file
 
         component_slug = self.pofile.object.slug
         filename = self.pofile.filename
 
-        for form in form_list:
-            for fieldname in form.fields.keys():
-                if 'msgid_field_' in fieldname:
-                    nkey = fieldname.split('msgid_field_')[1]
-                    msgstr_field = 'msgstr_field_%s' % nkey
-                    fuzzy_field = 'fuzzy_field_%s' % nkey
-
-                    if msgstr_field in form.changed_data or \
-                        fuzzy_field in form.changed_data:
-
-                        msgid_value = form.cleaned_data['msgid_field_%s' % nkey]
-                        entry = self.po_entries.find(unescape(msgid_value))
-
-                        msgstr_value = form.cleaned_data['msgstr_field_%s' % nkey]
-                        try:
-                            entry.msgstr = unescape(msgstr_value);
-                        except AttributeError:
-                            for i, value in enumerate(msgstr_value):
-                                entry.msgstr_plural['%s' % i]=unescape(value)
-
-                        # Taking care of fuzzies flags
-                        if form.cleaned_data.get('fuzzy_field_%s' % nkey, None):
-                            if 'fuzzy' not in entry.flags:
-                                entry.flags.append('fuzzy')
-                        else:
-                            if 'fuzzy' in entry.flags:
-                                entry.flags.remove('fuzzy')
-
-        if form_list:
+        if self.po_entries_changed:
             po_contents = self.po_entries.__str__().encode('utf-8')
             edited_file = SimpleUploadedFile(filename, po_contents)
             result_view = component_submit_file(request=request,