Merge branch 'release-1.0.0'

This commit is contained in:
vitalets 2012-11-19 18:32:24 +04:00
commit ec97af1d4b
81 changed files with 5163 additions and 10573 deletions
CHANGELOG.txtLICENSE-GPLREADME.mdgrunt.js
libs
jquery-ui-datepicker/js
poshytip
makezippackage.json
src
containers
editable-form
element
inputs
test

@ -1,9 +1,28 @@
X-editable changelog
=============================
Version 1.0.0 wip
Version 1.0.0 Nov 19, 2012
----------------------------
Initial release. Based on bootstrap-editable 1.1.4, but strongly refactored.
- support of bootstrap, jqueryui or pure jquery as core library
- directory structure re-arranged: split on several js files
- all known bugs of bootstrap-editable closed
Initial release. This library is new life of bootstrap-editable (1.1.4) that was strongly refactored and improved.
Main features:
- support not only bootstrap but any core library: bootstrap, jquery-ui or pure jquery
- different container classes to show form: popover, tooltip, poshytip, etc
- inline and popup versions
- new directory structure and logic in separate js files allowing easy contribution
It is not fully compatible with bootstrap-editable but has mainly the same interface and api.
Here list of differences to help you to upgrade your application:
[change] 'toggle' option value can be only click|manual (not toggling element id). In case of 'manual' you should write handler calling 'show' method.
[change] 'validate' option cannot be defined as object anymore.
[change] events 'init', 'update', 'shown', 'hidden' removed. Events 'save', 'cancel' added. Event 'render' remains.
[change] input's optiom 'template' renamed to 'tpl' (to exclude conflict with container's template).
[change] value can be stored internaly as object (previously was always string). Usefull for date inupt.
[change] 'error' callback option is removed. 'success' callback remained.
[enh] 'source' option in select can be array of structure [{value: 1, text: 'abc'}, {...}]. This allows to keep ordering of items in dropdown list. Previous format is supported for compability.
[enh] api method 'setValue' to set manually value of editable.
[change] locales directory is excluded from bootstrap-datepicker input. If you need localization you should jus download corresponding file from github.
[change] date and dateui specific options can be set only via 'datepicker' option in first level of config (previously it was possible to set some options directly in config, e.g. weekStart).
[change] if 'url' option defined as function - it is used as submit method instead of ajax (previously it was dynamically return url string and ajax occured anyway)
Also all known bugs of bootstrap-editable were closed.

@ -1,278 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

