Luke Plant avatar Luke Plant committed f0436fe

Updated GUI to have 'new row' and 'new column' buttons and items in the headings list

Comments (0)

Files changed (2)

semanticeditor/media/semanticeditor/javascript/wymeditor/plugins/semantic/wymeditor.semantic.js

     var previewbutton_id = id_prefix + 'previewbutton';
     var previewbox_id = id_prefix + 'previewbox';
     var refresh_id = id_prefix + 'refresh';
+    var newrowbutton_id = id_prefix + 'newrowbutton';
+    var newcolbutton_id = id_prefix + 'newcolbutton';
+    var removebutton_id = id_prefix + 'removebutton';
     var self = this;
 
     // Create elements
 	"<div class=\"prescontrol\">" +
 	"<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr><td width=\"50%\"><div class=\"prescontrolheadings\">Structure:<br/><select size=\"7\" id=\"" + headingsbox_id + "\"></select>" +
 	"<br/><label><input type=\"checkbox\" id=\"" + headingsfilter_id + "\"> Headings only</label></div></td>" +
-	"<td width=\"50%\"><div class=\"prescontroloptsboxcont\">Presentation choices:<div class=\"prescontroloptsbox\" id=\"" + optsbox_id + "\"></div></div></td></tr></table>" +
+	"<td width=\"50%\"><div class=\"prescontroloptsboxcont\">Presentation choices:<div class=\"prescontroloptsbox\" id=\"" + optsbox_id + "\"></div>" +
+        "<input type=\"submit\" value=\"New row\" id=\"" + newrowbutton_id  +"\" />" +
+        "<input type=\"submit\" value=\"New column\" id=\"" + newcolbutton_id  +"\" />" +
+        "<input type=\"submit\" value=\"Remove\" id=\"" + removebutton_id  +"\" />" +
+        "</div></td></tr></table>" +
 	"<table width=\"100%\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\"><tr>" +
 	    "<td><input type=\"submit\" value=\"Refresh structure\" id=\"" + refresh_id + "\" /></td>" +
 	    "<td><input type=\"submit\" value=\"Preview\" id=\"" + previewbutton_id + "\" /></td>" +
     this.previewbutton = jQuery('#' + previewbutton_id);
     this.previewbox = jQuery('#' + previewbox_id);
     this.refreshbutton = jQuery('#' + refresh_id);
+    this.newrowbutton = jQuery('#' + newrowbutton_id);
+    this.newcolbutton = jQuery('#' + newcolbutton_id);
+    this.removebutton = jQuery('#' + removebutton_id);
     this.optsbox.css('height', this.headingscontrol.get(0).clientHeight.toString() + "px");
 
     // Initial set up
     this.retrieve_styles();
-    this.refresh_headings();
-    this.separate_presentation();
-    this.update_optsbox();
+    // refresh_headings must come after separate_presentation
+    this.separate_presentation(function() { self.refresh_headings(); });
 
     // Event handlers
     this.headingscontrol.change(function(event) {
 				   self.update_active_heading_list();
 				   self.update_headingbox();
 			       });
+    this.newrowbutton.click(function(event) {
+                                self.insert_row();
+				return false;
+                            });
+    this.newcolbutton.click(function(event) {
+                                self.insert_column();
+				return false;
+                            });
+    this.removebutton.click(function(event) {
+                                self.remove_layout_command();
+				return false;
+                            });
     // Insert rewriting of HTML before the WYMeditor updates the textarea.
     jQuery(this.wym._options.updateSelector)
 	.bind(this.wym._options.updateEvent, function(event) {
 };
 
 // Splits the HTML into 'content HTML' and 'presentation'
-PresentationControls.prototype.separate_presentation = function() {
+PresentationControls.prototype.separate_presentation = function(andthen) {
+    // 'andthen' is a function to do afterwards.  This is a nasty
+    // hack to get things to work.
     var self = this;
     jQuery.post(this.opts.separate_presentation_url, { html: self.wym.xhtml() } ,
 		function(data) {
 			    self.presentation_info = value.presentation;
 			    // Update the HTML
                             self.set_html(value.html);
+                            if (andthen != null) {
+                                andthen();
+                            }
 			});
 		}, "json");
 };
     this.optsbox.find("input").unbind().removeAttr("checked").attr("disabled", true);
 };
 
