network_executive 0.0.4 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +53 -24
- data/app/assets/fonts/network_executive/league_gothic.css +13 -0
- data/app/assets/fonts/network_executive/league_gothic.svg +148 -0
- data/app/assets/fonts/network_executive/league_gothic.ttf +0 -0
- data/app/assets/fonts/network_executive/league_gothic.woff +0 -0
- data/app/assets/javascripts/network_executive/components/iframe_notifier.coffee +14 -0
- data/app/assets/javascripts/network_executive/components/namespace.coffee +1 -0
- data/app/assets/javascripts/network_executive/components/osd.coffee +65 -0
- data/app/assets/javascripts/network_executive/components/photo_player.coffee +55 -0
- data/app/assets/javascripts/network_executive/components/postman.coffee +23 -0
- data/app/assets/javascripts/network_executive/components/set_top_box.coffee +81 -0
- data/app/assets/javascripts/network_executive/components/tweet_player.coffee +95 -0
- data/app/assets/javascripts/network_executive/components/you_tube_player.coffee +85 -0
- data/app/assets/javascripts/network_executive/slideshow.coffee +6 -0
- data/app/assets/javascripts/network_executive/twitter.coffee +7 -0
- data/app/assets/javascripts/network_executive/you_tube.coffee +8 -0
- data/app/assets/javascripts/network_executive.coffee +10 -0
- data/app/assets/stylesheets/network_executive/{gui_components.css → components/gui_components.css} +0 -0
- data/app/assets/stylesheets/network_executive/{normalize.css → components/normalize.css} +0 -0
- data/app/assets/stylesheets/network_executive/{osd.css → components/osd.css} +6 -34
- data/app/assets/stylesheets/network_executive/components/osd_guide.css +43 -0
- data/app/assets/stylesheets/network_executive/components/photo_player.css +61 -0
- data/app/assets/stylesheets/network_executive/{smpte.css → components/smpte.css} +0 -0
- data/app/assets/stylesheets/network_executive/components/tweet_player.css +60 -0
- data/app/assets/stylesheets/network_executive/components/you_tube_player.css +12 -0
- data/app/assets/stylesheets/network_executive/off_air.css +5 -0
- data/app/assets/stylesheets/network_executive/slideshow.css +4 -0
- data/app/assets/stylesheets/network_executive/twitter.css +5 -0
- data/app/assets/stylesheets/network_executive/you_tube.css +3 -0
- data/app/assets/stylesheets/{network_executive/application.css → network_executive.css} +5 -5
- data/app/controllers/network_executive/components_controller.rb +4 -0
- data/app/controllers/network_executive/guide_controller.rb +41 -0
- data/app/controllers/network_executive/programs_controller.rb +9 -0
- data/app/helpers/network_executive/network_helper.rb +6 -0
- data/app/models/network_executive/channel.rb +15 -14
- data/app/models/network_executive/guide.rb +65 -0
- data/app/models/network_executive/program.rb +69 -5
- data/app/models/network_executive/viewer.rb +4 -0
- data/app/programs/network_executive/off_air.rb +18 -0
- data/app/views/network_executive/components/slideshow.html.erb +20 -0
- data/app/views/network_executive/components/twitter.html.erb +16 -0
- data/app/views/network_executive/components/you_tube.html.erb +13 -0
- data/app/views/network_executive/guide/index.html.erb +30 -0
- data/app/views/network_executive/network/index.html.erb +3 -3
- data/app/views/network_executive/programs/off_air.html.erb +13 -0
- data/config/routes.rb +7 -1
- data/lib/network_executive/channel_schedule.rb +65 -0
- data/lib/network_executive/components/photo_player.rb +48 -0
- data/lib/network_executive/components/tweet_player.rb +48 -0
- data/lib/network_executive/components/you_tube_player.rb +15 -0
- data/lib/network_executive/components.rb +3 -0
- data/lib/network_executive/engine.rb +29 -3
- data/lib/network_executive/off_air_schedule.rb +18 -0
- data/lib/network_executive/producer.rb +3 -3
- data/lib/network_executive/program_schedule.rb +96 -0
- data/lib/network_executive/program_schedule_proxy.rb +55 -0
- data/lib/network_executive/scheduled_program.rb +26 -0
- data/lib/network_executive/scheduling.rb +15 -21
- data/lib/network_executive/time_calculations.rb +10 -0
- data/lib/network_executive/version.rb +1 -1
- data/lib/network_executive.rb +2 -1
- data/network_executive.gemspec +5 -0
- data/spec/models/channel_spec.rb +30 -12
- data/spec/models/{lineup_spec.rb → guide_spec.rb} +28 -6
- data/spec/models/program_spec.rb +46 -3
- data/spec/models/viewer_spec.rb +9 -1
- data/spec/programs/off_air_spec.rb +9 -0
- data/spec/spec_helper.rb +3 -2
- data/spec/unit/channel_schedule_spec.rb +67 -0
- data/spec/unit/components/photo_player_spec.rb +76 -0
- data/spec/unit/components/tweet_player_spec.rb +68 -0
- data/spec/unit/components/you_tube_player_spec.rb +17 -0
- data/spec/unit/off_air_schedule_spec.rb +28 -0
- data/spec/unit/producer_spec.rb +2 -4
- data/spec/unit/program_schedule_proxy_spec.rb +102 -0
- data/spec/unit/program_schedule_spec.rb +191 -0
- data/spec/unit/scheduled_program_spec.rb +57 -0
- data/spec/unit/scheduling_spec.rb +61 -72
- data/vendor/assets/javascripts/bigtext.js +264 -0
- metadata +185 -44
- data/app/assets/javascripts/application.js +0 -13
- data/app/assets/javascripts/network_executive/osd.js +0 -62
- data/app/assets/javascripts/network_executive/set_top_box.js +0 -45
- data/app/controllers/network_executive/lineup_controller.rb +0 -11
- data/app/models/network_executive/channel_schedule.rb +0 -13
- data/app/models/network_executive/lineup.rb +0 -74
- data/app/models/network_executive/lineup_range.rb +0 -34
- data/app/models/network_executive/program_schedule.rb +0 -148
- data/app/views/network_executive/lineup/index.html.erb +0 -26
- data/spec/models/channel_schedule_spec.rb +0 -29
- data/spec/models/lineup_range_spec.rb +0 -65
- data/spec/models/program_schedule_spec.rb +0 -399
@@ -0,0 +1,191 @@
|
|
1
|
+
describe NetworkExecutive::ProgramSchedule do
|
2
|
+
|
3
|
+
it 'should define an Occurrence structure' do
|
4
|
+
occ = described_class::Occurrence.new
|
5
|
+
|
6
|
+
occ.should respond_to(:start_time)
|
7
|
+
occ.should respond_to(:duration)
|
8
|
+
occ.should respond_to(:end_time)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#initialize' do
|
12
|
+
context 'with an unknown program name' do
|
13
|
+
before do
|
14
|
+
NetworkExecutive::Program.stub( :find_by_name ).and_return nil
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should raise a ProgramNameError' do
|
18
|
+
expect{ described_class.new( 'null_prog' ) }.to raise_error NetworkExecutive::ProgramNameError
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with a known program name' do
|
23
|
+
let(:known_program) { double('program') }
|
24
|
+
let(:duration) { nil }
|
25
|
+
|
26
|
+
before do
|
27
|
+
NetworkExecutive::Program.stub( :find_by_name ).and_return known_program
|
28
|
+
end
|
29
|
+
|
30
|
+
subject { described_class.new( 'known', duration:duration ) }
|
31
|
+
|
32
|
+
it { should respond_to(:start_time) }
|
33
|
+
its(:program) { should == known_program }
|
34
|
+
|
35
|
+
context 'and no duration specified' do
|
36
|
+
its(:duration) { should == 24.hours }
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'and a duration specified' do
|
40
|
+
let(:duration) { 35.minutes }
|
41
|
+
|
42
|
+
its(:duration) { should == 35.minutes }
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#proxy' do
|
49
|
+
before do
|
50
|
+
NetworkExecutive::Program.stub( :find_by_name ).and_return true
|
51
|
+
end
|
52
|
+
|
53
|
+
subject { described_class.new('p').proxy }
|
54
|
+
|
55
|
+
it 'should have a schedule proxy' do
|
56
|
+
subject.should be_a NetworkExecutive::ProgramScheduleProxy
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should execute the block' do
|
60
|
+
canary = 'alive'
|
61
|
+
|
62
|
+
described_class.new('p'){ canary = 'dead' }.proxy
|
63
|
+
|
64
|
+
subject
|
65
|
+
|
66
|
+
canary.should == 'dead'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '#start_time=' do
|
71
|
+
before do
|
72
|
+
NetworkExecutive::Program.stub( :find_by_name ).and_return true
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should reset the proxy' do
|
76
|
+
time = Time.now
|
77
|
+
|
78
|
+
NetworkExecutive::ProgramScheduleProxy.should_receive(:new).with( time, anything )
|
79
|
+
|
80
|
+
described_class.new('p').start_time = time
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#duration=' do
|
85
|
+
before do
|
86
|
+
NetworkExecutive::Program.stub( :find_by_name ).and_return true
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should reset the proxy' do
|
90
|
+
time = 10.minutes
|
91
|
+
|
92
|
+
NetworkExecutive::ProgramScheduleProxy.should_receive(:new).with( anything, time )
|
93
|
+
|
94
|
+
described_class.new('p').duration = time
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe '#occurs_at?' do
|
99
|
+
before do
|
100
|
+
NetworkExecutive::Program.stub( :find_by_name ).and_return true
|
101
|
+
end
|
102
|
+
|
103
|
+
subject { described_class.new('p').occurs_at? Time.now }
|
104
|
+
|
105
|
+
it 'should delegate to its proxy' do
|
106
|
+
NetworkExecutive::ProgramScheduleProxy.any_instance.should_receive( :occurs_at? )
|
107
|
+
|
108
|
+
subject
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '#play' do
|
113
|
+
let(:program) { double('program') }
|
114
|
+
|
115
|
+
before do
|
116
|
+
NetworkExecutive::Program.stub( :find_by_name ).and_return program
|
117
|
+
end
|
118
|
+
|
119
|
+
subject { described_class.new('p').play }
|
120
|
+
|
121
|
+
it 'should delegate to its proxy' do
|
122
|
+
program.should_receive( :play )
|
123
|
+
|
124
|
+
subject do
|
125
|
+
# ...
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '#update' do
|
131
|
+
let(:program) { double('program') }
|
132
|
+
|
133
|
+
before do
|
134
|
+
NetworkExecutive::Program.stub( :find_by_name ).and_return program
|
135
|
+
end
|
136
|
+
|
137
|
+
subject { described_class.new('p').update }
|
138
|
+
|
139
|
+
it 'should delegate to its proxy' do
|
140
|
+
program.should_receive( :update )
|
141
|
+
|
142
|
+
subject do
|
143
|
+
# ...
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe '#whats_on?' do
|
149
|
+
before do
|
150
|
+
Timecop.freeze
|
151
|
+
|
152
|
+
NetworkExecutive::Program.stub( :find_by_name ).and_return double('program')
|
153
|
+
end
|
154
|
+
|
155
|
+
subject { described_class.new( 'p').whats_on? }
|
156
|
+
|
157
|
+
it 'should indicate if the schedule has anything occuring at the given time' do
|
158
|
+
NetworkExecutive::ProgramScheduleProxy.any_instance.should_receive( :occurring_at? ).with Time.now
|
159
|
+
|
160
|
+
subject
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe '#occurrence_at' do
|
165
|
+
before do
|
166
|
+
NetworkExecutive::Program.stub( :find_by_name ).and_return true
|
167
|
+
|
168
|
+
NetworkExecutive::ProgramScheduleProxy
|
169
|
+
.any_instance
|
170
|
+
.stub(:occurrences_between)
|
171
|
+
.and_return [ Time.now.end_of_day ]
|
172
|
+
end
|
173
|
+
|
174
|
+
let(:time) { Time.now.end_of_day }
|
175
|
+
|
176
|
+
subject do
|
177
|
+
described_class.new('p', start_time:time, duration:1.minute).occurrence_at time
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'should build an Occurrence' do
|
181
|
+
start_time = time.dup
|
182
|
+
duration = 1.minute - 1
|
183
|
+
end_time = start_time + duration
|
184
|
+
|
185
|
+
subject.start_time.should eq start_time
|
186
|
+
subject.duration.should eq duration
|
187
|
+
subject.end_time.should eq end_time
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
describe NetworkExecutive::ScheduledProgram do
|
4
|
+
|
5
|
+
it { should respond_to(:program) }
|
6
|
+
it { should respond_to(:occurrence) }
|
7
|
+
it { should respond_to(:remainder) }
|
8
|
+
it { should respond_to(:portion) }
|
9
|
+
|
10
|
+
describe '#display_name' do
|
11
|
+
let(:program) { double('program', display_name:'foo') }
|
12
|
+
|
13
|
+
subject { described_class.new(program).display_name }
|
14
|
+
|
15
|
+
it { should == 'foo' }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#+' do
|
19
|
+
context 'with a mismatched program' do
|
20
|
+
it 'should raise an ArgumentError' do
|
21
|
+
expect { subject + double('program') }.to raise_error ArgumentError
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with the same program type' do
|
26
|
+
let(:end_time) { Time.now }
|
27
|
+
let(:program_a) { OpenStruct.new( duration:59.seconds ) }
|
28
|
+
let(:occurrence) { OpenStruct.new( duration:59.seconds, end_time:end_time ) }
|
29
|
+
let(:program_b) { OpenStruct.new( duration:59.seconds ) }
|
30
|
+
|
31
|
+
subject do
|
32
|
+
described_class.new( program_a, occurrence ) + program_b
|
33
|
+
end
|
34
|
+
|
35
|
+
before do
|
36
|
+
program_a.stub(:occurrence).and_return double('occurrence').as_null_object
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should extend its duration with that of the other program' do
|
40
|
+
subject.program.duration.should == 119.seconds
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should extend its occurrences duration with that of the other program' do
|
44
|
+
subject.occurrence.duration.should == 119.seconds
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should extend its occurrences end time with that of the other program' do
|
48
|
+
subject.occurrence.end_time.should == end_time + 1.minute
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should return itself' do
|
52
|
+
subject.should be_a NetworkExecutive::ScheduledProgram
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -1,106 +1,95 @@
|
|
1
1
|
describe NetworkExecutive::Scheduling do
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
include NetworkExecutive::Scheduling
|
7
|
-
|
8
|
-
every :day, play:'my_show'
|
9
|
-
end
|
10
|
-
|
11
|
-
channel.schedule.first.should be_a NetworkExecutive::ProgramSchedule
|
3
|
+
let(:klass) do
|
4
|
+
Class.new do
|
5
|
+
include NetworkExecutive::Scheduling
|
12
6
|
end
|
13
7
|
end
|
14
8
|
|
15
|
-
|
16
|
-
|
17
|
-
channel = Class.new( NetworkExecutive::Channel ) do
|
18
|
-
include NetworkExecutive::Scheduling
|
19
|
-
end
|
20
|
-
|
21
|
-
channel.schedule.should be_a NetworkExecutive::ChannelSchedule
|
22
|
-
end
|
9
|
+
before do
|
10
|
+
stub_const 'MyChannel', klass
|
23
11
|
end
|
24
12
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
13
|
+
subject { MyChannel.new }
|
14
|
+
|
15
|
+
describe '.schedule' do
|
16
|
+
context 'with a block' do
|
17
|
+
it 'should add a program' do
|
18
|
+
params = [
|
19
|
+
'program',
|
20
|
+
kind_of(Hash)
|
21
|
+
]
|
22
|
+
|
23
|
+
NetworkExecutive::ChannelSchedule.any_instance.should_receive( :add ).with( *params )
|
24
|
+
|
25
|
+
MyChannel.schedule( 'program' ) do
|
26
|
+
# ...
|
27
|
+
end
|
29
28
|
end
|
30
29
|
end
|
31
30
|
|
32
|
-
context '
|
33
|
-
it 'should
|
34
|
-
|
31
|
+
context 'without a block' do
|
32
|
+
it 'should be a ChannelSchedule' do
|
33
|
+
MyChannel.schedule.should be_a NetworkExecutive::ChannelSchedule
|
35
34
|
end
|
36
35
|
end
|
36
|
+
end
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
channel.schedule.add double('program a', include?: false)
|
42
|
-
channel.schedule.add double('program b', include?: true)
|
43
|
-
channel.schedule.add program_c
|
44
|
-
channel.schedule.add double('program d', include?: false)
|
45
|
-
|
46
|
-
channel.new.whats_on?.should == program_c
|
38
|
+
describe '#schedule' do
|
39
|
+
it 'should be a ChannelSchedule' do
|
40
|
+
subject.schedule.should be_a NetworkExecutive::ChannelSchedule
|
47
41
|
end
|
42
|
+
end
|
48
43
|
|
49
|
-
|
50
|
-
|
51
|
-
program_b.stub(:include?).and_return true, false
|
52
|
-
|
53
|
-
program_c = double 'program c'
|
54
|
-
program_c.stub(:include?).and_return false, true
|
55
|
-
|
56
|
-
channel.schedule.add double('program a', include?: false)
|
57
|
-
channel.schedule.add program_b
|
58
|
-
channel.schedule.add program_c
|
59
|
-
channel.schedule.add double('program d', include?: false)
|
44
|
+
describe '#whats_on?' do
|
45
|
+
before { Timecop.freeze }
|
60
46
|
|
61
|
-
|
47
|
+
it 'should return what is on right now' do
|
48
|
+
subject.should_receive( :whats_on_at? ).with( Time.now.change(sec:0) )
|
62
49
|
|
63
|
-
|
64
|
-
shows.last[:program].should be program_c
|
50
|
+
subject.whats_on?
|
65
51
|
end
|
52
|
+
end
|
66
53
|
|
67
|
-
|
68
|
-
|
69
|
-
|
54
|
+
describe '#whats_on_at?' do
|
55
|
+
context 'with nothing scheduled' do
|
56
|
+
before do
|
57
|
+
NetworkExecutive::ChannelSchedule.any_instance.stub(:find).and_return nil
|
58
|
+
end
|
70
59
|
|
71
|
-
|
72
|
-
|
60
|
+
it 'should return OffAir' do
|
61
|
+
subject.whats_on_at?( Time.now ).should be_a NetworkExecutive::OffAirSchedule
|
73
62
|
end
|
74
63
|
end
|
75
|
-
end
|
76
64
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
65
|
+
context 'with something scheduled' do
|
66
|
+
let(:prog_1) { double('unscheduled', whats_on?: false) }
|
67
|
+
let(:prog_2) { double('scheduled', whats_on?: true) }
|
68
|
+
let(:prog_3) { double('unscheduled', whats_on?: false) }
|
81
69
|
|
82
|
-
|
70
|
+
before do
|
71
|
+
subject.schedule << prog_1
|
72
|
+
subject.schedule << prog_2
|
73
|
+
subject.schedule << prog_3
|
83
74
|
end
|
84
|
-
end
|
85
|
-
|
86
|
-
let(:channel) { klass.new }
|
87
75
|
|
88
|
-
|
89
|
-
|
76
|
+
it 'should return the scheduled program' do
|
77
|
+
subject.whats_on_at?( Time.now ).should == prog_2
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
90
81
|
|
91
|
-
|
82
|
+
describe '#whats_on_between?' do
|
83
|
+
it 'should ask the ChannelSchedule what is on between two dates' do
|
84
|
+
date_a = Time.now
|
85
|
+
date_b = date_a + 1.5.hours
|
92
86
|
|
93
|
-
|
87
|
+
args = [ date_a, date_b, nil ]
|
94
88
|
|
95
|
-
|
96
|
-
'block retval'
|
97
|
-
end
|
98
|
-
end
|
89
|
+
NetworkExecutive::ChannelSchedule.any_instance.should_receive(:whats_on_between?).with( *args )
|
99
90
|
|
100
|
-
|
101
|
-
subject.all?{ |x| x == 'block retval' }.should be_true
|
91
|
+
subject.whats_on_between? date_a, date_b
|
102
92
|
end
|
103
|
-
|
104
93
|
end
|
105
94
|
|
106
95
|
end
|
@@ -0,0 +1,264 @@
|
|
1
|
+
;(function(window, $)
|
2
|
+
{
|
3
|
+
var counter = 0,
|
4
|
+
$headCache = $('head'),
|
5
|
+
oldBigText = window.BigText,
|
6
|
+
oldjQueryMethod = $.fn.bigtext,
|
7
|
+
BigText = {
|
8
|
+
DEFAULT_MIN_FONT_SIZE_PX: null,
|
9
|
+
DEFAULT_MAX_FONT_SIZE_PX: 528,
|
10
|
+
GLOBAL_STYLE_ID: 'bigtext-style',
|
11
|
+
STYLE_ID: 'bigtext-id',
|
12
|
+
LINE_CLASS_PREFIX: 'bigtext-line',
|
13
|
+
EXEMPT_CLASS: 'bigtext-exempt',
|
14
|
+
DEFAULT_CHILD_SELECTOR: '> div',
|
15
|
+
childSelectors: {
|
16
|
+
div: '> div',
|
17
|
+
ol: '> li',
|
18
|
+
ul: '> li'
|
19
|
+
},
|
20
|
+
noConflict: function(restore)
|
21
|
+
{
|
22
|
+
if(restore) {
|
23
|
+
$.fn.bigtext = oldjQueryMethod;
|
24
|
+
window.BigText = oldBigText;
|
25
|
+
}
|
26
|
+
return BigText;
|
27
|
+
},
|
28
|
+
init: function()
|
29
|
+
{
|
30
|
+
if(!$('#'+BigText.GLOBAL_STYLE_ID).length) {
|
31
|
+
$headCache.append(BigText.generateStyleTag(BigText.GLOBAL_STYLE_ID, ['.bigtext * { white-space: nowrap; }',
|
32
|
+
'.bigtext .' + BigText.EXEMPT_CLASS + ', .bigtext .' + BigText.EXEMPT_CLASS + ' * { white-space: normal; }']));
|
33
|
+
}
|
34
|
+
},
|
35
|
+
bindResize: function(eventName, resizeFunction)
|
36
|
+
{
|
37
|
+
if($.throttle) {
|
38
|
+
// https://github.com/cowboy/jquery-throttle-debounce
|
39
|
+
$(window).unbind(eventName).bind(eventName, $.throttle(100, resizeFunction));
|
40
|
+
} else {
|
41
|
+
if($.fn.smartresize) {
|
42
|
+
// https://github.com/lrbabe/jquery-smartresize/
|
43
|
+
eventName = 'smartresize.' + eventName;
|
44
|
+
}
|
45
|
+
$(window).unbind(eventName).bind(eventName, resizeFunction);
|
46
|
+
}
|
47
|
+
},
|
48
|
+
getStyleId: function(id)
|
49
|
+
{
|
50
|
+
return BigText.STYLE_ID + '-' + id;
|
51
|
+
},
|
52
|
+
generateStyleTag: function(id, css)
|
53
|
+
{
|
54
|
+
return $('<style>' + css.join('\n') + '</style>').attr('id', id);
|
55
|
+
},
|
56
|
+
clearCss: function(id)
|
57
|
+
{
|
58
|
+
var styleId = BigText.getStyleId(id);
|
59
|
+
$('#' + styleId).remove();
|
60
|
+
},
|
61
|
+
generateCss: function(id, linesFontSizes, lineWordSpacings, minFontSizes)
|
62
|
+
{
|
63
|
+
var css = [];
|
64
|
+
|
65
|
+
BigText.clearCss(id);
|
66
|
+
|
67
|
+
for(var j=0, k=linesFontSizes.length; j<k; j++) {
|
68
|
+
css.push('#' + id + ' .' + BigText.LINE_CLASS_PREFIX + j + ' {' +
|
69
|
+
(minFontSizes[j] ? ' white-space: normal;' : '') +
|
70
|
+
(linesFontSizes[j] ? ' font-size: ' + linesFontSizes[j] + 'px;' : '') +
|
71
|
+
(lineWordSpacings[j] ? ' word-spacing: ' + lineWordSpacings[j] + 'px;' : '') +
|
72
|
+
'}');
|
73
|
+
}
|
74
|
+
|
75
|
+
return BigText.generateStyleTag(BigText.getStyleId(id), css);
|
76
|
+
},
|
77
|
+
jQueryMethod: function(options)
|
78
|
+
{
|
79
|
+
BigText.init();
|
80
|
+
|
81
|
+
options = $.extend({
|
82
|
+
minfontsize: BigText.DEFAULT_MIN_FONT_SIZE_PX,
|
83
|
+
maxfontsize: BigText.DEFAULT_MAX_FONT_SIZE_PX,
|
84
|
+
childSelector: '',
|
85
|
+
resize: true
|
86
|
+
}, options || {});
|
87
|
+
|
88
|
+
return this.each(function()
|
89
|
+
{
|
90
|
+
var $t = $(this).addClass('bigtext'),
|
91
|
+
childSelector = options.childSelector ||
|
92
|
+
BigText.childSelectors[this.tagName.toLowerCase()] ||
|
93
|
+
BigText.DEFAULT_CHILD_SELECTOR,
|
94
|
+
maxWidth = $t.width(),
|
95
|
+
id = $t.attr('id');
|
96
|
+
|
97
|
+
if(!id) {
|
98
|
+
id = 'bigtext-id' + (counter++);
|
99
|
+
$t.attr('id', id);
|
100
|
+
}
|
101
|
+
|
102
|
+
if(options.resize) {
|
103
|
+
BigText.bindResize('resize.bigtext-event-' + id, function()
|
104
|
+
{
|
105
|
+
BigText.jQueryMethod.call($('#' + id), options);
|
106
|
+
});
|
107
|
+
}
|
108
|
+
|
109
|
+
BigText.clearCss(id);
|
110
|
+
|
111
|
+
$t.find(childSelector).addClass(function(lineNumber, className)
|
112
|
+
{
|
113
|
+
// remove existing line classes.
|
114
|
+
return [className.replace(new RegExp('\\b' + BigText.LINE_CLASS_PREFIX + '\\d+\\b'), ''),
|
115
|
+
BigText.LINE_CLASS_PREFIX + lineNumber].join(' ');
|
116
|
+
});
|
117
|
+
|
118
|
+
var sizes = calculateSizes($t, childSelector, maxWidth, options.maxfontsize, options.minfontsize);
|
119
|
+
$headCache.append(BigText.generateCss(id, sizes.fontSizes, sizes.wordSpacings, sizes.minFontSizes));
|
120
|
+
});
|
121
|
+
}
|
122
|
+
};
|
123
|
+
|
124
|
+
function testLineDimensions($line, maxWidth, property, size, interval, units)
|
125
|
+
{
|
126
|
+
var width;
|
127
|
+
$line.css(property, size + units);
|
128
|
+
|
129
|
+
width = $line.width();
|
130
|
+
|
131
|
+
if(width >= maxWidth) {
|
132
|
+
$line.css(property, '');
|
133
|
+
|
134
|
+
if(width == maxWidth) {
|
135
|
+
return {
|
136
|
+
match: 'exact',
|
137
|
+
size: parseFloat((parseFloat(size) - 0.1).toFixed(3))
|
138
|
+
};
|
139
|
+
}
|
140
|
+
|
141
|
+
return {
|
142
|
+
match: 'estimate',
|
143
|
+
size: parseFloat((parseFloat(size) - interval).toFixed(3))
|
144
|
+
};
|
145
|
+
}
|
146
|
+
|
147
|
+
return false;
|
148
|
+
}
|
149
|
+
|
150
|
+
function calculateSizes($t, childSelector, maxWidth, maxFontSize, minFontSize)
|
151
|
+
{
|
152
|
+
var $c = $t.clone(true)
|
153
|
+
.addClass('bigtext-cloned')
|
154
|
+
.css({
|
155
|
+
fontFamily: $t.css('font-family'),
|
156
|
+
'min-width': parseInt(maxWidth, 10),
|
157
|
+
width: 'auto',
|
158
|
+
position: 'absolute',
|
159
|
+
left: -9999,
|
160
|
+
top: -9999
|
161
|
+
}).appendTo(document.body);
|
162
|
+
|
163
|
+
// font-size isn't the only thing we can modify, we can also mess with:
|
164
|
+
// word-spacing and letter-spacing.
|
165
|
+
// Note: webkit does not respect subpixel letter-spacing or word-spacing,
|
166
|
+
// nor does it respect hundredths of a font-size em.
|
167
|
+
var fontSizes = [],
|
168
|
+
wordSpacings = [],
|
169
|
+
minFontSizes = [],
|
170
|
+
ratios = [];
|
171
|
+
|
172
|
+
$c.find(childSelector).css({
|
173
|
+
'float': 'left',
|
174
|
+
'clear': 'left'
|
175
|
+
}).each(function(lineNumber) {
|
176
|
+
var $line = $(this),
|
177
|
+
intervals = [4,1,.4,.1],
|
178
|
+
lineMax;
|
179
|
+
|
180
|
+
if($line.hasClass(BigText.EXEMPT_CLASS)) {
|
181
|
+
fontSizes.push(null);
|
182
|
+
ratios.push(null);
|
183
|
+
minFontSizes.push(false);
|
184
|
+
return;
|
185
|
+
}
|
186
|
+
|
187
|
+
// TODO we can cache this ratio?
|
188
|
+
var autoGuessSubtraction = 20, // px
|
189
|
+
currentFontSize = parseFloat($line.css('font-size')),
|
190
|
+
lineWidth = $line.width(),
|
191
|
+
ratio = (lineWidth / currentFontSize).toFixed(6),
|
192
|
+
newFontSize = parseFloat(((maxWidth - autoGuessSubtraction) / ratio).toFixed(3));
|
193
|
+
|
194
|
+
outer: for(var m=0, n=intervals.length; m<n; m++) {
|
195
|
+
inner: for(var j=1, k=4; j<=k; j++) {
|
196
|
+
if(newFontSize + j*intervals[m] > maxFontSize) {
|
197
|
+
newFontSize = maxFontSize;
|
198
|
+
break outer;
|
199
|
+
}
|
200
|
+
|
201
|
+
lineMax = testLineDimensions($line, maxWidth, 'font-size', newFontSize + j*intervals[m], intervals[m], 'px');
|
202
|
+
if(lineMax !== false) {
|
203
|
+
newFontSize = lineMax.size;
|
204
|
+
|
205
|
+
if(lineMax.match == 'exact') {
|
206
|
+
break outer;
|
207
|
+
}
|
208
|
+
break inner;
|
209
|
+
}
|
210
|
+
}
|
211
|
+
}
|
212
|
+
|
213
|
+
ratios.push(maxWidth / newFontSize);
|
214
|
+
|
215
|
+
if(newFontSize > maxFontSize) {
|
216
|
+
fontSizes.push(maxFontSize);
|
217
|
+
minFontSizes.push(false);
|
218
|
+
} else if(!!minFontSize && newFontSize < minFontSize) {
|
219
|
+
fontSizes.push(minFontSize);
|
220
|
+
minFontSizes.push(true);
|
221
|
+
} else {
|
222
|
+
fontSizes.push(newFontSize);
|
223
|
+
minFontSizes.push(false);
|
224
|
+
}
|
225
|
+
}).each(function(lineNumber) {
|
226
|
+
var $line = $(this),
|
227
|
+
wordSpacing = 0,
|
228
|
+
interval = 1,
|
229
|
+
maxWordSpacing;
|
230
|
+
|
231
|
+
if($line.hasClass(BigText.EXEMPT_CLASS)) {
|
232
|
+
wordSpacings.push(null);
|
233
|
+
return;
|
234
|
+
}
|
235
|
+
|
236
|
+
// must re-use font-size, even though it was removed above.
|
237
|
+
$line.css('font-size', fontSizes[lineNumber] + 'px');
|
238
|
+
|
239
|
+
for(var m=1, n=5; m<n; m+=interval) {
|
240
|
+
maxWordSpacing = testLineDimensions($line, maxWidth, 'word-spacing', m, interval, 'px');
|
241
|
+
if(maxWordSpacing !== false) {
|
242
|
+
wordSpacing = maxWordSpacing.size;
|
243
|
+
break;
|
244
|
+
}
|
245
|
+
}
|
246
|
+
|
247
|
+
$line.css('font-size', '');
|
248
|
+
wordSpacings.push(wordSpacing);
|
249
|
+
}).removeAttr('style');
|
250
|
+
|
251
|
+
$c.remove();
|
252
|
+
|
253
|
+
return {
|
254
|
+
fontSizes: fontSizes,
|
255
|
+
wordSpacings: wordSpacings,
|
256
|
+
ratios: ratios,
|
257
|
+
minFontSizes: minFontSizes
|
258
|
+
};
|
259
|
+
}
|
260
|
+
|
261
|
+
$.fn.bigtext = BigText.jQueryMethod;
|
262
|
+
window.BigText = BigText;
|
263
|
+
|
264
|
+
})(this, jQuery);
|