@ -3,14 +3,14 @@
In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery.
## Description
X-editable is new life of [bootstrap-editable](http://github.com/vitalets/bootstrap-editable) that was strongly refactored and extended.
X-editable is new life of [bootstrap-editable](http://github.com/vitalets/bootstrap-editable) that was strongly refactored and improved.
## Demo & Documentation
**http://vitalets.github.com/x-editable**
## Contributing
Please make all pull requests against `dev` branch. Thanks!
Please make all pull requests against `dev` branch. Thanks for your support!
### Important notes
Please don't edit files in the `dist` subdirectory as they are generated via grunt. You'll find source code in the `src` subdirectory!
@ -40,4 +40,4 @@ Note that the `phantomjs` executable needs to be in the system `PATH` for grunt
## License
Copyright (c) 2012 Vitaliy Potapov
Licensed under the MIT, GPL licenses.
Licensed under the MIT licenses.

215
grunt.js

@ -1,43 +1,37 @@
/*global module:false*/
module.exports = function(grunt) {
function getFiles() {
//directories
var
lib = 'src/',
forms = lib+'editable-form/',
inputs = lib+'inputs/',
containers = lib+'containers/';
grunt.loadNpmTasks('grunt-contrib');
//grunt.loadTasks('tasks/');
//config for different cores of lib
var config = {
bootstrap: {
form: [forms+'editable-form-bootstrap.js'],
container: [containers+'editable-popover.js'],
inputs: [inputs+'date/date.js', inputs+'date/bootstrap-datepicker/js/bootstrap-datepicker.js'],
css: [inputs+'date/bootstrap-datepicker/css/datepicker.css']
},
jqueryui: {
form: [forms+'editable-form-jqueryui.js'],
container: [containers+'editable-tooltip.js'],
inputs: [inputs+'dateui/dateui.js'],
css: []
},
jquery: {
form: [],
container: [containers+'editable-poshytip.js'],
inputs: [inputs+'dateui/dateui.js'],
css: []
}
};
//directories
var
lib = 'src/',
forms = lib+'editable-form/',
inputs = lib+'inputs/',
containers = lib+'containers/';
//config for different cores of lib
var config = {
bootstrap: {
form: [forms+'editable-form-bootstrap.js'],
container: [containers+'editable-popover.js'],
inputs: [inputs+'date/date.js', inputs+'date/bootstrap-datepicker.js'],
css: [inputs+'date/datepicker.css']
},
jqueryui: {
form: [forms+'editable-form-jqueryui.js'],
container: [containers+'editable-tooltip.js'],
inputs: [inputs+'dateui.js'],
css: []
},
jquery: {
form: [],
container: [containers+'editable-poshytip.js'],
inputs: [inputs+'dateui.js'],
css: []
}
};
var inline = [containers+'editable-inline.js'];
//common js files
var js = [
var inline = [containers+'editable-inline.js'];
//common js files
var js = [
'<banner:meta.banner>',
forms+'editable-form.js',
forms+'editable-form-utils.js',
@ -47,59 +41,71 @@ containers = lib+'containers/';
inputs+'text.js',
inputs+'textarea.js',
inputs+'select.js'
];
//common css files
var css = [
];
//common css files
var css = [
'<banner:meta.banner>',
forms+'editable-form.css',
containers+'editable-container.css',
lib+'element/editable-element.css'
];
//create grunt concat task
var task, folder, dest, concat_files = {}, min_files = {};
for(var k in config) {
folder = '<%= dist %>/'+k+'-editable/';
];
//popup
task = k+'_popup_js';
dest = folder+'js/'+k+'-editable'+ (k === 'jquery' ? '-poshytip' : '');
concat_files[task] = {
src: js.concat(config[k].form).concat(config[k].container).concat(config[k].inputs),
dest: dest+'.js'
};
min_files[task] = {
src: ['<banner:meta.banner>', '<config:concat.'+task+'.dest>'],
dest: dest + '.min.js'
};
//inline
task = k+'_inline_js';
dest = folder+'js/'+k+'-editable-inline';
concat_files[task] = {
src: js.concat(config[k].form).concat(inline).concat(config[k].inputs),
dest: dest+'.js'
};
min_files[task] = {
src: ['<banner:meta.banner>', '<config:concat.'+task+'.dest>'],
dest: dest + '.min.js'
};
//create 'concat' config
var task, folder, dest, concat_files = {}, min_files = {};
for(var k in config) {
folder = '<%= dist %>/'+k+'-editable/';
//css
concat_files[k+'_css'] = {
src: css.concat(config[k].css),
dest: folder+'css/'+k+'-editable.css'
};
}
//popup
task = k+'_popup_js';
dest = folder+'js/'+k+'-editable'+ (k === 'jquery' ? '-poshytip' : '');
concat_files[task] = {
src: js.concat(config[k].form).concat(config[k].container).concat(config[k].inputs),
dest: dest+'.js'
};
min_files[task] = {
src: ['<banner:meta.banner>', '<config:concat.'+task+'.dest>'],
dest: dest + '.min.js'
};
//inline
task = k+'_inline_js';
dest = folder+'js/'+k+'-editable-inline';
concat_files[task] = {
src: js.concat(config[k].form).concat(inline).concat(config[k].inputs),
dest: dest+'.js'
};
min_files[task] = {
src: ['<banner:meta.banner>', '<config:concat.'+task+'.dest>'],
dest: dest + '.min.js'
};
//css
concat_files[k+'_css'] = {
src: css.concat(config[k].css),
dest: folder+'css/'+k+'-editable.css'
};
}
return {concat_files: concat_files, min_files: min_files};
}
/*global module:false*/
module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib');
//module for testing
var module = '';
//module = '&module=textarea';
//module = '&module=select';
//module = '&module=text';
//get js and css for different builds
var files = getFiles();
// Project configuration.
// Project configuration.
grunt.initConfig({
pkg: '<json:package.json>',
dist: 'dist',
@ -111,8 +117,8 @@ containers = lib+'containers/';
' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */'
},
clean: ['<config:dist>'],
concat: concat_files,
min: min_files,
concat: files.concat_files,
min: files.min_files,
qunit: {
bootstrap: [
'http://localhost:8000/test/index.html?f=bootstrap&c=popup'+module,
@ -142,8 +148,8 @@ containers = lib+'containers/';
'src/inputs/*.js',
'src/element/*.js',
'src/inputs/*.js',
'src/inputs/date/date.js'
//do not check bootstrap-datepicker
'src/inputs/date/date.js',
'src/inputs/dateui/dateui.js'
]
},
/*
@ -174,17 +180,41 @@ containers = lib+'containers/';
copy: {
dist: {
files: {
'<%= dist %>/bootstrap-editable/css/img' : 'src/editable-form/img/*',
'<%= dist %>/jqueryui-editable/css/img' : 'src/editable-form/img/*',
'<%= dist %>/jquery-editable/css/img' : 'src/editable-form/img/*',
'<%= dist %>/bootstrap-editable/js/locales' : 'src/inputs/date/locales/*',
'<%= dist %>': ['LICENSE-GPL', 'LICENSE-MIT', 'README.md', 'CHANGELOG.txt']
'<%= dist %>/bootstrap-editable/css/img/' : 'src/editable-form/img/*',
'<%= dist %>/jqueryui-editable/css/img/' : 'src/editable-form/img/*',
'<%= dist %>/jquery-editable/css/img/' : 'src/editable-form/img/*',
//licences
'<%= dist %>/': ['LICENSE-MIT', 'README.md', 'CHANGELOG.txt']
},
options: {
flatten: true
}
}
},
ui_datepicker: {
files: {
//copy jquery ui datepicker
'<%= dist %>/jquery-editable/jquery-ui-datepicker/' : 'src/inputs/dateui/jquery-ui-datepicker/**'
}
}
},
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
/*
@ -214,15 +244,16 @@ containers = lib+'containers/';
});
//test task
grunt.registerTask('test', 'server qunit:bootstrap');
grunt.registerTask('testall', 'server qunit');
grunt.registerTask('test', 'lint server qunit:bootstrap');
grunt.registerTask('testall', 'lint server qunit');
// Default task.
// grunt.registerTask('default', 'lint qunit');
grunt.registerTask('default', 'clean concat min copy');
grunt.registerTask('default', 'clean lint concat min copy');
// build
grunt.registerTask('build', 'clean lint concat min copy');
//to run particular task use ":", e.g. copy:libs
};

File diff suppressed because it is too large Load Diff

@ -1,470 +0,0 @@
/*
* Poshy Tip jQuery plugin v1.1
* http://vadikom.com/tools/poshy-tip-jquery-plugin-for-stylish-tooltips/
* Copyright 2010-2011, Vasil Dinkov, http://vadikom.com/
*/
(function($) {
var tips = [],
reBgImage = /^url\(["']?([^"'\)]*)["']?\);?$/i,
rePNG = /\.png$/i,
ie6 = $.browser.msie && $.browser.version == 6;
// make sure the tips' position is updated on resize
function handleWindowResize() {
$.each(tips, function() {
this.refresh(true);
});
}
$(window).resize(handleWindowResize);
$.Poshytip = function(elm, options) {
this.$elm = $(elm);
this.opts = $.extend({}, $.fn.poshytip.defaults, options);
this.$tip = $(['<div class="',this.opts.className,'">',
'<div class="tip-inner tip-bg-image"></div>',
'<div class="tip-arrow tip-arrow-top tip-arrow-right tip-arrow-bottom tip-arrow-left"></div>',
'</div>'].join('')).appendTo(document.body);
this.$arrow = this.$tip.find('div.tip-arrow');
this.$inner = this.$tip.find('div.tip-inner');
this.disabled = false;
this.content = null;
this.init();
};
$.Poshytip.prototype = {
init: function() {
tips.push(this);
// save the original title and a reference to the Poshytip object
var title = this.$elm.attr('title');
this.$elm.data('title.poshytip', title !== undefined ? title : null)
.data('poshytip', this);
// hook element events
if (this.opts.showOn != 'none') {
this.$elm.bind({
'mouseenter.poshytip': $.proxy(this.mouseenter, this),
'mouseleave.poshytip': $.proxy(this.mouseleave, this)
});
switch (this.opts.showOn) {
case 'hover':
if (this.opts.alignTo == 'cursor')
this.$elm.bind('mousemove.poshytip', $.proxy(this.mousemove, this));
if (this.opts.allowTipHover)
this.$tip.hover($.proxy(this.clearTimeouts, this), $.proxy(this.mouseleave, this));
break;
case 'focus':
this.$elm.bind({
'focus.poshytip': $.proxy(this.show, this),
'blur.poshytip': $.proxy(this.hide, this)
});
break;
}
}
},
mouseenter: function(e) {
if (this.disabled)
return true;
this.$elm.attr('title', '');
if (this.opts.showOn == 'focus')
return true;
this.clearTimeouts();
this.showTimeout = setTimeout($.proxy(this.show, this), this.opts.showTimeout);
},
mouseleave: function(e) {
if (this.disabled || this.asyncAnimating && (this.$tip[0] === e.relatedTarget || jQuery.contains(this.$tip[0], e.relatedTarget)))
return true;
var title = this.$elm.data('title.poshytip');
if (title !== null)
this.$elm.attr('title', title);
if (this.opts.showOn == 'focus')
return true;
this.clearTimeouts();
this.hideTimeout = setTimeout($.proxy(this.hide, this), this.opts.hideTimeout);
},
mousemove: function(e) {
if (this.disabled)
return true;
this.eventX = e.pageX;
this.eventY = e.pageY;
if (this.opts.followCursor && this.$tip.data('active')) {
this.calcPos();
this.$tip.css({left: this.pos.l, top: this.pos.t});
if (this.pos.arrow)
this.$arrow[0].className = 'tip-arrow tip-arrow-' + this.pos.arrow;
}
},
show: function() {
if (this.disabled || this.$tip.data('active'))
return;
this.reset();
this.update();
this.display();
if (this.opts.timeOnScreen)
setTimeout($.proxy(this.hide, this), this.opts.timeOnScreen);
},
hide: function() {
if (this.disabled || !this.$tip.data('active'))
return;
this.display(true);
},
reset: function() {
this.$tip.queue([]).detach().css('visibility', 'hidden').data('active', false);
this.$inner.find('*').poshytip('hide');
if (this.opts.fade)
this.$tip.css('opacity', this.opacity);
this.$arrow[0].className = 'tip-arrow tip-arrow-top tip-arrow-right tip-arrow-bottom tip-arrow-left';
this.asyncAnimating = false;
},
update: function(content, dontOverwriteOption) {
if (this.disabled)
return;
var async = content !== undefined;
if (async) {
if (!dontOverwriteOption)
this.opts.content = content;
if (!this.$tip.data('active'))
return;
} else {
content = this.opts.content;
}
// update content only if it has been changed since last time
var self = this,
newContent = typeof content == 'function' ?
content.call(this.$elm[0], function(newContent) {
self.update(newContent);
}) :
content == '[title]' ? this.$elm.data('title.poshytip') : content;
if (this.content !== newContent) {
this.$inner.empty().append(newContent);
this.content = newContent;
}
this.refresh(async);
},
refresh: function(async) {
if (this.disabled)
return;
if (async) {
if (!this.$tip.data('active'))
return;
// save current position as we will need to animate
var currPos = {left: this.$tip.css('left'), top: this.$tip.css('top')};
}
// reset position to avoid text wrapping, etc.
this.$tip.css({left: 0, top: 0}).appendTo(document.body);
// save default opacity
if (this.opacity === undefined)
this.opacity = this.$tip.css('opacity');
// check for images - this code is here (i.e. executed each time we show the tip and not on init) due to some browser inconsistencies
var bgImage = this.$tip.css('background-image').match(reBgImage),
arrow = this.$arrow.css('background-image').match(reBgImage);
if (bgImage) {
var bgImagePNG = rePNG.test(bgImage[1]);
// fallback to background-color/padding/border in IE6 if a PNG is used
if (ie6 && bgImagePNG) {
this.$tip.css('background-image', 'none');
this.$inner.css({margin: 0, border: 0, padding: 0});
bgImage = bgImagePNG = false;
} else {
this.$tip.prepend('<table class="fallback" border="0" cellpadding="0" cellspacing="0"><tr><td class="tip-top tip-bg-image" colspan="2"><span></span></td><td class="tip-right tip-bg-image" rowspan="2"><span></span></td></tr><tr><td class="tip-left tip-bg-image" rowspan="2"><span></span></td><td></td></tr><tr><td class="tip-bottom tip-bg-image" colspan="2"><span></span></td></tr></table>')
.css({border: 0, padding: 0, 'background-image': 'none', 'background-color': 'transparent'})
.find('.tip-bg-image').css('background-image', 'url("' + bgImage[1] +'")').end()
.find('td').eq(3).append(this.$inner);
}
// disable fade effect in IE due to Alpha filter + translucent PNG issue
if (bgImagePNG && !$.support.opacity)
this.opts.fade = false;
}
// IE arrow fixes
if (arrow && !$.support.opacity) {
// disable arrow in IE6 if using a PNG
if (ie6 && rePNG.test(arrow[1])) {
arrow = false;
this.$arrow.css('background-image', 'none');
}
// disable fade effect in IE due to Alpha filter + translucent PNG issue
this.opts.fade = false;
}
var $table = this.$tip.find('table.fallback');
if (ie6) {
// fix min/max-width in IE6
this.$tip[0].style.width = '';
$table.width('auto').find('td').eq(3).width('auto');
var tipW = this.$tip.width(),
minW = parseInt(this.$tip.css('min-width')),
maxW = parseInt(this.$tip.css('max-width'));
if (!isNaN(minW) && tipW < minW)
tipW = minW;
else if (!isNaN(maxW) && tipW > maxW)
tipW = maxW;
this.$tip.add($table).width(tipW).eq(0).find('td').eq(3).width('100%');
} else if ($table[0]) {
// fix the table width if we are using a background image
// IE9, FF4 use float numbers for width/height so use getComputedStyle for them to avoid text wrapping
// for details look at: http://vadikom.com/dailies/offsetwidth-offsetheight-useless-in-ie9-firefox4/
$table.width('auto').find('td').eq(3).width('auto').end().end().width(document.defaultView && document.defaultView.getComputedStyle && parseFloat(document.defaultView.getComputedStyle(this.$tip[0], null).width) || this.$tip.width()).find('td').eq(3).width('100%');
}
this.tipOuterW = this.$tip.outerWidth();
this.tipOuterH = this.$tip.outerHeight();
this.calcPos();
// position and show the arrow image
if (arrow && this.pos.arrow) {
this.$arrow[0].className = 'tip-arrow tip-arrow-' + this.pos.arrow;
this.$arrow.css('visibility', 'inherit');
}
if (async) {
this.asyncAnimating = true;
var self = this;
this.$tip.css(currPos).animate({left: this.pos.l, top: this.pos.t}, 200, function() { self.asyncAnimating = false; });
} else {
this.$tip.css({left: this.pos.l, top: this.pos.t});
}
},
display: function(hide) {
var active = this.$tip.data('active');
if (active && !hide || !active && hide)
return;
this.$tip.stop();
if ((this.opts.slide && this.pos.arrow || this.opts.fade) && (hide && this.opts.hideAniDuration || !hide && this.opts.showAniDuration)) {
var from = {}, to = {};
// this.pos.arrow is only undefined when alignX == alignY == 'center' and we don't need to slide in that rare case
if (this.opts.slide && this.pos.arrow) {
var prop, arr;
if (this.pos.arrow == 'bottom' || this.pos.arrow == 'top') {
prop = 'top';
arr = 'bottom';
} else {
prop = 'left';
arr = 'right';
}
var val = parseInt(this.$tip.css(prop));
from[prop] = val + (hide ? 0 : (this.pos.arrow == arr ? -this.opts.slideOffset : this.opts.slideOffset));
to[prop] = val + (hide ? (this.pos.arrow == arr ? this.opts.slideOffset : -this.opts.slideOffset) : 0) + 'px';
}
if (this.opts.fade) {
from.opacity = hide ? this.$tip.css('opacity') : 0;
to.opacity = hide ? 0 : this.opacity;
}
this.$tip.css(from).animate(to, this.opts[hide ? 'hideAniDuration' : 'showAniDuration']);
}
hide ? this.$tip.queue($.proxy(this.reset, this)) : this.$tip.css('visibility', 'inherit');
this.$tip.data('active', !active);
},
disable: function() {
this.reset();
this.disabled = true;
},
enable: function() {
this.disabled = false;
},
destroy: function() {
this.reset();
this.$tip.remove();
delete this.$tip;
this.content = null;
this.$elm.unbind('.poshytip').removeData('title.poshytip').removeData('poshytip');
tips.splice($.inArray(this, tips), 1);
},
clearTimeouts: function() {
if (this.showTimeout) {
clearTimeout(this.showTimeout);
this.showTimeout = 0;
}
if (this.hideTimeout) {
clearTimeout(this.hideTimeout);
this.hideTimeout = 0;
}
},
calcPos: function() {
var pos = {l: 0, t: 0, arrow: ''},
$win = $(window),
win = {
l: $win.scrollLeft(),
t: $win.scrollTop(),
w: $win.width(),
h: $win.height()
}, xL, xC, xR, yT, yC, yB;
if (this.opts.alignTo == 'cursor') {
xL = xC = xR = this.eventX;
yT = yC = yB = this.eventY;
} else { // this.opts.alignTo == 'target'
var elmOffset = this.$elm.offset(),
elm = {
l: elmOffset.left,
t: elmOffset.top,
w: this.$elm.outerWidth(),
h: this.$elm.outerHeight()
};
xL = elm.l + (this.opts.alignX != 'inner-right' ? 0 : elm.w); // left edge
xC = xL + Math.floor(elm.w / 2); // h center
xR = xL + (this.opts.alignX != 'inner-left' ? elm.w : 0); // right edge
yT = elm.t + (this.opts.alignY != 'inner-bottom' ? 0 : elm.h); // top edge
yC = yT + Math.floor(elm.h / 2); // v center
yB = yT + (this.opts.alignY != 'inner-top' ? elm.h : 0); // bottom edge
}
// keep in viewport and calc arrow position
switch (this.opts.alignX) {
case 'right':
case 'inner-left':
pos.l = xR + this.opts.offsetX;
if (pos.l + this.tipOuterW > win.l + win.w)
pos.l = win.l + win.w - this.tipOuterW;
if (this.opts.alignX == 'right' || this.opts.alignY == 'center')
pos.arrow = 'left';
break;
case 'center':
pos.l = xC - Math.floor(this.tipOuterW / 2);
if (pos.l + this.tipOuterW > win.l + win.w)
pos.l = win.l + win.w - this.tipOuterW;
else if (pos.l < win.l)
pos.l = win.l;
break;
default: // 'left' || 'inner-right'
pos.l = xL - this.tipOuterW - this.opts.offsetX;
if (pos.l < win.l)
pos.l = win.l;
if (this.opts.alignX == 'left' || this.opts.alignY == 'center')
pos.arrow = 'right';
}
switch (this.opts.alignY) {
case 'bottom':
case 'inner-top':
pos.t = yB + this.opts.offsetY;
// 'left' and 'right' need priority for 'target'
if (!pos.arrow || this.opts.alignTo == 'cursor')
pos.arrow = 'top';
if (pos.t + this.tipOuterH > win.t + win.h) {
pos.t = yT - this.tipOuterH - this.opts.offsetY;
if (pos.arrow == 'top')
pos.arrow = 'bottom';
}
break;
case 'center':
pos.t = yC - Math.floor(this.tipOuterH / 2);
if (pos.t + this.tipOuterH > win.t + win.h)
pos.t = win.t + win.h - this.tipOuterH;
else if (pos.t < win.t)
pos.t = win.t;
break;
default: // 'top' || 'inner-bottom'
pos.t = yT - this.tipOuterH - this.opts.offsetY;
// 'left' and 'right' need priority for 'target'
if (!pos.arrow || this.opts.alignTo == 'cursor')
pos.arrow = 'bottom';
if (pos.t < win.t) {
pos.t = yB + this.opts.offsetY;
if (pos.arrow == 'bottom')
pos.arrow = 'top';
}
}
this.pos = pos;
}
};
$.fn.poshytip = function(options) {
if (typeof options == 'string') {
var args = arguments,
method = options;
Array.prototype.shift.call(args);
// unhook live events if 'destroy' is called
if (method == 'destroy')
this.die('mouseenter.poshytip').die('focus.poshytip');
return this.each(function() {
var poshytip = $(this).data('poshytip');
if (poshytip && poshytip[method])
poshytip[method].apply(poshytip, args);
});
}
var opts = $.extend({}, $.fn.poshytip.defaults, options);
// generate CSS for this tip class if not already generated
if (!$('#poshytip-css-' + opts.className)[0])
$(['<style id="poshytip-css-',opts.className,'" type="text/css">',
'div.',opts.className,'{visibility:hidden;position:absolute;top:0;left:0;}',
'div.',opts.className,' table, div.',opts.className,' td{margin:0;font-family:inherit;font-size:inherit;font-weight:inherit;font-style:inherit;font-variant:inherit;}',
'div.',opts.className,' td.tip-bg-image span{display:block;font:1px/1px sans-serif;height:',opts.bgImageFrameSize,'px;width:',opts.bgImageFrameSize,'px;overflow:hidden;}',
'div.',opts.className,' td.tip-right{background-position:100% 0;}',
'div.',opts.className,' td.tip-bottom{background-position:100% 100%;}',
'div.',opts.className,' td.tip-left{background-position:0 100%;}',
'div.',opts.className,' div.tip-inner{background-position:-',opts.bgImageFrameSize,'px -',opts.bgImageFrameSize,'px;}',
'div.',opts.className,' div.tip-arrow{visibility:hidden;position:absolute;overflow:hidden;font:1px/1px sans-serif;}',
'</style>'].join('')).appendTo('head');
// check if we need to hook live events
if (opts.liveEvents && opts.showOn != 'none') {
var deadOpts = $.extend({}, opts, { liveEvents: false });
switch (opts.showOn) {
case 'hover':
this.live('mouseenter.poshytip', function() {
var $this = $(this);
if (!$this.data('poshytip'))
$this.poshytip(deadOpts).poshytip('mouseenter');
});
break;
case 'focus':
this.live('focus.poshytip', function() {
var $this = $(this);
if (!$this.data('poshytip'))
$this.poshytip(deadOpts).poshytip('show');
});
break;
}
return this;
}
return this.each(function() {
new $.Poshytip(this, opts);
});
}
// default settings
$.fn.poshytip.defaults = {
content: '[title]', // content to display ('[title]', 'string', element, function(updateCallback){...}, jQuery)
className: 'tip-yellow', // class for the tips
bgImageFrameSize: 10, // size in pixels for the background-image (if set in CSS) frame around the inner content of the tip
showTimeout: 500, // timeout before showing the tip (in milliseconds 1000 == 1 second)
hideTimeout: 100, // timeout before hiding the tip
timeOnScreen: 0, // timeout before automatically hiding the tip after showing it (set to > 0 in order to activate)
showOn: 'hover', // handler for showing the tip ('hover', 'focus', 'none') - use 'none' to trigger it manually
liveEvents: false, // use live events
alignTo: 'cursor', // align/position the tip relative to ('cursor', 'target')
alignX: 'right', // horizontal alignment for the tip relative to the mouse cursor or the target element
// ('right', 'center', 'left', 'inner-left', 'inner-right') - 'inner-*' matter if alignTo:'target'
alignY: 'top', // vertical alignment for the tip relative to the mouse cursor or the target element
// ('bottom', 'center', 'top', 'inner-bottom', 'inner-top') - 'inner-*' matter if alignTo:'target'
offsetX: -22, // offset X pixels from the default position - doesn't matter if alignX:'center'
offsetY: 18, // offset Y pixels from the default position - doesn't matter if alignY:'center'
allowTipHover: true, // allow hovering the tip without hiding it onmouseout of the target - matters only if showOn:'hover'
followCursor: false, // if the tip should follow the cursor - matters only if showOn:'hover' and alignTo:'cursor'
fade: true, // use fade animation
slide: true, // use slide animation
slideOffset: 8, // slide animation offset
showAniDuration: 300, // show animation duration - set to 0 if you don't want show animation
hideAniDuration: 300 // hide animation duration - set to 0 if you don't want hide animation
};
})(jQuery);

10
makezip

@ -1,10 +0,0 @@
cd dist
#extract version
version=$(head -1 bootstrap-editable/js/bootstrap-editable.js | sed -n 's/^.*v\([0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/p')
mkdir -p zip
rm -rf zip/*.zip
zip -rT zip/bootstrap-editable-$version.zip bootstrap-editable LICENSE-GPL LICENSE-MIT README.md CHANGELOG.txt
zip -rT zip/jqueryui-editable-$version.zip jqueryui-editable LICENSE-GPL LICENSE-MIT README.md CHANGELOG.txt
zip -rT zip/jquery-editable-$version.zip jquery-editable LICENSE-GPL LICENSE-MIT README.md CHANGELOG.txt

@ -1,9 +1,9 @@
{
"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",
"homepage": "https://github.com/vitalets/x-editable",
"homepage": "http://github.com/vitalets/x-editable",
"author": {
"name": "Vitaliy Potapov",
"email": "noginsk@rambler.ru"
@ -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": []
}

@ -1,48 +1,56 @@
/**
* 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
*/
Attaches stand-alone container with editable-form to HTML element. Element is used only for positioning, value is not stored anywhere.<br>
This method applied internally in <code>$().editable()</code>. You should subscribe on it's events (save / cancel) to get profit of it.<br>
Final realization can be different: bootstrap-popover, jqueryui-tooltip, poshytip, inline-div. It depends on which js file you include.<br>
Applied as jQuery method.
@class editableContainer
@uses editableform
**/
(function ($) {
//Constructor
var EditableContainer = function (element, options) {
this.init(element, options);
};
//methods
EditableContainer.prototype = {
containerName: null, //tbd in child class
innerCss: null, //tbd in child class
init: function(element, options) {
this.$element = $(element);
//todo: what is in priority: data or js?
this.options = $.extend({}, $.fn.editableContainer.defaults, $.fn.editableform.utils.getConfigData(this.$element), options);
this.splitOptions();
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);
//split options on containerOptions and formOptions
splitOptions: function() {
this.containerOptions = {};
this.formOptions = {};
var cDef = $.fn[this.containerName].defaults;
for(var k in this.options) {
if(k in cDef) {
this.containerOptions[k] = this.options[k];
} else {
this.formOptions[k] = this.options[k];
}
}
},
initContainer: function(){
this.call(this.containerOptions);
},
initForm: function() {
this.$form = $('<div>')
.editableform(this.options)
.editableform(this.formOptions)
.on({
save: $.proxy(this.save, this),
cancel: $.proxy(this.cancel, this),
@ -52,92 +60,188 @@
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. You can use <code>$(this).data('editableContainer')</code> inside handler to access to editableContainer instance
@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
$('#username').on('save', function(e, params) {
//assuming server response: '{success: true}'
var pk = $(this).data('editableContainer').options.pk;
if(params.response && params.response.success) {
alert('value: ' + params.newValue + ' with pk: ' + pk + ' saved!');
} else {
alert('error!');
}
});
**/
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;
if(key in this.containerOptions) {
this.containerOptions[key] = value;
this.setContainerOption(key, value);
} else {
this.formOptions[key] = value;
if(this.$form) {
this.$form.editableform('option', key, value);
}
}
},
setContainerOption: function(key, value) {
this.call('option', key, value);
},
/**
Destroys the container instance
@method destroy()
**/
destroy: function() {
this.call('destroy');
}
};
/**
jQuery method to initialize editableContainer.
//jQuery plugin definition
@method $().editableContainer(options)
@params {Object} options
@example
$('#edit').editableContainer({
type: 'text',
url: 'post.php',
pk: 1,
value: 'hello'
});
**/
$.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
@private
**/
value: null,
/**
Placement of container relative to element. Can be <code>top|right|bottom|left</code>. 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
@private
**/
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 +253,5 @@
}
}
};
}(window.jQuery));

@ -17,6 +17,11 @@
}
},
splitOptions: function() {
this.containerOptions = {};
this.formOptions = this.options;
},
tip: function() {
return this.$form;
},

@ -6,12 +6,25 @@
(function ($) {
//extend methods
/**
Container based on Bootstrap Popover
@class editableContainer (popover)
**/
$.extend($.fn.editableContainer.Constructor.prototype, {
containerName: 'popover',
innerCss: '.popover-content p',
option: function(key, value) {
this.options[key] = value;
initContainer: function(){
$.extend(this.containerOptions, {
trigger: 'manual',
selector: 'false',
content: ' '
});
this.call(this.containerOptions);
},
setContainerOption: function(key, value) {
this.container().options[key] = value;
},
@ -36,13 +49,9 @@
tp = {top:pos.top + pos.height, left:pos.left + pos.width / 2 - actualWidth / 2};
break;
case 'top':
/* For Bootstrap 2.1.0 - 2.1.1: 10 pixels needed to correct popover position. See https://github.com/twitter/bootstrap/issues/4665 */
//if($tip.find('.arrow').get(0).offsetHeight === 10) {actualHeight += 10;}
tp = {top:pos.top - actualHeight, left:pos.left + pos.width / 2 - actualWidth / 2};
break;
case 'left':
/* For Bootstrap 2.1.0 - 2.1.1: 10 pixels needed to correct popover position. See https://github.com/twitter/bootstrap/issues/4665 */
//if($tip.find('.arrow').get(0).offsetWidth === 10) {actualWidth += 10;}
tp = {top:pos.top + pos.height / 2 - actualHeight / 2, left:pos.left - actualWidth};
break;
case 'right':
@ -55,8 +64,10 @@
});
//defaults
/*
$.fn.editableContainer.defaults = $.extend({}, $.fn.popover.defaults, $.fn.editableContainer.defaults, {
content: ' '
});
});
*/
}(window.jQuery));

@ -12,10 +12,17 @@
initContainer: function(){
this.handlePlacement();
this.call(this.options);
$.extend(this.containerOptions, {
showOn: 'none',
content: '',
alignTo: 'target'
});
this.call(this.containerOptions);
var $content = $('<div>')
.append($('<label>').text(this.options.title || this.$element.data( "ui-tooltip-title") || this.$element.data( "originalTitle")))
.append($('<label>').text(this.options.title || this.$element.data( "title") || this.$element.data( "originalTitle")))
.append(this.initForm());
this.call('update', $content);
@ -25,7 +32,6 @@
this.$form.editableform('render');
this.tip().addClass('editable-container');
this.call('show');
this.$form.data('editableform').input.activate();
},
@ -59,20 +65,18 @@
break;
}
this.options.alignX = x;
this.options.offsetX = ox;
this.options.alignY = y;
this.options.offsetY = oy;
$.extend(this.containerOptions, {
alignX: x,
offsetX: ox,
alignY: y,
offsetY:oy
});
}
});
//defaults
$.fn.editableContainer.defaults = $.extend({}, $.fn.poshytip.defaults, $.fn.editableContainer.defaults, {
className: 'tip-yellowsimple',
showOn: 'none',
content: '',
alignTo: 'target'
$.fn.editableContainer.defaults = $.extend({}, $.fn.editableContainer.defaults, {
className: 'tip-yellowsimple'
});

@ -6,21 +6,48 @@
(function ($) {
//extend methods
/**
Container based on jQuery UI Tooltip
@class editableContainer (tooltip)
**/
$.extend($.fn.editableContainer.Constructor.prototype, {
containerName: 'tooltip',
innerCss: '.ui-tooltip-content',
//split options on containerOptions and formOptions
splitOptions: function() {
this.containerOptions = {};
this.formOptions = {};
//defaults for tooltip
var cDef = $.ui[this.containerName].prototype.options;
for(var k in this.options) {
if(k in cDef) {
this.containerOptions[k] = this.options[k];
} else {
this.formOptions[k] = this.options[k];
}
}
},
initContainer: function(){
this.handlePlacement();
this.options.open = $.proxy(function() {
//disable events hiding tooltip by default
this.container()._on(this.container().element, {
mouseleave: function(e){ e.stopImmediatePropagation(); },
focusout: function(e){ e.stopImmediatePropagation(); }
});
}, this);
this.call(this.options);
//disable standart event to show tooltip
$.extend(this.containerOptions, {
items: '*',
content: ' ',
track: false,
open: $.proxy(function() {
//disable events hiding tooltip by default
this.container()._on(this.container().element, {
mouseleave: function(e){ e.stopImmediatePropagation(); },
focusout: function(e){ e.stopImmediatePropagation(); }
});
}, this)
});
this.call(this.containerOptions);
//disable standart triggering tooltip event
this.container()._off(this.container().element, 'mouseover focusin');
},
@ -47,7 +74,7 @@
setPosition: function() {
this.tip().position( $.extend({
of: this.$element
}, this.options.position ) );
}, this.containerOptions.position ) );
},
handlePlacement: function() {
@ -79,19 +106,20 @@
break;
}
this.options.position = $.extend({}, this.options.position, pos);
this.containerOptions.position = pos;
},
destroy: function() {
//jqueryui tooltip destroy itself
}
destroy: function() {
//jqueryui tooltip destroys itself
}
});
//defaults
/*
$.fn.editableContainer.defaults = $.extend({}, $.fn.tooltip.defaults, $.fn.editableContainer.defaults, {
items: '*',
content: ' ',
position: {}
});
*/
}(window.jQuery));

