Commits

Thomas Waldmann committed a5b0f75 Merge

merged

Comments (0)

Files changed (6)

MoinMoin/forms.py

 from flatland.validation import Validator, Present, IsEmail, ValueBetween, URLValidator, Converted, ValueAtLeast
 from flatland.exc import AdaptationError
 
+from whoosh.query import Term, Or, Not, And
+
 from flask import g as flaskg
 
 from MoinMoin.constants.forms import *
-from MoinMoin.constants.keys import ITEMID, NAME
+from MoinMoin.constants.keys import ITEMID, NAME, LATEST_REVS
 from MoinMoin.i18n import _, L_, N_
 from MoinMoin.util.forms import FileStorage
 
     """Validator for JSON
     """
     invalid_json_msg = L_('Invalid JSON.')
+    invalid_name_msg = ""
+
+    def validname(self, meta, name, itemid):
+        names = meta.get(NAME)
+        if names is None:
+            self.invalid_name_msg = L_("No name field in the JSON meta.")
+            return False
+        if len(names) != len(set(names)):
+            self.invalid_name_msg = L_("The names in the JSON name list must be unique.")
+            return False
+        query = Or([Term(NAME, x) for x in names])
+        if itemid is not None:
+            query = And([query, Not(Term(ITEMID, itemid))])
+        duplicate_names = set()
+        with flaskg.storage.indexer.ix[LATEST_REVS].searcher() as searcher:
+            results = searcher.search(query)
+            for result in results:
+                duplicate_names |= set([x for x in result[NAME] if x in names])
+        if duplicate_names:
+            self.invalid_name_msg = L_("Item(s) named %(duplicate_names)s already exist.", duplicate_names=", ".join(duplicate_names))
+            return False
+        return True
 
     def validate(self, element, state):
         try:
-            json.loads(element.value)
+            meta = json.loads(element.value)
         except:  # catch ANY exception that happens due to unserializing
             return self.note_error(element, state, 'invalid_json_msg')
+        if not self.validname(meta, state[NAME], state[ITEMID]):
+            return self.note_error(element, state, 'invalid_name_msg')
         return True
 
 JSON = OptionalMultilineText.with_properties(lang='en', dir='ltr').validated_by(ValidJSON())

MoinMoin/items/__init__.py

                     # break them
                     return "OK"
             form = self.ModifyForm.from_request(request)
-            if form.validate():
+            state = dict(name=self.name, itemid=self.meta.get(ITEMID))
+            if form.validate(state):
                 meta, data, contenttype_guessed, comment = form._dump(self)
                 contenttype_qs = request.values.get('contenttype')
                 try:

