Merge branch 'master' into with-dvcs
authorRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Fri, 19 Aug 2011 11:20:03 +0000 (13:20 +0200)
committerRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Fri, 19 Aug 2011 11:20:03 +0000 (13:20 +0200)
apps/wiki/templates/wiki/tabs/summary_view.html
lib/vstorage/__init__.py
redakcja/settings/compress.py
redakcja/static/css/html.css
redakcja/static/js/lib/jquery/jquery.xmlns.js [new file with mode: 0644]
redakcja/static/js/wiki/view_summary.js
redakcja/static/js/wiki/wikiapi.js
redakcja/static/js/wiki/xslt.js

index 73eece2..53e6cdf 100644 (file)
                        <span data-ui-editable="true" data-edit-target="meta.galleryLink"
                        >{{ chunk.book.gallery }}</span>
                </p>
+               <p>
+                   <label>{% trans "Characters in document" %}:</label>
+                   <span id="charcount"></span> (<span id="charcount_pages"></span> {% trans "pages" %}<span id="charcount_untagged">, {% trans "untagged" %}</span>)
+               </p>
 
                <p><button type="button" id="publish_button">{% trans "Publish" %}</button></p>
        </div>
index a98f8de..2708ed7 100644 (file)
@@ -162,7 +162,7 @@ class VersionedStorage(object):
 
     def _file_to_title(self, filename):
         assert filename.startswith(self.repo_prefix)
-        name = filename[len(self.repo_prefix):].strip('/').split('.', 1)[0]
+        name = filename[len(self.repo_prefix):].strip('/').rsplit('.', 1)[0]
         return urlunquote(name)
 
     def __contains__(self, title):
index bf3e817..db72c00 100644 (file)
@@ -30,6 +30,7 @@ COMPRESS_JS = {
                 'js/lib/jquery/jquery.autocomplete.js',
                 'js/lib/jquery/jquery.blockui.js',
                 'js/lib/jquery/jquery.elastic.js',
+                'js/lib/jquery/jquery.xmlns.js',
                 'js/button_scripts.js',
                 'js/slugify.js',
 
index 3255d75..0d43611 100644 (file)
@@ -37,7 +37,7 @@
  -webkit-border-radius: 4px;
  }
  */
