diff --git a/app/assets/javascripts/timetable.js b/app/assets/javascripts/timetable.js index 1b8f25f..b9c9947 100644 --- a/app/assets/javascripts/timetable.js +++ b/app/assets/javascripts/timetable.js @@ -4,4 +4,5 @@ //= require timetable/timetable //= require timetable/group //= require timetable/lecturer +//= require timetable/classrooms //= require timetable/terminal diff --git a/app/assets/javascripts/timetable/classrooms.js.erb b/app/assets/javascripts/timetable/classrooms.js.erb new file mode 100644 index 0000000..4ab8005 --- /dev/null +++ b/app/assets/javascripts/timetable/classrooms.js.erb @@ -0,0 +1,56 @@ +<% +building_c = < +

'+building.name+' корпус

' +eos +building_c.gsub!(/\n\s*/, "") +content = < +

'+classroom.name+(classroom.title ? ': '+classroom.title+'' : '')+'

+ Расписание +' +eos +content.gsub!(/\n\s*/, "") +%> + +jQuery(document).ready(function($) { + + $('#classroom_name_input').on('input', function () { + $.ajax({ + url: "/timetable/classrooms.json", + data: {classroom: $(this).val()}, + dataType: 'json', + timeout: 15000, + beforeSend: function (jqXHR, settings) { + $(".ajax_message").hide(); + $(".ajax_spinner").show(); + $(".ajax_loading").show(); + }, + error: function (jqXHR, textStatus, errorThrown) { + $(".ajax_error").show(); + }, + success: function (data, textStatus, jqXHR) { + if (data.length) { + $(".list_box").empty(); + $.each(data, function (i, elem) { + var building = elem.building; + var html = <%= building_c %>; + $.each(building.classrooms, function (j, classroom) { + html += <%= content %>; + }); + $(html+'').appendTo(".list_box"); + }); + } else { + $(".ajax_not_found").show(); + } + }, + complete: function (jqXHR, textStatus) { + $(".ajax_spinner").hide(); + $(".ajax_loading").hide(); + } + }); + }); + + if ($('#lecturer_name_input').val()) $('#lecturer_name_input').trigger('input'); + +}); \ No newline at end of file diff --git a/app/assets/javascripts/timetable/timetable.js b/app/assets/javascripts/timetable/timetable.js index cc3d521..2091004 100644 --- a/app/assets/javascripts/timetable/timetable.js +++ b/app/assets/javascripts/timetable/timetable.js @@ -9,7 +9,7 @@ jQuery(document).ready(function($){ timer = setTimeout("window.location.reload(true)", 45000); }); - $('.list_box').on('click', '.group, .lecturer', function () { + $('.list_box').on('click', '.group, .lecturer, .classroom', function () { location.href = $('a', this).attr("href"); }); diff --git a/app/assets/stylesheets/timetable.css.scss b/app/assets/stylesheets/timetable.css.scss index be5a208..b70a183 100644 --- a/app/assets/stylesheets/timetable.css.scss +++ b/app/assets/stylesheets/timetable.css.scss @@ -7,6 +7,7 @@ *= require timetable/timetable *= require timetable/group *= require timetable/lecturer +*= require timetable/classrooms *= require timetable/terminal *= require about *= require help @@ -85,8 +86,8 @@ body.timetable { & li { float: left; - width: 250px; - font: normal 1.5em "Cuprum",sans-serif; + width: 175px; + font: normal 1.2em "Cuprum",sans-serif; list-style: none; border-right: 1px dotted silver; border-left: 1px dotted silver; @@ -97,7 +98,7 @@ body.timetable { display: block; width: 100%; height: 100%; - padding: 0.3em 0; + padding: 0.5em 0; text-align: center; text-decoration: none; text-shadow: white 1px 1px 2px; diff --git a/app/assets/stylesheets/timetable/classrooms.css.scss b/app/assets/stylesheets/timetable/classrooms.css.scss new file mode 100644 index 0000000..cac9308 --- /dev/null +++ b/app/assets/stylesheets/timetable/classrooms.css.scss @@ -0,0 +1,121 @@ +/* Keyboard preferences */ +$key_width: 2em; +$key_margin: 0.25em; +$keyboard_width: 12*($key_width+2*$key_margin); + +div.classroom_timetable_search { + + label { + display: block; + margin-bottom: 1em; + } + + .search_box { + -moz-box-sizing: border-box; + box-sizing: border-box; + font-size: 1.2em; + padding: 0.5em; + position: static; + overflow: hidden; + top: 49px; + width: 100%; + z-index: 0; + border-bottom: 1px solid silver; + background: #F0F0F9; + -moz-box-shadow: 1px 1px 10px 0 rgba(0,0,0,0.25); + -webkit-box-shadow: 1px 1px 10px 0 rgba(0,0,0,0.25); + box-shadow: 1px 1px 10px 0 rgba(0,0,0,0.25); + background-image: -o-linear-gradient(top, #dfdfe6 0%, #F0F0F9 50%, #dfdfe6 100%); + background-image: -moz-linear-gradient(top, #dfdfe6 0%, #F0F0F9 50%, #dfdfe6 100%); + background-image: -webkit-linear-gradient(top, #dfdfe6 0%, #F0F0F9 50%, #dfdfe6 100%); + background-image: -ms-linear-gradient(top, #dfdfe6 0%, #F0F0F9 50%, #dfdfe6 100%); + background-image: linear-gradient(top, #dfdfe6 0%, #F0F0F9 50%, #dfdfe6 100%); + + form { + margin-left: $keyboard_width; + } + + } + + .keyboard { + margin: 0; + text-align: center; + float: left; + width: $keyboard_width; + + .kbd_row { + overflow: hidden; + margin: 0 auto; + text-align: center; + + &.large { + font-size: 120%; + } + + } + + @for $i from 9 through 12 { + .kbd_row.k#{$i} { + width: $i*($key_width+2*$key_margin); + } + } + + .key { + float: left; + margin: $key_margin - 0.05em; // Strange Opera behaviour fix here + width: $key_width; + text-align: center; + font-size: 1em; + font-weight: bold; + } + + .key.backspace, .key.clear { + color: maroon !important; + } + + .key.whitespace { + width: 6*($key_width+2*$key_margin); + } + + .key.backspace { + width: 1.5*$key_width; + } + + } + + .list_box { + margin: 0; + + h2 { + font-size: 200%; + margin-bottom: 0.5em; + margin-top: 1.5em; + } + + .classroom { + padding: 0.5em 1em; + border: 1px dotted silver; + margin: -1px; + clear: both; + overflow: hidden; + + h3 { + margin: 0; + padding: 0.1em 1em 0.1em 0; + font-size: 2em; + float: left; + clear: left; + } + + a.button { + display: block; + width: 200px; + float: right; + font-size: 1.5em; + } + + } + + } + +} diff --git a/app/controllers/timetable/classrooms_controller.rb b/app/controllers/timetable/classrooms_controller.rb new file mode 100644 index 0000000..5032d95 --- /dev/null +++ b/app/controllers/timetable/classrooms_controller.rb @@ -0,0 +1,35 @@ +class Timetable::ClassroomsController < Timetable::BaseController + + def index + @buildings = Building.includes(:classrooms).reorder("buildings.id,(substring(classrooms.name, '^[0-9]+'))::int,substring(classrooms.name, '[^0-9_].*$')") + @buildings = @buildings.where("classrooms.name ILIKE ? OR classrooms.title ILIKE ? OR buildings.name ILIKE ?", *(["%#{params[:classroom]}%"]*3)) if params[:classroom] + respond_to do |format| + format.html do + if @buildings.count == 1 and @buildings.first.classrooms.count == 1 + redirect_to timetable_classroom_path(@buildings.first.classrooms.first) + end + end + format.json do + render :json => @buildings.to_json(only: [:id, :name], include: {classrooms: {only: [:id, :title, :name]}}) + end + end + end + + def show + @id = params[:id].to_i + unless @classroom = Classroom.find_by_id(@id) + suffix = @terminal ? '?terminal=true' : '' + redirect_to :controller => 'timetable/classrooms' + suffix + else + pairs = @classroom.pairs.includes(:subgroups).in_semester(current_semester).flatten + @days = Timetable.days + @times = Timetable.times + @weeks = Timetable.weeks + @pairs = Array.new(@days.size).map!{Array.new(@times.size).map!{Array.new(@weeks.size + 1).map!{Array.new}}} + pairs.each do |pair| + @pairs[pair.day_of_the_week - 1][pair.pair_number - 1][pair.week] << pair + end + end + end + +end diff --git a/app/helpers/timetable/classrooms_helper.rb b/app/helpers/timetable/classrooms_helper.rb new file mode 100644 index 0000000..09a9741 --- /dev/null +++ b/app/helpers/timetable/classrooms_helper.rb @@ -0,0 +1,2 @@ +module Timetable::ClassroomsHelper +end diff --git a/app/views/application/_timetable_main_menu.html.haml b/app/views/application/_timetable_main_menu.html.haml index 69924be..8ca12a6 100644 --- a/app/views/application/_timetable_main_menu.html.haml +++ b/app/views/application/_timetable_main_menu.html.haml @@ -3,6 +3,8 @@ #{link_to "Группы", timetable_groups_path} %li #{link_to "Преподаватели", timetable_lecturers_path} + %li + #{link_to "Аудитории", timetable_classrooms_path} - if @terminal %menu.help_menu %li diff --git a/app/views/timetable/classrooms/_day.html.haml b/app/views/timetable/classrooms/_day.html.haml new file mode 100644 index 0000000..bdf9239 --- /dev/null +++ b/app/views/timetable/classrooms/_day.html.haml @@ -0,0 +1,25 @@ +- both_week_pairs = @pairs[day_counter][time][0] +- first_week_pairs = @pairs[day_counter][time][1] +- second_week_pairs = @pairs[day_counter][time][2] +%td + -# Uncomment for debug purpose only! + =# both_week_pairs.size + =# first_week_pairs.size + =# second_week_pairs.size + - if both_week_pairs.empty? and first_week_pairs.empty? and second_week_pairs.empty? + .nopair + - else + .daycellcontainer{:title => day} + %table{:class => 'daycell'} + - if both_week_pairs.any? and !first_week_pairs.any? and !second_week_pairs.any? + %tr + = render 'week_in_day', :pairs => both_week_pairs, :skipcell => [], :singlerow => true + - else + - skipcell = [] + %tr + - if first_week_pairs.any? or both_week_pairs.any? + = render 'week_in_day', :pairs => first_week_pairs+both_week_pairs, :skipcell => skipcell, :singlerow => false + %tr + - if second_week_pairs.any? + = render 'week_in_day', :pairs => second_week_pairs, :skipcell => skipcell, :singlerow => false + diff --git a/app/views/timetable/classrooms/_day_header.html.haml b/app/views/timetable/classrooms/_day_header.html.haml new file mode 100644 index 0000000..abb2c94 --- /dev/null +++ b/app/views/timetable/classrooms/_day_header.html.haml @@ -0,0 +1,2 @@ +%th + = day_header \ No newline at end of file diff --git a/app/views/timetable/classrooms/_pair.html.haml b/app/views/timetable/classrooms/_pair.html.haml new file mode 100644 index 0000000..e27c5ea --- /dev/null +++ b/app/views/timetable/classrooms/_pair.html.haml @@ -0,0 +1,12 @@ +- flow = p.charge_card.groups.map{|g| g.name }.join ", " +.pair + = "#{flow}" + %br + - if p.assistant && p.assistant_id + .lecturer #{p.lecturer}, #{p.assistant} + - else + .lecturer #{p.lecturer} + = "#{p.discipline}" + - if ![1,2,9].include?(p.active_at.month) or ![5,6,7,12].include?(p.expired_at.month) + %br + с #{p.active_at} по #{p.expired_at} diff --git a/app/views/timetable/classrooms/_time.html.haml b/app/views/timetable/classrooms/_time.html.haml new file mode 100644 index 0000000..a360379 --- /dev/null +++ b/app/views/timetable/classrooms/_time.html.haml @@ -0,0 +1,4 @@ +%tr.timetablerow + %th + = time + = render :partial => 'day', :collection => @days, :locals => {:time => time_counter} \ No newline at end of file diff --git a/app/views/timetable/classrooms/_week_in_day.html.haml b/app/views/timetable/classrooms/_week_in_day.html.haml new file mode 100644 index 0000000..9e583e0 --- /dev/null +++ b/app/views/timetable/classrooms/_week_in_day.html.haml @@ -0,0 +1,37 @@ +- subgroups = [] +- to_display = [] +- pairs.sort_by { |p| p.expired_at }.each do |b| + - b.subgroups.each do |s| + - if !subgroups.include?(s.number) + - subgroups << s.number + - subgroups << 0 # Если есть пара с подгруппами, то пара без подгрупп уже не влезет + - to_display << [b, s.number] + +- if to_display.size > 0 + -# Если без подгрупп или есть только одна пара 3-ей или ещё какой подгруппы + - if subgroups.max == 0 or (subgroups.max > 2 and to_display.size == 1) + %td{:colspan => 2} + - pair = to_display.first[0] + = render 'pair', :p => pair, :s => to_display.first[1] + - else + -# Если есть пара третьей или большей подгруппы и есть место куда её воткнуть + - to_display.find_all{ |elem| elem[1] > 2 }.each do |elem| + - if subgroups.max > 2 and to_display.size == 2 and to_display.size - skipcell.size > 0 + - elem[2] = elem[1] # elem[1] - подгруппа-позиция, elem[2] - реальная подгруппа пары + - elem[1] = to_display.find_all{ |elem| elem[1] == 1 }.size > 1 ? 2 : 1 + - 1.upto(2) do |sub| + - if skipcell.include?(sub) + - skipcell - [sub] + - next + - sp = to_display.find_all{ |elem| elem[1] == sub } + - if sp.size > 0 + - pair = sp.first[0] + - a = {} + - if pair.week == 0 and !singlerow + - skipcell << sub + - a = {:rowspan=>2} + %td{a} + = render 'pair', :p => pair, :s => sp.first[2] + - else + %td.empty + diff --git a/app/views/timetable/classrooms/index.html.haml b/app/views/timetable/classrooms/index.html.haml new file mode 100644 index 0000000..305231e --- /dev/null +++ b/app/views/timetable/classrooms/index.html.haml @@ -0,0 +1,45 @@ +- title "Аудитории" + +.classroom_timetable_search + .search_box + .keyboard + .kbd_row.k10.large + - (1..10).each do |letter| + .key.classroom_letter #{letter%10} + .kbd_row.k12 + - %w(й ц у к е н г ш щ з х ъ).each do |letter| + .key.classroom_letter #{letter} + .kbd_row.k11 + - %w(ф ы в а п р о л д ж э).each do |letter| + .key.classroom_letter #{letter} + .kbd_row.k10 + - %w(я ч с м и т ь б ю .).each do |letter| + .key.classroom_letter #{letter} + .kbd_row.k9 + .key.clear ✖ + .key.whitespace   + .key.backspace ⌫ + = form_tag(url_for(), :method => "get") do + - if @terminal + %input{:type => :hidden, :name => :terminal, :value => @terminal} + %label{:for => "classroom_name_input"} Введите номер аудитории для поиска: + %input.timetable_input#classroom_name_input{:autofocus => true, :name => :classroom, :value => params[:classroom]} + %button{:type => "submit"} > + .list_box + - @buildings.each do |building| + .building + %h2 #{building.name} корпус + - building.classrooms.each do |classroom| + .classroom + %h3< + #{classroom.name} + - if classroom.title + %small> : #{classroom.title} + = link_to "Расписание", timetable_classroom_path(classroom), :class => "button link_to_timetable" + + .ajax_messages_container + .ajax_spinner + .ajax_spinner_image + .ajax_message.ajax_loading Ищем аудитории по вашему запросу… + .ajax_message.ajax_error Произошла ошибка при выполнении запроса. Пожалуйста, попробуйте ещё раз чуть позже. + .ajax_message.ajax_not_found Мы не нашли таких аудиторий в базе! Может быть, вы ошиблись при вводе? diff --git a/app/views/timetable/classrooms/show.html.haml b/app/views/timetable/classrooms/show.html.haml new file mode 100644 index 0000000..a57703b --- /dev/null +++ b/app/views/timetable/classrooms/show.html.haml @@ -0,0 +1,22 @@ +- title @classroom.full_name + += link_to "Назад", timetable_classrooms_path, :class => "button back_button", :id => "back_button_top" + +.timetable.lecturer_timetable + %h2 Аудитория #{@classroom.full_name}. Расписание учебных пар. + %p #{@classroom.capacity ? "Вместимость: #{@classroom.capacity} #{Russian.p(@classroom.capacity, "человек", "человека", "человек")}" : "Вместимость не указана"}#{", #{@classroom.properties_human}" if @classroom.properties_human.present?}. + - if @classroom.department.present? + %p Закреплена за кафедрой: #{@classroom.department.name} (#{@classroom.department.faculty.try(:name)}) + %table + %colgroup + %col.timecells + - 6.times do + %col.daycells + %thead + %tr + %th + = render :partial => 'day_header', :collection => @days + %tbody + = render :partial => 'time', :collection => @times + += link_to "Назад", timetable_classrooms_path, :class => "button back_button", :id => "back_button_bottom" diff --git a/config/routes.rb b/config/routes.rb index be45ebc..577590f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -8,6 +8,7 @@ namespace :timetable do resources :groups resources :lecturers + resources :classrooms root :to => redirect('/timetable/groups') end diff --git a/spec/controllers/timetable/classrooms_controller_spec.rb b/spec/controllers/timetable/classrooms_controller_spec.rb new file mode 100644 index 0000000..69110f5 --- /dev/null +++ b/spec/controllers/timetable/classrooms_controller_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe Timetable::ClassroomsController do + +end diff --git a/spec/helpers/timetable/classrooms_helper_spec.rb b/spec/helpers/timetable/classrooms_helper_spec.rb new file mode 100644 index 0000000..d1c3cb4 --- /dev/null +++ b/spec/helpers/timetable/classrooms_helper_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +# Specs in this file have access to a helper object that includes +# the Timetable::ClassroomsHelper. For example: +# +# describe Timetable::ClassroomsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# helper.concat_strings("this","that").should == "this that" +# end +# end +# end +describe Timetable::ClassroomsHelper do + pending "add some examples to (or delete) #{__FILE__}" +end