@ -1,5 +1,5 @@
/**
* Editable-form Bootstrap engine
/*
Editableform based on Twitter Bootstrap
*/
(function ($) {

@ -1,5 +1,5 @@
/**
* Editable-form jQuery UI engine
/*
Editableform based on jQuery UI
*/
(function ($) {

@ -1,5 +1,5 @@
/**
* EditableForm utils
* EditableForm utilites
*/
(function ($) {
$.extend($.fn.editableform, {

@ -30,14 +30,12 @@
display: inline-block;
}
/* for inline datepicker do not to inherit from table (bootstrap) */
.table-striped .editableform table td, .editableform table th {
border: none !important;
.editableform textarea {
height: 150px; /*default height for textarea*/
}
.table-striped .editableform table tr:nth-child(2n+1) td,
.table-striped .editableform table tr:nth-child(2n+1) th {
background-color: transparent;
}
.editableform .editable-date {
float: left;
padding: 0;
margin: 0 0 9px 0;
}

@ -1,21 +1,14 @@
/**
* 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
@uses text
@uses textarea
**/
(function ($) {
var EditableForm = function (element, options) {
this.options = $.extend({}, $.fn.editableform.defaults, options);
this.$container = $(element); //div, containing form
@ -42,13 +35,23 @@
initTemplate: function() {
this.$form = $($.fn.editableform.template);
},
/**
Renders editableform
@method render
**/
render: function() {
this.$loading = $(this.options.loading);
this.$loading = $($.fn.editableform.loading);
this.$container.empty().append(this.$loading);
this.showLoading();
this.initTemplate();
/**
Fired when rendering starts
@event rendering
@param {Object} event event object
**/
this.$container.triggerHandler('rendering');
//render input
@ -72,6 +75,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 +104,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,10 +158,23 @@
.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) {
this.error(xhr.responseText || xhr.statusText || 'Unknown error!');
this.error(typeof xhr === 'string' ? xhr : xhr.responseText || xhr.statusText || 'Unknown error!');
this.showForm();
}, this));
},
@ -170,13 +196,16 @@
pk: pk
});
//send ajax to server and return deferred object
return $.ajax({
url : (typeof this.options.url === 'function') ? this.options.url.call(this) : this.options.url,
data : params,
type : 'post',
dataType: 'json'
});
if(typeof this.options.url === 'function') { //user's function
return this.options.url.call(this, params);
} else { //send ajax to server and return deferred object
return $.ajax({
url : this.options.url,
data : params,
type : 'post',
dataType: 'json'
});
}
}
},
@ -194,7 +223,22 @@
}
};
//jquery plugin definition
/*
Initialize editableform. Applied to jQuery object.
@method $().editableform(options)
@params {Object} options
@example
var $form = $('&lt;div&gt;').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 +261,88 @@
//defaults
$.fn.editableform.defaults = {
/* see also defaults for input */
/**
Type of input. Can be <code>text|textarea|select|date</code>
@property type
@type string
@default 'text'
**/
type: 'text',
/**
Url for submit, e.g. <code>post.php</code>
If function - it will be called instead of ajax. Function can return deferred object to run fail/done callbacks.
@property url
@type string|function
@default null
@example
url: function(params) {
if(params.value === 'abc') {
var d = new $.Deferred;
return d.reject('field cannot be "abc"'); //returning error via deferred object
} else {
someModel.set(params.name, params.value); //save data in some js model
}
}
**/
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 <code>id</code> 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
loading: '<div class="editableform-loading"></div>',
/**
Initial value. If not defined - will be taken from element's content.
For __select__ 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 <code>auto|always|never</code>.
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',
/**
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
};
@ -237,14 +355,18 @@
'<div class="editable-error-block"></div>' +
'</form>';
//loading div
$.fn.editableform.loading = '<div class="editableform-loading"></div>';
//error class attahced to control-group
$.fn.editableform.errorGroupClass = null;
$.fn.editableform.errorGroupClass = null;
//error class attahced to editable-error-block
$.fn.editableform.errorBlockClass = 'editable-error';
//input types
$.fn.editableform.types = {};
$.fn.editableform.utils = {};
//input types
$.fn.editableform.types = {};
//utils
$.fn.editableform.utils = {};
}(window.jQuery));

@ -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 the page. Applied as jQuery method.
@class editable
@uses editableContainer
**/
(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 display customization.
@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) {
@ -253,6 +286,26 @@
this.hide();
this.setValue(params.newValue);
/**
Fired when new value was submitted. You can use <code>$(this).data('editable')</code> inside handler to access to editable instance
@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
$('#username').on('save', function(e, params) {
//assuming server response: '{success: true}'
var pk = $(this).data('editable').options.pk;
if(params.response && params.response.success) {
alert('value: ' + params.newValue + ' with pk: ' + pk + ' saved!');
} else {
alert('error!');
}
});
**/
},
validate: function () {
@ -261,11 +314,17 @@
}
},
setValue: function(v, convertStr) {
/**
Sets new value of editable
@method setValue(value, convertStr)
@param {mixed} value new value
@param {boolean} convertStr wether to convert value from string to internal format
**/
setValue: function(value, convertStr) {
if(convertStr) {
this.value = this.input.str2value(v);
this.value = this.input.str2value(value);
} else {
this.value = v;
this.value = value;
}
if(this.container) {
this.container.option('value', this.value);
@ -281,10 +340,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 matched editables
@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 +378,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 +399,18 @@
});
return result;
/**
This method collects values from several editable elements and submit them all to server.
It is designed mainly for <a href="#newrecord">creating new records</a>.
@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(obj) error handler (called on both client-side and server-side validation errors)
@param {function} options.success(obj) 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 +468,87 @@
$.fn.editable.defaults = {
type:'text',
/**
Type of input. Can be <code>text|textarea|select|date</code>
@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 <code>click|manual</code>.
When set to <code>manual</code> you should manually call <code>show/hide</code> methods of editable.
Note: if you are calling <code>show</code> on **click** event you need to apply <code>e.stopPropagation()</code> because container has behavior to hide on any click outside.
@example
$('#edit-button').click(function(e) {
e.stopPropagation();
$('#username').editable('toggle');
});
@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. Can be <code>auto|always|never</code>. Usefull for select and date.
For example, if dropdown list is <code>{1: 'a', 2: 'b'}</code> and element's value set to <code>1</code>, it's html will be automatically set to <code>'a'</code>.
<code>auto</code> - text will be automatically set only if element is empty.
<code>always|never</code> - 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
/**
Initial value of input
@property value
@type mixed
@default element's text
**/
value: null,
/**
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));

@ -1,16 +1,19 @@
/**
* editable abstract type definition
* Every new type must implement this interface
* It does not store value or text. It just store settings and input
*/
Abstract editable input class.
To create your own input you should inherit from this class.
@class abstract
**/
(function ($) {
var Abstract = function () { };
Abstract.prototype = {
/**
* initialize settings
*/
Iinitializes input
@method init()
**/
init: function(type, options, defaults) {
this.type = type;
this.options = $.extend({}, defaults, options);
@ -19,9 +22,10 @@
},
/**
* creates DOM element which is ready to be shown
* Can return jQuery deferred object
*/
Renders input. Can return jQuery deferred object.
@method render()
**/
render: function() {
this.$input = $(this.options.tpl);
if(this.options.inputclass) {
@ -34,51 +38,74 @@
},
/**
* set element's html by value
*/
Sets element's html by value.
@method value2html(value, element)
@param {mixed} value
@param {DOMElement} element
**/
value2html: function(value, element) {
var html = $('<div>').text(value).html();
$(element).html(html);
},
/**
* returns value from element's html
*/
Converts element's html to value
@method html2value(html)
@param {string} html
@returns {mixed}
**/
html2value: function(html) {
return $('<div>').html(html).text();
},
/**
* convert value to string for submiting on server
*/
Converts value to string (for submiting to server)
@method value2str(value)
@param {mixed} value
@returns {string}
**/
value2str: function(value) {
return value;
},
/**
* convert string received from server (data-value or options.value) into value object
*/
Converts string received from server into value.
@method str2value(str)
@param {string} str
@returns {mixed}
**/
str2value: function(str) {
return str;
},
/**
* set value to input
*/
Sets value of input.
@method value2input(value)
@param {mixed} value
**/
value2input: function(value) {
this.$input.val(value);
},
/**
* returns value (object) by input
*/
Returns value of input. Value can be object (e.g. datepicker)
@method input2value()
**/
input2value: function() {
return this.$input.val();
},
/**
* method called to focus input again
*/
Activates input. For text it sets focus.
@method activate()
**/
activate: function() {
if(this.$input.is(':visible')) {
this.$input.focus();
@ -86,11 +113,31 @@
}
};
Abstract.defaults = {
Abstract.defaults = {
/**
HTML template of input. Normally you should not change it.
@property tpl
@type string
@default ''
**/
tpl: '',
/**
CSS class automatically applied to input
@property inputclass
@type string
@default span2
**/
inputclass: 'span2',
name: null,
placeholder: false
/**
Name attribute of input
@property name
@type string
@default null
**/
name: null
};
$.extend($.fn.editableform.types, {abstract: Abstract});

@ -72,9 +72,12 @@
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
/* vitalets: required to disable css inheritance when display inline inside table */
border: none !important;
background-color: transparent !important;
}
.datepicker td.day:hover {
background: #eeeeee;
background: #eeeeee !important; /* disable inheritance for inline */
cursor: pointer;
}
.datepicker td.old,
@ -87,11 +90,60 @@
color: #999999;
cursor: default;
}
.datepicker td.today,
.datepicker td.today:hover,
.datepicker td.today.disabled,
.datepicker td.today.disabled:hover {
background-color: #fde19a !important; /* disable inheritance for inline */
background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a);
background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));
background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a);
background-image: -o-linear-gradient(top, #fdd49a, #fdf59a);
background-image: linear-gradient(top, #fdd49a, #fdf59a);
background-repeat: repeat-x;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);
border-color: #fdf59a #fdf59a #fbed50;
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
filter: progid:dximagetransform.microsoft.gradient(enabled=false);
}
.datepicker td.today:hover,
.datepicker td.today:hover:hover,
.datepicker td.today.disabled:hover,
.datepicker td.today.disabled:hover:hover,
.datepicker td.today:active,
.datepicker td.today:hover:active,
.datepicker td.today.disabled:active,
.datepicker td.today.disabled:hover:active,
.datepicker td.today.active,
.datepicker td.today:hover.active,
.datepicker td.today.disabled.active,
.datepicker td.today.disabled:hover.active,
.datepicker td.today.disabled,
.datepicker td.today:hover.disabled,
.datepicker td.today.disabled.disabled,
.datepicker td.today.disabled:hover.disabled,
.datepicker td.today[disabled],
.datepicker td.today:hover[disabled],
.datepicker td.today.disabled[disabled],
.datepicker td.today.disabled:hover[disabled] {
background-color: #fdf59a !important; /* disable inheritance for inline */
}
.datepicker td.today:active,
.datepicker td.today:hover:active,
.datepicker td.today.disabled:active,
.datepicker td.today.disabled:hover:active,
.datepicker td.today.active,
.datepicker td.today:hover.active,
.datepicker td.today.disabled.active,
.datepicker td.today.disabled:hover.active {
background-color: #fbf069 \9;
}
.datepicker td.active,
.datepicker td.active:hover,
.datepicker td.active.disabled,
.datepicker td.active.disabled:hover {
background-color: #006dcc;
background-color: #006dcc !important; /* disable inheritance for inline */
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
@ -216,10 +268,12 @@
.datepicker th.switch {
width: 145px;
}
.datepicker thead tr:first-child th {
.datepicker thead tr:first-child th,
.datepicker tfoot tr:first-child th {
cursor: pointer;
}
.datepicker thead tr:first-child th:hover {
.datepicker thead tr:first-child th:hover,
.datepicker tfoot tr:first-child th:hover {
background: #eeeeee;
}
.input-append.date .add-on i,

@ -1,14 +1,32 @@
/**
* date
* based on fork: https://github.com/vitalets/bootstrap-datepicker
*/
Bootstrap-datepicker.
Description and examples: http://vitalets.github.com/bootstrap-datepicker.
For localization you can include js file from here: https://github.com/eternicode/bootstrap-datepicker/tree/master/js/locales
@class date
@extends abstract
@example
<a href="#" id="dob" data-type="date" data-pk="1" data-url="post.php" data-original-title="Select date">15/05/1984</a>
<script>
$(function(){
$('#dob').editable({
format: 'yyyy-mm-dd',
viewformat: 'dd/mm/yyyy',
datepicker: {
weekStart: 1
}
}
});
});
</script>
**/
(function ($) {
var Date = function (options) {
this.init('date', options, Date.defaults);
//set popular options directly from settings or data-* attributes
var directOptions = $.fn.editableform.utils.sliceObj(this.options, ['format', 'weekStart', 'startView']);
var directOptions = $.fn.editableform.utils.sliceObj(this.options, ['format']);
//overriding datepicker config (as by default jQuery extend() is not recursive)
this.options.datepicker = $.extend({}, Date.defaults.datepicker, directOptions, options.datepicker);
@ -68,15 +86,50 @@
});
Date.defaults = $.extend({}, $.fn.editableform.types.abstract.defaults, {
tpl:'<div style="float: left; padding: 0; margin: 0 0 9px 0"></div>',
inputclass: 'well',
format:'yyyy-mm-dd', //format used for sending to server and converting from value
viewformat: null, //used for display date in element
//special options
weekStart: 0,
startView: 0,
/**
@property tpl
@default <div></div>
**/
tpl:'<div></div>',
/**
@property inputclass
@default editable-date well
**/
inputclass: 'editable-date well',
/**
Format used for sending value to server. Also applied when converting date from <code>data-value</code> attribute.<br>
Possible tokens are: <code>d, dd, m, mm, yy, yyyy</code>
@property format
@type string
@default yyyy-mm-dd
**/
format:'yyyy-mm-dd',
/**
Format used for displaying date. Also applied when converting date from element's text on init.
If not specified equals to <code>format</code>
@property viewformat
@type string
@default null
**/
viewformat: null,
/**
Configuration of datepicker.
Full list of options: http://vitalets.github.com/bootstrap-datepicker
@property datepicker
@type object
@default {
weekStart: 0,
startView: 0,
autoclose: false
}
**/
datepicker:{
autoclose:false
weekStart: 0,
startView: 0,
autoclose: false
}
});

@ -1,14 +1,32 @@
/**
* jQuery UI Datepicker
* Note: you can not use both date and dateui on the one page!
*/
jQuery UI Datepicker.
Description and examples: http://jqueryui.com/datepicker.
Do not use it together with bootstrap-datepicker.
@class dateui
@extends abstract
@example
<a href="#" id="dob" data-type="date" data-pk="1" data-url="post.php" data-original-title="Select date">15/05/1984</a>
<script>
$(function(){
$('#dob').editable({
format: 'yyyy-mm-dd',
viewformat: 'dd/mm/yyyy',
datepicker: {
firstDay: 1
}
}
});
});
</script>
**/
(function ($) {
var DateUI = function (options) {
this.init('dateui', options, DateUI.defaults);
//set popular options directly from settings or data-* attributes
var directOptions = $.fn.editableform.utils.sliceObj(this.options, ['format', 'firstDay']);
var directOptions = $.fn.editableform.utils.sliceObj(this.options, ['format']);
//overriding datepicker config (as by default jQuery extend() is not recursive)
this.options.datepicker = $.extend({}, DateUI.defaults.datepicker, directOptions, options.datepicker);
@ -86,14 +104,49 @@
});
DateUI.defaults = $.extend({}, $.fn.editableform.types.abstract.defaults, {
tpl:'<div style="float: left"></div>',
inputclass: '',
format:'yyyy-mm-dd', //format used for sending to server and converting from value
viewformat: null, //used for display date in element
/**
@property tpl
@default <div></div>
**/
tpl:'<div></div>',
/**
@property inputclass
@default 'editable-date'
**/
inputclass: 'editable-date',
/**
Format used for sending value to server. Also applied when converting date from <code>data-value</code> attribute.<br>
Full list of tokens: http://docs.jquery.com/UI/Datepicker/formatDate
//special options
firstDay: 0,
datepicker:{
@property format
@type string
@default yyyy-mm-dd
**/
format:'yyyy-mm-dd',
/**
Format used for displaying date. Also applied when converting date from element's text on init.
If not specified equals to <code>format</code>
@property viewformat
@type string
@default null
**/
viewformat: null,
/**
Configuration of datepicker.
Full list of options: http://api.jqueryui.com/datepicker
@property datepicker
@type object
@default {
firstDay: 0,
changeYear: true,
changeMonth: true
}
**/
datepicker: {
firstDay: 0,
changeYear: true,
changeMonth: true
}

Binary file not shown.

After

(image error) Size: 180 B

Binary file not shown.

After

(image error) Size: 182 B

Binary file not shown.

After

(image error) Size: 162 B

Binary file not shown.

After

(image error) Size: 123 B

Binary file not shown.

After

(image error) Size: 119 B

Binary file not shown.

After

(image error) Size: 3.4 KiB

Binary file not shown.

After

(image error) Size: 104 B

Binary file not shown.

After

(image error) Size: 88 B

Binary file not shown.

After

(image error) Size: 4.3 KiB

Binary file not shown.

After

(image error) Size: 4.3 KiB

Binary file not shown.

After

(image error) Size: 4.3 KiB

Binary file not shown.

After

(image error) Size: 4.3 KiB

Binary file not shown.

After

(image error) Size: 4.3 KiB

Binary file not shown.

After

(image error) Size: 4.3 KiB

Binary file not shown.

After

(image error) Size: 4.3 KiB

@ -0,0 +1,461 @@
/*! jQuery UI - v1.9.1 - 2012-11-05
* http://jqueryui.com
* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Lucida%20Grande%2CLucida%20Sans%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=5px&bgColorHeader=5c9ccc&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=55&borderColorHeader=4297d7&fcHeader=ffffff&iconColorHeader=d8e7f3&bgColorContent=fcfdfd&bgTextureContent=06_inset_hard.png&bgImgOpacityContent=100&borderColorContent=a6c9e2&fcContent=222222&iconColorContent=469bdd&bgColorDefault=dfeffc&bgTextureDefault=02_glass.png&bgImgOpacityDefault=85&borderColorDefault=c5dbec&fcDefault=2e6e9e&iconColorDefault=6da8d5&bgColorHover=d0e5f5&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=79b7e7&fcHover=1d5987&iconColorHover=217bc0&bgColorActive=f5f8f9&bgTextureActive=06_inset_hard.png&bgImgOpacityActive=100&borderColorActive=79b7e7&fcActive=e17009&iconColorActive=f9bd01&bgColorHighlight=fbec88&bgTextureHighlight=01_flat.png&bgImgOpacityHighlight=55&borderColorHighlight=fad42e&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
* Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT */
/* Layout helpers
----------------------------------*/
.ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
.ui-helper-clearfix:after { clear: both; }
.ui-helper-clearfix { zoom: 1; }
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals
----------------------------------*/
/* Overlays */
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
.ui-resizable { position: relative;}
.ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; }
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
.ui-accordion .ui-accordion-header { display: block; cursor: pointer; position: relative; margin-top: 2px; padding: .5em .5em .5em .7em; zoom: 1; }
.ui-accordion .ui-accordion-icons { padding-left: 2.2em; }
.ui-accordion .ui-accordion-noicons { padding-left: .7em; }
.ui-accordion .ui-accordion-icons .ui-accordion-icons { padding-left: 2.2em; }
.ui-accordion .ui-accordion-header .ui-accordion-header-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; overflow: auto; zoom: 1; }
.ui-autocomplete {
position: absolute;
top: 0; /* #8656 */
cursor: default;
}
/* workarounds */
* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
.ui-button, .ui-button:link, .ui-button:visited, .ui-button:hover, .ui-button:active { text-decoration: none; }
.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
.ui-button-icons-only { width: 3.4em; }
button.ui-button-icons-only { width: 3.7em; }
/*button text element */
.ui-button .ui-button-text { display: block; line-height: 1.4; }
.ui-button-text-only .ui-button-text { padding: .4em 1em; }
.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
/* no icon support for input elements, provide padding by default */
input.ui-button { padding: .4em 1em; }
/*button icon element(s) */
.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
/*button sets*/
.ui-buttonset { margin-right: 7px; }
.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
/* workarounds */
button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year { width: 49%;}
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
.ui-datepicker td { border: 0; padding: 1px; }
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi { width:auto; }
.ui-datepicker-multi .ui-datepicker-group { float:left; }
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
/* RTL support */
.ui-datepicker-rtl { direction: rtl; }
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
.ui-datepicker-cover {
position: absolute; /*must have*/
z-index: -1; /*must have*/
filter: mask(); /*must have*/
top: -4px; /*must have*/
left: -4px; /*must have*/
width: 200px; /*must have*/
height: 200px; /*must have*/
}.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
.ui-draggable .ui-dialog-titlebar { cursor: move; }
.ui-menu { list-style:none; padding: 2px; margin: 0; display:block; outline: none; }
.ui-menu .ui-menu { margin-top: -3px; position: absolute; }
.ui-menu .ui-menu-item { margin: 0; padding: 0; zoom: 1; width: 100%; }
.ui-menu .ui-menu-divider { margin: 5px -2px 5px -2px; height: 0; font-size: 0; line-height: 0; border-width: 1px 0 0 0; }
.ui-menu .ui-menu-item a { text-decoration: none; display: block; padding: 2px .4em; line-height: 1.5; zoom: 1; font-weight: normal; }
.ui-menu .ui-menu-item a.ui-state-focus,
.ui-menu .ui-menu-item a.ui-state-active { font-weight: normal; margin: -1px; }
.ui-menu .ui-state-disabled { font-weight: normal; margin: .4em 0 .2em; line-height: 1.5; }
.ui-menu .ui-state-disabled a { cursor: default; }
/* icon support */
.ui-menu-icons { position: relative; }
.ui-menu-icons .ui-menu-item a { position: relative; padding-left: 2em; }
/* left-aligned */
.ui-menu .ui-icon { position: absolute; top: .2em; left: .2em; }
/* right-aligned */
.ui-menu .ui-menu-icon { position: static; float: right; }
.ui-progressbar { height:2em; text-align: left; overflow: hidden; }
.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }.ui-slider { position: relative; text-align: left; }
.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
.ui-slider-horizontal { height: .8em; }
.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
.ui-slider-horizontal .ui-slider-range-min { left: 0; }
.ui-slider-horizontal .ui-slider-range-max { right: 0; }
.ui-slider-vertical { width: .8em; height: 100px; }
.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
.ui-slider-vertical .ui-slider-range-max { top: 0; }.ui-spinner { position:relative; display: inline-block; overflow: hidden; padding: 0; vertical-align: middle; }
.ui-spinner-input { border: none; background: none; padding: 0; margin: .2em 0; vertical-align: middle; margin-left: .4em; margin-right: 22px; }
.ui-spinner-button { width: 16px; height: 50%; font-size: .5em; padding: 0; margin: 0; text-align: center; position: absolute; cursor: default; display: block; overflow: hidden; right: 0; }
.ui-spinner a.ui-spinner-button { border-top: none; border-bottom: none; border-right: none; } /* more specificity required here to overide default borders */
.ui-spinner .ui-icon { position: absolute; margin-top: -8px; top: 50%; left: 0; } /* vertical centre icon */
.ui-spinner-up { top: 0; }
.ui-spinner-down { bottom: 0; }
/* TR overrides */
.ui-spinner .ui-icon-triangle-1-s {
/* need to fix icons sprite */
background-position:-65px -16px;
}
.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 0; margin: 1px .2em 0 0; border-bottom: 0; padding: 0; white-space: nowrap; }
.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
.ui-tabs .ui-tabs-nav li.ui-tabs-active { margin-bottom: -1px; padding-bottom: 1px; }
.ui-tabs .ui-tabs-nav li.ui-tabs-active a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-tabs-loading a { cursor: text; }
.ui-tabs .ui-tabs-nav li a, .ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
.ui-tooltip {
padding: 8px;
position: absolute;
z-index: 9999;
max-width: 300px;
-webkit-box-shadow: 0 0 5px #aaa;
box-shadow: 0 0 5px #aaa;
}
/* Fades and background-images don't work well together in IE6, drop the image */
* html .ui-tooltip {
background-image: none;
}
body .ui-tooltip { border-width: 2px; }
/* Component containers
----------------------------------*/
.ui-widget { font-family: Lucida Grande,Lucida Sans,Arial,sans-serif; font-size: 1.1em; }
.ui-widget .ui-widget { font-size: 1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Lucida Grande,Lucida Sans,Arial,sans-serif; font-size: 1em; }
.ui-widget-content { border: 1px solid #a6c9e2; background: #fcfdfd url(images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; color: #222222; }
.ui-widget-content a { color: #222222; }
.ui-widget-header { border: 1px solid #4297d7; background: #5c9ccc url(images/ui-bg_gloss-wave_55_5c9ccc_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
.ui-widget-header a { color: #ffffff; }
/* Interaction states
----------------------------------*/
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #c5dbec; background: #dfeffc url(images/ui-bg_glass_85_dfeffc_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #2e6e9e; }
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #2e6e9e; text-decoration: none; }
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #79b7e7; background: #d0e5f5 url(images/ui-bg_glass_75_d0e5f5_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1d5987; }
.ui-state-hover a, .ui-state-hover a:hover, .ui-state-hover a:link, .ui-state-hover a:visited { color: #1d5987; text-decoration: none; }
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #79b7e7; background: #f5f8f9 url(images/ui-bg_inset-hard_100_f5f8f9_1x100.png) 50% 50% repeat-x; font-weight: bold; color: #e17009; }
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #e17009; text-decoration: none; }
/* Interaction Cues
----------------------------------*/
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fad42e; background: #fbec88 url(images/ui-bg_flat_55_fbec88_40x100.png) 50% 50% repeat-x; color: #363636; }
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
.ui-state-disabled .ui-icon { filter:Alpha(Opacity=35); } /* For IE8 - See #6059 */
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-content .ui-icon {background-image: url(images/ui-icons_469bdd_256x240.png); }
.ui-widget-header .ui-icon {background-image: url(images/ui-icons_d8e7f3_256x240.png); }
.ui-state-default .ui-icon { background-image: url(images/ui-icons_6da8d5_256x240.png); }
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_217bc0_256x240.png); }
.ui-state-active .ui-icon {background-image: url(images/ui-icons_f9bd01_256x240.png); }
.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
/* positioning */
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-on { background-position: -96px -144px; }
.ui-icon-radio-off { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-start { background-position: -80px -160px; }
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
.ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* Corner radius */
.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; -khtml-border-top-left-radius: 5px; border-top-left-radius: 5px; }
.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; -khtml-border-top-right-radius: 5px; border-top-right-radius: 5px; }
.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; -khtml-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px; }
.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; -khtml-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px; }
/* Overlays */
.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .3;filter:Alpha(Opacity=30); }
.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .3;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -1,6 +1,24 @@
/**
* select
*/
Select (dropdown) input
@class select
@extends abstract
@example
<a href="#" id="status" data-type="select" data-pk="1" data-url="post.php" data-original-title="Select status"></a>
<script>
$(function(){
$('#status').editable({
value: 2,
source: [
{value: 1, text: 'Active'},
{value: 2, text: 'Blocked'},
{value: 3, text: 'Deleted'}
]
}
});
});
</script>
**/
(function ($) {
var Select = function (options) {
@ -28,13 +46,13 @@
},
html2value: function (html) {
return null; //it's not good idea to set value by text for SELECT. better set NULL
return null; //it's not good idea to set value by text for SELECT. Better set NULL
},
value2html: function (value, element) {
var deferred = $.Deferred();
this.onSourceReady(function () {
var i, text = null;
var i, text = '';
if($.isArray(this.sourceData)) {
for(i=0; i<this.sourceData.length; i++){
/*jshint eqeqeq: false*/
@ -213,12 +231,39 @@
});
Select.defaults = $.extend({}, $.fn.editableform.types.abstract.defaults, {
/**
@property tpl
@default <select></select>
**/
tpl:'<select></select>',
source:null, //can be string (url), object or array [{value: 1, text: 'abc'}, {...}]
/**
Source data for dropdown list. If string - considered ajax url to load items. Otherwise should be an array.
Array format is: <code>[{value: 1, text: "text"}, {...}]</code><br>
For compability it also supports format <code>{value1: text1, value2: text2 ...}</code> but it does not guarantee elements order.
@property source
@type string|array|object
@default null
**/
source:null,
/**
Data automatically prepended to the begining of dropdown list.
@property prepend
@type string|array|object
@default false
**/
prepend:false,
/**
Error message shown when list cannot be loaded (e.g. ajax error)
@property sourceError
@type string
@default Error when loading options
**/
sourceError: 'Error when loading options'
});
$.fn.editableform.types.select = Select;
}(window.jQuery));
}(window.jQuery));

@ -1,6 +1,19 @@
/**
* text
*/
Text input
@class text
@extends abstract
@example
<a href="#" id="username" data-type="text" data-pk="1">awesome</a>
<script>
$(function(){
$('#username').editable({
url: 'post.php',
title: 'Enter username'
});
});
</script>
**/
(function ($) {
var Text = function (options) {
this.init('text', options, Text.defaults);
@ -18,9 +31,21 @@
});
Text.defaults = $.extend({}, $.fn.editableform.types.abstract.defaults, {
tpl: '<input type="text">'
/**
@property tpl
@default <input type="text">
**/
tpl: '<input type="text">',
/**
Placeholder attribute of input. Shown when input is empty.
@property placeholder
@type string
@default null
**/
placeholder: null
});
$.fn.editableform.types.text = Text;
}(window.jQuery));
}(window.jQuery));

