preliminary search support
authorRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Fri, 30 Jul 2010 13:45:42 +0000 (15:45 +0200)
committerRadek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>
Tue, 3 Aug 2010 10:23:48 +0000 (12:23 +0200)
17 files changed:
apps/wiki/templates/wiki/document_details.html
apps/wiki/templates/wiki/document_details_base.html
apps/wiki/templates/wiki/tabs/gallery_view.html
apps/wiki/templates/wiki/tabs/gallery_view_item.html [new file with mode: 0644]
apps/wiki/templates/wiki/tabs/search_view.html [new file with mode: 0644]
apps/wiki/templates/wiki/tabs/search_view_item.html [new file with mode: 0644]
apps/wiki/templates/wiki/tabs/summary_view_item.html
redakcja/settings/compress.py
redakcja/static/css/gallery.css
redakcja/static/css/master.css
redakcja/static/js/lib/codemirror/codemirror.js
redakcja/static/js/lib/codemirror/editor.js
redakcja/static/js/wiki/base.js
redakcja/static/js/wiki/loader.js
redakcja/static/js/wiki/view_editor_source.js
redakcja/static/js/wiki/view_gallery.js
redakcja/static/js/wiki/view_search.js [new file with mode: 0644]

index 67b3c47..9657e0f 100644 (file)
        {% include "wiki/tabs/source_editor.html" %}
 {% endblock %}
 
+{% block tabs-right %}
+    {% include "wiki/tabs/gallery_view_item.html" %}
+    {% include "wiki/tabs/search_view_item.html" %}
+{% endblock %}
+
 {% block splitter-extra %}
-    {% include "wiki/tabs/gallery_view.html" %}
+<div class="vsplitbar" title="{% trans "Click to open/close gallery" %}">
+    </div>
+    <div id="sidebar">
+        {% include "wiki/tabs/gallery_view.html" %}
+        {% include "wiki/tabs/search_view.html" %}
+    </div>
 {% endblock %}
 
 {% block dialogs %}
index f86f936..3c6843d 100644 (file)
                        <span id='save-attempt-info'>{% trans "Save attempt in progress" %}</span>
                {% endif %}
     </div>
-    <ol id="tabs">
+    <ol id="tabs" class="tabs">
        {% block tabs-menu %} {% endblock %}
     </ol>
+    <ol id="tabs-right" class="tabs">
+        {% block tabs-right %} {% endblock %}
+    </ol>
 </div>
 <div id="splitter">
     <div id="editor" class="{% block editor-class %} {% endblock %}">
index 47f6af2..7bf6584 100644 (file)
@@ -1,6 +1,4 @@
 {% load i18n %}
-<div class="vsplitbar" title="{% trans "Click to open/close gallery" %}">
-</div>
 <div id="side-gallery">
     <!-- gallery toolbar -->
     <div class="toolbar">
diff --git a/apps/wiki/templates/wiki/tabs/gallery_view_item.html b/apps/wiki/templates/wiki/tabs/gallery_view_item.html
new file mode 100644 (file)
index 0000000..7325c82
--- /dev/null
@@ -0,0 +1,4 @@
+{% load i18n %}
+<li id="ScanGalleryPerspective" data-ui-related="side-gallery" data-ui-jsclass="ScanGalleryPerspective" class='active'>
+    <span>{% trans "Gallery" %}</span>
+</li>
diff --git a/apps/wiki/templates/wiki/tabs/search_view.html b/apps/wiki/templates/wiki/tabs/search_view.html
new file mode 100644 (file)
index 0000000..4bf1e89
--- /dev/null
@@ -0,0 +1,19 @@
+{% load i18n %}
+<div id='side-search'>
+    <p>{% trans "Search" %}:<br/>
+    <input id='search-input' /><br/>
+    <button id='search-button'>{% trans "Search" %}</button>
+    </p>
+
+    <p>{% trans "Replace with" %}:<br/>
+        <input id='replace-input' /><br/>
+        <button id='replace-button'>{% trans "Replace" %}</button><br/>
+    </p>
+
+    <p>{% trans "Options" %}<br/>
+        <input type="checkbox" id="search-case-sensitive" />
+            <label for="search-case-sensitive">{% trans "Case sensitive" %}</label><br/>
+        <input type="checkbox" id="search-from-cursor" />
+            <label for="search-from-cursor">{% trans "From cursor" %}</label><br/>
+    </p>
+</div>
\ No newline at end of file
diff --git a/apps/wiki/templates/wiki/tabs/search_view_item.html b/apps/wiki/templates/wiki/tabs/search_view_item.html
new file mode 100644 (file)
index 0000000..dbd4e09
--- /dev/null
@@ -0,0 +1,4 @@
+{% load i18n %}
+<li id="SearchPerspective" data-ui-related="side-search" data-ui-jsclass="SearchPerspective">
+    <span>{% trans "Search and replace" %}</span>
+</li>
index 79c9f8f..2b4daeb 100644 (file)
@@ -1,5 +1,5 @@
 {% load i18n %}
 {% load wiki %}
 <li id="SummaryPerspective" data-ui-related="summary-view-editor" data-ui-jsclass="SummaryPerspective">
