muck-services 0.1.10 → 0.1.11
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/app/controllers/muck/recommendations_controller.rb +21 -6
- data/app/models/entry.rb +7 -10
- data/app/views/recommendations/get_button.html.erb +5 -0
- data/app/views/recommendations/index.pjs.erb +1 -1
- data/app/views/recommendations/index.xml.builder +4 -6
- data/app/views/recommendations/real_time.html.erb +13 -0
- data/app/views/recommendations/{index_real_time.pjs.erb → real_time.pjs.erb} +0 -0
- data/app/views/recommendations/{index_real_time.xml.builder → real_time.xml.builder} +1 -1
- data/config/muck_services_routes.rb +3 -0
- data/locales/en.yml +2 -1
- data/muck-services.gemspec +8 -52
- data/public/images/folksemantic/logo-folksemantic-gm.gif +0 -0
- data/public/javascripts/recommenderextension.user.js +392 -0
- data/test/rails_root/config/environment.rb +7 -6
- data/test/rails_root/config/environments/test.rb +0 -10
- data/test/rails_root/db/migrate/20090602191243_create_muck_raker.rb +4 -19
- data/test/rails_root/db/migrate/20090703175825_denormalize_entries_subjects.rb +3 -29
- data/test/rails_root/db/migrate/20090717175825_normalize_entries_subjects.rb +3 -32
- data/test/rails_root/test/factories.rb +0 -145
- data/test/rails_root/test/functional/topics_controller_test.rb +4 -0
- data/test/rails_root/test/test_helper.rb +5 -40
- data/test/rails_root/test/unit/share_test.rb +3 -0
- data/test/rails_root/test/unit/user_test.rb +3 -0
- metadata +8 -52
- data/app/views/recommendations/index_js.pjs.erb +0 -39
- data/config/solr/README.txt +0 -0
- data/config/solr/cores/de/conf/protwords.txt +0 -21
- data/config/solr/cores/de/conf/schema.xml +0 -81
- data/config/solr/cores/de/conf/solrconfig.xml +0 -311
- data/config/solr/cores/de/conf/stopwords.txt +0 -341
- data/config/solr/cores/de/conf/synonyms.txt +0 -31
- data/config/solr/cores/en/conf/protwords.txt +0 -21
- data/config/solr/cores/en/conf/schema.xml +0 -83
- data/config/solr/cores/en/conf/solrconfig.xml +0 -311
- data/config/solr/cores/en/conf/stopwords.txt +0 -341
- data/config/solr/cores/en/conf/synonyms.txt +0 -31
- data/config/solr/cores/es/conf/protwords.txt +0 -21
- data/config/solr/cores/es/conf/schema.xml +0 -81
- data/config/solr/cores/es/conf/solrconfig.xml +0 -311
- data/config/solr/cores/es/conf/stopwords.txt +0 -206
- data/config/solr/cores/es/conf/synonyms.txt +0 -31
- data/config/solr/cores/fr/conf/protwords.txt +0 -21
- data/config/solr/cores/fr/conf/schema.xml +0 -82
- data/config/solr/cores/fr/conf/solrconfig.xml +0 -311
- data/config/solr/cores/fr/conf/stopwords.txt +0 -57
- data/config/solr/cores/fr/conf/synonyms.txt +0 -31
- data/config/solr/cores/ja/conf/protwords.txt +0 -21
- data/config/solr/cores/ja/conf/schema.xml +0 -69
- data/config/solr/cores/ja/conf/solrconfig.xml +0 -311
- data/config/solr/cores/ja/conf/stopwords.txt +0 -341
- data/config/solr/cores/ja/conf/synonyms.txt +0 -31
- data/config/solr/cores/nl/conf/protwords.txt +0 -21
- data/config/solr/cores/nl/conf/schema.xml +0 -78
- data/config/solr/cores/nl/conf/solrconfig.xml +0 -311
- data/config/solr/cores/nl/conf/stopwords.txt +0 -45691
- data/config/solr/cores/nl/conf/synonyms.txt +0 -31
- data/config/solr/cores/ru/conf/protwords.txt +0 -21
- data/config/solr/cores/ru/conf/schema.xml +0 -78
- data/config/solr/cores/ru/conf/solrconfig.xml +0 -311
- data/config/solr/cores/ru/conf/stopwords.txt +0 -341
- data/config/solr/cores/ru/conf/synonyms.txt +0 -31
- data/config/solr/cores/zh/conf/protwords.txt +0 -21
- data/config/solr/cores/zh/conf/schema.xml +0 -72
- data/config/solr/cores/zh/conf/solrconfig.xml +0 -311
- data/config/solr/cores/zh/conf/stopwords.txt +0 -341
- data/config/solr/cores/zh/conf/synonyms.txt +0 -31
- data/config/solr/solr.xml +0 -50
- data/test/rails_root/test/shoulda_macros/controller.rb +0 -49
- data/test/rails_root/test/shoulda_macros/forms.rb +0 -32
- data/test/rails_root/test/shoulda_macros/models.rb +0 -50
- data/test/rails_root/test/shoulda_macros/pagination.rb +0 -53
- data/test/rails_root/test/shoulda_macros/plugins.rb +0 -34
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.11
|
@@ -5,10 +5,7 @@ class Muck::RecommendationsController < ApplicationController
|
|
5
5
|
# GET /recommendations
|
6
6
|
# GET /recommendations.xml
|
7
7
|
def index
|
8
|
-
|
9
|
-
@real_time == params[:rtr]
|
10
|
-
|
11
|
-
@details = params[:details] == "true"
|
8
|
+
@details = (params[:details] == 'true')
|
12
9
|
|
13
10
|
@uri = params[:u] || request.env['HTTP_REFERER']
|
14
11
|
if @uri.blank? || !allowed_uri(@uri)
|
@@ -40,17 +37,35 @@ class Muck::RecommendationsController < ApplicationController
|
|
40
37
|
end
|
41
38
|
end
|
42
39
|
format.xml {
|
43
|
-
render(
|
40
|
+
render('recommendations/index.xml.builder', :layout => false)
|
44
41
|
}
|
45
42
|
format.pjs {
|
46
43
|
@host = "http://#{URI.parse(@uri).host}"
|
47
|
-
render(
|
44
|
+
render('recommendations/index.pjs.erb', :layout => false)
|
48
45
|
}
|
49
46
|
format.rss {
|
50
47
|
render(:template => 'recommendations/index.rss.builder', :layout => false)
|
51
48
|
}
|
52
49
|
end
|
53
50
|
end
|
51
|
+
|
52
|
+
def get_button
|
53
|
+
@uri = params[:u]
|
54
|
+
render 'recommendations/get_button', :layout => false
|
55
|
+
end
|
56
|
+
|
57
|
+
def real_time
|
58
|
+
respond_to do |format|
|
59
|
+
format.html do
|
60
|
+
@uri = params[:u]
|
61
|
+
@cache_key = "recommendations/real_time?u=#{CGI.escape(@uri)}"
|
62
|
+
if !fragment_exist?(@cache_key)
|
63
|
+
@recommendations = Entry.real_time_recommendations(@uri, I18n.locale.to_s, 5)
|
64
|
+
end
|
65
|
+
render 'recommendations/real_time', :layout => false
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
54
69
|
|
55
70
|
protected
|
56
71
|
|
data/app/models/entry.rb
CHANGED
@@ -176,15 +176,11 @@ class Entry < ActiveRecord::Base
|
|
176
176
|
words = text.split()
|
177
177
|
words[0..(length-1)].join(' ') + (words.length > length ? end_string : '')
|
178
178
|
end
|
179
|
-
|
179
|
+
|
180
180
|
def ranked_recommendations(limit = 5, order = "mixed", details = false, omit_feeds = nil)
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
return relevant_recommendations(limit, "clicks DESC, relevance", details, omit_feeds) if order == "clicks"
|
185
|
-
return relevant_recommendations(limit, "relevance", details, omit_feeds) if (order == "relevance" || details == true)
|
186
|
-
return relevant_recommendations_filtered(limit, details, omit_feeds) if omit_feeds != nil
|
187
|
-
# end
|
181
|
+
return relevant_recommendations(limit, "clicks DESC, relevance", details, omit_feeds) if order == "clicks"
|
182
|
+
return relevant_recommendations(limit, "relevance", details, omit_feeds) if (order == "relevance" || details == true)
|
183
|
+
return relevant_recommendations_filtered(limit, details, omit_feeds) if omit_feeds != nil
|
188
184
|
|
189
185
|
recs = []
|
190
186
|
if self.popular != nil && !self.popular.empty?
|
@@ -332,10 +328,11 @@ class Entry < ActiveRecord::Base
|
|
332
328
|
uri.sub(/index.?\.(html|aspx|shtm|htm|asp|php|cfm|jsp|shtml|jhtml)$/, '')
|
333
329
|
end
|
334
330
|
|
335
|
-
def self.real_time_recommendations(uri,
|
331
|
+
def self.real_time_recommendations(uri, language='en', limit=5, details=false, options = {})
|
332
|
+
raise MuckServices::Exceptions::LanguageNotSupported, I18n.t('muck.services.language_not_supported') unless Recommender::Languages.supported_languages.include?(language)
|
336
333
|
fields = "entries.id, entries.title, entries.permalink, entries.direct_link, feeds.short_title AS collection"
|
337
334
|
fields << ", entries.published_at, entries.description, entries.author" if details == true
|
338
|
-
more_like_this(uri, options.merge(:select => fields, :joins => "INNER JOIN feeds ON feeds.id = entries.feed_id"))
|
335
|
+
more_like_this(uri, options.merge(:select => fields, :joins => "INNER JOIN feeds ON feeds.id = entries.feed_id", :core => language, :limit => limit))
|
339
336
|
end
|
340
337
|
|
341
338
|
end
|
@@ -0,0 +1,5 @@
|
|
1
|
+
<html>
|
2
|
+
<body style="margin:0;padding:0;">
|
3
|
+
<div style="padding-bottom:5px;margin:0 1px 0 3px;text-align:center;background-color:white;border-left:1px solid black;border-right:1px solid black;border-bottom:1px solid black;"><input type='button' value='<%= t('muck.services.get_recommendations') %>' onclick='window.open("<%= "real_time?u=#{@uri}" %>","_self");return false;' /></div>
|
4
|
+
</body>
|
5
|
+
</html>
|
@@ -6,7 +6,7 @@ if !@json_recommendations.nil?
|
|
6
6
|
var catalog_page = <%= !@entry.direct_link.nil? and @uri == @entry.permalink %>;
|
7
7
|
var document_host = '<%= @host %>';
|
8
8
|
var recs = <%= @json_recommendations %>;
|
9
|
-
var app = "
|
9
|
+
var app = "<%= app = request.protocol + request.host_with_port + '/' %>";
|
10
10
|
<% if @details == true -%>
|
11
11
|
function truncate(text, length) {
|
12
12
|
nEnd = text.indexOf(" ", 200);
|
@@ -4,20 +4,18 @@ if @entry.nil?
|
|
4
4
|
xml.recommendations
|
5
5
|
else
|
6
6
|
|
7
|
+
app = request.protocol + request.host_with_port + '/'
|
7
8
|
@recommendations = @entry.ranked_recommendations(@limit, params[:order] || "mixed", @details)
|
8
|
-
#xml.recommendations(:document_id => @entry.nil? ? "" : @entry.id, :uri => @uri, :title => t(:gm_title), :more_prompt => t(:gm_more_prompt), :direct_link_text => t(:direct_link), :locale => @entry.language) do
|
9
9
|
xml.recommendations(:document_id => @entry.nil? ? "" : @entry.id, :uri => @uri, :title => t("muck.services.gm_title"), :more_prompt => t("muck.services.gm_more_prompt"), :direct_link_text => t("muck.services.direct_link")) do
|
10
10
|
@recommendations.each do |recommendation|
|
11
11
|
xml.recommendation do
|
12
12
|
xml.title recommendation["title"]
|
13
13
|
xml.collection recommendation["collection"]
|
14
|
-
xml.link
|
15
|
-
|
16
|
-
xml.has_direct_link "true" if (recommendation["direct_link"] != nil and @uri[0..20] == recommendation["uri"][0..20])
|
14
|
+
xml.link app + 'r?id=' + recommendation['id'].to_s
|
15
|
+
xml.has_direct_link "true" if (recommendation["direct_link"] != nil and @uri[0..20] == recommendation["uri"][0..20])
|
17
16
|
|
18
17
|
if @details == true
|
19
|
-
xml.direct_link
|
20
|
-
# xml.direct_link "http://localhost:3000/r?id=" + recommendation["id"].to_s + "&u=" + recommendation["direct_link"] if recommendation["direct_link"] != nil
|
18
|
+
xml.direct_link app + 'r?id=' + recommendation["id"].to_s + "&u=" + recommendation["direct_link"] if recommendation["direct_link"] != nil
|
21
19
|
xml.uri recommendation["uri"]
|
22
20
|
xml.direct_uri recommendation["direct_link"]
|
23
21
|
xml.description recommendation["description"]
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<% cache(@cache_key) do %>
|
2
|
+
<html>
|
3
|
+
<body style="margin:0;padding:0;">
|
4
|
+
<div style="padding-bottom:5px;margin:0 1px 0 3px;background-color:white;border-left:1px solid black;border-right:1px solid black;border-bottom:1px solid black;">
|
5
|
+
<ul style="margin:0 2px 2px;padding:0px;font-family:Arial,Helvetica,sans-serif;">
|
6
|
+
<% @recommendations.results.each_with_index do |r, i| %>
|
7
|
+
<li style="margin-left: 0px; padding: 3px; list-style-type: none; font-size: 12px; <%= (i % 2 == 0) ? 'background-color:#E6E6E6;' : '' %>"><%= link_to r.title + ' (' + r.collection + ')', visit_path(r), :target => '_top' %></li>
|
8
|
+
<% end %>
|
9
|
+
</ul>
|
10
|
+
</div>
|
11
|
+
</body>
|
12
|
+
</html>
|
13
|
+
<% end %>
|
File without changes
|
@@ -9,7 +9,7 @@ else
|
|
9
9
|
xml.recommendation do
|
10
10
|
xml.title recommendation["title"]
|
11
11
|
xml.collection recommendation["collection"]
|
12
|
-
xml.link "http://folksemantic.com/visits/" + recommendation["id"].to_s
|
12
|
+
xml.link "http://www.folksemantic.com/visits/" + recommendation["id"].to_s
|
13
13
|
|
14
14
|
if @details == true
|
15
15
|
xml.description recommendation["description"]
|
@@ -25,6 +25,9 @@ ActionController::Routing::Routes.draw do |map|
|
|
25
25
|
map.resources :oai_endpoints, :controller => 'muck/oai_endpoints', :has_many => :feeds
|
26
26
|
|
27
27
|
map.resources :feeds, :controller => 'muck/feeds', :collection => { :new_extended => :get, :new_oai_rss => :get }, :has_many => :entries
|
28
|
+
|
29
|
+
map.connect 'recommendations/real_time', :controller => 'muck/recommendations', :action => 'real_time'
|
30
|
+
map.connect 'recommendations/get_button', :controller => 'muck/recommendations', :action => 'get_button'
|
28
31
|
map.resources :recommendations, :controller => 'muck/recommendations'
|
29
32
|
|
30
33
|
map.resources :identity_feeds, :controller => 'muck/identity_feeds'
|
data/locales/en.yml
CHANGED
@@ -206,7 +206,8 @@ en:
|
|
206
206
|
videos: "Videos"
|
207
207
|
back: "Back"
|
208
208
|
explore: "Search for {{topic}}"
|
209
|
-
language_not_supported:
|
209
|
+
language_not_supported: The requested language is not supported
|
210
|
+
get_recommendations: Get Recommendations
|
210
211
|
comment_entries_count:
|
211
212
|
one: "1 Comment"
|
212
213
|
other: "{{count}} Comments"
|
data/muck-services.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{muck-services}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.11"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Joel Duffin", "Justin Ball"]
|
12
|
-
s.date = %q{2009-11-
|
12
|
+
s.date = %q{2009-11-13}
|
13
13
|
s.description = %q{This gem contains the rails specific code for dealing with feeds, aggregations and recommendations. It is meant to work with the muck-raker gem.}
|
14
14
|
s.email = %q{justin@tatemae.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -111,13 +111,14 @@ Gem::Specification.new do |s|
|
|
111
111
|
"app/views/oai_endpoints/show.html.erb",
|
112
112
|
"app/views/parts/_add_feed.html.erb",
|
113
113
|
"app/views/parts/_select_feed.html.erb",
|
114
|
+
"app/views/recommendations/get_button.html.erb",
|
114
115
|
"app/views/recommendations/index.html.erb",
|
115
116
|
"app/views/recommendations/index.pjs.erb",
|
116
117
|
"app/views/recommendations/index.rss.builder",
|
117
118
|
"app/views/recommendations/index.xml.builder",
|
118
|
-
"app/views/recommendations/
|
119
|
-
"app/views/recommendations/
|
120
|
-
"app/views/recommendations/
|
119
|
+
"app/views/recommendations/real_time.html.erb",
|
120
|
+
"app/views/recommendations/real_time.pjs.erb",
|
121
|
+
"app/views/recommendations/real_time.xml.builder",
|
121
122
|
"app/views/search/_languages.html.erb",
|
122
123
|
"app/views/search/_result.html.erb",
|
123
124
|
"app/views/search/_search_box.html.erb",
|
@@ -332,48 +333,6 @@ Gem::Specification.new do |s|
|
|
332
333
|
"app/views/visits/_toolbar.html.erb",
|
333
334
|
"app/views/visits/show.html.erb",
|
334
335
|
"config/muck_services_routes.rb",
|
335
|
-
"config/solr/README.txt",
|
336
|
-
"config/solr/cores/de/conf/protwords.txt",
|
337
|
-
"config/solr/cores/de/conf/schema.xml",
|
338
|
-
"config/solr/cores/de/conf/solrconfig.xml",
|
339
|
-
"config/solr/cores/de/conf/stopwords.txt",
|
340
|
-
"config/solr/cores/de/conf/synonyms.txt",
|
341
|
-
"config/solr/cores/en/conf/protwords.txt",
|
342
|
-
"config/solr/cores/en/conf/schema.xml",
|
343
|
-
"config/solr/cores/en/conf/solrconfig.xml",
|
344
|
-
"config/solr/cores/en/conf/stopwords.txt",
|
345
|
-
"config/solr/cores/en/conf/synonyms.txt",
|
346
|
-
"config/solr/cores/es/conf/protwords.txt",
|
347
|
-
"config/solr/cores/es/conf/schema.xml",
|
348
|
-
"config/solr/cores/es/conf/solrconfig.xml",
|
349
|
-
"config/solr/cores/es/conf/stopwords.txt",
|
350
|
-
"config/solr/cores/es/conf/synonyms.txt",
|
351
|
-
"config/solr/cores/fr/conf/protwords.txt",
|
352
|
-
"config/solr/cores/fr/conf/schema.xml",
|
353
|
-
"config/solr/cores/fr/conf/solrconfig.xml",
|
354
|
-
"config/solr/cores/fr/conf/stopwords.txt",
|
355
|
-
"config/solr/cores/fr/conf/synonyms.txt",
|
356
|
-
"config/solr/cores/ja/conf/protwords.txt",
|
357
|
-
"config/solr/cores/ja/conf/schema.xml",
|
358
|
-
"config/solr/cores/ja/conf/solrconfig.xml",
|
359
|
-
"config/solr/cores/ja/conf/stopwords.txt",
|
360
|
-
"config/solr/cores/ja/conf/synonyms.txt",
|
361
|
-
"config/solr/cores/nl/conf/protwords.txt",
|
362
|
-
"config/solr/cores/nl/conf/schema.xml",
|
363
|
-
"config/solr/cores/nl/conf/solrconfig.xml",
|
364
|
-
"config/solr/cores/nl/conf/stopwords.txt",
|
365
|
-
"config/solr/cores/nl/conf/synonyms.txt",
|
366
|
-
"config/solr/cores/ru/conf/protwords.txt",
|
367
|
-
"config/solr/cores/ru/conf/schema.xml",
|
368
|
-
"config/solr/cores/ru/conf/solrconfig.xml",
|
369
|
-
"config/solr/cores/ru/conf/stopwords.txt",
|
370
|
-
"config/solr/cores/ru/conf/synonyms.txt",
|
371
|
-
"config/solr/cores/zh/conf/protwords.txt",
|
372
|
-
"config/solr/cores/zh/conf/schema.xml",
|
373
|
-
"config/solr/cores/zh/conf/solrconfig.xml",
|
374
|
-
"config/solr/cores/zh/conf/stopwords.txt",
|
375
|
-
"config/solr/cores/zh/conf/synonyms.txt",
|
376
|
-
"config/solr/solr.xml",
|
377
336
|
"db/bootstrap/attention.yml",
|
378
337
|
"db/bootstrap/feeds.yml",
|
379
338
|
"db/bootstrap/oai_endpoints.yml",
|
@@ -463,6 +422,7 @@ Gem::Specification.new do |s|
|
|
463
422
|
"locales/zh-TW.yml",
|
464
423
|
"locales/zh.yml",
|
465
424
|
"muck-services.gemspec",
|
425
|
+
"public/images/folksemantic/logo-folksemantic-gm.gif",
|
466
426
|
"public/images/service_icons/16/amazon.png",
|
467
427
|
"public/images/service_icons/16/ask.png",
|
468
428
|
"public/images/service_icons/16/bibsonomy.png",
|
@@ -726,6 +686,7 @@ Gem::Specification.new do |s|
|
|
726
686
|
"public/images/service_icons/facebook_friend_links.jpg",
|
727
687
|
"public/images/service_icons/facebook_my_links.jpg",
|
728
688
|
"public/javascripts/muck_services.js",
|
689
|
+
"public/javascripts/recommenderextension.user.js",
|
729
690
|
"public/stylesheets/frame.css",
|
730
691
|
"public/stylesheets/muck_services.css",
|
731
692
|
"rails/init.rb"
|
@@ -815,11 +776,6 @@ Gem::Specification.new do |s|
|
|
815
776
|
"test/rails_root/test/functional/oai_endpoints_controller_test.rb",
|
816
777
|
"test/rails_root/test/functional/topics_controller_test.rb",
|
817
778
|
"test/rails_root/test/functional/visits_controller_test.rb",
|
818
|
-
"test/rails_root/test/shoulda_macros/controller.rb",
|
819
|
-
"test/rails_root/test/shoulda_macros/forms.rb",
|
820
|
-
"test/rails_root/test/shoulda_macros/models.rb",
|
821
|
-
"test/rails_root/test/shoulda_macros/pagination.rb",
|
822
|
-
"test/rails_root/test/shoulda_macros/plugins.rb",
|
823
779
|
"test/rails_root/test/test_helper.rb",
|
824
780
|
"test/rails_root/test/unit/aggregation_feed_test.rb",
|
825
781
|
"test/rails_root/test/unit/aggregation_test.rb",
|
Binary file
|
@@ -0,0 +1,392 @@
|
|
1
|
+
// ==UserScript==
|
2
|
+
// @name RecommenderExtension
|
3
|
+
// @namespace folksemanticsemanticFrames.com
|
4
|
+
// @description Folksemantic Recommender GM Script - Recommends resources to a user based upon their current url.
|
5
|
+
// @include *
|
6
|
+
// ==/UserScript==
|
7
|
+
|
8
|
+
var sUrlToGetRecsFor = new String(window.location);
|
9
|
+
if (self != top && !folksemanticFrames(sUrlToGetRecsFor)) return;
|
10
|
+
|
11
|
+
var Drag = function() {
|
12
|
+
this.init.apply(this, arguments);
|
13
|
+
};
|
14
|
+
|
15
|
+
Drag.fixE = function(e) {
|
16
|
+
if (typeof e == 'undefined') e = window.event;
|
17
|
+
if (typeof e.layerX == 'undefined') e.layerX = e.offsetX;
|
18
|
+
if (typeof e.layerY == 'undefined') e.layerY = e.offsetY;
|
19
|
+
return e;
|
20
|
+
};
|
21
|
+
|
22
|
+
Drag.prototype.init = function(handle, dragdiv) {
|
23
|
+
this.div = dragdiv || handle;
|
24
|
+
this.handle = handle;
|
25
|
+
if (isNaN(parseInt(this.div.style.left))) this.div.style.left = '0px';
|
26
|
+
if (isNaN(parseInt(this.div.style.top))) this.div.style.top = '0px';
|
27
|
+
this.onDragStart = function() {};
|
28
|
+
this.onDragEnd = function() {};
|
29
|
+
this.onDrag = function() {};
|
30
|
+
this.onClick = function() {};
|
31
|
+
this.mouseDown = addEventHandler(this.handle, 'mousedown', this.start, this);
|
32
|
+
};
|
33
|
+
|
34
|
+
Drag.prototype.start = function(e) {
|
35
|
+
e = Drag.fixE(e);
|
36
|
+
|
37
|
+
this.started = new Date();
|
38
|
+
var y = this.startY = parseInt(this.div.style.top);
|
39
|
+
var x = this.startX = parseInt(this.div.style.left);
|
40
|
+
this.onDragStart(x, y);
|
41
|
+
this.lastMouseX = e.clientX;
|
42
|
+
this.lastMouseY = e.clientY;
|
43
|
+
this.documentMove = addEventHandler(document, 'mousemove', this.drag, this);
|
44
|
+
this.documentStop = addEventHandler(document, 'mouseup', this.end, this);
|
45
|
+
if (e.preventDefault) e.preventDefault();
|
46
|
+
return false;
|
47
|
+
};
|
48
|
+
|
49
|
+
Drag.prototype.drag = function(e) {
|
50
|
+
e = Drag.fixE(e);
|
51
|
+
var ey = e.clientY;
|
52
|
+
var ex = e.clientX;
|
53
|
+
var y = parseInt(this.div.style.top);
|
54
|
+
var x = parseInt(this.div.style.left);
|
55
|
+
var nx = ex + x - this.lastMouseX;
|
56
|
+
var ny = ey + y - this.lastMouseY;
|
57
|
+
this.div.style.left = nx + 'px';
|
58
|
+
this.div.style.top = ny + 'px';
|
59
|
+
this.lastMouseX = ex;
|
60
|
+
this.lastMouseY = ey;
|
61
|
+
this.onDrag(nx, ny);
|
62
|
+
if (e.preventDefault) e.preventDefault();
|
63
|
+
return false;
|
64
|
+
};
|
65
|
+
|
66
|
+
Drag.prototype.end = function() {
|
67
|
+
removeEventHandler(document, 'mousemove', this.documentMove);
|
68
|
+
removeEventHandler(document, 'mouseup', this.documentStop);
|
69
|
+
var time = (new Date()) - this.started;
|
70
|
+
var x = parseInt(this.div.style.left), dx = x - this.startX;
|
71
|
+
var y = parseInt(this.div.style.top), dy = y - this.startY;
|
72
|
+
this.onDragEnd(x, y, dx, dy, time);
|
73
|
+
if ((dx * dx + dy * dy) < (4 * 4) && time < 1e3)
|
74
|
+
this.onClick(x, y, dx, dy, time);
|
75
|
+
};
|
76
|
+
|
77
|
+
function removeEventHandler(target, eventName, eventHandler) {
|
78
|
+
if (target.addEventListener)
|
79
|
+
target.removeEventListener(eventName, eventHandler, true);
|
80
|
+
else if (target.attachEvent)
|
81
|
+
target.detachEvent('on' + eventName, eventHandler);
|
82
|
+
}
|
83
|
+
|
84
|
+
function addEventHandler(target, eventName, eventHandler, scope) {
|
85
|
+
var f = scope ? function() {
|
86
|
+
eventHandler.apply(scope, arguments);
|
87
|
+
} : eventHandler;
|
88
|
+
if (target.addEventListener)
|
89
|
+
target.addEventListener(eventName, f, true);
|
90
|
+
else if (target.attachEvent)
|
91
|
+
target.attachEvent('on' + eventName, f);
|
92
|
+
return f;
|
93
|
+
}
|
94
|
+
|
95
|
+
function dom_setStyle(elt, str) {
|
96
|
+
elt.setAttribute("style", str);
|
97
|
+
// for MSIE:
|
98
|
+
if (elt.style.setAttribute) {
|
99
|
+
elt.style.setAttribute("cssText", str, 0);
|
100
|
+
// positioning for MSIE:
|
101
|
+
if (elt.style.position == "fixed") {
|
102
|
+
elt.style.position = "absolute";
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
function special_website_url(url) {
|
108
|
+
// NEEDS
|
109
|
+
if (url.indexOf("http://www.needs.org/") == 0)
|
110
|
+
{
|
111
|
+
bNeeds = true;
|
112
|
+
if (url.length > 167 && url.indexOf("http://www.needs.org/needs/public/search/search_results/learning_resource/summary/index.jhtml") == 0)
|
113
|
+
{
|
114
|
+
bNeedsRecord = true;
|
115
|
+
nHook = url.indexOf("?");
|
116
|
+
if (nHook != -1)
|
117
|
+
{
|
118
|
+
url = "http://www.needs.org/needs/" + url.substring(nHook, url.length);
|
119
|
+
}
|
120
|
+
}
|
121
|
+
}
|
122
|
+
// eduCommons websites
|
123
|
+
else if (document.getElementById("portlet-eduCommonsNavigation"))
|
124
|
+
{
|
125
|
+
bSpecialSite = true;
|
126
|
+
var nEnd = url.indexOf("/", 20);
|
127
|
+
if (nEnd != -1)
|
128
|
+
{
|
129
|
+
nEnd = url.indexOf("/", nEnd + 1);
|
130
|
+
if (nEnd != -1)
|
131
|
+
{
|
132
|
+
url = url.substr(0, nEnd);
|
133
|
+
}
|
134
|
+
}
|
135
|
+
}
|
136
|
+
// MIT
|
137
|
+
else if (url.indexOf("http://ocw.mit.edu/") == 0)
|
138
|
+
{
|
139
|
+
bSpecialSite = true;
|
140
|
+
bMIT = true;
|
141
|
+
var nEnd = url.indexOf("/", 20);
|
142
|
+
if (nEnd != -1)
|
143
|
+
{
|
144
|
+
nEnd = url.indexOf("/", nEnd + 1);
|
145
|
+
if (nEnd != -1)
|
146
|
+
{
|
147
|
+
nEnd = url.indexOf("/", nEnd + 1);
|
148
|
+
if (nEnd != -1)
|
149
|
+
{
|
150
|
+
url = url.substr(0, nEnd + 1) + "CourseHome/index.htm";
|
151
|
+
}
|
152
|
+
}
|
153
|
+
}
|
154
|
+
}
|
155
|
+
return encodeURI(url);
|
156
|
+
}
|
157
|
+
|
158
|
+
function getElementByClassName(sTagName, sClassName) {
|
159
|
+
var aTags = document.getElementsByTagName(sTagName);
|
160
|
+
for (var nTag = 0; nTag < aTags.length; nTag++)
|
161
|
+
{
|
162
|
+
if (sClassName == aTags[nTag].className) return aTags[nTag];
|
163
|
+
}
|
164
|
+
return null;
|
165
|
+
}
|
166
|
+
|
167
|
+
function identifySquatParent() {
|
168
|
+
// educommons
|
169
|
+
squatParent = document.getElementById("portlet-eduCommonsNavigation");
|
170
|
+
if (squatParent) {
|
171
|
+
squatSibling = squatParent.lastChild;
|
172
|
+
divTags = squatParent.getElementsByTagName("div");
|
173
|
+
lastDivTag = divTags[divTags.length - 1];
|
174
|
+
sTopMargin = (lastDivTag.className == "currentSelection") ? "6px" : "0px";
|
175
|
+
sLeftMargin = "0px";
|
176
|
+
sRightMargin = "0px";
|
177
|
+
} else {
|
178
|
+
// MIT
|
179
|
+
squatParent = getElementByClassName("div", "left-nav");
|
180
|
+
if (bMIT && squatParent) {
|
181
|
+
ulTags = squatParent.getElementsByTagName("ul");
|
182
|
+
if (ulTags)
|
183
|
+
{
|
184
|
+
ulTag = ulTags[0];
|
185
|
+
if (ulTag) ulTag.style.margin = "0px 0px 6px;";
|
186
|
+
}
|
187
|
+
squatSibling = squatParent.lastChild;
|
188
|
+
sLeftMargin = "6px";
|
189
|
+
sRightMargin = "6px";
|
190
|
+
}
|
191
|
+
// everything else
|
192
|
+
else {
|
193
|
+
if (body.parentNode) {
|
194
|
+
squatParent = body.parentNode;
|
195
|
+
squatSibling = body.nextSibling;
|
196
|
+
}
|
197
|
+
}
|
198
|
+
}
|
199
|
+
}
|
200
|
+
|
201
|
+
String.prototype.startsWith = function(str)
|
202
|
+
{
|
203
|
+
return (this.match("^" + str) == str)
|
204
|
+
}
|
205
|
+
|
206
|
+
function demoDomain(sUrl) {
|
207
|
+
for (nDomain = 0; nDomain < demoDomains.length; nDomain++) {
|
208
|
+
if (sUrl.startsWith(demoDomains[nDomain])) return true;
|
209
|
+
}
|
210
|
+
return folksemanticFrames(sUrl);
|
211
|
+
}
|
212
|
+
function blacklistedDomain(sUrl) {
|
213
|
+
for (nDomain = 0; nDomain < blacklistedDomains.length; nDomain++) {
|
214
|
+
if (sUrl.indexOf(blacklistedDomains[nDomain]) != -1) return true;
|
215
|
+
}
|
216
|
+
return false;
|
217
|
+
}
|
218
|
+
function folksemanticFrames(sUrl) {
|
219
|
+
return (sUrl.indexOf("show_recs=true") != -1);
|
220
|
+
}
|
221
|
+
|
222
|
+
function recList(recommendations, sDirectLinkText) {
|
223
|
+
var sRecListDivStart = '<div id="recommenderlist" style="margin: 3px; padding: 0px;">';
|
224
|
+
var sRecListDivEnd = '</div>';
|
225
|
+
var sListStart = '<ul style="margin: 0px; padding: 0px; list-style-type: none;">';
|
226
|
+
var sListEnd = '</ul>';
|
227
|
+
var sRecList = bSpecialSite == true ? '' : sListStart;
|
228
|
+
for (var i = 0; i < recommendations.length; i++)
|
229
|
+
{
|
230
|
+
// get info for the recommendation
|
231
|
+
rec_title = recommendations[i].getElementsByTagName('title')[0].textContent;
|
232
|
+
link_uri = recommendations[i].getElementsByTagName('link')[0].textContent;
|
233
|
+
collection = recommendations[i].getElementsByTagName('collection')[0].textContent;
|
234
|
+
has_direct_link = recommendations[i].getElementsByTagName('has_direct_link')[0];
|
235
|
+
rec_link = link_uri;
|
236
|
+
rec_description = recommendations[i].getElementsByTagName('description')[0].textContent;
|
237
|
+
rec_tag = '<a href="' + rec_link + '" style="color:#3987DC !important; text-decoration:none !important; " target="_top">' + rec_title + ' (' + collection + ')</a>';
|
238
|
+
direct_link_tag = has_direct_link ? ' <a href="' + rec_link + '&target=direct_link" style="color:#556664 !important; text-decoration:none !important; " target="_top">' + sDirectLinkText + '</a>' : "";
|
239
|
+
|
240
|
+
// our lists are different in educommons and on MIT's websites
|
241
|
+
if (bSpecialSite == true)
|
242
|
+
{
|
243
|
+
sRecList += "<p style='font-size:12px;'>";
|
244
|
+
sRecList += rec_tag + direct_link_tag;
|
245
|
+
sRecList += "</p>";
|
246
|
+
}
|
247
|
+
// default list styles
|
248
|
+
else
|
249
|
+
{
|
250
|
+
sRecList += '<li style="margin-left: 0px; padding: 3px; list-style-type: none; font-size: 12px; ';
|
251
|
+
if (i % 2 == 0) sRecList += 'background-color:#E6E6E6;';
|
252
|
+
sRecList += '">';
|
253
|
+
sRecList += rec_tag + direct_link_tag;
|
254
|
+
sRecList += '</li>';
|
255
|
+
}
|
256
|
+
}
|
257
|
+
if (bSpecialSite == false) sRecList += sListEnd;
|
258
|
+
return sRecList;
|
259
|
+
}
|
260
|
+
|
261
|
+
function morePrompt(root) {
|
262
|
+
var sDocID = root.getAttribute("document_id");
|
263
|
+
var sMorePrompt = root.getAttribute("more_prompt");
|
264
|
+
return sDocID == '' ? '' : '<div class="recommender_more_link" style="margin: 3px; padding: 0px;" align="center"><a href="' + sShowDocUrl + sDocID + '" style="color:#3987DC !important; text-decoration:none !important; ">' + sMorePrompt + '</a></div>';
|
265
|
+
}
|
266
|
+
|
267
|
+
function createCloseBox(recommendersquat) {
|
268
|
+
var close = window.document.createElement("div");
|
269
|
+
dom_setStyle(close,
|
270
|
+
"margin:3px; position:absolute; top:3px; right:3px; font-family:arial,sans-serif;padding:1px; width:10px; border:1px solid #BBBBBB; text-align:center; cursor:pointer; color:#BBB; font-size:11px; background-color:#fff; font-weight:bold; z-index:999;");
|
271
|
+
close.setAttribute("title", "Click to close panel");
|
272
|
+
close.addEventListener('click', function() {
|
273
|
+
this.parentNode.style.display = "none";
|
274
|
+
}, true);
|
275
|
+
close.appendChild(window.document.createTextNode("x"));
|
276
|
+
recommendersquat.appendChild(close);
|
277
|
+
}
|
278
|
+
|
279
|
+
function verticalScrollBars() {
|
280
|
+
var vHeight = 0;
|
281
|
+
if (document.all) {
|
282
|
+
if (document.documentElement) {
|
283
|
+
vHeight = document.documentElement.clientHeight;
|
284
|
+
} else {
|
285
|
+
vHeight = document.body.clientHeight
|
286
|
+
}
|
287
|
+
} else {
|
288
|
+
vHeight = window.innerHeight;
|
289
|
+
}
|
290
|
+
return (document.body.offsetHeight > vHeight);
|
291
|
+
}
|
292
|
+
|
293
|
+
function positionSquatter(recommendersquat, bRealTime) {
|
294
|
+
// we treat educommons and mit sites differently
|
295
|
+
if (bSpecialSite == true)
|
296
|
+
{
|
297
|
+
// position the squatter
|
298
|
+
recommendersquat.setAttribute("style", 'margin: ' + sTopMargin + ' ' + sRightMargin + ' ' + sBottomMargin + ' ' + sLeftMargin + '; padding: 3px; border:1px solid #000000; background-color:#FFFFFF; z-index:999; font-size: 12px; font-family:Arial, Helvetica, sans-serif !important; ');
|
299
|
+
}
|
300
|
+
// default positioning and styling
|
301
|
+
else {
|
302
|
+
// calculate the position for the recommender div
|
303
|
+
var squatterWidth = 250;
|
304
|
+
var scrollWidth = verticalScrollBars() ? 20 : 5;
|
305
|
+
var rightAligned = window.innerWidth - squatterWidth - scrollWidth;
|
306
|
+
|
307
|
+
// position the squatter
|
308
|
+
if (bRealTime){
|
309
|
+
style = 'margin:0px; border:none; width:' + squatterWidth + 'px; position:absolute; left:' + rightAligned + 'px; top:2px; background-color:transparent; z-index:999;';
|
310
|
+
}else{
|
311
|
+
style = 'margin:0px; font-size: 12px; font-family:Arial, Helvetica, sans-serif !important; border:1px solid #000; width:' + squatterWidth + 'px; position:absolute; left:' + rightAligned + 'px; top:2px; background-color:#FFF; z-index:999;';
|
312
|
+
}
|
313
|
+
recommendersquat.setAttribute("style", style);
|
314
|
+
|
315
|
+
recommendersquat.drag = new Drag(document.getElementById('recommendertop'), recommendersquat);
|
316
|
+
createCloseBox(recommendersquat);
|
317
|
+
}
|
318
|
+
}
|
319
|
+
|
320
|
+
function squatterHeader(sTitle, bFrame) {
|
321
|
+
border = bFrame ? "border-top:1px solid black;border-right:1px solid black;border-left:1px solid black;width:240px;" : "border:none;";
|
322
|
+
return '<div id="recommendertop" style="color:#777;background-color:white;font-weight:bold;font-size:16px;font-family:Arial,Helvetica,sans-serif;margin: 2px 3px 0 3px; padding: 2px;' + border + '"><img src="' + sBaseUrl + '/images/folksemantic/logo-folksemantic-gm.gif" style="vertical-align:middle;"/> ' + sTitle + '</div>';
|
323
|
+
}
|
324
|
+
|
325
|
+
function squatterContent(root, recommendations) {
|
326
|
+
return squatterHeader(root.getAttribute("title"),false) + recList(recommendations, root.getAttribute("direct_link_text")) + morePrompt(root);
|
327
|
+
}
|
328
|
+
|
329
|
+
function displayGetRecsButton(root,sUrl) {
|
330
|
+
src = sBaseUrl + 'recommendations/get_button?u=' + escape(sUrl);
|
331
|
+
header = squatterHeader(root.getAttribute("title"),true);
|
332
|
+
displaySquatter(header + '<iframe allowtransparency="true" scrolling="false" width="250px" height="280px" frameborder="0" src="' + src + '"></iframe>', true);
|
333
|
+
}
|
334
|
+
|
335
|
+
function displaySquatter(sContent, bRealTime) {
|
336
|
+
var recommendersquat = document.createElement('div');
|
337
|
+
recommendersquat.innerHTML = sContent;
|
338
|
+
squatParent.insertBefore(recommendersquat, squatSibling);
|
339
|
+
positionSquatter(recommendersquat, bRealTime);
|
340
|
+
}
|
341
|
+
|
342
|
+
function getRecs(sUrl) {
|
343
|
+
GM_xmlhttpRequest(
|
344
|
+
{
|
345
|
+
method: 'GET',
|
346
|
+
url: sUrl,
|
347
|
+
headers: {'User-agent': 'Mozilla/4.0 (compatible) Greasemonkey/0.3'},
|
348
|
+
|
349
|
+
onload: function(responseDetails)
|
350
|
+
{
|
351
|
+
var dom = new DOMParser().parseFromString(responseDetails.responseText, "application/xml");
|
352
|
+
var root = dom.getElementsByTagName('recommendations')[0];
|
353
|
+
var recommendations = dom.getElementsByTagName('recommendation');
|
354
|
+
if (recommendations.length > 0) {
|
355
|
+
displaySquatter(squatterContent(root, recommendations), false);
|
356
|
+
} else {
|
357
|
+
displayGetRecsButton(root,sUrlToGetRecsFor);
|
358
|
+
}
|
359
|
+
}
|
360
|
+
});
|
361
|
+
}
|
362
|
+
|
363
|
+
var sBaseUrl = 'http://www.folksemantic.com/';
|
364
|
+
//var sBaseUrl = 'http://localhost:3000/';
|
365
|
+
var sServiceUrl = sBaseUrl + 'recommendations.xml?';
|
366
|
+
var sShowDocUrl = sBaseUrl + 'resources/';
|
367
|
+
var squatParent = null;
|
368
|
+
var squatSibling = null;
|
369
|
+
var sTopMargin = "3px";
|
370
|
+
var sRightMargin = "3px";
|
371
|
+
var sBottomMargin = "40px";
|
372
|
+
var sLeftMargin = "3px";
|
373
|
+
var bSpecialSite = false;
|
374
|
+
var bNeeds = false;
|
375
|
+
var bMIT = false;
|
376
|
+
var bNeedsRecord = false;
|
377
|
+
var body = null;
|
378
|
+
var bodyTags = document.getElementsByTagName('body');
|
379
|
+
var demoDomains = ['http://ocw.mit.edu','http://www.engineeringpathway.com'];
|
380
|
+
var blacklistedDomains = ['google.com','localhost','folksemantic.com','ocwfinder.org','ocwfinder.com','oerrecommender.org'];
|
381
|
+
if (sUrlToGetRecsFor.indexOf('http') == 0 && bodyTags && bodyTags.length > 0)
|
382
|
+
{
|
383
|
+
sUrlToGetRecsFor = special_website_url(sUrlToGetRecsFor);
|
384
|
+
body = bodyTags[0];
|
385
|
+
if ((bNeeds == true && bNeedsRecord == true) || bNeeds == false) {
|
386
|
+
identifySquatParent();
|
387
|
+
}
|
388
|
+
if (squatParent != null) {
|
389
|
+
if (!blacklistedDomain(sUrlToGetRecsFor))
|
390
|
+
getRecs(sServiceUrl + "u=" + sUrlToGetRecsFor);
|
391
|
+
}
|
392
|
+
}
|