Commit 6977150f04be1bfe365e1cd86e3f8143c34a51bf
1 parent
5d526717
Exists in
master
and in
4 other branches
integrate tags plugins
Showing
6 changed files
with
212 additions
and
0 deletions
Show diff stats
Gemfile
Gemfile.lock
| ... | ... | @@ -54,6 +54,8 @@ GEM |
| 54 | 54 | activesupport (= 3.1.0) |
| 55 | 55 | activesupport (3.1.0) |
| 56 | 56 | multi_json (~> 1.0) |
| 57 | + acts-as-taggable-on (2.1.1) | |
| 58 | + rails | |
| 57 | 59 | acts_as_list (0.1.4) |
| 58 | 60 | addressable (2.2.6) |
| 59 | 61 | ansi (1.3.0) |
| ... | ... | @@ -246,6 +248,7 @@ PLATFORMS |
| 246 | 248 | ruby |
| 247 | 249 | |
| 248 | 250 | DEPENDENCIES |
| 251 | + acts-as-taggable-on (~> 2.1.0) | |
| 249 | 252 | acts_as_list |
| 250 | 253 | annotate! |
| 251 | 254 | autotest | ... | ... |
app/models/project.rb
db/migrate/20111101222453_acts_as_taggable_on_migration.rb
0 → 100644
| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | +class ActsAsTaggableOnMigration < ActiveRecord::Migration | |
| 2 | + def self.up | |
| 3 | + create_table :tags do |t| | |
| 4 | + t.string :name | |
| 5 | + end | |
| 6 | + | |
| 7 | + create_table :taggings do |t| | |
| 8 | + t.references :tag | |
| 9 | + | |
| 10 | + # You should make sure that the column created is | |
| 11 | + # long enough to store the required class names. | |
| 12 | + t.references :taggable, :polymorphic => true | |
| 13 | + t.references :tagger, :polymorphic => true | |
| 14 | + | |
| 15 | + t.string :context | |
| 16 | + | |
| 17 | + t.datetime :created_at | |
| 18 | + end | |
| 19 | + | |
| 20 | + add_index :taggings, :tag_id | |
| 21 | + add_index :taggings, [:taggable_id, :taggable_type, :context] | |
| 22 | + end | |
| 23 | + | |
| 24 | + def self.down | |
| 25 | + drop_table :taggings | |
| 26 | + drop_table :tags | |
| 27 | + end | |
| 28 | +end | ... | ... |
| ... | ... | @@ -0,0 +1,143 @@ |
| 1 | +/* Author: Alicia Liu */ | |
| 2 | + | |
| 3 | +(function ($) { | |
| 4 | + | |
| 5 | + $.widget("ui.tagify", { | |
| 6 | + options: { | |
| 7 | + delimiters: [13, 188], // what user can type to complete a tag in char codes: [enter], [comma] | |
| 8 | + outputDelimiter: ',', // delimiter for tags in original input field | |
| 9 | + cssClass: 'tagify-container', // CSS class to style the tagify div and tags, see stylesheet | |
| 10 | + addTagPrompt: 'add tags' // placeholder text | |
| 11 | + }, | |
| 12 | + | |
| 13 | + _create: function() { | |
| 14 | + var self = this, | |
| 15 | + el = self.element, | |
| 16 | + opts = self.options; | |
| 17 | + | |
| 18 | + this.tags = []; | |
| 19 | + | |
| 20 | + // hide text field and replace with a div that contains it's own input field for entering tags | |
| 21 | + this.tagInput = $("<input type='text'>") | |
| 22 | + .attr( 'placeholder', opts.addTagPrompt ) | |
| 23 | + .keypress( function(e) { | |
| 24 | + var $this = $(this), | |
| 25 | + pressed = e.which; | |
| 26 | + | |
| 27 | + for ( i in opts.delimiters ) { | |
| 28 | + | |
| 29 | + if (pressed == opts.delimiters[i]) { | |
| 30 | + self.add( $this.val() ); | |
| 31 | + e.preventDefault(); | |
| 32 | + return false; | |
| 33 | + } | |
| 34 | + } | |
| 35 | + }) | |
| 36 | + // for some reason, in Safari, backspace is only recognized on keyup | |
| 37 | + .keyup( function(e) { | |
| 38 | + var $this = $(this), | |
| 39 | + pressed = e.which; | |
| 40 | + | |
| 41 | + // if backspace is hit with no input, remove the last tag | |
| 42 | + if (pressed == 8) { // backspace | |
| 43 | + if ( $this.val() == "" ) { | |
| 44 | + self.remove(); | |
| 45 | + return false; | |
| 46 | + } | |
| 47 | + return; | |
| 48 | + } | |
| 49 | + }); | |
| 50 | + | |
| 51 | + this.tagDiv = $("<div></div>") | |
| 52 | + .addClass( opts.cssClass ) | |
| 53 | + .click( function() { | |
| 54 | + $(this).children('input').focus(); | |
| 55 | + }) | |
| 56 | + .append( this.tagInput ) | |
| 57 | + .insertAfter( el.hide() ); | |
| 58 | + | |
| 59 | + // if the field isn't empty, parse the field for tags, and prepopulate existing tags | |
| 60 | + var initVal = $.trim( el.val() ); | |
| 61 | + | |
| 62 | + if ( initVal ) { | |
| 63 | + var initTags = initVal.split( opts.outputDelimiter ); | |
| 64 | + $.each( initTags, function(i, tag) { | |
| 65 | + self.add( tag ); | |
| 66 | + }); | |
| 67 | + } | |
| 68 | + }, | |
| 69 | + | |
| 70 | + _setOption: function( key, value ) { | |
| 71 | + options.key = value; | |
| 72 | + }, | |
| 73 | + | |
| 74 | + // add a tag, public function | |
| 75 | + add: function(text) { | |
| 76 | + var self = this; | |
| 77 | + text = text || self.tagInput.val(); | |
| 78 | + if (text) { | |
| 79 | + var tagIndex = self.tags.length; | |
| 80 | + | |
| 81 | + var removeButton = $("<a href='#'>x</a>") | |
| 82 | + .click( function() { | |
| 83 | + self.remove( tagIndex ); | |
| 84 | + return false; | |
| 85 | + }); | |
| 86 | + var newTag = $("<span></span>") | |
| 87 | + .text( text ) | |
| 88 | + .append( removeButton ); | |
| 89 | + | |
| 90 | + self.tagInput.before( newTag ); | |
| 91 | + self.tags.push( text ); | |
| 92 | + self.tagInput.val(''); | |
| 93 | + } | |
| 94 | + }, | |
| 95 | + | |
| 96 | + // remove a tag by index, public function | |
| 97 | + // if index is blank, remove the last tag | |
| 98 | + remove: function( tagIndex ) { | |
| 99 | + var self = this; | |
| 100 | + if ( tagIndex == null || tagIndex === (self.tags.length - 1) ) { | |
| 101 | + this.tagDiv.children("span").last().remove(); | |
| 102 | + self.tags.pop(); | |
| 103 | + } | |
| 104 | + if ( typeof(tagIndex) == 'number' ) { | |
| 105 | + // otherwise just hide this tag, and we don't mess up the index | |
| 106 | + this.tagDiv.children( "span:eq(" + tagIndex + ")" ).hide(); | |
| 107 | + // we rely on the serialize function to remove null values | |
| 108 | + delete( self.tags[tagIndex] ); | |
| 109 | + } | |
| 110 | + }, | |
| 111 | + | |
| 112 | + // serialize the tags with the given delimiter, and write it back into the tagified field | |
| 113 | + serialize: function() { | |
| 114 | + var self = this; | |
| 115 | + var delim = self.options.outputDelimiter; | |
| 116 | + var tagsStr = self.tags.join( delim ); | |
| 117 | + | |
| 118 | + // our tags might have deleted entries, remove them here | |
| 119 | + var dupes = new RegExp(delim + delim + '+', 'g'); // regex: /,,+/g | |
| 120 | + var ends = new RegExp('^' + delim + '|' + delim + '$', 'g'); // regex: /^,|,$/g | |
| 121 | + var outputStr = tagsStr.replace( dupes, delim ).replace(ends, ''); | |
| 122 | + | |
| 123 | + self.element.val(outputStr); | |
| 124 | + return outputStr; | |
| 125 | + }, | |
| 126 | + | |
| 127 | + inputField: function() { | |
| 128 | + return this.tagInput; | |
| 129 | + }, | |
| 130 | + | |
| 131 | + containerDiv: function() { | |
| 132 | + return this.tagDiv; | |
| 133 | + }, | |
| 134 | + | |
| 135 | + // remove the div, and show original input | |
| 136 | + destroy: function() { | |
| 137 | + $.Widget.prototype.destroy.apply(this); | |
| 138 | + this.tagDiv.remove(); | |
| 139 | + this.element.show(); | |
| 140 | + } | |
| 141 | + }); | |
| 142 | + | |
| 143 | +})(jQuery); | |
| 0 | 144 | \ No newline at end of file | ... | ... |
| ... | ... | @@ -0,0 +1,34 @@ |
| 1 | +/* Tagify styles | |
| 2 | +Author: Alicia Liu test | |
| 3 | +*/ | |
| 4 | + | |
| 5 | +.tagify-container { | |
| 6 | +} | |
| 7 | + | |
| 8 | +.tagify-container > span { | |
| 9 | + display: inline-block; | |
| 10 | + padding: 8px 11px 8px 11px; | |
| 11 | + margin: 1px 5px 0px 0px; | |
| 12 | + border-radius: 4px; | |
| 13 | + border: 1px solid #d0e1ff; | |
| 14 | + background-color: #d0e1ff; | |
| 15 | + color: #0f326d; | |
| 16 | + font-weight: bold; | |
| 17 | + font-size: 14px; | |
| 18 | +} | |
| 19 | + | |
| 20 | +.tagify-container > span > a { | |
| 21 | + padding-left: 5px !important; | |
| 22 | + color: #83a5e1; | |
| 23 | + text-decoration: none; | |
| 24 | + font-weight: bold; | |
| 25 | +} | |
| 26 | + | |
| 27 | +.tagify-container > input { | |
| 28 | + border: 0 none; | |
| 29 | + width: 100px !important; | |
| 30 | +} | |
| 31 | + | |
| 32 | +.tagify-container > input:focus { | |
| 33 | + outline: none; | |
| 34 | +} | |
| 0 | 35 | \ No newline at end of file | ... | ... |