MoinMoin/templates/common.js

 
 
 
-// guessContentType is a helper function for the transcludeSubitem and linkSubItem functions defined below.
-function guessContentType() {
+// Executed when user clicks insert-name button defined in modify.html.
+// When a page with subitems is modified, a subitems sidebar is present. User may
+// position caret in textarea and click button to insert name into textarea.
+function InsertName(fullname) {
     "use strict";
-    // Used in the modify_text template to guess the data content type client-side
-    // This approach has the advantage of reacting to content type changes for the
-    // link/transclude code without having to re-fetch the page
-    var match,
-        meta_text = $("#f_meta_text").val(),
-        ctype_regex = /["']contenttype["']\s*:\s*["']([\w-_+.]+\/[\w-_+.]+)(;|["'])/;
-    if (meta_text) {
-        match = ctype_regex.exec(meta_text);
-        if (match) {return match[1]; }
-    }
-    // text/plain is the default value
-    return "text/plain";
-}
-
-// Executed when user clicks transclude-action button defined in modify_text.html.
-// When a page with subitems is modified, a subitems sidebar is present. User may
-// position caret in textarea and click button to insert transclusion into textarea.
-function transcludeSubitem(subitem_name, fullname) {
-    "use strict";
-    function moinwiki(subitem_name, fullname) {
-        // note: keep the many plusses, to avoid jinja2 templating kicking in
-        // when seeing two curly opening / closing braces
-        return "{" + "{" + fullname.replace("{" + "{", "\\" + "}" + "}") + "}" + "} ";
-    }
-    function mediawiki(subitem_name, fullname) {
-        // note: keep the many plusses, to avoid jinja2 templating kicking in
-        // when seeing two curly opening / closing braces
-        return "{" + "{:" + fullname.replace("}" + "}", "\\" + "}" + "}") + "}" + "} ";
-    }
-    function rst(subitem_name, fullname) {
-        return "\n.. include:: " + subitem_name + "\n";
-    }
-    function docbook(subitem_name, fullname) {
-        return ""; //XXX: the docbook converter currently doesn't handle transclusion with <ref> tags
-    }
-    var transclude_formats = {
-            "text/x.moin.wiki" : moinwiki,
-            "text/x.moin.creole" : moinwiki,
-            "text/x-mediawiki" : mediawiki,
-            "text/x-rst" : rst,
-            "application/docbook+xml" : docbook,
-            "text/plain" : function (x) {return x + " "; }
-        },
-        ctype = guessContentType(),
-        input_element = $("#f_content_form_data_text"),
-        ctype_format = transclude_formats[ctype];
-    if (!ctype_format) {
-        ctype_format = transclude_formats["text/plain"];
-    }
-    input_element.val(input_element.val() + ctype_format(subitem_name, fullname));
-    input_element.focus();
-}
-
-// Executed when user clicks link-action button defined in modify_text.html.
-// When a page with subitems is modified, a subitems sidebar is present. User may
-// position caret in textarea and click button to insert link into textarea.
-function linkSubitem(subitem_name, fullname) {
-    "use strict";
-    function moinwiki(subitem_name, fullname) {
-        return "[[" + fullname.replace("]", "\\]") + "|" + subitem_name.replace("]", "\\]") + "]] ";
-    }
-    function rst(subitem_name, fullname) {
-        return "`" + subitem_name.replace(">", "\\>").replace("`", "\\`") + " <" + fullname.replace(">", "\\>") + ">`_ ";
-    }
-    function docbook(subitem_name, fullname) {
-        return '<ulink url="/' + fullname.replace('"', '\\"') + '">' + subitem_name + "</ulink>";
-    }
-    var link_formats = {
-            "text/x.moin.wiki" : moinwiki,
-            "text/x.moin.creole" : moinwiki,
-            "text/x-mediawiki" : moinwiki,
-            "text/x-rst" : rst,
-            "application/docbook+xml" : docbook,
-            "text/plain" : function (x) {return x + " "; }
-        },
-        ctype = guessContentType(),
-        input_element = $("#f_content_form_data_text"),
-        ctype_format = link_formats[ctype];
-    if (!ctype_format) {
-        ctype_format = link_formats["text/plain"];
-    }
-    input_element.val(input_element.val() + ctype_format(subitem_name, fullname));
-    input_element.focus();
+    var textArea, scrollTop, endPos, startPos;
+    textArea = document.getElementById('f_content_form_data_text');
+    startPos = textArea.selectionStart;
+    endPos = textArea.selectionEnd;
+    textArea.value = textArea.value.substring(0, startPos) + fullname + textArea.value.substring(endPos, textArea.value.length);
+    textArea.focus();
+    textArea.setSelectionRange(startPos+fullname.length,startPos+fullname.length);
 }
 
 

MoinMoin/templates/modify.html

     {% call(fullname, shortname, contenttype, has_children) utils.render_subitem_navigation(item_name, True) %}
         {% set shortname = shortname|json_dumps %}
         {% set fullname = fullname|json_dumps %}
-        <button class="link-action" onclick='linkSubitem({{ shortname }}, {{ fullname }})'
-            title="{{ _('Link to Subitem') }}">{{ _('Link') }}</button>
-        <button class="transclude-action"
-            onclick='transcludeSubitem({{ shortname }}, {{ fullname }})'
-            title="{{ _('Transclude Subitem') }}">{{ _('Transclude') }}</button>
+        <button class="moin-insertname-action" onclick='InsertName({{ fullname }})'
+            title="{{ _('Insert Name') }}">{{ _('Insert Name') }}</button>
     {% endcall %}
 {% endblock %}
 

MoinMoin/themes/foobar/static/css/stylus/main.styl

     text-indent -9000%
     box-shadow none
 
-.link-action,
-.transclude-action
+.moin-insertname-action
     border: hidden
     text-indent: -9000%
     padding: 0
     overflow: hidden
     cursor: pointer
     box-shadow none
-
-.link-action
     background: url(../img/moin-link.png) no-repeat center center
 
-.transclude-action
-    background: url(../img/moin-transclusion.png) no-repeat center center
 
 // transclusion
 .moin-transclusion

MoinMoin/themes/modernized/static/css/stylus/main.styl

     border hidden
     text-indent -9000%
 
-.link-action,
-.transclude-action
+.moin-insertname-action
     border hidden
     text-indent -9000%
     padding 0
     overflow hidden
     cursor pointer
     box-shadow none
-
-.moin-subitem-navigation .link-action
     background url(../img/moin-link.png) no-repeat center center
 
-.moin-subitem-navigation .transclude-action
-    background url(../img/moin-transclusion.png) no-repeat center center
-
 #moin-footer
     clear both
     margin 0 0