merged
authorThomas Waldmann <tw AT waldmann-edv DOT de>
Thu, 11 Apr 2013 21:00:12 +0200
changeset 2086a5b0f7551a56
parent 2083 d1f6f392cdf6
parent 2085 7f4520c9b5f1
child 2089 d050c88db976
merged
MoinMoin/themes/foobar/static/css/stylus/main.styl
     1.1 --- a/MoinMoin/forms.py	Thu Apr 11 21:23:36 2013 +0530
     1.2 +++ b/MoinMoin/forms.py	Thu Apr 11 21:00:12 2013 +0200
     1.3 @@ -20,10 +20,12 @@
     1.4  from flatland.validation import Validator, Present, IsEmail, ValueBetween, URLValidator, Converted, ValueAtLeast
     1.5  from flatland.exc import AdaptationError
     1.6  
     1.7 +from whoosh.query import Term, Or, Not, And
     1.8 +
     1.9  from flask import g as flaskg
    1.10  
    1.11  from MoinMoin.constants.forms import *
    1.12 -from MoinMoin.constants.keys import ITEMID, NAME
    1.13 +from MoinMoin.constants.keys import ITEMID, NAME, LATEST_REVS
    1.14  from MoinMoin.i18n import _, L_, N_
    1.15  from MoinMoin.util.forms import FileStorage
    1.16  
    1.17 @@ -71,12 +73,36 @@
    1.18      """Validator for JSON
    1.19      """
    1.20      invalid_json_msg = L_('Invalid JSON.')
    1.21 +    invalid_name_msg = ""
    1.22 +
    1.23 +    def validname(self, meta, name, itemid):
    1.24 +        names = meta.get(NAME)
    1.25 +        if names is None:
    1.26 +            self.invalid_name_msg = L_("No name field in the JSON meta.")
    1.27 +            return False
    1.28 +        if len(names) != len(set(names)):
    1.29 +            self.invalid_name_msg = L_("The names in the JSON name list must be unique.")
    1.30 +            return False
    1.31 +        query = Or([Term(NAME, x) for x in names])
    1.32 +        if itemid is not None:
    1.33 +            query = And([query, Not(Term(ITEMID, itemid))])
    1.34 +        duplicate_names = set()
    1.35 +        with flaskg.storage.indexer.ix[LATEST_REVS].searcher() as searcher:
    1.36 +            results = searcher.search(query)
    1.37 +            for result in results:
    1.38 +                duplicate_names |= set([x for x in result[NAME] if x in names])
    1.39 +        if duplicate_names:
    1.40 +            self.invalid_name_msg = L_("Item(s) named %(duplicate_names)s already exist.", duplicate_names=", ".join(duplicate_names))
    1.41 +            return False
    1.42 +        return True
    1.43  
    1.44      def validate(self, element, state):
    1.45          try:
    1.46 -            json.loads(element.value)
    1.47 +            meta = json.loads(element.value)
    1.48          except:  # catch ANY exception that happens due to unserializing
    1.49              return self.note_error(element, state, 'invalid_json_msg')
    1.50 +        if not self.validname(meta, state[NAME], state[ITEMID]):
    1.51 +            return self.note_error(element, state, 'invalid_name_msg')
    1.52          return True
    1.53  
    1.54  JSON = OptionalMultilineText.with_properties(lang='en', dir='ltr').validated_by(ValidJSON())
     2.1 --- a/MoinMoin/items/__init__.py	Thu Apr 11 21:23:36 2013 +0530
     2.2 +++ b/MoinMoin/items/__init__.py	Thu Apr 11 21:00:12 2013 +0200
     2.3 @@ -727,7 +727,8 @@
     2.4                      # break them
     2.5                      return "OK"
     2.6              form = self.ModifyForm.from_request(request)
     2.7 -            if form.validate():
     2.8 +            state = dict(name=self.name, itemid=self.meta.get(ITEMID))
     2.9 +            if form.validate(state):
    2.10                  meta, data, contenttype_guessed, comment = form._dump(self)
    2.11                  contenttype_qs = request.values.get('contenttype')
    2.12                  try:
     3.1 --- a/MoinMoin/templates/common.js	Thu Apr 11 21:23:36 2013 +0530
     3.2 +++ b/MoinMoin/templates/common.js	Thu Apr 11 21:00:12 2013 +0200
     3.3 @@ -228,92 +228,18 @@
     3.4  
     3.5  
     3.6  
     3.7 -// guessContentType is a helper function for the transcludeSubitem and linkSubItem functions defined below.
     3.8 -function guessContentType() {
     3.9 +// Executed when user clicks insert-name button defined in modify.html.
    3.10 +// When a page with subitems is modified, a subitems sidebar is present. User may
    3.11 +// position caret in textarea and click button to insert name into textarea.
    3.12 +function InsertName(fullname) {
    3.13      "use strict";
    3.14 -    // Used in the modify_text template to guess the data content type client-side
    3.15 -    // This approach has the advantage of reacting to content type changes for the
    3.16 -    // link/transclude code without having to re-fetch the page
    3.17 -    var match,
    3.18 -        meta_text = $("#f_meta_text").val(),
    3.19 -        ctype_regex = /["']contenttype["']\s*:\s*["']([\w-_+.]+\/[\w-_+.]+)(;|["'])/;
    3.20 -    if (meta_text) {
    3.21 -        match = ctype_regex.exec(meta_text);
    3.22 -        if (match) {return match[1]; }
    3.23 -    }
    3.24 -    // text/plain is the default value
    3.25 -    return "text/plain";
    3.26 -}
    3.27 -
    3.28 -// Executed when user clicks transclude-action button defined in modify_text.html.
    3.29 -// When a page with subitems is modified, a subitems sidebar is present. User may
    3.30 -// position caret in textarea and click button to insert transclusion into textarea.
    3.31 -function transcludeSubitem(subitem_name, fullname) {
    3.32 -    "use strict";
    3.33 -    function moinwiki(subitem_name, fullname) {
    3.34 -        // note: keep the many plusses, to avoid jinja2 templating kicking in
    3.35 -        // when seeing two curly opening / closing braces
    3.36 -        return "{" + "{" + fullname.replace("{" + "{", "\\" + "}" + "}") + "}" + "} ";
    3.37 -    }
    3.38 -    function mediawiki(subitem_name, fullname) {
    3.39 -        // note: keep the many plusses, to avoid jinja2 templating kicking in
    3.40 -        // when seeing two curly opening / closing braces
    3.41 -        return "{" + "{:" + fullname.replace("}" + "}", "\\" + "}" + "}") + "}" + "} ";
    3.42 -    }
    3.43 -    function rst(subitem_name, fullname) {
    3.44 -        return "\n.. include:: " + subitem_name + "\n";
    3.45 -    }
    3.46 -    function docbook(subitem_name, fullname) {
    3.47 -        return ""; //XXX: the docbook converter currently doesn't handle transclusion with <ref> tags
    3.48 -    }
    3.49 -    var transclude_formats = {
    3.50 -            "text/x.moin.wiki" : moinwiki,
    3.51 -            "text/x.moin.creole" : moinwiki,
    3.52 -            "text/x-mediawiki" : mediawiki,
    3.53 -            "text/x-rst" : rst,
    3.54 -            "application/docbook+xml" : docbook,
    3.55 -            "text/plain" : function (x) {return x + " "; }
    3.56 -        },
    3.57 -        ctype = guessContentType(),
    3.58 -        input_element = $("#f_content_form_data_text"),
    3.59 -        ctype_format = transclude_formats[ctype];
    3.60 -    if (!ctype_format) {
    3.61 -        ctype_format = transclude_formats["text/plain"];
    3.62 -    }
    3.63 -    input_element.val(input_element.val() + ctype_format(subitem_name, fullname));
    3.64 -    input_element.focus();
    3.65 -}
    3.66 -
    3.67 -// Executed when user clicks link-action button defined in modify_text.html.
    3.68 -// When a page with subitems is modified, a subitems sidebar is present. User may
    3.69 -// position caret in textarea and click button to insert link into textarea.
    3.70 -function linkSubitem(subitem_name, fullname) {
    3.71 -    "use strict";
    3.72 -    function moinwiki(subitem_name, fullname) {
    3.73 -        return "[[" + fullname.replace("]", "\\]") + "|" + subitem_name.replace("]", "\\]") + "]] ";
    3.74 -    }
    3.75 -    function rst(subitem_name, fullname) {
    3.76 -        return "`" + subitem_name.replace(">", "\\>").replace("`", "\\`") + " <" + fullname.replace(">", "\\>") + ">`_ ";
    3.77 -    }
    3.78 -    function docbook(subitem_name, fullname) {
    3.79 -        return '<ulink url="/' + fullname.replace('"', '\\"') + '">' + subitem_name + "</ulink>";
    3.80 -    }
    3.81 -    var link_formats = {
    3.82 -            "text/x.moin.wiki" : moinwiki,
    3.83 -            "text/x.moin.creole" : moinwiki,
    3.84 -            "text/x-mediawiki" : moinwiki,
    3.85 -            "text/x-rst" : rst,
    3.86 -            "application/docbook+xml" : docbook,
    3.87 -            "text/plain" : function (x) {return x + " "; }
    3.88 -        },
    3.89 -        ctype = guessContentType(),
    3.90 -        input_element = $("#f_content_form_data_text"),
    3.91 -        ctype_format = link_formats[ctype];
    3.92 -    if (!ctype_format) {
    3.93 -        ctype_format = link_formats["text/plain"];
    3.94 -    }
    3.95 -    input_element.val(input_element.val() + ctype_format(subitem_name, fullname));
    3.96 -    input_element.focus();
    3.97 +    var textArea, scrollTop, endPos, startPos;
    3.98 +    textArea = document.getElementById('f_content_form_data_text');
    3.99 +    startPos = textArea.selectionStart;
   3.100 +    endPos = textArea.selectionEnd;
   3.101 +    textArea.value = textArea.value.substring(0, startPos) + fullname + textArea.value.substring(endPos, textArea.value.length);
   3.102 +    textArea.focus();
   3.103 +    textArea.setSelectionRange(startPos+fullname.length,startPos+fullname.length);
   3.104  }
   3.105  
   3.106  
     4.1 --- a/MoinMoin/templates/modify.html	Thu Apr 11 21:23:36 2013 +0530
     4.2 +++ b/MoinMoin/templates/modify.html	Thu Apr 11 21:00:12 2013 +0200
     4.3 @@ -23,11 +23,8 @@
     4.4      {% call(fullname, shortname, contenttype, has_children) utils.render_subitem_navigation(item_name, True) %}
     4.5          {% set shortname = shortname|json_dumps %}
     4.6          {% set fullname = fullname|json_dumps %}
     4.7 -        <button class="link-action" onclick='linkSubitem({{ shortname }}, {{ fullname }})'
     4.8 -            title="{{ _('Link to Subitem') }}">{{ _('Link') }}</button>
     4.9 -        <button class="transclude-action"
    4.10 -            onclick='transcludeSubitem({{ shortname }}, {{ fullname }})'
    4.11 -            title="{{ _('Transclude Subitem') }}">{{ _('Transclude') }}</button>
    4.12 +        <button class="moin-insertname-action" onclick='InsertName({{ fullname }})'
    4.13 +            title="{{ _('Insert Name') }}">{{ _('Insert Name') }}</button>
    4.14      {% endcall %}
    4.15  {% endblock %}
    4.16  
     5.1 --- a/MoinMoin/themes/foobar/static/css/stylus/main.styl	Thu Apr 11 21:23:36 2013 +0530
     5.2 +++ b/MoinMoin/themes/foobar/static/css/stylus/main.styl	Thu Apr 11 21:00:12 2013 +0200
     5.3 @@ -1038,8 +1038,7 @@
     5.4      text-indent -9000%
     5.5      box-shadow none
     5.6  
     5.7 -.link-action,
     5.8 -.transclude-action
     5.9 +.moin-insertname-action
    5.10      border: hidden
    5.11      text-indent: -9000%
    5.12      padding: 0
    5.13 @@ -1050,12 +1049,8 @@
    5.14      overflow: hidden
    5.15      cursor: pointer
    5.16      box-shadow none
    5.17 -
    5.18 -.link-action
    5.19      background: url(../img/moin-link.png) no-repeat center center
    5.20  
    5.21 -.transclude-action
    5.22 -    background: url(../img/moin-transclusion.png) no-repeat center center
    5.23  
    5.24  // transclusion
    5.25  .moin-transclusion
     6.1 --- a/MoinMoin/themes/modernized/static/css/stylus/main.styl	Thu Apr 11 21:23:36 2013 +0530
     6.2 +++ b/MoinMoin/themes/modernized/static/css/stylus/main.styl	Thu Apr 11 21:00:12 2013 +0200
     6.3 @@ -1412,8 +1412,7 @@
     6.4      border hidden
     6.5      text-indent -9000%
     6.6  
     6.7 -.link-action,
     6.8 -.transclude-action
     6.9 +.moin-insertname-action
    6.10      border hidden
    6.11      text-indent -9000%
    6.12      padding 0
    6.13 @@ -1424,13 +1423,8 @@
    6.14      overflow hidden
    6.15      cursor pointer
    6.16      box-shadow none
    6.17 -
    6.18 -.moin-subitem-navigation .link-action
    6.19      background url(../img/moin-link.png) no-repeat center center
    6.20  
    6.21 -.moin-subitem-navigation .transclude-action
    6.22 -    background url(../img/moin-transclusion.png) no-repeat center center
    6.23 -
    6.24  #moin-footer
    6.25      clear both
    6.26      margin 0 0