@ -1,6 +1,19 @@
/**
* textarea
*/
Textarea input
@class textarea
@extends abstract
@example
<a href="#" id="comments" data-type="textarea" data-pk="1">awesome comment!</a>
<script>
$(function(){
$('#comments').editable({
url: 'post.php',
title: 'Enter comments'
});
});
</script>
**/
(function ($) {
var Textarea = function (options) {
@ -53,8 +66,24 @@
});
Textarea.defaults = $.extend({}, $.fn.editableform.types.abstract.defaults, {
tpl:'<textarea rows="8"></textarea>',
inputclass:'span3'
/**
@property tpl
@default <textarea></textarea>
**/
tpl:'<textarea></textarea>',
/**
@property inputclass
@default span3
**/
inputclass:'span3',
/**
Placeholder attribute of input. Shown when input is empty.
@property placeholder
@type string
@default null
**/
placeholder: null
});
$.fn.editableform.types.textarea = Textarea;

@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test Bootstrap Editable</title>
<title>Test X-editable</title>
<!-- jquery -->
<script src="../libs/jquery/jquery-1.8.2.js"></script>

@ -54,7 +54,7 @@ function getAssets(f, c, src, libs) {
js.push(getContainer('editable-tooltip.js'));
//date
js.push(inputs+'dateui.js');
js.push(inputs+'dateui/dateui.js');
//style
css.push('style.css');
@ -67,9 +67,9 @@ function getAssets(f, c, src, libs) {
js.push(getContainer('editable-poshytip.js'));
//date
js.push(inputs+'dateui.js');
js.push(libs+'jquery-ui-datepicker/js/jquery-ui-1.9.1.custom.js');
css.unshift(jqueryui+'css/redmond/jquery-ui-1.9.1.custom.css');
js.push(inputs+'dateui/dateui.js');
js.push(inputs+'dateui/jquery-ui-datepicker/js/jquery-ui-1.9.1.custom.js');
css.unshift(inputs+'dateui/jquery-ui-datepicker/css/smoothness/jquery-ui-1.9.1.custom.css');
//style
css.push('style.css');
@ -83,9 +83,9 @@ function getAssets(f, c, src, libs) {
js.push(getContainer('editable-popover.js'));
//date
js.push(inputs+'date/bootstrap-datepicker.js');
js.push(inputs+'date/bootstrap-datepicker/js/bootstrap-datepicker.js');
js.push(inputs+'date/date.js');
css.push(inputs+'date/datepicker.css');
css.push(inputs+'date/bootstrap-datepicker/css/datepicker.css');
}
function getContainer(container) {

@ -83,6 +83,8 @@
if(!$.browser.webkit && fc.f !== 'jqueryui') {
ok(p.offset().top > e.offset().top, 'placement ok');
}
//check title
ok(p.find(':contains("'+title+'")').length, 'title ok');
e.remove();
});

@ -16,8 +16,11 @@ $(function () {
asyncTest("popover should contain datepicker with value and save new entered date", function () {
expect(9);
$.fn.editableform.types.date.defaults.datepicker.weekStart = 1;
var d = '15.05.1984',
e = $('<a href="#" data-type="date" data-pk="1" data-weekstart="1" data-url="post-date.php">'+d+'</a>').appendTo(fx).editable({
e = $('<a href="#" data-type="date" data-pk="1" data-url="post-date.php">'+d+'</a>').appendTo(fx).editable({
format: f,
datepicker: {
@ -57,9 +60,12 @@ $(function () {
});
asyncTest("viewformat, init by text", function () {
$.fn.editableform.types.date.defaults.datepicker.weekStart = 1;
var dview = '15/05/1984',
d = '1984-05-15',
e = $('<a href="#" data-type="date" data-pk="1" data-weekstart="1" data-url="post-date1.php">'+dview+'</a>').appendTo(fx).editable({
e = $('<a href="#" data-type="date" data-pk="1" data-url="post-date1.php">'+dview+'</a>').appendTo(fx).editable({
format: 'yyyy-mm-dd',
viewformat: 'dd/mm/yyyy',
datepicker: {

@ -20,7 +20,9 @@ $(function () {
e = $('<a href="#" data-type="date" data-pk="1" data-url="post-date.php">'+dview+'</a>').appendTo(fx).editable({
format: 'dd.mm.yyyy',
viewformat: 'dd/mm/yyyy',
firstDay: 1
datepicker: {
firstDay: 1
}
}),
nextD = '16.05.1984',
nextDview = '16/05/1984';

@ -9,11 +9,15 @@ $(function () {
5: 'Admin',
6: '',
'': 'Nothing'
};
};
window.size = 0;
//groups as array
window.groupsArr = [];
for(var i in groups) {
groupsArr.push({value: i, text: groups[i]});
}
for (e in groups) { size++; }
window.size = groupsArr.length;
$.mockjax({
url: 'groups.php',
@ -86,7 +90,25 @@ $(function () {
ok(!p.is(':visible'), 'popover was removed');
});
test("load options from native array", function () {
test("load options from normal array", function () {
var e = $('<a href="#" data-type="select" data-value="2" data-url="post.php">customer</a>').appendTo('#qunit-fixture').editable({
pk: 1,
source: groupsArr,
placement: 'right'
});
e.click()
var p = tip(e);
ok(p.is(':visible'), 'popover visible');
ok(p.find('select').length, 'select exists');
equal(p.find('select').find('option').length, groupsArr.length, 'options loaded');
equal(p.find('select').val(), e.data('editable').value, 'selected value correct');
p.find('button[type=button]').click();
ok(!p.is(':visible'), 'popover was removed');
});
test("load options from simple array", function () {
var arr = ['q', 'w', 'x'],
e = $('<a href="#" data-type="select" data-value="2" data-url="post.php">customer</a>').appendTo('#qunit-fixture').editable({
pk: 1,

@ -240,7 +240,33 @@ $(function () {
start();
}, timeout);
})
});
asyncTest("submit to url defined as function", function () {
expect(3);
var newText = 'qwe',
e = $('<a href="#" data-pk="1" id="a"></a>').appendTo(fx).editable({
url: function(params) {
ok(params.value, newText, 'new text passed in users function');
var d = new $.Deferred;
return d.reject('my error');
}
});
e.click();
var p = tip(e);
ok(p.find('input[type=text]').length, 'input exists')
p.find('input').val(newText);
p.find('form').submit();
setTimeout(function() {
equal(p.find('.editable-error-block').text(), 'my error', 'error shown correctly');
e.remove();
start();
}, timeout);
});
asyncTest("should show emptytext if entered text is empty", function () {
var emptytext = 'blabla',