murlsh 0.3.0 → 0.4.0
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/.gitignore +2 -0
- data/.htaccess +4 -0
- data/README.textile +2 -0
- data/Rakefile +101 -17
- data/VERSION +1 -1
- data/config.yaml +7 -6
- data/lib/murlsh/atom_feed.rb +2 -8
- data/lib/murlsh/auth.rb +1 -3
- data/lib/murlsh/openlock.rb +12 -0
- data/lib/murlsh/referrer.rb +1 -1
- data/lib/murlsh/url.rb +15 -5
- data/lib/murlsh/url_body.rb +13 -14
- data/lib/murlsh/url_server.rb +10 -17
- data/lib/murlsh.rb +1 -0
- data/murlsh.gemspec +3 -3
- data/public/css/screen.css +47 -13
- data/public/js/js.js +129 -107
- metadata +3 -3
- data/public/css/phone.css +0 -26
data/.gitignore
CHANGED
data/.htaccess
CHANGED
@@ -5,3 +5,7 @@ AddOutputFilterByType DEFLATE application/xhtml+xml
|
|
5
5
|
AddOutputFilterByType DEFLATE application/xml
|
6
6
|
AddOutputFilterByType DEFLATE text/css
|
7
7
|
AddOutputFilterByType DEFLATE text/html
|
8
|
+
|
9
|
+
<FilesMatch "\.gen\.(css|js)$">
|
10
|
+
Header add Expires "Wed, 22 Jun 2019 20:07:00 GMT"
|
11
|
+
</FilesMatch>
|
data/README.textile
CHANGED
data/Rakefile
CHANGED
@@ -1,21 +1,27 @@
|
|
1
1
|
$:.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
2
2
|
|
3
|
-
|
3
|
+
%w{
|
4
|
+
cgi
|
5
|
+
digest/md5
|
6
|
+
net/http
|
7
|
+
pp
|
8
|
+
uri
|
9
|
+
yaml
|
4
10
|
|
5
|
-
|
11
|
+
rubygems
|
6
12
|
|
7
|
-
|
8
|
-
|
9
|
-
|
13
|
+
flog
|
14
|
+
rake/testtask
|
15
|
+
sqlite3
|
10
16
|
|
11
|
-
|
12
|
-
require
|
17
|
+
murlsh
|
18
|
+
}.each { |d| require d }
|
13
19
|
|
14
20
|
config = YAML.load_file('config.yaml')
|
15
21
|
|
16
22
|
desc "Test remote content type fetch for a URL and show errors."
|
17
23
|
task :content_type, :url do |t, args|
|
18
|
-
puts Murlsh.get_content_type(args.url, :failproof => false)
|
24
|
+
puts Murlsh.get_content_type(args.url, :failproof => false, :debug => STDOUT)
|
19
25
|
end
|
20
26
|
|
21
27
|
namespace :db do
|
@@ -56,7 +62,8 @@ namespace :db do
|
|
56
62
|
email TEXT,
|
57
63
|
name TEXT,
|
58
64
|
title TEXT,
|
59
|
-
content_type TEXT
|
65
|
+
content_type TEXT,
|
66
|
+
via TEXT);
|
60
67
|
")
|
61
68
|
end
|
62
69
|
|
@@ -67,10 +74,12 @@ namespace :db do
|
|
67
74
|
|
68
75
|
end
|
69
76
|
|
70
|
-
|
77
|
+
directory 'tmp'
|
71
78
|
|
72
|
-
|
73
|
-
|
79
|
+
namespace :passenger do
|
80
|
+
|
81
|
+
desc 'Restart Passenger.'
|
82
|
+
task :restart => ['tmp'] do
|
74
83
|
open('tmp/restart.txt', 'w') { |f| }
|
75
84
|
end
|
76
85
|
|
@@ -92,7 +101,7 @@ end
|
|
92
101
|
|
93
102
|
desc "Test remote title fetch for a URL and show errors."
|
94
103
|
task :title, :url do |t, args|
|
95
|
-
puts Murlsh.get_title(args.url, :failproof => false)
|
104
|
+
puts Murlsh.get_title(args.url, :failproof => false, :debug => STDOUT)
|
96
105
|
end
|
97
106
|
|
98
107
|
desc 'Try to fetch the title for a url and update it in the database.'
|
@@ -124,9 +133,6 @@ end
|
|
124
133
|
|
125
134
|
desc "Validate XHTML."
|
126
135
|
task :validate do
|
127
|
-
require 'cgi'
|
128
|
-
require 'net/http'
|
129
|
-
|
130
136
|
net_http = Net::HTTP.new('validator.w3.org', 80)
|
131
137
|
#net_http.set_debug_output(STDOUT)
|
132
138
|
|
@@ -152,15 +158,93 @@ task :post_sh do
|
|
152
158
|
#!/bin/sh
|
153
159
|
|
154
160
|
URL="$1"
|
155
|
-
|
161
|
+
VIA="$2"
|
162
|
+
AUTH="$3" # password can be passed as second parameter or hardcoded here
|
156
163
|
|
157
164
|
curl \\
|
158
165
|
--data-urlencode "url=${URL}" \\
|
159
166
|
--data-urlencode "auth=${AUTH}" \\
|
167
|
+
--data-urlencode "via=${VIA}" \\
|
160
168
|
#{config.fetch('root_url')}
|
161
169
|
EOS
|
162
170
|
end
|
163
171
|
|
172
|
+
# Concatenate some files and return the result as a string.
|
173
|
+
def cat(in_files, sep=nil)
|
174
|
+
result = ''
|
175
|
+
in_files.each do |fname|
|
176
|
+
open(fname) do |h|
|
177
|
+
while (line = h.gets) do; result << line; end
|
178
|
+
result << sep if sep
|
179
|
+
end
|
180
|
+
end
|
181
|
+
result
|
182
|
+
end
|
183
|
+
|
184
|
+
directory 'public/css'
|
185
|
+
|
186
|
+
namespace :css do
|
187
|
+
|
188
|
+
desc 'Combine and compress css.'
|
189
|
+
task :compress => ['public/css'] do
|
190
|
+
combined = cat(config['css_files'].collect { |x| "public/#{x}" }, "\n")
|
191
|
+
|
192
|
+
md5sum = Digest::MD5.hexdigest(combined)
|
193
|
+
|
194
|
+
filename = "#{md5sum}.gen.css"
|
195
|
+
|
196
|
+
out = "public/css/#{filename}"
|
197
|
+
|
198
|
+
open(out, 'w') { |f| f.write(combined) }
|
199
|
+
puts "generated #{out}"
|
200
|
+
|
201
|
+
compressed_url = "css/#{filename}"
|
202
|
+
|
203
|
+
unless config['css_compressed'] == compressed_url
|
204
|
+
config['css_compressed'] = compressed_url
|
205
|
+
open('config.yaml', 'w') { |f| YAML.dump(config, f) }
|
206
|
+
puts "updated config with css_compressed = #{compressed_url}"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
directory 'public/js'
|
213
|
+
|
214
|
+
namespace :js do
|
215
|
+
|
216
|
+
desc 'Combine and compress javascript.'
|
217
|
+
task :compress => ['public/js'] do
|
218
|
+
combined = cat(config['js_files'].collect { |x| "public/#{x}" } )
|
219
|
+
|
220
|
+
compressed = Net::HTTP.post_form(
|
221
|
+
URI.parse('http://closure-compiler.appspot.com/compile'), {
|
222
|
+
'compilation_level' => 'SIMPLE_OPTIMIZATIONS',
|
223
|
+
'js_code' => combined,
|
224
|
+
'output_format' => 'text',
|
225
|
+
'output_info' => 'compiled_code',
|
226
|
+
}).body
|
227
|
+
|
228
|
+
md5sum = Digest::MD5.hexdigest(compressed)
|
229
|
+
|
230
|
+
filename = "#{md5sum}.gen.js"
|
231
|
+
|
232
|
+
out = "public/js/#{filename}"
|
233
|
+
|
234
|
+
open(out, 'w') { |f| f.write(compressed) }
|
235
|
+
puts "generated #{out}"
|
236
|
+
|
237
|
+
compressed_url = "js/#{filename}"
|
238
|
+
|
239
|
+
unless config['js_compressed'] == compressed_url
|
240
|
+
config['js_compressed'] = compressed_url
|
241
|
+
open('config.yaml', 'w') { |f| YAML.dump(config, f) }
|
242
|
+
puts "updated config with js_compressed = #{compressed_url}"
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
|
164
248
|
def ask(prompt, sep=':')
|
165
249
|
print "#{prompt}#{sep} "
|
166
250
|
return STDIN.gets.chomp
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/config.yaml
CHANGED
@@ -9,10 +9,11 @@ num_posts_feed: 25
|
|
9
9
|
num_posts_page: 100
|
10
10
|
page_title: mmb url share
|
11
11
|
root_url: http://urls.matthewm.boedicker.org/
|
12
|
-
css_prefix: css/
|
13
|
-
img_prefix: img/
|
14
|
-
js_prefix: js/
|
15
|
-
swf_prefix: swf/
|
16
12
|
css_files:
|
17
|
-
- jquery.jgrowl.css
|
18
|
-
- screen.css
|
13
|
+
- css/jquery.jgrowl.css
|
14
|
+
- css/screen.css
|
15
|
+
js_files:
|
16
|
+
- js/jquery-1.3.2.min.js
|
17
|
+
- js/jquery.cookie.js
|
18
|
+
- js/jquery.jgrowl_compressed.js
|
19
|
+
- js/js.js
|
data/lib/murlsh/atom_feed.rb
CHANGED
@@ -37,20 +37,14 @@ module Murlsh
|
|
37
37
|
|
38
38
|
# Generate the feed and write it to the filesystem with locking.
|
39
39
|
def write(entries, path)
|
40
|
-
|
41
|
-
f.flock(File::LOCK_EX)
|
42
|
-
|
43
|
-
make(entries, :target => f)
|
44
|
-
|
45
|
-
f.flock(File::LOCK_UN)
|
46
|
-
end
|
40
|
+
Murlsh::openlock(path, 'w') { |f| make(entries, :target => f) }
|
47
41
|
end
|
48
42
|
|
49
43
|
# Build the feed using XML builder. Options are passed to
|
50
44
|
# Builder::XmlMarkup.new.
|
51
45
|
def make(entries, options={})
|
52
46
|
xm = Builder::XmlMarkup.new(options)
|
53
|
-
xm.instruct!
|
47
|
+
xm.instruct!(:xml)
|
54
48
|
|
55
49
|
xm.feed(:xmlns => 'http://www.w3.org/2005/Atom') {
|
56
50
|
xm.id(@root_url)
|
data/lib/murlsh/auth.rb
CHANGED
@@ -30,11 +30,9 @@ module Murlsh
|
|
30
30
|
|
31
31
|
# Add a user to the authentication file.
|
32
32
|
def add_user(username, email, password)
|
33
|
-
|
34
|
-
f.flock(File::LOCK_EX)
|
33
|
+
Murlsh::openlock(@file, 'a') do |f|
|
35
34
|
f.write("#{[username, Digest::MD5.hexdigest(email),
|
36
35
|
BCrypt::Password.create(password)].join(',')}\n")
|
37
|
-
f.flock(File::LOCK_UN)
|
38
36
|
end
|
39
37
|
end
|
40
38
|
|
data/lib/murlsh/referrer.rb
CHANGED
@@ -38,7 +38,7 @@ module Murlsh
|
|
38
38
|
|
39
39
|
# Regex host match to name of query string parameter.
|
40
40
|
Qmap = {
|
41
|
-
/^www\.google\.(bs|ca|com|cz|dk|es|fi|nl)(\/m)?\/search$/ => 'q',
|
41
|
+
/^www\.google\.(bs|ca|com|cz|dk|es|fi|it|nl|no)(\/m)?\/search$/ => 'q',
|
42
42
|
/^www\.bing\.com\/search$/ => 'q',
|
43
43
|
}
|
44
44
|
|
data/lib/murlsh/url.rb
CHANGED
@@ -3,6 +3,10 @@ require 'active_record'
|
|
3
3
|
|
4
4
|
require 'uri'
|
5
5
|
|
6
|
+
module URI
|
7
|
+
def domain; host[/[a-z\d-]+\.[a-z]{2,}(\.[a-z]{2})?$/].downcase; end
|
8
|
+
end
|
9
|
+
|
6
10
|
module Murlsh
|
7
11
|
|
8
12
|
# URL ActiveRecord.
|
@@ -21,11 +25,7 @@ module Murlsh
|
|
21
25
|
|
22
26
|
# Return text showing what domain a link goes to.
|
23
27
|
def hostrec
|
24
|
-
begin
|
25
|
-
domain = URI(url).host[/[a-z\d-]+\.[a-z]{2,}(\.[a-z]{2})?$/].downcase
|
26
|
-
rescue Exception => e
|
27
|
-
domain = nil
|
28
|
-
end
|
28
|
+
domain = begin; URI(url).domain; rescue Exception; end
|
29
29
|
|
30
30
|
domain = Murlsh::Plugin.hooks('hostrec').inject(domain) {
|
31
31
|
|result,plugin| plugin.run(result, url, title) }
|
@@ -33,6 +33,16 @@ module Murlsh
|
|
33
33
|
yield domain if domain
|
34
34
|
end
|
35
35
|
|
36
|
+
# Yield the url that the url came from.
|
37
|
+
def viarec
|
38
|
+
if via
|
39
|
+
begin
|
40
|
+
yield URI(via)
|
41
|
+
rescue Exception
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
36
46
|
# Return true if this url is an image.
|
37
47
|
def is_image?
|
38
48
|
%w{image/gif image/jpeg image/png}.include?(content_type)
|
data/lib/murlsh/url_body.rb
CHANGED
@@ -6,7 +6,7 @@ module Murlsh
|
|
6
6
|
|
7
7
|
def initialize(config, db, req)
|
8
8
|
@config, @db, @req, @q = config, db, req, req.params['q']
|
9
|
-
super(:indent =>
|
9
|
+
super(:indent => @config['xhtml_indent'] || 0)
|
10
10
|
end
|
11
11
|
|
12
12
|
# Fetch urls base on query string parameters.
|
@@ -56,7 +56,15 @@ module Murlsh
|
|
56
56
|
|
57
57
|
a(mu.title.strip.gsub(/\s+/, ' '), :href => mu.url)
|
58
58
|
|
59
|
-
mu.hostrec
|
59
|
+
mu.hostrec do |hostrec|
|
60
|
+
text!(' ')
|
61
|
+
span(hostrec, :class => 'host')
|
62
|
+
end
|
63
|
+
mu.viarec do |via|
|
64
|
+
span(:class => 'via') {
|
65
|
+
text!(' (via '); a(via.domain, :href => via); text!(')')
|
66
|
+
}
|
67
|
+
end
|
60
68
|
span(", #{mu.time.fuzzy}", :class => 'date') if
|
61
69
|
@config.fetch('show_dates', true) and mu.time
|
62
70
|
last = mu
|
@@ -82,10 +90,7 @@ module Murlsh
|
|
82
90
|
:viewport =>
|
83
91
|
'width=device-width,minimum-scale=1.0,maximum-scale=1.0')
|
84
92
|
google_verify
|
85
|
-
css(@config
|
86
|
-
:prefix => @config.fetch('css_prefix', ''))
|
87
|
-
css('phone.css', :media => 'only screen and (max-device-width: 480px)',
|
88
|
-
:prefix => @config.fetch('css_prefix', ''))
|
93
|
+
css(@config['css_compressed'] || @config['css_files'])
|
89
94
|
atom(@config.fetch('feed_file'))
|
90
95
|
}
|
91
96
|
end
|
@@ -128,6 +133,7 @@ module Murlsh
|
|
128
133
|
form(:action => '', :method => 'post') {
|
129
134
|
fieldset(:id => 'add') {
|
130
135
|
self.p { add_form_input('Add URL:', 'url', 32) }
|
136
|
+
self.p { add_form_input('Via:', 'via', 32) }
|
131
137
|
self.p {
|
132
138
|
add_form_input('Password:', 'auth', 16, 'password')
|
133
139
|
input(:type => 'button', :id => 'submit', :value => 'Add')
|
@@ -156,14 +162,7 @@ module Murlsh
|
|
156
162
|
end
|
157
163
|
|
158
164
|
# Required javascript builder.
|
159
|
-
def js
|
160
|
-
javascript(%w{
|
161
|
-
jquery-1.3.2.min.js
|
162
|
-
jquery.cookie.js
|
163
|
-
jquery.jgrowl_compressed.js
|
164
|
-
js.js
|
165
|
-
}, :prefix => @config.fetch('js_prefix', ''))
|
166
|
-
end
|
165
|
+
def js; javascript(@config['js_compressed'] || @config['js_files']); end
|
167
166
|
|
168
167
|
end
|
169
168
|
|
data/lib/murlsh/url_server.rb
CHANGED
@@ -10,8 +10,7 @@ module Murlsh
|
|
10
10
|
class UrlServer
|
11
11
|
|
12
12
|
def initialize(config, db)
|
13
|
-
@config = config
|
14
|
-
@db = db
|
13
|
+
@config, @db = config, db
|
15
14
|
ActiveRecord::Base.default_timezone = :utc
|
16
15
|
|
17
16
|
Dir['plugins/*.rb'].each { |p| load p }
|
@@ -35,11 +34,7 @@ module Murlsh
|
|
35
34
|
|
36
35
|
# Respond to a POST request. Add the new url and return json.
|
37
36
|
def post(req)
|
38
|
-
|
39
|
-
|
40
|
-
url = req.params['url']
|
41
|
-
|
42
|
-
unless url.empty?
|
37
|
+
unless req.params['url'].empty?
|
43
38
|
auth = req.params['auth']
|
44
39
|
if user = auth.empty? ? nil : Murlsh::Auth.new(
|
45
40
|
@config.fetch('auth_file')).auth(auth)
|
@@ -48,9 +43,10 @@ module Murlsh
|
|
48
43
|
|
49
44
|
mu = Murlsh::Url.new do |u|
|
50
45
|
u.time = Time.now.gmtime
|
51
|
-
u.url = url
|
46
|
+
u.url = req.params['url']
|
52
47
|
u.email = user[:email]
|
53
48
|
u.name = user[:name]
|
49
|
+
u.via = req.params['via'] unless (req.params['via'] || []).empty?
|
54
50
|
end
|
55
51
|
|
56
52
|
Murlsh::Plugin.hooks('add_pre') { |p| p.run(mu, @config) }
|
@@ -59,25 +55,22 @@ module Murlsh
|
|
59
55
|
|
60
56
|
Murlsh::Plugin.hooks('add_post') { |p| p.run(@config) }
|
61
57
|
|
62
|
-
resp[
|
58
|
+
resp = Rack::Response.new([mu].to_json, 200, {
|
59
|
+
'Content-Type' => 'application/json' })
|
63
60
|
|
64
61
|
resp.set_cookie('auth',
|
65
62
|
:expires => Time.mktime(2015, 6, 22),
|
66
63
|
:path => '/',
|
67
64
|
:value => auth)
|
68
65
|
|
69
|
-
resp
|
66
|
+
resp
|
70
67
|
else
|
71
|
-
|
72
|
-
|
73
|
-
resp.write('Permission denied')
|
68
|
+
Rack::Response.new('Permission denied', 403, {
|
69
|
+
'Content-Type' => 'text/plain' })
|
74
70
|
end
|
75
71
|
else
|
76
|
-
|
77
|
-
resp['Content-Type'] = 'text/plain'
|
78
|
-
resp.write('No url')
|
72
|
+
Rack::Response.new('No url', 500, { 'Content-Type' => 'text/plain' })
|
79
73
|
end
|
80
|
-
resp
|
81
74
|
end
|
82
75
|
|
83
76
|
end
|
data/lib/murlsh.rb
CHANGED
data/murlsh.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{murlsh}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.4.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Matthew M. Boedicker"]
|
12
|
-
s.date = %q{2009-
|
12
|
+
s.date = %q{2009-12-13}
|
13
13
|
s.default_executable = %q{murlsh}
|
14
14
|
s.description = %q{url sharing site framework with easy adding, title lookup, atom feed, thumbnails and embedding}
|
15
15
|
s.email = %q{matthewm@boedicker.org}
|
@@ -34,6 +34,7 @@ Gem::Specification.new do |s|
|
|
34
34
|
"lib/murlsh/get_content_type.rb",
|
35
35
|
"lib/murlsh/get_title.rb",
|
36
36
|
"lib/murlsh/markup.rb",
|
37
|
+
"lib/murlsh/openlock.rb",
|
37
38
|
"lib/murlsh/plugin.rb",
|
38
39
|
"lib/murlsh/referrer.rb",
|
39
40
|
"lib/murlsh/sqlite3_adapter.rb",
|
@@ -48,7 +49,6 @@ Gem::Specification.new do |s|
|
|
48
49
|
"plugins/lookup_content_type_title.rb",
|
49
50
|
"plugins/update_feed.rb",
|
50
51
|
"public/css/jquery.jgrowl.css",
|
51
|
-
"public/css/phone.css",
|
52
52
|
"public/css/screen.css",
|
53
53
|
"public/js/jquery-1.3.2.min.js",
|
54
54
|
"public/js/jquery.cookie.js",
|
data/public/css/screen.css
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
body {
|
2
|
-
font-
|
2
|
+
font-size : 1em;
|
3
|
+
line-height : 1.5em;
|
3
4
|
}
|
4
5
|
|
5
6
|
img {
|
@@ -8,7 +9,7 @@ img {
|
|
8
9
|
|
9
10
|
#urls {
|
10
11
|
list-style-type : none;
|
11
|
-
width :
|
12
|
+
width : 600px;
|
12
13
|
}
|
13
14
|
|
14
15
|
li {
|
@@ -16,13 +17,6 @@ li {
|
|
16
17
|
float : left;
|
17
18
|
padding : 10px 20px 10px 10px;
|
18
19
|
width : 100%;
|
19
|
-
border-bottom : 1px solid #f6f6f6;
|
20
|
-
}
|
21
|
-
|
22
|
-
li.even {
|
23
|
-
background-color : #eee;
|
24
|
-
border-right : 1px solid #ddd;
|
25
|
-
border-bottom : 1px solid #ccc;
|
26
20
|
}
|
27
21
|
|
28
22
|
div.icon {
|
@@ -30,10 +24,12 @@ div.icon {
|
|
30
24
|
margin : 0 0.5em 0 0;
|
31
25
|
}
|
32
26
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
27
|
+
a:link {
|
28
|
+
color : #000;
|
29
|
+
}
|
30
|
+
|
31
|
+
a:visited {
|
32
|
+
color : #808080;
|
37
33
|
}
|
38
34
|
|
39
35
|
a:link, a:visited, a:active {
|
@@ -44,6 +40,12 @@ a:hover {
|
|
44
40
|
text-decoration : underline;
|
45
41
|
}
|
46
42
|
|
43
|
+
div.name {
|
44
|
+
float : left;
|
45
|
+
font-style : italic;
|
46
|
+
margin-right : 0.5em;
|
47
|
+
}
|
48
|
+
|
47
49
|
img.thumb, li object {
|
48
50
|
float : left;
|
49
51
|
margin-right : 10px;
|
@@ -92,3 +94,35 @@ div.jGrowl div.jGrowl-closer {
|
|
92
94
|
float : right;
|
93
95
|
width : auto;
|
94
96
|
}
|
97
|
+
|
98
|
+
/* iphone */
|
99
|
+
@media screen and (max-device-width : 480px) {
|
100
|
+
|
101
|
+
a.feed {
|
102
|
+
display : none;
|
103
|
+
}
|
104
|
+
|
105
|
+
body {
|
106
|
+
margin : 0;
|
107
|
+
padding : 0;
|
108
|
+
}
|
109
|
+
|
110
|
+
#urls {
|
111
|
+
margin : 0;
|
112
|
+
padding-left : 0;
|
113
|
+
width : 290px;
|
114
|
+
}
|
115
|
+
|
116
|
+
#urls li {
|
117
|
+
overflow : hidden;
|
118
|
+
}
|
119
|
+
|
120
|
+
input#q {
|
121
|
+
width : 130px;
|
122
|
+
}
|
123
|
+
|
124
|
+
input#url {
|
125
|
+
width : 160px;
|
126
|
+
}
|
127
|
+
|
128
|
+
}
|
data/public/js/js.js
CHANGED
@@ -1,23 +1,46 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
1
3
|
var Murlsh = {};
|
2
4
|
|
3
|
-
Murlsh.
|
4
|
-
|
5
|
+
Murlsh.tag = function(name, attr, text) {
|
6
|
+
var klass;
|
7
|
+
var result = $('<' + name + ' />');
|
8
|
+
|
9
|
+
if (attr) {
|
10
|
+
if (attr.klass) {
|
11
|
+
klass = attr.klass;
|
12
|
+
delete attr.klass;
|
13
|
+
}
|
14
|
+
result.attr(attr);
|
15
|
+
}
|
16
|
+
|
17
|
+
if (text) {
|
18
|
+
result.text(text);
|
19
|
+
}
|
20
|
+
|
21
|
+
if (klass) {
|
22
|
+
result.addClass(klass);
|
23
|
+
}
|
24
|
+
|
25
|
+
return result;
|
26
|
+
};
|
27
|
+
|
28
|
+
Murlsh.img = function(src, text) {
|
29
|
+
text = text || '';
|
30
|
+
return Murlsh.tag('img', {
|
5
31
|
src : src,
|
6
32
|
alt : text,
|
7
33
|
title : text
|
8
34
|
});
|
9
35
|
};
|
10
36
|
|
11
|
-
Murlsh.
|
12
|
-
|
13
|
-
};
|
14
|
-
|
15
|
-
Murlsh.closer_add = function(x) {
|
16
|
-
var html = (typeof x == 'object') ? $('<div />').append(x).html() : x;
|
37
|
+
Murlsh.closer_add = function(x, header) {
|
38
|
+
var html = (typeof x == 'object') ? Murlsh.tag('div').append(x).html() : x;
|
17
39
|
|
18
40
|
$.jGrowl(html, {
|
19
41
|
closeTemplate : 'X',
|
20
42
|
glue :'before',
|
43
|
+
header : header,
|
21
44
|
sticky : true
|
22
45
|
});
|
23
46
|
};
|
@@ -33,34 +56,40 @@ Murlsh.object_tag = function(data, height, width, params) {
|
|
33
56
|
};
|
34
57
|
|
35
58
|
Murlsh.flickr_thumb = function(d) {
|
36
|
-
var
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
zoom
|
41
|
-
|
42
|
-
|
43
|
-
|
59
|
+
var photo = d.photo;
|
60
|
+
if (d.stat == 'ok') {
|
61
|
+
var base = 'http://farm' + photo.farm + '.static.flickr.com/' +
|
62
|
+
photo.server + '/' + photo.id + '_';
|
63
|
+
var zoom;
|
64
|
+
if (photo.originalsecret) {
|
65
|
+
zoom = base + photo.originalsecret + '_o.' + photo.originalformat;
|
66
|
+
} else {
|
67
|
+
zoom = base + photo.secret + '_m.jpg';
|
68
|
+
}
|
44
69
|
|
45
|
-
|
46
|
-
|
47
|
-
|
70
|
+
var owner = photo.owner;
|
71
|
+
return Murlsh.img(base + photo.secret + '_s.jpg',
|
72
|
+
photo.title._content +
|
73
|
+
(owner && owner.username ? ' by ' + owner.username : '')
|
74
|
+
).addClass('thumb flickr').data('zoom', zoom);
|
75
|
+
}
|
48
76
|
};
|
49
77
|
|
50
78
|
Murlsh.flickr_click = function() {
|
51
|
-
Murlsh.closer_add(Murlsh.
|
79
|
+
Murlsh.closer_add(Murlsh.img($(this).data('zoom')));
|
52
80
|
};
|
53
81
|
|
54
|
-
Murlsh.
|
55
|
-
return Murlsh.
|
82
|
+
Murlsh.img_thumb = function(prefix, ext) {
|
83
|
+
return Murlsh.img(prefix + 'th.' +
|
84
|
+
(ext.match(/^pdf$/i) ? 'png' : ext)).addClass('thumb');
|
56
85
|
};
|
57
86
|
|
58
|
-
Murlsh.
|
59
|
-
Murlsh.closer_add(Murlsh.
|
87
|
+
Murlsh.img_click = function() {
|
88
|
+
Murlsh.closer_add(Murlsh.img($(this).data('href')));
|
60
89
|
};
|
61
90
|
|
62
91
|
Murlsh.vimeo_thumb = function(d) {
|
63
|
-
return Murlsh.
|
92
|
+
return Murlsh.img(d.thumbnail_url, d.title).addClass('thumb vimeo').attr({
|
64
93
|
height : d.thumbnail_height,
|
65
94
|
width : d.thumbnail_width
|
66
95
|
});
|
@@ -71,7 +100,7 @@ Murlsh.vimeo_click = function() {
|
|
71
100
|
};
|
72
101
|
|
73
102
|
Murlsh.youtube_thumb = function(id) {
|
74
|
-
return Murlsh.
|
103
|
+
return Murlsh.img('http://img.youtube.com/vi/' + id + '/1.jpg',
|
75
104
|
'click to watch').addClass('thumb youtube').data('id', id);
|
76
105
|
};
|
77
106
|
|
@@ -81,109 +110,99 @@ Murlsh.youtube_click = function() {
|
|
81
110
|
Murlsh.closer_add(Murlsh.object_tag(movie, 344, 425, [{ name : 'movie', value : movie }]));
|
82
111
|
};
|
83
112
|
|
113
|
+
Murlsh.thumb_insert = function(img, click_function, a) {
|
114
|
+
if (img) {
|
115
|
+
if (Murlsh.is_iphone()) {
|
116
|
+
a.prepend(img);
|
117
|
+
} else {
|
118
|
+
a.before(img.click(click_function));
|
119
|
+
}
|
120
|
+
}
|
121
|
+
};
|
122
|
+
|
84
123
|
Murlsh.is_iphone = function() {
|
85
124
|
return navigator.userAgent.match(/i(phone|pod)/i);
|
86
125
|
};
|
87
126
|
|
127
|
+
Murlsh.href_res = {
|
128
|
+
flickr :
|
129
|
+
/^http:\/\/(?:www\.)?flickr\.com\/photos\/[^\/]+?\/([0-9]+)/i,
|
130
|
+
imageshack :
|
131
|
+
/^(http:\/\/img\d+\.imageshack\.us\/img\d+\/\d+\/\w+\.)(jpe?g|gif|png)$/i,
|
132
|
+
mp3 :
|
133
|
+
/.*\.mp3$/i,
|
134
|
+
s3 :
|
135
|
+
/^(http:\/\/static\.mmb\.s3\.amazonaws.com\/.*\.)(jpe?g|gif|pdf|png)$/i,
|
136
|
+
vimeo :
|
137
|
+
/^http:\/\/(?:www\.)?vimeo\.com\/([0-9]+)$/i,
|
138
|
+
youtube :
|
139
|
+
/^http:\/\/(?:(?:www|uk)\.)?youtube\.com\/watch\?v=(.+?)(?:&|$)/i
|
140
|
+
};
|
141
|
+
|
88
142
|
Murlsh.add_extra = function() {
|
89
143
|
var this_a = $(this);
|
90
144
|
|
91
145
|
var href = $(this).attr('href');
|
92
146
|
|
93
|
-
var
|
94
|
-
|
95
|
-
href);
|
96
|
-
|
97
|
-
var imageshack_match =
|
98
|
-
/^(http:\/\/img\d+\.imageshack\.us\/img\d+\/\d+\/\w+\.)(jpg|gif|png)$/i.exec(
|
99
|
-
href);
|
100
|
-
|
101
|
-
var mp3_match = /.*\.mp3$/i.exec(href);
|
102
|
-
|
103
|
-
var s3_match =
|
104
|
-
/^(http:\/\/static\.mmb\.s3\.amazonaws.com\/.*\.)(jpg|gif|png)$/i.exec(
|
105
|
-
href);
|
106
|
-
|
107
|
-
var vimeo_match = /^http:\/\/(?:www\.)?vimeo\.com\/([0-9]+)$/i.exec(href);
|
108
|
-
|
109
|
-
var youtube_match =
|
110
|
-
/^http:\/\/(?:(?:www|uk)\.)?youtube\.com\/watch\?v=(.+?)(?:&|$)/i.exec(
|
111
|
-
href);
|
147
|
+
var match = {};
|
148
|
+
$.each(Murlsh.href_res, function(x, re) { return !(match[x] = re.exec(href)); });
|
112
149
|
|
113
150
|
var thumb;
|
114
|
-
var thumb_insert_func;
|
115
151
|
|
116
|
-
if (
|
117
|
-
|
118
|
-
|
119
|
-
if (Murlsh.is_iphone()) {
|
120
|
-
this_a.prepend(img);
|
121
|
-
} else {
|
122
|
-
this_a.before(img.click(Murlsh.flickr_click));
|
123
|
-
}
|
152
|
+
if (match.flickr) {
|
153
|
+
var callback = function(d) {
|
154
|
+
Murlsh.thumb_insert(Murlsh.flickr_thumb(d), Murlsh.flickr_click, this_a);
|
124
155
|
};
|
125
156
|
$.getJSON('http://api.flickr.com/services/rest/?api_key=d04e574aaf11bf2e1c03cba4ee7e5725&method=flickr.photos.getinfo&format=json&photo_id=' +
|
126
|
-
|
127
|
-
} else if (
|
128
|
-
thumb = Murlsh.
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
} else {
|
133
|
-
this_a.before(thumb.data('href', imageshack_match[0]).click(
|
134
|
-
Murlsh.imageshack_click));
|
135
|
-
}
|
136
|
-
} else if (mp3_match) {
|
157
|
+
match.flickr[1] + '&jsoncallback=?', callback);
|
158
|
+
} else if (match.imageshack) {
|
159
|
+
thumb = Murlsh.img_thumb(match.imageshack[1], match.imageshack[2]).data(
|
160
|
+
'href', match.imageshack[0]);
|
161
|
+
Murlsh.thumb_insert(thumb, Murlsh.img_click, this_a.html('imageshack.us'));
|
162
|
+
} else if (match.mp3) {
|
137
163
|
var swf = 'swf/player_mp3_mini.swf';
|
138
164
|
$(this).before(Murlsh.object_tag(swf, 20, 200, [
|
139
165
|
{ name : 'bgcolor', value : '#000000' },
|
140
|
-
{ name : 'FlashVars', value : 'mp3=' +
|
166
|
+
{ name : 'FlashVars', value : 'mp3=' + match.mp3[0] },
|
141
167
|
{ name : 'movie', value : swf }
|
142
168
|
]));
|
143
|
-
} else if (
|
144
|
-
thumb = Murlsh.
|
145
|
-
if (
|
146
|
-
|
169
|
+
} else if (match.s3) {
|
170
|
+
thumb = Murlsh.img_thumb(match.s3[1], match.s3[2]);
|
171
|
+
if (match.s3[2].match(/^pdf$/i)) {
|
172
|
+
this_a.before(thumb).html('pdf');
|
147
173
|
} else {
|
148
|
-
this_a.html('link');
|
149
|
-
this_a.before(thumb.data('href', s3_match[0]).click(
|
150
|
-
Murlsh.imageshack_click));
|
151
|
-
}
|
152
|
-
} else if (vimeo_match) {
|
153
|
-
thumb_insert_func = function vimeo_thumb_insert(d) {
|
154
|
-
var img = Murlsh.vimeo_thumb(d);
|
155
174
|
if (Murlsh.is_iphone()) {
|
156
|
-
this_a.
|
175
|
+
this_a.html(thumb);
|
157
176
|
} else {
|
158
|
-
this_a.
|
159
|
-
|
177
|
+
this_a.html('link');
|
178
|
+
this_a.before(thumb.data('href', match.s3[0]).click(Murlsh.img_click));
|
160
179
|
}
|
180
|
+
}
|
181
|
+
} else if (match.vimeo) {
|
182
|
+
var callback = function(d) {
|
183
|
+
var thumb = Murlsh.vimeo_thumb(d).data('embed_html', d.html);
|
184
|
+
Murlsh.thumb_insert(thumb, Murlsh.vimeo_click, this_a);
|
161
185
|
};
|
162
186
|
$.getJSON('http://vimeo.com/api/oembed.json?url=http%3A//vimeo.com/' +
|
163
|
-
|
164
|
-
} else if (
|
165
|
-
|
166
|
-
|
167
|
-
$(this).prepend(img);
|
168
|
-
} else {
|
169
|
-
$(this).before(img.click(Murlsh.youtube_click));
|
170
|
-
}
|
187
|
+
match.vimeo[1] + '&callback=?', callback);
|
188
|
+
} else if (match.youtube) {
|
189
|
+
thumb = Murlsh.youtube_thumb(match.youtube[1]);
|
190
|
+
Murlsh.thumb_insert(thumb, Murlsh.youtube_click, this_a);
|
171
191
|
}
|
172
192
|
};
|
173
193
|
|
174
194
|
Murlsh.format_li = function(d) {
|
175
|
-
var li =
|
176
|
-
d.title));
|
195
|
+
var li = Murlsh.tag('li').append(Murlsh.tag('a', { href : d.url }, d.title));
|
177
196
|
|
178
197
|
if (d.name) {
|
179
|
-
li.prepend(
|
198
|
+
li.prepend(Murlsh.tag('div', { klass : 'name' }, d.name));
|
180
199
|
}
|
181
200
|
|
182
201
|
var icon_size = 32;
|
183
202
|
|
184
203
|
if (d.email) {
|
185
|
-
li.prepend(
|
186
|
-
Murlsh.
|
204
|
+
li.prepend(Murlsh.tag('div', { klass : 'icon' }).append(
|
205
|
+
Murlsh.img(
|
187
206
|
'http://www.gravatar.com/avatar/' + d.email + '?s=' + icon_size,
|
188
207
|
d.name).attr({
|
189
208
|
width : icon_size,
|
@@ -194,29 +213,31 @@ Murlsh.format_li = function(d) {
|
|
194
213
|
return li;
|
195
214
|
};
|
196
215
|
|
197
|
-
Murlsh.
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
}
|
216
|
+
Murlsh.iphone_init = function() {
|
217
|
+
window.onorientationchange = function() {
|
218
|
+
if (window.orientation === 0 || window.orientation == 180) {
|
219
|
+
$('#urls').width(290);
|
220
|
+
} else {
|
221
|
+
$('#urls').width(450);
|
222
|
+
}
|
223
|
+
};
|
224
|
+
|
225
|
+
window.onorientationchange();
|
204
226
|
|
205
|
-
|
227
|
+
$('#urls li:first').prepend(Murlsh.tag('a', { href : '#bottom' }, 'bottom'));
|
228
|
+
$('#urls li:last').append(Murlsh.tag('a', { href : '#urls' }, 'top'));
|
229
|
+
};
|
206
230
|
|
207
231
|
$(document).ready(function() {
|
208
232
|
if (Murlsh.is_iphone()) {
|
209
|
-
Murlsh.
|
210
|
-
$('#urls li:first').prepend($('<a />').attr('href', '#bottom').text(
|
211
|
-
'bottom'));
|
212
|
-
$('#urls li:last').append($('<a />').attr('href', '#urls').text('top'));
|
233
|
+
Murlsh.iphone_init();
|
213
234
|
}
|
214
|
-
$('a').map(Murlsh.add_extra);
|
215
|
-
$('#urls li:even').addClass('even');
|
235
|
+
$('#urls a').map(Murlsh.add_extra);
|
216
236
|
|
217
237
|
$('#submit').click(function() {
|
218
238
|
$.post('url', {
|
219
239
|
url : $('#url').val(),
|
240
|
+
via : $('#via').val(),
|
220
241
|
auth : $('#auth').val()
|
221
242
|
}, function(d) {
|
222
243
|
$.each(d, function(i, v) {
|
@@ -225,6 +246,7 @@ $(document).ready(function() {
|
|
225
246
|
$(li).children('a:first').map(Murlsh.add_extra);
|
226
247
|
});
|
227
248
|
$('#url').val('');
|
249
|
+
$('#via').val('');
|
228
250
|
}, 'json');
|
229
251
|
});
|
230
252
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: murlsh
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew M. Boedicker
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-12-13 00:00:00 -05:00
|
13
13
|
default_executable: murlsh
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -107,6 +107,7 @@ files:
|
|
107
107
|
- lib/murlsh/get_content_type.rb
|
108
108
|
- lib/murlsh/get_title.rb
|
109
109
|
- lib/murlsh/markup.rb
|
110
|
+
- lib/murlsh/openlock.rb
|
110
111
|
- lib/murlsh/plugin.rb
|
111
112
|
- lib/murlsh/referrer.rb
|
112
113
|
- lib/murlsh/sqlite3_adapter.rb
|
@@ -121,7 +122,6 @@ files:
|
|
121
122
|
- plugins/lookup_content_type_title.rb
|
122
123
|
- plugins/update_feed.rb
|
123
124
|
- public/css/jquery.jgrowl.css
|
124
|
-
- public/css/phone.css
|
125
125
|
- public/css/screen.css
|
126
126
|
- public/js/jquery-1.3.2.min.js
|
127
127
|
- public/js/jquery.cookie.js
|
data/public/css/phone.css
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
a.feed {
|
2
|
-
display : none;
|
3
|
-
}
|
4
|
-
|
5
|
-
body {
|
6
|
-
margin : 0;
|
7
|
-
padding : 0;
|
8
|
-
}
|
9
|
-
|
10
|
-
#urls {
|
11
|
-
margin : 0;
|
12
|
-
padding-left : 0;
|
13
|
-
width : 290px;
|
14
|
-
}
|
15
|
-
|
16
|
-
#urls li {
|
17
|
-
overflow : hidden;
|
18
|
-
}
|
19
|
-
|
20
|
-
input#q {
|
21
|
-
width : 130px;
|
22
|
-
}
|
23
|
-
|
24
|
-
input#url {
|
25
|
-
width : 160px;
|
26
|
-
}
|