UNPKG

alpaca

Version:

Alpaca provides the easiest and fastest way to generate interactive forms for the web and mobile devices. It runs simply as HTML5 or more elaborately using Bootstrap, jQuery Mobile or jQuery UI. Alpaca uses Handlebars to process JSON schema and provide

481 lines (406 loc) 15.2 kB
(function($) { var Alpaca = $.alpaca; Alpaca.Fields.EditorField = Alpaca.Fields.TextField.extend( /** * @lends Alpaca.Fields.EditorField.prototype */ { /** * @see Alpaca.Fields.TextField#getFieldType */ getFieldType: function() { return "editor"; }, setup: function() { var self = this; this.base(); if (!self.options.aceTheme) { self.options.aceTheme = "ace/theme/chrome"; } if (!self.options.aceMode) { self.options.aceMode = "ace/mode/json"; } if (typeof(self.options.beautify) == "undefined") { self.options.beautify = true; } if (self.options.beautify && this.data) { if (self.options.aceMode === "ace/mode/json") { if (Alpaca.isObject(this.data)) { // convert to string to format it this.data = JSON.stringify(this.data, null, " "); } else if (Alpaca.isString(this.data)) { // convert to object and then back to string to format it this.data = JSON.stringify(JSON.parse(this.data), null, " "); } } if (self.options.aceMode === "ace/mode/html") { if (typeof(html_beautify) !== "undefined") { this.data = html_beautify(this.data); } } if (self.options.aceMode === "ace/mode/css") { if (typeof(css_beautify) !== "undefined") { this.data = css_beautify(this.data); } } if (self.options.aceMode === "ace/mode/javascript") { if (typeof(js_beautify) !== "undefined") { this.data = js_beautify(this.data); } } } if (self.options.aceMode === "ace/mode/json") { if (!this.data || this.data === "{}") { this.data = "{\n\t\n}"; } } }, /** * @see Alpaca.Fields.TextField#postRender */ afterRenderControl: function(model, callback) { var self = this; this.base(model, function() { if (self.control) { /* // ACE HEIGHT var aceHeight = self.options.aceHeight; if (aceHeight) { $(self.control).css("height", aceHeight); } */ // ACE WIDTH var aceWidth = self.options.aceWidth; if (!aceWidth) { aceWidth = "100%"; } $(self.control).css("width", aceWidth); } // locate where we will insert the editor var el = $(self.control)[0]; // ace must be included ahead of time if (!ace && window.ace) { ace = window.ace; } if (!ace) { Alpaca.logError("Editor Field is missing the 'ace' Cloud 9 Editor"); } else { self.editor = ace.edit(el); self.editor.setOptions({ maxLines: Infinity }); self.editor.getSession().setUseWrapMode(true); // theme var aceTheme = self.options.aceTheme; self.editor.setTheme(aceTheme); // mode var aceMode = self.options.aceMode; self.editor.getSession().setMode(aceMode); self.editor.renderer.setHScrollBarAlwaysVisible(false); //this.editor.renderer.setVScrollBarAlwaysVisible(false); // not implemented self.editor.setShowPrintMargin(false); // set data onto editor if (!self.data) { self.data = ""; } self.editor.setValue(self.data); self.editor.clearSelection(); // clear undo session self.editor.getSession().getUndoManager().reset(); // FIT-CONTENT the height of the editor to the contents contained within if (self.options.aceFitContentHeight) { var heightUpdateFunction = function() { var first = false; if (self.editor.renderer.lineHeight === 0) { first = true; self.editor.renderer.lineHeight = 16; } // http://stackoverflow.com/questions/11584061/ var newHeight = self.editor.getSession().getScreenLength() * self.editor.renderer.lineHeight + self.editor.renderer.scrollBar.getWidth(); $(self.control).height(newHeight.toString() + "px"); // This call is required for the editor to fix all of // its inner structure for adapting to a change in size self.editor.resize(); if (first) { window.setTimeout(function() { self.editor.clearSelection(); }, 100); } }; // Set initial size to match initial content heightUpdateFunction(); // Whenever a change happens inside the ACE editor, update // the size again self.editor.getSession().on('change', heightUpdateFunction); } else { // ACE HEIGHT var aceHeight = self.options.aceHeight; if (aceHeight) { $(self.control).css("min-height", aceHeight + "px"); } } // READONLY if (self.schema.readonly) { self.editor.setReadOnly(true); } // if the editor's dom element gets destroyed, make sure we clean up the editor instance // normally, we expect Alpaca fields to be destroyed by the destroy() method but they may also be // cleaned-up via the DOM, thus we check here. $(el).bind('destroyed', function() { if (self.editor) { self.editor.destroy(); self.editor = null; } }); } callback(); }); }, /** * @see Alpaca.Field#destroy */ destroy: function() { // destroy the editor instance if (this.editor) { this.editor.destroy(); this.editor = null; } // call up to base method this.base(); }, /** * @return the ACE editor instance */ getEditor: function() { return this.editor; }, /** * @see Alpaca.ControlField#handleValidate */ handleValidate: function() { var baseStatus = this.base(); var valInfo = this.validation; var wordCountStatus = this._validateWordCount(); valInfo["wordLimitExceeded"] = { "message": wordCountStatus ? "" : Alpaca.substituteTokens(this.getMessage("wordLimitExceeded"), [this.options.wordlimit]), "status": wordCountStatus }; var editorAnnotationsStatus = this._validateEditorAnnotations(); valInfo["editorAnnotationsExist"] = { "message": editorAnnotationsStatus ? "" : this.getMessage("editorAnnotationsExist"), "status": editorAnnotationsStatus }; return baseStatus && valInfo["wordLimitExceeded"]["status"] && valInfo["editorAnnotationsExist"]["status"]; }, _validateEditorAnnotations: function() { if (this.editor) { var annotations = this.editor.getSession().getAnnotations(); if (annotations && annotations.length > 0) { return false; } } return true; }, /** * Validate for word limit. * * @returns {Boolean} True if the number of words is equal to or less than the word limit. */ _validateWordCount: function() { if (this.options.wordlimit && this.options.wordlimit > -1) { var val = this.editor.getValue(); if (val) { var wordcount = val.split(" ").length; if (wordcount > this.options.wordlimit) { return false; } } } return true; }, /** * Force editor to resize to ensure it gets drawn correctly. * @override */ onDependentReveal: function() { if (this.editor) { this.editor.resize(); } }, /** *@see Alpaca.Fields.TextField#setValue */ setValue: function(value) { var self = this; if (this.editor) { if (self.schema.type == "object" && Alpaca.isObject(value)) { // format value = JSON.stringify(value, null, " "); } if (!value) { value = ""; } this.editor.setValue(value); self.editor.clearSelection(); } // be sure to call into base method this.base(value); }, /** * @see Alpaca.Fields.ControlField#getControlValue */ getControlValue: function() { var value = null; if (this.editor) { value = this.editor.getValue(); } // if expected type back is "object", we do the conversion if (this.schema.type == "object") { if (!value) { value = {}; } else { value = JSON.parse(value); } } return value; } /* builder_helpers */ , /** * @see Alpaca.Fields.TextField#getTitle */ getTitle: function() { return "Editor"; }, /** * @see Alpaca.Fields.TextField#getDescription */ getDescription: function() { return "Editor"; }, /** * @private * @see Alpaca.Fields.TextField#getSchemaOfOptions */ getSchemaOfOptions: function() { return Alpaca.merge(this.base(), { "properties": { "aceTheme": { "title": "ACE Editor Theme", "description": "Specifies the theme to set onto the editor instance", "type": "string", "default": "ace/theme/twilight" }, "aceMode": { "title": "ACE Editor Mode", "description": "Specifies the mode to set onto the editor instance", "type": "string", "default": "ace/mode/javascript" }, "aceWidth": { "title": "ACE Editor Height", "description": "Specifies the width of the wrapping div around the editor", "type": "string", "default": "100%" }, "aceHeight": { "title": "ACE Editor Height", "description": "Specifies the height of the wrapping div around the editor", "type": "string", "default": "300px" }, "aceFitContentHeight": { "title": "ACE Fit Content Height", "description": "Configures the ACE Editor to auto-fit its height to the contents of the editor", "type": "boolean", "default": false }, "wordlimit": { "title": "Word Limit", "description": "Limits the number of words allowed in the text area.", "type": "number", "default": -1 } } }); }, /** * @private * @see Alpaca.Fields.TextField#getOptionsForOptions */ getOptionsForOptions: function() { return Alpaca.merge(this.base(), { "fields": { "aceTheme": { "type": "text" }, "aceMode": { "type": "text" }, "wordlimit": { "type": "integer" } } }); } /* end_builder_helpers */ }); Alpaca.registerMessages({ "wordLimitExceeded": "The maximum word limit of {0} has been exceeded.", "editorAnnotationsExist": "The editor has errors in it that must be corrected" }); Alpaca.registerFieldClass("editor", Alpaca.Fields.EditorField); })(jQuery);