-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
212 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
db/migrate/20111101222453_acts_as_taggable_on_migration.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
class ActsAsTaggableOnMigration < ActiveRecord::Migration | ||
def self.up | ||
create_table :tags do |t| | ||
t.string :name | ||
end | ||
|
||
create_table :taggings do |t| | ||
t.references :tag | ||
|
||
# You should make sure that the column created is | ||
# long enough to store the required class names. | ||
t.references :taggable, :polymorphic => true | ||
t.references :tagger, :polymorphic => true | ||
|
||
t.string :context | ||
|
||
t.datetime :created_at | ||
end | ||
|
||
add_index :taggings, :tag_id | ||
add_index :taggings, [:taggable_id, :taggable_type, :context] | ||
end | ||
|
||
def self.down | ||
drop_table :taggings | ||
drop_table :tags | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
/* Author: Alicia Liu */ | ||
|
||
(function ($) { | ||
|
||
$.widget("ui.tagify", { | ||
options: { | ||
delimiters: [13, 188], // what user can type to complete a tag in char codes: [enter], [comma] | ||
outputDelimiter: ',', // delimiter for tags in original input field | ||
cssClass: 'tagify-container', // CSS class to style the tagify div and tags, see stylesheet | ||
addTagPrompt: 'add tags' // placeholder text | ||
}, | ||
|
||
_create: function() { | ||
var self = this, | ||
el = self.element, | ||
opts = self.options; | ||
|
||
this.tags = []; | ||
|
||
// hide text field and replace with a div that contains it's own input field for entering tags | ||
this.tagInput = $("<input type='text'>") | ||
.attr( 'placeholder', opts.addTagPrompt ) | ||
.keypress( function(e) { | ||
var $this = $(this), | ||
pressed = e.which; | ||
|
||
for ( i in opts.delimiters ) { | ||
|
||
if (pressed == opts.delimiters[i]) { | ||
self.add( $this.val() ); | ||
e.preventDefault(); | ||
return false; | ||
} | ||
} | ||
}) | ||
// for some reason, in Safari, backspace is only recognized on keyup | ||
.keyup( function(e) { | ||
var $this = $(this), | ||
pressed = e.which; | ||
|
||
// if backspace is hit with no input, remove the last tag | ||
if (pressed == 8) { // backspace | ||
if ( $this.val() == "" ) { | ||
self.remove(); | ||
return false; | ||
} | ||
return; | ||
} | ||
}); | ||
|
||
this.tagDiv = $("<div></div>") | ||
.addClass( opts.cssClass ) | ||
.click( function() { | ||
$(this).children('input').focus(); | ||
}) | ||
.append( this.tagInput ) | ||
.insertAfter( el.hide() ); | ||
|
||
// if the field isn't empty, parse the field for tags, and prepopulate existing tags | ||
var initVal = $.trim( el.val() ); | ||
|
||
if ( initVal ) { | ||
var initTags = initVal.split( opts.outputDelimiter ); | ||
$.each( initTags, function(i, tag) { | ||
self.add( tag ); | ||
}); | ||
} | ||
}, | ||
|
||
_setOption: function( key, value ) { | ||
options.key = value; | ||
}, | ||
|
||
// add a tag, public function | ||
add: function(text) { | ||
var self = this; | ||
text = text || self.tagInput.val(); | ||
if (text) { | ||
var tagIndex = self.tags.length; | ||
|
||
var removeButton = $("<a href='#'>x</a>") | ||
.click( function() { | ||
self.remove( tagIndex ); | ||
return false; | ||
}); | ||
var newTag = $("<span></span>") | ||
.text( text ) | ||
.append( removeButton ); | ||
|
||
self.tagInput.before( newTag ); | ||
self.tags.push( text ); | ||
self.tagInput.val(''); | ||
} | ||
}, | ||
|
||
// remove a tag by index, public function | ||
// if index is blank, remove the last tag | ||
remove: function( tagIndex ) { | ||
var self = this; | ||
if ( tagIndex == null || tagIndex === (self.tags.length - 1) ) { | ||
this.tagDiv.children("span").last().remove(); | ||
self.tags.pop(); | ||
} | ||
if ( typeof(tagIndex) == 'number' ) { | ||
// otherwise just hide this tag, and we don't mess up the index | ||
this.tagDiv.children( "span:eq(" + tagIndex + ")" ).hide(); | ||
// we rely on the serialize function to remove null values | ||
delete( self.tags[tagIndex] ); | ||
} | ||
}, | ||
|
||
// serialize the tags with the given delimiter, and write it back into the tagified field | ||
serialize: function() { | ||
var self = this; | ||
var delim = self.options.outputDelimiter; | ||
var tagsStr = self.tags.join( delim ); | ||
|
||
// our tags might have deleted entries, remove them here | ||
var dupes = new RegExp(delim + delim + '+', 'g'); // regex: /,,+/g | ||
var ends = new RegExp('^' + delim + '|' + delim + '$', 'g'); // regex: /^,|,$/g | ||
var outputStr = tagsStr.replace( dupes, delim ).replace(ends, ''); | ||
|
||
self.element.val(outputStr); | ||
return outputStr; | ||
}, | ||
|
||
inputField: function() { | ||
return this.tagInput; | ||
}, | ||
|
||
containerDiv: function() { | ||
return this.tagDiv; | ||
}, | ||
|
||
// remove the div, and show original input | ||
destroy: function() { | ||
$.Widget.prototype.destroy.apply(this); | ||
this.tagDiv.remove(); | ||
this.element.show(); | ||
} | ||
}); | ||
|
||
})(jQuery); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* Tagify styles | ||
Author: Alicia Liu test | ||
*/ | ||
|
||
.tagify-container { | ||
} | ||
|
||
.tagify-container > span { | ||
display: inline-block; | ||
padding: 8px 11px 8px 11px; | ||
margin: 1px 5px 0px 0px; | ||
border-radius: 4px; | ||
border: 1px solid #d0e1ff; | ||
background-color: #d0e1ff; | ||
color: #0f326d; | ||
font-weight: bold; | ||
font-size: 14px; | ||
} | ||
|
||
.tagify-container > span > a { | ||
padding-left: 5px !important; | ||
color: #83a5e1; | ||
text-decoration: none; | ||
font-weight: bold; | ||
} | ||
|
||
.tagify-container > input { | ||
border: 0 none; | ||
width: 100px !important; | ||
} | ||
|
||
.tagify-container > input:focus { | ||
outline: none; | ||
} |