+PresentationControls.prototype.get_heading_index = function() {
+    var selected = this.headingscontrol.get(0).value;
+    if (!selected) {
+	return null;
+    }
+    return parseInt(selected, 10);
+};
+
 PresentationControls.prototype.update_optsbox = function() {
     var self = this;
     this.unbind_optsbox();
     // Currently selected heading?
-    var selected = this.headingscontrol.get(0).value;
-    if (!selected) {
-	return;
-    }
-    var headingIndex = parseInt(selected, 10);
+    var headingIndex = self.get_heading_index();
+    if (headingIndex == null) return;
     var sect_id = this.active_heading_list[headingIndex].sect_id;
     var styles = this.presentation_info[sect_id];
     if (styles == null) {
     this.presentation_info[sect_id] = styles;
 };
 
+PresentationControls.prototype.insert_row = function() {
+    // Insert a new row command into outline above selected item
+    var headingIndex = this.get_heading_index();
+    if (headingIndex == null) return;
+    var sect_id = this.active_heading_list[headingIndex].sect_id;
+    if (sect_id.match(/^newrow_/)) {
+        alert("Can't insert new row here");
+        return;
+    }
+
+    for (var i=0; i < this.stored_headings.length; i++) {
+        if (this.stored_headings[i].sect_id == sect_id) {
+            // Update the headings:
+            this.insert_row_command(this.stored_headings, i, sect_id);
+            // Update presentation info:
+            // An empty array will do, don't actually need a
+            // command in there (and the GUI will overwrite any
+            // anything we put in it)
+            this.presentation_info['newrow_' + sect_id] = Array();
+            break;
+        }
+    }
+
+    // Refresh GUI
+    this.update_active_heading_list();
+    this.update_headingbox();
+
+    // select what was selected before
+    this.headingscontrol.get(0).value = headingIndex;
+};
+
+PresentationControls.prototype.insert_row_command = function(arr, i, sect_id) {
+    arr.splice(i, 0, {level:1,
+                      name:"New row",
+                      tag:"newrow",
+                      sect_id:"newrow_" + sect_id
+                     });
+};
+
+
+PresentationControls.prototype.insert_column = function() {
+    // Insert a new row command into outline above selected item
+    var headingIndex = this.get_heading_index();
+    if (headingIndex == null) return;
+    var sect_id = this.active_heading_list[headingIndex].sect_id;
+    if (sect_id.match(/^newrow_/) || sect_id.match(/^newcol_/)) {
+        alert("Can't insert new column here");
+        return;
+    }
+
+    for (var i=0; i < this.stored_headings.length; i++) {
+        if (this.stored_headings[i].sect_id == sect_id) {
+            // Update the headings:
+            this.insert_column_command(this.stored_headings, i, sect_id);
+            // Update presentation info:
+            // An empty array will do, don't actually need a
+            // command in there (and the GUI will overwrite any
+            // anything we put in it)
+            this.presentation_info['newcol_' + sect_id] = Array();
+            break;
+        }
+    }
+    // Refresh GUI
+    this.update_active_heading_list();
+    this.update_headingbox();
+
+    // select what was selected before
+    this.headingscontrol.get(0).value = headingIndex;
+};
+
+PresentationControls.prototype.insert_column_command = function(arr, i, sect_id) {
+    arr.splice(i, 0, {level:1,
+                      name:"New column",
+                      tag:"newcol",
+                      sect_id:"newcol_" + sect_id
+                     });
+};
+
+PresentationControls.prototype.remove_layout_command = function() {
+    var headingIndex = this.get_heading_index();
+    if (headingIndex == null) return;
+    var sect_id = this.active_heading_list[headingIndex].sect_id;
+    if (!sect_id.match(/^newrow_/) && !sect_id.match(/^newcol_/)) {
+        alert("Can only use 'remove' on new row or column commands");
+        return;
+    }
+    // Update heading list
+    this.stored_headings.splice(headingIndex, 1);
+    // Update presentation info
+    delete this.presentation_info[sect_id];
+    // Refresh GUI
+    this.update_active_heading_list();
+    this.update_headingbox();
+
+    if (headingIndex > 0) {
+        this.headingscontrol.get(0).value = headingIndex - 1;
+    }
+};
+
 // If data contains an error message, display to the user,
 // otherwise clear the displayed error and perform the callback
 // with the value in the data.
 	function(data) {
 	    self.with_good_data(data, function(value) {
 		self.stored_headings = value;
+                self.add_layout_to_headings();
 		self.update_active_heading_list();
 		self.update_headingbox();
 	    });
 	}, "json");
 };
 
