| 
									
										
										
										
											2018-01-11 00:01:16 -05:00
										 |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const attributesDialog = (function() { | 
					
						
							| 
									
										
										
										
											2018-02-10 08:37:14 -05:00
										 |  |  |     const $dialog = $("#attributes-dialog"); | 
					
						
							|  |  |  |     const $saveAttributesButton = $("#save-attributes-button"); | 
					
						
							|  |  |  |     const $attributesBody = $('#attributes-table tbody'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 21:40:09 -05:00
										 |  |  |     const attributesModel = new AttributesModel(); | 
					
						
							| 
									
										
										
										
											2018-02-04 19:27:27 -05:00
										 |  |  |     let attributeNames = []; | 
					
						
							| 
									
										
										
										
											2018-01-11 00:01:16 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 21:40:09 -05:00
										 |  |  |     function AttributesModel() { | 
					
						
							|  |  |  |         const self = this; | 
					
						
							| 
									
										
										
										
											2018-01-11 00:01:16 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 21:40:09 -05:00
										 |  |  |         this.attributes = ko.observableArray(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.loadAttributes = async function() { | 
					
						
							|  |  |  |             const noteId = noteEditor.getCurrentNoteId(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const attributes = await server.get('notes/' + noteId + '/attributes'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-04 17:22:21 -05:00
										 |  |  |             self.attributes(attributes.map(ko.observable)); | 
					
						
							| 
									
										
										
										
											2018-01-11 00:01:16 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-04 17:22:21 -05:00
										 |  |  |             addLastEmptyRow(); | 
					
						
							| 
									
										
										
										
											2018-02-04 19:27:27 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |             attributeNames = await server.get('attributes/names'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-05 21:07:18 -05:00
										 |  |  |             // attribute might not be rendered immediatelly so could not focus
 | 
					
						
							|  |  |  |             setTimeout(() => $(".attribute-name:last").focus(), 100); | 
					
						
							| 
									
										
										
										
											2018-02-10 08:37:14 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |             $attributesBody.sortable({ | 
					
						
							|  |  |  |                 handle: '.handle', | 
					
						
							|  |  |  |                 containment: $attributesBody, | 
					
						
							|  |  |  |                 update: function() { | 
					
						
							|  |  |  |                     let position = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-10 08:44:34 -05:00
										 |  |  |                     // we need to update positions by searching in the DOM, because order of the
 | 
					
						
							|  |  |  |                     // attributes in the viewmodel (self.attributes()) stays the same
 | 
					
						
							| 
									
										
										
										
											2018-02-10 08:37:14 -05:00
										 |  |  |                     $attributesBody.find('input[name="position"]').each(function() { | 
					
						
							|  |  |  |                         const attr = self.getTargetAttribute(this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         attr().position = position++; | 
					
						
							|  |  |  |                     }); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }); | 
					
						
							| 
									
										
										
										
											2018-01-11 21:40:09 -05:00
										 |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-06 23:09:19 -05:00
										 |  |  |         this.deleteAttribute = function(data, event) { | 
					
						
							| 
									
										
										
										
											2018-02-10 08:37:14 -05:00
										 |  |  |             const attr = self.getTargetAttribute(event.target); | 
					
						
							| 
									
										
										
										
											2018-02-06 23:09:19 -05:00
										 |  |  |             const attrData = attr(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (attrData) { | 
					
						
							|  |  |  |                 attrData.isDeleted = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 attr(attrData); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 addLastEmptyRow(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-04 17:22:21 -05:00
										 |  |  |         function isValid() { | 
					
						
							|  |  |  |             for (let attrs = self.attributes(), i = 0; i < attrs.length; i++) { | 
					
						
							| 
									
										
										
										
											2018-02-06 21:18:09 -05:00
										 |  |  |                 if (self.isEmptyName(i)) { | 
					
						
							| 
									
										
										
										
											2018-02-04 17:22:21 -05:00
										 |  |  |                     return false; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 21:40:09 -05:00
										 |  |  |         this.save = async function() { | 
					
						
							| 
									
										
										
										
											2018-02-04 23:16:45 -05:00
										 |  |  |             // we need to defocus from input (in case of enter-triggered save) because value is updated
 | 
					
						
							|  |  |  |             // on blur event (because of conflict with jQuery UI Autocomplete). Without this, input would
 | 
					
						
							|  |  |  |             // stay in focus, blur wouldn't be triggered and change wouldn't be updated in the viewmodel.
 | 
					
						
							| 
									
										
										
										
											2018-02-10 08:37:14 -05:00
										 |  |  |             $saveAttributesButton.focus(); | 
					
						
							| 
									
										
										
										
											2018-02-04 23:16:45 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-04 17:22:21 -05:00
										 |  |  |             if (!isValid()) { | 
					
						
							|  |  |  |                 alert("Please fix all validation errors and try saving again."); | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 21:40:09 -05:00
										 |  |  |             const noteId = noteEditor.getCurrentNoteId(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-04 17:22:21 -05:00
										 |  |  |             const attributesToSave = self.attributes() | 
					
						
							|  |  |  |                 .map(attr => attr()) | 
					
						
							|  |  |  |                 .filter(attr => attr.attributeId !== "" || attr.name !== ""); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const attributes = await server.put('notes/' + noteId + '/attributes', attributesToSave); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             self.attributes(attributes.map(ko.observable)); | 
					
						
							| 
									
										
										
										
											2018-01-11 21:40:09 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-04 17:22:21 -05:00
										 |  |  |             addLastEmptyRow(); | 
					
						
							| 
									
										
										
										
											2018-01-11 21:40:09 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |             showMessage("Attributes have been saved."); | 
					
						
							| 
									
										
										
										
											2018-02-04 20:23:30 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |             noteEditor.loadAttributeList(); | 
					
						
							| 
									
										
										
										
											2018-01-11 21:40:09 -05:00
										 |  |  |         }; | 
					
						
							| 
									
										
										
										
											2018-02-04 17:22:21 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         function addLastEmptyRow() { | 
					
						
							| 
									
										
										
										
											2018-02-06 23:09:19 -05:00
										 |  |  |             const attrs = self.attributes().filter(attr => attr().isDeleted === 0); | 
					
						
							| 
									
										
										
										
											2018-02-05 21:07:18 -05:00
										 |  |  |             const last = attrs.length === 0 ? null : attrs[attrs.length - 1](); | 
					
						
							| 
									
										
										
										
											2018-02-04 17:22:21 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-05 21:07:18 -05:00
										 |  |  |             if (!last || last.name.trim() !== "" || last.value !== "") { | 
					
						
							| 
									
										
										
										
											2018-02-04 17:22:21 -05:00
										 |  |  |                 self.attributes.push(ko.observable({ | 
					
						
							|  |  |  |                     attributeId: '', | 
					
						
							|  |  |  |                     name: '', | 
					
						
							| 
									
										
										
										
											2018-02-06 23:09:19 -05:00
										 |  |  |                     value: '', | 
					
						
							| 
									
										
										
										
											2018-02-10 08:37:14 -05:00
										 |  |  |                     isDeleted: 0, | 
					
						
							|  |  |  |                     position: 0 | 
					
						
							| 
									
										
										
										
											2018-02-04 17:22:21 -05:00
										 |  |  |                 })); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-06 23:09:19 -05:00
										 |  |  |         this.attributeChanged = function (data, event) { | 
					
						
							| 
									
										
										
										
											2018-02-04 17:22:21 -05:00
										 |  |  |             addLastEmptyRow(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-10 08:37:14 -05:00
										 |  |  |             const attr = self.getTargetAttribute(event.target); | 
					
						
							| 
									
										
										
										
											2018-02-06 23:09:19 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |             attr.valueHasMutated(); | 
					
						
							| 
									
										
										
										
											2018-02-04 17:22:21 -05:00
										 |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.isNotUnique = function(index) { | 
					
						
							|  |  |  |             const cur = self.attributes()[index](); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (cur.name.trim() === "") { | 
					
						
							|  |  |  |                 return false; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for (let attrs = self.attributes(), i = 0; i < attrs.length; i++) { | 
					
						
							|  |  |  |                 const attr = attrs[i](); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if (index !== i && cur.name === attr.name) { | 
					
						
							|  |  |  |                     return true; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.isEmptyName = function(index) { | 
					
						
							|  |  |  |             const cur = self.attributes()[index](); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return cur.name.trim() === "" && (cur.attributeId !== "" || cur.value !== ""); | 
					
						
							| 
									
										
										
										
											2018-02-06 23:09:19 -05:00
										 |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-10 08:37:14 -05:00
										 |  |  |         this.getTargetAttribute = function(target) { | 
					
						
							|  |  |  |             const context = ko.contextFor(target); | 
					
						
							| 
									
										
										
										
											2018-02-06 23:09:19 -05:00
										 |  |  |             const index = context.$index(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return self.attributes()[index]; | 
					
						
							| 
									
										
										
										
											2018-02-04 17:22:21 -05:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-01-11 00:01:16 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async function showDialog() { | 
					
						
							| 
									
										
										
										
											2018-02-10 08:37:14 -05:00
										 |  |  |         glob.activeDialog = $dialog; | 
					
						
							| 
									
										
										
										
											2018-01-11 00:01:16 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-04 19:43:11 -05:00
										 |  |  |         await attributesModel.loadAttributes(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-10 08:37:14 -05:00
										 |  |  |         $dialog.dialog({ | 
					
						
							| 
									
										
										
										
											2018-01-11 00:01:16 -05:00
										 |  |  |             modal: true, | 
					
						
							|  |  |  |             width: 800, | 
					
						
							| 
									
										
										
										
											2018-02-03 12:44:22 -05:00
										 |  |  |             height: 500 | 
					
						
							| 
									
										
										
										
											2018-01-11 00:01:16 -05:00
										 |  |  |         }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     $(document).bind('keydown', 'alt+a', e => { | 
					
						
							|  |  |  |         showDialog(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         e.preventDefault(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-21 23:06:25 -05:00
										 |  |  |     ko.applyBindings(attributesModel, document.getElementById('attributes-dialog')); | 
					
						
							| 
									
										
										
										
											2018-01-11 21:40:09 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-04 19:43:11 -05:00
										 |  |  |     $(document).on('focus', '.attribute-name', function (e) { | 
					
						
							|  |  |  |         if (!$(this).hasClass("ui-autocomplete-input")) { | 
					
						
							|  |  |  |             $(this).autocomplete({ | 
					
						
							|  |  |  |                 // shouldn't be required and autocomplete should just accept array of strings, but that fails
 | 
					
						
							|  |  |  |                 // because we have overriden filter() function in init.js
 | 
					
						
							|  |  |  |                 source: attributeNames.map(attr => { | 
					
						
							|  |  |  |                     return { | 
					
						
							|  |  |  |                         label: attr, | 
					
						
							|  |  |  |                         value: attr | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 }), | 
					
						
							|  |  |  |                 minLength: 0 | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $(this).autocomplete("search", $(this).val()); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     $(document).on('focus', '.attribute-value', async function (e) { | 
					
						
							|  |  |  |         if (!$(this).hasClass("ui-autocomplete-input")) { | 
					
						
							|  |  |  |             const attributeName = $(this).parent().parent().find('.attribute-name').val(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (attributeName.trim() === "") { | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const attributeValues = await server.get('attributes/values/' + encodeURIComponent(attributeName)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (attributeValues.length === 0) { | 
					
						
							|  |  |  |                 return; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             $(this).autocomplete({ | 
					
						
							|  |  |  |                 // shouldn't be required and autocomplete should just accept array of strings, but that fails
 | 
					
						
							|  |  |  |                 // because we have overriden filter() function in init.js
 | 
					
						
							|  |  |  |                 source: attributeValues.map(attr => { | 
					
						
							|  |  |  |                     return { | 
					
						
							|  |  |  |                         label: attr, | 
					
						
							|  |  |  |                         value: attr | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                 }), | 
					
						
							|  |  |  |                 minLength: 0 | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-02-04 19:27:27 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         $(this).autocomplete("search", $(this).val()); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-11 00:01:16 -05:00
										 |  |  |     return { | 
					
						
							|  |  |  |         showDialog | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | })(); |