diff --git a/grunt.js b/grunt.js index f8a2f7e..17f0026 100644 --- a/grunt.js +++ b/grunt.js @@ -187,6 +187,24 @@ containers = lib+'containers/'; } } }, + yuidoc: { + compile: { + name: '<%= pkg.title || pkg.name %>', + description: '<%= pkg.description %>', + version: '<%= pkg.version %>', + url: "<%= pkg.homepage %>", + // logo: 'src/editable-form/img/loading.gif', + options: { + paths: "src/", + ignorePaths: ['src/inputs/date/locales'], + outdir: "../docs/", +// theme: "simple", + themedir: "../yuidoc-theme" + //themedir: "../yuidoc-bootstrap-theme-master" + } + } + }, + //compress does not work properly for MAC OS (see https://github.com/vitalets/bootstrap-editable/issues/19) //zip will be created manually /* diff --git a/package.json b/package.json index b67b3b8..208fffd 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "x-editable", + "name": "X-editable", "title": "X-editable", "description": "In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery", "version": "1.0.0", @@ -19,10 +19,6 @@ { "type": "MIT", "url": "https://github.com/vitalets/x-editable/blob/master/LICENSE-MIT" - }, - { - "type": "GPL", - "url": "https://github.com/vitalets/x-editable/blob/master/LICENSE-GPL" } ], "dependencies": { @@ -30,8 +26,7 @@ }, "devDependencies": { "grunt": "~0.3.11", - "grunt-contrib": "0.1.1", - "moment": "1.7.0" + "grunt-contrib": "0.1.1" }, "keywords": [] } \ No newline at end of file diff --git a/src/containers/editable-container.js b/src/containers/editable-container.js index ba4b51a..405877b 100644 --- a/src/containers/editable-container.js +++ b/src/containers/editable-container.js @@ -1,26 +1,15 @@ /** -* Editable Container -* Container can be popover, inline form or whatever -* Container must provide following: -* 1. methods: -* show(), -* hide(), -* tip() - returns jquery object of container element -* option() -* -* 2. events: -* - save -* - cancel -* -* 3. settings: trigger, value, placement -*/ +Container for editableform. It can be popup (bootstrap-popover, jqueryui-tooltip, poshytip..) or inline. +Applied as jQuery method to any element. Element is used only for positioning! + +@class editableContainer +**/ (function ($) { - - //Constructor + var EditableContainer = function (element, options) { this.init(element, options); }; - + //methods EditableContainer.prototype = { containerName: null, //tbd in child class @@ -28,18 +17,19 @@ init: function(element, options) { this.$element = $(element); this.options = $.extend({}, $.fn.editableContainer.defaults, $.fn.editableform.utils.getConfigData(this.$element), options); + this.options.trigger = 'manual'; this.initContainer(); - + //bind 'destroyed' listener to destroy container when element is removed from dom this.$element.on('destroyed', $.proxy(function(){ this.destroy(); }, this)); }, - + initContainer: function(){ - this.call(this.options); + this.call(this.options); }, - + initForm: function() { this.$form = $('<div>') .editableform(this.options) @@ -52,92 +42,152 @@ return this.$form; }, + /** + Returns jquery object of container + @method tip() + **/ tip: function() { - return this.container().$tip; + return this.container().$tip; }, - - //return instance of container + container: function() { - return this.$element.data(this.containerName); + return this.$element.data(this.containerName); }, - - //call container's method + call: function() { - this.$element[this.containerName].apply(this.$element, arguments); + this.$element[this.containerName].apply(this.$element, arguments); }, - + + /** + Shows container with form + @method show() + **/ show: function () { this.call('show'); this.tip().addClass('editable-container'); - + this.initForm(); this.tip().find(this.innerCss).empty().append(this.$form); this.$form.editableform('render'); - }, - - hide: function() { - this.call('hide'); - }, - - setPosition: function() { - //tbd in child class - }, - - cancel: function() { - if(this.options.autohide) { - this.hide(); - } - this.$element.triggerHandler('cancel'); - }, - - save: function(e, params) { - if(this.options.autohide) { - this.hide(); - } - this.$element.triggerHandler('save', params); - }, - - option: function(key, value) { - this.options[key] = value; - this.call('option', key, value); - }, - - destroy: function() { - this.call('destroy'); - } + }, + + /** + Hides container with form + @method hide() + **/ + hide: function() { + this.call('hide'); + }, + + /** + Updates the position of container when content changed. + @method setPosition() + **/ + setPosition: function() { + //tbd in child class + }, + + cancel: function() { + if(this.options.autohide) { + this.hide(); + } + /** + Fired when form was cancelled by user + + @event cancel + @param {Object} event event object + **/ + this.$element.triggerHandler('cancel'); + }, + + save: function(e, params) { + if(this.options.autohide) { + this.hide(); + } + /** + Fired when new value was submitted + + @event save + @param {Object} event event object + @param {Object} params additional params + @param {mixed} params.newValue submitted value + @param {Object} params.response ajax response + **/ + this.$element.triggerHandler('save', params); + }, + + /** + Sets new option + @method option(key, value) + @param {string} key + @param {mixed} value + **/ + option: function(key, value) { + this.options[key] = value; + this.call('option', key, value); + }, + + /** + Destroys the container instance + @method destroy() + **/ + destroy: function() { + this.call('destroy'); + } + }; - + //jQuery plugin definition $.fn.editableContainer = function (option) { var args = arguments; return this.each(function () { var $this = $(this), - dataKey = 'editableContainer', - data = $this.data(dataKey), - options = typeof option === 'object' && option; + dataKey = 'editableContainer', + data = $this.data(dataKey), + options = typeof option === 'object' && option; if (!data) { $this.data(dataKey, (data = new EditableContainer(this, options))); } - + if (typeof option === 'string') { //call method data[option].apply(data, Array.prototype.slice.call(args, 1)); } }); }; - + //store constructor $.fn.editableContainer.Constructor = EditableContainer; - + //defaults - must be redefined! $.fn.editableContainer.defaults = { - trigger: 'manual', - value: null, - placement: 'top', - autohide: true + /** + Initial value of form input + + @property value + @type mixed + @default null + **/ + value: null, + /** + Placement of container relative to element. Can be top|right|bottom|left. Not used for inline container. + + @property placement + @type string + @default 'top' + **/ + placement: 'top', + /** + Wether to hide container on save/cancel. + + @property autohide + @type boolean + @default true + **/ + autohide: true }; - + /* * workaround to have 'destroyed' event to destroy popover when element is destroyed * see http://stackoverflow.com/questions/2200494/jquery-trigger-event-when-an-element-is-removed-from-the-dom @@ -149,5 +199,5 @@ } } }; - + }(window.jQuery)); \ No newline at end of file diff --git a/src/containers/editable-popover.js b/src/containers/editable-popover.js index 6bf22fc..db071ad 100644 --- a/src/containers/editable-popover.js +++ b/src/containers/editable-popover.js @@ -6,6 +6,11 @@ (function ($) { //extend methods + /** + Container based on Bootstrap Popover + + @class editableContainer (popover) + **/ $.extend($.fn.editableContainer.Constructor.prototype, { containerName: 'popover', innerCss: '.popover-content p', diff --git a/src/containers/editable-tooltip.js b/src/containers/editable-tooltip.js index d2d65dc..7596367 100644 --- a/src/containers/editable-tooltip.js +++ b/src/containers/editable-tooltip.js @@ -6,6 +6,11 @@ (function ($) { //extend methods + /** + Container based on jQuery UI Tooltip + + @class editableContainer (tooltip) + **/ $.extend($.fn.editableContainer.Constructor.prototype, { containerName: 'tooltip', innerCss: '.ui-tooltip-content', diff --git a/src/editable-form/editable-form-bootstrap.js b/src/editable-form/editable-form-bootstrap.js index 11cea04..8fe22a2 100644 --- a/src/editable-form/editable-form-bootstrap.js +++ b/src/editable-form/editable-form-bootstrap.js @@ -1,6 +1,10 @@ /** -* Editable-form Bootstrap engine -*/ +Editableform based on Twitter Bootstrap + +@class editableform (bootstrap) +@module editableform +@uses editableform +**/ (function ($) { //form template diff --git a/src/editable-form/editable-form-jqueryui.js b/src/editable-form/editable-form-jqueryui.js index 8e76b96..1d2585d 100644 --- a/src/editable-form/editable-form-jqueryui.js +++ b/src/editable-form/editable-form-jqueryui.js @@ -1,6 +1,10 @@ /** -* Editable-form jQuery UI engine -*/ +Editableform based on jQuery UI + +@class editableform (jqueryui) +@module editableform +@uses editableform +**/ (function ($) { $.extend($.fn.editableform.Constructor.prototype, { diff --git a/src/editable-form/editable-form.js b/src/editable-form/editable-form.js index fe00806..e9f0bfe 100644 --- a/src/editable-form/editable-form.js +++ b/src/editable-form/editable-form.js @@ -1,21 +1,12 @@ /** -* Editable-form plugin -* Form with single input element, two buttons and automatic loader, shown on init/submit -* Plugin applied to DIV tag and show form inside -* Input must be one of following types: -* - text -* - textarea -* - select -* - date -* - <your input here> -* -* EVENTS: -* - render -* - resize -* - save -*/ -(function ($) { +Form with single input element, two buttons and two states: normal/loading. +Applied as jQuery method to DIV tag (not to form tag!) +Editableform is linked with one of input types, e.g. 'text' or 'select'. +@class editableform +**/ +(function ($) { + var EditableForm = function (element, options) { this.options = $.extend({}, $.fn.editableform.defaults, options); this.$container = $(element); //div, containing form @@ -42,6 +33,11 @@ initTemplate: function() { this.$form = $($.fn.editableform.template); }, + /** + Renders editableform + + @method render + **/ render: function() { this.$loading = $(this.options.loading); this.$container.empty().append(this.$loading); @@ -49,6 +45,11 @@ this.initTemplate(); + /** + Fired when rendering starts + @event rendering + @param {Object} event event object + **/ this.$container.triggerHandler('rendering'); //render input @@ -72,6 +73,11 @@ }, this)); }, cancel: function() { + /** + Fired when form was cancelled by user + @event cancel + @param {Object} event event object + **/ this.$container.triggerHandler('cancel'); }, showLoading: function() { @@ -96,7 +102,12 @@ showForm: function() { this.$loading.hide(); this.$form.show(); - this.input.activate(); + this.input.activate(); + /** + Fired when form is shown + @event show + @param {Object} event event object + **/ this.$container.triggerHandler('show'); }, @@ -145,6 +156,19 @@ .done($.proxy(function(response) { this.error(false); this.value = newValue; + /** + Fired when form is submitted + @event save + @param {Object} event event object + @param {Object} params additional params + @param {mixed} params.newValue submitted value + @param {Object} params.response ajax response + + @example + $('#form-div').on('save'), function(e, params){ + if(params.newValue === 'username') {...} + }); + **/ this.$container.triggerHandler('save', {newValue: newValue, response: response}); }, this)) .fail($.proxy(function(xhr) { @@ -194,7 +218,22 @@ } }; - //jquery plugin definition + /* + Initialize editableform. Applied to jQuery object. + + @method $().editableform(options) + @params {Object} options + @example + var $form = $('<div>').editableform({ + type: 'text', + name: 'username', + url: 'post.php', + value: 'vitaliy' + }); + + //to display form you should call 'render' method + $form.editableform('render'); + */ $.fn.editableform = function (option) { var args = arguments; return this.each(function () { @@ -217,14 +256,86 @@ //defaults $.fn.editableform.defaults = { /* see also defaults for input */ + + /** + Type of input. Can be text|textarea|select|date + + @property type + @type String + @default 'text' + **/ type: 'text', + /** + Url for submit + + @property url + @type String|Object|Array + @default null + **/ url:null, + /** + Additional params for submit + + @property params + @type Object + @default null + **/ params:null, + /** + Name of field. Will be submitted on server. Can be taken from id attribute. + + @property name + @type String + @default null + **/ name: null, + /** + Primary key of editable object (e.g. record id in database). Use Object for composite keys. + + @property pk + @type String|Object|Function + @default null + **/ pk: null, - value: null, //initial value - send: 'auto', //always|auto|never + /** + Initial value. If not defined - will be taken from element's content. + For <i>select</i> type should be defined (as it is ID of shown text). + + @property value + @type String|Object + @default null + **/ + value: null, + /** + Strategy for sending data on server. Can be auto|always|never. + When 'auto' data will be sent on server only if pk defined, otherwise new value will be stored in element. + + @property send + @type String + @default 'auto' + **/ + send: 'auto', + /** + Template for loading element + + @property loading + @type String + @default <div class="editableform-loading"></div> + **/ loading: '<div class="editableform-loading"></div>', + /** + Function for client-side validation. If returns string - means validation not passed and string showed as error. + + @property validate + @type Function + @default null + @example + validate: function(value) { + if($.trim(value) == '') { + return 'This field is required'; + } + } + **/ validate: null }; diff --git a/src/element/editable-element.js b/src/element/editable-element.js index 038c69a..905d28a 100644 --- a/src/element/editable-element.js +++ b/src/element/editable-element.js @@ -1,11 +1,9 @@ /** -* Editable-element -* Initialize HTML element that can be editable by click. -* 1. methods -* -* 2. events -* - render -*/ +Makes editable any HTML element on page. +Applied as jquery method. + +@class editable +**/ (function ($) { var Editable = function (element, options) { @@ -27,7 +25,7 @@ //editableContainer must be defined if(!$.fn.editableContainer) { - $.error('You must define $.fn.editableContainer via including corresponding file (e.g. editablePopover)'); + $.error('You must define $.fn.editableContainer via including corresponding file (e.g. editable-popover.js)'); return; } @@ -89,11 +87,28 @@ } else { this.enable(); } + /** + Fired each time when element's text is rendered. Occurs on initialization and on each update of value. + Can be used for customizing display of value. + + @event render + @param {Object} event event object + @param {Object} editable editable instance + @example + $('#action').on('render', function(e, editable) { + var colors = {0: "gray", 1: "green", 2: "blue", 3: "red"}; + $(this).css("color", colors[editable.value]); + }); + **/ this.$element.triggerHandler('render', this); this.isInit = false; }, this)); }, + /** + Enables editable + @method enable() + **/ enable: function() { this.options.disabled = false; this.$element.removeClass('editable-disabled'); @@ -106,6 +121,10 @@ } }, + /** + Disables editable + @method disable() + **/ disable: function() { this.options.disabled = true; this.hide(); @@ -117,6 +136,10 @@ } }, + /** + Toggles enabled / disabled state of editable element + @method toggleDisabled() + **/ toggleDisabled: function() { if(this.options.disabled) { this.enable(); @@ -125,6 +148,13 @@ } }, + /** + Sets new option + + @method option(key, value) + @param {string} key + @param {mixed} value + **/ option: function(key, value) { if(key === 'disabled') { if(value) { @@ -143,7 +173,7 @@ } }, - /** + /* * set emptytext if element is empty (reverse: remove emptytext if needed) */ handleEmpty: function () { @@ -175,8 +205,9 @@ }, /** - * show container with form - */ + Shows container with form + @method show() + **/ show: function () { if(this.options.disabled) { return; @@ -206,8 +237,9 @@ }, /** - * hide container with form - */ + Hides container with form + @method hide() + **/ hide: function () { if(this.container && this.container.tip().is(':visible')) { this.container.hide(); @@ -220,8 +252,9 @@ }, /** - * show/hide form container - */ + Toggles container visibility (show / hide) + @method toggle() + **/ toggle: function () { if(this.container && this.container.tip().is(':visible')) { this.hide(); @@ -230,7 +263,7 @@ } }, - /** + /* * called when form was submitted */ save: function(e, params) { @@ -261,6 +294,12 @@ } }, + /** + Sets new value of editable + @method setValue(v, convertStr) + @param {mixed} v new value + @param {boolean} convertStr wether to convert value from string to internal format + **/ setValue: function(v, convertStr) { if(convertStr) { this.value = this.input.str2value(v); @@ -281,10 +320,35 @@ /* EDITABLE PLUGIN DEFINITION * ======================= */ + /** + jQuery method to initialize editable element. + + @method $().editable(options) + @params {Object} options + @example + $('#username').editable({ + type: 'text', + url: 'post.php', + pk: 1 + }); + **/ $.fn.editable = function (option) { - //special methods returning non-jquery object + //special API methods returning non-jquery object var result = {}, args = arguments, datakey = 'editable'; switch (option) { + /** + Runs client-side validation for all editables in jquery array + + @method validate() + @returns {Object} validation errors map + @example + $('#username, #fullname').editable('validate'); + // possible result: + { + username: "username is requied", + fullname: "fullname should be minimum 3 letters length" + } + **/ case 'validate': this.each(function () { var $this = $(this), data = $this.data(datakey), error; @@ -294,6 +358,18 @@ }); return result; + /** + Returns current values of editable elements. If value is <code>null</code> or <code>undefined</code> it will not be returned + @method getValue() + @returns {Object} object of element names and values + @example + $('#username, #fullname').editable('validate'); + // possible result: + { + username: "superuser", + fullname: "John" + } + **/ case 'getValue': this.each(function () { var $this = $(this), data = $this.data(datakey); @@ -303,6 +379,18 @@ }); return result; + /** + This method collects values from several editable elements and submit them all to server. + It is designed mainly for creating new records. + + @method submit(options) + @param {object} options + @param {object} options.url url to submit data + @param {object} options.data additional data to submit + @param {function} options.error error handler (called on both client-side and server-side validation errors) + @param {function} options.success success handler + @returns {Object} jQuery object + **/ case 'submit': //collects value, validate and submit to server for creating new record var config = arguments[1] || {}, $elems = this, @@ -360,14 +448,71 @@ $.fn.editable.defaults = { - type:'text', + /** + Type of input. Can be text|textarea|select|date + + @property type + @type String + @default 'text' + **/ + type: 'text', + /** + Sets disabled state of editable + + @property disabled + @type boolean + @default false + **/ disabled: false, + /** + How to toggle editable. Can be click|manual. + + @property toggle + @type string + @default 'click' + **/ toggle: 'click', - trigger: 'manual', + /** + Text shown when element is empty. + + @property emptytext + @type string + @default 'Empty' + **/ emptytext: 'Empty', + /** + Allows to automatically set element's text based on it's value. Usefull for select and date. + For example, if element's list is <code>{1: 'a', 2: 'b'}</code> value set to <code>1</code>, it's text will be automatically set to <code>a</code>. + Can be auto|always|never. <code>auto</code> means text will be set only if element is empty. + <code>always|never</code> means always(never) try to set element's text. + + @property autotext + @type string + @default 'auto' + **/ autotext: 'auto', + /** + Wether to return focus on element after form is closed. + This allows fully keyboard input. + + @property enablefocus + @type boolean + @default false + **/ enablefocus: false, - success: function(response, newValue) {} //value successfully sent on server and response status = 200 + /** + Success callback. Called when value successfully sent on server and response status = 200. + Can be used to process json response. If this function returns string - means error occured and string is shown as error message. + + @property success + @type function + @default null + @example + success: function(response, newValue) { + if(!response.success) return response.msg; + } + **/ + success: function(response, newValue) {} }; }(window.jQuery)); \ No newline at end of file