diff --git a/Gemfile.lock b/Gemfile.lock index f341328..8b2f435 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -15,7 +15,7 @@ GEM arel (3.0.2) bcrypt-ruby (3.0.1) builder (3.0.4) - haml (4.0.0) + haml (4.0.1) tilt http_router (0.10.2) rack (>= 1.0.0) @@ -26,7 +26,7 @@ GEM mime-types (~> 1.16) treetop (~> 1.4.8) mime-types (1.21) - multi_json (1.6.1) + multi_json (1.7.2) padrino (0.10.7) padrino-admin (= 0.10.7) padrino-cache (= 0.10.7) @@ -56,10 +56,10 @@ GEM padrino-core (= 0.10.7) polyglot (0.3.3) rack (1.5.2) - rack-protection (1.4.0) + rack-protection (1.5.0) rack rake (10.0.3) - sinatra (1.3.5) + sinatra (1.3.6) rack (~> 1.4) rack-protection (~> 1.3) tilt (~> 1.3, >= 1.3.3) @@ -67,11 +67,11 @@ GEM sinatra (>= 1.0.0) sqlite3 (1.3.7) thor (0.15.4) - tilt (1.3.4) + tilt (1.3.6) treetop (1.4.12) polyglot polyglot (>= 0.3.1) - tzinfo (0.3.35) + tzinfo (0.3.37) url_mount (0.2.1) rack diff --git a/admin/views/books/_form.haml b/admin/views/books/_form.haml index bb2d707..5e2070d 100644 --- a/admin/views/books/_form.haml +++ b/admin/views/books/_form.haml @@ -2,33 +2,36 @@ =f.label :library_id =f.error_message_on :library_id =f.select(:library_id, :collection => @libraries, :fields => [:street, :id]) - %span.description Ex: a simple text .group =f.label :title =f.error_message_on :title =f.text_field :title, :class => :text_field - %span.description Ex: a simple text + %span.description Ex: Handmaid's Tale, The .group =f.label :author =f.error_message_on :author =f.text_field :author, :class => :text_field - %span.description Ex: a simple text + %span.description Ex: Atwood, Margaret .group =f.label :added =f.error_message_on :added =f.text_field :added, :class => :text_field - %span.description Ex: a simple text + %span.description Ex: a 2013-03-10 .group =f.label :in =f.error_message_on :in_stock =f.check_box :in_stock, :class => :check_box - %span.description Ex: a simple text +.group + =f.label :donated + =f.error_message_on :donated + =f.check_box :donated, :class => :check_box + .group.navform.wat-cf =f.submit pat(:save), :class => :button =f.submit pat(:cancel), :onclick => "window.location='#{url(:books, :index)}';return false", :class => :button diff --git a/admin/views/books/index.haml b/admin/views/books/index.haml index 7b4db9a..5bcacfe 100644 --- a/admin/views/books/index.haml +++ b/admin/views/books/index.haml @@ -18,6 +18,7 @@ %th=mat(:book, :in_stock) %th=mat(:book, :created_at) %th=mat(:book, :updated_at) + %th=mat(:book, :donated) %th.last=" " -@books.each do |book| %tr @@ -29,6 +30,7 @@ %td=book.in_stock %td=book.created_at %td=book.updated_at + %td=book.donated %td.last =button_to pat(:edit), url(:books, :edit, :id => book.id), :method => :get, :class => :button_to ="|" diff --git a/app/views/layouts/application.haml b/app/views/layouts/application.haml index 67a7f75..e825f16 100644 --- a/app/views/layouts/application.haml +++ b/app/views/layouts/application.haml @@ -5,21 +5,16 @@ %title A Little Free Library in Lents %meta{:content => "", :name => "description"}/ %meta{:content => "", :name => "author"}/ - / Le HTML5 shim, for IE6-8 support of HTML elements + / HTML5 shim, for IE6-8 support of HTML elements /[if lt IE 9] - / Le styles + / Styles %link{:href => "/stylesheets/bootstrap.css", :rel => "stylesheet"}/ :css body { padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */ } %link{:href => "/stylesheets/bootstrap-responsive.css", :rel => "stylesheet"}/ - / Le fav and touch icons - %link{:href => "images/favicon.ico", :rel => "shortcut icon"}/ - %link{:href => "images/apple-touch-icon.png", :rel => "apple-touch-icon"}/ - %link{:href => "images/apple-touch-icon-72x72.png", :rel => "apple-touch-icon", :sizes => "72x72"}/ - %link{:href => "images/apple-touch-icon-114x114.png", :rel => "apple-touch-icon", :sizes => "114x114"}/ %body .navbar.navbar-fixed-top .navbar-inner @@ -47,23 +42,12 @@ =yield / /container / - Le javascript + javascript \================================================== / Placed at the end of the document so the pages load faster - %script{:src => "/js/jquery.js"} - %script{:src => "/js/bootstrap-transition.js"} - %script{:src => "/js/bootstrap-alert.js"} - %script{:src => "/js/bootstrap-modal.js"} - %script{:src => "/js/bootstrap-dropdown.js"} - %script{:src => "/js/bootstrap-scrollspy.js"} - %script{:src => "/js/bootstrap-tab.js"} - %script{:src => "/js/bootstrap-tooltip.js"} - %script{:src => "/js/bootstrap-popover.js"} - %script{:src => "/js/bootstrap-button.js"} - %script{:src => "/js/bootstrap-collapse.js"} - %script{:src => "/js/bootstrap-carousel.js"} - %script{:src => "/js/bootstrap-typeahead.js"} - + %script{:src => "/javascripts/jquery-1.9.1.min.js"} + %script{:src => "/javascripts/bootstrap.min.js"} + %script{:src => "/javascripts/jquery.tablesorter.min.js"} :javascript var _gaq = _gaq || [];_gaq.push(['_setAccount', 'UA-609327-5']);_gaq.push(['_trackPageview']); (function() {var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; diff --git a/app/views/libraries/inventory.haml b/app/views/libraries/inventory.haml index 537ed82..bceffe0 100644 --- a/app/views/libraries/inventory.haml +++ b/app/views/libraries/inventory.haml @@ -1,19 +1,29 @@ %h2="Library at #{@library.street}" -%table{:class => 'table'} +%p + %strong Current inventory: + #{@library.books.in.count} books + %strong Books ever seen: + #{@library.books.count} books + %i{:class => 'icon-plus-sign'} + New this week + %i{:class => 'icon-gift'} + Donated + +%table{:class => 'table', :id => 'inventory'} %thead %th Title %th Author %th Added %tbody -@books.each do |book| - -if book.created_at > (Date.today - 7.days) - %tr{:class => "info"} - %td=book.title - %td=book.author - %td=book.created_at.strftime("%B %d, %Y") - -else - %tr - %td=book.title - %td=book.author - %td=book.created_at.strftime("%B %d, %Y") + %tr + %td + #{book.title} + - if book.created_at > (Date.today - 7.days) + %i{:class => 'icon-plus-sign', :title => 'New this week'} + - if book.donated == true + %i{:class => 'icon-gift', :title => "Donated" } + %td=book.author + %td=book.created_at.strftime("%B %d, %Y") + diff --git a/db/migrate/005_add_donated_to_books.rb b/db/migrate/005_add_donated_to_books.rb new file mode 100644 index 0000000..39c6a0b --- /dev/null +++ b/db/migrate/005_add_donated_to_books.rb @@ -0,0 +1,9 @@ +class AddDonatedToBooks < ActiveRecord::Migration + def self.up + add_column :books, :donated, :boolean, :default => 0 + end + + def self.down + remove_column :books, :donated + end +end diff --git a/db/schema.rb b/db/schema.rb index 548f65d..412add9 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 4) do +ActiveRecord::Schema.define(:version => 5) do create_table "accounts", :force => true do |t| t.string "name" @@ -29,8 +29,9 @@ t.string "author" t.date "added" t.boolean "in_stock" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.boolean "donated", :default => false end create_table "libraries", :force => true do |t| diff --git a/models/book.rb b/models/book.rb index 9e05a86..4b70b09 100644 --- a/models/book.rb +++ b/models/book.rb @@ -1,3 +1,12 @@ class Book < ActiveRecord::Base belongs_to :library + after_initialize :init + + def init + self.in_stock ||= true + self.added ||= Date.today + end + + scope :in, where(:in_stock => true) + end diff --git a/public/javascripts/jquery-1.9.1.min.js b/public/javascripts/jquery-1.9.1.min.js new file mode 100644 index 0000000..006e953 --- /dev/null +++ b/public/javascripts/jquery-1.9.1.min.js @@ -0,0 +1,5 @@ +/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license +//@ sourceMappingURL=jquery.min.map +*/(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:v&&!v.call("\ufeff\u00a0")?function(e){return null==e?"":v.call(e)}:function(e){return null==e?"":(e+"").replace(T,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?b.merge(n,"string"==typeof e?[e]:e):d.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(g)return g.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return f.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),b.isFunction(e)?(r=h.call(arguments,2),i=function(){return e.apply(n||this,r.concat(h.call(arguments)))},i.guid=e.guid=e.guid||b.guid++,i):t},access:function(e,n,r,i,o,a,s){var u=0,l=e.length,c=null==r;if("object"===b.type(r)){o=!0;for(u in r)b.access(e,n,u,r[u],!0,a,s)}else if(i!==t&&(o=!0,b.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(b(e),n)})),n))for(;l>u;u++)n(e[u],r,s?i:i.call(e[u],u,n(e[u],r)));return o?e:c?n.call(e):l?n(e[0],r):a},now:function(){return(new Date).getTime()}}),b.ready.promise=function(t){if(!n)if(n=b.Deferred(),"complete"===o.readyState)setTimeout(b.ready);else if(o.addEventListener)o.addEventListener("DOMContentLoaded",H,!1),e.addEventListener("load",H,!1);else{o.attachEvent("onreadystatechange",H),e.attachEvent("onload",H);var r=!1;try{r=null==e.frameElement&&o.documentElement}catch(i){}r&&r.doScroll&&function a(){if(!b.isReady){try{r.doScroll("left")}catch(e){return setTimeout(a,50)}q(),b.ready()}}()}return n.promise(t)},b.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=b.type(e);return b.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=b(o);var _={};function F(e){var t=_[e]={};return b.each(e.match(w)||[],function(e,n){t[n]=!0}),t}b.Callbacks=function(e){e="string"==typeof e?_[e]||F(e):b.extend({},e);var n,r,i,o,a,s,u=[],l=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=u.length,n=!0;u&&o>a;a++)if(u[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,u&&(l?l.length&&c(l.shift()):r?u=[]:p.disable())},p={add:function(){if(u){var t=u.length;(function i(t){b.each(t,function(t,n){var r=b.type(n);"function"===r?e.unique&&p.has(n)||u.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=u.length:r&&(s=t,c(r))}return this},remove:function(){return u&&b.each(arguments,function(e,t){var r;while((r=b.inArray(t,u,r))>-1)u.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?b.inArray(e,u)>-1:!(!u||!u.length)},empty:function(){return u=[],this},disable:function(){return u=l=r=t,this},disabled:function(){return!u},lock:function(){return l=t,r||p.disable(),this},locked:function(){return!l},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!u||i&&!l||(n?l.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},b.extend({Deferred:function(e){var t=[["resolve","done",b.Callbacks("once memory"),"resolved"],["reject","fail",b.Callbacks("once memory"),"rejected"],["notify","progress",b.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return b.Deferred(function(n){b.each(t,function(t,o){var a=o[0],s=b.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&b.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?b.extend(e,r):r}},i={};return r.pipe=r.then,b.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=h.call(arguments),r=n.length,i=1!==r||e&&b.isFunction(e.promise)?r:0,o=1===i?e:b.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?h.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,u,l;if(r>1)for(s=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&b.isFunction(n[t].promise)?n[t].promise().done(a(t,l,n)).fail(o.reject).progress(a(t,u,s)):--i;return i||o.resolveWith(l,n),o.promise()}}),b.support=function(){var t,n,r,a,s,u,l,c,p,f,d=o.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="
t |