tagedit-rails 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. data/.gitignore +17 -0
  2. data/.project +13 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +54 -0
  6. data/Rakefile +1 -0
  7. data/lib/tagedit/rails.rb +8 -0
  8. data/lib/tagedit/rails/version.rb +5 -0
  9. data/tagedit-rails.gemspec +27 -0
  10. data/vendor/assets/images/cross.png +0 -0
  11. data/vendor/assets/images/delete.png +0 -0
  12. data/vendor/assets/images/disc.png +0 -0
  13. data/vendor/assets/images/edit.png +0 -0
  14. data/vendor/assets/images/go.png +0 -0
  15. data/vendor/assets/images/tick.png +0 -0
  16. data/vendor/assets/images/undo.png +0 -0
  17. data/vendor/assets/javascripts/jquery.tagedit.extensions.js +3 -0
  18. data/vendor/assets/javascripts/tagedit.js +3 -0
  19. data/vendor/assets/javascripts/tagedit/jquery.autoGrowInput.js +63 -0
  20. data/vendor/assets/javascripts/tagedit/jquery.tagedit.js +458 -0
  21. data/vendor/assets/stylesheets/jquery.tagedit.css +47 -0
  22. data/vendor/assets/stylesheets/jquery.tagedit.extensions.css +3 -0
  23. data/vendor/assets/stylesheets/tagedit.css +5 -0
  24. data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  25. data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  26. data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_flat_10_000000_40x100.png +0 -0
  27. data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  28. data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  29. data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  30. data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  31. data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  32. data/vendor/assets/stylesheets/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  33. data/vendor/assets/stylesheets/ui-lightness/images/ui-icons_222222_256x240.png +0 -0
  34. data/vendor/assets/stylesheets/ui-lightness/images/ui-icons_228ef1_256x240.png +0 -0
  35. data/vendor/assets/stylesheets/ui-lightness/images/ui-icons_ef8c08_256x240.png +0 -0
  36. data/vendor/assets/stylesheets/ui-lightness/images/ui-icons_ffd27a_256x240.png +0 -0
  37. data/vendor/assets/stylesheets/ui-lightness/images/ui-icons_ffffff_256x240.png +0 -0
  38. data/vendor/assets/stylesheets/ui-lightness/jquery-ui-1.8.6.custom.css +347 -0
  39. metadata +164 -0
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <projectDescription>
3
+ <name>tagedit-rails</name>
4
+ <comment></comment>
5
+ <projects>
6
+ </projects>
7
+ <buildSpec>
8
+ </buildSpec>
9
+ <natures>
10
+ <nature>org.radrails.rails.core.railsnature</nature>
11
+ <nature>com.aptana.ruby.core.rubynature</nature>
12
+ </natures>
13
+ </projectDescription>
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in tagedit-rails.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Matthew
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,54 @@
1
+ # Tagedit Rails
2
+
3
+ Use [Tagedit](https://github.com/webworka/Tagedit) with Rails 3.2.6+ Asset Pipeline.
4
+
5
+ ## Installation
6
+
7
+ This gem vendors Tagedit for Rails 3.2.6 and greater. The files will be
8
+ added to the asset pipeline and available for you to use.
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'tagedit-rails'
13
+
14
+ And then execute:
15
+
16
+ $ bundle install
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install tagedit-rails
21
+
22
+ Now you need to edit your `app/assets/javascripts/application.js` file and add the following line:
23
+
24
+ ``` javascript
25
+ //= require tagedit
26
+ ```
27
+
28
+ And then edit your `app/assets/stylesheets/application.css` file and add the following line:
29
+
30
+
31
+ ``` css
32
+ /*
33
+ *= require tagedit
34
+ */
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ With the gem installed and included in your asset manifests, you can now
40
+ use tagedit as you normally would.
41
+
42
+ ## Requirements
43
+
44
+ Be aware the original Tagedit use his own jquery and jquery-ui files, in this version I changed it to gems usage.
45
+
46
+ You should have `require jquery` and `require jquery.ui.all` in your `app/assets/javascripts/application.js` before this gem.
47
+
48
+ ## Contributing
49
+
50
+ 1. Fork it
51
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
52
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
53
+ 4. Push to the branch (`git push origin my-new-feature`)
54
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,8 @@
1
+ require "tagedit/rails/version"
2
+
3
+ module Tagedit
4
+ module Rails
5
+ class Engine < ::Rails::Engine
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module Tagedit
2
+ module Rails
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'tagedit/rails/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "tagedit-rails"
8
+ spec.version = Tagedit::Rails::VERSION
9
+ spec.authors = ["Matthew Oklander"]
10
+ spec.email = ["mottiokla@gmail.com"]
11
+ spec.description = 'This gem provides Tagedit extension for your Rails 3.2.6+ application.'
12
+ spec.summary = 'Use Tagedit with Rails 3.2.6+'
13
+ spec.homepage = "http://www.o-sandbox.com"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "jquery-rails", ">= 3.0.4"
22
+ spec.add_dependency "jquery-ui-rails", ">= 4.0.4"
23
+ spec.add_dependency "rails", ">= 3.2.6"
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.3"
26
+ spec.add_development_dependency "rake"
27
+ end
@@ -0,0 +1,3 @@
1
+ /*
2
+ * If you need to extend or overwrite existing behavior this is the file to do it.
3
+ */
@@ -0,0 +1,3 @@
1
+ //= require tagedit/jquery.autoGrowInput
2
+ //= require tagedit/jquery.tagedit
3
+ //= require jquery.tagedit.extensions
@@ -0,0 +1,63 @@
1
+ (function($){
2
+
3
+ // jQuery autoGrowInput plugin by James Padolsey
4
+ // See related thread: http://stackoverflow.com/questions/931207/is-there-a-jquery-autogrow-plugin-for-text-fields
5
+
6
+ $.fn.autoGrowInput = function(o) {
7
+
8
+ o = $.extend({
9
+ maxWidth: 1000,
10
+ minWidth: 0,
11
+ comfortZone: 70
12
+ }, o);
13
+
14
+ this.filter('input:text').each(function(){
15
+
16
+ var minWidth = o.minWidth || $(this).width(),
17
+ val = '',
18
+ input = $(this),
19
+ testSubject = $('<tester/>').css({
20
+ position: 'absolute',
21
+ top: -9999,
22
+ left: -9999,
23
+ width: 'auto',
24
+ fontSize: input.css('fontSize'),
25
+ fontFamily: input.css('fontFamily'),
26
+ fontWeight: input.css('fontWeight'),
27
+ letterSpacing: input.css('letterSpacing'),
28
+ whiteSpace: 'nowrap'
29
+ }),
30
+ check = function() {
31
+
32
+ if (val === (val = input.val())) {return;}
33
+
34
+ // Enter new content into testSubject
35
+ var escaped = val.replace(/&/g, '&amp;').replace(/\s/g,'&nbsp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
36
+ testSubject.html(escaped);
37
+
38
+ // Calculate new width + whether to change
39
+ var testerWidth = testSubject.width(),
40
+ newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth,
41
+ currentWidth = input.width(),
42
+ isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth)
43
+ || (newWidth > minWidth && newWidth < o.maxWidth);
44
+
45
+ // Animate width
46
+ if (isValidWidthChange) {
47
+ input.width(newWidth);
48
+ }
49
+
50
+ };
51
+
52
+ testSubject.insertAfter(input);
53
+
54
+ $(this).bind('keyup keydown blur update', check);
55
+
56
+ check();
57
+ });
58
+
59
+ return this;
60
+
61
+ };
62
+
63
+ })(jQuery);
@@ -0,0 +1,458 @@
1
+ /*
2
+ * Tagedit - jQuery Plugin
3
+ * The Plugin can be used to edit tags from a database the easy way
4
+ *
5
+ * Examples and documentation at: tagedit.webwork-albrecht.de
6
+ *
7
+ * Copyright (c) 2010 Oliver Albrecht <info@webwork-albrecht.de>
8
+ *
9
+ * License:
10
+ * This work is licensed under a MIT License
11
+ * http://www.opensource.org/licenses/mit-license.php
12
+ *
13
+ * @author Oliver Albrecht Mial: info@webwork-albrecht.de Twitter: @webworka
14
+ * @version 1.2.1 (11/2011)
15
+ * Requires: jQuery v1.4+, jQueryUI v1.8+, jQuerry.autoGrowInput
16
+ *
17
+ * Example of usage:
18
+ *
19
+ * $( "input.tag" ).tagedit();
20
+ *
21
+ * Possible options:
22
+ *
23
+ * autocompleteURL: '', // url for a autocompletion
24
+ * deleteEmptyItems: true, // Deletes items with empty value
25
+ * deletedPostfix: '-d', // will be put to the Items that are marked as delete
26
+ * addedPostfix: '-a', // will be put to the Items that are choosem from the database
27
+ * additionalListClass: '', // put a classname here if the wrapper ul shoud receive a special class
28
+ * allowEdit: true, // Switch on/off edit entries
29
+ * allowDelete: true, // Switch on/off deletion of entries. Will be ignored if allowEdit = false
30
+ * allowAdd: true, // switch on/off the creation of new entries
31
+ * direction: 'ltr' // Sets the writing direction for Outputs and Inputs
32
+ * animSpeed: 500 // Sets the animation speed for effects
33
+ * autocompleteOptions: {}, // Setting Options for the jquery UI Autocomplete (http://jqueryui.com/demos/autocomplete/)
34
+ * breakKeyCodes: [ 13, 44 ], // Sets the characters to break on to parse the tags (defaults: return, comma)
35
+ * checkNewEntriesCaseSensitive: false, // If there is a new Entry, it is checked against the autocompletion list. This Flag controlls if the check is (in-)casesensitive
36
+ * texts: { // some texts
37
+ * removeLinkTitle: 'Remove from list.',
38
+ * saveEditLinkTitle: 'Save changes.',
39
+ * deleteLinkTitle: 'Delete this tag from database.',
40
+ * deleteConfirmation: 'Are you sure to delete this entry?',
41
+ * deletedElementTitle: 'This Element will be deleted.',
42
+ * breakEditLinkTitle: 'Cancel'
43
+ * }
44
+ */
45
+
46
+ (function($) {
47
+
48
+ $.fn.tagedit = function(options) {
49
+ /**
50
+ * Merge Options with defaults
51
+ */
52
+ options = $.extend(true, {
53
+ // default options here
54
+ autocompleteURL: null,
55
+ deletedPostfix: '-d',
56
+ addedPostfix: '-a',
57
+ additionalListClass: '',
58
+ allowEdit: true,
59
+ allowDelete: true,
60
+ allowAdd: true,
61
+ direction: 'ltr',
62
+ animSpeed: 500,
63
+ autocompleteOptions: {
64
+ select: function( event, ui ) {
65
+ $(this).val(ui.item.value).trigger('transformToTag', [ui.item.id]);
66
+ return false;
67
+ }
68
+ },
69
+ breakKeyCodes: [ 13, 44 ],
70
+ checkNewEntriesCaseSensitive: false,
71
+ texts: {
72
+ removeLinkTitle: 'Remove from list.',
73
+ saveEditLinkTitle: 'Save changes.',
74
+ deleteLinkTitle: 'Delete this tag from database.',
75
+ deleteConfirmation: 'Are you sure to delete this entry?',
76
+ deletedElementTitle: 'This Element will be deleted.',
77
+ breakEditLinkTitle: 'Cancel'
78
+ }
79
+ }, options || {});
80
+
81
+ // no action if there are no elements
82
+ if(this.length == 0) {
83
+ return;
84
+ }
85
+
86
+ // set the autocompleteOptions source
87
+ if(options.autocompleteURL) {
88
+ options.autocompleteOptions.source = options.autocompleteURL;
89
+ }
90
+
91
+ // Set the direction of the inputs
92
+ var direction= this.attr('dir');
93
+ if(direction && direction.length > 0) {
94
+ options.direction = this.attr('dir');
95
+ }
96
+
97
+ var elements = this;
98
+
99
+ var baseNameRegexp = new RegExp("^(.*)\\[([0-9]*?("+options.deletedPostfix+"|"+options.addedPostfix+")?)?\]$", "i");
100
+
101
+ var baseName = elements.eq(0).attr('name').match(baseNameRegexp);
102
+ if(baseName && baseName.length == 4) {
103
+ baseName = baseName[1];
104
+ }
105
+ else {
106
+ // Elementname does not match the expected format, exit
107
+ alert('elementname dows not match the expected format (regexp: '+baseNameRegexp+')')
108
+ return;
109
+ }
110
+
111
+ // init elements
112
+ inputsToList();
113
+
114
+ /**
115
+ * Creates the tageditinput from a list of textinputs
116
+ *
117
+ */
118
+ function inputsToList() {
119
+ var html = '<ul class="tagedit-list '+options.additionalListClass+'">';
120
+
121
+ elements.each(function() {
122
+ var element_name = $(this).attr('name').match(baseNameRegexp);
123
+ if(element_name && element_name.length == 4 && (options.deleteEmptyItems == false || $(this).val().length > 0)) {
124
+ if(element_name[1].length > 0) {
125
+ var elementId = typeof element_name[2] != 'undefined'? element_name[2]: '';
126
+
127
+ html += '<li class="tagedit-listelement tagedit-listelement-old">';
128
+ html += '<span dir="'+options.direction+'">' + $(this).val() + '</span>';
129
+ html += '<input type="hidden" name="'+baseName+'['+elementId+']" value="'+$(this).val()+'" />';
130
+ html += '<a class="tagedit-close" title="'+options.texts.removeLinkTitle+'">x</a>';
131
+ html += '</li>';
132
+ }
133
+ }
134
+ });
135
+
136
+ // replace Elements with the list and save the list in the local variable elements
137
+ elements.last().after(html)
138
+ var newList = elements.last().next();
139
+ elements.remove();
140
+ elements = newList;
141
+
142
+ // Check if some of the elementshav to be marked as deleted
143
+ if(options.deletedPostfix.length > 0) {
144
+ elements.find('input[name$="'+options.deletedPostfix+'\]"]').each(function() {
145
+ markAsDeleted($(this).parent());
146
+ });
147
+ }
148
+
149
+ // put an input field at the End
150
+ // Put an empty element at the end
151
+ html = '<li class="tagedit-listelement tagedit-listelement-new">';
152
+ html += '<input type="text" name="'+baseName+'[]" value="" id="tagedit-input" disabled="disabled" class="tagedit-input-disabled" dir="'+options.direction+'"/>';
153
+ html += '</li>';
154
+ html += '</ul>';
155
+
156
+ elements
157
+ .append(html)
158
+ // Set function on the input
159
+ .find('#tagedit-input')
160
+ .each(function() {
161
+ $(this).autoGrowInput({comfortZone: 15, minWidth: 15, maxWidth: 20000});
162
+
163
+ // Event ist triggert in case of choosing an item from the autocomplete, or finish the input
164
+ $(this).bind('transformToTag', function(event, id) {
165
+ var oldValue = (typeof id != 'undefined' && id.length > 0);
166
+
167
+ var checkAutocomplete = oldValue == true? false : true;
168
+ // check if the Value ist new
169
+ var isNewResult = isNew($(this).val(), checkAutocomplete);
170
+ if(isNewResult[0] === true || (isNewResult[0] === false && typeof isNewResult[1] == 'string')) {
171
+
172
+ if(oldValue == false && typeof isNewResult[1] == 'string') {
173
+ oldValue = true;
174
+ id = isNewResult[1];
175
+ }
176
+
177
+ if(options.allowAdd == true || oldValue) {
178
+ // Make a new tag in front the input
179
+ html = '<li class="tagedit-listelement tagedit-listelement-old">';
180
+ html += '<span dir="'+options.direction+'">' + $(this).val() + '</span>';
181
+ var name = oldValue? baseName + '['+id+options.addedPostfix+']' : baseName + '[]';
182
+ html += '<input type="hidden" name="'+name+'" value="'+$(this).val()+'" />';
183
+ html += '<a class="tagedit-close" title="'+options.texts.removeLinkTitle+'">x</a>';
184
+ html += '</li>';
185
+
186
+ $(this).parent().before(html);
187
+ }
188
+ }
189
+ $(this).val('');
190
+
191
+ // close autocomplete
192
+ if(options.autocompleteOptions.source) {
193
+ $(this).autocomplete( "close" );
194
+ }
195
+
196
+ })
197
+ .keydown(function(event) {
198
+ var code = event.keyCode > 0? event.keyCode : event.which;
199
+
200
+ switch(code) {
201
+ case 8: // BACKSPACE
202
+ if($(this).val().length == 0) {
203
+ // delete Last Tag
204
+ var elementToRemove = elements.find('li.tagedit-listelement-old').last();
205
+ elementToRemove.fadeOut(options.animSpeed, function() {elementToRemove.remove();})
206
+ event.preventDefault();
207
+ return false;
208
+ }
209
+ break;
210
+ case 9: // TAB
211
+ if($(this).val().length > 0 && $('ul.ui-autocomplete #ui-active-menuitem').length == 0) {
212
+ $(this).trigger('transformToTag');
213
+ event.preventDefault();
214
+ return false;
215
+ }
216
+ break;
217
+ }
218
+ return true;
219
+ })
220
+ .keypress(function(event) {
221
+ var code = event.keyCode > 0? event.keyCode : event.which;
222
+ if($.inArray(code, options.breakKeyCodes) > -1) {
223
+ if($(this).val().length > 0 && $('ul.ui-autocomplete #ui-active-menuitem').length == 0) {
224
+ $(this).trigger('transformToTag');
225
+ }
226
+ event.preventDefault();
227
+ return false;
228
+ }
229
+ return true;
230
+ })
231
+ .bind('paste', function(e){
232
+ var that = $(this);
233
+ if (e.type == 'paste'){
234
+ setTimeout(function(){
235
+ that.trigger('transformToTag');
236
+ }, 1);
237
+ }
238
+ })
239
+ .blur(function() {
240
+ if($(this).val().length == 0) {
241
+ // disable the field to prevent sending with the form
242
+ $(this).attr('disabled', 'disabled').addClass('tagedit-input-disabled');
243
+ }
244
+ else {
245
+ // Delete entry after a timeout
246
+ var input = $(this);
247
+ $(this).data('blurtimer', window.setTimeout(function() {input.val('');}, 500));
248
+ }
249
+ })
250
+ .focus(function() {
251
+ window.clearTimeout($(this).data('blurtimer'));
252
+ });
253
+
254
+ if(options.autocompleteOptions.source != false) {
255
+ $(this).autocomplete(options.autocompleteOptions);
256
+ }
257
+ })
258
+ .end()
259
+ .click(function(event) {
260
+ switch(event.target.tagName) {
261
+ case 'A':
262
+ $(event.target).parent().fadeOut(options.animSpeed, function() {
263
+ $(event.target).parent().remove();
264
+ });
265
+ break;
266
+ case 'INPUT':
267
+ case 'SPAN':
268
+ case 'LI':
269
+ if($(event.target).hasClass('tagedit-listelement-deleted') == false &&
270
+ $(event.target).parent('li').hasClass('tagedit-listelement-deleted') == false) {
271
+ // Don't edit an deleted Items
272
+ return doEdit(event);
273
+ }
274
+ default:
275
+ $(this).find('#tagedit-input')
276
+ .removeAttr('disabled')
277
+ .removeClass('tagedit-input-disabled')
278
+ .focus();
279
+ }
280
+ return false;
281
+ })
282
+ }
283
+
284
+ /**
285
+ * Sets all Actions and events for editing an Existing Tag.
286
+ *
287
+ * @param event {object} The original Event that was given
288
+ * return {boolean}
289
+ */
290
+ function doEdit(event) {
291
+ if(options.allowEdit == false) {
292
+ // Do nothing
293
+ return;
294
+ }
295
+
296
+ var element = event.target.tagName == 'SPAN'? $(event.target).parent() : $(event.target);
297
+
298
+ var closeTimer = null;
299
+
300
+ // Event that is fired if the User finishes the edit of a tag
301
+ element.bind('finishEdit', function(event, doReset) {
302
+ window.clearTimeout(closeTimer);
303
+
304
+ var textfield = $(this).find(':text');
305
+ var isNewResult = isNew(textfield.val(), true);
306
+ if(textfield.val().length > 0 && (typeof doReset == 'undefined' || doReset === false) && (isNewResult[0] == true)) {
307
+ // This is a new Value and we do not want to do a reset. Set the new value
308
+ $(this).find(':hidden').val(textfield.val());
309
+ $(this).find('span').html(textfield.val());
310
+ }
311
+
312
+ textfield.remove();
313
+ $(this).find('a.tagedit-save, a.tagedit-break, a.tagedit-delete, tester').remove(); // Workaround. This normaly has to be done by autogrow Plugin
314
+ $(this).removeClass('tagedit-listelement-edit').unbind('finishEdit');
315
+ return false;
316
+ });
317
+
318
+ var hidden = element.find(':hidden');
319
+ html = '<input type="text" name="tmpinput" autocomplete="off" value="'+hidden.val()+'" class="tagedit-edit-input" dir="'+options.direction+'"/>';
320
+ html += '<a class="tagedit-save" title="'+options.texts.saveEditLinkTitle+'">o</a>';
321
+ html += '<a class="tagedit-break" title="'+options.texts.breakEditLinkTitle+'">x</a>';
322
+
323
+ // If the Element is one from the Database, it can be deleted
324
+ if(options.allowDelete == true && element.find(':hidden').length > 0 &&
325
+ typeof element.find(':hidden').attr('name').match(baseNameRegexp)[3] != 'undefined') {
326
+ html += '<a class="tagedit-delete" title="'+options.texts.deleteLinkTitle+'">d</a>';
327
+ }
328
+
329
+ hidden.after(html);
330
+ element
331
+ .addClass('tagedit-listelement-edit')
332
+ .find('a.tagedit-save')
333
+ .click(function() {
334
+ $(this).parent().trigger('finishEdit');
335
+ return false;
336
+ })
337
+ .end()
338
+ .find('a.tagedit-break')
339
+ .click(function() {
340
+ $(this).parent().trigger('finishEdit', [true]);
341
+ return false;
342
+ })
343
+ .end()
344
+ .find('a.tagedit-delete')
345
+ .click(function() {
346
+ window.clearTimeout(closeTimer);
347
+ if(confirm(options.texts.deleteConfirmation)) {
348
+ markAsDeleted($(this).parent());
349
+ }
350
+ else {
351
+ $(this).parent().find(':text').trigger('finishEdit', [true]);
352
+ }
353
+ return false;
354
+ })
355
+ .end()
356
+ .find(':text')
357
+ .focus()
358
+ .autoGrowInput({comfortZone: 10, minWidth: 15, maxWidth: 20000})
359
+ .keypress(function(event) {
360
+ switch(event.keyCode) {
361
+ case 13: // RETURN
362
+ event.preventDefault();
363
+ $(this).parent().trigger('finishEdit');
364
+ return false;
365
+ case 27: // ESC
366
+ event.preventDefault();
367
+ $(this).parent().trigger('finishEdit', [true]);
368
+ return false;
369
+ }
370
+ return true;
371
+ })
372
+ .blur(function() {
373
+ var that = $(this);
374
+ closeTimer = window.setTimeout(function() {that.parent().trigger('finishEdit', [true])}, 500);
375
+ });
376
+ }
377
+
378
+ /**
379
+ * Marks a single Tag as deleted.
380
+ *
381
+ * @param element {object}
382
+ */
383
+ function markAsDeleted(element) {
384
+ element
385
+ .trigger('finishEdit', [true])
386
+ .addClass('tagedit-listelement-deleted')
387
+ .attr('title', options.deletedElementTitle);
388
+ element.find(':hidden').each(function() {
389
+ var nameEndRegexp = new RegExp('('+options.addedPostfix+'|'+options.deletedPostfix+')?\]');
390
+ var name = $(this).attr('name').replace(nameEndRegexp, options.deletedPostfix+']');
391
+ $(this).attr('name', name);
392
+ });
393
+
394
+ }
395
+
396
+ /**
397
+ * Checks if a tag is already choosen.
398
+ *
399
+ * @param value {string}
400
+ * @param checkAutocomplete {boolean} optional Check also the autocomplet values
401
+ * @returns {Array} First item is a boolean, telling if the item should be put to the list, second is optional the ID from autocomplete list
402
+ */
403
+ function isNew(value, checkAutocomplete) {
404
+ checkAutocomplete = typeof checkAutocomplete == 'undefined'? false : checkAutocomplete;
405
+ var autoCompleteId = null;
406
+
407
+ var compareValue = options.checkNewEntriesCaseSensitive == true? value : value.toLowerCase();
408
+
409
+ var isNew = true;
410
+ elements.find('li.tagedit-listelement-old input:hidden').each(function() {
411
+ var elementValue = options.checkNewEntriesCaseSensitive == true? $(this).val() : $(this).val().toLowerCase();
412
+ if(elementValue == compareValue) {
413
+ isNew = false;
414
+ }
415
+ });
416
+
417
+ if (isNew == true && checkAutocomplete == true && options.autocompleteOptions.source != false) {
418
+ var result = [];
419
+ if ($.isArray(options.autocompleteOptions.source)) {
420
+ result = options.autocompleteOptions.source;
421
+ }
422
+ else if ($.isFunction(options.autocompleteOptions.source)) {
423
+ options.autocompleteOptions.source({term: value}, function (data) {result = data});
424
+ }
425
+ else if (typeof options.autocompleteOptions.source === "string") {
426
+ // Check also autocomplete values
427
+ var autocompleteURL = options.autocompleteOptions.source;
428
+ if (autocompleteURL.match(/\?/)) {
429
+ autocompleteURL += '&';
430
+ } else {
431
+ autocompleteURL += '?';
432
+ }
433
+ autocompleteURL += 'term=' + value;
434
+ $.ajax({
435
+ async: false,
436
+ url: autocompleteURL,
437
+ dataType: 'json',
438
+ complete: function (XMLHttpRequest, textStatus) {
439
+ result = $.parseJSON(XMLHttpRequest.responseText);
440
+ }
441
+ });
442
+ }
443
+
444
+ // If there is an entry for that already in the autocomplete, don't use it (Check could be case sensitive or not)
445
+ for (var i = 0; i < result.length; i++) {
446
+ var label = options.checkNewEntriesCaseSensitive == true? result[i].label : result[i].label.toLowerCase();
447
+ if (label == compareValue) {
448
+ isNew = false;
449
+ autoCompleteId = result[i].id;
450
+ break;
451
+ }
452
+ }
453
+ }
454
+
455
+ return new Array(isNew, autoCompleteId);
456
+ }
457
+ }
458
+ })(jQuery);