-    <span>{{ document.name|wiki_title }}</span>
+    <span>{% trans "Summary" %}</span>
 </li>
index 7207f1b..5e8d721 100644 (file)
@@ -51,6 +51,7 @@ COMPRESS_JS = {
                 'js/wiki/view_editor_source.js',
                 'js/wiki/view_editor_wysiwyg.js',
                 'js/wiki/view_gallery.js',
+                'js/wiki/view_search.js',
                 'js/wiki/view_column_diff.js',
         ),
         'output_filename': 'compressed/detail_scripts_?.js',
index 97c9c12..9c6e3a5 100644 (file)
@@ -1,18 +1,27 @@
-/* =========== */
-/* = Gallery = */
-/* =========== */
-
-#side-gallery {
+#sidebar {
+    display:none;
     position: absolute;
-    /* overflow: hidden; */
     top: 0px;
     right: 0px;
     bottom: 0px;
     width: 480px;
-    display: none;
     background-color: #FFF;
 }
 
+#side-search {
+    height: 100%;
+    display: none;
+    background-color: #C1C1C1;
+}
+
+#side-search p {
+    padding: .5em;
+}
+
+/* =========== */
+/* = Gallery = */
+/* =========== */
+
 #side-gallery .error_message
 {
        background-color: white;
index fd05daa..cbfe66a 100644 (file)
@@ -117,16 +117,22 @@ body {
     color: #222;
 }
 
-#tabs {
+.tabs {
        overflow: hidden;
     margin: 0;
        padding: 0;
        height: 31px;
        border: 0px;
        padding-left: 1em;
+    float: left;
+}
+
+#tabs-right {
+    float: right;
+    padding-right: 1em;
 }
 
