muck-services 0.1.10 → 0.1.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
}
|