+PresentationControls.prototype.add_layout_to_headings = function() {
+    // Row/Column info is transmitted as part of presentation info
+    // but it is displayed in the headings list, because it represents
+    // divs that are inserted (and can be styled).  So we need to
+    // update this.stored_headings using this.presentation_info
+    var first_sect_id;
+    if (this.stored_headings.length > 0) {
+        first_sect_id = this.stored_headings[0].sect_id;
+    } else {
+        first_sect_id = '';
+    }
+    for (var i = 0; i < this.stored_headings.length; i++) {
+        // Loop through, if any have corresponding newrow or newcol
+        // entries, then add them into list.
+        var sect_id = this.stored_headings[i].sect_id;
+        if (this.presentation_info['newrow_' + sect_id] != null) {
+            this.insert_row_command(this.stored_headings, i, sect_id);
+            i++;
+        }
+        if (this.presentation_info['newcol_' + sect_id] != null) {
+            this.insert_column_command(this.stored_headings, i, sect_id);
+            i++;
+        }
+    }
+
+    // If after this process we don't have newrow and newcol commands
+    // at the beginning of the heading list, we add them.
+    if (this.stored_headings[0].tag != 'newrow') {
+        // FIXME - what if first_sect_id is '' ?
+        this.insert_row_command(this.stored_headings, 0, first_sect_id);
+    }
+    if (this.stored_headings[1].tag != 'newcol') {
+        // FIXME - what if first_sect_id is '' ?
+        this.insert_column_command(this.stored_headings, 1, first_sect_id);
+    }
+
+};
+
+
 PresentationControls.prototype.update_active_heading_list = function() {
     var self = this;
     var items;
     this.headingscontrol.empty();
     jQuery.each(this.active_heading_list, function(i, item) {
 		    var spaces = (new Array((item.level - 1)*3)).join("&nbsp;");
-		    self.headingscontrol.append("<option value='" + i.toString() + "'>" + spaces + item.tag.toLowerCase() + ": " + escapeHtml(item.name) + "</option>");
+                    var caption = "";
+                    var tag = item.tag.toLowerCase();
+                    if (tag == 'newrow' || tag == 'newcol') {
+                        caption = "[" + escapeHtml(item.name) + "]";
+                    } else {
+                        caption = tag + ": " + escapeHtml(item.name);
+                    }
+		    self.headingscontrol.append("<option value='" + i.toString() + "'>" + spaces + caption + "</option>");
     });
 };
 
 PresentationControls.prototype.retrieve_styles = function() {
     // Retrieve via AJAX
-    // TODO - remove hardcoded URL
     var self = this;
     jQuery.getJSON(this.opts.retrieve_styles_url, {},
 		   function (data) {

semanticeditor/views.py

 
 @json_view
 def retrieve_styles(request):
-    retval = [NEWROW, NEWCOL]
-    retval += [PresentationClass(c.name,
-                                 verbose_name=c.verbose_name,
-                                 description=c.description)
-               for c in CssClass.objects.all().order_by('verbose_name')]
+    retval = [PresentationClass(c.name,
+                              verbose_name=c.verbose_name,
+                              description=c.description)
+            for c in CssClass.objects.all().order_by('verbose_name')]
     return success(map(PI_to_dict,retval))
 
 @json_view
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.