2 |
3 |
4 | Facets Live! The revolution is application logic delivery.
5 |
6 |
7 |
8 |

9 |
10 | $ sudo gem install live
11 |
12 |

13 |
14 | require 'live'
15 | require 'live/username/script.rb'
16 |
17 |
18 |
19 |
20 | We take you now to live action happening in your neighborhood.
21 |
22 |
23 |
58 |
59 |
60 | Look deep into my eyes.
61 |
62 |
63 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/config/prime/scripts.yml:
--------------------------------------------------------------------------------
1 | ---
2 | - owner: facets
3 | name: instance
4 | code: |
5 |
6 | module Kernel
7 | # Returns an instance of Instance class which provides internal
8 | # access to an object in a very object-oriented fashion.
9 | def instance
10 | Instance.new(self)
11 | end
12 | end
13 |
14 | # = Instance Class
15 | #
16 | # class Friend
17 | # attr_accessor :name, :age, :phone
18 | # def initialize(name, age, phone)
19 | # @name, @age, @phone = name, age, phone
20 | # end
21 | # end
22 | #
23 | # f1 = Friend.new("John", 30, "555-1212")
24 | # p f1.instance
25 | # f1.instance.update({:name=>'Jerry'})
26 | # p f1.instance
27 | #
28 | class Instance
29 |
30 | include Enumerable
31 |
32 | def initialize(delegate)
33 | @delegate = delegate
34 | end
35 |
36 | def instance_delegate
37 | @delegate
38 | end
39 |
40 | def each
41 | @delegate.instance_variables.each do |name|
42 | yield(name[1..-1].to_sym, @delegate.instance_variable_get(name))
43 | end
44 | end
45 |
46 | def to_hash
47 | h = {}
48 | each do |name, value|
49 | h[name] = value
50 | end
51 | h
52 | end
53 |
54 | def [](name)
55 | name = atize(name)
56 | @delegate.instance_variable_get(name)
57 | end
58 |
59 | def []=(name, value)
60 | name = atize(name)
61 | @delegate.instance_variable_set(name,value)
62 | end
63 |
64 | def <<(pair)
65 | name, value = *pair
66 | name = atize(name)
67 | @delegate.instance_variable_set(name, value)
68 | end
69 |
70 | # (See also: Kernel#populate, which uses accessor method rather than setting instance variables directly.)
71 | def update(hash)
72 | hash.each do |pair|
73 | self << pair
74 | end
75 | end
76 |
77 | def keys
78 | @delegate.instance_variables.collect do |name|
79 | name[1..-1].to_sym
80 | end
81 | end
82 |
83 | def names
84 | @delegate.instance_variables.collect do |name|
85 | name[1..-1]
86 | end
87 | end
88 |
89 | def values
90 | @delegate.instance_variables.collect do |name|
91 | @delegate.instance_variable_get(name)
92 | end
93 | end
94 |
95 | private
96 |
97 | def atize(name)
98 | name !~ /^@/ ? "@#{name}" : name
99 | end
100 |
101 | end
102 |
103 |
--------------------------------------------------------------------------------
/lib/live/public/css/screen/buttons.css:
--------------------------------------------------------------------------------
1 | /* BUTTONS */
2 |
3 | .buttons a, .buttons button {
4 | display:block;
5 | float:left;
6 | margin:0 7px 0 0;
7 | background-color:#f5f5f5;
8 | border:1px solid #dedede;
9 | border-top:1px solid #eee;
10 | border-left:1px solid #eee;
11 |
12 | font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif;
13 | font-size:100%;
14 | line-height:130%;
15 | text-decoration:none;
16 | font-weight:bold;
17 | color:#565656;
18 | cursor:pointer;
19 | padding:5px 10px 6px 7px; /* Links */
20 | }
21 | .buttons button{
22 | width:auto;
23 | overflow:visible;
24 | padding:4px 10px 3px 7px; /* IE6 */
25 | }
26 | .buttons button[type]{
27 | padding:5px 10px 5px 7px; /* Firefox */
28 | line-height:17px; /* Safari */
29 | }
30 | *:first-child+html button[type]{
31 | padding:4px 10px 3px 7px; /* IE7 */
32 | }
33 | .buttons button img, .buttons a img{
34 | margin:0 3px -3px 0 !important;
35 | padding:0;
36 | border:none;
37 | width:16px;
38 | height:16px;
39 | }
40 | .buttons label {
41 | margin:0 7px 0 0;
42 | background-color:#f5f5f5;
43 |
44 | font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif;
45 | font-size:100%;
46 | line-height:130%;
47 | text-decoration:none;
48 | font-weight:bold;
49 | color:#565656;
50 | padding:5px 10px 6px 7px; /* Links */
51 | }
52 | /* STANDARD */
53 |
54 | button:hover, .buttons a:hover{
55 | background-color:#dff4ff;
56 | border:1px solid #c2e1ef;
57 | color:#336699;
58 | }
59 | .buttons a:active{
60 | background-color:#6299c5;
61 | border:1px solid #6299c5;
62 | color:#fff;
63 | }
64 |
65 | /* POSITIVE */
66 |
67 | button.positive, .buttons a.positive{
68 | color:#529214;
69 | }
70 | .buttons a.positive:hover, button.positive:hover{
71 | background-color:#E6EFC2;
72 | border:1px solid #C6D880;
73 | color:#529214;
74 | }
75 | .buttons a.positive:active{
76 | background-color:#529214;
77 | border:1px solid #529214;
78 | color:#fff;
79 | }
80 |
81 | /* NEGATIVE */
82 |
83 | .buttons a.negative, button.negative{
84 | color:#d12f19;
85 | }
86 | .buttons a.negative:hover, button.negative:hover{
87 | background:#fbe3e4;
88 | border:1px solid #fbc2c4;
89 | color:#d12f19;
90 | }
91 | .buttons a.negative:active{
92 | background-color:#d12f19;
93 | border:1px solid #d12f19;
94 | color:#fff;
95 | }
96 |
97 | input {
98 | font-size: 100%;
99 | font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif;
100 | color:#565656;
101 | }
102 |
103 |
--------------------------------------------------------------------------------
/lib/live/views/edit.erb:
--------------------------------------------------------------------------------
1 |
70 |
71 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/lib/live/views/layout.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Facets Live! <%= @title %>
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
32 |
33 |
34 |
35 |
36 |
37 |
70 |
71 | <% if flash[:message] %>
72 |
73 |
<%= flash[:message] %>
74 |
75 | <% end %>
76 |
77 | <%= yield %>
78 |
79 |
80 |
81 |
82 |
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/lib/live/models/script.rb:
--------------------------------------------------------------------------------
1 | require 'coderay'
2 |
3 | module Live
4 |
5 | #
6 | class Script < Sequel::Model(:scripts)
7 |
8 | #
9 | def self.popular(limit=10)
10 | order(:downloads).limit(limit)
11 | end
12 |
13 | #
14 | def self.newest(limit=10)
15 | #order(:created).distinct(:owner, :name).limit(limit)
16 | filter(:archive=>nil).order(:modified).limit(limit)
17 | end
18 |
19 | #
20 | def self.latest(limit=10)
21 | #.order(:modified).distinct(:owner, :name).limit(limit)
22 | filter(:archive=>nil).order(:modified).limit(limit)
23 | end
24 |
25 | # Create the scripts table.
26 | def self.create_table
27 | database.create_table(table_name) do |t|
28 | t.primary_key :id
29 | t.varchar :owner, :size=>50 # owner of script
30 | t.varchar :name, :size=>50 # name of script
31 | t.integer :version, :default=>1 # version number
32 | t.varchar :description # brief description
33 | t.text :code # script's source code
34 | t.text :test # unit test code
35 | t.integer :rating # rating # TODO: keep?
36 | t.integer :downloads # number of times this script has been required/loaded (less cache)
37 | t.timestamp :downloaded, :null=>true # date and time of last require/load
38 | t.varchar :modifier # last person to modify the script
39 | t.timestamp :modified # date and time the script was last modified
40 | t.timestamp :created # date and time the script was created
41 | t.integer :copy # id of script from which this script was copied
42 | t.integer :archive # id of the current script; NULL if this is the current script
43 | end
44 | end
45 |
46 | # Drop table from database.
47 | def self.drop_table
48 | database.drop_table(table_name)
49 | end
50 |
51 | # Script save creates a new record in the table, in order to keep a history.
52 | #--
53 | # TODO: If nothing has changed there is no need to create a new record.
54 | #
55 | # TODO: compressing +code+ and +test+ would save space, but what about searching?
56 | #++
57 | def save(bump=false)
58 | now = Time.now
59 |
60 | if exists?
61 | if bump
62 | # archive current version
63 | h = self.values.dup
64 | h.delete(:id)
65 | history = self.class.new(h)
66 | history.archive = id
67 | history.save
68 | end
69 | else
70 | self.created = now
71 | end
72 |
73 | if bump
74 | self.version = version.to_i + 1
75 | end
76 |
77 | self.modified = now
78 |
79 | super()
80 | end
81 |
82 | #
83 | #def owner_name
84 | # "#{owner}/#{name}"
85 | #end
86 |
87 | #
88 | def code_highlighted
89 | CodeRay.scan(code, :ruby).div
90 | end
91 |
92 | #
93 | def test_highlighted
94 | CodeRay.scan(test, :ruby).div
95 | end
96 |
97 | #
98 | def track(user_id)
99 | Track[:user_id=>user_id, :owner=>owner, :name=>name]
100 | end
101 |
102 | end
103 |
104 | end
105 |
106 |
--------------------------------------------------------------------------------
/lib/live/public/css/screen.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif;
3 | color: #565656;
4 | }
5 |
6 | h1 { font-size: 150%; }
7 | h2 { font-size: 133%; }
8 | h3 { font-size: 125%; }
9 |
10 | #header {
11 | background: url(/img/top.png) repeat-x white;
12 | height: 130px;
13 | padding: 0;
14 | text-align: left;
15 | margin-bottom: 20px;
16 | }
17 |
18 | #content {
19 | margin: 1em;
20 | padding: 1em;
21 | background: #fff;
22 | -moz-border-radius: 3em;
23 | -webkit-border-radius: 3em;
24 | border-radius: 3em;
25 | }
26 |
27 | #footer {
28 | margin: 0;
29 | padding: 20px;
30 | background: url(/img/gradiant-up.jpg) bottom repeat-x #fff;
31 | min-height: 100px;
32 | }
33 |
34 | .page {
35 | width: 960px;
36 | margin: 0 auto;
37 | position: relative;
38 | }
39 |
40 | .flash {
41 | position: absolute;
42 | top: 100px;
43 | width: 100%;
44 | text-align: center;
45 | z-index: 10;
46 | }
47 |
48 | .flash div {
49 | width: 960px;
50 | margin: 0 auto;
51 | -moz-border-radius: 10px;
52 | -webkit-border-radius: 10px;
53 | border-radius: 10px;
54 | background: #111;
55 | opacity: 0.8;
56 | padding: 20px;
57 | color: white;
58 | font-weight: bold;
59 | }
60 |
61 | .monitor {
62 | background: #ccc;
63 | border: 1px solid #ccc;
64 | -moz-border-radius: 5px;
65 | -webkit-border-radius: 5px;
66 | border-radius: 5px;
67 | margin: 20px 0; padding: 20px;
68 | }
69 |
70 | .instructions {
71 | border: 1px solid #ccc;
72 | padding: 5px;
73 | background: #cfc;
74 | color: black;
75 | border: 1px solid #ccc;
76 | -moz-border-radius: 5px;
77 | -webkit-border-radius: 5px;
78 | border-radius: 5px;
79 | }
80 |
81 | .instructions pre {
82 | color #555;
83 | font-weight: bold;
84 | }
85 |
86 | .copyright {
87 | font-size: 0.8em;
88 | font-weight: normal;
89 | }
90 |
91 | .CodeRay {
92 | min-height: 400px;
93 | border: 1px solid #ccc;
94 | padding: 10px;
95 | }
96 |
97 |
98 |
99 | #sign-form td {
100 | padding: 5px 0;
101 | }
102 |
103 | /* INFO */
104 |
105 | #info {
106 | position: absolute;
107 | right: 0;
108 | top: 10px;
109 | }
110 |
111 | #info .menu {
112 | margin: 0 0 10px 0;
113 | }
114 |
115 | #info a {
116 | font-size: 14px;
117 | font-weight: bold;
118 | padding: 5px;
119 | text-decoration: none;
120 | color: white;
121 | }
122 |
123 | #info a:hover {
124 | background: red;
125 | opacity: 0.8;
126 | -moz-border-radius: 8px;
127 | -webkit-border-radius: 8px;
128 | border-radius: 8px;
129 | }
130 |
131 | #info input {
132 | width: 280px;
133 | padding: 3px;
134 | -moz-border-radius: 8px;
135 | -webkit-border-radius: 8px;
136 | border-radius: 8px;
137 | }
138 |
139 | /* SCRIPT VIEW & EDIT */
140 |
141 | #script {
142 |
143 | }
144 |
145 | #script .name {
146 | font-weight: bold;
147 | margin: 5px 0;
148 | }
149 |
150 | #script .name a {
151 | font-size: 0.8em;
152 | text-decoration: none;
153 | }
154 |
155 | #script .ruby {
156 | border: 1px solid #ccc;
157 | width: 100%;
158 | min-height: 300px;
159 | padding: 10px;
160 | }
161 |
162 | /* BROWSE & SEARCH */
163 |
164 | #script-browse a {
165 | font-weight: bold;
166 | text-decoration: none;
167 | }
168 |
169 | #script-browse-index {
170 | padding: 20px;
171 | border: 1px solid #ccc;
172 | margin: 20px 0;
173 | }
174 |
175 | #script-browse-counts {
176 | margin: 20px 0;
177 | }
178 |
179 | #script-browse-list {
180 | padding: 20px;
181 | border: 1px solid #ccc;
182 | }
183 |
184 | #script-browse-list {
185 | padding: 5px;
186 | }
187 |
188 | #script-browse-list li {
189 | margin: 0;
190 | padding: 10px 0;
191 | }
192 |
193 | .labels {
194 | padding: 5px;
195 | color: #565656;
196 | font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif;
197 | }
198 |
199 |
--------------------------------------------------------------------------------
/lib/live/public/js/jquery.ui.stars/ui.stars.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery UI Stars v2.1.1
3 | * http://plugins.jquery.com/project/Star_Rating_widget
4 | *
5 | * Copyright (c) 2009 Orkan (orkans@gmail.com)
6 | * Dual licensed under the MIT and GPL licenses.
7 | * http://docs.jquery.com/License
8 | *
9 | * $Rev: 114 $
10 | * $Date:: 2009-06-12 #$
11 | * $Build: 32 (2009-06-12)
12 | *
13 | * Depends:
14 | * ui.core.js
15 | *
16 | */
17 | (function(A){A.widget("ui.stars",{_init:function(){var B=this,E=this.options,F=0;E.isSelect=E.inputType=="select";this.$form=A(this.element).closest("form");this.$selec=E.isSelect?A("select",this.element):null;this.$rboxs=E.isSelect?A("option",this.$selec):A(":radio",this.element);this.$stars=this.$rboxs.map(function(I){var J={value:this.value,title:(E.isSelect?this.text:this.title)||this.value,isDefault:(E.isSelect&&this.defaultSelected)||this.defaultChecked};if(I==0){E.split=typeof E.split!="number"?0:E.split;E.val2id=[];E.id2val=[];E.id2title=[];E.name=E.isSelect?B.$selec.get(0).name:this.name;E.disabled=E.disabled||(E.isSelect?A(B.$selec).attr("disabled"):A(this).attr("disabled"))}if(J.value==E.cancelValue){E.cancelTitle=J.title;return null}E.val2id[J.value]=F;E.id2val[F]=J.value;E.id2title[F]=J.title;if(J.isDefault){E.checked=F;E.value=E.defaultValue=J.value;E.title=J.title}var H=A("").addClass(E.starClass);var K=A("").attr("title",E.showTitles?J.title:"").text(J.value);if(E.split){var G=(F%E.split);var L=Math.floor(E.starWidth/E.split);H.width(L);K.css("margin-left","-"+(G*L)+"px")}F++;return H.append(K).get(0)});E.items=F;E.isSelect?this.$selec.remove():this.$rboxs.remove();this.$cancel=A("").addClass(E.cancelClass).append(A("").attr("title",E.showTitles?E.cancelTitle:"").text(E.cancelValue));E.cancelShow&=!E.disabled&&!E.oneVoteOnly;E.cancelShow&&this.element.append(this.$cancel);this.element.append(this.$stars);if(E.checked===undefined){E.checked=-1;E.value=E.defaultValue=E.cancelValue;E.title=""}this.$value=A('');this.element.append(this.$value);this.$stars.bind("click.stars",function(H){if(!E.forceSelect&&E.disabled){return false}var G=B.$stars.index(this);E.checked=G;E.value=E.id2val[G];E.title=E.id2title[G];B.$value.attr({disabled:E.disabled?"disabled":"",value:E.value});C(G,false);B._disableCancel();!E.forceSelect&&B.callback(H,"star")}).bind("mouseover.stars",function(){if(E.disabled){return false}var G=B.$stars.index(this);C(G,true)}).bind("mouseout.stars",function(){if(E.disabled){return false}C(B.options.checked,false)});this.$cancel.bind("click.stars",function(G){if(!E.forceSelect&&(E.disabled||E.value==E.cancelValue)){return false}E.checked=-1;E.value=E.cancelValue;E.title="";B.$value.val(E.value).attr({disabled:"disabled"});D();B._disableCancel();!E.forceSelect&&B.callback(G,"cancel")}).bind("mouseover.stars",function(){if(B._disableCancel()){return false}B.$cancel.addClass(E.cancelHoverClass);D();B._showCap(E.cancelTitle)}).bind("mouseout.stars",function(){if(B._disableCancel()){return false}B.$cancel.removeClass(E.cancelHoverClass);B.$stars.triggerHandler("mouseout.stars")});this.$form.bind("reset.stars",function(){!E.disabled&&B.select(E.defaultValue)});A(window).unload(function(){B.$cancel.unbind(".stars");B.$stars.unbind(".stars");B.$form.unbind(".stars");B.$selec=B.$rboxs=B.$stars=B.$value=B.$cancel=B.$form=null});function C(G,I){if(G!=-1){var J=I?E.starHoverClass:E.starOnClass;var H=I?E.starOnClass:E.starHoverClass;B.$stars.eq(G).prevAll("."+E.starClass).andSelf().removeClass(H).addClass(J);B.$stars.eq(G).nextAll("."+E.starClass).removeClass(E.starHoverClass+" "+E.starOnClass);B._showCap(E.id2title[G])}else{D()}}function D(){B.$stars.removeClass(E.starOnClass+" "+E.starHoverClass);B._showCap("")}this.select(E.value);E.disabled&&this.disable()},_disableCancel:function(){var C=this.options,B=C.disabled||C.oneVoteOnly||(C.value==C.cancelValue);if(B){this.$cancel.removeClass(C.cancelHoverClass).addClass(C.cancelDisabledClass)}else{this.$cancel.removeClass(C.cancelDisabledClass)}this.$cancel.css("opacity",B?0.5:1);return B},_disableAll:function(){var B=this.options;this._disableCancel();if(B.disabled){this.$stars.filter("div").addClass(B.starDisabledClass)}else{this.$stars.filter("div").removeClass(B.starDisabledClass)}},_showCap:function(B){var C=this.options;if(C.captionEl){C.captionEl.text(B)}},value:function(){return this.options.value},select:function(D){var C=this.options,B=(D==C.cancelValue)?this.$cancel:this.$stars.eq(C.val2id[D]);C.forceSelect=true;B.triggerHandler("click.stars");C.forceSelect=false},selectID:function(D){var C=this.options,B=(D==-1)?this.$cancel:this.$stars.eq(D);C.forceSelect=true;B.triggerHandler("click.stars");C.forceSelect=false},enable:function(){this.options.disabled=false;this._disableAll()},disable:function(){this.options.disabled=true;this._disableAll()},destroy:function(){this.options.isSelect?this.$selec.appendTo(this.element):this.$rboxs.appendTo(this.element);this.$form.unbind(".stars");this.$cancel.unbind(".stars").remove();this.$stars.unbind(".stars").remove();this.$value.remove();this.element.unbind(".stars").removeData("stars")},callback:function(C,B){var D=this.options;D.callback&&D.callback(this,B,D.value,C);D.oneVoteOnly&&!D.disabled&&this.disable()}});A.extend(A.ui.stars,{version:"2.1.1",getter:"value",defaults:{inputType:"radio",split:0,disabled:false,cancelTitle:"Cancel Rating",cancelValue:0,cancelShow:true,oneVoteOnly:false,showTitles:false,captionEl:null,callback:null,starWidth:16,cancelClass:"ui-stars-cancel",starClass:"ui-stars-star",starOnClass:"ui-stars-star-on",starHoverClass:"ui-stars-star-hover",starDisabledClass:"ui-stars-star-disabled",cancelHoverClass:"ui-stars-cancel-hover",cancelDisabledClass:"ui-stars-cancel-disabled"}})})(jQuery);
--------------------------------------------------------------------------------
/lib/live/server.rb:
--------------------------------------------------------------------------------
1 | require 'sinatra/base'
2 | #require 'sinatra_warden'
3 | require 'rack/flash'
4 | require 'live/auth'
5 |
6 | module Live
7 |
8 | # = Facets Live! Sinatra-based Server
9 | #
10 | class Server < Sinatra::Base
11 | enable :sessions #use Rack::Session::Cookie
12 | use Rack::Flash
13 |
14 | include Authentication
15 |
16 | set :root, File.dirname(__FILE__)
17 | set :static, true
18 |
19 | #
20 | get '/' do
21 | @scripts_newest = Script.newest
22 | @scripts_latest = Script.latest
23 | @scripts_popular = Script.popular
24 | erb :index
25 | end
26 |
27 | # Sign up for new account.
28 | get '/register' do
29 | @title = "Sign Up"
30 | erb :register
31 | end
32 |
33 | # Sign up for new account.
34 | post '/register' do
35 | if params[:password] != params[:confirm]
36 | flash[:message] = "Oops! Could not confirm password."
37 | redirect(back)
38 | end
39 |
40 | @user = ::User.new
41 |
42 | @user.username = params[:username]
43 | @user.name = params[:name]
44 | @user.email = params[:email]
45 | @user.website = params[:website]
46 |
47 | @user.salt = Digest::SHA1.hexdigest("--#{Time.now.to_f}--#{@user.email}--")
48 |
49 | @user.password = params[:password]
50 |
51 | if @user.save
52 | flash[:message] = 'Account created. Please sign-in.'
53 | redirect '/' #MainController.r(:index)
54 | end
55 | end
56 |
57 | get '/profile' do
58 | authorize!('/login')
59 | @title = 'Profile'
60 | erb :profile
61 | end
62 |
63 | #
64 | post '/profile' do
65 | authorize!('/login')
66 |
67 | if params[:password] != params[:confirm]
68 | flash[:message] = "Oops! Could not confirm new password."
69 | redirect(back)
70 | end
71 |
72 | user.name = params[:name]
73 | user.email = params[:email]
74 | user.website = params[:website]
75 |
76 | user.username = params[:username] # TODO: remove
77 | user.password = params[:password] if params[:password] && !params[:password].empty?
78 |
79 | if user.save
80 | flash[:message] = 'Profile saved'
81 | redirect "/dashboard"
82 | end
83 | end
84 |
85 | #
86 | get '/login' do
87 | redirect(back) if authorized?
88 | @title = "Sign In"
89 | erb :login
90 | end
91 |
92 | #
93 | post '/login' do
94 | if authorized?
95 | flash[:message] = "Signed In" # TODO: NOT WORKING
96 | redirect '/dashboard'
97 | else
98 | @title = "Sign In"
99 | flash[:message] = "Invalid Credentials"
100 | erb :login
101 | end
102 | end
103 |
104 | #
105 | get '/logout' do
106 | self.user = nil
107 | flash[:message] = "Signed Out"
108 | redirect '/'
109 | end
110 |
111 | #
112 | post '/search' do
113 | @title = "Search"
114 | @criteria = params[:criteria]
115 | if @criteria
116 | @scripts = Script.filter(:archive => nil, :name => /^#{@criteria}/i).order(:name).limit(25)
117 | else
118 | redirect '/browse/A'
119 | end
120 | erb :browse
121 | end
122 |
123 | #
124 | get '/browse/:letter' do
125 | @title = "Browse"
126 | @letter = params[:letter]
127 | if @letter
128 | @scripts = Script.filter(:archive => nil, :name => /^#{@letter}/i).order(:name).limit(25)
129 | else
130 | @scripts = Script.filter(:archive => nil).order(:name).limit(25)
131 | end
132 | erb :browse
133 | end
134 |
135 | #
136 | get '/dashboard' do
137 | authorize!('/login') # must be logged-in
138 |
139 | @title = "Dashboard"
140 | @scripts = Script.filter(:archive => nil, :owner => user.username)
141 | @watchlist = Track.filter(:user_id => user_id, :watch => true) #.limit(20) #paginate?
142 |
143 | erb :dashboard
144 | end
145 |
146 | #
147 | get '/script/:id' do
148 | id = params[:id]
149 | @script = Script[:id=>id]
150 | @track = Track[:user_id=>user_id, :owner=>@script.owner, :name=>@script.name]
151 | erb :script
152 | end
153 |
154 | #
155 | get '/script/:owner/:name' do
156 | owner = params[:owner]
157 | name = params[:name]
158 | @script = Script[:archive=>nil, :owner=>owner, :name=>name]
159 | @track = Track[:user_id=>user_id, :owner=>@script.owner, :name=>@script.name]
160 | erb :script
161 | end
162 |
163 | #
164 | get '/copy/:id/:name' do
165 | authorize!('/login')
166 |
167 | id = params[:id]
168 | name = params[:name]
169 |
170 | script = Script[:name=>name,:owner=>user.username]
171 | if script
172 | flash[:message] = "ERROR! You already have a script named '#{name}'."
173 | redirect(back)
174 | else
175 | orig = Script[:id=>id]
176 | vals = orig.values.dup
177 | vals.delete(:id)
178 | copy = Script.create(vals)
179 | copy.name = name
180 | copy.owner = user.username
181 | copy.version = 1
182 | copy.copy = orig.id
183 | copy.rating = 0
184 | copy.downloads = 0
185 | copy.downloaded = Time.now #nil
186 | copy.created = Time.now
187 | copy.archive = nil
188 | copy.save
189 | @script = copy
190 | erb :edit
191 | end
192 | end
193 |
194 | # Create new script.
195 | get '/edit' do
196 | authorize!('/login')
197 |
198 | @script = Script.new(:owner=>user.username, :modifier=>user.username, :modified=>Time.now)
199 | erb :edit
200 | end
201 |
202 | # Edit script.
203 | get '/edit/:id' do
204 | authorize!('/login')
205 |
206 | id = params[:id]
207 |
208 | @script = Script[:id=>id]
209 |
210 | if user.username != @script.owner
211 | flash[:message] = "Unathorized Access!"
212 | redirect(back)
213 | else
214 | erb :edit
215 | end
216 | end
217 |
218 | #
219 | post '/edit' do
220 | authorize!('/login')
221 |
222 | id = params[:id]
223 | if id.empty?
224 | @script = Script.new(:owner=>user.username, :modifier=>user.username, :modified=>Time.now)
225 | else
226 | @script = Script[:id=>id]
227 | if user.username != @script.owner
228 | flash[:message] = "Unathorized Access!"
229 | redirect(back)
230 | end
231 | end
232 |
233 | @script[:name] = params[:name] if @script.new?
234 | @script[:code] = params[:code]
235 | @script[:test] = params[:test]
236 | @script[:description] = params[:desc]
237 |
238 | @script[:modifier] = user.username
239 |
240 | bump = (params[:bump] == 'true' ? true : false)
241 |
242 | if @script.save(bump)
243 | flash[:message] = 'Script saved'
244 | redirect "/script/#{@script.id}"
245 | else
246 | flash[:message] = 'Script error!'
247 | redirect "/edit"
248 | end
249 | end
250 |
251 | #
252 | get '/watch/:owner/:name' do
253 | authorize!('/login')
254 |
255 | owner = params[:owner]
256 | name = params[:name]
257 | track = Track[:user_id=>user_id, :owner=>owner, :name=>name]
258 | unless track
259 | track = Track.new(:user_id=>user_id, :owner=>owner, :name=>name)
260 | end
261 | track.watch = true
262 | track.save
263 | redirect(back)
264 | end
265 |
266 | #
267 | get '/unwatch/:owner/:name' do
268 | authorize!('/login')
269 |
270 | owner = params[:owner]
271 | name = params[:name]
272 | track = Track[:user_id=>user_id, :owner=>owner, :name=>name]
273 | unless track
274 | track = Track.new(:user_id=>user_id, :owner=>owner, :name=>name)
275 | end
276 | track.watch = false
277 | track.save
278 | redirect(back)
279 | end
280 |
281 | #
282 | get '/star/:id' do
283 | authorize!('/login')
284 |
285 | id = params[:id]
286 |
287 | script = Script[:id=>id]
288 | track = script.track(user_id)
289 | #track = Track[:user_id=>user_id, :owner=>script.owner, :name=>script.name]
290 | unless track
291 | track = Track.new(:user_id=>user_id, :owner=>script.owner, :name=>script.name)
292 | end
293 |
294 | track.star = !track.star
295 | track.save
296 |
297 | 'Starred!'
298 | end
299 |
300 | #
301 | get '/flag/:id' do
302 | authorize!('/login')
303 |
304 | id = params[:id]
305 |
306 | script = Script[:id=>id]
307 | track = script.track(user_id)
308 | #track = Track[:user_id=>user_id, :owner=>script.owner, :name=>script.name]
309 | unless track
310 | track = Track.new(:user_id=>user_id, :owner=>script.owner, :name=>script.name)
311 | end
312 |
313 | track.flag = !track.flag
314 | track.save
315 |
316 | 'Flagged!'
317 | end
318 |
319 | #
320 | get '/require/:user/:name' do
321 | user = params[:user]
322 | name = params[:name]
323 | Script[:user=>user, :name=>name, :archive=>nil].code
324 | end
325 |
326 | #
327 | get '/require/:user/:name/:vers' do
328 | user = params[:user]
329 | name = params[:name]
330 | vers = params[:vers]
331 | Script[:user=>user, :name=>name, :vers=>vers].code
332 | end
333 |
334 | #post '/set-flash' do
335 | # # Set a flash entry
336 | # flash[:notice] = "Thanks for signing up!"
337 | #
338 | # # Get a flash entry
339 | # flash[:notice] # => "Thanks for signing up!"
340 | #
341 | # # Set a flash entry for only the current request
342 | # flash.now[:notice] = "Thanks for signing up!"
343 | #end
344 | end
345 |
346 | end
347 |
348 |
--------------------------------------------------------------------------------
/lib/live/public/js/jquery.ui.stars/ui.stars.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * jQuery UI Stars v2.1.1
3 | * http://plugins.jquery.com/project/Star_Rating_widget
4 | *
5 | * Copyright (c) 2009 Orkan (orkans@gmail.com)
6 | * Dual licensed under the MIT and GPL licenses.
7 | * http://docs.jquery.com/License
8 | *
9 | * $Rev: 114 $
10 | * $Date:: 2009-06-12 #$
11 | * $Build: 32 (2009-06-12)
12 | *
13 | * Depends:
14 | * ui.core.js
15 | *
16 | */
17 | (function($) {
18 |
19 | $.widget("ui.stars",
20 | {
21 | _init: function() {
22 | var self = this, o = this.options, id = 0;
23 |
24 | o.isSelect = o.inputType == "select";
25 | this.$form = $(this.element).closest("form");
26 | this.$selec = o.isSelect ? $("select", this.element) : null;
27 | this.$rboxs = o.isSelect ? $("option", this.$selec) : $(":radio", this.element);
28 |
29 | /*
30 | * Map all inputs from $rboxs array to Stars elements
31 | */
32 | this.$stars = this.$rboxs.map(function(i)
33 | {
34 | var el = {
35 | value: this.value,
36 | title: (o.isSelect ? this.text : this.title) || this.value,
37 | isDefault: (o.isSelect && this.defaultSelected) || this.defaultChecked
38 | };
39 |
40 | if(i==0) {
41 | o.split = typeof o.split != "number" ? 0 : o.split;
42 | o.val2id = [];
43 | o.id2val = [];
44 | o.id2title = [];
45 | o.name = o.isSelect ? self.$selec.get(0).name : this.name;
46 | o.disabled = o.disabled || (o.isSelect ? $(self.$selec).attr("disabled") : $(this).attr("disabled"));
47 | }
48 |
49 | /*
50 | * Consider it as a Cancel button?
51 | */
52 | if(el.value == o.cancelValue) {
53 | o.cancelTitle = el.title;
54 | return null;
55 | }
56 |
57 | o.val2id[el.value] = id;
58 | o.id2val[id] = el.value;
59 | o.id2title[id] = el.title;
60 |
61 | if(el.isDefault) {
62 | o.checked = id;
63 | o.value = o.defaultValue = el.value;
64 | o.title = el.title;
65 | }
66 |
67 | var $s = $("").addClass(o.starClass);
68 | var $a = $('').attr("title", o.showTitles ? el.title : "").text(el.value);
69 |
70 | /*
71 | * Prepare division settings
72 | */
73 | if(o.split) {
74 | var oddeven = (id % o.split);
75 | var stwidth = Math.floor(o.starWidth / o.split);
76 | $s.width(stwidth);
77 | $a.css("margin-left", "-" + (oddeven * stwidth) + "px");
78 | }
79 |
80 | id++;
81 | return $s.append($a).get(0);
82 | });
83 |
84 | /*
85 | * How many Stars?
86 | */
87 | o.items = id;
88 |
89 | /*
90 | * Remove old content
91 | */
92 | o.isSelect ? this.$selec.remove() : this.$rboxs.remove();
93 |
94 | /*
95 | * Append Stars interface
96 | */
97 | this.$cancel = $("").addClass(o.cancelClass).append( $("").attr("title", o.showTitles ? o.cancelTitle : "").text(o.cancelValue) );
98 | o.cancelShow &= !o.disabled && !o.oneVoteOnly;
99 | o.cancelShow && this.element.append(this.$cancel);
100 | this.element.append(this.$stars);
101 |
102 | /*
103 | * Initial selection
104 | */
105 | if(o.checked === undefined) {
106 | o.checked = -1;
107 | o.value = o.defaultValue = o.cancelValue;
108 | o.title = "";
109 | }
110 |
111 | this.$value = $('');
112 | this.element.append(this.$value);
113 |
114 |
115 | /*
116 | * Attach stars event handler
117 | */
118 | this.$stars.bind("click.stars", function(e) {
119 | if(!o.forceSelect && o.disabled) return false;
120 |
121 | var i = self.$stars.index(this);
122 | o.checked = i;
123 | o.value = o.id2val[i];
124 | o.title = o.id2title[i];
125 | self.$value.attr({disabled: o.disabled ? "disabled" : "", value: o.value});
126 |
127 | fillTo(i, false);
128 | self._disableCancel();
129 |
130 | !o.forceSelect && self.callback(e, "star");
131 | })
132 | .bind("mouseover.stars", function() {
133 | if(o.disabled) return false;
134 | var i = self.$stars.index(this);
135 | fillTo(i, true);
136 | })
137 | .bind("mouseout.stars", function() {
138 | if(o.disabled) return false;
139 | fillTo(self.options.checked, false);
140 | });
141 |
142 |
143 | /*
144 | * Attach cancel event handler
145 | */
146 | this.$cancel.bind("click.stars", function(e) {
147 | if(!o.forceSelect && (o.disabled || o.value == o.cancelValue)) return false;
148 |
149 | o.checked = -1;
150 | o.value = o.cancelValue;
151 | o.title = "";
152 | self.$value.val(o.value).attr({disabled: "disabled"});
153 |
154 | fillNone();
155 | self._disableCancel();
156 |
157 | !o.forceSelect && self.callback(e, "cancel");
158 | })
159 | .bind("mouseover.stars", function() {
160 | if(self._disableCancel()) return false;
161 | self.$cancel.addClass(o.cancelHoverClass);
162 | fillNone();
163 | self._showCap(o.cancelTitle);
164 | })
165 | .bind("mouseout.stars", function() {
166 | if(self._disableCancel()) return false;
167 | self.$cancel.removeClass(o.cancelHoverClass);
168 | self.$stars.triggerHandler("mouseout.stars");
169 | });
170 |
171 |
172 | /*
173 | * Attach onReset event handler to the parent FORM
174 | */
175 | this.$form.bind("reset.stars", function(){
176 | !o.disabled && self.select(o.defaultValue);
177 | });
178 |
179 |
180 | /*
181 | * Clean up to avoid memory leaks in certain versions of IE 6
182 | */
183 | $(window).unload(function(){
184 | self.$cancel.unbind(".stars");
185 | self.$stars.unbind(".stars");
186 | self.$form.unbind(".stars");
187 | self.$selec = self.$rboxs = self.$stars = self.$value = self.$cancel = self.$form = null;
188 | });
189 |
190 |
191 | /*
192 | * Star selection helpers
193 | */
194 | function fillTo(index, hover) {
195 | if(index != -1) {
196 | var addClass = hover ? o.starHoverClass : o.starOnClass;
197 | var remClass = hover ? o.starOnClass : o.starHoverClass;
198 | self.$stars.eq(index).prevAll("." + o.starClass).andSelf().removeClass(remClass).addClass(addClass);
199 | self.$stars.eq(index).nextAll("." + o.starClass).removeClass(o.starHoverClass + " " + o.starOnClass);
200 | self._showCap(o.id2title[index]);
201 | }
202 | else fillNone();
203 | };
204 | function fillNone() {
205 | self.$stars.removeClass(o.starOnClass + " " + o.starHoverClass);
206 | self._showCap("");
207 | };
208 |
209 |
210 | /*
211 | * Finally, set up the Stars
212 | */
213 | this.select(o.value);
214 | o.disabled && this.disable();
215 |
216 | },
217 |
218 | /*
219 | * Private functions
220 | */
221 | _disableCancel: function() {
222 | var o = this.options, disabled = o.disabled || o.oneVoteOnly || (o.value == o.cancelValue);
223 | if(disabled) this.$cancel.removeClass(o.cancelHoverClass).addClass(o.cancelDisabledClass);
224 | else this.$cancel.removeClass(o.cancelDisabledClass);
225 | this.$cancel.css("opacity", disabled ? 0.5 : 1);
226 | return disabled;
227 | },
228 | _disableAll: function() {
229 | var o = this.options;
230 | this._disableCancel();
231 | if(o.disabled) this.$stars.filter("div").addClass(o.starDisabledClass);
232 | else this.$stars.filter("div").removeClass(o.starDisabledClass);
233 | },
234 | _showCap: function(s) {
235 | var o = this.options;
236 | if(o.captionEl) o.captionEl.text(s);
237 | },
238 |
239 | /*
240 | * Public functions
241 | */
242 | value: function() {
243 | return this.options.value;
244 | },
245 | select: function(val) {
246 | var o = this.options, e = (val == o.cancelValue) ? this.$cancel : this.$stars.eq(o.val2id[val]);
247 | o.forceSelect = true;
248 | e.triggerHandler("click.stars");
249 | o.forceSelect = false;
250 | },
251 | selectID: function(id) {
252 | var o = this.options, e = (id == -1) ? this.$cancel : this.$stars.eq(id);
253 | o.forceSelect = true;
254 | e.triggerHandler("click.stars");
255 | o.forceSelect = false;
256 | },
257 | enable: function() {
258 | this.options.disabled = false;
259 | this._disableAll();
260 | },
261 | disable: function() {
262 | this.options.disabled = true;
263 | this._disableAll();
264 | },
265 | destroy: function() {
266 | this.options.isSelect ? this.$selec.appendTo(this.element) : this.$rboxs.appendTo(this.element);
267 | this.$form.unbind(".stars");
268 | this.$cancel.unbind(".stars").remove();
269 | this.$stars.unbind(".stars").remove();
270 | this.$value.remove();
271 | this.element.unbind(".stars").removeData("stars");
272 | },
273 | callback: function(e, type) {
274 | var o = this.options;
275 | o.callback && o.callback(this, type, o.value, e);
276 | o.oneVoteOnly && !o.disabled && this.disable();
277 | }
278 | });
279 |
280 | $.extend($.ui.stars, {
281 | version: "2.1.1",
282 | getter: "value",
283 | defaults: {
284 | inputType: "radio", // radio|select
285 | split: 0,
286 | disabled: false,
287 | cancelTitle: "Cancel Rating",
288 | cancelValue: 0,
289 | cancelShow: true,
290 | oneVoteOnly: false,
291 | showTitles: false,
292 | captionEl: null,
293 | callback: null, // function(ui, type, value, event)
294 |
295 | /*
296 | * CSS classes
297 | */
298 | starWidth: 16,
299 | cancelClass: 'ui-stars-cancel',
300 | starClass: 'ui-stars-star',
301 | starOnClass: 'ui-stars-star-on',
302 | starHoverClass: 'ui-stars-star-hover',
303 | starDisabledClass: 'ui-stars-star-disabled',
304 | cancelHoverClass: 'ui-stars-cancel-hover',
305 | cancelDisabledClass: 'ui-stars-cancel-disabled'
306 | }
307 | });
308 |
309 | })(jQuery);
310 |
--------------------------------------------------------------------------------
/lib/live/public/js/jquery.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * jQuery JavaScript Library v1.3.2
3 | * http://jquery.com/
4 | *
5 | * Copyright (c) 2009 John Resig
6 | * Dual licensed under the MIT and GPL licenses.
7 | * http://docs.jquery.com/License
8 | *
9 | * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
10 | * Revision: 6246
11 | */
12 | (function(){
13 |
14 | var
15 | // Will speed up references to window, and allows munging its name.
16 | window = this,
17 | // Will speed up references to undefined, and allows munging its name.
18 | undefined,
19 | // Map over jQuery in case of overwrite
20 | _jQuery = window.jQuery,
21 | // Map over the $ in case of overwrite
22 | _$ = window.$,
23 |
24 | jQuery = window.jQuery = window.$ = function( selector, context ) {
25 | // The jQuery object is actually just the init constructor 'enhanced'
26 | return new jQuery.fn.init( selector, context );
27 | },
28 |
29 | // A simple way to check for HTML strings or ID strings
30 | // (both of which we optimize for)
31 | quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,
32 | // Is it a simple selector
33 | isSimple = /^.[^:#\[\.,]*$/;
34 |
35 | jQuery.fn = jQuery.prototype = {
36 | init: function( selector, context ) {
37 | // Make sure that a selection was provided
38 | selector = selector || document;
39 |
40 | // Handle $(DOMElement)
41 | if ( selector.nodeType ) {
42 | this[0] = selector;
43 | this.length = 1;
44 | this.context = selector;
45 | return this;
46 | }
47 | // Handle HTML strings
48 | if ( typeof selector === "string" ) {
49 | // Are we dealing with HTML string or an ID?
50 | var match = quickExpr.exec( selector );
51 |
52 | // Verify a match, and that no context was specified for #id
53 | if ( match && (match[1] || !context) ) {
54 |
55 | // HANDLE: $(html) -> $(array)
56 | if ( match[1] )
57 | selector = jQuery.clean( [ match[1] ], context );
58 |
59 | // HANDLE: $("#id")
60 | else {
61 | var elem = document.getElementById( match[3] );
62 |
63 | // Handle the case where IE and Opera return items
64 | // by name instead of ID
65 | if ( elem && elem.id != match[3] )
66 | return jQuery().find( selector );
67 |
68 | // Otherwise, we inject the element directly into the jQuery object
69 | var ret = jQuery( elem || [] );
70 | ret.context = document;
71 | ret.selector = selector;
72 | return ret;
73 | }
74 |
75 | // HANDLE: $(expr, [context])
76 | // (which is just equivalent to: $(content).find(expr)
77 | } else
78 | return jQuery( context ).find( selector );
79 |
80 | // HANDLE: $(function)
81 | // Shortcut for document ready
82 | } else if ( jQuery.isFunction( selector ) )
83 | return jQuery( document ).ready( selector );
84 |
85 | // Make sure that old selector state is passed along
86 | if ( selector.selector && selector.context ) {
87 | this.selector = selector.selector;
88 | this.context = selector.context;
89 | }
90 |
91 | return this.setArray(jQuery.isArray( selector ) ?
92 | selector :
93 | jQuery.makeArray(selector));
94 | },
95 |
96 | // Start with an empty selector
97 | selector: "",
98 |
99 | // The current version of jQuery being used
100 | jquery: "1.3.2",
101 |
102 | // The number of elements contained in the matched element set
103 | size: function() {
104 | return this.length;
105 | },
106 |
107 | // Get the Nth element in the matched element set OR
108 | // Get the whole matched element set as a clean array
109 | get: function( num ) {
110 | return num === undefined ?
111 |
112 | // Return a 'clean' array
113 | Array.prototype.slice.call( this ) :
114 |
115 | // Return just the object
116 | this[ num ];
117 | },
118 |
119 | // Take an array of elements and push it onto the stack
120 | // (returning the new matched element set)
121 | pushStack: function( elems, name, selector ) {
122 | // Build a new jQuery matched element set
123 | var ret = jQuery( elems );
124 |
125 | // Add the old object onto the stack (as a reference)
126 | ret.prevObject = this;
127 |
128 | ret.context = this.context;
129 |
130 | if ( name === "find" )
131 | ret.selector = this.selector + (this.selector ? " " : "") + selector;
132 | else if ( name )
133 | ret.selector = this.selector + "." + name + "(" + selector + ")";
134 |
135 | // Return the newly-formed element set
136 | return ret;
137 | },
138 |
139 | // Force the current matched set of elements to become
140 | // the specified array of elements (destroying the stack in the process)
141 | // You should use pushStack() in order to do this, but maintain the stack
142 | setArray: function( elems ) {
143 | // Resetting the length to 0, then using the native Array push
144 | // is a super-fast way to populate an object with array-like properties
145 | this.length = 0;
146 | Array.prototype.push.apply( this, elems );
147 |
148 | return this;
149 | },
150 |
151 | // Execute a callback for every element in the matched set.
152 | // (You can seed the arguments with an array of args, but this is
153 | // only used internally.)
154 | each: function( callback, args ) {
155 | return jQuery.each( this, callback, args );
156 | },
157 |
158 | // Determine the position of an element within
159 | // the matched set of elements
160 | index: function( elem ) {
161 | // Locate the position of the desired element
162 | return jQuery.inArray(
163 | // If it receives a jQuery object, the first element is used
164 | elem && elem.jquery ? elem[0] : elem
165 | , this );
166 | },
167 |
168 | attr: function( name, value, type ) {
169 | var options = name;
170 |
171 | // Look for the case where we're accessing a style value
172 | if ( typeof name === "string" )
173 | if ( value === undefined )
174 | return this[0] && jQuery[ type || "attr" ]( this[0], name );
175 |
176 | else {
177 | options = {};
178 | options[ name ] = value;
179 | }
180 |
181 | // Check to see if we're setting style values
182 | return this.each(function(i){
183 | // Set all the styles
184 | for ( name in options )
185 | jQuery.attr(
186 | type ?
187 | this.style :
188 | this,
189 | name, jQuery.prop( this, options[ name ], type, i, name )
190 | );
191 | });
192 | },
193 |
194 | css: function( key, value ) {
195 | // ignore negative width and height values
196 | if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 )
197 | value = undefined;
198 | return this.attr( key, value, "curCSS" );
199 | },
200 |
201 | text: function( text ) {
202 | if ( typeof text !== "object" && text != null )
203 | return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
204 |
205 | var ret = "";
206 |
207 | jQuery.each( text || this, function(){
208 | jQuery.each( this.childNodes, function(){
209 | if ( this.nodeType != 8 )
210 | ret += this.nodeType != 1 ?
211 | this.nodeValue :
212 | jQuery.fn.text( [ this ] );
213 | });
214 | });
215 |
216 | return ret;
217 | },
218 |
219 | wrapAll: function( html ) {
220 | if ( this[0] ) {
221 | // The elements to wrap the target around
222 | var wrap = jQuery( html, this[0].ownerDocument ).clone();
223 |
224 | if ( this[0].parentNode )
225 | wrap.insertBefore( this[0] );
226 |
227 | wrap.map(function(){
228 | var elem = this;
229 |
230 | while ( elem.firstChild )
231 | elem = elem.firstChild;
232 |
233 | return elem;
234 | }).append(this);
235 | }
236 |
237 | return this;
238 | },
239 |
240 | wrapInner: function( html ) {
241 | return this.each(function(){
242 | jQuery( this ).contents().wrapAll( html );
243 | });
244 | },
245 |
246 | wrap: function( html ) {
247 | return this.each(function(){
248 | jQuery( this ).wrapAll( html );
249 | });
250 | },
251 |
252 | append: function() {
253 | return this.domManip(arguments, true, function(elem){
254 | if (this.nodeType == 1)
255 | this.appendChild( elem );
256 | });
257 | },
258 |
259 | prepend: function() {
260 | return this.domManip(arguments, true, function(elem){
261 | if (this.nodeType == 1)
262 | this.insertBefore( elem, this.firstChild );
263 | });
264 | },
265 |
266 | before: function() {
267 | return this.domManip(arguments, false, function(elem){
268 | this.parentNode.insertBefore( elem, this );
269 | });
270 | },
271 |
272 | after: function() {
273 | return this.domManip(arguments, false, function(elem){
274 | this.parentNode.insertBefore( elem, this.nextSibling );
275 | });
276 | },
277 |
278 | end: function() {
279 | return this.prevObject || jQuery( [] );
280 | },
281 |
282 | // For internal use only.
283 | // Behaves like an Array's method, not like a jQuery method.
284 | push: [].push,
285 | sort: [].sort,
286 | splice: [].splice,
287 |
288 | find: function( selector ) {
289 | if ( this.length === 1 ) {
290 | var ret = this.pushStack( [], "find", selector );
291 | ret.length = 0;
292 | jQuery.find( selector, this[0], ret );
293 | return ret;
294 | } else {
295 | return this.pushStack( jQuery.unique(jQuery.map(this, function(elem){
296 | return jQuery.find( selector, elem );
297 | })), "find", selector );
298 | }
299 | },
300 |
301 | clone: function( events ) {
302 | // Do the clone
303 | var ret = this.map(function(){
304 | if ( !jQuery.support.noCloneEvent && !jQuery.isXMLDoc(this) ) {
305 | // IE copies events bound via attachEvent when
306 | // using cloneNode. Calling detachEvent on the
307 | // clone will also remove the events from the orignal
308 | // In order to get around this, we use innerHTML.
309 | // Unfortunately, this means some modifications to
310 | // attributes in IE that are actually only stored
311 | // as properties will not be copied (such as the
312 | // the name attribute on an input).
313 | var html = this.outerHTML;
314 | if ( !html ) {
315 | var div = this.ownerDocument.createElement("div");
316 | div.appendChild( this.cloneNode(true) );
317 | html = div.innerHTML;
318 | }
319 |
320 | return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g, "").replace(/^\s*/, "")])[0];
321 | } else
322 | return this.cloneNode(true);
323 | });
324 |
325 | // Copy the events from the original to the clone
326 | if ( events === true ) {
327 | var orig = this.find("*").andSelf(), i = 0;
328 |
329 | ret.find("*").andSelf().each(function(){
330 | if ( this.nodeName !== orig[i].nodeName )
331 | return;
332 |
333 | var events = jQuery.data( orig[i], "events" );
334 |
335 | for ( var type in events ) {
336 | for ( var handler in events[ type ] ) {
337 | jQuery.event.add( this, type, events[ type ][ handler ], events[ type ][ handler ].data );
338 | }
339 | }
340 |
341 | i++;
342 | });
343 | }
344 |
345 | // Return the cloned set
346 | return ret;
347 | },
348 |
349 | filter: function( selector ) {
350 | return this.pushStack(
351 | jQuery.isFunction( selector ) &&
352 | jQuery.grep(this, function(elem, i){
353 | return selector.call( elem, i );
354 | }) ||
355 |
356 | jQuery.multiFilter( selector, jQuery.grep(this, function(elem){
357 | return elem.nodeType === 1;
358 | }) ), "filter", selector );
359 | },
360 |
361 | closest: function( selector ) {
362 | var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null,
363 | closer = 0;
364 |
365 | return this.map(function(){
366 | var cur = this;
367 | while ( cur && cur.ownerDocument ) {
368 | if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) ) {
369 | jQuery.data(cur, "closest", closer);
370 | return cur;
371 | }
372 | cur = cur.parentNode;
373 | closer++;
374 | }
375 | });
376 | },
377 |
378 | not: function( selector ) {
379 | if ( typeof selector === "string" )
380 | // test special case where just one selector is passed in
381 | if ( isSimple.test( selector ) )
382 | return this.pushStack( jQuery.multiFilter( selector, this, true ), "not", selector );
383 | else
384 | selector = jQuery.multiFilter( selector, this );
385 |
386 | var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;
387 | return this.filter(function() {
388 | return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;
389 | });
390 | },
391 |
392 | add: function( selector ) {
393 | return this.pushStack( jQuery.unique( jQuery.merge(
394 | this.get(),
395 | typeof selector === "string" ?
396 | jQuery( selector ) :
397 | jQuery.makeArray( selector )
398 | )));
399 | },
400 |
401 | is: function( selector ) {
402 | return !!selector && jQuery.multiFilter( selector, this ).length > 0;
403 | },
404 |
405 | hasClass: function( selector ) {
406 | return !!selector && this.is( "." + selector );
407 | },
408 |
409 | val: function( value ) {
410 | if ( value === undefined ) {
411 | var elem = this[0];
412 |
413 | if ( elem ) {
414 | if( jQuery.nodeName( elem, 'option' ) )
415 | return (elem.attributes.value || {}).specified ? elem.value : elem.text;
416 |
417 | // We need to handle select boxes special
418 | if ( jQuery.nodeName( elem, "select" ) ) {
419 | var index = elem.selectedIndex,
420 | values = [],
421 | options = elem.options,
422 | one = elem.type == "select-one";
423 |
424 | // Nothing was selected
425 | if ( index < 0 )
426 | return null;
427 |
428 | // Loop through all the selected options
429 | for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
430 | var option = options[ i ];
431 |
432 | if ( option.selected ) {
433 | // Get the specifc value for the option
434 | value = jQuery(option).val();
435 |
436 | // We don't need an array for one selects
437 | if ( one )
438 | return value;
439 |
440 | // Multi-Selects return an array
441 | values.push( value );
442 | }
443 | }
444 |
445 | return values;
446 | }
447 |
448 | // Everything else, we just grab the value
449 | return (elem.value || "").replace(/\r/g, "");
450 |
451 | }
452 |
453 | return undefined;
454 | }
455 |
456 | if ( typeof value === "number" )
457 | value += '';
458 |
459 | return this.each(function(){
460 | if ( this.nodeType != 1 )
461 | return;
462 |
463 | if ( jQuery.isArray(value) && /radio|checkbox/.test( this.type ) )
464 | this.checked = (jQuery.inArray(this.value, value) >= 0 ||
465 | jQuery.inArray(this.name, value) >= 0);
466 |
467 | else if ( jQuery.nodeName( this, "select" ) ) {
468 | var values = jQuery.makeArray(value);
469 |
470 | jQuery( "option", this ).each(function(){
471 | this.selected = (jQuery.inArray( this.value, values ) >= 0 ||
472 | jQuery.inArray( this.text, values ) >= 0);
473 | });
474 |
475 | if ( !values.length )
476 | this.selectedIndex = -1;
477 |
478 | } else
479 | this.value = value;
480 | });
481 | },
482 |
483 | html: function( value ) {
484 | return value === undefined ?
485 | (this[0] ?
486 | this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g, "") :
487 | null) :
488 | this.empty().append( value );
489 | },
490 |
491 | replaceWith: function( value ) {
492 | return this.after( value ).remove();
493 | },
494 |
495 | eq: function( i ) {
496 | return this.slice( i, +i + 1 );
497 | },
498 |
499 | slice: function() {
500 | return this.pushStack( Array.prototype.slice.apply( this, arguments ),
501 | "slice", Array.prototype.slice.call(arguments).join(",") );
502 | },
503 |
504 | map: function( callback ) {
505 | return this.pushStack( jQuery.map(this, function(elem, i){
506 | return callback.call( elem, i, elem );
507 | }));
508 | },
509 |
510 | andSelf: function() {
511 | return this.add( this.prevObject );
512 | },
513 |
514 | domManip: function( args, table, callback ) {
515 | if ( this[0] ) {
516 | var fragment = (this[0].ownerDocument || this[0]).createDocumentFragment(),
517 | scripts = jQuery.clean( args, (this[0].ownerDocument || this[0]), fragment ),
518 | first = fragment.firstChild;
519 |
520 | if ( first )
521 | for ( var i = 0, l = this.length; i < l; i++ )
522 | callback.call( root(this[i], first), this.length > 1 || i > 0 ?
523 | fragment.cloneNode(true) : fragment );
524 |
525 | if ( scripts )
526 | jQuery.each( scripts, evalScript );
527 | }
528 |
529 | return this;
530 |
531 | function root( elem, cur ) {
532 | return table && jQuery.nodeName(elem, "table") && jQuery.nodeName(cur, "tr") ?
533 | (elem.getElementsByTagName("tbody")[0] ||
534 | elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
535 | elem;
536 | }
537 | }
538 | };
539 |
540 | // Give the init function the jQuery prototype for later instantiation
541 | jQuery.fn.init.prototype = jQuery.fn;
542 |
543 | function evalScript( i, elem ) {
544 | if ( elem.src )
545 | jQuery.ajax({
546 | url: elem.src,
547 | async: false,
548 | dataType: "script"
549 | });
550 |
551 | else
552 | jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
553 |
554 | if ( elem.parentNode )
555 | elem.parentNode.removeChild( elem );
556 | }
557 |
558 | function now(){
559 | return +new Date;
560 | }
561 |
562 | jQuery.extend = jQuery.fn.extend = function() {
563 | // copy reference to target object
564 | var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
565 |
566 | // Handle a deep copy situation
567 | if ( typeof target === "boolean" ) {
568 | deep = target;
569 | target = arguments[1] || {};
570 | // skip the boolean and the target
571 | i = 2;
572 | }
573 |
574 | // Handle case when target is a string or something (possible in deep copy)
575 | if ( typeof target !== "object" && !jQuery.isFunction(target) )
576 | target = {};
577 |
578 | // extend jQuery itself if only one argument is passed
579 | if ( length == i ) {
580 | target = this;
581 | --i;
582 | }
583 |
584 | for ( ; i < length; i++ )
585 | // Only deal with non-null/undefined values
586 | if ( (options = arguments[ i ]) != null )
587 | // Extend the base object
588 | for ( var name in options ) {
589 | var src = target[ name ], copy = options[ name ];
590 |
591 | // Prevent never-ending loop
592 | if ( target === copy )
593 | continue;
594 |
595 | // Recurse if we're merging object values
596 | if ( deep && copy && typeof copy === "object" && !copy.nodeType )
597 | target[ name ] = jQuery.extend( deep,
598 | // Never move original objects, clone them
599 | src || ( copy.length != null ? [ ] : { } )
600 | , copy );
601 |
602 | // Don't bring in undefined values
603 | else if ( copy !== undefined )
604 | target[ name ] = copy;
605 |
606 | }
607 |
608 | // Return the modified object
609 | return target;
610 | };
611 |
612 | // exclude the following css properties to add px
613 | var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
614 | // cache defaultView
615 | defaultView = document.defaultView || {},
616 | toString = Object.prototype.toString;
617 |
618 | jQuery.extend({
619 | noConflict: function( deep ) {
620 | window.$ = _$;
621 |
622 | if ( deep )
623 | window.jQuery = _jQuery;
624 |
625 | return jQuery;
626 | },
627 |
628 | // See test/unit/core.js for details concerning isFunction.
629 | // Since version 1.3, DOM methods and functions like alert
630 | // aren't supported. They return false on IE (#2968).
631 | isFunction: function( obj ) {
632 | return toString.call(obj) === "[object Function]";
633 | },
634 |
635 | isArray: function( obj ) {
636 | return toString.call(obj) === "[object Array]";
637 | },
638 |
639 | // check if an element is in a (or is an) XML document
640 | isXMLDoc: function( elem ) {
641 | return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" ||
642 | !!elem.ownerDocument && jQuery.isXMLDoc( elem.ownerDocument );
643 | },
644 |
645 | // Evalulates a script in a global context
646 | globalEval: function( data ) {
647 | if ( data && /\S/.test(data) ) {
648 | // Inspired by code by Andrea Giammarchi
649 | // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
650 | var head = document.getElementsByTagName("head")[0] || document.documentElement,
651 | script = document.createElement("script");
652 |
653 | script.type = "text/javascript";
654 | if ( jQuery.support.scriptEval )
655 | script.appendChild( document.createTextNode( data ) );
656 | else
657 | script.text = data;
658 |
659 | // Use insertBefore instead of appendChild to circumvent an IE6 bug.
660 | // This arises when a base node is used (#2709).
661 | head.insertBefore( script, head.firstChild );
662 | head.removeChild( script );
663 | }
664 | },
665 |
666 | nodeName: function( elem, name ) {
667 | return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
668 | },
669 |
670 | // args is for internal usage only
671 | each: function( object, callback, args ) {
672 | var name, i = 0, length = object.length;
673 |
674 | if ( args ) {
675 | if ( length === undefined ) {
676 | for ( name in object )
677 | if ( callback.apply( object[ name ], args ) === false )
678 | break;
679 | } else
680 | for ( ; i < length; )
681 | if ( callback.apply( object[ i++ ], args ) === false )
682 | break;
683 |
684 | // A special, fast, case for the most common use of each
685 | } else {
686 | if ( length === undefined ) {
687 | for ( name in object )
688 | if ( callback.call( object[ name ], name, object[ name ] ) === false )
689 | break;
690 | } else
691 | for ( var value = object[0];
692 | i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
693 | }
694 |
695 | return object;
696 | },
697 |
698 | prop: function( elem, value, type, i, name ) {
699 | // Handle executable functions
700 | if ( jQuery.isFunction( value ) )
701 | value = value.call( elem, i );
702 |
703 | // Handle passing in a number to a CSS property
704 | return typeof value === "number" && type == "curCSS" && !exclude.test( name ) ?
705 | value + "px" :
706 | value;
707 | },
708 |
709 | className: {
710 | // internal only, use addClass("class")
711 | add: function( elem, classNames ) {
712 | jQuery.each((classNames || "").split(/\s+/), function(i, className){
713 | if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
714 | elem.className += (elem.className ? " " : "") + className;
715 | });
716 | },
717 |
718 | // internal only, use removeClass("class")
719 | remove: function( elem, classNames ) {
720 | if (elem.nodeType == 1)
721 | elem.className = classNames !== undefined ?
722 | jQuery.grep(elem.className.split(/\s+/), function(className){
723 | return !jQuery.className.has( classNames, className );
724 | }).join(" ") :
725 | "";
726 | },
727 |
728 | // internal only, use hasClass("class")
729 | has: function( elem, className ) {
730 | return elem && jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
731 | }
732 | },
733 |
734 | // A method for quickly swapping in/out CSS properties to get correct calculations
735 | swap: function( elem, options, callback ) {
736 | var old = {};
737 | // Remember the old values, and insert the new ones
738 | for ( var name in options ) {
739 | old[ name ] = elem.style[ name ];
740 | elem.style[ name ] = options[ name ];
741 | }
742 |
743 | callback.call( elem );
744 |
745 | // Revert the old values
746 | for ( var name in options )
747 | elem.style[ name ] = old[ name ];
748 | },
749 |
750 | css: function( elem, name, force, extra ) {
751 | if ( name == "width" || name == "height" ) {
752 | var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
753 |
754 | function getWH() {
755 | val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
756 |
757 | if ( extra === "border" )
758 | return;
759 |
760 | jQuery.each( which, function() {
761 | if ( !extra )
762 | val -= parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
763 | if ( extra === "margin" )
764 | val += parseFloat(jQuery.curCSS( elem, "margin" + this, true)) || 0;
765 | else
766 | val -= parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
767 | });
768 | }
769 |
770 | if ( elem.offsetWidth !== 0 )
771 | getWH();
772 | else
773 | jQuery.swap( elem, props, getWH );
774 |
775 | return Math.max(0, Math.round(val));
776 | }
777 |
778 | return jQuery.curCSS( elem, name, force );
779 | },
780 |
781 | curCSS: function( elem, name, force ) {
782 | var ret, style = elem.style;
783 |
784 | // We need to handle opacity special in IE
785 | if ( name == "opacity" && !jQuery.support.opacity ) {
786 | ret = jQuery.attr( style, "opacity" );
787 |
788 | return ret == "" ?
789 | "1" :
790 | ret;
791 | }
792 |
793 | // Make sure we're using the right name for getting the float value
794 | if ( name.match( /float/i ) )
795 | name = styleFloat;
796 |
797 | if ( !force && style && style[ name ] )
798 | ret = style[ name ];
799 |
800 | else if ( defaultView.getComputedStyle ) {
801 |
802 | // Only "float" is needed here
803 | if ( name.match( /float/i ) )
804 | name = "float";
805 |
806 | name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
807 |
808 | var computedStyle = defaultView.getComputedStyle( elem, null );
809 |
810 | if ( computedStyle )
811 | ret = computedStyle.getPropertyValue( name );
812 |
813 | // We should always get a number back from opacity
814 | if ( name == "opacity" && ret == "" )
815 | ret = "1";
816 |
817 | } else if ( elem.currentStyle ) {
818 | var camelCase = name.replace(/\-(\w)/g, function(all, letter){
819 | return letter.toUpperCase();
820 | });
821 |
822 | ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
823 |
824 | // From the awesome hack by Dean Edwards
825 | // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
826 |
827 | // If we're not dealing with a regular pixel number
828 | // but a number that has a weird ending, we need to convert it to pixels
829 | if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
830 | // Remember the original values
831 | var left = style.left, rsLeft = elem.runtimeStyle.left;
832 |
833 | // Put in the new values to get a computed value out
834 | elem.runtimeStyle.left = elem.currentStyle.left;
835 | style.left = ret || 0;
836 | ret = style.pixelLeft + "px";
837 |
838 | // Revert the changed values
839 | style.left = left;
840 | elem.runtimeStyle.left = rsLeft;
841 | }
842 | }
843 |
844 | return ret;
845 | },
846 |
847 | clean: function( elems, context, fragment ) {
848 | context = context || document;
849 |
850 | // !context.createElement fails in IE with an error but returns typeof 'object'
851 | if ( typeof context.createElement === "undefined" )
852 | context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
853 |
854 | // If a single string is passed in and it's a single tag
855 | // just do a createElement and skip the rest
856 | if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) {
857 | var match = /^<(\w+)\s*\/?>$/.exec(elems[0]);
858 | if ( match )
859 | return [ context.createElement( match[1] ) ];
860 | }
861 |
862 | var ret = [], scripts = [], div = context.createElement("div");
863 |
864 | jQuery.each(elems, function(i, elem){
865 | if ( typeof elem === "number" )
866 | elem += '';
867 |
868 | if ( !elem )
869 | return;
870 |
871 | // Convert html string into DOM nodes
872 | if ( typeof elem === "string" ) {
873 | // Fix "XHTML"-style tags in all browsers
874 | elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
875 | return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
876 | all :
877 | front + ">" + tag + ">";
878 | });
879 |
880 | // Trim whitespace, otherwise indexOf won't work as expected
881 | var tags = elem.replace(/^\s+/, "").substring(0, 10).toLowerCase();
882 |
883 | var wrap =
884 | // option or optgroup
885 | !tags.indexOf("", "" ] ||
887 |
888 | !tags.indexOf("", "" ] ||
890 |
891 | tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
892 | [ 1, "" ] ||
893 |
894 | !tags.indexOf("
", "" ] ||
896 |
897 | // matched above
898 | (!tags.indexOf(" | ", "
" ] ||
900 |
901 | !tags.indexOf("", "" ] ||
903 |
904 | // IE can't serialize and