Add Editor class to generalize in-place editors.
This commit is contained in:
		
							parent
							
								
									d208a254a9
								
							
						
					
					
						commit
						6e679f79b6
					
				
					 2 changed files with 205 additions and 0 deletions
				
			
		|  | @ -31,6 +31,11 @@ li | ||||||
| 
 | 
 | ||||||
|     margin-bottom: 4px; |     margin-bottom: 4px; | ||||||
| } | } | ||||||
|  | .editor_input | ||||||
|  | { | ||||||
|  |     width: 100%; | ||||||
|  |     max-width: 800px; | ||||||
|  | } | ||||||
| .header_element | .header_element | ||||||
| { | { | ||||||
|     display: flex; |     display: flex; | ||||||
|  | @ -43,6 +48,10 @@ li | ||||||
| { | { | ||||||
|     background-color: #ffffd4; |     background-color: #ffffd4; | ||||||
| } | } | ||||||
|  | .hidden | ||||||
|  | { | ||||||
|  |     display: none !important; | ||||||
|  | } | ||||||
| #content_body | #content_body | ||||||
| { | { | ||||||
|     display: flex; |     display: flex; | ||||||
|  | @ -51,6 +60,8 @@ li | ||||||
| } | } | ||||||
| #search_go_button, | #search_go_button, | ||||||
| .add_tag_button, | .add_tag_button, | ||||||
|  | .editor_open_button, | ||||||
|  | .editor_save_button, | ||||||
| .green_button | .green_button | ||||||
| { | { | ||||||
|     border-top: 2px solid #c2ffc3; |     border-top: 2px solid #c2ffc3; | ||||||
|  | @ -61,6 +72,8 @@ li | ||||||
| } | } | ||||||
| #search_go_button:active, | #search_go_button:active, | ||||||
| .add_tag_button:active, | .add_tag_button:active, | ||||||
|  | .editor_open_button:active, | ||||||
|  | .editor_save_button:active, | ||||||
| .green_button:active | .green_button:active | ||||||
| { | { | ||||||
|     border-top: 2px solid #259427; |     border-top: 2px solid #259427; | ||||||
|  | @ -70,6 +83,7 @@ li | ||||||
| } | } | ||||||
| .remove_tag_button, | .remove_tag_button, | ||||||
| .remove_tag_button_perm, | .remove_tag_button_perm, | ||||||
|  | .editor_cancel_button, | ||||||
| .red_button | .red_button | ||||||
| { | { | ||||||
|     border-top: 2px solid #ffacac; |     border-top: 2px solid #ffacac; | ||||||
|  | @ -81,6 +95,7 @@ li | ||||||
| } | } | ||||||
| .remove_tag_button:active, | .remove_tag_button:active, | ||||||
| .remove_tag_button_perm:active, | .remove_tag_button_perm:active, | ||||||
|  | .editor_cancel_button:active, | ||||||
| .red_button:active | .red_button:active | ||||||
| { | { | ||||||
|     border-top: 2px solid #bd1b1b; |     border-top: 2px solid #bd1b1b; | ||||||
|  |  | ||||||
|  | @ -1,3 +1,193 @@ | ||||||
|  | function Editor(elements, on_open, on_save, on_cancel) | ||||||
|  | { | ||||||
|  |     /* | ||||||
|  |     This class wraps around display elements like headers and paragraphs, and | ||||||
|  |     creates inputs / textareas to edit them with. | ||||||
|  | 
 | ||||||
|  |     The placeholder text for the edit elements comes from the | ||||||
|  |     data-editor-placeholder attribute of the display elements if available. | ||||||
|  | 
 | ||||||
|  |     The on_open, on_save and on_cancel callbacks will receive two arguments: | ||||||
|  |         1. This editor object. | ||||||
|  |         2. the edit elements as either: | ||||||
|  |             If the display elements ALL have data-editor-id attributes, | ||||||
|  |             then a dictionary of {data-editor-id: edit_element, ...}. | ||||||
|  |             Otherwise, an array of [edit_element, ...] in their original order. | ||||||
|  | 
 | ||||||
|  |     When your callbacks are used, the default `open`, `save`, `cancel` | ||||||
|  |     methods are not called automatically. You should call them from within | ||||||
|  |     your function. | ||||||
|  |     */ | ||||||
|  |     this.cancel = function() | ||||||
|  |     { | ||||||
|  |         this.close(); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     this.close = function() | ||||||
|  |     { | ||||||
|  |         for (var index = 0; index < this.display_elements.length; index += 1) | ||||||
|  |         { | ||||||
|  |             this.display_elements[index].classList.remove("hidden"); | ||||||
|  |             this.edit_elements[index].classList.add("hidden"); | ||||||
|  |         } | ||||||
|  |         this.open_button.classList.remove("hidden") | ||||||
|  |         this.save_button.classList.add("hidden"); | ||||||
|  |         this.cancel_button.classList.add("hidden"); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     this.hide_spinner = function() | ||||||
|  |     { | ||||||
|  |         this.spinner.classList.add("hidden"); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     this.open = function() | ||||||
|  |     { | ||||||
|  |         for (var index = 0; index < this.display_elements.length; index += 1) | ||||||
|  |         { | ||||||
|  |             var display_element = this.display_elements[index]; | ||||||
|  |             var edit_element = this.edit_elements[index]; | ||||||
|  |             display_element.classList.add("hidden"); | ||||||
|  |             edit_element.classList.remove("hidden"); | ||||||
|  | 
 | ||||||
|  |             edit_element.value = display_element.innerText; | ||||||
|  |         } | ||||||
|  |         this.open_button.classList.add("hidden") | ||||||
|  |         this.save_button.classList.remove("hidden"); | ||||||
|  |         this.cancel_button.classList.remove("hidden"); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     this.save = function() | ||||||
|  |     { | ||||||
|  |         for (var index = 0; index < this.display_elements.length; index += 1) | ||||||
|  |         { | ||||||
|  |             var display_element = this.display_elements[index]; | ||||||
|  |             var edit_element = this.edit_elements[index]; | ||||||
|  | 
 | ||||||
|  |             display_element.innerText = edit_element.value; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         this.close(); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     this.show_spinner = function() | ||||||
|  |     { | ||||||
|  |         this.spinner.classList.remove("hidden"); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     this.display_elements = []; | ||||||
|  |     this.edit_elements = []; | ||||||
|  |     this.can_use_element_map = true; | ||||||
|  |     this.edit_element_map = {}; | ||||||
|  | 
 | ||||||
|  |     for (var index = 0; index < elements.length; index += 1) | ||||||
|  |     { | ||||||
|  |         var display_element = elements[index]; | ||||||
|  |         var edit_element; | ||||||
|  |         if (display_element.tagName == "P") | ||||||
|  |         { | ||||||
|  |             edit_element = document.createElement("textarea"); | ||||||
|  |             edit_element.rows = 6; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             edit_element = document.createElement("input"); | ||||||
|  |             edit_element.type = "text"; | ||||||
|  |         } | ||||||
|  |         edit_element.classList.add("editor_input"); | ||||||
|  |         edit_element.classList.add("hidden"); | ||||||
|  |         if (display_element.dataset.editorPlaceholder !== undefined) | ||||||
|  |         { | ||||||
|  |             edit_element.placeholder = display_element.dataset.editorPlaceholder; | ||||||
|  |         } | ||||||
|  |         if (this.can_use_element_map) | ||||||
|  |         { | ||||||
|  |             if (display_element.dataset.editorId !== undefined) | ||||||
|  |             { | ||||||
|  |                 this.edit_element_map[display_element.dataset.editorId] = edit_element; | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 this.can_use_element_map = false; | ||||||
|  |                 this.edit_element_map = null; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         display_element.parentElement.insertBefore(edit_element, display_element.nextSibling); | ||||||
|  | 
 | ||||||
|  |         this.display_elements.push(display_element); | ||||||
|  |         this.edit_elements.push(edit_element); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     var self = this; | ||||||
|  |     var binder = function(func, fallback) | ||||||
|  |     { | ||||||
|  |         if (func == undefined) | ||||||
|  |         { | ||||||
|  |             return fallback; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         var bound = function() | ||||||
|  |         { | ||||||
|  |             if (this.can_use_element_map) | ||||||
|  |             { | ||||||
|  |                 func(self, self.edit_element_map); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 func(self, self.edit_elements); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         return bound; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     this.bound_open = binder(on_open, this.open); | ||||||
|  |     this.bound_save = binder(on_save, this.save); | ||||||
|  |     this.bound_cancel = binder(on_cancel, this.cancel); | ||||||
|  | 
 | ||||||
|  |     var last_element = this.edit_elements[this.edit_elements.length - 1]; | ||||||
|  |     var toolbox = document.createElement("div"); | ||||||
|  |     last_element.parentElement.insertBefore(toolbox, last_element.nextSibling); | ||||||
|  | 
 | ||||||
|  |     this.open_button = document.createElement("button"); | ||||||
|  |     this.open_button.innerText = "Edit"; | ||||||
|  |     this.open_button.classList.add("editor_open_button"); | ||||||
|  |     this.open_button.onclick = this.bound_open.bind(this); | ||||||
|  |     toolbox.appendChild(this.open_button); | ||||||
|  | 
 | ||||||
|  |     this.save_button = document.createElement("button"); | ||||||
|  |     this.save_button.innerText = "Save"; | ||||||
|  |     this.save_button.classList.add("editor_save_button"); | ||||||
|  |     this.save_button.classList.add("hidden"); | ||||||
|  |     this.save_button.onclick = this.bound_save.bind(this); | ||||||
|  |     toolbox.appendChild(this.save_button); | ||||||
|  | 
 | ||||||
|  |     this.cancel_button = document.createElement("button"); | ||||||
|  |     this.cancel_button.innerText = "Cancel"; | ||||||
|  |     this.cancel_button.classList.add("editor_cancel_button"); | ||||||
|  |     this.cancel_button.classList.add("hidden"); | ||||||
|  |     this.cancel_button.onclick = this.bound_cancel.bind(this); | ||||||
|  |     toolbox.appendChild(this.cancel_button); | ||||||
|  | 
 | ||||||
|  |     this.spinner = document.createElement("span"); | ||||||
|  |     this.spinner.innerText = "Submitting..."; | ||||||
|  |     this.spinner.classList.add("editor_spinner"); | ||||||
|  |     this.spinner.classList.add("hidden"); | ||||||
|  |     toolbox.appendChild(this.spinner); | ||||||
|  | 
 | ||||||
|  |     for (var index = 0; index < this.edit_elements.length; index += 1) | ||||||
|  |     { | ||||||
|  |         var edit_element = this.edit_elements[index]; | ||||||
|  |         if (edit_element.tagName == "TEXTAREA") | ||||||
|  |         { | ||||||
|  |             bind_box_to_button(edit_element, this.save_button, true); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             bind_box_to_button(edit_element, this.save_button, false); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| function create_message_bubble(message_area, message_positivity, message_text, lifespan) | function create_message_bubble(message_area, message_positivity, message_text, lifespan) | ||||||
| { | { | ||||||
|     if (lifespan === undefined) |     if (lifespan === undefined) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue