Commit 65ff2c7a427bdc4417ac2cdab7f7c27a39890e99

Authored by Michel Felipe
Committed by Leandro Santos
1 parent 60716a4f

Each tags is defined in a task, store it in database. Added to the logged user l…

…ike a tagger of tasks. jQuery plugin 'inputosaurus.js' was customize and a pull request was made in your github repo
app/controllers/my_profile/tasks_controller.rb
... ... @@ -41,33 +41,18 @@ class TasksController < MyProfileController
41 41  
42 42 def close
43 43 failed = {}
44   - save = false
45 44  
46 45 if params[:tasks]
47 46 params[:tasks].each do |id, value|
48 47 decision = value[:decision]
49   -
50   - if value[:task].is_a?(Hash) && value[:task][:tag_list]
51   -
  48 + if request.post? && VALID_DECISIONS.include?(decision) && id && decision != 'skip'
52 49 task = profile.find_in_all_tasks(id)
53   - task.tag_list = value[:task][:tag_list]
54   - value[:task].delete('tag_list')
55   -
56   - save = true
57   - end
58   -
59   - if request.post?
60   - if VALID_DECISIONS.include?(decision) && id && decision != 'skip'
61   - task ||= profile.find_in_all_tasks(id)
62   - begin
63   - task.update_attributes(value[:task])
64   - task.send(decision)
65   - rescue Exception => ex
66   - message = "#{task.title} (#{task.requestor ? task.requestor.name : task.author_name})"
67   - failed[ex.message] ? failed[ex.message] << message : failed[ex.message] = [message]
68   - end
69   - elsif save
70   - task.save!
  50 + begin
  51 + task.update_attributes(value[:task])
  52 + task.send(decision)
  53 + rescue Exception => ex
  54 + message = "#{task.title} (#{task.requestor ? task.requestor.name : task.author_name})"
  55 + failed[ex.message] ? failed[ex.message] << message : failed[ex.message] = [message]
71 56 end
72 57 end
73 58 end
... ... @@ -104,4 +89,24 @@ class TasksController &lt; MyProfileController
104 89 @ticket = Ticket.find(:first, :conditions => ['(requestor_id = ? or target_id = ?) and id = ?', profile.id, profile.id, params[:id]])
105 90 end
106 91  
  92 + def save_tags
  93 +
  94 + if request.post? && params[:tag_list]
  95 + result = {
  96 + success: false
  97 + }
  98 +
  99 + ActsAsTaggableOn.remove_unused_tags = true
  100 +
  101 + task = Task.find_by_id params[:task_id]
  102 + save = user.tag(task, with: params[:tag_list], on: :tags)
  103 +
  104 + if save
  105 + result[:success] = true
  106 + end
  107 + end
  108 +
  109 + render json: result
  110 + end
  111 +
107 112 end
... ...
app/models/person.rb
... ... @@ -16,6 +16,8 @@ class Person &lt; Profile
16 16 acts_as_trackable :after_add => Proc.new {|p,t| notify_activity(t)}
17 17 acts_as_accessor
18 18  
  19 + acts_as_tagger
  20 +
19 21 scope :members_of, lambda { |resources|
20 22 resources = [resources] if !resources.kind_of?(Array)
21 23 conditions = resources.map {|resource| "role_assignments.resource_type = '#{resource.class.base_class.name}' AND role_assignments.resource_id = #{resource.id || -1}"}.join(' OR ')
... ...
app/views/tasks/_task.html.erb
... ... @@ -64,7 +64,7 @@
64 64  
65 65 <div class="formfieldline">
66 66 <div class="formfield tag-list-fields">
67   - <%= labelled_text_field(_('Tags'),"tasks[#{task.id}][task][tag_list]", task.tag_list.to_s, :size => 36, :class => 'tag-list') %>
  67 + <%= labelled_text_field(_('Tags'),"tasks[#{task.id}][task][tag_list]", task.tags_from(nil).to_s, :size => 36, :class => 'tag-list','data-submit-values'=>"{'task_id':'#{task.id}'}") %>
68 68 </div>
69 69 </div>
70 70  
... ...
app/views/tasks/index.html.erb
... ... @@ -75,7 +75,13 @@
75 75 <script>
76 76 jQuery('.tag-list').inputosaurus({
77 77 autoCompleteSource: <%= "'/myprofile/#{profile.identifier}/cms/search_tags'," %>
78   - activateFinalResult : true
  78 + activateFinalResult: true,
  79 + submitTags: {
  80 + url: <%= "'/myprofile/#{profile.identifier}/tasks/save_tags'" %>,
  81 + success: function(response){
  82 + console.dir(response);
  83 + }
  84 + }
79 85 })
80 86 </script>
81 87  
... ...
public/javascripts/inputosaurus.js
1 1 /**
2   - * Inputosaurus Text
  2 + * Inputosaurus Text
3 3 *
4 4 * Must be instantiated on an <input> element
5 5 * Allows multiple input items. Each item is represented with a removable tag that appears to be inside the input area.
... ... @@ -30,7 +30,7 @@
30 30 //
31 31 // 'change' - triggered whenever a tag is added or removed (should be similar to binding the the change event of the instantiated input
32 32 // 'keyup' - keyup event on the newly created input
33   -
  33 +
34 34 // while typing, the user can separate values using these delimiters
35 35 // the value tags are created on the fly when an inputDelimiter is detected
36 36 inputDelimiters : [',', ';'],
... ... @@ -56,12 +56,15 @@
56 56 // manipulate and return the input value after parseInput() parsing
57 57 // the array of tag names is passed and expected to be returned as an array after manipulation
58 58 parseHook : null,
59   -
  59 +
60 60 // define a placeholder to display when the input is empty
61 61 placeholder: null,
62   -
  62 +
63 63 // when you check for duplicates it check for the case
64   - caseSensitiveDuplicates: false
  64 + caseSensitiveDuplicates: false,
  65 +
  66 + //Ajax options to send tags
  67 + submitTags: null
65 68 },
66 69  
67 70 _create: function() {
... ... @@ -69,7 +72,7 @@
69 72 els = {},
70 73 o = widget.options,
71 74 placeholder = o.placeholder || this.element.attr('placeholder') || null;
72   -
  75 +
73 76 this._chosenValues = [];
74 77  
75 78 // Create the elements
... ... @@ -77,11 +80,11 @@
77 80 els.input = $('<input type="text" />');
78 81 els.inputCont = $('<li class="inputosaurus-input inputosaurus-required"></li>');
79 82 els.origInputCont = $('<li class="inputosaurus-input-hidden inputosaurus-required">');
80   -
  83 +
81 84 // define starting placeholder
82   - if (placeholder) {
  85 + if (placeholder) {
83 86 o.placeholder = placeholder;
84   - els.input.attr('placeholder', o.placeholder);
  87 + els.input.attr('placeholder', o.placeholder);
85 88 if (o.width) {
86 89 els.input.css('min-width', o.width - 50);
87 90 }
... ... @@ -90,11 +93,11 @@
90 93 o.wrapperElement && o.wrapperElement.append(els.ul);
91 94 this.element.replaceWith(o.wrapperElement || els.ul);
92 95 els.origInputCont.append(this.element).hide();
93   -
  96 +
94 97 els.inputCont.append(els.input);
95 98 els.ul.append(els.inputCont);
96 99 els.ul.append(els.origInputCont);
97   -
  100 +
98 101 o.width && els.ul.css('width', o.width);
99 102  
100 103 this.elements = els;
... ... @@ -130,8 +133,8 @@
130 133 var auto = $(this).data('ui-autocomplete') || $(this).data('autocomplete');
131 134 var menu = auto.menu,
132 135 $menuItems;
133   -
134   -
  136 +
  137 +
135 138 // zIndex will force the element on top of anything (like a dialog it's in)
136 139 menu.element.zIndex && menu.element.zIndex($(this).zIndex() + 1);
137 140 menu.element.width(widget.elements.ul.outerWidth());
... ... @@ -241,7 +244,7 @@
241 244  
242 245 widget.elements.input.width(txtWidth < maxWidth ? txtWidth : maxWidth);
243 246 },
244   -
  247 +
245 248 // resets placeholder on representative input
246 249 _resetPlaceholder: function () {
247 250 var placeholder = this.options.placeholder,
... ... @@ -266,7 +269,7 @@
266 269 ev.preventDefault();
267 270 lastTag.find('a').focus();
268 271 }
269   -
  272 +
270 273 },
271 274  
272 275 _editTag : function(ev) {
... ... @@ -285,6 +288,7 @@
285 288 v.key === tagKey && (tagName = v.value);
286 289 });
287 290  
  291 + widget.beforeEditValue = widget.element.val();
288 292 widget.elements.input.val(tagName);
289 293  
290 294 widget._removeTag(ev);
... ... @@ -295,7 +299,7 @@
295 299 var widget = ev.data.widget;
296 300 switch(ev.which){
297 301  
298   - case $.ui.keyCode.BACKSPACE:
  302 + case $.ui.keyCode.BACKSPACE:
299 303 ev && ev.preventDefault();
300 304 ev && ev.stopPropagation();
301 305 $(ev.currentTarget).trigger('click');
... ... @@ -409,11 +413,18 @@
409 413 },
410 414  
411 415 _setValue : function(value) {
412   - var val = this.element.val();
  416 +
  417 + if(arguments[1] && (arguments[1].type == 'dblclick' && value == '')){
  418 + return false;
  419 + }
  420 + var val = this.element.val().replace(/,\s*/g,',');
