diff --git a/app/assets/javascripts/desktop.js b/app/assets/javascripts/desktop.js index c4f95055..c55534a4 100644 --- a/app/assets/javascripts/desktop.js +++ b/app/assets/javascripts/desktop.js @@ -16,3 +16,4 @@ //= require orbitdesktop //= require jquery.gridster //= require desktop/books_pages +//= require jquery.tokeninput diff --git a/app/assets/javascripts/jquery.tokeninput.js b/app/assets/javascripts/jquery.tokeninput.js new file mode 100644 index 00000000..830e982f --- /dev/null +++ b/app/assets/javascripts/jquery.tokeninput.js @@ -0,0 +1,1043 @@ +/* + * jQuery Plugin: Tokenizing Autocomplete Text Entry + * Version 1.6.1 + * + * Copyright (c) 2009 James Smith (http://loopj.com) + * Licensed jointly under the GPL and MIT licenses, + * choose which one suits your project best! + * + */ + +(function ($) { +// Default settings +var DEFAULT_SETTINGS = { + // Search settings + method: "GET", + queryParam: "q", + searchDelay: 300, + minChars: 1, + propertyToSearch: "name", + jsonContainer: null, + contentType: "json", + + // Prepopulation settings + prePopulate: null, + processPrePopulate: false, + + // Display settings + hintText: "Type in a search term", + noResultsText: "No results", + searchingText: "Searching...", + deleteText: "×", + animateDropdown: true, + placeholder: null, + theme: null, + zindex: 999, + resultsLimit: null, + + enableHTML: false, + + resultsFormatter: function(item) { + var string = item[this.propertyToSearch]; + return "
" + (this.enableHTML ? string : _escapeHTML(string)) + "
" + escapeHTML($(input).data("settings").searchingText) + "
"); + show_dropdown(); + } + } + + function show_dropdown_hint () { + if($(input).data("settings").hintText) { + dropdown.html("" + escapeHTML($(input).data("settings").hintText) + "
"); + show_dropdown(); + } + } + + var regexp_special_chars = new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\-]', 'g'); + function regexp_escape(term) { + return term.replace(regexp_special_chars, '\\$&'); + } + + // Highlight the query part of the search term + function highlight_term(value, term) { + return value.replace( + new RegExp( + "(?![^&;]+;)(?!<[^<>]*)(" + regexp_escape(term) + ")(?![^<>]*>)(?![^&;]+;)", + "gi" + ), function(match, p1) { + return "" + escapeHTML(p1) + ""; + } + ); + } + + function find_value_and_highlight_term(template, value, term) { + return template.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + regexp_escape(value) + ")(?![^<>]*>)(?![^&;]+;)", "g"), highlight_term(value, term)); + } + + // Populate the results dropdown with some results + function populate_dropdown (query, results) { + if(results && results.length) { + dropdown.empty(); + var dropdown_ul = $("" + escapeHTML($(input).data("settings").noResultsText) + "
"); + show_dropdown(); + } + } + } + + // 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($(input).data("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($(input).data("settings").classes.selectedDropdownItem); + selected_dropdown_item = null; + } + + // Do a search and show the "searching" dropdown if the input is longer + // than $(input).data("settings").minChars + function do_search() { + var query = input_box.val(); + + if(query && query.length) { + if(selected_token) { + deselect_token($(selected_token), POSITION.AFTER); + } + + if(query.length >= $(input).data("settings").minChars) { + show_dropdown_searching(); + clearTimeout(timeout); + + timeout = setTimeout(function(){ + run_search(query); + }, $(input).data("settings").searchDelay); + } else { + hide_dropdown(); + } + } + } + + // Do the actual search + function run_search(query) { + var cache_key = query + computeURL(); + var cached_results = cache.get(cache_key); + if(cached_results) { + if ($.isFunction($(input).data("settings").onCachedResult)) { + cached_results = $(input).data("settings").onCachedResult.call(hidden_input, cached_results); + } + populate_dropdown(query, cached_results); + } else { + // Are we doing an ajax search or local data search? + if($(input).data("settings").url) { + var url = computeURL(); + // Extract exisiting get params + var ajax_params = {}; + ajax_params.data = {}; + if(url.indexOf("?") > -1) { + var parts = url.split("?"); + ajax_params.url = parts[0]; + + var param_array = parts[1].split("&"); + $.each(param_array, function (index, value) { + var kv = value.split("="); + ajax_params.data[kv[0]] = kv[1]; + }); + } else { + ajax_params.url = url; + } + + // Prepare the request + ajax_params.data[$(input).data("settings").queryParam] = query; + ajax_params.type = $(input).data("settings").method; + ajax_params.dataType = $(input).data("settings").contentType; + if($(input).data("settings").crossDomain) { + ajax_params.dataType = "jsonp"; + } + + // Attach the success callback + ajax_params.success = function(results) { + cache.add(cache_key, $(input).data("settings").jsonContainer ? results[$(input).data("settings").jsonContainer] : results); + if($.isFunction($(input).data("settings").onResult)) { + results = $(input).data("settings").onResult.call(hidden_input, results); + } + + // only populate the dropdown if the results are associated with the active search query + if(input_box.val() === query) { + populate_dropdown(query, $(input).data("settings").jsonContainer ? results[$(input).data("settings").jsonContainer] : results); + } + }; + + // Make the request + $.ajax(ajax_params); + } else if($(input).data("settings").local_data) { + // Do the search through local data + var results = $.grep($(input).data("settings").local_data, function (row) { + return row[$(input).data("settings").propertyToSearch].toLowerCase().indexOf(query.toLowerCase()) > -1; + }); + + cache.add(cache_key, results); + if($.isFunction($(input).data("settings").onResult)) { + results = $(input).data("settings").onResult.call(hidden_input, results); + } + populate_dropdown(query, results); + } + } + } + + // compute the dynamic URL + function computeURL() { + var url = $(input).data("settings").url; + if(typeof $(input).data("settings").url == 'function') { + url = $(input).data("settings").url.call($(input).data("settings")); + } + return url; + } + + // Bring browser focus to the specified object. + // Use of setTimeout is to get around an IE bug. + // (See, e.g., http://stackoverflow.com/questions/2600186/focus-doesnt-work-in-ie) + // + // obj: a jQuery object to focus() + function focus_with_timeout(obj) { + setTimeout(function() { obj.focus(); }, 50); + } + +}; + +// Really basic cache for the results +$.TokenList.Cache = function (options) { + var settings = $.extend({ + max_size: 500 + }, 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 += 1; + } + + data[query] = results; + }; + + this.get = function (query) { + return data[query]; + }; +}; +}(jQuery)); + diff --git a/app/assets/stylesheets/token-input-facebook.css b/app/assets/stylesheets/token-input-facebook.css new file mode 100644 index 00000000..5ddde0ce --- /dev/null +++ b/app/assets/stylesheets/token-input-facebook.css @@ -0,0 +1,122 @@ +/* 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, sans-serif; + min-height: 1px; + z-index: 999; + margin: 0; + padding: 0; + background-color: #fff; + list-style-type: none; + clear: left; +} + +ul.token-input-list-facebook li input { + border: 0; + width: 100px; + padding: 3px 8px; + background-color: white; + margin: 2px 0; + -webkit-appearance: caret; +} + +li.token-input-token-facebook { + overflow: hidden; + height: auto !important; + height: 15px; + 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; + white-space: nowrap; +} + +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; + margin: 0; + padding: 0; + list-style-type: none; +} + +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, sans-serif; + 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; + margin: 0; + list-style-type: none; +} + +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: normal; +} + +div.token-input-dropdown-facebook ul li.token-input-selected-dropdown-item-facebook { + background-color: #3b5998; + color: #fff; +} \ No newline at end of file diff --git a/app/assets/stylesheets/token-input-mac.css b/app/assets/stylesheets/token-input-mac.css new file mode 100644 index 00000000..1d712312 --- /dev/null +++ b/app/assets/stylesheets/token-input-mac.css @@ -0,0 +1,204 @@ +/* Example tokeninput style #2: Mac Style */ +fieldset.token-input-mac { + position: relative; + padding: 0; + margin: 5px 0; + background: #fff; + width: 400px; + border: 1px solid #A4BDEC; + border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; +} + +fieldset.token-input-mac.token-input-dropdown-mac { + border-radius: 10px 10px 0 0; + -moz-border-radius: 10px 10px 0 0; + -webkit-border-radius: 10px 10px 0 0; + box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25); + -moz-box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25); + -webkit-box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25); +} + +ul.token-input-list-mac { + overflow: hidden; + height: auto !important; + height: 1%; + cursor: text; + font-size: 12px; + font-family: Verdana, sans-serif; + min-height: 1px; + z-index: 999; + margin: 0; + padding: 3px; + background: transparent; +} + +ul.token-input-list-mac.error { + border: 1px solid #C52020; +} + +ul.token-input-list-mac li { + list-style-type: none; +} + +li.token-input-token-mac p { + display: inline; + padding: 0; + margin: 0; +} + +li.token-input-token-mac span { + color: #a6b3cf; + margin-left: 5px; + font-weight: bold; + cursor: pointer; +} + +/* TOKENS */ + +li.token-input-token-mac { + font-family: "Lucida Grande", Arial, sans-serif; + font-size: 9pt; + line-height: 12pt; + overflow: hidden; + height: 16px; + margin: 3px; + padding: 0 10px; + background: none; + background-color: #dee7f8; + color: #000; + cursor: default; + border: 1px solid #a4bdec; + border-radius: 15px; + -moz-border-radius: 15px; + -webkit-border-radius: 15px; + float: left; +} + +li.token-input-highlighted-token-mac { + background-color: #bbcef1; + border: 1px solid #598bec; + color: #000; +} + +li.token-input-selected-token-mac { + background-color: #598bec; + border: 1px solid transparent; + color: #fff; +} + +li.token-input-highlighted-token-mac span.token-input-delete-token-mac { + color: #000; +} + +li.token-input-selected-token-mac span.token-input-delete-token-mac { + color: #fff; +} + +li.token-input-input-token-mac { + border: none; + background: transparent; + float: left; + padding: 0; + margin: 0; +} + +li.token-input-input-token-mac input { + border: 0; + width: 100px; + padding: 3px; + background-color: transparent; + margin: 0; +} + +div.token-input-dropdown-mac { + position: absolute; + border: 1px solid #A4BDEC; + border-top: none; + left: -1px; + right: -1px; + background-color: #fff; + overflow: hidden; + cursor: default; + font-size: 10pt; + font-family: "Lucida Grande", Arial, sans-serif; + padding: 5px; + border-radius: 0 0 10px 10px; + -moz-border-radius: 0 0 10px 10px; + -webkit-border-radius: 0 0 10px 10px; + box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25); + -moz-box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25); + -webkit-box-shadow: 0 5px 20px 0 rgba(0,0,0,0.25); + clip:rect(0px, 1000px, 1000px, -10px); +} + +div.token-input-dropdown-mac p { + font-size: 8pt; + margin: 0; + padding: 0 5px; + font-style: italic; + color: #aaa; +} + +div.token-input-dropdown-mac h3.token-input-dropdown-category-mac { + font-family: "Lucida Grande", Arial, sans-serif; + font-size: 10pt; + font-weight: bold; + border: none; + padding: 0 5px; + margin: 0; +} + +div.token-input-dropdown-mac ul { + margin: 0; + padding: 0; +} + +div.token-input-dropdown-mac ul li { + list-style-type: none; + cursor: pointer; + background: none; + background-color: #fff; + margin: 0; + padding: 0 0 0 25px; +} + +div.token-input-dropdown-mac ul li.token-input-dropdown-item-mac { + background-color: #fff; +} + +div.token-input-dropdown-mac ul li.token-input-dropdown-item-mac.odd { + background-color: #ECF4F9; + border-radius: 15px; + -moz-border-radius: 15px; + -webkit-border-radius: 15px; +} + +div.token-input-dropdown-mac ul li.token-input-dropdown-item-mac span.token-input-dropdown-item-description-mac { + float: right; + font-size: 8pt; + font-style: italic; + padding: 0 10px 0 0; + color: #999; +} + +div.token-input-dropdown-mac ul li strong { + font-weight: bold; + text-decoration: underline; + font-style: none; +} + +div.token-input-dropdown-mac ul li.token-input-selected-dropdown-item-mac, +div.token-input-dropdown-mac ul li.token-input-selected-dropdown-item-mac.odd { + background-color: #598bec; + color: #fff; + border-radius: 15px; + -moz-border-radius: 15px; + -webkit-border-radius: 15px; +} + +div.token-input-dropdown-mac ul li.token-input-selected-dropdown-item-mac span.token-input-dropdown-item-description-mac, +div.token-input-dropdown-mac ul li.token-input-selected-dropdown-item-mac.odd span.token-input-dropdown-item-description-mac { + color: #fff; +} diff --git a/app/assets/stylesheets/token-input.css b/app/assets/stylesheets/token-input.css new file mode 100644 index 00000000..003f5848 --- /dev/null +++ b/app/assets/stylesheets/token-input.css @@ -0,0 +1,127 @@ +/* Example tokeninput style #1: Token vertical list*/ +ul.token-input-list { + overflow: hidden; + height: auto !important; + height: 1%; + width: 400px; + border: 1px solid #999; + cursor: text; + font-size: 12px; + font-family: Verdana, sans-serif; + z-index: 999; + margin: 0; + padding: 0; + background-color: #fff; + list-style-type: none; + clear: left; +} + +ul.token-input-list li { + list-style-type: none; +} + +ul.token-input-list li input { + border: 0; + width: 350px; + padding: 3px 8px; + background-color: white; + -webkit-appearance: caret; +} + +ul.token-input-disabled, +ul.token-input-disabled li input { + background-color: #E8E8E8; +} + +ul.token-input-disabled li.token-input-token { + background-color: #D9E3CA; + color: #7D7D7D +} + +ul.token-input-disabled li.token-input-token span { + color: #CFCFCF; + cursor: default; +} + +li.token-input-token { + overflow: hidden; + height: auto !important; + height: 1%; + margin: 3px; + padding: 3px 5px; + background-color: #d0efa0; + color: #000; + font-weight: bold; + cursor: default; + display: block; +} + +li.token-input-token p { + float: left; + padding: 0; + margin: 0; +} + +li.token-input-token span { + float: right; + color: #777; + cursor: pointer; +} + +li.token-input-selected-token { + background-color: #08844e; + color: #fff; +} + +li.token-input-selected-token span { + color: #bbb; +} + +div.token-input-dropdown { + 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: 12px; + font-family: Verdana, sans-serif; + z-index: 1; +} + +div.token-input-dropdown p { + margin: 0; + padding: 5px; + font-weight: bold; + color: #777; +} + +div.token-input-dropdown ul { + margin: 0; + padding: 0; +} + +div.token-input-dropdown ul li { + background-color: #fff; + padding: 3px; + list-style-type: none; +} + +div.token-input-dropdown ul li.token-input-dropdown-item { + background-color: #fafafa; +} + +div.token-input-dropdown ul li.token-input-dropdown-item2 { + background-color: #fff; +} + +div.token-input-dropdown ul li em { + font-weight: bold; + font-style: normal; +} + +div.token-input-dropdown ul li.token-input-selected-dropdown-item { + background-color: #d0efa0; +} diff --git a/vendor/built_in_modules/personal_conference/app/controllers/panel/personal_conference/desktop/conference_pages_controller.rb b/vendor/built_in_modules/personal_conference/app/controllers/panel/personal_conference/desktop/conference_pages_controller.rb index 2021e94e..2c4f7cb5 100644 --- a/vendor/built_in_modules/personal_conference/app/controllers/panel/personal_conference/desktop/conference_pages_controller.rb +++ b/vendor/built_in_modules/personal_conference/app/controllers/panel/personal_conference/desktop/conference_pages_controller.rb @@ -23,13 +23,21 @@ class Panel::PersonalConference::Desktop::ConferencePagesController < Applicatio @writing_conference = WritingConference.new @paper_types = ConferencePaperType.all @author_types = ConferenceAuthorType.all - #@co_author_candidate = - # CoAuthor.where(name_id: current_user.id).map{|c|c.co_author} - #@conference_candidate = - # WritingConference.where(create_user_id: current_user.id).map{|j|j.conference_title}.uniq + + if (not params[:q].nil?) and (current_user.name.include?params[:q]) + @user = [{ :id => 0, :name => current_user.name}] # self account name + else + @user = [] + end + + @co_authors = ConferenceCoAuthor.where(name_id: current_user.id, :co_author => /#{params[:q]}/) + @co_authors = [{ :id => params[:q], :name => params[:q] }] + # search string + @user + # self account name + @co_authors.map{|m| { :id => m.id, :name => m.co_author } } # match pattern respond_to do |format| format.html { render :layout => false} + format.json { render :json => @co_authors.to_json } end end diff --git a/vendor/built_in_modules/personal_conference/app/helpers/panel/personal_conference/desktop/conference_pages_helper.rb b/vendor/built_in_modules/personal_conference/app/helpers/panel/personal_conference/desktop/conference_pages_helper.rb index afff7344..8fb62cef 100644 --- a/vendor/built_in_modules/personal_conference/app/helpers/panel/personal_conference/desktop/conference_pages_helper.rb +++ b/vendor/built_in_modules/personal_conference/app/helpers/panel/personal_conference/desktop/conference_pages_helper.rb @@ -71,4 +71,16 @@ module Panel::PersonalConference::Desktop::ConferencePagesHelper file_type = "" end end + + def generate_authors_name ids + author_name = ids.map{|m| + if m == "0" + {:id => 0, :name => current_user.name} + else + {:id => m, :name => ConferenceCoAuthor.find(m).co_author} + end + } + + author_name.to_json + end end diff --git a/vendor/built_in_modules/personal_conference/app/models/conference_co_author.rb b/vendor/built_in_modules/personal_conference/app/models/conference_co_author.rb index 71e5b17f..1f0db884 100644 --- a/vendor/built_in_modules/personal_conference/app/models/conference_co_author.rb +++ b/vendor/built_in_modules/personal_conference/app/models/conference_co_author.rb @@ -3,11 +3,12 @@ class ConferenceCoAuthor LANGUAGE_TYPES = [ "English", "Chinese" ] - field :name_id, type: BSON::ObjectId + field :name_id, type: BSON::ObjectId # this is author field :co_author, localize: true field :email belongs_to :conference_co_author_relations + has_and_belongs_to_many :writing_conferences VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/ validates :email, format: { with: VALID_EMAIL_REGEX }, diff --git a/vendor/built_in_modules/personal_conference/app/models/writing_conference.rb b/vendor/built_in_modules/personal_conference/app/models/writing_conference.rb index 9248c977..c74eccbc 100644 --- a/vendor/built_in_modules/personal_conference/app/models/writing_conference.rb +++ b/vendor/built_in_modules/personal_conference/app/models/writing_conference.rb @@ -16,6 +16,7 @@ class WritingConference has_and_belongs_to_many :tags, :class_name => "PersonalConferenceTag" has_and_belongs_to_many :conference_author_types has_and_belongs_to_many :conference_paper_types + has_and_belongs_to_many :conference_co_authors field :year field :language @@ -43,6 +44,25 @@ class WritingConference after_save :save_writing_conference_files validates :url, :format => /^(http|https):\/\/(([a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5})|((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(:[0-9]{1,5})?(\/.*)?/i, :unless => Proc.new{self.url.blank?} + attr_reader :author_tokens + + def author_tokens=(ids) + authors_ids = ids.split(",").map{|id| + begin + ConferenceCoAuthor.find(m).id + rescue + if id != "0" + new_co_author = ConferenceCoAuthor.new(:co_author => id, :name_id => create_user_id) + new_co_author.save + new_co_author.id + else + id + end + end + } + self.conference_co_author_ids = authors_ids + end + def self.search( category_id = nil ) if category_id.to_s.size > 0 find(:all, :conditions => {writing_conference_category_id: category_id}).desc( :is_top, :title ) diff --git a/vendor/built_in_modules/personal_conference/app/views/panel/personal_conference/desktop/conference_pages/_form.html.erb b/vendor/built_in_modules/personal_conference/app/views/panel/personal_conference/desktop/conference_pages/_form.html.erb index fd6e59c9..7a1c958c 100644 --- a/vendor/built_in_modules/personal_conference/app/views/panel/personal_conference/desktop/conference_pages/_form.html.erb +++ b/vendor/built_in_modules/personal_conference/app/views/panel/personal_conference/desktop/conference_pages/_form.html.erb @@ -104,14 +104,20 @@