Skip to content
Browse files

Merge branch 'master' of git@github.com:Smudge/newstc into mass-data

  • Loading branch information...
2 parents 18be2e0 + 6142039 commit 3f61cb825aee741bb452677fe35e753e7e6bf273 Wei Yan committed
View
20 app/controllers/notices_controller.rb
@@ -108,15 +108,21 @@ def fetch_loc_groups
def set_sources(update = false)
@notice.remove_all_viewer_sources if update
if params[:for_users]
- params[:for_users].split(",").map(&:strip).each do |login_or_name|
- viewer = User.search(login_or_name)
- if viewer
- @notice.add_viewer_source(viewer)
- else
- @notice.errors.add_to_base "\'#{login_or_name}\' is not a valid name or NetID." unless login_or_name.blank?
- end
+ # params[:for_users].split(",").map(&:strip).each do |login_or_name|
+ # viewer = User.search(login_or_name)
+ # if viewer
+ # @notice.add_viewer_source(viewer)
+ # else
+ # @notice.errors.add_to_base "\'#{login_or_name}\' is not a valid name or NetID." unless login_or_name.blank?
+ # end
+ # end
+ #parse autocomplete
+ params[:for_users].split(",").each do |l|
+ l = l.split("||")
+ @notice.add_viewer_source(l[0].constantize.find(l[1])) if l.length == 2
end
end
+ @notice.add_viewer_source(@department) if params[:department_wide_viewers] && !@notice.is_sticky
@notice.remove_all_display_location_sources if update
@notice.add_display_location_source(@department) if params[:department_wide_locations] && current_user.is_admin_of?(@department)
if params[:for_locations]
View
20 app/controllers/sub_requests_controller.rb
@@ -39,11 +39,17 @@ def edit
# POST /sub_requests
# POST /sub_requests.xml
- def create
+ def create
@sub_request = SubRequest.new(params[:sub_request])
@sub_request.shift = Shift.find(params[:shift_id])
- params[:list_of_logins].split(/\W+/).each do |l|
- @sub_request.add_substitute_source(User.find_by_login(l))
+ # params[:list_of_logins].split(/\W+/).each do |l|
+ # @sub_request.add_substitute_source(User.find_by_login(l))
+ # end
+
+ #parse autocomplete
+ params[:list_of_logins].split(",").each do |l|
+ l = l.split("||")
+ @sub_request.add_substitute_source(l[0].constantize.find(l[1])) if l.length == 2
end
@@ -66,9 +72,13 @@ def update
#TODO This should probably be in a transaction, so that
#if the update fails all sub sources don't get deleted...
@sub_request.remove_all_substitute_sources
- params[:list_of_logins].split(/\W+/).each do |l|
- @sub_request.add_substitute_source(User.find_by_login(l))
+
+ #parse autocomplete
+ params[:list_of_logins].split(",").each do |l|
+ l = l.split("||")
+ @sub_request.add_substitute_source(l[0].constantize.find(l[1])) if l.length == 2
end
+
respond_to do |format|
if @sub_request.update_attributes(params[:sub_request])
flash[:notice] = 'SubRequest was successfully updated.'
View
53 app/controllers/users_controller.rb
@@ -9,6 +9,17 @@ def index
else
@users = @department.users.select{|user| user.is_active?(@department)}
end
+
+ #filter results if we are searching
+ if params[:search]
+ @search_result = []
+ @users.each do |user|
+ if user.login.downcase.include?(params[:search]) or user.name.downcase.include?(params[:search])
+ @search_result << user
+ end
+ end
+ @users = @search_result
+ end
end
def show
@@ -130,4 +141,46 @@ def mass_create
end
redirect_to department_users_path
end
+
+ def autocomplete
+ departments = current_user.departments
+ users = Department.find(params[:department_id]).users
+ roles = Department.find(params[:department_id]).roles
+
+ @list = []
+ users.each do |user|
+ if user.login.downcase.include?(params[:q]) or user.name.downcase.include?(params[:q])
+ #if (user.login and user.login.include?(params[:q])) or (user.name and user.name.include?(params[:q]))
+ @list << {:id => "User||#{user.id}", :name => "#{user.name} (#{user.login})"}
+ end
+ end
+ departments.each do |department|
+ if department.name.downcase.include?(params[:q])
+ #if (user.login and user.login.include?(params[:q])) or (user.name and user.name.include?(params[:q]))
+ @list << {:id => "Department||#{department.id}", :name => "Department: #{department.name}"}
+ end
+ end
+ roles.each do |role|
+ if role.name.downcase.include?(params[:q])
+ #if (user.login and user.login.include?(params[:q])) or (user.name and user.name.include?(params[:q]))
+ @list << {:id => "Role||#{role.id}", :name => "Role: #{role.name}"}
+ end
+ end
+
+ #@users = @users.collect{|user| :id => user.id, :name => user.name}
+ render :layout => false
+ end
+
+ def search
+ @all_users = Department.find(params[:department_id]).users
+ unless @all_users.nil?
+ @users = []
+ @all_users.each do |user|
+ if user.login.downcase.include?(params[:search]) or user.name.downcase.include?(params[:search])
+ #if (user.login and user.login.include?(params[:q])) or (user.name and user.name.include?(params[:q]))
+ @users << user
+ end
+ end
+ end
+ end
end
View
29 app/helpers/application_helper.rb
@@ -10,5 +10,34 @@ def link_toggle(id, name, speed = "medium")
link_to_function name, "$('##{id}').slideToggle('#{speed}')"
# link_to_function name, "Effect.toggle('#{id}', 'appear', { duration: 0.3 });"
end
+
+ def tokenized_users_autocomplete(object, field, id)
+ json_string = ""
+ unless object.nil?
+ object.send(field).each do |user_source|
+ json_string += "{name: '#{user_source.name}', id: '#{user_source.class}||#{user_source.id}'},\n"
+ end
+ end
+
+ '<script type="text/javascript">
+ $(document).ready(function() {
+ $("#'+id+'").tokenInput("'+autocomplete_department_users_path(current_department)+'", {
+ prePopulate: ['+json_string+'],
+ classes: {
+ tokenList: "token-input-list-facebook",
+ token: "token-input-token-facebook",
+ tokenDelete: "token-input-delete-token-facebook",
+ selectedToken: "token-input-selected-token-facebook",
+ highlightedToken: "token-input-highlighted-token-facebook",
+ dropdown: "token-input-dropdown-facebook",
+ dropdownItem: "token-input-dropdown-item-facebook",
+ dropdownItem2: "token-input-dropdown-item2-facebook",
+ selectedDropdownItem: "token-input-selected-dropdown-item-facebook",
+ inputToken: "token-input-input-token-facebook"
+ }
+ });
+ });
+ </script>' + text_field_tag(id)
+ end
end
View
4 app/models/notice.rb
@@ -89,6 +89,10 @@ def add_viewer_source(source)
def viewers
self.viewer_links.collect{|l| l.user_source.users}.flatten.uniq
end
+
+ def viewer_sources
+ self.viewer_links.collect{|l| l.user_source}
+ end
def remove_all_viewer_sources
UserSourceLink.delete_all(:user_sink_id => self.id)
View
1 app/models/report.rb
@@ -10,3 +10,4 @@ def get_notices
all_notices.uniq
end
end
+
View
4 app/models/user.rb
@@ -80,9 +80,9 @@ def self.search(search_string)
def permission_list
roles.collect { |r| r.permissions }.flatten
end
-
+
def current_shift
- self.shifts.select{|shift| shift.signed_in? and !shift.submitted?}
+ self.shifts.select{|shift| shift.signed_in? and !shift.submitted?}[0]
end
# check if a user can see locations and shifts under this loc group
View
2 app/views/layouts/include/main_header.html.erb
@@ -4,7 +4,7 @@
<head>
<title><%= h(yield(:title) || 'Student Technology Collaborative') %></title>
<%= stylesheet_link_tag 'application', 'nav' %>
- <%= javascript_include_tag 'application' %>
+ <%= javascript_include_tag 'application', 'jrails', 'jquery' %>
<%= yield(:head) %>
</head>
<body>
View
27 app/views/notices/_announcement.html.erb
@@ -1,22 +1,19 @@
<fieldset class="announcement", title= "<%= "Posted on #{announcement.start_time.to_date} at #{announcement.start_time.to_s(:am_pm)}" %>" >
<% if current_user.is_admin_of?(@department) %>
- <div class="right">
- <%= link_to '[x]', { :controller => 'notices', :action => 'destroy', :id => announcement },
- :confirm => "Are you sure you want to remove this announcement?",
- :method => :delete %>
- </div>
- <div class="grayright">
- <%= link_to 'Edit', edit_notice_path(announcement) %>
- </div>
+ <div class="right">
+ <%= link_to '[x]', { :controller => 'notices', :action => 'destroy', :id => announcement },
+ :confirm => "Are you sure you want to remove this announcement?",
+ :method => :delete %>
+ </div>
+ <div class="grayright">
+ <%= link_to 'Edit', edit_notice_path(announcement) %>
+ </div>
<% end %>
- <%= announcement.content %>
-<br />
-<div class="grayleft">
+ <%= announcement.content %> <br />
+
+ <div class="grayleft">
<%= "by #{(announcement.author.name )}" -%>
-</div>
- <div class="grayright">
- <%= announcement.display_for %>
</div>
- </fieldset>
+</fieldset>
View
46 app/views/notices/_form.html.erb
@@ -1,21 +1,22 @@
+<% javascript 'jrails', 'jquery', 'jquery-ui', 'jquery.tokeninput' %>
+<% stylesheet 'tokeninput-facebook' %>
+
<fieldset>
<% form_for(@notice) do |f| %>
<%= f.error_messages %>
-
<% if current_user.is_admin_of?(@department) %>
- <p>
- Post as sticky? (start/end time preferences will be ignored)
- <%= f.check_box :is_sticky %>
- </p>
<p>
- Specify a start time<br />
- <%= f.datetime_select :start_time %>
- </p>
- <p>
- Specify an end time<br />
- <%= f.datetime_select :end_time %> <br /> or check here to make it indefinite:
-
- <%= check_box_tag :indefinite -%>
+ Post as sticky? (start/end time preferences will be ignored)
+ <%= f.check_box :is_sticky %>
+ </p>
+ <p>
+ Specify a start time<br />
+ <%= f.datetime_select :start_time %>
+ </p>
+ <p>
+ Specify an end time<br />
+ <%= f.datetime_select :end_time %> <br /> or check here to make it indefinite:
+ <%= check_box_tag :indefinite -%>
</p>
<% end %>
@@ -23,10 +24,10 @@
<%= f.label :content %><br />
<%= f.text_area :content %>
</p>
-
+<-- everything below should be invisible by default -->
<p>
<%= label_tag :for_users %><br />
- <%= text_field_tag :for_users %>
+ <%= tokenized_users_autocomplete(@notice, "viewer_sources", "for_users") %>
</p>
For locations: <br />
<% if current_user.is_admin_of?(@department) %>
@@ -39,12 +40,17 @@
<% for location in loc_group.locations do %>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
- <%= check_box_tag "for_locations[]", location.id, false, :disabled => false %><%= location.name %><br />
+ <% if current_user.current_shift %>
+ <%= check_box_tag "for_locations[]", location.id, current_user.current_shift.location == location, :disabled => false %>
+ <% else %>
+ <%= check_box_tag "for_locations[]", location.id, false, :disabled => false %>
+ <% end %>
+ <%= location.name %><br />
<% end %>
<% end %>
- </fieldset>
- <p>
- <%= f.submit 'Create/Edit' %>
- </p>
+</fieldset>
+<p>
+ <%= f.submit 'Create/Update' %>
+</p>
<% end %>
View
6 app/views/notices/_notice.html.erb
@@ -1,7 +1,7 @@
-<% stylesheet 'notice', 'message_center' %>
+<% stylesheet 'notice' %>
<% if notice.is_sticky %>
-<%= render :partial => 'notices/sticky', :collection => [notice] %>
+ <%= render :partial => 'notices/sticky', :collection => [notice] %>
<% else %>
-<%= render :partial => 'notices/announcement', :collection => [notice] %>
+ <%= render :partial => 'notices/announcement', :collection => [notice] %>
<% end %>
View
20 app/views/notices/_sticky.html.erb
@@ -1,16 +1,16 @@
- <fieldset class="sticky", title= "<%= "Posted on #{sticky.start_time.to_date} at #{sticky.start_time.to_s(:am_pm)}" %>" >
- <div class="right">
- <%= link_to '[x]', { :controller => 'notices', :action => 'destroy', :id => sticky },
- :confirm => "Are you sure you want to remove this notice? It will be removed for all users and all locations.",
- :method => :delete %>
- </div>
- <%= sticky.content %>
- <br />
+<fieldset class="sticky", title= "<%= "Posted on #{sticky.start_time.to_date} at #{sticky.start_time.to_s(:am_pm)}" %>" >
+ <div class="right">
+ <%= link_to '[x]', { :controller => 'notices', :action => 'destroy', :id => sticky },
+ :confirm => "Are you sure you want to remove this notice? It will be removed for all users and all locations.",
+ :method => :delete %>
+ </div>
+ <%= sticky.content %>
+ <br />
<div class="grayleft">
- <%= "by #{(sticky.author.name )} #{distance_of_time_in_words(sticky.start_time, Time.now, true)} ago" %>
+ <%= "by #{sticky.author.name} #{distance_of_time_in_words(sticky.start_time, Time.now, true)} ago" %>
</div>
<div class="grayright">
<%= sticky.display_for %>
</div>
- </fieldset>
+</fieldset>
View
6 app/views/notices/index.html.erb
@@ -1,7 +1,7 @@
<h1 id="page_title"><%=h "Notices - " %><font size = -2><%= link_to 'Post a new notice', {:action => 'new'} %></font></h1>
<% unless current_user.notices.empty? %>
- <fieldset>
+ <fieldset class ="index">
<legend>For you</legend>
<%= render :partial => 'notice', :collection => current_user.notices if current_user.notices%>
</fieldset>
@@ -10,7 +10,7 @@
<% @department.locations.each do |loc| %>
<% unless loc.notices.empty? %>
- <fieldset>
+ <fieldset class ="index">
<legend><%= loc.name %></legend>
<%= render :partial => 'notice', :collection => loc.notices %>
</fieldset>
@@ -20,7 +20,7 @@
<% if current_user.is_admin_of?(@department) %>
<% unless Notice.inactive.empty? %>
-<fieldset>
+<fieldset class ="index">
<legend>Inactive Notices</legend>
<%= render :partial => 'notice', :collection => Notice.inactive %>
</fieldset>
View
7 app/views/sub_requests/_form.html.erb
@@ -1,3 +1,6 @@
+<% javascript 'jrails', 'jquery', 'jquery-ui', 'jquery.tokeninput' %>
+<% stylesheet 'tokeninput-facebook' %>
+
<% form_for (params[:id] ? @sub_request : [:shift, @sub_request]) do |f| %>
<%= f.error_messages %>
@@ -20,8 +23,8 @@
<%= f.datetime_select :end, :default => @sub_request.shift.end %>
</p>
<p>
- <%= label_tag "List of logins that can take sub" %><br />
- <%= text_field_tag :list_of_logins %>
+ <%= label_tag "People/groups eligible for this sub" %><br />
+ <%= tokenized_users_autocomplete(@sub_request, "user_sources", "list_of_logins") %>
</p>
<p>
<%= f.label :reason %><br />
View
1 app/views/users/autocomplete.html.erb
@@ -0,0 +1 @@
+<%= @list.to_json %>
View
20 app/views/users/index.html.erb
@@ -1,4 +1,20 @@
-<% title "Users" %>
+<% title (params[:search] ? "User results for '#{params[:search]}'" : "Users") %>
+
+<div id="searchbox" style="display:none; margin-bottom: 1em">
+ <% form_tag (department_users_path(current_department), :method => :get) do %>
+ Search for a user: <%= text_field_tag :search %>
+ <%= submit_tag "Submit", :id => 'search_submit' %>
+ TODO: AJAXify this!
+ <% end %>
+</div>
+
+<script type="text/javascript">
+ $('div#searchbox').toggle();
+ $('input#search_submit').toggle();
+ $('#search').delayedObserver(0.5, function(){alert('test!')});
+</script>
+
+<%= observe_field :search, :function => "alert('test!')", :frequency => 0.5 %>
<table>
<tr>
@@ -25,8 +41,6 @@
<% end %>
</table>
-<p><%= link_to "New User", new_department_user_path(@department) %><br />
-<%= link_to "Mass Add", mass_add_department_users_path(@department) %><br />
<% if params[:show_inactive].nil? %>
<%= link_to "Show Inactive Users", :show_inactive => true %>
<% else %>
View
2 config/routes.rb
@@ -39,7 +39,7 @@
end
map.resources :departments, :shallow => true do |departments|
- departments.resources :users, :collection => {:mass_add => :get, :mass_create => :post, :restore => :post}
+ departments.resources :users, :collection => {:mass_add => :get, :mass_create => :post, :restore => :post, :autocomplete => :get}
departments.resources :loc_groups
departments.resources :locations
departments.resources :roles
View
529 public/javascripts/jquery.tokeninput.js
@@ -0,0 +1,529 @@
+/* via http://loopj.com/2009/04/25/jquery-plugin-tokenizing-autocomplete-text-entry/ */
+(function($) {
+
+$.fn.tokenInput = function (url, options) {
+ var settings = $.extend({
+ url: url,
+ prePopulate: "",
+ hintText: "Type in a search term",
+ noResultsText: "No results",
+ searchingText: "Searching...",
+ searchDelay: 300
+ }, options);
+
+ settings.classes = $.extend({
+ tokenList: "token-input-list",
+ token: "token-input-token",
+ tokenDelete: "token-input-delete-token",
+ selectedToken: "token-input-selected-token",
+ highlightedToken: "token-input-highlighted-token",
+ dropdown: "token-input-dropdown",
+ dropdownItem: "token-input-dropdown-item",
+ dropdownItem2: "token-input-dropdown-item2",
+ selectedDropdownItem: "token-input-selected-dropdown-item",
+ inputToken: "token-input-input-token"
+ }, options.classes);
+
+ return this.each(function () {
+ var list = new $.TokenList(this, settings);
+ });
+};
+
+$.TokenList = function (input, settings) {
+ //
+ // Variables
+ //
+
+ // Input box position "enum"
+ var POSITION = {
+ BEFORE: 0,
+ AFTER: 1,
+ END: 2
+ };
+
+ // Keys "enum"
+ var KEY = {
+ BACKSPACE: 8,
+ RETURN: 13,
+ LEFT: 37,
+ UP: 38,
+ RIGHT: 39,
+ DOWN: 40
+ };
+
+ // Save the tokens
+ var saved_tokens = [];
+
+ // Basic cache to save on db hits
+ var cache = new $.TokenList.Cache();
+
+ // Keep track of the timeout
+ var timeout;
+
+ // Create a new text input an attach keyup events
+ var input_box = $("<input type=\"text\">")
+ .css({
+ outline: "none"
+ })
+ .focus(function () {
+ show_dropdown_hint();
+ })
+ .blur(function () {
+ if(!selected_dropdown_item) {
+ hide_dropdown();
+ }
+ })
+ .keydown(function (event) {
+ var previous_token;
+ var next_token;
+
+ switch(event.keyCode) {
+ case KEY.LEFT:
+ case KEY.RIGHT:
+ case KEY.UP:
+ case KEY.DOWN:
+ if(!$(this).val()) {
+ previous_token = input_token.prev();
+ next_token = input_token.next();
+
+ if((previous_token.length && previous_token.get(0) === selected_token) || (next_token.length && next_token.get(0) === selected_token)) {
+ // Check if there is a previous/next token and it is selected
+ if(event.keyCode == KEY.LEFT || event.keyCode == KEY.UP) {
+ deselect_token($(selected_token), POSITION.BEFORE);
+ } else {
+ deselect_token($(selected_token), POSITION.AFTER);
+ }
+ } else if((event.keyCode == KEY.LEFT || event.keyCode == KEY.UP) && previous_token.length) {
+ // We are moving left, select the previous token if it exists
+ select_token($(previous_token.get(0)));
+ } else if((event.keyCode == KEY.RIGHT || event.keyCode == KEY.DOWN) && next_token.length) {
+ // We are moving right, select the next token if it exists
+ select_token($(next_token.get(0)));
+ }
+ } else {
+ var dropdown_item = null;
+
+ if(event.keyCode == KEY.DOWN || event.keyCode == KEY.RIGHT) {
+ dropdown_item = $(selected_dropdown_item).next();
+ } else {
+ dropdown_item = $(selected_dropdown_item).prev();
+ }
+
+ if(dropdown_item.length) {
+ select_dropdown_item(dropdown_item);
+ }
+ return false;
+ }
+ break;
+
+ case KEY.BACKSPACE:
+ previous_token = input_token.prev();
+
+ if(!$(this).val().length) {
+ if(selected_token) {
+ delete_token($(selected_token));
+ } else if(previous_token.length) {
+ select_token($(previous_token.get(0)));
+ }
+
+ return false;
+ } else if($(this).val().length == 1) {
+ hide_dropdown();
+ } else {
+ show_dropdown_searching();
+ do_search(1);
+ }
+ break;
+
+ case KEY.RETURN:
+ if(selected_dropdown_item) {
+ add_token($(selected_dropdown_item));
+ return false;
+ }
+ break;
+
+ default:
+ if(is_printable_character(event.keyCode)) {
+ show_dropdown_searching();
+ clearTimeout(timeout);
+ timeout = setTimeout(do_search, settings.searchDelay);
+ }
+
+ break;
+ }
+ });
+
+ // Keep a reference to the original input box
+ var hidden_input = $(input)
+ .hide()
+ .focus(function () {
+ input_box.focus();
+ })
+ .blur(function () {
+ input_box.blur();
+ })
+ .val("");
+
+ // Keep a reference to the selected token and dropdown item
+ var selected_token = null;
+ var selected_dropdown_item = null;
+
+ // The list to store the token items in
+ var token_list = $("<ul />")
+ .addClass(settings.classes.tokenList)
+ .insertAfter(hidden_input)
+ .click(function (event) {
+ var li = get_element_from_event(event, "li");
+ if(li && li.get(0) != input_token.get(0)) {
+ toggle_select_token(li);
+ return false;
+ } else {
+ input_box.focus();
+
+ if(selected_token) {
+ deselect_token($(selected_token), POSITION.END);
+ }
+ }
+ })
+ .mouseover(function (event) {
+ var li = get_element_from_event(event, "li");
+ if(li && selected_token !== this) {
+ li.addClass(settings.classes.highlightedToken);
+ }
+ })
+ .mouseout(function (event) {
+ var li = get_element_from_event(event, "li");
+ if(li && selected_token !== this) {
+ li.removeClass(settings.classes.highlightedToken);
+ }
+ })
+ .mousedown(function (event) {
+ // Stop user selecting text on tokens
+ var li = get_element_from_event(event, "li");
+ if(li){
+ return false;
+ }
+ });
+
+
+ // The list to store the dropdown items in
+ var dropdown = $("<div>")
+ .addClass(settings.classes.dropdown)
+ .insertAfter(token_list)
+ .hide();
+
+ // The token holding the input box
+ var input_token = $("<li />")
+ .addClass(settings.classes.inputToken)
+ .appendTo(token_list)
+ .append(input_box);
+
+ init_list();
+
+ //
+ // Functions
+ //
+
+ function is_printable_character(keycode) {
+ if((keycode >= 48 && keycode <= 90) || // 0-1a-z
+ (keycode >= 96 && keycode <= 111) || // numpad 0-9 + - / * .
+ (keycode >= 186 && keycode <= 192) || // ; = , - . / ^
+ (keycode >= 219 && keycode <= 222) // ( \ ) '
+ ) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ // Get an element of a particular type from an event (click/mouseover etc)
+ function get_element_from_event (event, element_type) {
+ var target = $(event.target);
+ var element = null;
+
+ if(target.is(element_type)) {
+ element = target;
+ } else if(target.parent(element_type).length) {
+ element = target.parent(element_type+":first");
+ }
+
+ return element;
+ }
+
+ // Add a token to the token list
+ function add_token (item) {
+ var li_data = $.data(item.get(0), "tokeninput");
+ var this_token = $("<li><p>"+ li_data.name +"</p> </li>")
+ .addClass(settings.classes.token)
+ .insertBefore(input_token);
+
+ $("<span>x</span>")
+ .addClass(settings.classes.tokenDelete)
+ .appendTo(this_token)
+ .click(function () {
+ delete_token($(this).parent());
+ return false;
+ });
+
+ $.data(this_token.get(0), "tokeninput", {"id": li_data.id, "name": li_data.name});
+
+ // Clear input box and make sure it keeps focus
+ input_box
+ .val("")
+ .focus();
+
+ // Don't show the help dropdown, they've got the idea
+ hide_dropdown();
+
+ // Save this token id
+ var id_string = li_data.id + ","
+ hidden_input.val(hidden_input.val() + id_string);
+ }
+
+ //pre-populate list if items exist
+ function init_list () {
+ li_data = settings.prePopulate;
+ if(li_data.length) {
+ for(var i in li_data) {
+
+ var this_token = $("<li><p>"+li_data[i].name+"</p> </li>")
+ .addClass(settings.classes.token)
+ .insertBefore(input_token);
+
+ $("<span>x</span>")
+ .addClass(settings.classes.tokenDelete)
+ .appendTo(this_token)
+ .click(function () {
+ delete_token($(this).parent());
+ return false;
+ });
+
+ $.data(this_token.get(0), "tokeninput", {"id": li_data[i].id, "name": li_data[i].name});
+
+ // Clear input box and make sure it keeps focus
+ input_box
+ .val("")
+ .focus();
+
+ // Don't show the help dropdown, they've got the idea
+ hide_dropdown();
+
+ // Save this token id
+ var id_string = li_data[i].id + ","
+ hidden_input.val(hidden_input.val() + id_string);
+ }
+ }
+ }
+
+ // Select a token in the token list
+ function select_token (token) {
+ token.addClass(settings.classes.selectedToken);
+ selected_token = token.get(0);
+
+ // Hide input box
+ input_box.val("");
+
+ // Hide dropdown if it is visible (eg if we clicked to select token)
+ hide_dropdown();
+ }
+
+ // Deselect a token in the token list
+ function deselect_token (token, position) {
+ token.removeClass(settings.classes.selectedToken);
+ selected_token = null;
+
+ if(position == POSITION.BEFORE) {
+ input_token.insertBefore(token);
+ } else if(position == POSITION.AFTER) {
+ input_token.insertAfter(token);
+ } else {
+ input_token.appendTo(token_list);
+ }
+
+ // Show the input box and give it focus again
+ input_box.focus();
+ }
+
+ // Toggle selection of a token in the token list
+ function toggle_select_token (token) {
+ if(selected_token == token.get(0)) {
+ deselect_token(token, POSITION.END);
+ } else {
+ if(selected_token) {
+ deselect_token($(selected_token), POSITION.END);
+ }
+ select_token(token);
+ }
+ }
+
+ // Delete a token from the token list
+ function delete_token (token) {
+ // Remove the id from the saved list
+ var token_data = $.data(token.get(0), "tokeninput");
+ //saved_tokens.splice($.inArray(saved_tokens, token_data.id), 1);
+
+ // Delete the token
+ token.remove();
+ selected_token = null;
+
+ // Show the input box and give it focus again
+ input_box.focus();
+
+ // Delete this token's id from hidden input
+ var str = hidden_input.val()
+ var start = str.indexOf(token_data.id+",");
+ var end = str.indexOf(",", start) + 1;
+
+ if(end >= str.length) {
+ hidden_input.val(str.slice(0, start));
+ } else {
+ hidden_input.val(str.slice(0, start) + str.slice(end, str.length));
+ }
+ }
+
+ // Hide and clear the results dropdown
+ function hide_dropdown () {
+ dropdown.hide().empty();
+ selected_dropdown_item = null;
+ }
+
+ function show_dropdown_searching () {
+ dropdown
+ .html("<p>"+settings.searchingText+"</p>")
+ .show();
+ }
+
+ function show_dropdown_hint () {
+ dropdown
+ .html("<p>"+settings.hintText+"</p>")
+ .show();
+ }
+
+ // Highlight the query part of the search term
+ function highlight_term(value, term) {
+ return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<em>$1</em>");
+ }
+
+ // Populate the results dropdown with some results
+ function populate_dropdown (query, results) {
+ if(results.length) {
+ dropdown.empty();
+ var dropdown_ul = $("<ul>")
+ .appendTo(dropdown)
+ .mouseover(function (event) {
+ select_dropdown_item(get_element_from_event(event, "li"));
+ })
+ .click(function (event) {
+ add_token(get_element_from_event(event, "li"));
+ })
+ .mousedown(function (event) {
+ // Stop user selecting text on tokens
+ return false;
+ })
+ .hide();
+
+ for(var i in results) {
+ if (results.hasOwnProperty(i)) {
+ var this_li = $("<li>"+highlight_term(results[i].name, query)+"</li>")
+ .appendTo(dropdown_ul);
+
+ if(i%2) {
+ this_li.addClass(settings.classes.dropdownItem);
+ } else {
+ this_li.addClass(settings.classes.dropdownItem2);
+ }
+
+ if(i == 0) {
+ select_dropdown_item(this_li);
+ }
+
+ $.data(this_li.get(0), "tokeninput", {"id": results[i].id, "name": results[i].name});
+ }
+ }
+
+ dropdown.show();
+ dropdown_ul.slideDown("fast");
+
+ } else {
+ dropdown
+ .html("<p>"+settings.noResultsText+"</p>")
+ .show();
+ }
+ }
+
+ // Highlight an item in the results dropdown
+ function select_dropdown_item (item) {
+ if(item) {
+ if(selected_dropdown_item) {
+ deselect_dropdown_item($(selected_dropdown_item));
+ }
+
+ item.addClass(settings.classes.selectedDropdownItem);
+ selected_dropdown_item = item.get(0);
+ }
+ }
+
+ // Remove highlighting from an item in the results dropdown
+ function deselect_dropdown_item (item) {
+ item.removeClass(settings.classes.selectedDropdownItem);
+ selected_dropdown_item = null;
+ }
+
+ // Do a search
+ function do_search(trim_last_char) {
+ var query = input_box.val().toLowerCase();
+
+ if(trim_last_char == 1) {
+ query = query.substring(0, query.length-1);
+ }
+
+ if(query && query.length) {
+ if(selected_token) {
+ deselect_token($(selected_token), POSITION.AFTER);
+ }
+
+ var cached_results = cache.get(query);
+ if(cached_results) {
+ populate_dropdown(query, cached_results);
+ } else {
+ $.get(settings.url, {"q": query }, function (results) {
+ cache.add(query, results);
+ populate_dropdown(query, results);
+ }, "json");
+ }
+ }
+ }
+};
+
+// Really basic cache for the results
+$.TokenList.Cache = function (options) {
+ var settings = $.extend({
+ max_size: 10
+ }, options);
+
+ var data = {};
+ var size = 0;
+
+ var flush = function () {
+ data = {};
+ size = 0;
+ };
+
+ this.add = function (query, results) {
+ if(size > settings.max_size) {
+ flush();
+ }
+
+ if(!data[query]) {
+ size++;
+ }
+
+ data[query] = results;
+ };
+
+ this.get = function (query) {
+ return data[query];
+ };
+};
+
+})(jQuery);
View
8 public/stylesheets/notice.css
@@ -1,5 +1,8 @@
+fieldset.index {
+ width: 75%;
+}
+
fieldset.sticky {
- width:48%;
padding: 5px;
margin: 0 0 0 0;
background-color:#FFFF99;
@@ -7,8 +10,7 @@ fieldset.sticky {
clear: right
}
-fieldset.announcement {
- width:48%;
+fieldset.announcement {
padding: 5px;
margin:0 0 0 0;
background-color:#ADD8E6;
View
118 public/stylesheets/tokeninput-facebook.css
@@ -0,0 +1,118 @@
+/* Example tokeninput style #2: Facebook style */
+ul.token-input-list-facebook {
+ overflow: hidden;
+ height: auto !important;
+ height: 1%;
+ width: 400px;
+ border: 1px solid #8496ba;
+ cursor: text;
+ font-size: 12px;
+ font-family: Verdana;
+ min-height: 1px;
+ z-index: 999;
+ margin: 0;
+ padding: 0;
+ background-color: #fff;
+}
+
+ul.token-input-list-facebook {
+ list-style-type: none;
+}
+
+ul.token-input-list-facebook li input {
+ border: 0;
+ width: 100px;
+ padding: 3px 8px;
+ background-color: white;
+ margin: 2px 0;
+}
+
+li.token-input-token-facebook {
+ overflow: hidden;
+ height: auto !important;
+ height: 1%;
+ margin: 3px;
+ padding: 1px 3px;
+ background-color: #eff2f7;
+ color: #000;
+ cursor: default;
+ border: 1px solid #ccd5e4;
+ font-size: 11px;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ float: left;
+}
+
+li.token-input-token-facebook p {
+ display: inline;
+ padding: 0;
+ margin: 0;
+}
+
+li.token-input-token-facebook span {
+ color: #a6b3cf;
+ margin-left: 5px;
+ font-weight: bold;
+ cursor: pointer;
+}
+
+li.token-input-selected-token-facebook {
+ background-color: #5670a6;
+ border: 1px solid #3b5998;
+ color: #fff;
+}
+
+li.token-input-input-token-facebook {
+ float: left;
+}
+
+div.token-input-dropdown-facebook {
+ position: absolute;
+ width: 400px;
+ background-color: #fff;
+ overflow: hidden;
+ border-left: 1px solid #ccc;
+ border-right: 1px solid #ccc;
+ border-bottom: 1px solid #ccc;
+ cursor: default;
+ font-size: 11px;
+ font-family: Verdana;
+ z-index: 1;
+}
+
+div.token-input-dropdown-facebook p {
+ margin: 0;
+ padding: 5px;
+ font-weight: bold;
+ color: #777;
+}
+
+div.token-input-dropdown-facebook ul {
+ margin: 0;
+ padding: 0;
+}
+
+div.token-input-dropdown-facebook ul li {
+ background-color: #fff;
+ padding: 3px;
+}
+
+div.token-input-dropdown-facebook ul li.token-input-dropdown-item-facebook {
+ background-color: #fff;
+}
+
+div.token-input-dropdown-facebook ul li.token-input-dropdown-item2-facebook {
+ background-color: #fff;
+}
+
+div.token-input-dropdown-facebook ul li em {
+ font-weight: bold;
+ font-style: none;
+}
+
+div.token-input-dropdown-facebook ul li.token-input-selected-dropdown-item-facebook {
+ background-color: #3b5998;
+ color: #fff;
+}
+

0 comments on commit 3f61cb8

Please sign in to comment.
Something went wrong with that request. Please try again.