413 421  
414 422 if(val !== value){
415 423 this.element.val(value);
416 424 this._trigger('change');
  425 + if($.isPlainObject(this.options.submitTags)){
  426 + this._sendTags();
  427 + }
417 428 }
418 429 },
419 430  
... ... @@ -439,7 +450,7 @@
439 450 },
440 451  
441 452 _removeTag : function(ev) {
442   - var $closest = $(ev.currentTarget).closest('li'),
  453 + var $closest = $(ev.currentTarget).closest('li'),
443 454 key = $closest.data('ui-inputosaurus') || $closest.data('inputosaurus'),
444 455 indexFound = false,
445 456 widget = (ev && ev.data.widget) || this;
... ... @@ -453,7 +464,7 @@
453 464  
454 465 indexFound !== false && widget._chosenValues.splice(indexFound, 1);
455 466  
456   - widget._setValue(widget._buildValue());
  467 + widget._setValue(widget._buildValue(),ev);
457 468  
458 469 $(ev.currentTarget).closest('li').remove();
459 470 widget.elements.input.focus();
... ... @@ -477,7 +488,7 @@
477 488 var delim = this.options.outputDelimiter,
478 489 val = this.element.val(),
479 490 values = [];
480   -
  491 +
481 492 values.push(val);
482 493 delim && (values = val.split(delim));
483 494  
... ... @@ -515,9 +526,37 @@
515 526  
516 527 this.elements.ul.replaceWith(this.element);
517 528  
  529 + },
  530 +
  531 + _sendTags: function(){
  532 +
  533 + var requestTags = this.options.submitTags;
  534 + if(this.element.val() != '' && this.beforeEditValue != this.element.val()) {
  535 +
  536 + opts = $.extend({
  537 + url: requestTags.url,
  538 + dataType: 'json',
  539 + data:{},
  540 + type:'POST'
  541 + },requestTags);
  542 +
  543 + var extraValues = this.element.data('submit-values');
  544 + if(typeof extraValues == 'string' && /\{*/.test(extraValues)){
  545 + extraValues = $.parseJSON(extraValues.replace(/\'/g,'\"'));
  546 + }
  547 +
  548 + if(!$.isEmptyObject(extraValues)){
  549 + for(v in extraValues){
  550 + opts.data[v] = extraValues[v];
  551 + }
  552 + }
  553 +
  554 + opts.data.tag_list = this.element.val();
  555 +
  556 + $.ajax(opts);
  557 + }
518 558 }
519 559 };
520 560  
521 561 $.widget("ui.inputosaurus", inputosaurustext);
522   -})(jQuery);
523   -
  562 +})($ || jQuery);
... ...