-#tabs li {
+.tabs li {
        height: 18px;
        margin-top: 6px;
        margin-bottom: 0px;
@@ -157,7 +163,7 @@ body {
     -webkit-border-bottom-right-radius: 0px;
 }
 
-#tabs li.active {
+.tabs li.active {
     background-color: #C1C1C1;
 }
 
index 8c62dab..8475989 100644 (file)
@@ -177,8 +177,8 @@ var CodeMirror = (function(){
     replaceChars: function(text, start, end) {
       this.editor.replaceChars(text, start, end);
     },
-    getSearchCursor: function(string, fromCursor) {
-      return this.editor.getSearchCursor(string, fromCursor);
+    getSearchCursor: function(string, fromCursor, regexp, case_sensitive) {
+      return this.editor.getSearchCursor(string, fromCursor, regexp, case_sensitive);
     },
 
     undo: function() {this.editor.history.undo();},
index f5fe841..4eb6d09 100644 (file)
@@ -223,7 +223,29 @@ var Editor = (function(){
   // indicating whether anything was found, and can be called again to
   // skip to the next find. Use the select and replace methods to
   // actually do something with the found locations.
-  function SearchCursor(editor, string, fromCursor) {
+  function SearchCursor(editor, string, fromCursor, regexp, case_sensitive) {
+
+    function casedIndexOf(hay, needle, case_sensitive) {
+        if (case_sensitive)
+            return hay.indexOf(needle);
+        else
+            return hay.toLowerCase().indexOf(needle.toLowerCase())
+    }
+
+    function casedLastIndexOf(hay, needle, case_sensitive) {
+        if (case_sensitive)
+            return hay.lastIndexOf(needle);
+        else
+            return hay.toLowerCase().lastIndexOf(needle.toLowerCase());
+    }
+
+    function casedEqual(a, b, case_sensitive) {
+        if (case_sensitive)
+            return a == b;
+        else
+            return a.toLowerCase() == b.toLowerCase();
+    }
+
     this.editor = editor;
     this.history = editor.history;
     this.history.commit();
@@ -252,7 +274,8 @@ var Editor = (function(){
       // For one-line strings, searching can be done simply by calling
       // indexOf on the current line.
       function() {
-        var match = cleanText(self.history.textAfter(self.line).slice(self.offset)).indexOf(string);
+        var match = casedIndexOf(cleanText(self.history.textAfter(self.line).slice(self.offset)),
+                string, case_sensitive);
         if (match > -1)
           return {from: {node: self.line, offset: self.offset + match},
                   to: {node: self.line, offset: self.offset + match + string.length}};
@@ -262,19 +285,19 @@ var Editor = (function(){
       // end of the line and the last match starts at the start.
       function() {
         var firstLine = cleanText(self.history.textAfter(self.line).slice(self.offset));
-        var match = firstLine.lastIndexOf(target[0]);
+        var match = casedLastIndexOf(firstLine, target[0], case_sensitive);
         if (match == -1 || match != firstLine.length - target[0].length)
           return false;
         var startOffset = self.offset + match;
 
         var line = self.history.nodeAfter(self.line);
         for (var i = 1; i < target.length - 1; i++) {
-          if (cleanText(self.history.textAfter(line)) != target[i])
+          if (!casedEqual(cleanText(self.history.textAfter(line)), target[i], case_sensitive))
             return false;
           line = self.history.nodeAfter(line);
         }
 
-        if (cleanText(self.history.textAfter(line)).indexOf(target[target.length - 1]) != 0)
+        if (casedIndexOf(cleanText(self.history.textAfter(line)), target[target.length - 1], case_sensitive) != 0)
           return false;
 
         return {from: {node: self.line, offset: startOffset},
@@ -619,8 +642,8 @@ var Editor = (function(){
               offset: lastLine.length};
     },
 
-    getSearchCursor: function(string, fromCursor) {
-      return new SearchCursor(this, string, fromCursor);
+    getSearchCursor: function(string, fromCursor, regexp, case_sensitive) {
+      return new SearchCursor(this, string, fromCursor, regexp, case_sensitive);
     },
 
     // Re-indent the whole buffer
index 61a3949..de1d8e5 100644 (file)
                if($tab.length != 1)
                        $tab = $(DEFAULT_PERSPECTIVE);
 
-               var $old = $('#tabs li').filter('.active');
+               var $old = $tab.closest('.tabs').find('.active');
 
                $old.each(function(){
                        $(this).removeClass('active');
index e2d4d2b..58a12e1 100644 (file)
@@ -36,7 +36,7 @@ $(function()
                /*
                 * TABS
                 */
-        $('#tabs li').live('click', function(event, callback) {
+        $('.tabs li').live('click', function(event, callback) {
                        $.wiki.switchToTab(this);
         });
 
@@ -62,19 +62,19 @@ $(function()
         $('.vsplitbar').toggle(
                        function() {
                                $.wiki.state.perspectives.ScanGalleryPerspective.show = true;
-                               $('#side-gallery').show();
-                               $('.vsplitbar').css('right', 480).addClass('.active');
+                               $('#sidebar').show();
+                               $('.vsplitbar').css('right', 480).addClass('active');
                                $('#editor .editor').css('right', 510);
                                $(window).resize();
-                               gallery.onEnter();
+                               $.wiki.perspectiveForTab('#tabs-right .active').onEnter();
                        },
                        function() {
                                $.wiki.state.perspectives.ScanGalleryPerspective.show = false;
-                               $('#side-gallery').hide();
+                               $('#sidebar').hide();
                                $('.vsplitbar').css('right', 0).removeClass('active');
                                $('#editor .editor').css('right', 30);
                                $(window).resize();
-                               gallery.onExit();
+                               $.wiki.perspectiveForTab('#tabs-right .active').onExit();
                        }
                );
 
@@ -137,6 +137,6 @@ $(function()
        /*
         * Initialize all perspectives
         */
-       initAll( $.makeArray($('ol#tabs li')), initialize);
+       initAll( $.makeArray($('.tabs li')), initialize);
        console.log(location.hash);
 });
index 9fc9922..0597140 100644 (file)
                console.log('Exiting', this.doc);
                this.doc.setText(this.codemirror.getCode());
 
+        if ($('.vsplitbar').hasClass('active') && $('#SearchPerspective').hasClass('active')) {
+            $.wiki.switchToTab('#ScanGalleryPerspective');
+        }
+
                if(success) success();
        }
 
index c487d46..1be30bf 100644 (file)
 
         $.wiki.Perspective.prototype.onEnter.call(this);
 
+        $('.vsplitbar').not('.active').trigger('click');
+
         this.doc.refreshGallery({
             success: function(doc, data){
                 self.$image.show();
diff --git a/redakcja/static/js/wiki/view_search.js b/redakcja/static/js/wiki/view_search.js
new file mode 100644 (file)
index 0000000..34393dc
--- /dev/null
@@ -0,0 +1,113 @@
+(function($){
+
+    /*
+     * Perspective
+     */
+    function SearchPerspective(options){
+        var old_callback = options.callback || function() { };
+
+        this.noupdate_hash_onenter = true;
+
+        options.callback = function(){
+            var self = this;
+
+            this.editor = null;
+            this.$element = $("#side-search");
+            this.$searchInput = $('#search-input', this.$element);
+            this.$replaceInput = $('#replace-input', this.$element);
+            this.$searchButton = $('#search-button', this.$element);
+            this.$replaceButton = $('#replace-button', this.$element);
+
+            this.$replaceButton.attr("disabled","disabled");
+            this.options = Array();
+
+            // handlers
+            this.$searchInput.change(function(event){
+                self.searchCursor = null;
+            });
+            this.$replaceInput.change(function(event){
+                self.searchCursor = null;
+            });
+
+            $("#side-search input:checkbox").each(function() {
+                self.options[this.id] = this.checked;
+            }).change(function(){
+                self.options[this.id] = this.checked;
+                self.searchCursor = null;
+            });
+
+            this.$searchButton.click(function(){
+                if (!self.search())
+                    alert('Brak wyników.');
+            });
+
+            this.$replaceButton.click(function(){
+                self.replace();
+            });
+
+            old_callback.call(this);
+        };
+
+        $.wiki.Perspective.call(this, options);
+    };
+
+    SearchPerspective.prototype = new $.wiki.Perspective();
+
+    SearchPerspective.prototype.search = function(){
+        var self = this;
+        var query = self.$searchInput.val();
+
+        if (!self.editor)
+            self.editor = $.wiki.perspectiveForTab('#CodeMirrorPerspective').codemirror
+
+        if (!self.searchCursor) {
+            self.searchCursor = self.editor.getSearchCursor(
+                self.$searchInput.val(), 
+                self.options['search-from-cursor'], 
+                self.options['search-regexp'],
+                self.options['search-case-sensitive']
+            );
+        }
+        if (self.searchCursor.findNext()) {
+            self.searchCursor.select();
+            self.$replaceButton.removeAttr("disabled");
+            return true;
+        }
+        else {
+            self.searchCursor = null;
+            this.$replaceButton.attr("disabled","disabled");
+            return false;
+        }
+    };
+
+    SearchPerspective.prototype.replace = function(){
+        var self = this;
+        var query = self.$replaceInput.val();
+
+        if (!self.searchCursor) {
+            self.search();
+        }
+        else {}
+        self.searchCursor.select();
+        self.searchCursor.replace(query);
+        self.search();
+    };
+
+    SearchPerspective.prototype.onEnter = function(success, failure){
+        var self = this;
+
+        $.wiki.Perspective.prototype.onEnter.call(this);
+        self.$searchCursor = null;
+
+        $('.vsplitbar').not('.active').trigger('click');
+        if ($.wiki.activePerspective() != 'CodeMirrorPerspective')
+            $.wiki.switchToTab('#CodeMirrorPerspective');
+    };
+
+    SearchPerspective.prototype.onExit = function(success, failure) {
+
+    };
+
+    $.wiki.SearchPerspective = SearchPerspective;
+
+})(jQuery);
\ No newline at end of file