-.htmlview *[x-node = 'RDF'] {
+.htmlview *[x-node = 'RDF'][x-ns = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'] {
     display: none;
 }
 
diff --git a/redakcja/static/js/lib/jquery/jquery.xmlns.js b/redakcja/static/js/lib/jquery/jquery.xmlns.js
new file mode 100644 (file)
index 0000000..96c5a55
--- /dev/null
@@ -0,0 +1,411 @@
+//
+//  jquery.xmlns.js:  xml-namespace selector support for jQuery
+//
+//  This plugin modifies the jQuery tag and attribute selectors to
+//  support optional namespace specifiers as defined in CSS 3:
+//
+//    $("elem")      - matches 'elem' nodes in the default namespace
+//    $("|elem")     - matches 'elem' nodes that don't have a namespace
+//    $("NS|elem")   - matches 'elem' nodes in declared namespace 'NS'
+//    $("*|elem")    - matches 'elem' nodes in any namespace
+//    $("NS|*")      - matches any nodes in declared namespace 'NS'
+//
+//  A similar synax is also supported for attribute selectors, but note
+//  that the default namespace does *not* apply to attributes - a missing
+//  or empty namespace selector selects only attributes with no namespace.
+//
+//  In a slight break from the W3C standards, and with a nod to ease of
+//  implementation, the empty namespace URI is treated as equivalent to
+//  an unspecified namespace.  Plenty of browsers seem to make the same
+//  assumption...
+//
+//  Namespace declarations live in the $.xmlns object, which is a simple
+//  mapping from namespace ids to namespace URIs.  The default namespace
+//  is determined by the value associated with the empty string.
+//
+//    $.xmlns.D = "DAV:"
+//    $.xmlns.FOO = "http://www.foo.com/xmlns/foobar"
+//    $.xmlns[""] = "http://www.example.com/new/default/namespace/"
+//
+//  Unfortunately this is a global setting - I can't find a way to do
+//  query-object-specific namespaces since the jQuery selector machinery
+//  is stateless.  However, you can use the 'xmlns' function to push and
+//  pop namespace delcarations with ease:
+//
+//    $().xmlns({D:"DAV:"})     // pushes the DAV: namespace
+//    $().xmlns("DAV:")         // makes DAV: the default namespace
+//    $().xmlns(false)          // pops the namespace we just pushed
+//    $().xmlns(false)          // pops again, returning to defaults
+//
+//  To execute this as a kind of "transaction", pass a function as the
+//  second argument.  It will be executed in the context of the current
+//  jQuery object:
+//
+//    $().xmlns("DAV:",function() {
+//      //  The default namespace is DAV: within this function,
+//      //  but it is reset to the previous value on exit.
+//      return this.find("response").each(...);
+//    }).find("div")
+//
+//  If you pass a string as a function, it will be executed against the
+//  current jQuery object using find(); i.e. the following will find all
+//  "href" elements in the "DAV:" namespace:
+//
+//    $().xmlns("DAV:","href")
+//
+// 
+//  And finally, the legal stuff:
+//
+//    Copyright (c) 2009, Ryan Kelly.
+//    TAG and ATTR functions derived from jQuery's selector.js.
+//    Dual licensed under the MIT and GPL licenses.
+//    http://docs.jquery.com/License
+//
+
+(function($) {
+
+//  Some common default namespaces, that are treated specially by browsers.
+//
+var default_xmlns = {
+    "xml": "http://www.w3.org/XML/1998/namespace",
+    "xmlns": "http://www.w3.org/2000/xmlns/",
+    "html": "http://www.w3.org/1999/xhtml/"
+};
+
+//  A reverse mapping for common namespace prefixes.
+//
+var default_xmlns_rev = {}
+for(var k in default_xmlns) {
+    default_xmlns_rev[default_xmlns[k]] = k;
+}
+
+
+//  $.xmlns is a mapping from namespace identifiers to namespace URIs.
+//  The default default-namespace is "*", and we provide some additional
+//  defaults that are specified in the XML Namespaces standard.
+//
+$.extend({xmlns: $.extend({},default_xmlns,{"":"*"})});
+
+
+//  jQuery method to push/pop namespace declarations.
+//
+//  If a single argument is specified:
+//    * if it's a mapping, push those namespaces onto the stack
+//    * if it's a string, push that as the default namespace
+//    * if it evaluates to false, pop the latest namespace
+//
+//  If two arguments are specified, the second is executed "transactionally"
+//  using the namespace declarations found in the first.  It can be either a
+//  a selector string (in which case it is passed to this.find()) or a function
+//  (in which case it is called in the context of the current jQuery object).
+//  The given namespace mapping is automatically pushed before executing and
+//  popped afterwards.
+//
+var xmlns_stack = [];
+$.fn.extend({xmlns: function(nsmap,func) {
+    if(typeof nsmap == "string") {
+        nsmap = {"":nsmap};
+    }
+    if(nsmap) {
+        xmlns_stack.push($.xmlns);
+        $.xmlns = $.extend({},$.xmlns,nsmap);
+        if(func !== undefined) {
+            if(typeof func == "string") {
+                return this.find(func).xmlns(undefined)
+            } else {
+                var self = this;
+                try {
+                    self = func.call(this);
+                    if(!self) {
+                        self = this;
+                    }
+                } finally {
+                    self.xmlns(undefined);
+                }
+                return self
+            }
+        } else {
+            return this;
+        }
+    } else {
+        $.xmlns = (xmlns_stack ? xmlns_stack.pop() : {});
+        return this;
+    }
+}});
+
+
+//  Convert a namespace prefix into a namespace URI, based
+//  on the delcarations made in $.xmlns.
+//
+var getNamespaceURI = function(id) {
+    // No namespace id, use the default.
+    if(!id) {
+        return $.xmlns[""];
+    }
+    // Strip the pipe character from the specifier
+    id = id.substr(0,id.length-1);
+    // Certain special namespaces aren't mapped to a URI
+    if(id == "" || id == "*") {
+        return id;
+    }
+    var ns = $.xmlns[id];
+    if(typeof(ns) == "undefined") {
+        throw "Syntax error, undefined namespace prefix '" + id + "'";
+    }
+    return ns;
+};
+
+
+//  Update the regex used by $.expr to parse selector components for a
+//  particular type of selector (e.g. "TAG" or "ATTR").
+//
+//  This logic is taken straight from the jQuery/Sizzle sources.
+//
+var setExprMatchRegex = function(type,regex) {
+  $.expr.match[type] = new RegExp(regex.source + /(?![^\[]*\])(?![^\(]*\))/.source);
+  if($.expr.leftMatch) {
+      $.expr.leftMatch[type] = new RegExp(/(^(?:.|\r|\n)*?)/.source + $.expr.match[type].source.replace(/\\(\d+)/g, function(all, num){
+          return "\\" + (num - 0 + 1);
+      }));
+  }
+}
+
+
+
+//  Modify the TAG match regexp to include optional namespace selector.
+//  This is basically (namespace|)?(tagname).
+//
+setExprMatchRegex("TAG",/^((?:((?:[\w\u00c0-\uFFFF\*_-]*\|)?)((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)))/);
+
+
+//  Perform some capability-testing.
+//
+var div = document.createElement("div");
+
+//  Sometimes getElementsByTagName("*") will return comment nodes,
+//  which we will have to remove from the results.
+//
+var gebtn_yields_comments = false;
+div.appendChild(document.createComment(""));
+if(div.getElementsByTagName("*").length > 0) {
+    gebtn_yields_comments = true;
+}
+
+//  Some browsers return node.localName in upper case, some in lower case.
+//
+var localname_is_uppercase = true;
+if(div.localName && div.localName == "div") {
+    localname_is_uppercase = false;
+}
+
+//  Allow the testing div to be garbage-collected.
+//
+div = null;
+
+
+//  Modify the TAG find function to account for a namespace selector.
+//
+$.expr.find.TAG = function(match,context,isXML) {
+    var ns = getNamespaceURI(match[2]);
+    var ln = match[3];
+    var res;
+    if(typeof context.getElementsByTagNameNS != "undefined") {
+        //  Easy case - we have getElementsByTagNameNS
+        res = context.getElementsByTagNameNS(ns,ln);
+    } else if(typeof context.selectNodes != "undefined") {
+        //  Use xpath if possible (not available on HTML DOM nodes in IE)
+        if(context.ownerDocument) {
+            context.ownerDocument.setProperty("SelectionLanguage","XPath");
+        } else {
+            context.setProperty("SelectionLanguage","XPath");
+        }
+        var predicate = "";
+        if(ns != "*") {
+            if(ln != "*") {
+                predicate="namespace-uri()='"+ns+"' and local-name()='"+ln+"'";
+            } else {
+                predicate="namespace-uri()='"+ns+"'";
+            }
+        } else {
+            if(ln != "*") {
+                predicate="local-name()='"+ln+"'";
+            }
+        }
+        if(predicate) {
+            res = context.selectNodes("descendant-or-self::*["+predicate+"]");
+        } else {
+            res = context.selectNodes("descendant-or-self::*");
+        }
+    } else {
+        //  Otherwise, we need to simulate using getElementsByTagName
+        res = context.getElementsByTagName(ln); 
+        if(gebtn_yields_comments && ln == "*") {
+            var tmp = [];
+            for(var i=0; res[i]; i++) {
+                if(res[i].nodeType == 1) {
+                    tmp.push(res[i]);
+                }
+            }
+            res = tmp;
+        }
+        if(res && ns != "*") {
+            var tmp = [];
+            for(var i=0; res[i]; i++) {
+               if(res[i].namespaceURI == ns || res[i].tagUrn == ns) {
+                   tmp.push(res[i]);
+               }
+            }
+            res = tmp;
+        }
+    }
+    return res;
+};
+
+
+//  Check whether a node is part of an XML document.
+//  Copied verbatim from jQuery sources, needed in TAG preFilter below.
+//
+var isXML = function(elem){
+    return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
+            !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML";
+};
+
+
+//  Modify the TAG preFilter function to work with modified match regexp.
+//  This normalises case of the tag name if we're in a HTML document.
+//
+$.expr.preFilter.TAG = function(match, curLoop, inplace, result, not, isXML) {
+  var ln = match[3];
+  if(!isXML) {
+      if(localname_is_uppercase) {
+          ln = ln.toUpperCase();
+      } else {
+          ln = ln.toLowerCase();
+      }
+  }
+  return [match[0],getNamespaceURI(match[2]),ln];
+};
+
+
+//  Modify the TAG filter function to account for a namespace selector.
+//
+$.expr.filter.TAG = function(elem,match) {
+    var ns = match[1];
+    var ln = match[2];
+    var e_ns = elem.namespaceURI ? elem.namespaceURI : elem.tagUrn;
+    var e_ln = elem.localName ? elem.localName : elem.tagName;
+    if(ns == "*" || e_ns == ns || (ns == "" && !e_ns)) {
+        return ((ln == "*" && elem.nodeType == 1)  || e_ln == ln);
+    }
+    return false;
+};
+
+
+//  Modify the ATTR match regexp to extract a namespace selector.
+//  This is basically ([namespace|])(attrname)(op)(quote)(pattern)(quote)
+//
+setExprMatchRegex("ATTR",/\[\s*((?:((?:[\w\u00c0-\uFFFF\*_-]*\|)?)((?:[\w\u00c0-\uFFFF_-]|\\.)+)))\s*(?:(\S?=)\s*(['"]*)(.*?)\5|)\s*\]/);
+
+
+//  Modify the ATTR preFilter function to account for new regexp match groups,
+//  and normalise the namespace URI.
+//
+$.expr.preFilter.ATTR = function(match, curLoop, inplace, result, not, isXML) {
+    var name = match[3].replace(/\\/g, "");
+    if(!isXML && $.expr.attrMap[name]) {
+        match[3] = $.expr.attrMap[name];
+    }
+    if( match[4] == "~=" ) {
+        match[6] = " " + match[6] + " ";
+    }
+    if(!match[2] || match[2] == "|") {
+        match[2] = "";
+    } else {
+        match[2] = getNamespaceURI(match[2]);
+    }
+    return match;
+};
+
+
+//  Modify the ATTR filter function to account for namespace selector.
+//  Unfortunately this means factoring out the attribute-checking code
+//  into a separate function, since it might be called multiple times.
+//
+var filter_attr = function(result,type,check) {
+    var value = result + "";
+    return result == null ?
+                type === "!=" :
+                type === "=" ?
+                value === check :
+                type === "*=" ?
+                value.indexOf(check) >= 0 :
+                type === "~=" ?
+                (" " + value + " ").indexOf(check) >= 0 :
+                !check ?
+                value && result !== false :
+                type === "!=" ?
+                value != check :
+                type === "^=" ?
+                value.indexOf(check) === 0 :
+                type === "$=" ?
+                value.substr(value.length - check.length) === check :
+                type === "|=" ?
+                value === check || value.substr(0,check.length+1)===check+"-" :
+                false;
+}
+
+
+$.expr.filter.ATTR = function(elem, match) {
+    var ns = match[2];
+    var name = match[3];
+    var type = match[4];
+    var check = match[6];
+    var result;
+    //  No namespace, just use ordinary attribute lookup.
+    if(ns == "") {
+        result = $.expr.attrHandle[name] ?
+                     $.expr.attrHandle[name](elem) :
+                     elem[name] != null ?
+                         elem[name] :
+                         elem.getAttribute(name);
+        return filter_attr(result,type,check);
+    }
+    //  Directly use getAttributeNS if applicable and available
+    if(ns != "*" && typeof elem.getAttributeNS != "undefined") {
+        return filter_attr(elem.getAttributeNS(ns,name),type,check);
+    }
+    //  Need to iterate over all attributes, either because we couldn't
+    //  look it up or because we need to match all namespaces.
+    var attrs = elem.attributes;
+    for(var i=0; attrs[i]; i++) {
+        var ln = attrs[i].localName;
+        if(!ln) {
+            ln = attrs[i].nodeName
+            var idx = ln.indexOf(":");
+            if(idx >= 0) {
+                ln = ln.substr(idx+1);
+            }
+        }
+        if(ln == name) {
+            result = attrs[i].nodeValue;
+            if(ns == "*" || attrs[i].namespaceURI == ns) {
+                if(filter_attr(result,type,check)) {
+                    return true;
+                }
+            }
+            if(attrs[i].namespaceURI === "" && attrs[i].prefix) {
+                if(attrs[i].prefix == default_xmlns_rev[ns]) {
+                    if(filter_attr(result,type,check)) {
+                        return true;
+                    }
+                }
+            }
+        }
+    }
+    return false;
+};
+
+
+})(jQuery);
+
index 811096d..b16c288 100644 (file)
 
     SummaryPerspective.prototype = new $.wiki.Perspective();
 
+    SummaryPerspective.prototype.showCharCount = function() {
+        var cc;
+        try {
+            cc = this.doc.getLength();
+            $('#charcount_untagged').hide();
+        }
+        catch (e) {
+            $('#charcount_untagged').show();
+            cc = this.doc.text.replace(/\s{2,}/g, ' ').length;
+        }
+        $('#charcount').html(cc);
+        $('#charcount_pages').html((Math.round(cc/18)/100).toLocaleString());
+    }
+
     SummaryPerspective.prototype.freezeState = function(){
         // must
     };
 
        SummaryPerspective.prototype.onEnter = function(success, failure){
                $.wiki.Perspective.prototype.onEnter.call(this);
+               
+               this.showCharCount();
 
                console.log("Entered summery view");
        };
index 3907e8e..c8b3627 100644 (file)
                });
        };
 
+    WikiDocument.prototype.getLength = function(params) {
+        var xml = this.text.replace(/\/(\s+)/g, '<br />$1');
+        var parser = new DOMParser();
+        var doc = parser.parseFromString(xml, 'text/xml');
+        var error = $('parsererror', doc);
+
+        if (error.length > 0) {
+            throw "Not an XML document.";
+        }
+        $.xmlns["rdf"] = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; 
+        $('rdf|RDF, motyw, pa, pe, pr, pt', doc).remove();
+        var text = $(doc).text();
+        text = $.trim(text.replace(/\s{2,}/g, ' '));
+        return text.length;
+    }
+
+
        $.wikiapi.WikiDocument = WikiDocument;
 })(jQuery);
index 0390fd4..4f562a2 100644 (file)
@@ -61,7 +61,7 @@ function withThemes(code_block, onError)
 function xml2html(options) {
     withStylesheets(function() {
         var xml = options.xml.replace(/\/(\s+)/g, '<br />$1');
-        xml = xml.replace(/([^a-zA-Z0-9ąćęłńóśźżĄĆĘŁŃÓŚŹŻ\s<>«»\\*_!,:;?%."'=#()\/-]+)/g, '<alien>$1</alien>');
+        xml = xml.replace(/([^a-zA-Z0-9ąćęłńóśźżĄĆĘŁŃÓŚŹŻ\s<>«»\\*_!,:;?&%."'=#()\/-]+)/g, '<alien>$1</alien>');
         var parser = new DOMParser();
         var serializer = new XMLSerializer();
         var doc = parser.parseFromString(xml, 'text/xml');